* Xmas Offer
From: Mrs Julie Leach @ 2016-11-26 7:02 UTC (permalink / raw)
To: Recipients
You are a recipient to Mrs Julie Leach Donation of $3 million USD. Contact ( julieleach93-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org ) for claims.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v4 0/6] arm64: arch_timer: Add workaround for hisilicon-161601 erratum
From: Ding Tianhong @ 2016-11-26 8:00 UTC (permalink / raw)
To: catalin.marinas, will.deacon, marc.zyngier, mark.rutland, oss,
devicetree, shawnguo, stuart.yoder, linux-arm-kernel, linuxarm,
hanjun.guo
Cc: Ding Tianhong
Erratum Hisilicon-161601 says that the ARM generic timer counter "has the
potential to contain an erroneous value when the timer value changes".
Accesses to TVAL (both read and write) are also affected due to the implicit counter
read. Accesses to CVAL are not affected.
The workaround is to reread the system count registers until the value of the second
read is larger than the first one by less than 32, the system counter can be guaranteed
not to return wrong value twice by back-to-back read and the error value is always larger
than the correct one by 32. Writes to TVAL are replaced with an equivalent write to CVAL.
v2: Introducing a new generic erratum handling mechanism for fsl,a008585 and hisilicon,161601.
Significant rework based on feedback, including seperate the fsl erratum a008585
to another patch, update the erratum name and remove unwanted code.
v3: Introducing the erratum_workaround_set_sne generic function for fsl erratum a008585
and make the #define __fsl_a008585_read_reg to be private to the .c file instead of
being globally visible. After discussion with Marc and Will, a consensus decision was
made to remove the commandline parameter for enabling fsl,erratum-a008585 erratum,
and make some generic name more specific, export timer_unstable_counter_workaround
for module access.
Significant rework based on feedback, including fix some alignment problem, make the
#define __hisi_161601_read_reg to be private to the .c file instead of being globally
visible, add more accurate annotation and modify a bit of logical format to enable
arch_timer_read_ool_enabled, remove the kernel commandline parameter
clocksource.arm_arch_timer.hisilicon-161601.
Introduce a generic aquick framework for erratum in ACPI mode.
v4: rename the quirk handler parameter to make it more generic, and
avoid break loop when handling the quirk becasue it need to
support multi quirks handler.
update some data structures for acpi mode.
Ding Tianhong (4):
arm64: arch_timer: Add device tree binding for hisilicon-161601
erratum
arm64: arch_timer: Introduce a generic erratum handing mechanism for
fsl-a008585
arm64: arch_timer: Work around Erratum Hisilicon-161601
arm64: arch timer: Add timer erratum property for Hip05-d02 and
Hip06-d03
Hanjun Guo (2):
arm64: arch_timer: apci: Introduce a generic aquirk framework for
erratum
arm64: arch_timer: acpi: add hisi timer errata data
Documentation/arm64/silicon-errata.txt | 1 +
.../devicetree/bindings/arm/arch_timer.txt | 8 +
Documentation/kernel-parameters.txt | 9 -
arch/arm64/boot/dts/hisilicon/hip05.dtsi | 1 +
arch/arm64/boot/dts/hisilicon/hip06.dtsi | 1 +
arch/arm64/include/asm/arch_timer.h | 38 ++--
drivers/clocksource/Kconfig | 9 +
drivers/clocksource/arm_arch_timer.c | 197 +++++++++++++++++----
8 files changed, 194 insertions(+), 70 deletions(-)
--
1.9.0
^ permalink raw reply
* [PATCH v4 1/6] arm64: arch_timer: Add device tree binding for hisilicon-161601 erratum
From: Ding Tianhong @ 2016-11-26 8:00 UTC (permalink / raw)
To: catalin.marinas, will.deacon, marc.zyngier, mark.rutland, oss,
devicetree, shawnguo, stuart.yoder, linux-arm-kernel, linuxarm,
hanjun.guo
Cc: Ding Tianhong
In-Reply-To: <1480147248-12828-1-git-send-email-dingtianhong@huawei.com>
This erratum describes a bug in logic outside the core, so MIDR can't be
used to identify its presence, and reading an SoC-specific revision
register from common arch timer code would be awkward. So, describe it
in the device tree.
v2: Use the new erratum name and update the description.
Signed-off-by: Ding Tianhong <dingtianhong@huawei.com>
Acked-by: Rob Herring <robh@kernel.org>
---
Documentation/devicetree/bindings/arm/arch_timer.txt | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/arch_timer.txt b/Documentation/devicetree/bindings/arm/arch_timer.txt
index ef5fbe9..c27b2c4 100644
--- a/Documentation/devicetree/bindings/arm/arch_timer.txt
+++ b/Documentation/devicetree/bindings/arm/arch_timer.txt
@@ -31,6 +31,14 @@ to deliver its interrupts via SPIs.
This also affects writes to the tval register, due to the implicit
counter read.
+- hisilicon,erratum-161601 : A boolean property. Indicates the presence of
+ erratum 161601, which says that reading the counter is unreliable unless
+ reading twice on the register and the value of the second read is larger
+ than the first by less than 32. If the verification is unsuccessful, then
+ discard the value of this read and repeat this procedure until the verification
+ is successful. This also affects writes to the tval register, due to the
+ implicit counter read.
+
** Optional properties:
- arm,cpu-registers-not-fw-configured : Firmware does not initialize
--
1.9.0
^ permalink raw reply related
* [PATCH v4 2/6] arm64: arch_timer: Introduce a generic erratum handing mechanism for fsl-a008585
From: Ding Tianhong @ 2016-11-26 8:00 UTC (permalink / raw)
To: catalin.marinas, will.deacon, marc.zyngier, mark.rutland, oss,
devicetree, shawnguo, stuart.yoder, linux-arm-kernel, linuxarm,
hanjun.guo
Cc: Ding Tianhong
In-Reply-To: <1480147248-12828-1-git-send-email-dingtianhong@huawei.com>
The workaround for hisilicon,161601 will check the return value of the system counter
by different way, in order to distinguish with the fsl-a008585 workaround, introduce
a new generic erratum handing mechanism for fsl-a008585 and rename some functions.
v2: Introducing a new generic erratum handling mechanism for fsl erratum a008585.
v3: Introducing the erratum_workaround_set_sne generic function for fsl erratum a008585
and make the #define __fsl_a008585_read_reg to be private to the .c file instead of
being globally visible. After discussion with Marc and Will, a consensus decision was
made to remove the commandline parameter for enabling fsl,erratum-a008585 erratum,
and make some generic name more specific, export timer_unstable_counter_workaround
for module access.
Signed-off-by: Ding Tianhong <dingtianhong@huawei.com>
---
Documentation/kernel-parameters.txt | 9 -----
arch/arm64/include/asm/arch_timer.h | 36 ++++++-----------
drivers/clocksource/arm_arch_timer.c | 78 +++++++++++++++++++++---------------
3 files changed, 58 insertions(+), 65 deletions(-)
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 37babf9..c9db07c 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -738,15 +738,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
loops can be debugged more effectively on production
systems.
- clocksource.arm_arch_timer.fsl-a008585=
- [ARM64]
- Format: <bool>
- Enable/disable the workaround of Freescale/NXP
- erratum A-008585. This can be useful for KVM
- guests, if the guest device tree doesn't show the
- erratum. If unspecified, the workaround is
- enabled based on the device tree.
-
clearcpuid=BITNUM [X86]
Disable CPUID feature X for the kernel. See
arch/x86/include/asm/cpufeatures.h for the valid bit
diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h
index eaa5bbe..f882c7c 100644
--- a/arch/arm64/include/asm/arch_timer.h
+++ b/arch/arm64/include/asm/arch_timer.h
@@ -31,39 +31,27 @@
#if IS_ENABLED(CONFIG_FSL_ERRATUM_A008585)
extern struct static_key_false arch_timer_read_ool_enabled;
-#define needs_fsl_a008585_workaround() \
+#define needs_unstable_timer_counter_workaround() \
static_branch_unlikely(&arch_timer_read_ool_enabled)
#else
-#define needs_fsl_a008585_workaround() false
+#define needs_unstable_timer_counter_workaround() false
#endif
-u32 __fsl_a008585_read_cntp_tval_el0(void);
-u32 __fsl_a008585_read_cntv_tval_el0(void);
-u64 __fsl_a008585_read_cntvct_el0(void);
-/*
- * The number of retries is an arbitrary value well beyond the highest number
- * of iterations the loop has been observed to take.
- */
-#define __fsl_a008585_read_reg(reg) ({ \
- u64 _old, _new; \
- int _retries = 200; \
- \
- do { \
- _old = read_sysreg(reg); \
- _new = read_sysreg(reg); \
- _retries--; \
- } while (unlikely(_old != _new) && _retries); \
- \
- WARN_ON_ONCE(!_retries); \
- _new; \
-})
+struct arch_timer_erratum_workaround {
+ int erratum; /* Indicate the Erratum ID */
+ u32 (*read_cntp_tval_el0)(void);
+ u32 (*read_cntv_tval_el0)(void);
+ u64 (*read_cntvct_el0)(void);
+};
+
+extern struct arch_timer_erratum_workaround *timer_unstable_counter_workaround;
#define arch_timer_reg_read_stable(reg) \
({ \
u64 _val; \
- if (needs_fsl_a008585_workaround()) \
- _val = __fsl_a008585_read_##reg(); \
+ if (needs_unstable_timer_counter_workaround()) \
+ _val = timer_unstable_counter_workaround->read_##reg();\
else \
_val = read_sysreg(reg); \
_val; \
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 73c487d..696386f 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -95,40 +95,53 @@ static int __init early_evtstrm_cfg(char *buf)
*/
#ifdef CONFIG_FSL_ERRATUM_A008585
-DEFINE_STATIC_KEY_FALSE(arch_timer_read_ool_enabled);
-EXPORT_SYMBOL_GPL(arch_timer_read_ool_enabled);
-
-static int fsl_a008585_enable = -1;
+struct arch_timer_erratum_workaround *timer_unstable_counter_workaround = NULL;
+EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround);
-static int __init early_fsl_a008585_cfg(char *buf)
-{
- int ret;
- bool val;
+#define FSL_A008585 0x0001
- ret = strtobool(buf, &val);
- if (ret)
- return ret;
-
- fsl_a008585_enable = val;
- return 0;
-}
-early_param("clocksource.arm_arch_timer.fsl-a008585", early_fsl_a008585_cfg);
+DEFINE_STATIC_KEY_FALSE(arch_timer_read_ool_enabled);
+EXPORT_SYMBOL_GPL(arch_timer_read_ool_enabled);
-u32 __fsl_a008585_read_cntp_tval_el0(void)
+/*
+ * The number of retries is an arbitrary value well beyond the highest number
+ * of iterations the loop has been observed to take.
+ */
+#define __fsl_a008585_read_reg(reg) ({ \
+ u64 _old, _new; \
+ int _retries = 200; \
+ \
+ do { \
+ _old = read_sysreg(reg); \
+ _new = read_sysreg(reg); \
+ _retries--; \
+ } while (unlikely(_old != _new) && _retries); \
+ \
+ WARN_ON_ONCE(!_retries); \
+ _new; \
+})
+
+static u32 fsl_a008585_read_cntp_tval_el0(void)
{
return __fsl_a008585_read_reg(cntp_tval_el0);
}
-u32 __fsl_a008585_read_cntv_tval_el0(void)
+static u32 fsl_a008585_read_cntv_tval_el0(void)
{
return __fsl_a008585_read_reg(cntv_tval_el0);
}
-u64 __fsl_a008585_read_cntvct_el0(void)
+static u64 fsl_a008585_read_cntvct_el0(void)
{
return __fsl_a008585_read_reg(cntvct_el0);
}
-EXPORT_SYMBOL(__fsl_a008585_read_cntvct_el0);
+
+static struct arch_timer_erratum_workaround arch_timer_fsl_a008585 = {
+ .erratum = FSL_A008585,
+ .read_cntp_tval_el0 = fsl_a008585_read_cntp_tval_el0,
+ .read_cntv_tval_el0 = fsl_a008585_read_cntv_tval_el0,
+ .read_cntvct_el0 = fsl_a008585_read_cntvct_el0,
+};
#endif /* CONFIG_FSL_ERRATUM_A008585 */
static __always_inline
@@ -281,7 +294,7 @@ static __always_inline void set_next_event(const int access, unsigned long evt,
}
#ifdef CONFIG_FSL_ERRATUM_A008585
-static __always_inline void fsl_a008585_set_next_event(const int access,
+static __always_inline void erratum_set_next_event_generic(const int access,
unsigned long evt, struct clock_event_device *clk)
{
unsigned long ctrl;
@@ -299,17 +312,17 @@ static __always_inline void fsl_a008585_set_next_event(const int access,
arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk);
}
-static int fsl_a008585_set_next_event_virt(unsigned long evt,
+static int erratum_set_next_event_virt(unsigned long evt,
struct clock_event_device *clk)
{
- fsl_a008585_set_next_event(ARCH_TIMER_VIRT_ACCESS, evt, clk);
+ erratum_set_next_event_generic(ARCH_TIMER_VIRT_ACCESS, evt, clk);
return 0;
}
-static int fsl_a008585_set_next_event_phys(unsigned long evt,
+static int erratum_set_next_event_phys(unsigned long evt,
struct clock_event_device *clk)
{
- fsl_a008585_set_next_event(ARCH_TIMER_PHYS_ACCESS, evt, clk);
+ erratum_set_next_event_generic(ARCH_TIMER_PHYS_ACCESS, evt, clk);
return 0;
}
#endif /* CONFIG_FSL_ERRATUM_A008585 */
@@ -342,16 +355,16 @@ static int arch_timer_set_next_event_phys_mem(unsigned long evt,
return 0;
}
-static void fsl_a008585_set_sne(struct clock_event_device *clk)
+static void erratum_workaround_set_sne(struct clock_event_device *clk)
{
#ifdef CONFIG_FSL_ERRATUM_A008585
if (!static_branch_unlikely(&arch_timer_read_ool_enabled))
return;
if (arch_timer_uses_ppi == VIRT_PPI)
- clk->set_next_event = fsl_a008585_set_next_event_virt;
+ clk->set_next_event = erratum_set_next_event_virt;
else
- clk->set_next_event = fsl_a008585_set_next_event_phys;
+ clk->set_next_event = erratum_set_next_event_phys;
#endif
}
@@ -384,7 +397,7 @@ static void __arch_timer_setup(unsigned type,
BUG();
}
- fsl_a008585_set_sne(clk);
+ erratum_workaround_set_sne(clk);
} else {
clk->features |= CLOCK_EVT_FEAT_DYNIRQ;
clk->name = "arch_mem_timer";
@@ -891,9 +904,10 @@ static int __init arch_timer_of_init(struct device_node *np)
arch_timer_c3stop = !of_property_read_bool(np, "always-on");
#ifdef CONFIG_FSL_ERRATUM_A008585
- if (fsl_a008585_enable < 0)
- fsl_a008585_enable = of_property_read_bool(np, "fsl,erratum-a008585");
- if (fsl_a008585_enable) {
+ if (!timer_unstable_counter_workaround && of_property_read_bool(np, "fsl,erratum-a008585"))
+ timer_unstable_counter_workaround = &arch_timer_fsl_a008585;
+
+ if (timer_unstable_counter_workaround) {
static_branch_enable(&arch_timer_read_ool_enabled);
pr_info("Enabling workaround for FSL erratum A-008585\n");
}
--
1.9.0
^ permalink raw reply related
* [PATCH v4 3/6] arm64: arch_timer: Work around Erratum Hisilicon-161601
From: Ding Tianhong @ 2016-11-26 8:00 UTC (permalink / raw)
To: catalin.marinas, will.deacon, marc.zyngier, mark.rutland, oss,
devicetree, shawnguo, stuart.yoder, linux-arm-kernel, linuxarm,
hanjun.guo
Cc: Ding Tianhong
In-Reply-To: <1480147248-12828-1-git-send-email-dingtianhong@huawei.com>
Erratum Hisilicon-161601 says that the ARM generic timer counter "has the
potential to contain an erroneous value when the timer value changes".
Accesses to TVAL (both read and write) are also affected due to the implicit counter
read. Accesses to CVAL are not affected.
The workaround is to reread the system count registers until the value of the second
read is larger than the first one by less than 32, the system counter can be guaranteed
not to return wrong value twice by back-to-back read and the error value is always larger
than the correct one by 32. Writes to TVAL are replaced with an equivalent write to CVAL.
The workaround is enabled if the hisilicon,erratum-161601 property is found in
the timer node in the device tree. This can be overridden with the
clocksource.arm_arch_timer.hisilicon-161601 boot parameter, which allows KVM
users to enable the workaround until a mechanism is implemented to
automatically communicate this information.
Fix some description for fsl erratum a008585.
v2: Significant rework based on feedback, including seperate the fsl erratum a008585
to another patch, update the erratum name and remove unwanted code.
v3: Significant rework based on feedback, including fix some alignment problem, make the
#define __hisi_161601_read_reg to be private to the .c file instead of being globally
visible, add more accurate annotation and modify a bit of logical format to enable
arch_timer_read_ool_enabled, remove the kernel commandline parameter
clocksource.arm_arch_timer.hisilicon-161601.
Signed-off-by: Ding Tianhong <dingtianhong@huawei.com>
---
Documentation/arm64/silicon-errata.txt | 1 +
arch/arm64/include/asm/arch_timer.h | 2 +-
drivers/clocksource/Kconfig | 9 +++++
drivers/clocksource/arm_arch_timer.c | 67 +++++++++++++++++++++++++++++++---
4 files changed, 73 insertions(+), 6 deletions(-)
diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt
index 405da11..1c1a95f 100644
--- a/Documentation/arm64/silicon-errata.txt
+++ b/Documentation/arm64/silicon-errata.txt
@@ -63,3 +63,4 @@ stable kernels.
| Cavium | ThunderX SMMUv2 | #27704 | N/A |
| | | | |
| Freescale/NXP | LS2080A/LS1043A | A-008585 | FSL_ERRATUM_A008585 |
+| Hisilicon | Hip0{5,6,7} | #161601 | HISILICON_ERRATUM_161601|
diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h
index f882c7c..ebf4cde 100644
--- a/arch/arm64/include/asm/arch_timer.h
+++ b/arch/arm64/include/asm/arch_timer.h
@@ -29,7 +29,7 @@
#include <clocksource/arm_arch_timer.h>
-#if IS_ENABLED(CONFIG_FSL_ERRATUM_A008585)
+#if IS_ENABLED(CONFIG_FSL_ERRATUM_A008585) || IS_ENABLED(CONFIG_HISILICON_ERRATUM_161601)
extern struct static_key_false arch_timer_read_ool_enabled;
#define needs_unstable_timer_counter_workaround() \
static_branch_unlikely(&arch_timer_read_ool_enabled)
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index e2c6e43..6847ef8 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -315,6 +315,15 @@ config FSL_ERRATUM_A008585
value"). The workaround will only be active if the
fsl,erratum-a008585 property is found in the timer node.
+config HISILICON_ERRATUM_161601
+ bool "Workaround for Hisilicon Erratum 161601"
+ default y
+ depends on ARM_ARCH_TIMER && ARM64
+ help
+ This option enables a workaround for Hisilicon Erratum
+ 161601. The workaround will be active if the hisilicon,erratum-161601
+ property is found in the timer node.
+
config ARM_GLOBAL_TIMER
bool "Support for the ARM global timer" if COMPILE_TEST
select CLKSRC_OF if OF
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 696386f..3d59af1 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -94,15 +94,18 @@ static int __init early_evtstrm_cfg(char *buf)
* Architected system timer support.
*/
-#ifdef CONFIG_FSL_ERRATUM_A008585
+#if CONFIG_FSL_ERRATUM_A008585 || IS_ENABLED(CONFIG_HISILICON_ERRATUM_161601)
struct arch_timer_erratum_workaround *timer_unstable_counter_workaround = NULL;
EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround);
#define FSL_A008585 0x0001
+#define HISILICON_161601 0x0002
DEFINE_STATIC_KEY_FALSE(arch_timer_read_ool_enabled);
EXPORT_SYMBOL_GPL(arch_timer_read_ool_enabled);
+#endif
+#ifdef CONFIG_FSL_ERRATUM_A008585
/*
* The number of retries is an arbitrary value well beyond the highest number
* of iterations the loop has been observed to take.
@@ -144,6 +147,51 @@ static u64 fsl_a008585_read_cntvct_el0(void)
};
#endif /* CONFIG_FSL_ERRATUM_A008585 */
+#ifdef CONFIG_HISILICON_ERRATUM_161601
+/*
+ * Theoretically the erratum should not occur more than twice in succession,
+ * so set the retry count to 2 is sufficient here.
+ * Verify whether the value of the second read is larger than the first by
+ * less than 32 is the only way to confirm the value is correct, so clear the
+ * lower 5 bits to check whether the difference is greater than 32 or not.
+ */
+#define __hisi_161601_read_reg(reg) ({ \
+ u64 _old, _new; \
+ int _retries = 2; \
+ \
+ do { \
+ _old = read_sysreg(reg); \
+ _new = read_sysreg(reg); \
+ _retries--; \
+ } while (unlikely((_new - _old) >> 5) && _retries); \
+ \
+ WARN_ON_ONCE(!_retries); \
+ _new; \
+})
+
+static u32 hisi_161601_read_cntp_tval_el0(void)
+{
+ return __hisi_161601_read_reg(cntp_tval_el0);
+}
+
+static u32 hisi_161601_read_cntv_tval_el0(void)
+{
+ return __hisi_161601_read_reg(cntv_tval_el0);
+}
+
+static u64 hisi_161601_read_cntvct_el0(void)
+{
+ return __hisi_161601_read_reg(cntvct_el0);
+}
+
+static struct arch_timer_erratum_workaround arch_timer_hisi_161601 = {
+ .erratum = HISILICON_161601,
+ .read_cntp_tval_el0 = hisi_161601_read_cntp_tval_el0,
+ .read_cntv_tval_el0 = hisi_161601_read_cntv_tval_el0,
+ .read_cntvct_el0 = hisi_161601_read_cntvct_el0,
+};
+#endif /* CONFIG_HISILICON_ERRATUM_161601 */
+
static __always_inline
void arch_timer_reg_write(int access, enum arch_timer_reg reg, u32 val,
struct clock_event_device *clk)
@@ -293,7 +341,7 @@ static __always_inline void set_next_event(const int access, unsigned long evt,
arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk);
}
-#ifdef CONFIG_FSL_ERRATUM_A008585
+#if IS_ENABLED(CONFIG_FSL_ERRATUM_A008585) || IS_ENABLED(CONFIG_HISILICON_ERRATUM_161601)
static __always_inline void erratum_set_next_event_generic(const int access,
unsigned long evt, struct clock_event_device *clk)
{
@@ -357,7 +405,7 @@ static int arch_timer_set_next_event_phys_mem(unsigned long evt,
static void erratum_workaround_set_sne(struct clock_event_device *clk)
{
-#ifdef CONFIG_FSL_ERRATUM_A008585
+#if IS_ENABLED(CONFIG_FSL_ERRATUM_A008585) || IS_ENABLED(CONFIG_HISILICON_ERRATUM_161601)
if (!static_branch_unlikely(&arch_timer_read_ool_enabled))
return;
@@ -617,7 +665,7 @@ static void __init arch_counter_register(unsigned type)
clocksource_counter.archdata.vdso_direct = true;
-#ifdef CONFIG_FSL_ERRATUM_A008585
+#if IS_ENABLED(CONFIG_FSL_ERRATUM_A008585) || IS_ENABLED(CONFIG_HISILICON_ERRATUM_161601)
/*
* Don't use the vdso fastpath if errata require using
* the out-of-line counter accessor.
@@ -906,10 +954,19 @@ static int __init arch_timer_of_init(struct device_node *np)
#ifdef CONFIG_FSL_ERRATUM_A008585
if (!timer_unstable_counter_workaround && of_property_read_bool(np, "fsl,erratum-a008585"))
timer_unstable_counter_workaround = &arch_timer_fsl_a008585;
+#endif
+
+#ifdef CONFIG_HISILICON_ERRATUM_161601
+ if (!timer_unstable_counter_workaround && of_property_read_bool(np, "hisilicon,erratum-161601"))
+ timer_unstable_counter_workaround = &arch_timer_hisi_161601;
+#endif
+#if IS_ENABLED(CONFIG_FSL_ERRATUM_A008585) || IS_ENABLED(CONFIG_HISILICON_ERRATUM_161601)
if (timer_unstable_counter_workaround) {
static_branch_enable(&arch_timer_read_ool_enabled);
- pr_info("Enabling workaround for FSL erratum A-008585\n");
+ pr_info("Enabling workaround for %s\n",
+ timer_unstable_counter_workaround->erratum == FSL_A008585 ?
+ "FSL ERRATUM A-008585" : "HISILICON ERRATUM 161601");
}
#endif
--
1.9.0
^ permalink raw reply related
* [PATCH v4 4/6] arm64: arch timer: Add timer erratum property for Hip05-d02 and Hip06-d03
From: Ding Tianhong @ 2016-11-26 8:00 UTC (permalink / raw)
To: catalin.marinas, will.deacon, marc.zyngier, mark.rutland, oss,
devicetree, shawnguo, stuart.yoder, linux-arm-kernel, linuxarm,
hanjun.guo
Cc: Ding Tianhong
In-Reply-To: <1480147248-12828-1-git-send-email-dingtianhong@huawei.com>
Enable workaround for hisilicon erratum 161601 on Hip05-d02 and Hip06-d03 board.
Signed-off-by: Ding Tianhong <dingtianhong@huawei.com>
---
arch/arm64/boot/dts/hisilicon/hip05.dtsi | 1 +
arch/arm64/boot/dts/hisilicon/hip06.dtsi | 1 +
2 files changed, 2 insertions(+)
diff --git a/arch/arm64/boot/dts/hisilicon/hip05.dtsi b/arch/arm64/boot/dts/hisilicon/hip05.dtsi
index 4b472a3..a8e9969 100644
--- a/arch/arm64/boot/dts/hisilicon/hip05.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hip05.dtsi
@@ -281,6 +281,7 @@
<GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
<GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
<GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+ hisilicon,erratum-161601;
};
pmu {
diff --git a/arch/arm64/boot/dts/hisilicon/hip06.dtsi b/arch/arm64/boot/dts/hisilicon/hip06.dtsi
index b548763..c31f9f9 100644
--- a/arch/arm64/boot/dts/hisilicon/hip06.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hip06.dtsi
@@ -260,6 +260,7 @@
<GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
<GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
<GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+ hisilicon,erratum-161601;
};
pmu {
--
1.9.0
^ permalink raw reply related
* [PATCH v4 5/6] arm64: arch_timer: apci: Introduce a generic aquirk framework for erratum
From: Ding Tianhong @ 2016-11-26 8:00 UTC (permalink / raw)
To: catalin.marinas-5wv7dgnIgG8, will.deacon-5wv7dgnIgG8,
marc.zyngier-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
oss-fOR+EgIDQEHk1uMJSBkQmQ, devicetree-u79uwXL29TY76Z2rM5mHXA,
shawnguo-DgEjT+Ai2ygdnm+yROfE0A, stuart.yoder-3arQi8VN3Tc,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linuxarm-hv44wF8Li93QT0dZR+AlfA,
hanjun.guo-QSEj5FYQhm4dnm+yROfE0A
Cc: Ding Tianhong
In-Reply-To: <1480147248-12828-1-git-send-email-dingtianhong-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
From: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Introduce a general quirk framework for each timer erratum in ACPI,
which use the oem information in GTDT table for platform specific erratums.
The struct gtdt_arch_timer_fixup is introduced to record the oem
information to match the quirk and handle the erratum.
v3: Introduce a generic aquick framework for erratum in ACPI mode.
v4: rename the quirk handler parameter to make it more generic, and
avoid break loop when handling the quirk becasue it need to
support multi quirks handler.
Signed-off-by: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Signed-off-by: Ding Tianhong <dingtianhong-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
---
drivers/clocksource/arm_arch_timer.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 3d59af1..d4f4a0d 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -1068,6 +1068,39 @@ static int __init arch_timer_mem_init(struct device_node *np)
arch_timer_mem_init);
#ifdef CONFIG_ACPI
+struct gtdt_arch_timer_fixup {
+ char oem_id[ACPI_OEM_ID_SIZE];
+ char oem_table_id[ACPI_OEM_TABLE_ID_SIZE];
+ u32 oem_revision;
+
+ /* quirk handler for arch timer erratum */
+ void (*handler)(void *context);
+ void *context;
+};
+
+/* note: this needs to be updated according to the doc of OEM ID
+ * and TABLE ID for different board.
+ */
+struct gtdt_arch_timer_fixup arch_timer_quirks[] __initdata = {
+};
+
+void __init arch_timer_acpi_quirks_handler(char *oem_id,
+ char *oem_table_id,
+ u32 oem_revision)
+{
+ struct gtdt_arch_timer_fixup *quirks = arch_timer_quirks;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(arch_timer_quirks); i++, quirks++) {
+ if (!memcmp(quirks->oem_id, oem_id, ACPI_OEM_ID_SIZE) &&
+ !memcmp(quirks->oem_table_id, oem_table_id, ACPI_OEM_TABLE_ID_SIZE) &&
+ quirks->oem_revision == oem_revision) {
+ if (quirks->handler && quirks->context)
+ quirks->handler(quirks->context);
+ }
+ }
+}
+
static int __init map_generic_timer_interrupt(u32 interrupt, u32 flags)
{
int trigger, polarity;
@@ -1094,6 +1127,9 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
return -EINVAL;
}
+ arch_timer_acpi_quirks_handler(table->oem_id, table->oem_table_id,
+ table->oem_revision);
+
gtdt = container_of(table, struct acpi_table_gtdt, header);
arch_timers_present |= ARCH_CP15_TIMER;
--
1.9.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v4 6/6] arm64: arch_timer: acpi: add hisi timer errata data
From: Ding Tianhong @ 2016-11-26 8:00 UTC (permalink / raw)
To: catalin.marinas, will.deacon, marc.zyngier, mark.rutland, oss,
devicetree, shawnguo, stuart.yoder, linux-arm-kernel, linuxarm,
hanjun.guo
Cc: Ding Tianhong
In-Reply-To: <1480147248-12828-1-git-send-email-dingtianhong@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
Add hisi timer specific erratum fixes.
v3: add hisilicon erratum 161601 for ACPI mode.
v4: update some data structures.
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Signed-off-by: Ding Tianhong <dingtianhong@huawei.com>
---
drivers/clocksource/arm_arch_timer.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index d4f4a0d..649f7fe 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -1078,10 +1078,28 @@ struct gtdt_arch_timer_fixup {
void *context;
};
+#ifdef CONFIG_HISILICON_ERRATUM_161601
+static void __init erratum_workaround_enable(void *context)
+{
+ u64 erratum = (u64) context;
+
+ if (erratum & HISILICON_161601) {
+ timer_unstable_counter_workaround = &arch_timer_hisi_161601;
+ static_branch_enable(&arch_timer_read_ool_enabled);
+ pr_info("Enabling workaround for HISILICON ERRATUM 161601\n");
+ }
+}
+#endif
+
/* note: this needs to be updated according to the doc of OEM ID
* and TABLE ID for different board.
*/
struct gtdt_arch_timer_fixup arch_timer_quirks[] __initdata = {
+#ifdef CONFIG_HISILICON_ERRATUM_161601
+ {"HISI", "hip05", 0, &erratum_workaround_enable, (void *) HISILICON_161601},
+ {"HISI", "hip06", 0, &erratum_workaround_enable, (void *) HISILICON_161601},
+ {"HISI", "hip07", 0, &erratum_workaround_enable, (void *) HISILICON_161601},
+#endif
};
void __init arch_timer_acpi_quirks_handler(char *oem_id,
--
1.9.0
^ permalink raw reply related
* Xmas Offer
From: Mrs Julie Leach @ 2016-11-26 10:26 UTC (permalink / raw)
To: Recipients
You are a recipient to Mrs Julie Leach Donation of $3 million USD. Contact ( julieleach93-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org ) for claims.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* I hope this email meets you well in good health condition
From: Bentley @ 2016-11-26 12:52 UTC (permalink / raw)
How you doing today? I hope you are doing well. My name is Jones, from the US. I'm in Syria right now fighting ISIS. I want to get to know you better, if I may be so bold. I consider myself an easy-going man, and I am currently looking for a relationship in which I feel loved. Please tell me more about yourself, if you don't mind.
Hope to hear from you soon.
Regards,
Jones.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v3 00/12] Initial Tegra186 support
From: Pavel Machek @ 2016-11-26 13:39 UTC (permalink / raw)
To: Thierry Reding
Cc: Sivaram Nair, devicetree-u79uwXL29TY76Z2rM5mHXA,
Peter De Schrijver, Timo Alho, Joseph Lo,
linux-tegra-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <20160819173233.13260-1-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Hi!
> From: Thierry Reding <treding-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
>
> Hi everyone,
>
> This is a set of patches to add initial support for Tegra186. It is
> based on Joseph's patches but I rewrote some of the drivers to be a
> little easier to comprehend and maintain (hopefully). I've also
> included clock and reset drivers as a proof of concept.
Is there any phone/tablet on the market with this chipset?
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply
* [PATCH 0/5] Meson GXL and GXM USB support
From: Martin Blumenstingl @ 2016-11-26 14:56 UTC (permalink / raw)
To: linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, kishon-l0cyMroinI0,
khilman-rdvid1DuHRBWk0Htik3J/w, carlo-KA+7E9HrN00dnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, robh+dt-DgEjT+Ai2ygdnm+yROfE0A
Cc: catalin.marinas-5wv7dgnIgG8, will.deacon-5wv7dgnIgG8,
narmstrong-rdvid1DuHRBWk0Htik3J/w, Martin Blumenstingl
USB support on GXL and GXM differs a lot from Meson8b and GXBB:
The most obvious change is that GXL and GXM now have one dwc3
controller and one dwc2 controller (instead of two dwc2 controllers).
With that there are also new USB PHYs.
Due to lack of hardware I was only able to test this on a board with
GXM, but as far as I understand the hardware my preparations should be
correct (so it should also work on GXL).
dwc2 will probably stay unused on most GXM devices since it's limited
to device mode via some dwc2 hardware configuration register.
dwc3 is probably used on all devices, even if there is more than just
one USB port. dwc3 has a built-in USB2 hub - on GXL this hub has two
ports enabled, while on GXM there are three ports enabled (see below
for lsusb output). There are no USB3 ports enabled in the dwc3 hardware
configuration, meaning that the SoC is limited to high-speed mode.
On my GXM device the dwc3 hardware configuration forces it into "host
only" mode.
The SoCs contain two PHY blocks: one USB3 PHY and up to four USB2 PHYs
(on GXM there are only three enabled, but the registers should support
up to four).
The USB3 PHY also handles the OTG interrupts, but since dwc3's hardware
configuration enforces "host only" mode I was not able to test this. It
simply takes care of an interrupt and then notifies all related PHYs
about the new mode.
The USB2 PHY block is a bit different: I created one PHY driver which
spans all "PHY ports" because the handling is a bit tricky. It turns
out that for each available USB port in dwc3's hub the corresponding
PHY must be enabled (even if there is no physical port - in my case
port 3 is not connected to anything, but disabling the PHY breaks
ports 1 and 2 as well).
I decided not not pass the USB2 PHYs directly to dwc3 due to three
reasons: 1. the USB3 PHY (which holds a reference to all relevant
USB2 PHY ports) controls the mode of the USB2 PHY ports (since both
are used with the same controller and thus it makes sense to keep the
mode consistent across all ports) 2. the dwc3 driver does not support
passing multiple USB2 PHYs (only one USB2 and one USB3 PHY can be
passed to it) 3. it is similar to how the vendor reference driver
manages the PHYs. Please note that this coupling is not a fixed, this
is all configurable via devicetree (so if the third USB2 PHY has to
be passed two the dwc2 controller then this is still possible by
just moving on PHY reference in the .dts).
The coupling of the USB2 and USB3 PHYs is the reason why I sent the
two drivers in one patch, even though they are handling different IP
blocks (different registers, etc.).
Unfortunately there are no datasheets available for any of these PHYs.
Both drivers were written by reading the reference drivers provided by
Amlogic and analyzing the registers on the kernel that was shipped with
my board.
As a last note: the dwc3 driver currently only explicitly enables the
first USB port "DWC3_GUSB2PHYCFG(0)" in the internal hub. The hardware
seems to enable the other two (DWC3_GUSB2PHYCFG(1) and
DWC3_GUSB2PHYCFG(2)) automatically. I will ask the dwc3 maintainers if
changes to dwc3 are desired any how these should look like, but for now
it's working fine even without changes there.
lsusb output on GXM for the dwc3 hub:
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
...
Hub Port Status:
Port 1: 0000.0100 power
Port 2: 0000.0100 power
Port 3: 0000.0100 power
NOTE: The devicetree changes depend on my previous series:
"[PATCH 0/2] minor GXL and GXM improvements" - see [0]
NOTE2: This series depends on an upstream dwc3/xhci-plat DMA fix
(special thanks to Arnd Bergmann and Sriram Dash for fixing that):
"[PATCH v5 0/6] inherit dma configuration from parent dev" - see [1]
I have a tree with all dependencies applied available at [2] if
someone wants a quick way to test this (I don't take any responsibility
if anything explodes though).
[0] http://lists.infradead.org/pipermail/linux-amlogic/2016-November/001665.html
[1] http://marc.info/?l=linux-usb&m=147938307209685&w=2
[2] https://github.com/xdarklight/linux/commits/meson-gx-integration-4.10-20161126
Martin Blumenstingl (5):
Documentation: dt-bindings: Add documentation for Meson GXL USB2/3
PHYs
phy: meson: add USB2 and USB3 PHY support for Meson GXL
arm64: dts: meson-gxl: add USB support
ARM64: dts: meson-gxm: add GXM specific USB configuration
ARM64: dts: meson-gx-p23x-q20x: enable USB on P23x and Q20x boards
.../devicetree/bindings/phy/meson-gxl-usb2-phy.txt | 25 ++
.../devicetree/bindings/phy/meson-gxl-usb3-phy.txt | 27 ++
.../arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 12 +
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 49 +++
.../arm64/boot/dts/amlogic/meson-gxm-s912-q200.dts | 17 +
arch/arm64/boot/dts/amlogic/meson-gxm.dtsi | 10 +
drivers/phy/Kconfig | 13 +
drivers/phy/Makefile | 2 +
drivers/phy/phy-meson-gxl-usb2.c | 374 ++++++++++++++++++++
drivers/phy/phy-meson-gxl-usb3.c | 377 +++++++++++++++++++++
10 files changed, 906 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt
create mode 100644 Documentation/devicetree/bindings/phy/meson-gxl-usb3-phy.txt
create mode 100644 drivers/phy/phy-meson-gxl-usb2.c
create mode 100644 drivers/phy/phy-meson-gxl-usb3.c
--
2.10.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 1/5] Documentation: dt-bindings: Add documentation for Meson GXL USB2/3 PHYs
From: Martin Blumenstingl @ 2016-11-26 14:56 UTC (permalink / raw)
To: linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, kishon-l0cyMroinI0,
khilman-rdvid1DuHRBWk0Htik3J/w, carlo-KA+7E9HrN00dnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, robh+dt-DgEjT+Ai2ygdnm+yROfE0A
Cc: catalin.marinas-5wv7dgnIgG8, will.deacon-5wv7dgnIgG8,
narmstrong-rdvid1DuHRBWk0Htik3J/w, Martin Blumenstingl
In-Reply-To: <20161126145635.24488-1-martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
This adds the DT binding documentation for the USB2 and USB3 PHYs found
in the Meson GXL and GXM SoCs.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
---
.../devicetree/bindings/phy/meson-gxl-usb2-phy.txt | 25 ++++++++++++++++++++
.../devicetree/bindings/phy/meson-gxl-usb3-phy.txt | 27 ++++++++++++++++++++++
2 files changed, 52 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt
create mode 100644 Documentation/devicetree/bindings/phy/meson-gxl-usb3-phy.txt
diff --git a/Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt b/Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt
new file mode 100644
index 0000000..e7828ca
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt
@@ -0,0 +1,25 @@
+* Amlogic Meson GXL and GXM USB2 PHY binding
+
+This describes the USB2 PHY block which provides multiple USB2 PHY ports.
+
+Required properties:
+- compatible: Should be "amlogic,meson-gxl-usb2-phy"
+- reg: The base address and length of the registers
+- #phys-cells: should be 1 (see phy-bindings.txt in this directory)
+- clocks: phandle and clock identifier for the phy clocks
+- clock-names: "usb" and "usb_ddr"
+- resets: reference to the reset controller
+
+Optional properties:
+- phy-supply: see phy-bindings.txt in this directory
+
+
+Example:
+ usb2_phys: phy@78000 {
+ compatible = "amlogic,meson-gxl-usb2-phy";
+ #phy-cells = <1>;
+ reg = <0x0 0x78000 0x0 0x80>;
+ clocks = <&clkc CLKID_USB1>, <&clkc CLKID_USB1_DDR_BRIDGE>;
+ clock-names = "usb", "usb_ddr";
+ resets = <&reset RESET_USB_OTG>;
+ };
diff --git a/Documentation/devicetree/bindings/phy/meson-gxl-usb3-phy.txt b/Documentation/devicetree/bindings/phy/meson-gxl-usb3-phy.txt
new file mode 100644
index 0000000..be779e8
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/meson-gxl-usb3-phy.txt
@@ -0,0 +1,27 @@
+* Amlogic Meson GXL and GXM USB3 PHY binding
+
+Required properties:
+- compatible: Should be "amlogic,meson-gxl-usb3-phy"
+- reg: The base address and length of the registers
+- #phys-cells: should be 0 (see phy-bindings.txt in this directory)
+- interrupts: describes the OTG device/host mode detection interrupt
+- phys: a list of related PHYs (typically the USB2 PHYs, see
+ meson-gxl-usb2-phy.txt in this directory). The mode of
+ the listed PHYs will be managed by the USB3 PHY (which
+ is required for OTG device/host detection to work).
+ The number of PHYs listed typically matches the number
+ of ports which are enabled in the USB controller which
+ uses this PHY.
+
+Optional properties:
+- phy-supply: see phy-bindings.txt in this directory
+
+
+Example:
+ usb3_phy0: phy@78080 {
+ compatible = "amlogic,meson-gxl-usb3-phy";
+ #phy-cells = <0>;
+ reg = <0x0 0x78080 0x0 0x20>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+ phys = <&usb2_phys 0>, <&usb2_phys 1>;
+ };
--
2.10.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 2/5] phy: meson: add USB2 and USB3 PHY support for Meson GXL
From: Martin Blumenstingl @ 2016-11-26 14:56 UTC (permalink / raw)
To: linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, kishon-l0cyMroinI0,
khilman-rdvid1DuHRBWk0Htik3J/w, carlo-KA+7E9HrN00dnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, robh+dt-DgEjT+Ai2ygdnm+yROfE0A
Cc: catalin.marinas-5wv7dgnIgG8, will.deacon-5wv7dgnIgG8,
narmstrong-rdvid1DuHRBWk0Htik3J/w, Martin Blumenstingl
In-Reply-To: <20161126145635.24488-1-martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
This adds two new USB PHY drivers found on Meson GXL and GXM SoCs.
The registers for the USB2 PHY block handle a maximum of 4 ports (newer
SoCs may allow more ports, the driver handles this as long as the
register length is adjusted in the .dts). The PHY block theoretically
allows powering down each PHY port separately (by putting it into
"reset" state). Unfortunately this does not work (my board has 2 USB
ports, connected to port 1 and 2 of the dwc3's internal hub. When
leaving the third USB PHY disabled then the hub sees that a device is
plugged in, but it does not work: "usb usb1-port2: connect-debounce
failed").
The USB3 PHY will take care of enabling/disabling all available ports,
because the USB3 PHY also manages the mode of the USB2 PHYs.
The USB3 PHY actually has three purposes:
- it provides the USB3 PHY
- it handles the OTG device/host mode detection interrupt
- it notifies the corresponding USB2 PHYs of the OTG mode changes
On GXL and GXM SoCs one references all available USB2 PHY ports in the
USB3 PHY because all are connected to the same USB controller (thus the
mode will always match). This behavior is configurable via devicetree,
by passing (or not passing) a list of other ("child") PHYs which should
be configured by the USB3 PHY.
Unfortunately there are no datasheets available for any of these PHYs.
Both drivers were written by reading the reference drivers provided by
Amlogic and analyzing the registers on the kernel that was shipped with
my board.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
---
drivers/phy/Kconfig | 13 ++
drivers/phy/Makefile | 2 +
drivers/phy/phy-meson-gxl-usb2.c | 374 ++++++++++++++++++++++++++++++++++++++
drivers/phy/phy-meson-gxl-usb3.c | 377 +++++++++++++++++++++++++++++++++++++++
4 files changed, 766 insertions(+)
create mode 100644 drivers/phy/phy-meson-gxl-usb2.c
create mode 100644 drivers/phy/phy-meson-gxl-usb3.c
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 728e03f..ea74843 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -502,4 +502,17 @@ config PHY_MESON8B_USB2
and GXBB SoCs.
If unsure, say N.
+config PHY_MESON_GXL_USB
+ tristate "Meson GXL USB2 and USB3 PHY drivers"
+ default ARCH_MESON
+ depends on OF && (ARCH_MESON || COMPILE_TEST)
+ depends on USB_SUPPORT
+ select USB_COMMON
+ select GENERIC_PHY
+ select REGMAP_MMIO
+ help
+ Enable this to support the Meson USB2 and USB3 PHYs found in
+ Meson GXL SoCs.
+ If unsure, say N.
+
endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 0c7fdae..960a96e 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -61,3 +61,5 @@ obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o
obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o
+obj-$(CONFIG_PHY_MESON_GXL_USB) += phy-meson-gxl-usb2.o
+obj-$(CONFIG_PHY_MESON_GXL_USB) += phy-meson-gxl-usb3.o
diff --git a/drivers/phy/phy-meson-gxl-usb2.c b/drivers/phy/phy-meson-gxl-usb2.c
new file mode 100644
index 0000000..c081ce3
--- /dev/null
+++ b/drivers/phy/phy-meson-gxl-usb2.c
@@ -0,0 +1,374 @@
+/*
+ * Meson GXL USB2 PHY driver
+ *
+ * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/usb/of.h>
+
+/* bits [31:27] are read-only */
+#define U2P_R0 0x0
+ #define U2P_R0_BYPASS_SEL BIT(0)
+ #define U2P_R0_BYPASS_DM_EN BIT(1)
+ #define U2P_R0_BYPASS_DP_EN BIT(2)
+ #define U2P_R0_TXBITSTUFF_ENH BIT(3)
+ #define U2P_R0_TXBITSTUFF_EN BIT(4)
+ #define U2P_R0_DM_PULLDOWN BIT(5)
+ #define U2P_R0_DP_PULLDOWN BIT(6)
+ #define U2P_R0_DP_VBUS_VLD_EXT_SEL BIT(7)
+ #define U2P_R0_DP_VBUS_VLD_EXT BIT(8)
+ #define U2P_R0_ADP_PRB_EN BIT(9)
+ #define U2P_R0_ADP_DISCHARGE BIT(10)
+ #define U2P_R0_ADP_CHARGE BIT(11)
+ #define U2P_R0_DRV_VBUS BIT(12)
+ #define U2P_R0_ID_PULLUP BIT(13)
+ #define U2P_R0_LOOPBACK_EN_B BIT(14)
+ #define U2P_R0_OTG_DISABLE BIT(15)
+ #define U2P_R0_COMMON_ONN BIT(16)
+ #define U2P_R0_FSEL_SHIFT 17
+ #define U2P_R0_FSEL_MASK GENMASK(19, 17)
+ #define U2P_R0_REF_CLK_SEL_SHIFT 20
+ #define U2P_R0_REF_CLK_SEL_MASK GENMASK(21, 20)
+ #define U2P_R0_POWER_ON_RESET BIT(22)
+ #define U2P_R0_V_ATE_TEST_EN_B_SHIFT 23
+ #define U2P_R0_V_ATE_TEST_EN_B_MASK GENMASK(24, 23)
+ #define U2P_R0_ID_SET_ID_DQ BIT(25)
+ #define U2P_R0_ATE_RESET BIT(26)
+ #define U2P_R0_FSV_MINUS BIT(27)
+ #define U2P_R0_FSV_PLUS BIT(28)
+ #define U2P_R0_BYPASS_DM_DATA BIT(29)
+ #define U2P_R0_BYPASS_DP_DATA BIT(30)
+
+#define U2P_R1 0x4
+ #define U2P_R1_BURN_IN_TEST BIT(0)
+ #define U2P_R1_ACA_ENABLE BIT(1)
+ #define U2P_R1_DCD_ENABLE BIT(2)
+ #define U2P_R1_VDAT_SRC_EN_B BIT(3)
+ #define U2P_R1_VDAT_DET_EN_B BIT(4)
+ #define U2P_R1_CHARGES_SEL BIT(5)
+ #define U2P_R1_TX_PREEMP_PULSE_TUNE BIT(6)
+ #define U2P_R1_TX_PREEMP_AMP_TUNE_SHIFT 7
+ #define U2P_R1_TX_PREEMP_AMP_TUNE_MASK GENMASK(8, 7)
+ #define U2P_R1_TX_RES_TUNE_SHIFT 9
+ #define U2P_R1_TX_RES_TUNE_MASK GENMASK(10, 9)
+ #define U2P_R1_TX_RISE_TUNE_SHIFT 11
+ #define U2P_R1_TX_RISE_TUNE_MASK GENMASK(12, 11)
+ #define U2P_R1_TX_VREF_TUNE_SHIFT 13
+ #define U2P_R1_TX_VREF_TUNE_MASK GENMASK(16, 13)
+ #define U2P_R1_TX_FSLS_TUNE_SHIFT 17
+ #define U2P_R1_TX_FSLS_TUNE_MASK GENMASK(20, 17)
+ #define U2P_R1_TX_HSXV_TUNE_SHIFT 21
+ #define U2P_R1_TX_HSXV_TUNE_MASK GENMASK(22, 21)
+ #define U2P_R1_OTG_TUNE_SHIFT 23
+ #define U2P_R1_OTG_TUNE_MASK GENMASK(25, 23)
+ #define U2P_R1_SQRX_TUNE_SHIFT 26
+ #define U2P_R1_SQRX_TUNE_MASK GENMASK(28, 26)
+ #define U2P_R1_COMP_DIS_TUNE_SHIFT 29
+ #define U2P_R1_COMP_DIS_TUNE_MASK GENMASK(31, 29)
+
+/* bits [31:14] are read-only */
+#define U2P_R2 0x8
+ #define U2P_R2_DATA_IN_SHIFT 0
+ #define U2P_R2_DATA_IN_MASK GENMASK(3, 0)
+ #define U2P_R2_DATA_IN_EN_SHIFT 4
+ #define U2P_R2_DATA_IN_EN_MASK GENMASK(7, 4)
+ #define U2P_R2_ADDR_SHIFT 8
+ #define U2P_R2_ADDR_MASK GENMASK(11, 8)
+ #define U2P_R2_DATA_OUT_SEL BIT(12)
+ #define U2P_R2_CLK BIT(13)
+ #define U2P_R2_DATA_OUT_SHIFT 14
+ #define U2P_R2_DATA_OUT_MASK GENMASK(17, 14)
+ #define U2P_R2_ACA_PIN_RANGE_C BIT(18)
+ #define U2P_R2_ACA_PIN_RANGE_B BIT(19)
+ #define U2P_R2_ACA_PIN_RANGE_A BIT(20)
+ #define U2P_R2_ACA_PIN_GND BIT(21)
+ #define U2P_R2_ACA_PIN_FLOAT BIT(22)
+ #define U2P_R2_CHARGE_DETECT BIT(23)
+ #define U2P_R2_DEVICE_SESSION_VALID BIT(24)
+ #define U2P_R2_ADP_PROBE BIT(25)
+ #define U2P_R2_ADP_SENSE BIT(26)
+ #define U2P_R2_SESSION_END BIT(27)
+ #define U2P_R2_VBUS_VALID BIT(28)
+ #define U2P_R2_B_VALID BIT(29)
+ #define U2P_R2_A_VALID BIT(30)
+ #define U2P_R2_ID_DIG BIT(31)
+
+#define U2P_R3 0xc
+
+#define PHY_PORT_RESOURCE_SIZE 0x20
+
+#define RESET_COMPLETE_TIME 500
+
+struct phy_meson_gxl_usb2_priv {
+ struct regmap *regmap;
+ enum phy_mode mode;
+};
+
+struct phy_meson_gxl_usb2_drv {
+ void __iomem *base;
+ int num_ports;
+ struct phy **ports;
+ struct clk *clk_usb;
+ struct clk *clk_usb_ddr;
+};
+
+static const struct regmap_config phy_meson_gxl_usb2_regmap_conf = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = U2P_R3,
+};
+
+static int phy_meson_gxl_usb2_set_mode(struct phy *phy, enum phy_mode mode)
+{
+ struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
+
+ switch (mode) {
+ case PHY_MODE_USB_HOST:
+ case PHY_MODE_USB_OTG:
+ regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DM_PULLDOWN,
+ U2P_R0_DM_PULLDOWN);
+ regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DP_PULLDOWN,
+ U2P_R0_DP_PULLDOWN);
+ regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_ID_PULLUP, 0);
+ break;
+
+ case PHY_MODE_USB_DEVICE:
+ regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DM_PULLDOWN,
+ 0);
+ regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DP_PULLDOWN,
+ 0);
+ regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_ID_PULLUP,
+ U2P_R0_ID_PULLUP);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* reset the PHY and wait until settings are stabilized */
+ regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET,
+ U2P_R0_POWER_ON_RESET);
+ udelay(RESET_COMPLETE_TIME);
+ regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET, 0);
+ udelay(RESET_COMPLETE_TIME);
+
+ priv->mode = mode;
+
+ return 0;
+}
+
+static int phy_meson_gxl_usb2_power_off(struct phy *phy)
+{
+ struct phy_meson_gxl_usb2_drv *drv_priv =
+ dev_get_drvdata(phy->dev.parent);
+ struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
+
+ /* power off the PHY by putting it into reset mode */
+ regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET,
+ U2P_R0_POWER_ON_RESET);
+
+ clk_disable_unprepare(drv_priv->clk_usb_ddr);
+ clk_disable_unprepare(drv_priv->clk_usb);
+
+ return 0;
+}
+
+static int phy_meson_gxl_usb2_power_on(struct phy *phy)
+{
+ struct phy_meson_gxl_usb2_drv *drv_priv =
+ dev_get_drvdata(phy->dev.parent);
+ struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
+ int ret;
+
+ ret = clk_prepare_enable(drv_priv->clk_usb);
+ if (ret) {
+ dev_err(&phy->dev, "Failed to enable USB clock\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(drv_priv->clk_usb_ddr);
+ if (ret) {
+ clk_disable_unprepare(drv_priv->clk_usb);
+
+ dev_err(&phy->dev, "Failed to enable USB DDR clock\n");
+ return ret;
+ }
+
+ /* power on the PHY by taking it out of reset mode */
+ regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET, 0);
+
+ ret = phy_meson_gxl_usb2_set_mode(phy, priv->mode);
+ if (ret) {
+ phy_meson_gxl_usb2_power_off(phy);
+
+ dev_err(&phy->dev, "Failed to initialize PHY with mode %d\n",
+ priv->mode);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct phy_ops phy_meson_gxl_usb2_ops = {
+ .power_on = phy_meson_gxl_usb2_power_on,
+ .power_off = phy_meson_gxl_usb2_power_off,
+ .set_mode = phy_meson_gxl_usb2_set_mode,
+ .owner = THIS_MODULE,
+};
+
+static struct phy *phy_meson_gxl_usb2_of_xlate(struct device *dev,
+ struct of_phandle_args *args)
+{
+ struct phy_meson_gxl_usb2_drv *priv = dev_get_drvdata(dev);
+ int port;
+
+ if (args->args_count != 1) {
+ dev_err(dev, "Invalid number of cells in 'phy' property\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ port = args->args[0];
+ if (WARN_ON(port >= priv->num_ports))
+ return ERR_PTR(-ENODEV);
+
+ return priv->ports[port];
+}
+
+static int phy_meson_gxl_usb2_probe_port(struct device *dev, int port)
+{
+ struct phy_meson_gxl_usb2_drv *drv_priv = dev_get_drvdata(dev);
+ struct phy_meson_gxl_usb2_priv *phy_priv;
+ struct phy *phy;
+ void __iomem *port_base;
+
+ phy_priv = devm_kzalloc(dev, sizeof(*phy_priv), GFP_KERNEL);
+ if (!phy_priv)
+ return -ENOMEM;
+
+ switch (of_usb_get_dr_mode_by_phy(dev->of_node, port)) {
+ case USB_DR_MODE_PERIPHERAL:
+ phy_priv->mode = PHY_MODE_USB_DEVICE;
+ break;
+ case USB_DR_MODE_OTG:
+ phy_priv->mode = PHY_MODE_USB_OTG;
+ break;
+ case USB_DR_MODE_HOST:
+ default:
+ phy_priv->mode = PHY_MODE_USB_HOST;
+ break;
+ }
+
+ phy = devm_phy_create(dev, NULL, &phy_meson_gxl_usb2_ops);
+ if (IS_ERR(phy)) {
+ dev_err(dev, "failed to create PHY port %d\n", port);
+ return PTR_ERR(phy);
+ }
+
+ port_base = drv_priv->base + (port * PHY_PORT_RESOURCE_SIZE);
+ phy_priv->regmap = devm_regmap_init_mmio(&phy->dev, port_base,
+ &phy_meson_gxl_usb2_regmap_conf);
+ if (IS_ERR(phy_priv->regmap))
+ return PTR_ERR(phy_priv->regmap);
+
+ phy_set_drvdata(phy, phy_priv);
+
+ drv_priv->ports[port] = phy;
+
+ return 0;
+}
+
+static int phy_meson_gxl_usb2_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct phy_meson_gxl_usb2_drv *priv;
+ struct phy_provider *phy_provider;
+ struct resource *res;
+ int i, ret;
+
+ ret = device_reset(dev);
+ if (ret) {
+ dev_err(dev, "failed to reset device\n");
+ return ret;
+ }
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, priv);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ priv->num_ports = resource_size(res) / PHY_PORT_RESOURCE_SIZE;
+ if (priv->num_ports < 1) {
+ dev_err(dev, "specified memory range is too small\n");
+ return -EINVAL;
+ }
+
+ priv->ports = devm_kcalloc(dev, priv->num_ports, sizeof(*priv->ports),
+ GFP_KERNEL);
+ if (!priv->ports)
+ return -ENOMEM;
+
+ priv->clk_usb = devm_clk_get(dev, "usb");
+ if (IS_ERR(priv->clk_usb)) {
+ dev_err(dev, "failed to get USB clock\n");
+ return PTR_ERR(priv->clk_usb);
+ }
+
+ priv->clk_usb_ddr = devm_clk_get(dev, "usb_ddr");
+ if (IS_ERR(priv->clk_usb_ddr)) {
+ dev_err(dev, "failed to get USB DDR clock\n");
+ return PTR_ERR(priv->clk_usb_ddr);
+ }
+
+ for (i = 0; i < priv->num_ports; i++) {
+ ret = phy_meson_gxl_usb2_probe_port(dev, i);
+ if (ret)
+ return ret;
+ }
+
+ phy_provider = devm_of_phy_provider_register(dev,
+ phy_meson_gxl_usb2_of_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id phy_meson_gxl_usb2_of_match[] = {
+ { .compatible = "amlogic,meson-gxl-usb2-phy", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, phy_meson_gxl_usb2_of_match);
+
+static struct platform_driver phy_meson_gxl_usb2_driver = {
+ .probe = phy_meson_gxl_usb2_probe,
+ .driver = {
+ .name = "phy-meson-gxl-usb2",
+ .of_match_table = phy_meson_gxl_usb2_of_match,
+ },
+};
+module_platform_driver(phy_meson_gxl_usb2_driver);
+
+MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>");
+MODULE_DESCRIPTION("Meson GXL USB2 PHY driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/phy/phy-meson-gxl-usb3.c b/drivers/phy/phy-meson-gxl-usb3.c
new file mode 100644
index 0000000..90a4028
--- /dev/null
+++ b/drivers/phy/phy-meson-gxl-usb3.c
@@ -0,0 +1,377 @@
+/*
+ * Meson GXL USB3 PHY driver
+ *
+ * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/reset.h>
+#include <linux/regmap.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/usb/of.h>
+#include <linux/workqueue.h>
+
+#define USB_R0 0x00
+ #define USB_R0_P30_FSEL_SHIFT 0
+ #define USB_R0_P30_FSEL_MASK GENMASK(5, 0)
+ #define USB_R0_P30_PHY_RESET BIT(6)
+ #define USB_R0_P30_TEST_POWERDOWN_HSP BIT(7)
+ #define USB_R0_P30_TEST_POWERDOWN_SSP BIT(8)
+ #define USB_R0_P30_ACJT_LEVEL_SHIFT 9
+ #define USB_R0_P30_ACJT_LEVEL_MASK GENMASK(13, 9)
+ #define USB_R0_P30_TX_BOOST_LEVEL_SHIFT 14
+ #define USB_R0_P30_TX_BOOST_LEVEL_MASK GENMASK(16, 14)
+ #define USB_R0_P30_LANE0_TX2RX_LOOPBACK BIT(17)
+ #define USB_R0_P30_LANE0_EXT_PCLK_REQ BIT(18)
+ #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_SHIFT 19
+ #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK GENMASK(28, 19)
+ #define USB_R0_U2D_SS_SCALEDOWN_MODE_SHIFT 29
+ #define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK GENMASK(30, 29)
+ #define USB_R0_U2D_ACT BIT(31)
+
+#define USB_R1 0x04
+ #define USB_R1_U3H_BIGENDIAN_GS BIT(0)
+ #define USB_R1_U3H_PME_ENABLE BIT(1)
+ #define USB_R1_U3H_HUB_PORT_OVERCURRENT_SHIFT 2
+ #define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK GENMASK(6, 2)
+ #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_SHIFT 7
+ #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(11, 7)
+ #define USB_R1_U3H_HOST_U2_PORT_DISABLE_SHIFT 12
+ #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(15, 12)
+ #define USB_R1_U3H_HOST_U3_PORT_DISABLE BIT(16)
+ #define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT BIT(17)
+ #define USB_R1_U3H_HOST_MSI_ENABLE BIT(18)
+ #define USB_R1_U3H_FLADJ_30MHZ_REG_SHIFT 19
+ #define USB_R1_U3H_FLADJ_30MHZ_REG_MASK GENMASK(24, 19)
+ #define USB_R1_P30_PCS_TX_SWING_FULL_SHIFT 25
+ #define USB_R1_P30_PCS_TX_SWING_FULL_MASK GENMASK(31, 25)
+
+#define USB_R2 0x08
+ #define USB_R2_P30_CR_DATA_IN_SHIFT 0
+ #define USB_R2_P30_CR_DATA_IN_MASK GENMASK(15, 0)
+ #define USB_R2_P30_CR_READ BIT(16)
+ #define USB_R2_P30_CR_WRITE BIT(17)
+ #define USB_R2_P30_CR_CAP_ADDR BIT(18)
+ #define USB_R2_P30_CR_CAP_DATA BIT(19)
+ #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_SHIFT 20
+ #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(25, 20)
+ #define USB_R2_P30_PCS_TX_DEEMPH_6DB_SHIFT 26
+ #define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK GENMASK(31, 26)
+
+#define USB_R3 0x0c
+ #define USB_R3_P30_SSC_ENABLE BIT(0)
+ #define USB_R3_P30_SSC_RANGE_SHIFT 1
+ #define USB_R3_P30_SSC_RANGE_MASK GENMASK(3, 1)
+ #define USB_R3_P30_SSC_REF_CLK_SEL_SHIFT 4
+ #define USB_R3_P30_SSC_REF_CLK_SEL_MASK GENMASK(12, 4)
+ #define USB_R3_P30_REF_SSP_EN BIT(13)
+ #define USB_R3_P30_LOS_BIAS_SHIFT 16
+ #define USB_R3_P30_LOS_BIAS_MASK GENMASK(18, 16)
+ #define USB_R3_P30_LOS_LEVEL_SHIFT 19
+ #define USB_R3_P30_LOS_LEVEL_MASK GENMASK(23, 19)
+ #define USB_R3_P30_MPLL_MULTIPLIER_SHIFT 24
+ #define USB_R3_P30_MPLL_MULTIPLIER_MASK GENMASK(30, 24)
+
+#define USB_R4 0x10
+ #define USB_R4_P21_PORT_RESET_0 BIT(0)
+ #define USB_R4_P21_SLEEP_M0 BIT(1)
+ #define USB_R4_MEM_PD_SHIFT 2
+ #define USB_R4_MEM_PD_MASK GENMASK(3, 2)
+ #define USB_R4_P21_ONLY BIT(4)
+
+#define USB_R5 0x14
+ #define USB_R5_ID_DIG_SYNC BIT(0)
+ #define USB_R5_ID_DIG_REG BIT(1)
+ #define USB_R5_ID_DIG_CFG_SHIFT 2
+ #define USB_R5_ID_DIG_CFG_MASK GENMASK(3, 2)
+ #define USB_R5_ID_DIG_EN_0 BIT(4)
+ #define USB_R5_ID_DIG_EN_1 BIT(5)
+ #define USB_R5_ID_DIG_CURR BIT(6)
+ #define USB_R5_ID_DIG_IRQ BIT(7)
+ #define USB_R5_ID_DIG_TH_SHIFT 8
+ #define USB_R5_ID_DIG_TH_MASK GENMASK(15, 8)
+ #define USB_R5_ID_DIG_CNT_SHIFT 16
+ #define USB_R5_ID_DIG_CNT_MASK GENMASK(23, 16)
+
+/* read-only register */
+#define USB_R6 0x18
+ #define USB_R6_P30_CR_DATA_OUT_SHIFT 0
+ #define USB_R6_P30_CR_DATA_OUT_MASK GENMASK(15, 0)
+ #define USB_R6_P30_CR_ACK BIT(16)
+
+#define RESET_COMPLETE_TIME 500
+
+struct phy_meson_gxl_usb3_priv {
+ struct regmap *regmap;
+ struct delayed_work otg_work;
+ struct phy *this_phy;
+ int num_usb2_phys;
+ struct phy **usb2_phys;
+};
+
+static const struct regmap_config phy_meson_gxl_usb3_regmap_conf = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = USB_R6,
+};
+
+static int phy_meson_gxl_usb3_update_mode(struct phy *phy)
+{
+ struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
+ u32 val;
+ enum phy_mode mode;
+ int i, ret;
+
+ ret = regmap_read(priv->regmap, USB_R5, &val);
+ if (ret)
+ return ret;
+
+ if (val & USB_R5_ID_DIG_CURR) {
+ mode = PHY_MODE_USB_DEVICE;
+
+ regmap_update_bits(priv->regmap, USB_R0, USB_R0_U2D_ACT,
+ USB_R0_U2D_ACT);
+ regmap_update_bits(priv->regmap, USB_R4, USB_R4_P21_SLEEP_M0,
+ USB_R4_P21_SLEEP_M0);
+ } else {
+ mode = PHY_MODE_USB_HOST;
+
+ regmap_update_bits(priv->regmap, USB_R0, USB_R0_U2D_ACT, 0);
+ regmap_update_bits(priv->regmap, USB_R4, USB_R4_P21_SLEEP_M0,
+ 0);
+ }
+
+ /* inform the USB2 PHY that we have changed the mode */
+ for (i = 0; i < priv->num_usb2_phys; i++) {
+ ret = phy_set_mode(priv->usb2_phys[i], mode);
+ if (ret) {
+ dev_err(&phy->dev,
+ "Failed to update usb2-phy #%d mode to %d\n",
+ i, mode);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static void phy_meson_gxl_usb3_work(struct work_struct *data)
+{
+ struct phy_meson_gxl_usb3_priv *priv =
+ container_of(data, struct phy_meson_gxl_usb3_priv,
+ otg_work.work);
+
+ phy_meson_gxl_usb3_update_mode(priv->this_phy);
+
+ /* unmask IRQs which may have arrived in the meantime */
+ regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_IRQ, 0);
+}
+
+static int phy_meson_gxl_usb3_init(struct phy *phy)
+{
+ struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
+ int i, ret;
+
+ for (i = 0; i < priv->num_usb2_phys; i++) {
+ ret = phy_init(priv->usb2_phys[i]);
+ if (ret) {
+ dev_err(&phy->dev,
+ "Failed to initialize related usb2-phy #%d\n",
+ i);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int phy_meson_gxl_usb3_exit(struct phy *phy)
+{
+ struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
+ int i, ret;
+
+ for (i = 0; i < priv->num_usb2_phys; i++) {
+ ret = phy_exit(priv->usb2_phys[i]);
+ if (ret) {
+ dev_err(&phy->dev,
+ "Failed to exit related usb2-phy #%d\n", i);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int phy_meson_gxl_usb3_power_on(struct phy *phy)
+{
+ struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
+ int i, ret;
+
+ for (i = 0; i < priv->num_usb2_phys; i++) {
+ ret = phy_power_on(priv->usb2_phys[i]);
+ if (ret) {
+ dev_err(&phy->dev,
+ "Failed to power on related usb2-phy #%d\n",
+ i);
+ return ret;
+ }
+ }
+
+ regmap_update_bits(priv->regmap, USB_R1,
+ USB_R1_U3H_FLADJ_30MHZ_REG_MASK,
+ 0x20 << USB_R1_U3H_FLADJ_30MHZ_REG_SHIFT);
+
+ regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_0,
+ USB_R5_ID_DIG_EN_0);
+ regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_1,
+ USB_R5_ID_DIG_EN_1);
+ regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_TH_MASK,
+ 0xff << USB_R5_ID_DIG_TH_SHIFT);
+
+ return phy_meson_gxl_usb3_update_mode(phy);
+}
+
+static int phy_meson_gxl_usb3_power_off(struct phy *phy)
+{
+ struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
+ int i, ret;
+
+ for (i = 0; i < priv->num_usb2_phys; i++) {
+ ret = phy_power_off(priv->usb2_phys[i]);
+ if (ret) {
+ dev_err(&phy->dev,
+ "Failed to power off related usb2-phy #%d\n",
+ i);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static irqreturn_t phy_meson_gxl_usb3_irq(int irq, void *data)
+{
+ u32 val;
+ struct phy_meson_gxl_usb3_priv *priv = data;
+
+ regmap_read(priv->regmap, USB_R5, &val);
+ if (!(val & USB_R5_ID_DIG_IRQ)) {
+ dev_err(&priv->this_phy->dev, "spurious interrupt\n");
+ return IRQ_NONE;
+ }
+
+ schedule_delayed_work(&priv->otg_work, msecs_to_jiffies(10));
+
+ /* acknowledge the IRQ */
+ regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_IRQ, 0);
+
+ return IRQ_HANDLED;
+}
+
+static const struct phy_ops phy_meson_gxl_usb3_ops = {
+ .init = phy_meson_gxl_usb3_init,
+ .exit = phy_meson_gxl_usb3_exit,
+ .power_on = phy_meson_gxl_usb3_power_on,
+ .power_off = phy_meson_gxl_usb3_power_off,
+ .owner = THIS_MODULE,
+};
+
+static int phy_meson_gxl_usb3_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct phy_meson_gxl_usb3_priv *priv;
+ struct resource *res;
+ struct phy *phy;
+ struct phy_provider *phy_provider;
+ void __iomem *base;
+ int i, irq;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ priv->regmap = devm_regmap_init_mmio(dev, base,
+ &phy_meson_gxl_usb3_regmap_conf);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq >= 0) {
+ INIT_DELAYED_WORK(&priv->otg_work, phy_meson_gxl_usb3_work);
+
+ irq = devm_request_irq(dev, irq, phy_meson_gxl_usb3_irq,
+ IRQF_SHARED, dev_name(dev),
+ priv);
+ if (irq < 0) {
+ dev_err(dev, "could not register IRQ handler (%d)\n",
+ irq);
+ return -EINVAL;
+ }
+ }
+
+ priv->num_usb2_phys = of_count_phandle_with_args(np, "phys",
+ "#phy-cells");
+
+ priv->usb2_phys = devm_kcalloc(dev, priv->num_usb2_phys,
+ sizeof(*priv->usb2_phys), GFP_KERNEL);
+ if (!priv->usb2_phys)
+ return -ENOMEM;
+
+ for (i = 0; i < priv->num_usb2_phys; i++) {
+ priv->usb2_phys[i] = devm_of_phy_get_by_index(dev, np, i);
+ if (IS_ERR(priv->usb2_phys[i])) {
+ dev_err(dev, "failed to get related usb2-phy #%d", i);
+ return PTR_ERR(priv->usb2_phys[i]);
+ }
+ }
+
+ phy = devm_phy_create(dev, np, &phy_meson_gxl_usb3_ops);
+ if (IS_ERR(phy)) {
+ dev_err(dev, "failed to create PHY\n");
+ return PTR_ERR(phy);
+ }
+
+ phy_set_drvdata(phy, priv);
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id phy_meson_gxl_usb3_of_match[] = {
+ { .compatible = "amlogic,meson-gxl-usb3-phy", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, phy_meson_gxl_usb3_of_match);
+
+static struct platform_driver phy_meson_gxl_usb3_driver = {
+ .probe = phy_meson_gxl_usb3_probe,
+ .driver = {
+ .name = "phy-meson-gxl-usb3",
+ .of_match_table = phy_meson_gxl_usb3_of_match,
+ },
+};
+module_platform_driver(phy_meson_gxl_usb3_driver);
+
+MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>");
+MODULE_DESCRIPTION("Meson GXL USB3 PHY driver");
+MODULE_LICENSE("GPL");
--
2.10.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 3/5] arm64: dts: meson-gxl: add USB support
From: Martin Blumenstingl @ 2016-11-26 14:56 UTC (permalink / raw)
To: linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, kishon-l0cyMroinI0,
khilman-rdvid1DuHRBWk0Htik3J/w, carlo-KA+7E9HrN00dnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, robh+dt-DgEjT+Ai2ygdnm+yROfE0A
Cc: catalin.marinas-5wv7dgnIgG8, will.deacon-5wv7dgnIgG8,
narmstrong-rdvid1DuHRBWk0Htik3J/w, Martin Blumenstingl
In-Reply-To: <20161126145635.24488-1-martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
This adds USB support the the Meson GXL SoC. On most devices only the
dwc3 controller is used. It has an internal USB hub which provides two
ports. The PHYs for these ports are defined through the USB3 PHY, which
is ensures that all PHYs are using the same mode (because all of them
are used by the same controller).
Signed-off-by: Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
---
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 49 ++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
index 3af54dc..99ac900 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
@@ -44,9 +44,58 @@
#include "meson-gx.dtsi"
#include <dt-bindings/clock/gxbb-clkc.h>
#include <dt-bindings/gpio/meson-gxl-gpio.h>
+#include <dt-bindings/reset/amlogic,meson-gxbb-reset.h>
/ {
compatible = "amlogic,meson-gxl";
+
+ soc {
+
+ usb0: usb@c9000000 {
+ compatible = "snps,dwc3";
+ reg = <0x0 0xc9000000 0x0 0x100000>;
+ interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+ phys = <&usb3_phy0>;
+ phy-names = "usb3-phy";
+ dr_mode = "host";
+ maximum-speed = "high-speed";
+ snps,dis_u2_susphy_quirk;
+ };
+
+ usb1: usb@c9100000 {
+ compatible = "snps,dwc2";
+ reg = <0x0 0xc9100000 0x0 0x40000>;
+ interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clkc CLKID_USB>;
+ clock-names = "otg";
+ dr_mode = "host";
+ status = "disabled";
+ };
+ };
+};
+
+&apb {
+ usb2_phys: phy@78000 {
+ compatible = "amlogic,meson-gxl-usb2-phy";
+ #phy-cells = <1>;
+ reg = <0x0 0x78000 0x0 0x80>;
+ clocks = <&clkc CLKID_USB1>, <&clkc CLKID_USB1_DDR_BRIDGE>;
+ clock-names = "usb", "usb_ddr";
+ resets = <&reset RESET_USB_OTG>;
+ status = "disabled";
+ };
+
+ usb3_phy0: phy@78080 {
+ compatible = "amlogic,meson-gxl-usb3-phy";
+ #phy-cells = <0>;
+ reg = <0x0 0x78080 0x0 0x20>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+
+ /* dwc3 on GXL enables 2 USB ports on the internal hub */
+ phys = <&usb2_phys 0>, <&usb2_phys 1>;
+
+ status = "disabled";
+ };
};
ðmac {
--
2.10.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 4/5] ARM64: dts: meson-gxm: add GXM specific USB configuration
From: Martin Blumenstingl @ 2016-11-26 14:56 UTC (permalink / raw)
To: linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, kishon-l0cyMroinI0,
khilman-rdvid1DuHRBWk0Htik3J/w, carlo-KA+7E9HrN00dnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, robh+dt-DgEjT+Ai2ygdnm+yROfE0A
Cc: catalin.marinas-5wv7dgnIgG8, will.deacon-5wv7dgnIgG8,
narmstrong-rdvid1DuHRBWk0Htik3J/w, Martin Blumenstingl
In-Reply-To: <20161126145635.24488-1-martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
The USB configuration on GXM is slightly different than on GXL. On GXM
the dwc2 controller is limited (via GHWCFG2_OP_MODE_MASK) to "device
mode".
The dwc3 controller's internal hub has 3 ports (instead of 2 on GXL)
enabled. It's hardware configuration limits it (via DWC3_GHWPARAMS0)
to host mode only.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
---
arch/arm64/boot/dts/amlogic/meson-gxm.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
index 2b1d276e..0a6b224 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
@@ -121,3 +121,13 @@
clock-indices = <0 1>;
clock-output-names = "vbig", "vlittle";
};
+
+&usb3_phy0 {
+ /* dwc3 on GXM enables 3 USB ports on the internal hub */
+ phys = <&usb2_phys 0>, <&usb2_phys 1>, <&usb2_phys 2>;
+};
+
+&usb1 {
+ /* the dwc2 hardware configuration on GXM only allows device mode */
+ dr_mode = "device";
+};
--
2.10.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 5/5] ARM64: dts: meson-gx-p23x-q20x: enable USB on P23x and Q20x boards
From: Martin Blumenstingl @ 2016-11-26 14:56 UTC (permalink / raw)
To: linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, kishon-l0cyMroinI0,
khilman-rdvid1DuHRBWk0Htik3J/w, carlo-KA+7E9HrN00dnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, robh+dt-DgEjT+Ai2ygdnm+yROfE0A
Cc: catalin.marinas-5wv7dgnIgG8, will.deacon-5wv7dgnIgG8,
narmstrong-rdvid1DuHRBWk0Htik3J/w, Martin Blumenstingl
In-Reply-To: <20161126145635.24488-1-martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
All four devices are only using the dwc3 controller. The actual ports
are provided by dwc3's internal USB hub.
The implementation on P230, P231 and Q201 seems identical: the USB VBUS
supply seems to be hard-wired, while on Q200 the USB VBUS is provided
by GPIOAO_5.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
---
arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 12 ++++++++++++
arch/arm64/boot/dts/amlogic/meson-gxm-s912-q200.dts | 17 +++++++++++++++++
2 files changed, 29 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
index 7a078be..360c91d 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
@@ -188,3 +188,15 @@
ðmac {
status = "okay";
};
+
+&usb2_phys {
+ status = "okay";
+};
+
+&usb3_phy0 {
+ status = "okay";
+};
+
+&usb0 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-s912-q200.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-s912-q200.dts
index 5dbc660..6c28e87 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxm-s912-q200.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-s912-q200.dts
@@ -49,6 +49,19 @@
/ {
compatible = "amlogic,q200", "amlogic,s912", "amlogic,meson-gxm";
model = "Amlogic Meson GXM (S912) Q200 Development Board";
+
+ usb_pwr: regulator-usb-pwrs {
+ compatible = "regulator-fixed";
+
+ regulator-name = "USB_PWR";
+
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+
+ /* signal name in schematic: USB_PWR_EN */
+ gpio = <&gpio GPIODV_24 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
};
/* Q200 has exclusive choice between internal or external PHY */
@@ -75,3 +88,7 @@
max-speed = <1000>;
};
};
+
+&usb3_phy0 {
+ phy-supply = <&usb_pwr>;
+};
--
2.10.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 00/39] mtd: nand: denali: 2nd round of Denali NAND IP patch bomb
From: Masahiro Yamada @ 2016-11-26 18:05 UTC (permalink / raw)
To: linux-mtd
Cc: Masahiro Yamada, devicetree, linux-kernel, Boris Brezillon,
Marek Vasut, Brian Norris, Richard Weinberger, David Woodhouse,
Cyrille Pitchen, Rob Herring, Mark Rutland
As I said in the 1st round series, I am tackling on this driver
to use it for my SoCs.
The previous series was just cosmetic things, but this series
includes *real* changes.
After some more cleanups, I will start to add changes that
are really necessary.
One of the biggest problems I want to solve is a bunch of
hard-coded parameters that prevent me from using this driver for
my SoCs.
I will introduce capability flags that are associated with DT
compatible and make platform-dependent parameters overridable.
I still have lots of reworks to get done (so probably 3rd round
series will come), but I hope it is getting better and
I am showing a big picture now.
Masahiro Yamada (39):
mtd: nand: allow to set only one of ECC size and ECC strength from DT
mtd: nand: denali: remove unused CONFIG option and macros
mtd: nand: denali: remove redundant define of BANK(x)
mtd: nand: denali: remove more unused struct members
mtd: nand: denali: fix comment of denali_nand_info::flash_mem
mtd: nand: denali: fix write_oob_data() function
mtd: nand: denali: transfer OOB only when oob_required is set
mtd: nand: denali: introduce capability flag
mtd: nand: denali: fix erased page check code
mtd: nand: denali: remove redundant if conditional of erased_check
mtd: nand: denali: increment ecc_stats.failed by one per error
mtd: nand: denali: return 0 for uncorrectable ECC error
mtd: nand: denali: increment ecc_stats->corrected
mtd: nand: denali: replace uint{8/16/32}_t with u{8/16/32}
mtd: nand: denali: improve readability of handle_ecc()
mtd: nand: denali: rename handle_ecc() to denali_sw_ecc_fixup()
mtd: nand: denali: support HW_ECC_FIXUP capability
mtd: nand: denali: move denali_read_page_raw() above
denali_read_page()
mtd: nand: denali: perform erased check against raw transferred page
mtd: nand: denali_dt: enable HW_ECC_FIXUP capability for DT platform
mtd: nand: denali: support 64bit capable DMA engine
mtd: nand: denali_dt: remove dma-mask DT property
mtd: nand: denali_dt: use pdev instead of ofdev for platform_device
mtd: nand: denali: add NEW_N_BANKS_FORMAT capability
mtd: nand: denali: use nand_chip to hold frequently accessed data
mtd: nand: denali: call nand_set_flash_node() to set DT node
mtd: nand: denali: do not set mtd->name
mtd: nand: denali: move multi NAND fixup code to a helper function
mtd: nand: denali: refactor multi NAND fixup code in more generic way
mtd: nand: denali: set DEVICES_CONNECTED 1 if not set
mtd: nand: denali: remove meaningless writes to read-only registers
mtd: nand: denali: remove unnecessary writes to ECC_CORRECTION
mtd: nand: denali: support 1024 byte ECC step size
mtd: nand: denali: fix the condition for 15 bit ECC strength
mtd: nand: denali: calculate ecc.strength and ecc.bytes generically
mtd: nand: denali: allow to use SoC-specific ECC strength
mtd: nand: denali: support "nand-ecc-strength" DT property
mtd: nand: denali: remove Toshiba, Hynix specific fixup code
mtd: nand: denali_dt: add compatible strings for UniPhier SoC variants
.../devicetree/bindings/mtd/denali-nand.txt | 19 +-
drivers/mtd/nand/Kconfig | 11 -
drivers/mtd/nand/denali.c | 740 ++++++++++++---------
drivers/mtd/nand/denali.h | 84 +--
drivers/mtd/nand/denali_dt.c | 95 ++-
drivers/mtd/nand/denali_pci.c | 2 +
drivers/mtd/nand/nand_base.c | 6 -
7 files changed, 515 insertions(+), 442 deletions(-)
--
2.7.4
^ permalink raw reply
* [PATCH 22/39] mtd: nand: denali_dt: remove dma-mask DT property
From: Masahiro Yamada @ 2016-11-26 18:06 UTC (permalink / raw)
To: linux-mtd
Cc: Masahiro Yamada, devicetree, linux-kernel, Boris Brezillon,
Marek Vasut, Brian Norris, Richard Weinberger, David Woodhouse,
Cyrille Pitchen, Rob Herring, Mark Rutland
In-Reply-To: <1480183585-592-1-git-send-email-yamada.masahiro@socionext.com>
The driver sets appropriate DMA mask. Delete the "dma-mask" DT
property. Refer to the Link tag for negative opinions for this
binding.
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Link: https://lkml.org/lkml/2016/2/8/57
---
Documentation/devicetree/bindings/mtd/denali-nand.txt | 2 --
drivers/mtd/nand/denali_dt.c | 9 ---------
2 files changed, 11 deletions(-)
diff --git a/Documentation/devicetree/bindings/mtd/denali-nand.txt b/Documentation/devicetree/bindings/mtd/denali-nand.txt
index b04d03a..603110b 100644
--- a/Documentation/devicetree/bindings/mtd/denali-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/denali-nand.txt
@@ -5,7 +5,6 @@ Required properties:
- reg : should contain registers location and length for data and reg.
- reg-names: Should contain the reg names "nand_data" and "denali_reg"
- interrupts : The interrupt number.
- - dm-mask : DMA bit mask
The device tree may optionally contain sub-nodes describing partitions of the
address space. See partition.txt for more detail.
@@ -19,5 +18,4 @@ nand: nand@ff900000 {
reg = <0xff900000 0x100000>, <0xffb80000 0x10000>;
reg-names = "nand_data", "denali_reg";
interrupts = <0 144 4>;
- dma-mask = <0xffffffff>;
};
diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c
index 9dcd203..6a486a7 100644
--- a/drivers/mtd/nand/denali_dt.c
+++ b/drivers/mtd/nand/denali_dt.c
@@ -40,8 +40,6 @@ static const struct of_device_id denali_nand_dt_ids[] = {
MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
-static u64 denali_dma_mask;
-
static int denali_dt_probe(struct platform_device *ofdev)
{
struct resource *denali_reg, *nand_data;
@@ -79,13 +77,6 @@ static int denali_dt_probe(struct platform_device *ofdev)
if (IS_ERR(denali->flash_mem))
return PTR_ERR(denali->flash_mem);
- if (!of_property_read_u32(ofdev->dev.of_node,
- "dma-mask", (u32 *)&denali_dma_mask)) {
- denali->dev->dma_mask = &denali_dma_mask;
- } else {
- denali->dev->dma_mask = NULL;
- }
-
dt->clk = devm_clk_get(&ofdev->dev, NULL);
if (IS_ERR(dt->clk)) {
dev_err(&ofdev->dev, "no clk available\n");
--
2.7.4
^ permalink raw reply related
* [PATCH 33/39] mtd: nand: denali: support 1024 byte ECC step size
From: Masahiro Yamada @ 2016-11-26 18:06 UTC (permalink / raw)
To: linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: Masahiro Yamada, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Boris Brezillon, Marek Vasut,
Brian Norris, Richard Weinberger, David Woodhouse,
Cyrille Pitchen, Rob Herring, Mark Rutland
In-Reply-To: <1480183585-592-1-git-send-email-yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A@public.gmane.org>
This driver was originally written for the Intel MRST platform with
several platform specific parameters hard-coded. Another thing we
need to fix is the hard-coded ECC step size. Currently, it is
defined as follows:
#define ECC_SECTOR_SIZE 512
(somehow, it is defined in both denali.c and denali.h)
This must be avoided because the Denali IP supports 1024 byte ECC
size as well. Add a new flag DENALI_CAPS_ECC_SIZE_1024. If it is
specified, ecc.size is set to 1024, otherwise set to 512.
We can use "nand-ecc-step-size" DT property to override the ecc.size
if we want, but this capability flag can provide the reasonable
default because it is associated with the DT compatible strings.
Signed-off-by: Masahiro Yamada <yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A@public.gmane.org>
---
.../devicetree/bindings/mtd/denali-nand.txt | 4 ++++
drivers/mtd/nand/denali.c | 26 +++++++++++-----------
drivers/mtd/nand/denali.h | 3 +--
3 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/Documentation/devicetree/bindings/mtd/denali-nand.txt b/Documentation/devicetree/bindings/mtd/denali-nand.txt
index 603110b..e9d5818 100644
--- a/Documentation/devicetree/bindings/mtd/denali-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/denali-nand.txt
@@ -6,6 +6,10 @@ Required properties:
- reg-names: Should contain the reg names "nand_data" and "denali_reg"
- interrupts : The interrupt number.
+Optional properties:
+ - nand-ecc-step-size: must be 512 or 1024. If not specified, default to 512.
+ see nand.txt for details.
+
The device tree may optionally contain sub-nodes describing partitions of the
address space. See partition.txt for more detail.
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 63f7500..5d80f16 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -894,8 +894,6 @@ static bool denali_hw_ecc_fixup(struct denali_nand_info *denali,
return false;
}
-#define ECC_SECTOR_SIZE 512
-
#define ECC_SECTOR(x) (((x) & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12)
#define ECC_BYTE(x) (((x) & ECC_ERROR_ADDRESS__OFFSET))
#define ECC_CORRECTION_VALUE(x) ((x) & ERR_CORRECTION_INFO__BYTEMASK)
@@ -908,6 +906,7 @@ static bool denali_sw_ecc_fixup(struct denali_nand_info *denali, u8 *buf,
{
bool check_erased_page = false;
unsigned int bitflips = 0;
+ unsigned int ecc_size = denali->nand.ecc.size;
u32 err_address, err_correction_info, err_byte, err_sector, err_device,
err_correction_value;
@@ -930,18 +929,18 @@ static bool denali_sw_ecc_fixup(struct denali_nand_info *denali, u8 *buf,
if (ECC_ERROR_CORRECTABLE(err_correction_info)) {
/*
- * If err_byte is larger than ECC_SECTOR_SIZE, means error
+ * If err_byte is larger than ecc_size, means error
* happened in OOB, so we ignore it. It's no need for
* us to correct it err_device is represented the NAND
* error bits are happened in if there are more than
* one NAND connected.
*/
- if (err_byte < ECC_SECTOR_SIZE) {
+ if (err_byte < ecc_size) {
struct mtd_info *mtd =
nand_to_mtd(&denali->nand);
int offset;
- offset = (err_sector * ECC_SECTOR_SIZE + err_byte) *
+ offset = (err_sector * ecc_size + err_byte) *
denali->devnum + err_device;
/* correct the ECC error */
buf[offset] ^= err_correction_value;
@@ -1590,22 +1589,25 @@ int denali_init(struct denali_nand_info *denali)
/* no subpage writes on denali */
chip->options |= NAND_NO_SUBPAGE_WRITE;
+ /* If "nand-ecc-step-size" DT property is specified, respect it */
+ if (!chip->ecc.size)
+ chip->ecc.size = denali->caps & DENALI_CAPS_ECC_SIZE_1024 ?
+ 1024 : 512;
+
/*
* Denali Controller only support 15bit and 8bit ECC in MRST,
* so just let controller do 15bit ECC for MLC and 8bit ECC for
* SLC if possible.
* */
if (!nand_is_slc(chip) &&
- (mtd->oobsize > (denali->bbtskipbytes +
- ECC_15BITS * (mtd->writesize /
- ECC_SECTOR_SIZE)))) {
+ mtd->oobsize > denali->bbtskipbytes +
+ ECC_15BITS * (mtd->writesize / chip->ecc.size)) {
/* if MLC OOB size is large enough, use 15bit ECC*/
chip->ecc.strength = 15;
chip->ecc.bytes = ECC_15BITS;
iowrite32(15, denali->flash_reg + ECC_CORRECTION);
- } else if (mtd->oobsize < (denali->bbtskipbytes +
- ECC_8BITS * (mtd->writesize /
- ECC_SECTOR_SIZE))) {
+ } else if (mtd->oobsize <
+ denali->bbtskipbytes + ECC_8BITS * (mtd->writesize / chip->ecc.size)) {
pr_err("Your NAND chip OOB is not large enough to contain 8bit ECC correction codes");
goto failed_req_irq;
} else {
@@ -1616,8 +1618,6 @@ int denali_init(struct denali_nand_info *denali)
mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
- /* override the default read operations */
- chip->ecc.size = ECC_SECTOR_SIZE;
chip->ecc.read_page = denali_read_page;
chip->ecc.read_page_raw = denali_read_page_raw;
chip->ecc.write_page = denali_write_page;
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
index d621b74..5209625 100644
--- a/drivers/mtd/nand/denali.h
+++ b/drivers/mtd/nand/denali.h
@@ -396,8 +396,6 @@
#define MODE_10 0x08000000
#define MODE_11 0x0C000000
-#define ECC_SECTOR_SIZE 512
-
struct nand_buf {
int head;
int tail;
@@ -434,6 +432,7 @@ struct denali_nand_info {
#define DENALI_CAPS_HW_ECC_FIXUP BIT(0)
#define DENALI_CAPS_DMA_64BIT BIT(1)
#define DENALI_CAPS_NEW_N_BANKS_FORMAT BIT(2)
+#define DENALI_CAPS_ECC_SIZE_1024 BIT(3)
};
extern int denali_init(struct denali_nand_info *denali);
--
2.7.4
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 37/39] mtd: nand: denali: support "nand-ecc-strength" DT property
From: Masahiro Yamada @ 2016-11-26 18:06 UTC (permalink / raw)
To: linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: Masahiro Yamada, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Boris Brezillon, Marek Vasut,
Brian Norris, Richard Weinberger, David Woodhouse,
Cyrille Pitchen, Rob Herring, Mark Rutland
In-Reply-To: <1480183585-592-1-git-send-email-yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A@public.gmane.org>
Historically, this driver tried to choose as big ECC strength as
possible, but it would be reasonable to allow DT to set a particular
ECC strength with "nand-ecc-strength" property.
Going forward, DT platforms should specify "nand-ecc-strength" or
"nand-ecc-maximize" to show the ECC strength strategy explicitly.
If nothing is specified in DT, "nand-ecc-maximize" is implied since
this was the original behavior. It applies to PCI platforms too.
Signed-off-by: Masahiro Yamada <yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A@public.gmane.org>
---
.../devicetree/bindings/mtd/denali-nand.txt | 5 ++++
drivers/mtd/nand/denali.c | 27 +++++++++++++++++++++-
drivers/mtd/nand/denali_pci.c | 2 ++
3 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/mtd/denali-nand.txt b/Documentation/devicetree/bindings/mtd/denali-nand.txt
index e9d5818..51fe195 100644
--- a/Documentation/devicetree/bindings/mtd/denali-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/denali-nand.txt
@@ -9,6 +9,11 @@ Required properties:
Optional properties:
- nand-ecc-step-size: must be 512 or 1024. If not specified, default to 512.
see nand.txt for details.
+ - nand-ecc-strength: see nand.txt for details
+ - nand-ecc-maximize: see nand.txt for details
+
+Note:
+Either nand-ecc-strength or nand-ecc-maximize should be specified.
The device tree may optionally contain sub-nodes describing partitions of the
address space. See partition.txt for more detail.
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 54c9e0c..df174ca 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1393,6 +1393,21 @@ static int denali_set_max_ecc_strength(struct denali_nand_info *denali)
return -EINVAL;
}
+static int denali_check_ecc_strength(struct denali_nand_info *denali)
+{
+ const int *ecc_strength = denali->ecc_strength_avail;
+
+ for (; *ecc_strength; ecc_strength++) {
+ if (*ecc_strength == denali->nand.ecc.strength)
+ return 0;
+ }
+
+ dev_err(denali->dev,
+ "Specified ECC strength is not supported for this controller.\n");
+
+ return -EINVAL;
+}
+
static int denali_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
@@ -1628,7 +1643,17 @@ int denali_init(struct denali_nand_info *denali)
if (!denali->ecc_strength_avail)
denali->ecc_strength_avail = denali_default_ecc_strength;
- ret = denali_set_max_ecc_strength(denali);
+ if (!chip->ecc.strength && !(chip->ecc.options & NAND_ECC_MAXIMIZE)) {
+ dev_info(denali->dev,
+ "No ECC strength is specified. Trying max ECC strength strategy\n");
+ chip->ecc.options |= NAND_ECC_MAXIMIZE;
+ }
+
+ if (chip->ecc.options & NAND_ECC_MAXIMIZE)
+ ret = denali_set_max_ecc_strength(denali);
+ else
+ ret = denali_check_ecc_strength(denali);
+
if (ret)
goto failed_req_irq;
diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c
index ac84323..0064f3e 100644
--- a/drivers/mtd/nand/denali_pci.c
+++ b/drivers/mtd/nand/denali_pci.c
@@ -85,6 +85,8 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
goto failed_remap_reg;
}
+ denali->nand.ecc.options |= NAND_ECC_MAXIMIZE;
+
ret = denali_init(denali);
if (ret)
goto failed_remap_mem;
--
2.7.4
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 39/39] mtd: nand: denali_dt: add compatible strings for UniPhier SoC variants
From: Masahiro Yamada @ 2016-11-26 18:06 UTC (permalink / raw)
To: linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: Masahiro Yamada, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Boris Brezillon, Marek Vasut,
Brian Norris, Richard Weinberger, David Woodhouse,
Cyrille Pitchen, Rob Herring, Mark Rutland
In-Reply-To: <1480183585-592-1-git-send-email-yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A@public.gmane.org>
Add two compatible strings for UniPhier SoCs. The revision register
on both shows revision 5.0, but they are different hardware.
Features:
- DMA engine with 64 bit physical address support
- 1024 byte ECC step size
- 8 / 16 / 24 bit ECC strength
- The n_banks format depends on SoC
Signed-off-by: Masahiro Yamada <yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A@public.gmane.org>
---
.../devicetree/bindings/mtd/denali-nand.txt | 10 +++++--
drivers/mtd/nand/denali_dt.c | 33 ++++++++++++++++++++--
2 files changed, 38 insertions(+), 5 deletions(-)
diff --git a/Documentation/devicetree/bindings/mtd/denali-nand.txt b/Documentation/devicetree/bindings/mtd/denali-nand.txt
index 51fe195..cea46e2 100644
--- a/Documentation/devicetree/bindings/mtd/denali-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/denali-nand.txt
@@ -1,13 +1,19 @@
* Denali NAND controller
Required properties:
- - compatible : should be "denali,denali-nand-dt"
+ - compatible : should be one of the following:
+ "denali,denali-nand-dt"
+ "denali,denali-nand-uniphier-v5a"
+ "denali,denali-nand-uniphier-v5b"
- reg : should contain registers location and length for data and reg.
- reg-names: Should contain the reg names "nand_data" and "denali_reg"
- interrupts : The interrupt number.
Optional properties:
- - nand-ecc-step-size: must be 512 or 1024. If not specified, default to 512.
+ - nand-ecc-step-size: must be 512 or 1024. If not specified, default to:
+ 512 for "denali,denali-nand-dt"
+ 1024 for "denali,denali-nand-uniphier-v5a"
+ 1024 for "denali,denali-nand-uniphier-v5b"
see nand.txt for details.
- nand-ecc-strength: see nand.txt for details
- nand-ecc-maximize: see nand.txt for details
diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c
index aa1e032..b411889 100644
--- a/drivers/mtd/nand/denali_dt.c
+++ b/drivers/mtd/nand/denali_dt.c
@@ -34,10 +34,37 @@ struct denali_dt_data {
unsigned int caps;
};
+static const int denali_uniphier_ecc_strength[] = {
+ 24, 16, 8, 0,
+};
+
+static const struct denali_dt_data denali_uniphier_v5a_data = {
+ .ecc_strength_avail = denali_uniphier_ecc_strength,
+ .caps = DENALI_CAPS_DMA_64BIT |
+ DENALI_CAPS_ECC_SIZE_1024,
+};
+
+static const struct denali_dt_data denali_uniphier_v5b_data = {
+ .ecc_strength_avail = denali_uniphier_ecc_strength,
+ .caps = DENALI_CAPS_DMA_64BIT |
+ DENALI_CAPS_NEW_N_BANKS_FORMAT |
+ DENALI_CAPS_ECC_SIZE_1024,
+};
+
static const struct of_device_id denali_nand_dt_ids[] = {
- { .compatible = "denali,denali-nand-dt" },
- { /* sentinel */ }
- };
+ {
+ .compatible = "denali,denali-nand-dt",
+ },
+ {
+ .compatible = "denali,denali-nand-uniphier-v5a",
+ .data = &denali_uniphier_v5a_data,
+ },
+ {
+ .compatible = "denali,denali-nand-uniphier-v5b",
+ .data = &denali_uniphier_v5b_data,
+ },
+ { /* sentinel */ }
+};
MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
--
2.7.4
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH] arm64: dts: uniphier: add SD-ctrl node for LD11 SoC
From: Masahiro Yamada @ 2016-11-26 18:10 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: Masahiro Yamada, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Will Deacon,
Mark Rutland, Catalin Marinas
The LD11 SoC is equipped with SD-ctrl (0x59810000) as well as
MIO-ctrl (0x5b3e0000). The SD-ctrl block on this SoC has just
one register for controlling RST_n pin of the eMMC device.
Signed-off-by: Masahiro Yamada <yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A@public.gmane.org>
---
arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi b/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi
index 0e5c58f..7a62fb9 100644
--- a/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi
+++ b/arch/arm64/boot/dts/socionext/uniphier-ld11.dtsi
@@ -273,6 +273,17 @@
reg = <0x59801000 0x400>;
};
+ sdctrl@59810000 {
+ compatible = "socionext,uniphier-ld11-sdctrl",
+ "simple-mfd", "syscon";
+ reg = <0x59810000 0x400>;
+
+ sd_rst: reset {
+ compatible = "socionext,uniphier-ld11-sd-reset";
+ #reset-cells = <1>;
+ };
+ };
+
perictrl@59820000 {
compatible = "socionext,uniphier-perictrl",
"simple-mfd", "syscon";
--
2.7.4
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 0/5] mfd: twl: improvements and new regulator driver
From: Nicolae Rosia @ 2016-11-26 18:13 UTC (permalink / raw)
To: Lee Jones, Mark Brown, Rob Herring, Mark Rutland, Tony Lindgren
Cc: Liam Girdwood, Paul Gortmaker, Graeme Gregory, Baruch Siach,
linux-omap-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Nicolae Rosia
Hello,
The current TWL MFD driver has a number of problems which are
very well described by Russell King [0].
This series attemps to fix this by making the driver's private
structure available to child nodes.
A regulator driver for TWL6032 which makes use of the private
drvdata is introduced.
A driver for TWL6032 PMIC already exists in mainline,
twl-regulator, but it has the following drawbacks:
* has no mainline users
* it does not follow the recommended regulators binding since
it uses a compatible string for every regulator;
* it is broken
** the features flag is not set, hence the TWL6032
support is broken since it depends on TWL6032_SUBCLASS flag;
** even with that fixed, bit manipulations are wrong
If this receives positive feedback, I could convert all TWL drivers
to use drvdata, then get rid of the exported symbols.
[0] https://www.spinics.net/lists/linux-omap/msg133387.html
Nicolae Rosia (5):
mfd: twl-core: make driver DT only
mfd: twl: remove useless header
mfd: twl: move structure definitions to a public header
regulator: Add support for TI TWL6032
mfd: twl: use mfd_add_devices for TWL6032 regulator
.../bindings/regulator/twl6032-regulator.txt | 109 ++++
drivers/mfd/Kconfig | 1 +
drivers/mfd/twl-core.c | 444 ++--------------
drivers/mfd/twl-core.h | 10 -
drivers/mfd/twl4030-irq.c | 2 -
drivers/mfd/twl6030-irq.c | 2 -
drivers/regulator/Kconfig | 7 +
drivers/regulator/Makefile | 1 +
drivers/regulator/twl6032-regulator.c | 582 +++++++++++++++++++++
include/linux/mfd/twl-core.h | 35 ++
10 files changed, 768 insertions(+), 425 deletions(-)
create mode 100644 Documentation/devicetree/bindings/regulator/twl6032-regulator.txt
delete mode 100644 drivers/mfd/twl-core.h
create mode 100644 drivers/regulator/twl6032-regulator.c
create mode 100644 include/linux/mfd/twl-core.h
--
2.9.3
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 1/5] mfd: twl-core: make driver DT only
From: Nicolae Rosia @ 2016-11-26 18:13 UTC (permalink / raw)
To: Lee Jones, Mark Brown, Rob Herring, Mark Rutland, Tony Lindgren
Cc: Liam Girdwood, Paul Gortmaker, Graeme Gregory, Baruch Siach,
linux-omap, linux-arm-kernel, linux-kernel, devicetree,
Nicolae Rosia
In-Reply-To: <20161126181326.14951-1-Nicolae_Rosia@mentor.com>
All users are DT-only and it makes no sense to keep
unused code
Signed-off-by: Nicolae Rosia <Nicolae_Rosia@mentor.com>
---
drivers/mfd/Kconfig | 1 +
drivers/mfd/twl-core.c | 399 +------------------------------------------------
2 files changed, 8 insertions(+), 392 deletions(-)
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index c6df644..c180f8b 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1333,6 +1333,7 @@ config MFD_TPS80031
config TWL4030_CORE
bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 Support"
depends on I2C=y
+ depends on OF
select IRQ_DOMAIN
select REGMAP_I2C
help
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index c64615d..48b0668 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -13,6 +13,9 @@
* Code cleanup and modifications to IRQ handler.
* by syed khasim <x0khasim@ti.com>
*
+ * Code cleanup and modifications:
+ * Copyright (C) 2016 Nicolae Rosia <nicolae.rosia@gmail.com>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -604,376 +607,6 @@ int twl_get_hfclk_rate(void)
}
EXPORT_SYMBOL_GPL(twl_get_hfclk_rate);
-static struct device *
-add_numbered_child(unsigned mod_no, const char *name, int num,
- void *pdata, unsigned pdata_len,
- bool can_wakeup, int irq0, int irq1)
-{
- struct platform_device *pdev;
- struct twl_client *twl;
- int status, sid;
-
- if (unlikely(mod_no >= twl_get_last_module())) {
- pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
- return ERR_PTR(-EPERM);
- }
- sid = twl_priv->twl_map[mod_no].sid;
- twl = &twl_priv->twl_modules[sid];
-
- pdev = platform_device_alloc(name, num);
- if (!pdev)
- return ERR_PTR(-ENOMEM);
-
- pdev->dev.parent = &twl->client->dev;
-
- if (pdata) {
- status = platform_device_add_data(pdev, pdata, pdata_len);
- if (status < 0) {
- dev_dbg(&pdev->dev, "can't add platform_data\n");
- goto put_device;
- }
- }
-
- if (irq0) {
- struct resource r[2] = {
- { .start = irq0, .flags = IORESOURCE_IRQ, },
- { .start = irq1, .flags = IORESOURCE_IRQ, },
- };
-
- status = platform_device_add_resources(pdev, r, irq1 ? 2 : 1);
- if (status < 0) {
- dev_dbg(&pdev->dev, "can't add irqs\n");
- goto put_device;
- }
- }
-
- status = platform_device_add(pdev);
- if (status)
- goto put_device;
-
- device_init_wakeup(&pdev->dev, can_wakeup);
-
- return &pdev->dev;
-
-put_device:
- platform_device_put(pdev);
- dev_err(&twl->client->dev, "failed to add device %s\n", name);
- return ERR_PTR(status);
-}
-
-static inline struct device *add_child(unsigned mod_no, const char *name,
- void *pdata, unsigned pdata_len,
- bool can_wakeup, int irq0, int irq1)
-{
- return add_numbered_child(mod_no, name, -1, pdata, pdata_len,
- can_wakeup, irq0, irq1);
-}
-
-static struct device *
-add_regulator_linked(int num, struct regulator_init_data *pdata,
- struct regulator_consumer_supply *consumers,
- unsigned num_consumers, unsigned long features)
-{
- struct twl_regulator_driver_data drv_data;
-
- /* regulator framework demands init_data ... */
- if (!pdata)
- return NULL;
-
- if (consumers) {
- pdata->consumer_supplies = consumers;
- pdata->num_consumer_supplies = num_consumers;
- }
-
- if (pdata->driver_data) {
- /* If we have existing drv_data, just add the flags */
- struct twl_regulator_driver_data *tmp;
- tmp = pdata->driver_data;
- tmp->features |= features;
- } else {
- /* add new driver data struct, used only during init */
- drv_data.features = features;
- drv_data.set_voltage = NULL;
- drv_data.get_voltage = NULL;
- drv_data.data = NULL;
- pdata->driver_data = &drv_data;
- }
-
- /* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */
- return add_numbered_child(TWL_MODULE_PM_MASTER, "twl_reg", num,
- pdata, sizeof(*pdata), false, 0, 0);
-}
-
-static struct device *
-add_regulator(int num, struct regulator_init_data *pdata,
- unsigned long features)
-{
- return add_regulator_linked(num, pdata, NULL, 0, features);
-}
-
-/*
- * NOTE: We know the first 8 IRQs after pdata->base_irq are
- * for the PIH, and the next are for the PWR_INT SIH, since
- * that's how twl_init_irq() sets things up.
- */
-
-static int
-add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
- unsigned long features)
-{
- struct device *child;
-
- if (IS_ENABLED(CONFIG_GPIO_TWL4030) && pdata->gpio) {
- child = add_child(TWL4030_MODULE_GPIO, "twl4030_gpio",
- pdata->gpio, sizeof(*pdata->gpio),
- false, irq_base + GPIO_INTR_OFFSET, 0);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- if (IS_ENABLED(CONFIG_KEYBOARD_TWL4030) && pdata->keypad) {
- child = add_child(TWL4030_MODULE_KEYPAD, "twl4030_keypad",
- pdata->keypad, sizeof(*pdata->keypad),
- true, irq_base + KEYPAD_INTR_OFFSET, 0);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- if (IS_ENABLED(CONFIG_TWL4030_MADC) && pdata->madc &&
- twl_class_is_4030()) {
- child = add_child(TWL4030_MODULE_MADC, "twl4030_madc",
- pdata->madc, sizeof(*pdata->madc),
- true, irq_base + MADC_INTR_OFFSET, 0);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- if (IS_ENABLED(CONFIG_RTC_DRV_TWL4030)) {
- /*
- * REVISIT platform_data here currently might expose the
- * "msecure" line ... but for now we just expect board
- * setup to tell the chip "it's always ok to SET_TIME".
- * Eventually, Linux might become more aware of such
- * HW security concerns, and "least privilege".
- */
- child = add_child(TWL_MODULE_RTC, "twl_rtc", NULL, 0,
- true, irq_base + RTC_INTR_OFFSET, 0);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- if (IS_ENABLED(CONFIG_PWM_TWL)) {
- child = add_child(TWL_MODULE_PWM, "twl-pwm", NULL, 0,
- false, 0, 0);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- if (IS_ENABLED(CONFIG_PWM_TWL_LED)) {
- child = add_child(TWL_MODULE_LED, "twl-pwmled", NULL, 0,
- false, 0, 0);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- if (IS_ENABLED(CONFIG_TWL4030_USB) && pdata->usb &&
- twl_class_is_4030()) {
-
- static struct regulator_consumer_supply usb1v5 = {
- .supply = "usb1v5",
- };
- static struct regulator_consumer_supply usb1v8 = {
- .supply = "usb1v8",
- };
- static struct regulator_consumer_supply usb3v1 = {
- .supply = "usb3v1",
- };
-
- /* First add the regulators so that they can be used by transceiver */
- if (IS_ENABLED(CONFIG_REGULATOR_TWL4030)) {
- /* this is a template that gets copied */
- struct regulator_init_data usb_fixed = {
- .constraints.valid_modes_mask =
- REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .constraints.valid_ops_mask =
- REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- };
-
- child = add_regulator_linked(TWL4030_REG_VUSB1V5,
- &usb_fixed, &usb1v5, 1,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator_linked(TWL4030_REG_VUSB1V8,
- &usb_fixed, &usb1v8, 1,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator_linked(TWL4030_REG_VUSB3V1,
- &usb_fixed, &usb3v1, 1,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- }
-
- child = add_child(TWL_MODULE_USB, "twl4030_usb",
- pdata->usb, sizeof(*pdata->usb), true,
- /* irq0 = USB_PRES, irq1 = USB */
- irq_base + USB_PRES_INTR_OFFSET,
- irq_base + USB_INTR_OFFSET);
-
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- /* we need to connect regulators to this transceiver */
- if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && child) {
- usb1v5.dev_name = dev_name(child);
- usb1v8.dev_name = dev_name(child);
- usb3v1.dev_name = dev_name(child);
- }
- }
-
- if (IS_ENABLED(CONFIG_TWL4030_WATCHDOG) && twl_class_is_4030()) {
- child = add_child(TWL_MODULE_PM_RECEIVER, "twl4030_wdt", NULL,
- 0, false, 0, 0);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- if (IS_ENABLED(CONFIG_INPUT_TWL4030_PWRBUTTON) && twl_class_is_4030()) {
- child = add_child(TWL_MODULE_PM_MASTER, "twl4030_pwrbutton",
- NULL, 0, true, irq_base + 8 + 0, 0);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- if (IS_ENABLED(CONFIG_MFD_TWL4030_AUDIO) && pdata->audio &&
- twl_class_is_4030()) {
- child = add_child(TWL4030_MODULE_AUDIO_VOICE, "twl4030-audio",
- pdata->audio, sizeof(*pdata->audio),
- false, 0, 0);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- /* twl4030 regulators */
- if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_4030()) {
- child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VIO, pdata->vio,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VDAC, pdata->vdac,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator((features & TWL4030_VAUX2)
- ? TWL4030_REG_VAUX2_4030
- : TWL4030_REG_VAUX2,
- pdata->vaux2, features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- /* maybe add LDOs that are omitted on cost-reduced parts */
- if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && !(features & TPS_SUBSET)
- && twl_class_is_4030()) {
- child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VSIM, pdata->vsim,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4,
- features);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- if (IS_ENABLED(CONFIG_CHARGER_TWL4030) && pdata->bci &&
- !(features & (TPS_SUBSET | TWL5031))) {
- child = add_child(TWL_MODULE_MAIN_CHARGE, "twl4030_bci",
- pdata->bci, sizeof(*pdata->bci), false,
- /* irq0 = CHG_PRES, irq1 = BCI */
- irq_base + BCI_PRES_INTR_OFFSET,
- irq_base + BCI_INTR_OFFSET);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata->power) {
- child = add_child(TWL_MODULE_PM_MASTER, "twl4030_power",
- pdata->power, sizeof(*pdata->power), false,
- 0, 0);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
- return 0;
-}
-
-/*----------------------------------------------------------------------*/
-
/*
* These three functions initialize the on-chip clock framework,
* letting it generate the right frequencies for USB, MADC, and
@@ -1000,8 +633,7 @@ static inline int __init unprotect_pm_master(void)
return e;
}
-static void clocks_init(struct device *dev,
- struct twl4030_clock_init_data *clock)
+static void clocks_init(struct device *dev)
{
int e = 0;
struct clk *osc;
@@ -1031,8 +663,6 @@ static void clocks_init(struct device *dev,
}
ctrl |= HIGH_PERF_SQ;
- if (clock && clock->ck32k_lowpwr_enable)
- ctrl |= CK32K_LOWPWR_EN;
e |= unprotect_pm_master();
/* effect->MADC+USB ck en */
@@ -1071,16 +701,10 @@ static int twl_remove(struct i2c_client *client)
return 0;
}
-static struct of_dev_auxdata twl_auxdata_lookup[] = {
- OF_DEV_AUXDATA("ti,twl4030-gpio", 0, "twl4030-gpio", NULL),
- { /* sentinel */ },
-};
-
/* NOTE: This driver only handles a single twl4030/tps659x0 chip */
static int
twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
- struct twl4030_platform_data *pdata = dev_get_platdata(&client->dev);
struct device_node *node = client->dev.of_node;
struct platform_device *pdev;
const struct regmap_config *twl_regmap_config;
@@ -1088,8 +712,8 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
int status;
unsigned i, num_slaves;
- if (!node && !pdata) {
- dev_err(&client->dev, "no platform data\n");
+ if (!node) {
+ dev_err(&client->dev, "no DT info\n");
return -EINVAL;
}
@@ -1177,7 +801,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
twl_priv->ready = true;
/* setup clock framework */
- clocks_init(&pdev->dev, pdata ? pdata->clock : NULL);
+ clocks_init(&pdev->dev);
/* read TWL IDCODE Register */
if (twl_class_is_4030()) {
@@ -1225,15 +849,6 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
TWL4030_DCDC_GLOBAL_CFG);
}
- if (node) {
- if (pdata)
- twl_auxdata_lookup[0].platform_data = pdata->gpio;
- status = of_platform_populate(node, NULL, twl_auxdata_lookup,
- &client->dev);
- } else {
- status = add_children(pdata, irq_base, id->driver_data);
- }
-
fail:
if (status < 0)
twl_remove(client);
--
2.9.3
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox