Skip to content

Commit

Permalink
[Blackfin] arch: Prevent potential Core Hang situation
Browse files Browse the repository at this point in the history
If the new value written to the PLL_CTL or VR_CTL register is the
same as the previous value, the PLL wake-up will occur immediately
(PLL is already locked), but the core and system clock will be
bypassed for the PLL_LOCKCNT duration. For this interval, code will
execute at the CLKIN rate instead of at the expected CCLK rate.
Software should guard against this condition by comparing the
current value to the new value before writing the new value.

Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Bryan Wu <cooloney@kernel.org>
  • Loading branch information
Michael Hennerich authored and Bryan Wu committed Apr 23, 2008
1 parent 4bea8b2 commit a81501a
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 18 deletions.
57 changes: 55 additions & 2 deletions include/asm-blackfin/mach-bf527/cdefBF52x_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,71 @@
*/

#ifndef _CDEF_BF52X_H
#define _CDEF_BF52X_H

#include <asm/system.h>
#include <asm/blackfin.h>

#include "defBF52x_base.h"

/* Include core specific register pointer definitions */
#include <asm/mach-common/cdef_LPBlackfin.h>

/* ==== begin from cdefBF534.h ==== */

/* Clock and System Control (0xFFC00000 - 0xFFC000FF) */
#define bfin_read_PLL_CTL() bfin_read16(PLL_CTL)
#define bfin_write_PLL_CTL(val) bfin_write16(PLL_CTL, val)
/* Writing to PLL_CTL initiates a PLL relock sequence. */
static __inline__ void bfin_write_PLL_CTL(unsigned int val)
{
unsigned long flags, iwr0, iwr1;

if (val == bfin_read_PLL_CTL())
return;

local_irq_save(flags);
/* Enable the PLL Wakeup bit in SIC IWR */
iwr0 = bfin_read32(SIC_IWR0);
iwr1 = bfin_read32(SIC_IWR1);
/* Only allow PPL Wakeup) */
bfin_write32(SIC_IWR0, IWR_ENABLE(0));
bfin_write32(SIC_IWR1, 0);

bfin_write16(PLL_CTL, val);
SSYNC();
asm("IDLE;");

bfin_write32(SIC_IWR0, iwr0);
bfin_write32(SIC_IWR1, iwr1);
local_irq_restore(flags);
}
#define bfin_read_PLL_DIV() bfin_read16(PLL_DIV)
#define bfin_write_PLL_DIV(val) bfin_write16(PLL_DIV, val)
#define bfin_read_VR_CTL() bfin_read16(VR_CTL)
#define bfin_write_VR_CTL(val) bfin_write16(VR_CTL, val)
/* Writing to VR_CTL initiates a PLL relock sequence. */
static __inline__ void bfin_write_VR_CTL(unsigned int val)
{
unsigned long flags, iwr0, iwr1;

if (val == bfin_read_VR_CTL())
return;

local_irq_save(flags);
/* Enable the PLL Wakeup bit in SIC IWR */
iwr0 = bfin_read32(SIC_IWR0);
iwr1 = bfin_read32(SIC_IWR1);
/* Only allow PPL Wakeup) */
bfin_write32(SIC_IWR0, IWR_ENABLE(0));
bfin_write32(SIC_IWR1, 0);

bfin_write16(VR_CTL, val);
SSYNC();
asm("IDLE;");

bfin_write32(SIC_IWR0, iwr0);
bfin_write32(SIC_IWR1, iwr1);
local_irq_restore(flags);
}
#define bfin_read_PLL_STAT() bfin_read16(PLL_STAT)
#define bfin_write_PLL_STAT(val) bfin_write16(PLL_STAT, val)
#define bfin_read_PLL_LOCKCNT() bfin_read16(PLL_LOCKCNT)
Expand Down
31 changes: 27 additions & 4 deletions include/asm-blackfin/mach-bf533/cdefBF532.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,27 @@

/* Clock and System Control (0xFFC0 0400-0xFFC0 07FF) */
#define bfin_read_PLL_CTL() bfin_read16(PLL_CTL)
#define bfin_write_PLL_CTL(val) bfin_write16(PLL_CTL,val)
/* Writing to PLL_CTL initiates a PLL relock sequence. */
static __inline__ void bfin_write_PLL_CTL(unsigned int val)
{
unsigned long flags, iwr;

if (val == bfin_read_PLL_CTL())
return;

local_irq_save(flags);
/* Enable the PLL Wakeup bit in SIC IWR */
iwr = bfin_read32(SIC_IWR);
/* Only allow PPL Wakeup) */
bfin_write32(SIC_IWR, IWR_ENABLE(0));

bfin_write16(PLL_CTL, val);
SSYNC();
asm("IDLE;");

bfin_write32(SIC_IWR, iwr);
local_irq_restore(flags);
}
#define bfin_read_PLL_STAT() bfin_read16(PLL_STAT)
#define bfin_write_PLL_STAT(val) bfin_write16(PLL_STAT,val)
#define bfin_read_PLL_LOCKCNT() bfin_read16(PLL_LOCKCNT)
Expand All @@ -57,18 +77,21 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val)
{
unsigned long flags, iwr;

if (val == bfin_read_VR_CTL())
return;

local_irq_save(flags);
/* Enable the PLL Wakeup bit in SIC IWR */
iwr = bfin_read32(SIC_IWR);
/* Only allow PPL Wakeup) */
bfin_write32(SIC_IWR, IWR_ENABLE(0));

bfin_write16(VR_CTL, val);
SSYNC();

local_irq_save(flags);
asm("IDLE;");
local_irq_restore(flags);

bfin_write32(SIC_IWR, iwr);
local_irq_restore(flags);
}

/* System Interrupt Controller (0xFFC0 0C00-0xFFC0 0FFF) */
Expand Down
31 changes: 27 additions & 4 deletions include/asm-blackfin/mach-bf537/cdefBF534.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,27 @@

/* Clock and System Control (0xFFC00000 - 0xFFC000FF) */
#define bfin_read_PLL_CTL() bfin_read16(PLL_CTL)
#define bfin_write_PLL_CTL(val) bfin_write16(PLL_CTL,val)
/* Writing to PLL_CTL initiates a PLL relock sequence. */
static __inline__ void bfin_write_PLL_CTL(unsigned int val)
{
unsigned long flags, iwr;

if (val == bfin_read_PLL_CTL())
return;

local_irq_save(flags);
/* Enable the PLL Wakeup bit in SIC IWR */
iwr = bfin_read32(SIC_IWR);
/* Only allow PPL Wakeup) */
bfin_write32(SIC_IWR, IWR_ENABLE(0));

bfin_write16(PLL_CTL, val);
SSYNC();
asm("IDLE;");

bfin_write32(SIC_IWR, iwr);
local_irq_restore(flags);
}
#define bfin_read_PLL_DIV() bfin_read16(PLL_DIV)
#define bfin_write_PLL_DIV(val) bfin_write16(PLL_DIV,val)
#define bfin_read_VR_CTL() bfin_read16(VR_CTL)
Expand All @@ -53,18 +73,21 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val)
{
unsigned long flags, iwr;

if (val == bfin_read_VR_CTL())
return;

local_irq_save(flags);
/* Enable the PLL Wakeup bit in SIC IWR */
iwr = bfin_read32(SIC_IWR);
/* Only allow PPL Wakeup) */
bfin_write32(SIC_IWR, IWR_ENABLE(0));

bfin_write16(VR_CTL, val);
SSYNC();

local_irq_save(flags);
asm("IDLE;");
local_irq_restore(flags);

bfin_write32(SIC_IWR, iwr);
local_irq_restore(flags);
}
#define bfin_read_PLL_STAT() bfin_read16(PLL_STAT)
#define bfin_write_PLL_STAT(val) bfin_write16(PLL_STAT,val)
Expand Down
37 changes: 33 additions & 4 deletions include/asm-blackfin/mach-bf548/cdefBF54x_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,33 @@
/* PLL Registers */

#define bfin_read_PLL_CTL() bfin_read16(PLL_CTL)
#define bfin_write_PLL_CTL(val) bfin_write16(PLL_CTL, val)
/* Writing to PLL_CTL initiates a PLL relock sequence. */
static __inline__ void bfin_write_PLL_CTL(unsigned int val)
{
unsigned long flags, iwr0, iwr1, iwr2;

if (val == bfin_read_PLL_CTL())
return;

local_irq_save(flags);
/* Enable the PLL Wakeup bit in SIC IWR */
iwr0 = bfin_read32(SIC_IWR0);
iwr1 = bfin_read32(SIC_IWR1);
iwr2 = bfin_read32(SIC_IWR2);
/* Only allow PPL Wakeup) */
bfin_write32(SIC_IWR0, IWR_ENABLE(0));
bfin_write32(SIC_IWR1, 0);
bfin_write32(SIC_IWR2, 0);

bfin_write16(PLL_CTL, val);
SSYNC();
asm("IDLE;");

bfin_write32(SIC_IWR0, iwr0);
bfin_write32(SIC_IWR1, iwr1);
bfin_write32(SIC_IWR2, iwr2);
local_irq_restore(flags);
}
#define bfin_read_PLL_DIV() bfin_read16(PLL_DIV)
#define bfin_write_PLL_DIV(val) bfin_write16(PLL_DIV, val)
#define bfin_read_VR_CTL() bfin_read16(VR_CTL)
Expand All @@ -52,6 +78,10 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val)
{
unsigned long flags, iwr0, iwr1, iwr2;

if (val == bfin_read_VR_CTL())
return;

local_irq_save(flags);
/* Enable the PLL Wakeup bit in SIC IWR */
iwr0 = bfin_read32(SIC_IWR0);
iwr1 = bfin_read32(SIC_IWR1);
Expand All @@ -63,13 +93,12 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val)

bfin_write16(VR_CTL, val);
SSYNC();

local_irq_save(flags);
asm("IDLE;");
local_irq_restore(flags);

bfin_write32(SIC_IWR0, iwr0);
bfin_write32(SIC_IWR1, iwr1);
bfin_write32(SIC_IWR2, iwr2);
local_irq_restore(flags);
}
#define bfin_read_PLL_STAT() bfin_read16(PLL_STAT)
#define bfin_write_PLL_STAT(val) bfin_write16(PLL_STAT, val)
Expand Down
34 changes: 30 additions & 4 deletions include/asm-blackfin/mach-bf561/cdefBF561.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,30 @@

/* Clock and System Control (0xFFC00000 - 0xFFC000FF) */
#define bfin_read_PLL_CTL() bfin_read16(PLL_CTL)
#define bfin_write_PLL_CTL(val) bfin_write16(PLL_CTL,val)
/* Writing to PLL_CTL initiates a PLL relock sequence. */
static __inline__ void bfin_write_PLL_CTL(unsigned int val)
{
unsigned long flags, iwr0, iwr1;

if (val == bfin_read_PLL_CTL())
return;

local_irq_save(flags);
/* Enable the PLL Wakeup bit in SIC IWR */
iwr0 = bfin_read32(SICA_IWR0);
iwr1 = bfin_read32(SICA_IWR1);
/* Only allow PPL Wakeup) */
bfin_write32(SICA_IWR0, IWR_ENABLE(0));
bfin_write32(SICA_IWR1, 0);

bfin_write16(PLL_CTL, val);
SSYNC();
asm("IDLE;");

bfin_write32(SICA_IWR0, iwr0);
bfin_write32(SICA_IWR1, iwr1);
local_irq_restore(flags);
}
#define bfin_read_PLL_DIV() bfin_read16(PLL_DIV)
#define bfin_write_PLL_DIV(val) bfin_write16(PLL_DIV,val)
#define bfin_read_VR_CTL() bfin_read16(VR_CTL)
Expand All @@ -56,6 +79,10 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val)
{
unsigned long flags, iwr0, iwr1;

if (val == bfin_read_VR_CTL())
return;

local_irq_save(flags);
/* Enable the PLL Wakeup bit in SIC IWR */
iwr0 = bfin_read32(SICA_IWR0);
iwr1 = bfin_read32(SICA_IWR1);
Expand All @@ -65,12 +92,11 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val)

bfin_write16(VR_CTL, val);
SSYNC();

local_irq_save(flags);
asm("IDLE;");
local_irq_restore(flags);

bfin_write32(SICA_IWR0, iwr0);
bfin_write32(SICA_IWR1, iwr1);
local_irq_restore(flags);
}
#define bfin_read_PLL_STAT() bfin_read16(PLL_STAT)
#define bfin_write_PLL_STAT(val) bfin_write16(PLL_STAT,val)
Expand Down

0 comments on commit a81501a

Please sign in to comment.