From: John Jacques <john.jacq...@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.jacq...@lsi.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.8.1.4 -- _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto