[linux-yocto] [PATCH 154/161] arch/powerpc: Add a Work Around for Axxia 3500 Resets
Cristian Bercaru
cristian.bercaru at windriver.com
Thu May 21 12:22:16 PDT 2015
From: John Jacques <john.jacques at lsi.com>
The work around is to switch the PPCs back to the reference
clock before issuing a reset. As described in the defect:
The reset_system issue is caused since the 6
counters are **NOT** reset by reset_system, but the
PLL and clock switch that controls the counters
**IS**. Workaround for this: switch clk_ppc to
clk_ref before a reset_system or reset_chip. This
logically should work, BUT no STA work has been done
to validate this. Empirically, this seems to work.
Signed-off-by: John Jacques <john.jacques at lsi.com>
Signed-off-by: Bruce Ashfield <bruce.ashfield at windriver.com>
---
arch/powerpc/platforms/44x/acpx1.c | 112 +++++++++++++++++++++++++++++++++++-
arch/powerpc/sysdev/ppc4xx_soc.c | 68 ----------------------
2 files changed, 111 insertions(+), 69 deletions(-)
diff --git a/arch/powerpc/platforms/44x/acpx1.c b/arch/powerpc/platforms/44x/acpx1.c
index df93e06..5410530 100644
--- a/arch/powerpc/platforms/44x/acpx1.c
+++ b/arch/powerpc/platforms/44x/acpx1.c
@@ -260,12 +260,122 @@ static int __init acpx14xx_probe(void)
return 1;
}
+/*
+ * Issue a "core" reset.
+ */
+
+void
+acp_jump_to_boot_loader(void *input)
+{
+ mpic_teardown_this_cpu(0);
+ /* This is only valid in the "core" reset case, so 0x10000000. */
+ mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | 0x10000000);
+
+ while (1)
+ ; /* Just in case the jump fails. */
+}
+
+/*
+ * Get all other cores to run "acp_jump_to_boot_loader()" then go
+ * there as well.
+ */
+
+void
+acp_reset_cores(void)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ if (cpu != smp_processor_id())
+ smp_call_function_single(cpu, acp_jump_to_boot_loader,
+ NULL, 0);
+ }
+
+ acp_jump_to_boot_loader(NULL);
+}
+
+static void
+acpx14xx_restart(char *command)
+{
+ struct device_node *np;
+ u32 reset_type = DBCR0_RST_SYSTEM;
+ const u32 *prop;
+
+ np = of_find_node_by_type(NULL, "cpu");
+
+ if (np) {
+ prop = of_get_property(np, "reset-type", NULL);
+
+ /*
+ * Check if property exists and if it is in range:
+ * 1 - PPC4xx core reset
+ * 2 - PPC4xx chip reset
+ * 3 - PPC4xx system reset (default)
+ */
+ if ((prop) && ((prop[0] >= 1) && (prop[0] <= 3)))
+ reset_type = prop[0] << 28;
+ }
+
+ if (DBCR0_RST_CORE == reset_type) {
+ acp_reset_cores();
+ } else {
+ /*
+ In this case, reset_type is either chip or system.
+
+ On the AXM3500 (PVR=0x7ff520c1), writing to DBCR0
+ will occasionally stall the system. As a
+ work-around, write to the system control register.
+
+ Also, the core clock should be switched back to the
+ reference clock. This is due to the following:
+
+ The reset_system issue is caused since the 6
+ counters are **NOT** reset by reset_system, but the
+ PLL and clock switch that controls the counters
+ **IS**. Workaround for this: switch clk_ppc to
+ clk_ref before a reset_system or reset_chip. This
+ logically should work, BUT no STA work has been done
+ to validate this. Empirically, this seems to work.
+ */
+
+ u32 pvr_value;
+
+ asm volatile ("mfpvr %0" : "=r"(pvr_value));
+
+ if (0x7ff520c1 == pvr_value) {
+ u32 value;
+
+ /* Enable privileged accesses */
+ value = mfdcrx(0xd0a);
+ value |= 0xab;
+ mtdcrx(0xd0a, value);
+
+ /* Switch to the reference clock */
+ printk(KERN_WARNING
+ "Switching PPCs to Reference Clock\n");
+ value = mfdcrx(0xd00);
+ value &= ~0xc0000000;
+ mtdcrx(0xd00, value);
+
+ /* Reset */
+ printk(KERN_WARNING
+ "Resetting Using SYSCON\n");
+ mtdcrx(0xe00, (reset_type >> 28));
+ } else {
+ mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | reset_type);
+ }
+ }
+
+ while (1)
+ ; /* Just in case the reset doesn't work */
+}
+
define_machine(acpx14xx) {
.name = "ACPX1",
.probe = acpx14xx_probe,
.progress = udbg_progress,
.init_IRQ = acpx14xx_init_irq,
.setup_arch = acpx14xx_setup_arch,
- .restart = ppc4xx_reset_system,
+ .restart = acpx14xx_restart,
.calibrate_decr = generic_calibrate_decr,
};
diff --git a/arch/powerpc/sysdev/ppc4xx_soc.c b/arch/powerpc/sysdev/ppc4xx_soc.c
index 5505f46..e7737e8 100644
--- a/arch/powerpc/sysdev/ppc4xx_soc.c
+++ b/arch/powerpc/sysdev/ppc4xx_soc.c
@@ -193,45 +193,6 @@ static int __init ppc4xx_l2c_probe(void)
}
arch_initcall(ppc4xx_l2c_probe);
-#ifdef CONFIG_ACP
-
-/*
- * Issue a "core" reset.
- */
-
-void
-acp_jump_to_boot_loader(void *input)
-{
- mpic_teardown_this_cpu(0);
- /* This is only valid in the "core" reset case, so 0x10000000. */
- mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | 0x10000000);
-
- while (1)
- ; /* Just in case the jump fails. */
-}
-
-/*
- * Get all other cores to run "acp_jump_to_boot_loader()" then go
- * there as well.
- */
-
-void
-acp_reset_cores(void)
-{
- int cpu;
-
- for_each_possible_cpu(cpu) {
- if (cpu != smp_processor_id())
- smp_call_function_single(cpu, acp_jump_to_boot_loader,
- NULL, 0);
- }
-
- acp_jump_to_boot_loader(NULL);
-}
-
-
-#endif
-
/*
* Apply a system reset. Alternatively a board specific value may be
* provided via the "reset-type" property in the cpu node.
@@ -256,36 +217,7 @@ void ppc4xx_reset_system(char *cmd)
reset_type = prop[0] << 28;
}
-#ifdef CONFIG_ACP
- if (DBCR0_RST_CORE == reset_type) {
- acp_reset_cores();
- } else {
- /*
- In this case, reset_type is either chip or system.
-
- On the AXM3500 (PVR=0x7ff520c1), writing to DBCR0
- will occasionally stall the system. As a
- work-around, write to the system control register.
- */
-
- u32 pvr_value;
-
- asm volatile ("mfpvr %0" : "=r"(pvr_value));
-
- if (0x7ff520c1 == pvr_value) {
- u32 value;
-
- value = mfdcrx(0xd0a);
- value |= 0xab;
- mtdcrx(0xd0a, value);
- mtdcrx(0xe00, 1);
- } else {
- mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | reset_type);
- }
- }
-#else
mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | reset_type);
-#endif
while (1)
; /* Just in case the reset doesn't work */
--
1.7.9.5
More information about the linux-yocto
mailing list