From: Kever Yang <hidden> Date: 2014-10-13 20:12:10
rk3288 is qual-core CPU Soc, we enable the smp in this patch.
In version 3 we use regmap and pmu syscon for cpu power on/off.
This should be work after Pankaj Dubey's patch applied:
"syscon: Decouple syscon interface from platform devices"
(https://lkml.org/lkml/2014/9/30/156)
Changes in v4:
- add rockchip,pmu property into cpus.txt
- merge patch "fix up rk3288 smp cpu hotplug" into this patch
- remove "rockchip,rk3288-pmu-sram" because we don't use it here
- remove "[PATCH v3 2/6] ARM: dts: rockchip: use the same pmu node"
Changes in v3:
- add pmu regmap patches in version 3
- use one ops and secondary_starup for all rockchip SOCs
- pick back the power domain operation for cpu hotplug
- remove 'enable-method' from this patch
- add compitable name "rockchip,rk3288-pmu-sram" for pmu-intmem
Changes in v2:
- use rk3288_boot_secondary instead ofsmp_boot_secondary
- discards the power domain operation
- handle the per cpu starup when actived by 'sev'
- adjust the alignment
Kever Yang (6):
ARM: rockchip: convert to regmap and use pmu syscon if available
ARM: rockchip: add option to access the pmu via a phandle in
smp_operations
ARM: dts: rockchip: add pmu references to cpus nodes
ARM: rockchip: add basic smp support for rk3288
ARM: dts: rockchip: add intmem node for rk3288 smp support
ARM: dts: rockchip: add reset for CPU nodes
Documentation/devicetree/bindings/arm/cpus.txt | 9 +
arch/arm/boot/dts/rk3288.dtsi | 18 ++
arch/arm/mach-rockchip/headsmp.S | 5 +-
arch/arm/mach-rockchip/platsmp.c | 223 ++++++++++++++++++++-----
4 files changed, 211 insertions(+), 44 deletions(-)
--
1.9.1
From: Kever Yang <hidden> Date: 2014-10-13 20:12:13
From: Heiko Stuebner <heiko@sntech.de>
Makes it possible to define a rockchip,pmu phandle in the cpus node directly
referencing the pmu syscon instead of searching for specific compatible.
The old way of finding the pmu stays of course available.
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Kever Yang <redacted>
---
Changes in v4:
- add rockchip,pmu property into cpus.txt
Changes in v3:
- add this patch
Changes in v2: None
Documentation/devicetree/bindings/arm/cpus.txt | 9 +++++++++
arch/arm/mach-rockchip/platsmp.c | 13 +++++++++++++
2 files changed, 22 insertions(+)
@@ -227,6 +227,15 @@ nodes to be present and contain the properties described below. # List of phandles to idle state nodes supported by this cpu [3].+ - rockchip,pmu+ Usage: optional for systems that have an "enable-method"+ property value of "rockchip,rk3066-smp"+ While optional, it is the preferred way to get access to+ the cpu-core power-domains.+ Value type: <phandle>+ Definition: Specifies the syscon node controlling the cpu core+ power domains.+ Example 1 (dual-cluster big.LITTLE system 32-bit): cpus {
From: Kever Yang <hidden> Date: 2014-10-13 20:12:17
This patch add intmem node des which is needed by platsmp.c
Signed-off-by: Kever Yang <redacted>
---
Changes in v4:
- remove "rockchip,rk3288-pmu-sram" because we don't use it here
Changes in v3:
- remove 'enable-method' from this patch
- add compitable name "rockchip,rk3288-pmu-sram" for pmu-intmem
Changes in v2:
- adjust the alignment
arch/arm/boot/dts/rk3288.dtsi | 12 ++++++++++++
1 file changed, 12 insertions(+)
From: Kever Yang <hidden> Date: 2014-10-13 20:12:33
This patch add reset for CPU nodes to use the reset controller.
Signed-off-by: Kever Yang <redacted>
---
Changes in v4: None
Changes in v3: None
Changes in v2: None
arch/arm/boot/dts/rk3288.dtsi | 4 ++++
1 file changed, 4 insertions(+)
From: Kever Yang <hidden> Date: 2014-10-13 20:12:50
This patch add basic rk3288 smp support.
Only cortex-A9 need invalid L1, A7/A12/A15/A17 should not invalid L1, since
for A7/A12/A15, the invalidation would be taken as clean and invalidate.
If you use the software manual invalidation instead of hardware invalidation
(assert l1/l2rstdisable during reset) after reset, there is tiny change that
some cachelines would be in dirty and valid state after reset(since the ram
content would be random value after reset), then the unexpected clean might
lead to system crash.
It is a known issue for the A12/A17 MPCore multiprocessor that the active
processors might be stalled when the individual processor is powered down,
we can avoid this prolbem by softreset the processor before power it down.
Signed-off-by: Kever Yang <redacted>
---
Changes in v4:
- merge patch "fix up rk3288 smp cpu hotplug" into this patch
Changes in v3:
- use one ops and secondary_starup for all rockchip SOCs
- pick back the power domain operation for cpu hotplug
Changes in v2:
- use rk3288_boot_secondary instead ofsmp_boot_secondary
- discards the power domain operation
- handle the per cpu starup when actived by 'sev'
arch/arm/mach-rockchip/headsmp.S | 5 +-
arch/arm/mach-rockchip/platsmp.c | 120 +++++++++++++++++++++++++++++++--------
2 files changed, 100 insertions(+), 25 deletions(-)
@@ -53,11 +55,47 @@ static int pmu_power_domain_is_on(int pd)return!(val&BIT(pd));}+structreset_control*rockchip_get_core_reset(intcpu)+{+structdevice*dev=get_cpu_device(cpu);+structdevice_node*np;++/* The cpu device is only available after the initial core bringup */+if(dev)+np=dev->of_node;+else+np=of_get_cpu_node(cpu,0);++returnof_reset_control_get(np,NULL);+}+staticintpmu_set_power_domain(intpd,boolon){u32val=(on)?0:BIT(pd);intret;+/*+*Weneedtosoftresetthecpuwhenweturnoffthecpupowerdomain,+*orelsetheactiveprocessorsmightbestalledwhentheindividual+*processorispowereddown.+*/+if(read_cpuid_part_number()!=ARM_CPU_PART_CORTEX_A9){+structreset_control*rstc=rockchip_get_core_reset(pd);++if(IS_ERR(rstc)){+pr_err("%s: could not get reset control for core %d\n",+__func__,pd);+returnPTR_ERR(rstc);+}++if(on)+reset_control_deassert(rstc);+else+reset_control_assert(rstc);++reset_control_put(rstc);+}+ret=regmap_update_bits(pmu,PMU_PWRDN_CON,BIT(pd),val);if(ret<0){pr_err("%s: could not update power domain\n",__func__);
@@ -84,6 +122,8 @@ static int pmu_set_power_domain(int pd, bool on)staticint__cpuinitrockchip_boot_secondary(unsignedintcpu,structtask_struct*idle){+intret;+if(!sram_base_addr||!pmu){pr_err("%s: sram or pmu missing for cpu boot\n",__func__);return-ENXIO;
@@ -96,7 +136,26 @@ static int __cpuinit rockchip_boot_secondary(unsigned int cpu,}/* start the core */-returnpmu_set_power_domain(0+cpu,true);+ret=pmu_set_power_domain(0+cpu,true);+if(ret<0)+returnret;++if(read_cpuid_part()!=ARM_CPU_PART_CORTEX_A9){+/* We communicate with the bootrom to active the cpus other+*thancpu0,afterablobofinitializecode,theywill+*stay@wfestate,oncetheyareactived,theywillcheck+*themailbox:+*sram_base_addr+4:0xdeadbeaf+*sram_base_addr+8:startaddressforpc+**/+udelay(10);+writel(virt_to_phys(rockchip_secondary_startup),+sram_base_addr+8);+writel(0xDEADBEAF,sram_base_addr+4);+dsb_sev();+}++return0;}/**
@@ -129,8 +188,6 @@ static int __init rockchip_smp_prepare_sram(struct device_node *node)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);
@@ -204,40 +261,55 @@ static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus)structdevice_node*node;unsignedinti;-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-smp-sram");if(!node){pr_err("%s: could not find sram dt node\n",__func__);return;}-if(rockchip_smp_prepare_sram(node))+sram_base_addr=of_iomap(node,0);+if(!sram_base_addr){+pr_err("%s: could not map sram registers\n",__func__);return;+}if(rockchip_smp_prepare_pmu())return;-/* enable the SCU power domain */-pmu_set_power_domain(PMU_PWRDN_SCU,true);+if(read_cpuid_part()==ARM_CPU_PART_CORTEX_A9){+if(rockchip_smp_prepare_sram(node))+return;-/*-*Whilethenumberofcpusisgatheredfromdt,alsogetthenumber-*ofcoresfromthescutoverifythisvaluewhenbootingthecores.-*/-ncores=scu_get_core_count(scu_base_addr);+/* enable the SCU power domain */+pmu_set_power_domain(PMU_PWRDN_SCU,true);++node=of_find_compatible_node(NULL,NULL,"arm,cortex-a9-scu");+if(!node){+pr_err("%s: missing scu\n",__func__);+return;+}-scu_enable(scu_base_addr);+scu_base_addr=of_iomap(node,0);+if(!scu_base_addr){+pr_err("%s: could not map scu registers\n",__func__);+return;+}++/*+*Whilethenumberofcpusisgatheredfromdt,alsogetthe+*numberofcoresfromthescutoverifythisvaluewhen+*bootingthecores.+*/+ncores=scu_get_core_count(scu_base_addr);+pr_err("%s: ncores %d\n",__func__,ncores);++scu_enable(scu_base_addr);+}else{+unsignedintl2ctlr;++asm("mrc p15, 1, %0, c9, c0, 2\n":"=r"(l2ctlr));+ncores=((l2ctlr>>24)&0x3)+1;+}/* Make sure that all cores except the first are really off */for(i=1;i<ncores;i++)
From: Doug Anderson <dianders@chromium.org> Date: 2014-10-14 20:24:09
Kever,
On Mon, Oct 13, 2014 at 1:12 PM, Kever Yang [off-list ref] wrote:
+ /*
+ * We need to soft reset the cpu when we turn off the cpu power domain,
+ * or else the active processors might be stalled when the individual
+ * processor is powered down.
+ */
+ if (read_cpuid_part_number() != ARM_CPU_PART_CORTEX_A9) {
I haven't done a full review of this patch, but it seems unlikely that
your uses of read_cpuid_part_number() and read_cpuid_part() in this
patch are correct. You use both functions and in both cases compare
the results to ARM_CPU_PART_CORTEX_A9.
Am Dienstag, 14. Oktober 2014, 13:24:03 schrieb Doug Anderson:
Kever,
On Mon, Oct 13, 2014 at 1:12 PM, Kever Yang [off-list ref]
wrote:
quoted
+ /*
+ * We need to soft reset the cpu when we turn off the cpu power
domain, + * or else the active processors might be stalled when
the individual + * processor is powered down.
+ */
+ if (read_cpuid_part_number() != ARM_CPU_PART_CORTEX_A9) {
I haven't done a full review of this patch, but it seems unlikely that
your uses of read_cpuid_part_number() and read_cpuid_part() in this
patch are correct. You use both functions and in both cases compare
the results to ARM_CPU_PART_CORTEX_A9.
From: Kever Yang <hidden> Date: 2014-10-14 21:50:19
Heiko,
On 10/14/2014 02:23 PM, Heiko St?bner wrote:
Am Dienstag, 14. Oktober 2014, 13:24:03 schrieb Doug Anderson:
quoted
Kever,
On Mon, Oct 13, 2014 at 1:12 PM, Kever Yang [off-list ref]
wrote:
quoted
quoted
+ /*
+ * We need to soft reset the cpu when we turn off the cpu power
domain, + * or else the active processors might be stalled when
the individual + * processor is powered down.
+ */
+ if (read_cpuid_part_number() != ARM_CPU_PART_CORTEX_A9) {
I haven't done a full review of this patch, but it seems unlikely that
your uses of read_cpuid_part_number() and read_cpuid_part() in this
patch are correct. You use both functions and in both cases compare
the results to ARM_CPU_PART_CORTEX_A9.
I think read_cpuid_part() would be the correct one, as it does
You are right, read_cpuid_part() is correct one on kernel next,
I mix up 3.14 kernel and next tree, only read_cpuid_part_number() is
available
in 3.14 kernel.
I will correct it in my next version, any other changes needed for new
version?
- Kever.
From: Russell King - ARM Linux <hidden> Date: 2014-10-14 23:38:10
On Tue, Oct 14, 2014 at 02:50:07PM -0700, Kever Yang wrote:
Heiko,
On 10/14/2014 02:23 PM, Heiko St?bner wrote:
quoted
Am Dienstag, 14. Oktober 2014, 13:24:03 schrieb Doug Anderson:
quoted
Kever,
On Mon, Oct 13, 2014 at 1:12 PM, Kever Yang [off-list ref]
wrote:
quoted
quoted
+ /*
+ * We need to soft reset the cpu when we turn off the cpu power
domain, + * or else the active processors might be stalled when
the individual + * processor is powered down.
+ */
+ if (read_cpuid_part_number() != ARM_CPU_PART_CORTEX_A9) {
I haven't done a full review of this patch, but it seems unlikely that
your uses of read_cpuid_part_number() and read_cpuid_part() in this
patch are correct. You use both functions and in both cases compare
the results to ARM_CPU_PART_CORTEX_A9.
I think read_cpuid_part() would be the correct one, as it does
You are right, read_cpuid_part() is correct one on kernel next,
I mix up 3.14 kernel and next tree, only read_cpuid_part_number() is
available
in 3.14 kernel.
I will correct it in my next version, any other changes needed for new
version?
You need to at the _very_ _minimum_ build test your code against a
recent kernel, and preferably test it to make sure that it works as
you intend.
Developing on such an old kernel version, and hoping that the code is
going to be correct for later kernels isn't a nice idea.
--
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.
From: Kever Yang <hidden> Date: 2014-10-15 06:49:18
Russell,
On 10/14/2014 04:37 PM, Russell King - ARM Linux wrote:
On Tue, Oct 14, 2014 at 02:50:07PM -0700, Kever Yang wrote:
quoted
Heiko,
On 10/14/2014 02:23 PM, Heiko St?bner wrote:
quoted
Am Dienstag, 14. Oktober 2014, 13:24:03 schrieb Doug Anderson:
quoted
Kever,
On Mon, Oct 13, 2014 at 1:12 PM, Kever Yang [off-list ref]
wrote:
quoted
quoted
+ /*
+ * We need to soft reset the cpu when we turn off the cpu power
domain, + * or else the active processors might be stalled when
the individual + * processor is powered down.
+ */
+ if (read_cpuid_part_number() != ARM_CPU_PART_CORTEX_A9) {
I haven't done a full review of this patch, but it seems unlikely that
your uses of read_cpuid_part_number() and read_cpuid_part() in this
patch are correct. You use both functions and in both cases compare
the results to ARM_CPU_PART_CORTEX_A9.
I think read_cpuid_part() would be the correct one, as it does
You are right, read_cpuid_part() is correct one on kernel next,
I mix up 3.14 kernel and next tree, only read_cpuid_part_number() is
available
in 3.14 kernel.
I will correct it in my next version, any other changes needed for new
version?
You need to at the _very_ _minimum_ build test your code against a
recent kernel, and preferably test it to make sure that it works as
you intend.
Thanks for you advice, I'll be more careful next time.
I'm sorry for not test this patch with rk3188(A9 based) board,
I do have test it on top of kernel next with my rk3288 evb(not A9 based),
and I didn't get any warning for read_cpuid_part_number()
during building the image.
- Kever
Developing on such an old kernel version, and hoping that the code is
going to be correct for later kernels isn't a nice idea.
From: Russell King - ARM Linux <hidden> Date: 2014-10-14 23:36:27
On Tue, Oct 14, 2014 at 11:23:40PM +0200, Heiko St?bner wrote:
Am Dienstag, 14. Oktober 2014, 13:24:03 schrieb Doug Anderson:
quoted
Kever,
On Mon, Oct 13, 2014 at 1:12 PM, Kever Yang [off-list ref]
wrote:
quoted
quoted
+ /*
+ * We need to soft reset the cpu when we turn off the cpu power
domain, + * or else the active processors might be stalled when
the individual + * processor is powered down.
+ */
+ if (read_cpuid_part_number() != ARM_CPU_PART_CORTEX_A9) {
I haven't done a full review of this patch, but it seems unlikely that
your uses of read_cpuid_part_number() and read_cpuid_part() in this
patch are correct. You use both functions and in both cases compare
the results to ARM_CPU_PART_CORTEX_A9.
I think read_cpuid_part() would be the correct one, as it does
read_cpuid_id() & ARM_CPU_PART_MASK
which in turn should mask the correct parts of the cpuid to match against
ARM_CPU_PART_CORTEX_A9 [0].
The clue is the deprecated message. Clearly the original author did not
even build test their code, or if they did, they ignored the warnings.
Either way, that's a fairly worrying issue which raises the question:
how well was this code tested in the first place?
Note that the above quoted if() evaluates to always-false.
--
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.
From: Kever Yang <hidden> Date: 2014-10-13 20:13:10
This patch add pmu reference and enable-method for smp
Signed-off-by: Kever Yang <redacted>
---
Changes in v4: None
Changes in v3:
- add this patch
Changes in v2: None
arch/arm/boot/dts/rk3288.dtsi | 2 ++
1 file changed, 2 insertions(+)
From: Kever Yang <hidden> Date: 2014-10-13 20:13:39
From: Heiko Stuebner <heiko@sntech.de>
The pmu register space is - like the GRF - shared by quite some peripherals.
On the rk3188 and rk3288 even parts of the pinctrl are living there.
Therefore we normally shouldn't map it a second time when the syscon
does this already.
Therefore convert the cpu power-domain handling to access the pmu via a
regmap and at first try to get it via the syscon interface.
Getting this syscon will only fail if the pmu node does not have the
"syscon" compatible and thus does not get shared with other drivers.
In this case we map it like before and create the necessary regmap on
top of it.
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Kever Yang <redacted>
---
Changes in v4: None
Changes in v3:
- add this patch in version 3
Changes in v2: None
arch/arm/mach-rockchip/platsmp.c | 104 +++++++++++++++++++++++++++++----------
1 file changed, 78 insertions(+), 26 deletions(-)
@@ -37,23 +39,42 @@ static int ncores;#define PMU_PWRDN_SCU 4-staticvoid__iomem*pmu_base_addr;+staticstructregmap*pmu;-staticinlineboolpmu_power_domain_is_on(intpd)+staticintpmu_power_domain_is_on(intpd){-return!(readl_relaxed(pmu_base_addr+PMU_PWRDN_ST)&BIT(pd));+u32val;+intret;++ret=regmap_read(pmu,PMU_PWRDN_ST,&val);+if(ret<0)+returnret;++return!(val&BIT(pd));}-staticvoidpmu_set_power_domain(intpd,boolon)+staticintpmu_set_power_domain(intpd,boolon){-u32val=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){}+u32val=(on)?0:BIT(pd);+intret;++ret=regmap_update_bits(pmu,PMU_PWRDN_CON,BIT(pd),val);+if(ret<0){+pr_err("%s: could not update power domain\n",__func__);+returnret;+}++ret=-1;+while(ret!=on){+ret=pmu_power_domain_is_on(pd);+if(ret<0){+pr_err("%s: could not read power domain state\n",+__func__);+returnret;+}+}++return0;}/*
@@ -63,7 +84,7 @@ static void pmu_set_power_domain(int pd, bool on)staticint__cpuinitrockchip_boot_secondary(unsignedintcpu,structtask_struct*idle){-if(!sram_base_addr||!pmu_base_addr){+if(!sram_base_addr||!pmu){pr_err("%s: sram or pmu missing for cpu boot\n",__func__);return-ENXIO;}
@@ -75,9 +96,7 @@ static int __cpuinit rockchip_boot_secondary(unsigned int cpu,}/* start the core */-pmu_set_power_domain(0+cpu,true);--return0;+returnpmu_set_power_domain(0+cpu,true);}/**
@@ -125,6 +144,48 @@ static int __init rockchip_smp_prepare_sram(struct device_node *node)return0;}+staticstructregmap_configrockchip_pmu_regmap_config={+.reg_bits=32,+.val_bits=32,+.reg_stride=4,+};++staticint__initrockchip_smp_prepare_pmu(void)+{+structdevice_node*node;+void__iomem*pmu_base;++pmu=syscon_regmap_lookup_by_compatible("rockchip,rk3066-pmu");+if(!IS_ERR(pmu))+return0;++/* fallback, create our own regmap for the pmu area */+pmu=NULL;+node=of_find_compatible_node(NULL,NULL,"rockchip,rk3066-pmu");+if(!node){+pr_err("%s: could not find pmu dt node\n",__func__);+return-ENODEV;+}++pmu_base=of_iomap(node,0);+if(!pmu_base){+pr_err("%s: could not map pmu registers\n",__func__);+return-ENOMEM;+}++pmu=regmap_init_mmio(NULL,pmu_base,&rockchip_pmu_regmap_config);+if(IS_ERR(pmu)){+intret=PTR_ERR(pmu);++iounmap(pmu_base);+pmu=NULL;+pr_err("%s: regmap init failed\n",__func__);+returnret;+}++return0;+}+staticvoid__initrockchip_smp_prepare_cpus(unsignedintmax_cpus){structdevice_node*node;
@@ -151,17 +212,8 @@ static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus)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 pmu dt node\n",__func__);+if(rockchip_smp_prepare_pmu())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);