* [PATCH v3] arm: remove !CPU_V6 and !GENERIC_ATOMIC64 build dependencies for XEN
From: Stefano Stabellini @ 2014-01-20 15:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140116193123.GB22105@mudshark.cambridge.arm.com>
On Thu, 16 Jan 2014, Will Deacon wrote:
> Hi Stefano,
>
> On Thu, Jan 16, 2014 at 04:27:55PM +0000, Stefano Stabellini wrote:
> > On Thu, 9 Jan 2014, Will Deacon wrote:
> > > Ok, thanks for the explanation. Looking at the patch, I wonder whether it's
> > > not cleaner just to implement xchg code separately for Xen? The Linux code
> > > isn't always sufficient (due to the GENERIC_ATOMIC64 stuff) and most of the
> > > churn coming out of this patch is an attempt to provide some small code
> > > reuse at the cost of code readability.
> > >
> > > What do others think?
> >
> > I am OK with that, in fact my first version of the patch did just that:
> >
> > http://marc.info/?l=linux-arm-kernel&m=138436406724990&w=2
> >
> > Is that what you had in mind?
>
> For the xchg part, yes, that looks a lot better. I don't like the #undef
> CONFIG_CPU_V6 though, can that be rewritten to use __LINUX_ARM_ARCH__?
The problem is that the 1 and 2 byte parameter size cases in __cmpxchg
are ifdef'ed CONFIG_CPU_V6 but drivers/xen/grant-table.c needs them.
So we can either undef CONFIG_CPU_V6 in grant-table.c or call a
different function.
If I switch from ifdef CONFIG_CPU_V6 to if __LINUX_ARM_ARCH__ > 6 in
__cmpxchg, we still have the problem that if __LINUX_ARM_ARCH__ == 6,
grant-table.c doesn't compile.
Maybe the approach taken by the other patch for cmpxchg is better, see
below.
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c1f1a7e..ae54ae0 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1881,8 +1881,7 @@ config XEN_DOM0
config XEN
bool "Xen guest support on ARM (EXPERIMENTAL)"
depends on ARM && AEABI && OF
- depends on CPU_V7 && !CPU_V6
- depends on !GENERIC_ATOMIC64
+ depends on CPU_V7
select ARM_PSCI
select SWIOTLB_XEN
help
diff --git a/arch/arm/include/asm/cmpxchg.h b/arch/arm/include/asm/cmpxchg.h
index df2fbba..cc8a4a2 100644
--- a/arch/arm/include/asm/cmpxchg.h
+++ b/arch/arm/include/asm/cmpxchg.h
@@ -133,6 +133,44 @@ extern void __bad_cmpxchg(volatile void *ptr, int size);
* cmpxchg only support 32-bits operands on ARMv6.
*/
+static inline unsigned long __cmpxchg8(volatile void *ptr, unsigned long old,
+ unsigned long new)
+{
+ unsigned long oldval, res;
+
+ do {
+ asm volatile("@ __cmpxchg1\n"
+ " ldrexb %1, [%2]\n"
+ " mov %0, #0\n"
+ " teq %1, %3\n"
+ " strexbeq %0, %4, [%2]\n"
+ : "=&r" (res), "=&r" (oldval)
+ : "r" (ptr), "Ir" (old), "r" (new)
+ : "memory", "cc");
+ } while (res);
+
+ return oldval;
+}
+
+static inline unsigned long __cmpxchg16(volatile void *ptr, unsigned long old,
+ unsigned long new)
+{
+ unsigned long oldval, res;
+
+ do {
+ asm volatile("@ __cmpxchg1\n"
+ " ldrexh %1, [%2]\n"
+ " mov %0, #0\n"
+ " teq %1, %3\n"
+ " strexheq %0, %4, [%2]\n"
+ : "=&r" (res), "=&r" (oldval)
+ : "r" (ptr), "Ir" (old), "r" (new)
+ : "memory", "cc");
+ } while (res);
+
+ return oldval;
+}
+
static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
unsigned long new, int size)
{
@@ -141,28 +179,10 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
switch (size) {
#ifndef CONFIG_CPU_V6 /* min ARCH >= ARMv6K */
case 1:
- do {
- asm volatile("@ __cmpxchg1\n"
- " ldrexb %1, [%2]\n"
- " mov %0, #0\n"
- " teq %1, %3\n"
- " strexbeq %0, %4, [%2]\n"
- : "=&r" (res), "=&r" (oldval)
- : "r" (ptr), "Ir" (old), "r" (new)
- : "memory", "cc");
- } while (res);
+ oldval = __cmpxchg8(ptr, old, new);
break;
case 2:
- do {
- asm volatile("@ __cmpxchg1\n"
- " ldrexh %1, [%2]\n"
- " mov %0, #0\n"
- " teq %1, %3\n"
- " strexheq %0, %4, [%2]\n"
- : "=&r" (res), "=&r" (oldval)
- : "r" (ptr), "Ir" (old), "r" (new)
- : "memory", "cc");
- } while (res);
+ oldval = __cmpxchg16(ptr, old, new);
break;
#endif
case 4:
diff --git a/arch/arm/include/asm/sync_bitops.h b/arch/arm/include/asm/sync_bitops.h
index 63479ee..942659a 100644
--- a/arch/arm/include/asm/sync_bitops.h
+++ b/arch/arm/include/asm/sync_bitops.h
@@ -21,7 +21,29 @@
#define sync_test_and_clear_bit(nr, p) _test_and_clear_bit(nr, p)
#define sync_test_and_change_bit(nr, p) _test_and_change_bit(nr, p)
#define sync_test_bit(nr, addr) test_bit(nr, addr)
-#define sync_cmpxchg cmpxchg
+static inline unsigned long sync_cmpxchg(volatile void *ptr,
+ unsigned long old,
+ unsigned long new)
+{
+ unsigned long oldval;
+ int size = sizeof(*(ptr));
+
+ smp_mb();
+ switch (size) {
+ case 1:
+ oldval = __cmpxchg8(ptr, old, new);
+ break;
+ case 2:
+ oldval = __cmpxchg16(ptr, old, new);
+ break;
+ default:
+ oldval = __cmpxchg(ptr, old, new, size);
+ break;
+ }
+ smp_mb();
+
+ return oldval;
+}
#endif
diff --git a/arch/arm/include/asm/xen/events.h b/arch/arm/include/asm/xen/events.h
index 8b1f37b..2032ee6 100644
--- a/arch/arm/include/asm/xen/events.h
+++ b/arch/arm/include/asm/xen/events.h
@@ -16,7 +16,37 @@ static inline int xen_irqs_disabled(struct pt_regs *regs)
return raw_irqs_disabled_flags(regs->ARM_cpsr);
}
-#define xchg_xen_ulong(ptr, val) atomic64_xchg(container_of((ptr), \
+#ifdef CONFIG_GENERIC_ATOMIC64
+/* if CONFIG_GENERIC_ATOMIC64 is defined we cannot use the generic
+ * atomic64_xchg function because it is implemented using spin locks.
+ * Here we need proper atomic instructions to read and write memory
+ * shared with the hypervisor.
+ */
+static inline u64 xen_atomic64_xchg(atomic64_t *ptr, u64 new)
+{
+ u64 result;
+ unsigned long tmp;
+
+ smp_mb();
+
+ __asm__ __volatile__("@ xen_atomic64_xchg\n"
+"1: ldrexd %0, %H0, [%3]\n"
+" strexd %1, %4, %H4, [%3]\n"
+" teq %1, #0\n"
+" bne 1b"
+ : "=&r" (result), "=&r" (tmp), "+Qo" (ptr->counter)
+ : "r" (&ptr->counter), "r" (new)
+ : "cc");
+
+ smp_mb();
+
+ return result;
+}
+#else
+#define xen_atomic64_xchg atomic64_xchg
+#endif
+
+#define xchg_xen_ulong(ptr, val) xen_atomic64_xchg(container_of((ptr), \
atomic64_t, \
counter), (val))
^ permalink raw reply related
* [PATCH v7 0/7] ARM: rockchip: add smp functionality
From: Heiko Stübner @ 2014-01-20 15:41 UTC (permalink / raw)
To: linux-arm-kernel
This series enables the use of the additional cores on Rockchip
Cortex-A9 SoCs.
To achieve this, add the scu, the needed sram and power-management-unit.
Tested on both a BQ Curie2 (rk3066a / dual core) and
on a Radxa Rock (rk3188 / quad core).
changes since v6:
- address comments from Mark Rutland
- using of_property_read_u32_index instead of parsing the list manually
- include v4 of "of: add functions to count number of elements in a property"
to not have to count property-elements manually anymore
changes since v5:
- Grant Likely liked it better to "specify reserved regions of the
memory instead of the valid ranges", so go back to the mmio-sram-reserved
property originally suggested by Rob Herring
changes since v4:
- rebase on top of the recent rk3188 board support
- implement suggestion from Matt Sealey in moving the sram-limit from
marking reserved regions to marking available regions - hopefully
I got the usage right
- remove __CPUINIT as suggested by Fabio Estevam
changes since v3:
- address comments from Rob Herring:
- split the gathering of the reserve-data into a separate loop
- spelling and style fixes
- first patch only included for reference, already part of the
char-misc git tree
changes since v2:
- rework the sram allocation following the suggestion from Philipp Zabel
changes since v1:
- add reserved block feature for mmio-sram, to not use two logical
sram nodes
- the sram content is kept intact while the device is running, so
copying the trampoline is only needed once
Heiko Stuebner (7):
of: add functions to count number of elements in a property
dt-bindings: sram: describe option to reserve parts of the memory
misc: sram: implement mmio-sram-reserved option
ARM: rockchip: add snoop-control-unit
ARM: rockchip: add sram dt nodes and documentation
ARM: rockchip: add power-management-unit
ARM: rockchip: add smp bringup code
.../devicetree/bindings/arm/rockchip/pmu.txt | 16 ++
.../devicetree/bindings/arm/rockchip/smp-sram.txt | 23 +++
Documentation/devicetree/bindings/misc/sram.txt | 8 +
arch/arm/boot/dts/rk3066a.dtsi | 6 +
arch/arm/boot/dts/rk3188.dtsi | 6 +
arch/arm/boot/dts/rk3xxx.dtsi | 10 +
arch/arm/mach-rockchip/Kconfig | 1 +
arch/arm/mach-rockchip/Makefile | 1 +
arch/arm/mach-rockchip/core.h | 22 +++
arch/arm/mach-rockchip/headsmp.S | 30 +++
arch/arm/mach-rockchip/platsmp.c | 208 ++++++++++++++++++++
arch/arm/mach-rockchip/rockchip.c | 2 +
drivers/misc/sram.c | 121 +++++++++++-
drivers/of/base.c | 32 +++
include/linux/of.h | 76 +++++++
15 files changed, 554 insertions(+), 8 deletions(-)
create mode 100644 Documentation/devicetree/bindings/arm/rockchip/pmu.txt
create mode 100644 Documentation/devicetree/bindings/arm/rockchip/smp-sram.txt
create mode 100644 arch/arm/mach-rockchip/core.h
create mode 100644 arch/arm/mach-rockchip/headsmp.S
create mode 100644 arch/arm/mach-rockchip/platsmp.c
--
1.7.10.4
^ permalink raw reply
* [PATCH v7 1/7] of: add functions to count number of elements in a property
From: Heiko Stübner @ 2014-01-20 15:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4970034.fqvMoHdOyd@phil>
The need to know the number of array elements in a property is
a common pattern. To prevent duplication of open-coded implementations
add a helper static function that also centralises strict sanity
checking and DTB format details, as well as a set of wrapper functions
for u8, u16, u32 and u64.
Suggested-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
This is the same as v4 when this patch was separate, that was a result of the
discussion in in v6 of the rockchip-smp series.
drivers/of/base.c | 32 ++++++++++++++++++++++
include/linux/of.h | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 108 insertions(+)
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 8d007d8..d08acbc 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -883,6 +883,38 @@ struct device_node *of_find_node_by_phandle(phandle handle)
EXPORT_SYMBOL(of_find_node_by_phandle);
/**
+ * of_property_count_elems_of_size - Count the number of elements in a property
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @elem_size: size of the individual element
+ *
+ * Search for a property in a device node and count the number of elements of
+ * size elem_size in it. Returns number of elements on sucess, -EINVAL if the
+ * property does not exist or its length does not match a multiple of elem_size
+ * and -ENODATA if the property does not have a value.
+ */
+int of_property_count_elems_of_size(const struct device_node *np,
+ const char *propname, int elem_size)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+
+ if (prop->length % elem_size != 0) {
+ pr_err("size of %s in node %s is not a multiple of %d\n",
+ propname, np->full_name, elem_size);
+ return -EINVAL;
+ }
+
+ return prop->length / elem_size;
+}
+EXPORT_SYMBOL_GPL(of_property_count_elems_of_size);
+
+/**
* of_find_property_value_of_size
*
* @np: device node from which the property value is to be read.
diff --git a/include/linux/of.h b/include/linux/of.h
index 70c64ba..b59f2e4 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -250,6 +250,8 @@ extern struct device_node *of_find_node_with_property(
extern struct property *of_find_property(const struct device_node *np,
const char *name,
int *lenp);
+extern int of_property_count_elems_of_size(const struct device_node *np,
+ const char *propname, int elem_size);
extern int of_property_read_u32_index(const struct device_node *np,
const char *propname,
u32 index, u32 *out_value);
@@ -431,6 +433,12 @@ static inline struct device_node *of_find_compatible_node(
return NULL;
}
+static inline int of_property_count_elems_of_size(const struct device_node *np,
+ const char *propname, int elem_size)
+{
+ return -ENOSYS;
+}
+
static inline int of_property_read_u32_index(const struct device_node *np,
const char *propname, u32 index, u32 *out_value)
{
@@ -570,6 +578,74 @@ static inline int of_node_to_nid(struct device_node *device) { return 0; }
#endif
/**
+ * of_property_count_u8_elems - Count the number of u8 elements in a property
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ *
+ * Search for a property in a device node and count the number of u8 elements
+ * in it. Returns number of elements on sucess, -EINVAL if the property does
+ * not exist or its length does not match a multiple of u8 and -ENODATA if the
+ * property does not have a value.
+ */
+static inline int of_property_count_u8_elems(const struct device_node *np,
+ const char *propname)
+{
+ return of_property_count_elems_of_size(np, propname, sizeof(u8));
+}
+
+/**
+ * of_property_count_u16_elems - Count the number of u16 elements in a property
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ *
+ * Search for a property in a device node and count the number of u16 elements
+ * in it. Returns number of elements on sucess, -EINVAL if the property does
+ * not exist or its length does not match a multiple of u16 and -ENODATA if the
+ * property does not have a value.
+ */
+static inline int of_property_count_u16_elems(const struct device_node *np,
+ const char *propname)
+{
+ return of_property_count_elems_of_size(np, propname, sizeof(u16));
+}
+
+/**
+ * of_property_count_u32_elems - Count the number of u32 elements in a property
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ *
+ * Search for a property in a device node and count the number of u32 elements
+ * in it. Returns number of elements on sucess, -EINVAL if the property does
+ * not exist or its length does not match a multiple of u32 and -ENODATA if the
+ * property does not have a value.
+ */
+static inline int of_property_count_u32_elems(const struct device_node *np,
+ const char *propname)
+{
+ return of_property_count_elems_of_size(np, propname, sizeof(u32));
+}
+
+/**
+ * of_property_count_u64_elems - Count the number of u64 elements in a property
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ *
+ * Search for a property in a device node and count the number of u64 elements
+ * in it. Returns number of elements on sucess, -EINVAL if the property does
+ * not exist or its length does not match a multiple of u64 and -ENODATA if the
+ * property does not have a value.
+ */
+static inline int of_property_count_u64_elems(const struct device_node *np,
+ const char *propname)
+{
+ return of_property_count_elems_of_size(np, propname, sizeof(u64));
+}
+
+/**
* of_property_read_bool - Findfrom a property
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
--
1.7.10.4
^ permalink raw reply related
* [PATCH v7 2/7] dt-bindings: sram: describe option to reserve parts of the memory
From: Heiko Stübner @ 2014-01-20 15:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4970034.fqvMoHdOyd@phil>
Some SoCs need parts of their sram for special purposes. So while being part
of the peripheral, it should not be part of the genpool controlling the sram.
Therefore add an option mmio-sram-reserved to keep arbitrary portions of the
sram from general usage.
Suggested-by: Rob Herring <robherring2@gmail.com>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Ulrich Prinz <ulrich.prinz@googlemail.com>
Acked-by: Rob Herring <robh@kernel.org>
---
Documentation/devicetree/bindings/misc/sram.txt | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/Documentation/devicetree/bindings/misc/sram.txt b/Documentation/devicetree/bindings/misc/sram.txt
index 4d0a00e..09ee7a3 100644
--- a/Documentation/devicetree/bindings/misc/sram.txt
+++ b/Documentation/devicetree/bindings/misc/sram.txt
@@ -8,9 +8,17 @@ Required properties:
- reg : SRAM iomem address range
+Optional properties:
+
+- mmio-sram-reserved: ordered list of reserved chunks inside the sram that
+ should not be used by the operating system.
+ Format is <base size>, <base size>, ...; with base being relative to the
+ reg property base.
+
Example:
sram: sram at 5c000000 {
compatible = "mmio-sram";
reg = <0x5c000000 0x40000>; /* 256 KiB SRAM at address 0x5c000000 */
+ mmio-sram-reserved = <0x0 0x100>; /* reserve 0x5c000000-0x5c000100 */
};
--
1.7.10.4
^ permalink raw reply related
* [PATCH v7 3/7] misc: sram: implement mmio-sram-reserved option
From: Heiko Stübner @ 2014-01-20 15:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4970034.fqvMoHdOyd@phil>
This implements support for the mmio-sram-reserved option to keep the
genpool from using these areas.
Suggested-by: Rob Herring <robherring2@gmail.com>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Ulrich Prinz <ulrich.prinz@googlemail.com>
---
drivers/misc/sram.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 113 insertions(+), 8 deletions(-)
diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c
index afe66571..8681961 100644
--- a/drivers/misc/sram.c
+++ b/drivers/misc/sram.c
@@ -36,13 +36,23 @@ struct sram_dev {
struct clk *clk;
};
+struct sram_reserve {
+ u32 start;
+ u32 size;
+};
+
static int sram_probe(struct platform_device *pdev)
{
void __iomem *virt_base;
struct sram_dev *sram;
struct resource *res;
- unsigned long size;
- int ret;
+ struct device_node *np = pdev->dev.of_node;
+ unsigned long size, cur_start, cur_size;
+ int reserved_size = 0;
+ struct sram_reserve *rblocks;
+ unsigned int nblocks;
+ int ret = 0;
+ int i;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
virt_base = devm_ioremap_resource(&pdev->dev, res);
@@ -65,19 +75,114 @@ static int sram_probe(struct platform_device *pdev)
if (!sram->pool)
return -ENOMEM;
- ret = gen_pool_add_virt(sram->pool, (unsigned long)virt_base,
- res->start, size, -1);
- if (ret < 0) {
- if (sram->clk)
- clk_disable_unprepare(sram->clk);
- return ret;
+ if (np) {
+ reserved_size = of_property_count_u32_elems(np,
+ "mmio-sram-reserved");
+
+ /* mmio-sram-reserved is optional, so its absence is no error */
+ if (reserved_size < 0)
+ reserved_size = 0;
+
+ if (reserved_size % 2) {
+ dev_warn(&pdev->dev, "wrong number of arguments in mmio-sram-reserved\n");
+ reserved_size = 0;
+ }
+ }
+
+ /*
+ * We need an additional block to mark the end of the memory region
+ * after the reserved blocks from the dt are processed.
+ */
+ nblocks = reserved_size / 2 + 1;
+ rblocks = kmalloc((nblocks) * sizeof(*rblocks), GFP_KERNEL);
+ if (!rblocks) {
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+
+ cur_start = 0;
+ for (i = 0; i < nblocks - 1; i++) {
+ /* checked the property exists above so can skip return vals */
+ of_property_read_u32_index(np, "mmio-sram-reserved",
+ 2 * i, &rblocks[i].start);
+ of_property_read_u32_index(np, "mmio-sram-reserved",
+ 2 * i + 1, &rblocks[i].size);
+
+ if (rblocks[i].start < cur_start) {
+ dev_err(&pdev->dev,
+ "unsorted reserved list (0x%x before current 0x%lx)\n",
+ rblocks[i].start, cur_start);
+ ret = -EINVAL;
+ goto err_chunks;
+ }
+
+ if (rblocks[i].start >= size) {
+ dev_err(&pdev->dev,
+ "reserved block at 0x%x outside the sram size 0x%lx\n",
+ rblocks[i].start, size);
+ ret = -EINVAL;
+ goto err_chunks;
+ }
+
+ if (rblocks[i].start + rblocks[i].size > size) {
+ dev_warn(&pdev->dev,
+ "reserved block at 0x%x to large, trimming\n",
+ rblocks[i].start);
+ rblocks[i].size = size - rblocks[i].start;
+ }
+
+ cur_start = rblocks[i].start + rblocks[i].size;
+
+ dev_dbg(&pdev->dev, "found reserved block 0x%x-0x%x\n",
+ rblocks[i].start,
+ rblocks[i].start + rblocks[i].size);
+ }
+
+ /* the last chunk marks the end of the region */
+ rblocks[nblocks - 1].start = size;
+ rblocks[nblocks - 1].size = 0;
+
+ cur_start = 0;
+ for (i = 0; i < nblocks; i++) {
+ /* current start is in a reserved block, so continue after it */
+ if (rblocks[i].start == cur_start) {
+ cur_start = rblocks[i].start + rblocks[i].size;
+ continue;
+ }
+
+ /*
+ * allocate the space between the current starting
+ * address and the following reserved block, or the
+ * end of the region.
+ */
+ cur_size = rblocks[i].start - cur_start;
+
+ dev_dbg(&pdev->dev, "adding chunk 0x%lx-0x%lx\n",
+ cur_start, cur_start + cur_size);
+ ret = gen_pool_add_virt(sram->pool,
+ (unsigned long)virt_base + cur_start,
+ res->start + cur_start, cur_size, -1);
+ if (ret < 0)
+ goto err_chunks;
+
+ /* next allocation after this reserved block */
+ cur_start = rblocks[i].start + rblocks[i].size;
}
+ kfree(rblocks);
+
platform_set_drvdata(pdev, sram);
dev_dbg(&pdev->dev, "SRAM pool: %ld KiB @ 0x%p\n", size / 1024, virt_base);
return 0;
+
+err_chunks:
+ kfree(rblocks);
+err_alloc:
+ if (sram->clk)
+ clk_disable_unprepare(sram->clk);
+ return ret;
}
static int sram_remove(struct platform_device *pdev)
--
1.7.10.4
^ permalink raw reply related
* [PATCH v7 4/7] ARM: rockchip: add snoop-control-unit
From: Heiko Stübner @ 2014-01-20 15:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4970034.fqvMoHdOyd@phil>
This adds the device-node and config select to enable the
scu in all Rockchip Cortex-A9 SoCs.
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Ulrich Prinz <ulrich.prinz@googlemail.com>
---
arch/arm/boot/dts/rk3xxx.dtsi | 5 +++++
arch/arm/mach-rockchip/Kconfig | 1 +
2 files changed, 6 insertions(+)
diff --git a/arch/arm/boot/dts/rk3xxx.dtsi b/arch/arm/boot/dts/rk3xxx.dtsi
index 0fcbcfd..0a3d5b1 100644
--- a/arch/arm/boot/dts/rk3xxx.dtsi
+++ b/arch/arm/boot/dts/rk3xxx.dtsi
@@ -26,6 +26,11 @@
compatible = "simple-bus";
ranges;
+ scu at 1013c000 {
+ compatible = "arm,cortex-a9-scu";
+ reg = <0x1013c000 0x100>;
+ };
+
gic: interrupt-controller at 1013d000 {
compatible = "arm,cortex-a9-gic";
interrupt-controller;
diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
index cf073de..412cbcf 100644
--- a/arch/arm/mach-rockchip/Kconfig
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -5,6 +5,7 @@ config ARCH_ROCKCHIP
select ARCH_REQUIRE_GPIOLIB
select ARM_GIC
select CACHE_L2X0
+ select HAVE_ARM_SCU
select HAVE_ARM_TWD if SMP
select HAVE_SMP
select COMMON_CLK
--
1.7.10.4
^ permalink raw reply related
* [PATCH v7 5/7] ARM: rockchip: add sram dt nodes and documentation
From: Heiko Stübner @ 2014-01-20 15:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4970034.fqvMoHdOyd@phil>
Add dt-nodes for the sram on rk3066 and rk3188 including the reserved section
needed for smp bringup.
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Ulrich Prinz <ulrich.prinz@googlemail.com>
---
.../devicetree/bindings/arm/rockchip/smp-sram.txt | 23 ++++++++++++++++++++
arch/arm/boot/dts/rk3066a.dtsi | 6 +++++
arch/arm/boot/dts/rk3188.dtsi | 6 +++++
3 files changed, 35 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/rockchip/smp-sram.txt
diff --git a/Documentation/devicetree/bindings/arm/rockchip/smp-sram.txt b/Documentation/devicetree/bindings/arm/rockchip/smp-sram.txt
new file mode 100644
index 0000000..80c878e
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/rockchip/smp-sram.txt
@@ -0,0 +1,23 @@
+Rockchip SRAM for smp bringup:
+------------------------------
+
+Rockchip's smp-capable SoCs use the first part of the sram for the bringup
+of the cores. Once the core gets powered up it executes the code that is
+residing at the very beginning of the sram.
+
+Therefore a reserved section has to be added to the mmio-sram declaration.
+
+Required node properties:
+- compatible : should contain both "rockchip,rk3066-sram", "mmio-sram"
+ so that the smp code can select the correct sram node.
+
+The rest of the properties should follow the generic mmio-sram discription
+found in ../../misc/sram.txt
+
+Example:
+
+ sram: sram at 10080000 {
+ compatible = "rockchip,rk3066-sram", "mmio-sram";
+ reg = <0x10080000 0x10000>;
+ mmio-sram-reserved = <0x0 0x50>;
+ };
diff --git a/arch/arm/boot/dts/rk3066a.dtsi b/arch/arm/boot/dts/rk3066a.dtsi
index be5d2b0..0dfb680 100644
--- a/arch/arm/boot/dts/rk3066a.dtsi
+++ b/arch/arm/boot/dts/rk3066a.dtsi
@@ -64,6 +64,12 @@
clock-names = "timer", "pclk";
};
+ sram: sram at 10080000 {
+ compatible = "rockchip,rk3066-sram", "mmio-sram";
+ reg = <0x10080000 0x10000>;
+ mmio-sram-reserved = <0x0 0x50>;
+ };
+
pinctrl at 20008000 {
compatible = "rockchip,rk3066a-pinctrl";
reg = <0x20008000 0x150>;
diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi
index 1a26b03..1fc7eda 100644
--- a/arch/arm/boot/dts/rk3188.dtsi
+++ b/arch/arm/boot/dts/rk3188.dtsi
@@ -60,6 +60,12 @@
interrupts = <GIC_PPI 13 0xf04>;
};
+ sram: sram at 10080000 {
+ compatible = "rockchip,rk3066-sram", "mmio-sram";
+ reg = <0x10080000 0x8000>;
+ mmio-sram-reserved = <0x0 0x50>;
+ };
+
pinctrl at 20008000 {
compatible = "rockchip,rk3188-pinctrl";
reg = <0x20008000 0xa0>,
--
1.7.10.4
^ permalink raw reply related
* [PATCH v7 6/7] ARM: rockchip: add power-management-unit
From: Heiko Stübner @ 2014-01-20 15:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4970034.fqvMoHdOyd@phil>
The pmu is needed to bring up the cores during smp operations and later
also other system parts. Therefore add a node and documentation for it.
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Ulrich Prinz <ulrich.prinz@googlemail.com>
---
Documentation/devicetree/bindings/arm/rockchip/pmu.txt | 16 ++++++++++++++++
arch/arm/boot/dts/rk3xxx.dtsi | 5 +++++
2 files changed, 21 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/rockchip/pmu.txt
diff --git a/Documentation/devicetree/bindings/arm/rockchip/pmu.txt b/Documentation/devicetree/bindings/arm/rockchip/pmu.txt
new file mode 100644
index 0000000..3ee9b42
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/rockchip/pmu.txt
@@ -0,0 +1,16 @@
+Rockchip power-management-unit:
+-------------------------------
+
+The pmu is used to turn off and on different power domains of the SoCs
+This includes the power to the CPU cores.
+
+Required node properties:
+- compatible value : = "rockchip,rk3066-pmu";
+- reg : physical base address and the size of the registers window
+
+Example:
+
+ pmu at 20004000 {
+ compatible = "rockchip,rk3066-pmu";
+ reg = <0x20004000 0x100>;
+ };
diff --git a/arch/arm/boot/dts/rk3xxx.dtsi b/arch/arm/boot/dts/rk3xxx.dtsi
index 0a3d5b1..26e5a96 100644
--- a/arch/arm/boot/dts/rk3xxx.dtsi
+++ b/arch/arm/boot/dts/rk3xxx.dtsi
@@ -31,6 +31,11 @@
reg = <0x1013c000 0x100>;
};
+ pmu at 20004000 {
+ compatible = "rockchip,rk3066-pmu";
+ reg = <0x20004000 0x100>;
+ };
+
gic: interrupt-controller at 1013d000 {
compatible = "arm,cortex-a9-gic";
interrupt-controller;
--
1.7.10.4
^ permalink raw reply related
* [PATCH v7 7/7] ARM: rockchip: add smp bringup code
From: Heiko Stübner @ 2014-01-20 15:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4970034.fqvMoHdOyd@phil>
This adds the necessary smp-operations and startup code to use
additional cores on Rockchip SoCs.
We currently hog the power management unit in the smp code, as it is
necessary to control the power to the cpu core and nothing else is
currently using it, so a generic implementation can be done later.
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Ulrich Prinz <ulrich.prinz@googlemail.com>
---
arch/arm/mach-rockchip/Makefile | 1 +
arch/arm/mach-rockchip/core.h | 22 ++++
arch/arm/mach-rockchip/headsmp.S | 30 ++++++
arch/arm/mach-rockchip/platsmp.c | 208 +++++++++++++++++++++++++++++++++++++
arch/arm/mach-rockchip/rockchip.c | 2 +
5 files changed, 263 insertions(+)
create mode 100644 arch/arm/mach-rockchip/core.h
create mode 100644 arch/arm/mach-rockchip/headsmp.S
create mode 100644 arch/arm/mach-rockchip/platsmp.c
diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile
index 1547d4f..4377a14 100644
--- a/arch/arm/mach-rockchip/Makefile
+++ b/arch/arm/mach-rockchip/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip.o
+obj-$(CONFIG_SMP) += headsmp.o platsmp.o
diff --git a/arch/arm/mach-rockchip/core.h b/arch/arm/mach-rockchip/core.h
new file mode 100644
index 0000000..e2e7c9d
--- /dev/null
+++ b/arch/arm/mach-rockchip/core.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+extern char rockchip_secondary_trampoline;
+extern char rockchip_secondary_trampoline_end;
+
+extern unsigned long rockchip_boot_fn;
+extern void rockchip_secondary_startup(void);
+
+extern struct smp_operations rockchip_smp_ops;
diff --git a/arch/arm/mach-rockchip/headsmp.S b/arch/arm/mach-rockchip/headsmp.S
new file mode 100644
index 0000000..73206e3
--- /dev/null
+++ b/arch/arm/mach-rockchip/headsmp.S
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+ENTRY(rockchip_secondary_startup)
+ bl v7_invalidate_l1
+ b secondary_startup
+ENDPROC(rockchip_secondary_startup)
+
+ENTRY(rockchip_secondary_trampoline)
+ ldr pc, 1f
+ENDPROC(rockchip_secondary_trampoline)
+ .globl rockchip_boot_fn
+rockchip_boot_fn:
+1: .space 4
+
+ENTRY(rockchip_secondary_trampoline_end)
diff --git a/arch/arm/mach-rockchip/platsmp.c b/arch/arm/mach-rockchip/platsmp.c
new file mode 100644
index 0000000..3459b17
--- /dev/null
+++ b/arch/arm/mach-rockchip/platsmp.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <asm/cacheflush.h>
+#include <asm/smp_scu.h>
+#include <asm/smp_plat.h>
+#include <asm/mach/map.h>
+
+#include "core.h"
+
+static void __iomem *scu_base_addr;
+static void __iomem *sram_base_addr;
+static int ncores;
+
+#define PMU_PWRDN_CON 0x08
+#define PMU_PWRDN_ST 0x0c
+
+#define PMU_PWRDN_SCU 4
+
+static void __iomem *pmu_base_addr;
+
+static inline bool pmu_power_domain_is_on(int pd)
+{
+ return !(readl_relaxed(pmu_base_addr + PMU_PWRDN_ST) & BIT(pd));
+}
+
+static void pmu_set_power_domain(int pd, bool on)
+{
+ u32 val = readl_relaxed(pmu_base_addr + PMU_PWRDN_CON);
+ if (on)
+ val &= ~BIT(pd);
+ else
+ val |= BIT(pd);
+ writel(val, pmu_base_addr + PMU_PWRDN_CON);
+
+ while (pmu_power_domain_is_on(pd) != on) { }
+}
+
+/*
+ * Handling of CPU cores
+ */
+
+static int __cpuinit rockchip_boot_secondary(unsigned int cpu,
+ struct task_struct *idle)
+{
+ if (!sram_base_addr || !pmu_base_addr) {
+ pr_err("%s: sram or pmu missing for cpu boot\n", __func__);
+ return -ENXIO;
+ }
+
+ if (cpu >= ncores) {
+ pr_err("%s: cpu %d outside maximum number of cpus %d\n",
+ __func__, cpu, ncores);
+ return -ENXIO;
+ }
+
+ /* start the core */
+ pmu_set_power_domain(0 + cpu, true);
+
+ return 0;
+}
+
+/**
+ * rockchip_smp_prepare_sram - populate necessary sram block
+ * Starting cores execute the code residing at the start of the on-chip sram
+ * after power-on. Therefore make sure, this sram region is reserved and
+ * big enough. After this check, copy the trampoline code that directs the
+ * core to the real startup code in ram into the sram-region.
+ * @node: mmio-sram device node
+ */
+static int __init rockchip_smp_prepare_sram(struct device_node *node)
+{
+ unsigned int trampoline_sz = &rockchip_secondary_trampoline_end -
+ &rockchip_secondary_trampoline;
+ const __be32 *reserved_list = NULL;
+ int reserved_size;
+ int rstart = -1;
+ unsigned int rsize;
+ unsigned int i;
+
+ reserved_list = of_get_property(node, "mmio-sram-reserved",
+ &reserved_size);
+ if (!reserved_list) {
+ pr_err("%s: wrong number of arguments in mmio-sram-reserved\n",
+ __func__);
+ return -ENOENT;
+ }
+
+ reserved_size /= sizeof(*reserved_list);
+ if (!reserved_size || reserved_size % 2) {
+ pr_err("%s: wrong number of arguments in mmio-sram-reserved\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < reserved_size; i += 2) {
+ /* get the next reserved block */
+ rstart = be32_to_cpu(*reserved_list++);
+ rsize = be32_to_cpu(*reserved_list++);
+
+ if (!rstart)
+ break;
+ }
+
+ if (rstart) {
+ pr_err("%s: start of sram is not reserved from mmio-sram\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (rsize < trampoline_sz) {
+ pr_err("%s: reserved block with size 0x%x is to small for trampoline size 0x%x\n",
+ __func__, rsize, trampoline_sz);
+ return -EINVAL;
+ }
+
+ sram_base_addr = of_iomap(node, 0);
+
+ /* set the boot function for the sram code */
+ rockchip_boot_fn = virt_to_phys(rockchip_secondary_startup);
+
+ /* copy the trampoline to sram, that runs during startup of the core */
+ memcpy(sram_base_addr, &rockchip_secondary_trampoline, trampoline_sz);
+ flush_cache_all();
+ outer_clean_range(0, trampoline_sz);
+
+ dsb_sev();
+
+ return 0;
+}
+
+static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus)
+{
+ struct device_node *node;
+ unsigned int i;
+
+ node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
+ if (!node) {
+ pr_err("%s: missing scu\n", __func__);
+ return;
+ }
+
+ scu_base_addr = of_iomap(node, 0);
+ if (!scu_base_addr) {
+ pr_err("%s: could not map scu registers\n", __func__);
+ return;
+ }
+
+ node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-sram");
+ if (!node) {
+ pr_err("%s: could not find sram dt node\n", __func__);
+ return;
+ }
+
+ if (rockchip_smp_prepare_sram(node))
+ return;
+
+ node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-pmu");
+ if (!node) {
+ pr_err("%s: could not find sram dt node\n", __func__);
+ return;
+ }
+
+ pmu_base_addr = of_iomap(node, 0);
+ if (!pmu_base_addr) {
+ pr_err("%s: could not map pmu registers\n", __func__);
+ return;
+ }
+
+ /* enable the SCU power domain */
+ pmu_set_power_domain(PMU_PWRDN_SCU, true);
+
+ /*
+ * While the number of cpus is gathered from dt, also get the number
+ * of cores from the scu to verify this value when booting the cores.
+ */
+ ncores = scu_get_core_count(scu_base_addr);
+
+ scu_enable(scu_base_addr);
+
+ /* Make sure that all cores except the first are really off */
+ for (i = 1; i < ncores; i++)
+ pmu_set_power_domain(0 + i, false);
+}
+
+struct smp_operations rockchip_smp_ops __initdata = {
+ .smp_prepare_cpus = rockchip_smp_prepare_cpus,
+ .smp_boot_secondary = rockchip_boot_secondary,
+};
diff --git a/arch/arm/mach-rockchip/rockchip.c b/arch/arm/mach-rockchip/rockchip.c
index 82c0b07..d211d6f 100644
--- a/arch/arm/mach-rockchip/rockchip.c
+++ b/arch/arm/mach-rockchip/rockchip.c
@@ -22,6 +22,7 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/hardware/cache-l2x0.h>
+#include "core.h"
static void __init rockchip_dt_init(void)
{
@@ -38,6 +39,7 @@ static const char * const rockchip_board_dt_compat[] = {
};
DT_MACHINE_START(ROCKCHIP_DT, "Rockchip Cortex-A9 (Device Tree)")
+ .smp = smp_ops(rockchip_smp_ops),
.init_machine = rockchip_dt_init,
.dt_compat = rockchip_board_dt_compat,
MACHINE_END
--
1.7.10.4
^ permalink raw reply related
* [PATCH] ARM: shmobile: compile drivers/sh for CONFIG_ARCH_SHMOBILE_MULTI
From: Laurent Pinchart @ 2014-01-20 15:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <52DD224B.1050502@codethink.co.uk>
On Monday 20 January 2014 13:19:07 Ben Dooks wrote:
> I've added linux-arm-kernel to the list to get a wider view from
> people who actively use the clock subsystem.
>
> On 20/01/14 12:54, Mark Brown wrote:
> > On Mon, Jan 20, 2014 at 12:01:00PM +0000, Ben Dooks wrote:
> >> On 20/01/14 11:47, Mark Brown wrote:
> >>> I think that just makes things more complicated and isn't adding
> >>> anything over pm_runtime_enable(), it's just boilerplate code. In
> >>> theory essentially every driver running on platforms which don't have
> >>> explicit management of core IP clocks ought to be calling this since
> >>> potentially the IP might be deployed on another platform which does have
> >>> clock management (this does actually happen with things like the
> >>> DesignWare IPs) and it doesn't do anything like say which clocks are
> >>> expected to be managed in this way which is another thing that can come
> >>> up when moving devices between platforms.
> >>
> >> That sounds like a real headache where you have two sets of code
> >> looking at possibly the same clocks, and behaving differently between
> >> different platforms.
> >
> > Yup, it's usually only one set of code on the client side but it's
> > annoying that platform integrations aren't done consistently in hardware
> > and that this flows through into software.
> >
> >>> I'm also struggling to see how it provides any sort of build time
> >>> protection, it would allow the generation of a warning at runtime at
> >>> best.
> >>
> >> If you don't have the code it WILL NOT LINK. At the moment it is
> >> entirely possible to link a kernel which will produce a set of confusing
> >> errors as drivers fail to initialise at startup.
> >
> > How will this prevent the code linking? I would expect the "manage the
> > clocks via runtime PM" call to be a bit of core code, I wouldn't expect
> > it to be provided by a specific platform otherwise we're in for fail in
> > a multiplatform environment. Besides, if it fails to link there's some
> > missing Kconfig anyway since randconfig is supposed to work.
> >
> >> We've already had other people run into the issue where they do not
> >> know why a driver is failing to work (rcar-thermal is one) as the code
> >> that was managing the clock for it magically vanished during the
> >> development cycle.
> >
> > I agree there's a usability problem here, I just don't think that this
> > is the best fix for it, I think it's breaking abstractions.
> >
> >>> As far as I can tell the problem that Ben has seen here is that the
> >>> platform really, really needs the code for its power domains running to
> >>> be functional (this doesn't seem unreasonable and may not be related to
> >>> clocks, this may be required to have the IPs powered up at all). I'd
> >>> expect this is something for the platform to sort out rather than
> >>> something for individual drivers to have to carry code for.
> >>
> >> What's power domains got to do with this? You keep bringing this up
> >> but the error is purely to do with clock management. The code happens
> >> to be sitting in the drivers/base/pm directory, but could easily sit
> >> elsewhere.
> >
> > What these platforms are saying is esssentially that the clocks are part
> > of the power domain - they're a fundamental part of getting the IP
> > available for use so there is no point in managing them separately.
> > This is where I think the abstraction problem is coming, to me it seems
> > like the platform isn't successfully ensuring that the code to manage
> > the power domain is there. The fact that part of what's missing is the
> > clocks shouldn't matter to the drivers, in doing things like this the
> > platform is trying to abstract that detail away from the drivers.
> >
> >>> If it was going to be drivers carrying code for this I would expect it
> >>> to be something like providing a list of clocks to be managed along with
> >>> runtime PM - this would also make the code more widely applicable since
> >>> it's quite common for the runtime PM callbacks to do nothing more than
> >>> just enable and disable clocks.
> >>
> >> If we are really saying that bus clocks should not be managed
> >> by the drivers, then we should just enable this across the whole
> >> kernel and remove the management from any extant drivers (or make
> >> it so that any drivers that must manage their bus clocks have a
> >> call to do so).
> >
> > Yes, I think that would be a useful way to go since it would factor out
> > some common code patterns that keep cropping up (as I suggested to you
> > previously). It may not just be the main IP clocks that the drivers are
> > managing like this (some drivers end up managing other clocks at the
> > same time even if they could be more flexible) so if it was something
> > drivers could make use of themselves that'd be good.
>
> At the moment, the code to actually use the support is sitting in
> drivers/sh and gets initialised if it is built. This is the source
> of the original confusions.
>
> I think it would be ok if drivers could /opt out/
Most drivers have a single functional clock (if any) and only need it to be
enabled/disabled in sync with runtime PM. As this requirements is common,
making it the default sounds reasonable. Other drivers need to manage their
clocks, or at least part of their clocks, manually. There are good and bad
reasons for this, and some bad reasons come from driver code that should be
fixed, but we can't ignore the problems for now.
The simplest implementation would be a way to let a driver opt-out completely.
Unless a driver opts out, the runtime PM core will get the default clock for
the device (with a NULL con ID) and manage it automatically. I'm not sure what
to do when the runtime PM core fails to get the clock, as this can be caused
by various problems or non-problems.
One particular problem that needs to be considered is deferred probing. An
option would be to have all non-SoC devices opt-out from automatic clock
management, but that will make the opt-out case the most common one. We also
need to consider IP cores that can be present on-SoC or off-SoC in discrete
chips.
The problem isn't as simple as it seems, and more advanced implementations
that would allow listing clocks that should be managed automatically (or the
other way around) would also add another level of complexity. The required
information is platform-dependent, but we currently don't express it as such
in DT.
> if the bus clock handling was done like this for all platforms and we simply
> noted that the pm code is doing it. At that point it would be nice just to
> build the code in drivers/base/power unconditionally.
>
> At the moment we could quite easily enable this code for all the ARM
> platforms as the clk framework should deal nicely with properly balanced
> clk_enable() and clk_disable() calls.
>
> Enabling it across the board would also remove any issues with changes in
> platform behaviour and find any bugs sooner rather than later.
--
Regards,
Laurent Pinchart
^ permalink raw reply
* [PATCH] ARM: shmobile: compile drivers/sh for CONFIG_ARCH_SHMOBILE_MULTI
From: Mark Brown @ 2014-01-20 15:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482392.XFeYNLvUZH@avalon>
On Mon, Jan 20, 2014 at 04:48:10PM +0100, Laurent Pinchart wrote:
> The problem isn't as simple as it seems, and more advanced implementations
> that would allow listing clocks that should be managed automatically (or the
> other way around) would also add another level of complexity. The required
> information is platform-dependent, but we currently don't express it as such
> in DT.
Well, the set of clocks an IP requires will tend to be the same - it's
normally just that integrators may have done things like tie them
together or decide to spread confusion by renaming them.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140120/4673e8f6/attachment.sig>
^ permalink raw reply
* [PATCH v2 00/16] ARM: support for ICP DAS LP-8x4x (with dts)
From: Sergei Ianovich @ 2014-01-20 16:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1389309176.32346.1.camel@host5.omatika.ru>
On Fri, 2014-01-10 at 03:12 +0400, Sergei Ianovich wrote:
> On Thu, 2013-12-19 at 06:30 +0100, Arnd Bergmann wrote:
> > This would work only if we can probe the devices behind the external
> > bus controller before the controller itsef has been set up, since
> > the initialization order can depend on a number of things but not
> > the bus hierarchy. It will also work if the code setting up the
> > bus controller can be guaranteed to run before we call
> > of_platform_populate for the regular devices, which is probably
> > the best solution here.
>
> There has been no activity for 3 weeks. Could we resume the series?
It's over a month now. Is anything wrong?
^ permalink raw reply
* PWM...
From: Mark Brown @ 2014-01-20 16:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140120001446.GD9752@verge.net.au>
On Mon, Jan 20, 2014 at 09:14:46AM +0900, Simon Horman wrote:
> On Sun, Jan 19, 2014 at 09:26:40PM +0100, Arnd Bergmann wrote:
> > Right: if you change an existing dts file from #pwm-cells=<2> to
> > #pwm-cells=<3>, that requires changing all references to the pwm
> Would this change imply that old dtbs would no longer work with new kernels?
So long as the code can still handle both values for #pwm-cells existing
DTBs should work fine.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140120/54d626fe/attachment.sig>
^ permalink raw reply
* [PATCH v2 00/16] ARM: support for ICP DAS LP-8x4x (with dts)
From: Daniel Mack @ 2014-01-20 16:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390234117.25903.0.camel@host5.omatika.ru>
On 01/20/2014 05:08 PM, Sergei Ianovich wrote:
> On Fri, 2014-01-10 at 03:12 +0400, Sergei Ianovich wrote:
>> On Thu, 2013-12-19 at 06:30 +0100, Arnd Bergmann wrote:
>>> This would work only if we can probe the devices behind the external
>>> bus controller before the controller itsef has been set up, since
>>> the initialization order can depend on a number of things but not
>>> the bus hierarchy. It will also work if the code setting up the
>>> bus controller can be guaranteed to run before we call
>>> of_platform_populate for the regular devices, which is probably
>>> the best solution here.
>>
>> There has been no activity for 3 weeks. Could we resume the series?
>
> It's over a month now. Is anything wrong?
>
No, I'm busy, that's all.
That said, the current situation is
a) we need someone to have a look at the performance regression of the
MMC file system layer that you reported. I couldn't find a PXA-based
board yet with a MMC slot soldered on it. But as you apparently have
such hardware, I'd really appreciate your help here. Could you do some
measurements and see whether you see major differences in packet size or
timings?
b) Marek Vasut thankfully reported back to me and signaled success with
his pxa-pata driver. So we're most probably good in that area.
c) Robert Jarzmik is still in the process of converting the camera
driver. Here as well, I lack hardware, I can't even compile-test
anything here.
So please, if you have any spare time, have a look at the MMC
regressions and see if you can contribute anything. I'll hope to find
some time to rebase my patches on top of 3.13 very soon, so we have a
new base to work on.
Thanks,
Daniel
^ permalink raw reply
* [PATCH RFC 04/10] base: power: Add generic OF-based power domain look-up
From: Tomasz Figa @ 2014-01-20 16:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <87r48a8t99.fsf@linaro.org>
Hi Kevin,
On 14.01.2014 16:42, Kevin Hilman wrote:
> Tomasz Figa <tomasz.figa@gmail.com> writes:
>
>> This patch introduces generic code to perform power domain look-up using
>> device tree and automatically bind devices to their power domains.
>> Generic device tree binding is introduced to specify power domains of
>> devices in their device tree nodes.
>>
>> Backwards compatibility with legacy Samsung-specific power domain
>> bindings is provided, but for now the new code is not compiled when
>> CONFIG_ARCH_EXYNOS is selected to avoid collision with legacy code. This
>> will change as soon as Exynos power domain code gets converted to use
>> the generic framework in further patch.
>>
>> Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
>
> I haven't read through this in detail yet, but wanted to make sure that
> the DT representation can handle nested power domains. At least
> SH-mobile has a hierarchy of power domains and the genpd code can handle
> that, so wanted to make sure that the DT representation can handle it as
> well.
The representation of power domains themselves as implied by this patch
is fully platform-specific. The only generic part is the
#power-domain-cells property, which defines the number of cells needed
to identify the power domain of given provider. You are free to have any
platform-specific properties (or even generic ones, added on top of this
patch) to let you specify the hierarchy in DT.
Best regards,
Tomasz
^ permalink raw reply
* [RFC PATCH 2/3] arm64: KVM: trap VM system registers until MMU and caches are ON
From: Anup Patel @ 2014-01-20 16:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <52DD27A6.5010706@arm.com>
Hi Marc,
On Mon, Jan 20, 2014 at 7:11 PM, Marc Zyngier <marc.zyngier@arm.com> wrote:
> Hi Anup,
>
> On 20/01/14 12:00, Anup Patel wrote:
>> On Fri, Jan 17, 2014 at 8:33 PM, Marc Zyngier <marc.zyngier@arm.com> wrote:
>>> In order to be able to detect the point where the guest enables
>>> its MMU and caches, trap all the VM related system registers.
>>>
>>> Once we see the guest enabling both the MMU and the caches, we
>>> can go back to a saner mode of operation, which is to leave these
>>> registers in complete control of the guest.
>>>
>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
>>> ---
>>> arch/arm64/include/asm/kvm_arm.h | 3 ++-
>>> arch/arm64/kvm/sys_regs.c | 58 ++++++++++++++++++++++++++++++++--------
>>> 2 files changed, 49 insertions(+), 12 deletions(-)
>>>
>>> diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
>>> index c98ef47..fd0a651 100644
>>> --- a/arch/arm64/include/asm/kvm_arm.h
>>> +++ b/arch/arm64/include/asm/kvm_arm.h
>>> @@ -62,6 +62,7 @@
>>> * RW: 64bit by default, can be overriden for 32bit VMs
>>> * TAC: Trap ACTLR
>>> * TSC: Trap SMC
>>> + * TVM: Trap VM ops (until M+C set in SCTLR_EL1)
>>> * TSW: Trap cache operations by set/way
>>> * TWE: Trap WFE
>>> * TWI: Trap WFI
>>> @@ -74,7 +75,7 @@
>>> * SWIO: Turn set/way invalidates into set/way clean+invalidate
>>> */
>>> #define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \
>>> - HCR_BSU_IS | HCR_FB | HCR_TAC | \
>>> + HCR_TVM | HCR_BSU_IS | HCR_FB | HCR_TAC | \
>>> HCR_AMO | HCR_IMO | HCR_FMO | \
>>> HCR_SWIO | HCR_TIDCP | HCR_RW)
>>> #define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
>>> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
>>> index 02e9d09..5e92b9e 100644
>>> --- a/arch/arm64/kvm/sys_regs.c
>>> +++ b/arch/arm64/kvm/sys_regs.c
>>> @@ -121,6 +121,42 @@ done:
>>> }
>>>
>>> /*
>>> + * Generic accessor for VM registers. Only called as long as HCR_TVM
>>> + * is set.
>>> + */
>>> +static bool access_vm_reg(struct kvm_vcpu *vcpu,
>>> + const struct sys_reg_params *p,
>>> + const struct sys_reg_desc *r)
>>> +{
>>> + BUG_ON(!p->is_write);
>>> +
>>> + vcpu_sys_reg(vcpu, r->reg) = *vcpu_reg(vcpu, p->Rt);
>>> + return true;
>>> +}
>>> +
>>> +/*
>>> + * SCTLR_EL1 accessor. Only called as long as HCR_TVM is set. If the
>>> + * guest enables the MMU, we stop trapping the VM sys_regs and leave
>>> + * it in complete control of the caches.
>>> + */
>>> +static bool access_sctlr_el1(struct kvm_vcpu *vcpu,
>>> + const struct sys_reg_params *p,
>>> + const struct sys_reg_desc *r)
>>> +{
>>> + unsigned long val;
>>> +
>>> + BUG_ON(!p->is_write);
>>> +
>>> + val = *vcpu_reg(vcpu, p->Rt);
>>> + vcpu_sys_reg(vcpu, r->reg) = val;
>>> +
>>> + if ((val & (0b101)) == 0b101) /* MMU+Caches enabled? */
>>> + vcpu->arch.hcr_el2 &= ~HCR_TVM;
>>> +
>>> + return true;
>>> +}
>>> +
>>> +/*
>>> * We could trap ID_DFR0 and tell the guest we don't support performance
>>> * monitoring. Unfortunately the patch to make the kernel check ID_DFR0 was
>>> * NAKed, so it will read the PMCR anyway.
>>> @@ -185,32 +221,32 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>>> NULL, reset_mpidr, MPIDR_EL1 },
>>> /* SCTLR_EL1 */
>>> { Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b000),
>>> - NULL, reset_val, SCTLR_EL1, 0x00C50078 },
>>> + access_sctlr_el1, reset_val, SCTLR_EL1, 0x00C50078 },
>>
>> This patch in its current form breaks Aarch32 VMs on Foundation v8 Model
>> because encoding for Aarch64 VM registers we get Op0=0b11 and for Aarch32
>> VM registers we get Op0=0b00 when trapped.
>>
>> Either its a Foundation v8 Model bug or we need to add more enteries in
>> sys_reg_desc[] for Aarch32 VM registers with Op0=0b00.
>
> That's a good point. But Op0 isn't defined for AArch32, the value is
> simply hardcoded in kvm_handle_cp15_32/kvm_handle_cp15_64, which is
> obviously horribly broken.
>
> I'll work on a fix for that, thanks noticing it.
>
> Does this series otherwise fix your L3 cache issue (assuming you stick
> to 64bit guests)?
Just started trying your patches today.
First tried on Foundation v8 Model.
Next we will try on X-Gene.
Me or Pranav will soon provide more feedback in this regard.
>
> Cheers,
>
> M.
> --
> Jazz is not dead. It just smells funny...
Thanks,
Anup
^ permalink raw reply
* [PATCH 1/3] mmc: add support for power-on sequencing through DT
From: Mark Brown @ 2014-01-20 16:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390190215-22700-2-git-send-email-olof@lixom.net>
On Sun, Jan 19, 2014 at 07:56:53PM -0800, Olof Johansson wrote:
> + if (host->card_regulator) {
NULL is a potentially valid regulator; use IS_ERR(). Also see below...
> + dev_dbg(host->parent, "Enabling external regulator");
> + if (regulator_enable(host->card_regulator))
> + dev_err(host->parent, "Failed to enable external regulator");
You should really log the error code here.
> + host->card_regulator = regulator_get(host->parent, "card-external-vcc");
> +
...this won't handle probe deferral or other errors. Given what this is
for it should probably be using regulator_get_optional(), the driver is
happy to carry on if a supply isn't available. On the other hand it
just enables and disables so it's probably easier to just ignore that
and let the stub regulator get used anyway.
I have to say I do worry what happens if the device has multiple
supplies that need to be managed (which is common enough, for example
analogue and digital supplies tend to be decoupled) or if the device can
do useful things with the supplies. In the case of SDIO it's *probably*
less relevant though I have seen applications where it might be.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140120/39e9521a/attachment.sig>
^ permalink raw reply
* [PATCH v7.1 7/7] ARM: rockchip: add smp bringup code
From: Heiko Stübner @ 2014-01-20 16:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <49656088.hl7gr3DUdp@phil>
This adds the necessary smp-operations and startup code to use
additional cores on Rockchip SoCs.
We currently hog the power management unit in the smp code, as it is
necessary to control the power to the cpu core and nothing else is
currently using it, so a generic implementation can be done later.
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Ulrich Prinz <ulrich.prinz@googlemail.com>
---
As somehow was to be expected, I forgot to change the second user of the
mmio-reserved data to use of_property_read_u32_index and the newly introduced
element count function.
arch/arm/mach-rockchip/Makefile | 1 +
arch/arm/mach-rockchip/core.h | 22 +++++
arch/arm/mach-rockchip/headsmp.S | 30 ++++++
arch/arm/mach-rockchip/platsmp.c | 196 +++++++++++++++++++++++++++++++++++++
arch/arm/mach-rockchip/rockchip.c | 2 +
5 files changed, 251 insertions(+)
create mode 100644 arch/arm/mach-rockchip/core.h
create mode 100644 arch/arm/mach-rockchip/headsmp.S
create mode 100644 arch/arm/mach-rockchip/platsmp.c
diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile
index 1547d4f..4377a14 100644
--- a/arch/arm/mach-rockchip/Makefile
+++ b/arch/arm/mach-rockchip/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip.o
+obj-$(CONFIG_SMP) += headsmp.o platsmp.o
diff --git a/arch/arm/mach-rockchip/core.h b/arch/arm/mach-rockchip/core.h
new file mode 100644
index 0000000..e2e7c9d
--- /dev/null
+++ b/arch/arm/mach-rockchip/core.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+extern char rockchip_secondary_trampoline;
+extern char rockchip_secondary_trampoline_end;
+
+extern unsigned long rockchip_boot_fn;
+extern void rockchip_secondary_startup(void);
+
+extern struct smp_operations rockchip_smp_ops;
diff --git a/arch/arm/mach-rockchip/headsmp.S b/arch/arm/mach-rockchip/headsmp.S
new file mode 100644
index 0000000..73206e3
--- /dev/null
+++ b/arch/arm/mach-rockchip/headsmp.S
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+ENTRY(rockchip_secondary_startup)
+ bl v7_invalidate_l1
+ b secondary_startup
+ENDPROC(rockchip_secondary_startup)
+
+ENTRY(rockchip_secondary_trampoline)
+ ldr pc, 1f
+ENDPROC(rockchip_secondary_trampoline)
+ .globl rockchip_boot_fn
+rockchip_boot_fn:
+1: .space 4
+
+ENTRY(rockchip_secondary_trampoline_end)
diff --git a/arch/arm/mach-rockchip/platsmp.c b/arch/arm/mach-rockchip/platsmp.c
new file mode 100644
index 0000000..4a49103
--- /dev/null
+++ b/arch/arm/mach-rockchip/platsmp.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <asm/cacheflush.h>
+#include <asm/smp_scu.h>
+#include <asm/smp_plat.h>
+#include <asm/mach/map.h>
+
+#include "core.h"
+
+static void __iomem *scu_base_addr;
+static void __iomem *sram_base_addr;
+static int ncores;
+
+#define PMU_PWRDN_CON 0x08
+#define PMU_PWRDN_ST 0x0c
+
+#define PMU_PWRDN_SCU 4
+
+static void __iomem *pmu_base_addr;
+
+static inline bool pmu_power_domain_is_on(int pd)
+{
+ return !(readl_relaxed(pmu_base_addr + PMU_PWRDN_ST) & BIT(pd));
+}
+
+static void pmu_set_power_domain(int pd, bool on)
+{
+ u32 val = readl_relaxed(pmu_base_addr + PMU_PWRDN_CON);
+ if (on)
+ val &= ~BIT(pd);
+ else
+ val |= BIT(pd);
+ writel(val, pmu_base_addr + PMU_PWRDN_CON);
+
+ while (pmu_power_domain_is_on(pd) != on) { }
+}
+
+/*
+ * Handling of CPU cores
+ */
+
+static int __cpuinit rockchip_boot_secondary(unsigned int cpu,
+ struct task_struct *idle)
+{
+ if (!sram_base_addr || !pmu_base_addr) {
+ pr_err("%s: sram or pmu missing for cpu boot\n", __func__);
+ return -ENXIO;
+ }
+
+ if (cpu >= ncores) {
+ pr_err("%s: cpu %d outside maximum number of cpus %d\n",
+ __func__, cpu, ncores);
+ return -ENXIO;
+ }
+
+ /* start the core */
+ pmu_set_power_domain(0 + cpu, true);
+
+ return 0;
+}
+
+/**
+ * rockchip_smp_prepare_sram - populate necessary sram block
+ * Starting cores execute the code residing at the start of the on-chip sram
+ * after power-on. Therefore make sure, this sram region is reserved and
+ * big enough. After this check, copy the trampoline code that directs the
+ * core to the real startup code in ram into the sram-region.
+ * @node: mmio-sram device node
+ */
+static int __init rockchip_smp_prepare_sram(struct device_node *node)
+{
+ unsigned int trampoline_sz = &rockchip_secondary_trampoline_end -
+ &rockchip_secondary_trampoline;
+ int reserved_size;
+ int rstart = -1;
+ unsigned int rsize;
+
+ reserved_size = of_property_count_u32_elems(node, "mmio-sram-reserved");
+ if (reserved_size <= 0 || reserved_size % 2) {
+ pr_err("%s: incorrect mmio-sram-reserved property\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ of_property_read_u32_index(node, "mmio-sram-reserved", 0, &rstart);
+ of_property_read_u32_index(node, "mmio-sram-reserved", 1, &rsize);
+
+ /*
+ * Reserved sections are sorted in ascending order and we need
+ * the block starting@0. So everything else is an error.
+ */
+ if (rstart) {
+ pr_err("%s: start of sram is not reserved from mmio-sram\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (rsize < trampoline_sz) {
+ pr_err("%s: reserved block with size 0x%x is to small for trampoline size 0x%x\n",
+ __func__, rsize, trampoline_sz);
+ return -EINVAL;
+ }
+
+ sram_base_addr = of_iomap(node, 0);
+
+ /* set the boot function for the sram code */
+ rockchip_boot_fn = virt_to_phys(rockchip_secondary_startup);
+
+ /* copy the trampoline to sram, that runs during startup of the core */
+ memcpy(sram_base_addr, &rockchip_secondary_trampoline, trampoline_sz);
+ flush_cache_all();
+ outer_clean_range(0, trampoline_sz);
+
+ dsb_sev();
+
+ return 0;
+}
+
+static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus)
+{
+ struct device_node *node;
+ unsigned int i;
+
+ node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
+ if (!node) {
+ pr_err("%s: missing scu\n", __func__);
+ return;
+ }
+
+ scu_base_addr = of_iomap(node, 0);
+ if (!scu_base_addr) {
+ pr_err("%s: could not map scu registers\n", __func__);
+ return;
+ }
+
+ node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-sram");
+ if (!node) {
+ pr_err("%s: could not find sram dt node\n", __func__);
+ return;
+ }
+
+ if (rockchip_smp_prepare_sram(node))
+ return;
+
+ node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-pmu");
+ if (!node) {
+ pr_err("%s: could not find sram dt node\n", __func__);
+ return;
+ }
+
+ pmu_base_addr = of_iomap(node, 0);
+ if (!pmu_base_addr) {
+ pr_err("%s: could not map pmu registers\n", __func__);
+ return;
+ }
+
+ /* enable the SCU power domain */
+ pmu_set_power_domain(PMU_PWRDN_SCU, true);
+
+ /*
+ * While the number of cpus is gathered from dt, also get the number
+ * of cores from the scu to verify this value when booting the cores.
+ */
+ ncores = scu_get_core_count(scu_base_addr);
+
+ scu_enable(scu_base_addr);
+
+ /* Make sure that all cores except the first are really off */
+ for (i = 1; i < ncores; i++)
+ pmu_set_power_domain(0 + i, false);
+}
+
+struct smp_operations rockchip_smp_ops __initdata = {
+ .smp_prepare_cpus = rockchip_smp_prepare_cpus,
+ .smp_boot_secondary = rockchip_boot_secondary,
+};
diff --git a/arch/arm/mach-rockchip/rockchip.c b/arch/arm/mach-rockchip/rockchip.c
index 82c0b07..d211d6f 100644
--- a/arch/arm/mach-rockchip/rockchip.c
+++ b/arch/arm/mach-rockchip/rockchip.c
@@ -22,6 +22,7 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/hardware/cache-l2x0.h>
+#include "core.h"
static void __init rockchip_dt_init(void)
{
@@ -38,6 +39,7 @@ static const char * const rockchip_board_dt_compat[] = {
};
DT_MACHINE_START(ROCKCHIP_DT, "Rockchip Cortex-A9 (Device Tree)")
+ .smp = smp_ops(rockchip_smp_ops),
.init_machine = rockchip_dt_init,
.dt_compat = rockchip_board_dt_compat,
MACHINE_END
--
1.7.10.4
^ permalink raw reply related
* [PATCH] ARM: dts: Add basic devices for AM3517-craneboard
From: Nishanth Menon @ 2014-01-20 16:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <52B1D866.7040300@baylibre.com>
Benoit,
On 12/18/2013 11:16 AM, Benoit Cousson wrote:
> On 18/12/2013 18:02, Nishanth Menon wrote:
>> On 12/18/2013 10:57 AM, Benoit Cousson wrote:
>>> On 17/12/2013 20:45, Nishanth Menon wrote:
>>>> On 12/09/2013 03:55 PM, Nishanth Menon wrote:
>>>>> Craneboard is a hardware development platform based on the Sitara
>>>>> AM3517 ARM Cortex - A8 microprocessor device - see [1] for more
>>>>> details. Add basic devices for craneboard as replacement for the board
>>>>> file scheduled for removal as part of device tree conversion
>>>>>
>>>>> [1] http://craneboard.org
>>>>>
>>>>> Signed-off-by: Nishanth Menon <nm@ti.com>
>>>>> ---
>>>>
>>>> gentle ping.. had'nt seen a response on this patch. Could we queue
>>>> this up for v3.14-rc1?
>>>
>>> Yep, it looks good to me.
>> Thanks benoit.
>>
>>> But if you don't mind I'll start pushing my branch after Xmas :-).
>>
>> As long as Tony is ok with it, I have no issues either - will be great
>> to have dt only boot in .14-rc1 though.
>
> Good point, it is already -rc4.
>
> OK, I'll just queued it and pushed it to for_3.14/dts.
I dont see this in next-20140120 yet - wondering if Tony or you have
plans for one of .14 rcs OR if this is queued for .15.
--
Regards,
Nishanth Menon
^ permalink raw reply
* [PATCH RFC v4 00/10] ahci: library-ise ahci_platform, add sunxi driver and cleanup imx driver
From: Hans de Goede @ 2014-01-20 16:44 UTC (permalink / raw)
To: linux-arm-kernel
Hi All,
Here is v4 of my patchset for adding ahci-sunxi support. It has grown quite
a bit since I've been going for a more generic approach this time and I've
also cleaned up the ahci-imx driver to use the same generic approach.
History:
v1, by Olliver Schinagl:
This was using the approach of having a platform device which probe method
creates a new child platform device which gets driven by ahci_platform.c,
as done by ahci_imx.c .
v2, by Hans de Goede:
Stand-alone platform driver based on Olliver's work
v3, by Hans de Goede:
patch-series, with 4 different parts
a) Make ahci_platform.c more generic, handle more then 1 clk, target pwr
regulator
b) New ahci-sunxi code only populating ahci_platform_data, passed to
ahci_platform.c to of_device_id matching.
c) Refactor ahci-imx code to work the same as the new ahci-sunxi code, this
is the reason why v3 is an RFC, I'm waiting for the wandboard I ordered to
arrive so that I can actually test this.
d) dts bindings for the sunxi ahci parts
v4, by Hans de Goede:
patch-series, with 5 different parts:
a) Make ahci_platform.c more generic, handle more then 1 clk, target pwr
regulator
b) Turn parts of ahci_platform.c into a library for use by other drivers
c) New ahci-sunxi driver using the ahci_platform.c library functionality
d) Refactor ahci-imx code to work the same as the new ahci-sunxi code
e) dts bindings for the sunxi ahci parts
Parts a-d are intended for merging through the ata tree, the dts bindings
will be merged to Maxime Ripard's sunxi-dts tree.
Regards,
Hans
^ permalink raw reply
* [PATCH RFC v4 01/10] libahci: Allow drivers to override start_engine
From: Hans de Goede @ 2014-01-20 16:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390236303-22538-1-git-send-email-hdegoede@redhat.com>
Allwinner A10 and A20 ARM SoCs have an AHCI sata controller which needs a
special register to be poked before starting the DMA engine.
This register gets reset on an ahci_stop_engine call, so there is no other
place then ahci_start_engine where this poking can be done.
This commit allows drivers to override ahci_start_engine behavior for use by
the Allwinner AHCI driver (and potentially other drivers in the future).
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/ata/ahci.c | 6 ++++--
drivers/ata/ahci.h | 3 ++-
drivers/ata/libahci.c | 27 ++++++++++++++++++---------
drivers/ata/sata_highbank.c | 3 ++-
4 files changed, 26 insertions(+), 13 deletions(-)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index c0ed4f27..bb4c903 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -559,6 +559,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
struct ata_port *ap = link->ap;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
bool online;
int rc;
@@ -569,7 +570,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
deadline, &online, NULL);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
@@ -584,6 +585,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
{
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
bool online;
@@ -599,7 +601,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
deadline, &online, NULL);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
/* The pseudo configuration device on SIMG4726 attached to
* ASUS P5W-DH Deluxe doesn't send signature FIS after
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 2289efd..2c04211 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -323,6 +323,8 @@ struct ahci_host_priv {
u32 em_msg_type; /* EM message type */
struct clk *clk; /* Only for platforms supporting clk */
void *plat_data; /* Other platform data */
+ /* Optional ahci_start_engine override */
+ void (*start_engine)(struct ata_port *ap);
};
extern int ahci_ignore_sss;
@@ -357,7 +359,6 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
int (*check_ready)(struct ata_link *link));
int ahci_stop_engine(struct ata_port *ap);
-void ahci_start_engine(struct ata_port *ap);
int ahci_check_ready(struct ata_link *link);
int ahci_kick_engine(struct ata_port *ap);
int ahci_port_resume(struct ata_port *ap);
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index c482f8c..96d128c 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -69,6 +69,7 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
+static void ahci_start_engine(struct ata_port *ap);
static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
static int ahci_port_start(struct ata_port *ap);
@@ -500,6 +501,9 @@ void ahci_save_initial_config(struct device *dev,
hpriv->cap = cap;
hpriv->cap2 = cap2;
hpriv->port_map = port_map;
+
+ if (!hpriv->start_engine)
+ hpriv->start_engine = ahci_start_engine;
}
EXPORT_SYMBOL_GPL(ahci_save_initial_config);
@@ -565,7 +569,7 @@ static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
return -EINVAL;
}
-void ahci_start_engine(struct ata_port *ap)
+static void ahci_start_engine(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
u32 tmp;
@@ -576,7 +580,6 @@ void ahci_start_engine(struct ata_port *ap)
writel(tmp, port_mmio + PORT_CMD);
readl(port_mmio + PORT_CMD); /* flush */
}
-EXPORT_SYMBOL_GPL(ahci_start_engine);
int ahci_stop_engine(struct ata_port *ap)
{
@@ -766,7 +769,7 @@ static void ahci_start_port(struct ata_port *ap)
/* enable DMA */
if (!(hpriv->flags & AHCI_HFLAG_DELAY_ENGINE))
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
/* turn on LEDs */
if (ap->flags & ATA_FLAG_EM) {
@@ -1234,7 +1237,7 @@ int ahci_kick_engine(struct ata_port *ap)
/* restart engine */
out_restart:
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
return rc;
}
EXPORT_SYMBOL_GPL(ahci_kick_engine);
@@ -1426,6 +1429,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
bool online;
@@ -1443,7 +1447,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
rc = sata_link_hardreset(link, timing, deadline, &online,
ahci_check_ready);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
if (online)
*class = ahci_dev_classify(ap);
@@ -2007,10 +2011,12 @@ static void ahci_thaw(struct ata_port *ap)
void ahci_error_handler(struct ata_port *ap)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
/* restart engine */
ahci_stop_engine(ap);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
}
sata_pmp_error_handler(ap);
@@ -2031,6 +2037,7 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
struct ata_device *dev = ap->link.device;
u32 devslp, dm, dito, mdat, deto;
@@ -2094,7 +2101,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
PORT_DEVSLP_ADSE);
writel(devslp, port_mmio + PORT_DEVSLP);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
/* enable device sleep feature for the drive */
err_mask = ata_dev_set_feature(dev,
@@ -2106,6 +2113,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
static void ahci_enable_fbs(struct ata_port *ap)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp = ap->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
u32 fbs;
@@ -2134,11 +2142,12 @@ static void ahci_enable_fbs(struct ata_port *ap)
} else
dev_err(ap->host->dev, "Failed to enable FBS\n");
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
}
static void ahci_disable_fbs(struct ata_port *ap)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp = ap->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
u32 fbs;
@@ -2166,7 +2175,7 @@ static void ahci_disable_fbs(struct ata_port *ap)
pp->fbs_enabled = false;
}
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
}
static void ahci_pmp_attach(struct ata_port *ap)
diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
index ea3b3dc..30aa9c1 100644
--- a/drivers/ata/sata_highbank.c
+++ b/drivers/ata/sata_highbank.c
@@ -404,6 +404,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
static const unsigned long timing[] = { 5, 100, 500};
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
bool online;
@@ -432,7 +433,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
break;
} while (!online && retry--);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
if (online)
*class = ahci_dev_classify(ap);
--
1.8.5.3
^ permalink raw reply related
* [PATCH RFC v4 02/10] libahci: Move ahci_host_priv declaration to include/linux/ahci.h
From: Hans de Goede @ 2014-01-20 16:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390236303-22538-1-git-send-email-hdegoede@redhat.com>
With the ahci-platform.c changes later in this patch-set, some
arch/arm/mach-foo/*.c sata drivers need access to ahci_host_priv, so move
its declaration outside of drivers/ata.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/ata/ahci.h | 20 +-------------------
include/linux/ahci.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 47 insertions(+), 19 deletions(-)
create mode 100644 include/linux/ahci.h
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 2c04211..0f80129 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -35,7 +35,7 @@
#ifndef _AHCI_H
#define _AHCI_H
-#include <linux/clk.h>
+#include <linux/ahci.h>
#include <linux/libata.h>
/* Enclosure Management Control */
@@ -309,24 +309,6 @@ struct ahci_port_priv {
char *irq_desc; /* desc in /proc/interrupts */
};
-struct ahci_host_priv {
- void __iomem * mmio; /* bus-independent mem map */
- unsigned int flags; /* AHCI_HFLAG_* */
- u32 cap; /* cap to use */
- u32 cap2; /* cap2 to use */
- u32 port_map; /* port map to use */
- u32 saved_cap; /* saved initial cap */
- u32 saved_cap2; /* saved initial cap2 */
- u32 saved_port_map; /* saved initial port_map */
- u32 em_loc; /* enclosure management location */
- u32 em_buf_sz; /* EM buffer size in byte */
- u32 em_msg_type; /* EM message type */
- struct clk *clk; /* Only for platforms supporting clk */
- void *plat_data; /* Other platform data */
- /* Optional ahci_start_engine override */
- void (*start_engine)(struct ata_port *ap);
-};
-
extern int ahci_ignore_sss;
extern struct device_attribute *ahci_shost_attrs[];
diff --git a/include/linux/ahci.h b/include/linux/ahci.h
new file mode 100644
index 0000000..3499d44
--- /dev/null
+++ b/include/linux/ahci.h
@@ -0,0 +1,46 @@
+/*
+ * ahci.h - Common AHCI SATA definitions and declarations
+ *
+ * Maintained by: Tejun Heo <tj@kernel.org>
+ * Please ALWAYS copy linux-ide at vger.kernel.org
+ * on emails.
+ *
+ * Copyright 2004-2005 Red Hat, Inc.
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_AHCI_H__
+#define __LINUX_AHCI_H__
+
+#include <linux/clk.h>
+
+struct ata_port;
+
+struct ahci_host_priv {
+ void __iomem *mmio; /* bus-independent mem map */
+ unsigned int flags; /* AHCI_HFLAG_* */
+ u32 cap; /* cap to use */
+ u32 cap2; /* cap2 to use */
+ u32 port_map; /* port map to use */
+ u32 saved_cap; /* saved initial cap */
+ u32 saved_cap2; /* saved initial cap2 */
+ u32 saved_port_map; /* saved initial port_map */
+ u32 em_loc; /* enclosure management location */
+ u32 em_buf_sz; /* EM buffer size in byte */
+ u32 em_msg_type; /* EM message type */
+ struct clk *clk; /* Optional */
+ void *plat_data; /* Other platform data */
+ /* Optional ahci_start_engine override */
+ void (*start_engine)(struct ata_port *ap);
+};
+
+#endif
--
1.8.5.3
^ permalink raw reply related
* [PATCH RFC v4 03/10] ahci-platform: Pass ahci_host_priv ptr to ahci_platform_data init method
From: Hans de Goede @ 2014-01-20 16:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390236303-22538-1-git-send-email-hdegoede@redhat.com>
Some ahci_platform_data->init methods need access to the ahci_host_priv data.
When calling ahci_platform_data->init the ata_host has not been allocated yet,
so access to ahci_host_priv through the dev argument is not possible.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/mach-davinci/devices-da8xx.c | 5 +++--
arch/arm/mach-spear/spear1340.c | 2 +-
drivers/ata/ahci_imx.c | 12 ++++++------
drivers/ata/ahci_platform.c | 2 +-
include/linux/ahci_platform.h | 3 ++-
5 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index 78829c5..28e7c4c 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -14,6 +14,7 @@
#include <linux/platform_device.h>
#include <linux/dma-contiguous.h>
#include <linux/serial_8250.h>
+#include <linux/ahci.h>
#include <linux/ahci_platform.h>
#include <linux/clk.h>
#include <linux/reboot.h>
@@ -1061,7 +1062,7 @@ static unsigned long da850_sata_xtal[] = {
KHZ_TO_HZ(60000),
};
-static int da850_sata_init(struct device *dev, void __iomem *addr)
+static int da850_sata_init(struct device *dev, struct ahci_host_priv *hpriv)
{
int i, ret;
unsigned int val;
@@ -1096,7 +1097,7 @@ static int da850_sata_init(struct device *dev, void __iomem *addr)
SATA_PHY_TXSWING(3) |
SATA_PHY_ENPLL(1);
- __raw_writel(val, addr + SATA_P0PHYCR_REG);
+ __raw_writel(val, hpriv->mmio + SATA_P0PHYCR_REG);
return 0;
diff --git a/arch/arm/mach-spear/spear1340.c b/arch/arm/mach-spear/spear1340.c
index 3fb6834..9e2f3ac 100644
--- a/arch/arm/mach-spear/spear1340.c
+++ b/arch/arm/mach-spear/spear1340.c
@@ -77,7 +77,7 @@
SPEAR1340_MIPHY_PLL_RATIO_TOP(25))
/* SATA device registration */
-static int sata_miphy_init(struct device *dev, void __iomem *addr)
+static int sata_miphy_init(struct device *dev, struct ahci_host_priv *hpriv)
{
writel(SPEAR1340_SATA_CFG_VAL, SPEAR1340_PCIE_SATA_CFG);
writel(SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK,
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
index 3e23e99..49fa0ca 100644
--- a/drivers/ata/ahci_imx.c
+++ b/drivers/ata/ahci_imx.c
@@ -91,7 +91,7 @@ static const struct ata_port_info ahci_imx_port_info = {
.port_ops = &ahci_imx_ops,
};
-static int imx6q_sata_init(struct device *dev, void __iomem *mmio)
+static int imx6q_sata_init(struct device *dev, struct ahci_host_priv *hpriv)
{
int ret = 0;
unsigned int reg_val;
@@ -145,19 +145,19 @@ static int imx6q_sata_init(struct device *dev, void __iomem *mmio)
* Implement the port0.
* Get the ahb clock rate, and configure the TIMER1MS register.
*/
- reg_val = readl(mmio + HOST_CAP);
+ reg_val = readl(hpriv->mmio + HOST_CAP);
if (!(reg_val & HOST_CAP_SSS)) {
reg_val |= HOST_CAP_SSS;
- writel(reg_val, mmio + HOST_CAP);
+ writel(reg_val, hpriv->mmio + HOST_CAP);
}
- reg_val = readl(mmio + HOST_PORTS_IMPL);
+ reg_val = readl(hpriv->mmio + HOST_PORTS_IMPL);
if (!(reg_val & 0x1)) {
reg_val |= 0x1;
- writel(reg_val, mmio + HOST_PORTS_IMPL);
+ writel(reg_val, hpriv->mmio + HOST_PORTS_IMPL);
}
reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
- writel(reg_val, mmio + HOST_TIMER1MS);
+ writel(reg_val, hpriv->mmio + HOST_TIMER1MS);
return 0;
}
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 4b231ba..434ab89 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -149,7 +149,7 @@ static int ahci_probe(struct platform_device *pdev)
* returned successfully.
*/
if (pdata && pdata->init) {
- rc = pdata->init(dev, hpriv->mmio);
+ rc = pdata->init(dev, hpriv);
if (rc)
goto disable_unprepare_clk;
}
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index 73a2500..737fe38 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -19,9 +19,10 @@
struct device;
struct ata_port_info;
+struct ahci_host_priv;
struct ahci_platform_data {
- int (*init)(struct device *dev, void __iomem *addr);
+ int (*init)(struct device *dev, struct ahci_host_priv *hpriv);
void (*exit)(struct device *dev);
int (*suspend)(struct device *dev);
int (*resume)(struct device *dev);
--
1.8.5.3
^ permalink raw reply related
* [PATCH RFC v4 04/10] ahci-platform: Add support for devices with more then 1 clock
From: Hans de Goede @ 2014-01-20 16:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390236303-22538-1-git-send-email-hdegoede@redhat.com>
The allwinner-sun4i AHCI controller needs 2 clocks to be enabled and the
imx AHCI controller needs 3 clocks to be enabled.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
.../devicetree/bindings/ata/ahci-platform.txt | 1 +
drivers/ata/ahci_platform.c | 97 +++++++++++++++-------
include/linux/ahci.h | 4 +-
include/linux/ahci_platform.h | 3 +
4 files changed, 73 insertions(+), 32 deletions(-)
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index 89de156..3ced07d 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -10,6 +10,7 @@ Required properties:
Optional properties:
- dma-coherent : Present if dma operations are coherent
+- clocks : a list of phandle + clock specifier pairs
Example:
sata at ffe08000 {
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 434ab89..aaa0c08 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -87,6 +87,44 @@ static struct scsi_host_template ahci_platform_sht = {
AHCI_SHT("ahci_platform"),
};
+
+int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
+{
+ int c, rc;
+
+ for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
+ rc = clk_prepare_enable(hpriv->clks[c]);
+ if (rc)
+ goto disable_unprepare_clk;
+ }
+ return 0;
+
+disable_unprepare_clk:
+ while (--c >= 0)
+ clk_disable_unprepare(hpriv->clks[c]);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
+
+void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
+{
+ int c;
+
+ for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
+ if (hpriv->clks[c])
+ clk_disable_unprepare(hpriv->clks[c]);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
+
+
+static void ahci_put_clks(struct ahci_host_priv *hpriv)
+{
+ int c;
+
+ for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
+ clk_put(hpriv->clks[c]);
+}
+
static int ahci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -97,10 +135,8 @@ static int ahci_probe(struct platform_device *pdev)
struct ahci_host_priv *hpriv;
struct ata_host *host;
struct resource *mem;
- int irq;
- int n_ports;
- int i;
- int rc;
+ struct clk *clk;
+ int i, irq, max_clk, n_ports, rc;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
@@ -131,17 +167,26 @@ static int ahci_probe(struct platform_device *pdev)
return -ENOMEM;
}
- hpriv->clk = clk_get(dev, NULL);
- if (IS_ERR(hpriv->clk)) {
- dev_err(dev, "can't get clock\n");
- } else {
- rc = clk_prepare_enable(hpriv->clk);
- if (rc) {
- dev_err(dev, "clock prepare enable failed");
- goto free_clk;
+ max_clk = dev->of_node ? AHCI_MAX_CLKS : 1;
+ for (i = 0; i < max_clk; i++) {
+ if (i == 0)
+ clk = clk_get(dev, NULL); /* For old platform init */
+ else
+ clk = of_clk_get(dev->of_node, i);
+
+ if (IS_ERR(clk)) {
+ rc = PTR_ERR(clk);
+ if (rc == -EPROBE_DEFER)
+ goto free_clk;
+ break;
}
+ hpriv->clks[i] = clk;
}
+ rc = ahci_enable_clks(dev, hpriv);
+ if (rc)
+ goto free_clk;
+
/*
* Some platforms might need to prepare for mmio region access,
* which could be done in the following init call. So, the mmio
@@ -222,11 +267,9 @@ pdata_exit:
if (pdata && pdata->exit)
pdata->exit(dev);
disable_unprepare_clk:
- if (!IS_ERR(hpriv->clk))
- clk_disable_unprepare(hpriv->clk);
+ ahci_disable_clks(hpriv);
free_clk:
- if (!IS_ERR(hpriv->clk))
- clk_put(hpriv->clk);
+ ahci_put_clks(hpriv);
return rc;
}
@@ -239,10 +282,8 @@ static void ahci_host_stop(struct ata_host *host)
if (pdata && pdata->exit)
pdata->exit(dev);
- if (!IS_ERR(hpriv->clk)) {
- clk_disable_unprepare(hpriv->clk);
- clk_put(hpriv->clk);
- }
+ ahci_disable_clks(hpriv);
+ ahci_put_clks(hpriv);
}
#ifdef CONFIG_PM_SLEEP
@@ -277,8 +318,7 @@ static int ahci_suspend(struct device *dev)
if (pdata && pdata->suspend)
return pdata->suspend(dev);
- if (!IS_ERR(hpriv->clk))
- clk_disable_unprepare(hpriv->clk);
+ ahci_disable_clks(hpriv);
return 0;
}
@@ -290,13 +330,9 @@ static int ahci_resume(struct device *dev)
struct ahci_host_priv *hpriv = host->private_data;
int rc;
- if (!IS_ERR(hpriv->clk)) {
- rc = clk_prepare_enable(hpriv->clk);
- if (rc) {
- dev_err(dev, "clock prepare enable failed");
- return rc;
- }
- }
+ rc = ahci_enable_clks(dev, hpriv);
+ if (rc)
+ return rc;
if (pdata && pdata->resume) {
rc = pdata->resume(dev);
@@ -317,8 +353,7 @@ static int ahci_resume(struct device *dev)
return 0;
disable_unprepare_clk:
- if (!IS_ERR(hpriv->clk))
- clk_disable_unprepare(hpriv->clk);
+ ahci_disable_clks(hpriv);
return rc;
}
diff --git a/include/linux/ahci.h b/include/linux/ahci.h
index 3499d44..19970b0 100644
--- a/include/linux/ahci.h
+++ b/include/linux/ahci.h
@@ -23,6 +23,8 @@
#include <linux/clk.h>
+#define AHCI_MAX_CLKS 3
+
struct ata_port;
struct ahci_host_priv {
@@ -37,7 +39,7 @@ struct ahci_host_priv {
u32 em_loc; /* enclosure management location */
u32 em_buf_sz; /* EM buffer size in byte */
u32 em_msg_type; /* EM message type */
- struct clk *clk; /* Optional */
+ struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
void *plat_data; /* Other platform data */
/* Optional ahci_start_engine override */
void (*start_engine)(struct ata_port *ap);
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index 737fe38..0071d0b 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -31,4 +31,7 @@ struct ahci_platform_data {
unsigned int mask_port_map;
};
+int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
+void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
+
#endif /* _AHCI_PLATFORM_H */
--
1.8.5.3
^ permalink raw reply related
* [PATCH RFC v4 05/10] ahci-platform: Add support for an optional regulator for sata-target power
From: Hans de Goede @ 2014-01-20 16:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390236303-22538-1-git-send-email-hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
.../devicetree/bindings/ata/ahci-platform.txt | 1 +
drivers/ata/ahci_platform.c | 35 ++++++++++++++++++++--
include/linux/ahci.h | 2 ++
3 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index 3ced07d..1ac807f 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -11,6 +11,7 @@ Required properties:
Optional properties:
- dma-coherent : Present if dma operations are coherent
- clocks : a list of phandle + clock specifier pairs
+- target-supply : regulator for SATA target power
Example:
sata at ffe08000 {
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index aaa0c08..2f319e9 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -167,6 +167,13 @@ static int ahci_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ hpriv->target_pwr = devm_regulator_get_optional(dev, "target");
+ if (IS_ERR(hpriv->target_pwr)) {
+ if (PTR_ERR(hpriv->target_pwr) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ hpriv->target_pwr = NULL;
+ }
+
max_clk = dev->of_node ? AHCI_MAX_CLKS : 1;
for (i = 0; i < max_clk; i++) {
if (i == 0)
@@ -183,9 +190,15 @@ static int ahci_probe(struct platform_device *pdev)
hpriv->clks[i] = clk;
}
+ if (hpriv->target_pwr) {
+ rc = regulator_enable(hpriv->target_pwr);
+ if (rc)
+ goto free_clk;
+ }
+
rc = ahci_enable_clks(dev, hpriv);
if (rc)
- goto free_clk;
+ goto disable_regulator;
/*
* Some platforms might need to prepare for mmio region access,
@@ -268,6 +281,9 @@ pdata_exit:
pdata->exit(dev);
disable_unprepare_clk:
ahci_disable_clks(hpriv);
+disable_regulator:
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
free_clk:
ahci_put_clks(hpriv);
return rc;
@@ -284,6 +300,9 @@ static void ahci_host_stop(struct ata_host *host)
ahci_disable_clks(hpriv);
ahci_put_clks(hpriv);
+
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
}
#ifdef CONFIG_PM_SLEEP
@@ -320,6 +339,9 @@ static int ahci_suspend(struct device *dev)
ahci_disable_clks(hpriv);
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+
return 0;
}
@@ -330,9 +352,15 @@ static int ahci_resume(struct device *dev)
struct ahci_host_priv *hpriv = host->private_data;
int rc;
+ if (hpriv->target_pwr) {
+ rc = regulator_enable(hpriv->target_pwr);
+ if (rc)
+ return rc;
+ }
+
rc = ahci_enable_clks(dev, hpriv);
if (rc)
- return rc;
+ goto disable_regulator;
if (pdata && pdata->resume) {
rc = pdata->resume(dev);
@@ -354,6 +382,9 @@ static int ahci_resume(struct device *dev)
disable_unprepare_clk:
ahci_disable_clks(hpriv);
+disable_regulator:
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
return rc;
}
diff --git a/include/linux/ahci.h b/include/linux/ahci.h
index 19970b0..ac69cdc 100644
--- a/include/linux/ahci.h
+++ b/include/linux/ahci.h
@@ -22,6 +22,7 @@
#define __LINUX_AHCI_H__
#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
#define AHCI_MAX_CLKS 3
@@ -40,6 +41,7 @@ struct ahci_host_priv {
u32 em_buf_sz; /* EM buffer size in byte */
u32 em_msg_type; /* EM message type */
struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
+ struct regulator *target_pwr; /* Optional */
void *plat_data; /* Other platform data */
/* Optional ahci_start_engine override */
void (*start_engine)(struct ata_port *ap);
--
1.8.5.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