[PATCHv5 3/8] ARM: OMAP4460: Workaround for ROM bug because of CA9 r2pX gic control register change

Tero Kristo t-kristo at ti.com
Wed May 16 04:54:51 EDT 2012


On Tue, 2012-05-15 at 14:44 -0700, Kevin Hilman wrote:
> Santosh,
> 
> Tero Kristo <t-kristo at ti.com> writes:
> 
> > From: Santosh Shilimkar <santosh.shilimkar at ti.com>
> >
> > GIC distributor control register has changed between CortexA9 r1pX and
> > r2pX. The Control Register secure banked version is now composed of 2
> > bits:
> >      bit 0 == Secure Enable
> >      bit 1 == Non-Secure Enable
> > The Non-Secure banked register has not changed. 
> 
> For those without the r1pX TRM handy, please include what this look like
> before (presumably 1 bit?)  The changelog and in-code comments should
> both be enhanced.
> 
> > Since the ROM Code is based on the r1pX GIC, the CPU1 GIC restoration
> > will cause a problem to CPU0 Non-Secure SW.
> 
> Please describe the problem, so we can better understand the specifics
> of the workaround.

Santosh, can you provide a better changelog for this?

> 
> Also, is there an erratum number for this?

Nothing public. I don't think there are any public documents about ROM
code, including erratas.

> 
> > The workaround must be:
> >      1) Before doing the CPU1 wakeup, CPU0 must disable
> >         the GIC distributor
> >      2) CPU1 must re-enable the GIC distributor on
> >         it's wakeup path.
> 
> Again, because the problem was not described, I am not entirely sure why
> the workaround "must" be this, and how it fixes the problem.  Remember
> to put yourself in the shoes of a reviewer who has not been deeply
> involved in the code, so what seems obvious to you will not be obvious
> to the reviewer without having to study the code and dig in to the TRMs.
> 
> > With this procedure, the GIC configuration done between the
> > CPU0 wakeup and CPU1 wakeup will not be lost but during this
> > short windows, the CPU0 will not receive interrupts
> 
> Hmm, so I guess this means that CPU0 always has to wakeup first, even on GP
> devices? 

Yes.

> 
> Also, the changelog doesn't describe what power states this affects, and
> whether it's an idle problem or just a supend problem.  A quick glance
> at the code suggests that only suspend is being addressed by this patch.
> However, with the addition of coupled CPUidle (coming very soon now),
> won't we have this same problem in idle?  IMO, this patch should address
> both.

My understanding is that this happens if mpu_pwrdm goes off. Cpuidle
support is not added to this patch as it does not exist yet. Probably
shouldn't be that big fix.

> 
> This workaround also assumes that you always want CPU1 to wakeup
> immediately after CPU0.  I guess that will be the case for the coupled
> states that would be affected by this bug, but the changelog should
> describe that as well

Yes, this patch assumes both CPUs attempt to wake-up, thus cpu1 is stuck
in the hold loop. The device-off set patch #17 addresses this issue and
puts cpu1 back to idle immediately if no wake request is received from
cpu0. That patch should be possible to move to this set if needed.


> 
> Some minor comments below...
> 
> > Signed-off-by: Santosh Shilimkar <santosh.shilimkar at ti.com>
> > Signed-off-by: Tero Kristo <t-kristo at ti.com>
> > ---
> >  arch/arm/mach-omap2/common.h              |    2 +
> >  arch/arm/mach-omap2/omap-headsmp.S        |   36 +++++++++++++++++++++++++++++
> >  arch/arm/mach-omap2/omap-mpuss-lowpower.c |    9 ++++++-
> >  arch/arm/mach-omap2/omap-smp.c            |   28 +++++++++++++++++++++-
> >  arch/arm/mach-omap2/omap4-common.c        |    8 +++++-
> >  5 files changed, 80 insertions(+), 3 deletions(-)
> >
> > diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
> > index 57da7f4..48d1ebe 100644
> > --- a/arch/arm/mach-omap2/common.h
> > +++ b/arch/arm/mach-omap2/common.h
> > @@ -199,6 +199,7 @@ static inline void __iomem *omap4_get_scu_base(void)
> >  #endif
> >  
> >  extern void __init gic_init_irq(void);
> > +extern void gic_dist_disable(void);
> >  extern void omap_smc1(u32 fn, u32 arg);
> >  extern void __iomem *omap4_get_sar_ram_base(void);
> >  extern void omap_do_wfi(void);
> > @@ -206,6 +207,7 @@ extern void omap_do_wfi(void);
> >  #ifdef CONFIG_SMP
> >  /* Needed for secondary core boot */
> >  extern void omap_secondary_startup(void);
> > +extern void omap_secondary_startup_4460(void);
> >  extern u32 omap_modify_auxcoreboot0(u32 set_mask, u32 clear_mask);
> >  extern void omap_auxcoreboot_addr(u32 cpu_addr);
> >  extern u32 omap_read_auxcoreboot0(void);
> > diff --git a/arch/arm/mach-omap2/omap-headsmp.S b/arch/arm/mach-omap2/omap-headsmp.S
> > index 503ac77..d602555 100644
> > --- a/arch/arm/mach-omap2/omap-headsmp.S
> > +++ b/arch/arm/mach-omap2/omap-headsmp.S
> > @@ -43,3 +43,39 @@ hold:	ldr	r12,=0x103
> >  	b	secondary_startup
> >  ENDPROC(omap_secondary_startup)
> >  
> > +ENTRY(omap_secondary_startup_4460)
> > +hold_2:	ldr	r12,=0x103
> > +	dsb
> > +	smc	#0			@ read from AuxCoreBoot0
> > +	mov	r0, r0, lsr #9
> > +	mrc	p15, 0, r4, c0, c0, 5
> > +	and	r4, r4, #0x0f
> > +	cmp	r0, r4
> > +	bne	hold_2
> > +
> > +	/*
> > +	 * GIC distributor control register has changed between
> > +	 * CortexA9 r1pX and r2pX. The Control Register secure
> > +	 * banked version is now composed of 2 bits:
> > +	 * bit 0 == Secure Enable
> > +	 * bit 1 == Non-Secure Enable
> > +	 * The Non-Secure banked register has not changed
> > +	 * Because the ROM Code is based on the r1pX GIC, the CPU1
> > +	 * GIC restoration will cause a problem to CPU0 Non-Secure SW.
> > +	 * The workaround must be:
> > +	 * 1) Before doing the CPU1 wakeup, CPU0 must disable
> > +	 * the GIC distributor
> > +	 * 2) CPU1 must re-enable the GIC distributor on
> > +	 * it's wakeup path.
> > +	 */
> > +	ldr	r1, =0x48241000
> 
> Why not OMAP44XX_GIC_DIST_BASE for readability sake?

Will change this.

> 
> > +	ldr	r0, [r1]
> > +	orr	r0, #1
> > +	str	r0, [r1]
> > +
> > +	/*
> > +	 * we've been released from the wait loop,secondary_stack
> > +	 * should now contain the SVC stack for this core
> > +	 */
> > +	b	secondary_startup
> > +ENDPROC(omap_secondary_startup_4460)
> > diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
> > index 13670aa..e02c082 100644
> > --- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c
> > +++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
> > @@ -68,6 +68,7 @@ struct omap4_cpu_pm_info {
> >  	void __iomem *scu_sar_addr;
> >  	void __iomem *wkup_sar_addr;
> >  	void __iomem *l2x0_sar_addr;
> > +	void (*secondary_startup)(void);
> >  };
> >  
> >  static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info);
> > @@ -300,6 +301,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
> >  int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
> >  {
> >  	unsigned int cpu_state = 0;
> > +	struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu);
> >  
> >  	if (omap_rev() == OMAP4430_REV_ES1_0)
> >  		return -ENXIO;
> > @@ -309,7 +311,7 @@ int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
> >  
> >  	clear_cpu_prev_pwrst(cpu);
> >  	set_cpu_next_pwrst(cpu, power_state);
> > -	set_cpu_wakeup_addr(cpu, virt_to_phys(omap_secondary_startup));
> > +	set_cpu_wakeup_addr(cpu, virt_to_phys(pm_info->secondary_startup));
> >  	scu_pwrst_prepare(cpu, power_state);
> >  
> >  	/*
> > @@ -360,6 +362,11 @@ int __init omap4_mpuss_init(void)
> >  	pm_info->scu_sar_addr = sar_base + SCU_OFFSET1;
> >  	pm_info->wkup_sar_addr = sar_base + CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
> >  	pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET1;
> > +	if (cpu_is_omap446x())
> > +		pm_info->secondary_startup = omap_secondary_startup_4460;
> > +	else
> > +		pm_info->secondary_startup = omap_secondary_startup;
> 
> Does this exist on 4470 too?

No, only valid for 4460. ROM code should be fixed on 4470 (haven't
tested that though as I don't have access to 4470 devices.)

> 
> Using a PM erratum check here instead of cpu_is* would make this more
> scalable.  
> 
> Same comment for the cpu_is* check in wakeup_secondary()
> 
> Then, where the erratum is defined, it should state clearly why this
> affects 446x and not before (presumably because 4430 has r1pX and 4460
> has r2pX.)

Yea, I can add errata flag for this. The errata support for omap4 PM is
currently defined in the device off set, so I guess I need to pull that
to this set.

> 
> >  	pm_info->pwrdm = pwrdm_lookup("cpu1_pwrdm");
> >  	if (!pm_info->pwrdm) {
> >  		pr_err("Lookup failed for CPU1 pwrdm\n");
> > diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c
> > index deffbf1..c3eb9e8 100644
> > --- a/arch/arm/mach-omap2/omap-smp.c
> > +++ b/arch/arm/mach-omap2/omap-smp.c
> > @@ -33,6 +33,7 @@
> >  
> >  /* SCU base address */
> >  static void __iomem *scu_base;
> > +bool omap4_smp_romcode_errata;
> 
> static?

Yes should be.

-Tero





More information about the linux-arm-kernel mailing list