Skip to content

Commit

Permalink
[ARM] 5577/2: ep93xx: syscon locked register functions
Browse files Browse the repository at this point in the history
Add core functions to handle writes to the ep93xx software locked
registers.

There are a number of registers in the EP93xx System Controller
that require a write to the software lock register before they
can be updated. This patch adds a number of exported functions
to the ep93xx core that handle this access.

The software locked clock divider registers, VidClkDiv, MIRClkDiv,
I2SClkDiv and KeyTchClkDiv would typically involve writing a
specific value to the register. To support this the
ep93xx_syscon_swlocked_write() function is provided.

For the DeviceCfg register it's more typical to only need to
set or clear a single bit. A generic ep93xx_devcfg_set_clear()
function is provided to handle both operations. Two inline
functions, ep93xx_devcfg_set_bits() and ep93xx_devcfg_clear_bits()
are also provided to improve code readability.

In addition, the remaining bits in the System Controller Device
Config Register have been documented and the previously defined
names shortened.

All code paths that use this functionality have been updated
except for arch/arm/kernel/crunch.c. That code is in a context
switch path, which is not reentrant, so it is safe against itself.

Cc: Lennert Buytenhek <buytenh@wantstofly.org>
Cc: Matthias Kaehlcke <matthias@kaehlcke.net>
Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com>
Acked-by: Ryan Mallon <ryan@bluewatersys.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Hartley Sweeten authored and Russell King committed Jul 9, 2009
1 parent f04989b commit 02239f0
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 35 deletions.
13 changes: 9 additions & 4 deletions arch/arm/kernel/crunch.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ void crunch_task_release(struct thread_info *thread)

static int crunch_enabled(u32 devcfg)
{
return !!(devcfg & EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE);
return !!(devcfg & EP93XX_SYSCON_DEVCFG_CPENA);
}

static int crunch_do(struct notifier_block *self, unsigned long cmd, void *t)
Expand All @@ -56,11 +56,16 @@ static int crunch_do(struct notifier_block *self, unsigned long cmd, void *t)
break;

case THREAD_NOTIFY_SWITCH:
devcfg = __raw_readl(EP93XX_SYSCON_DEVICE_CONFIG);
devcfg = __raw_readl(EP93XX_SYSCON_DEVCFG);
if (crunch_enabled(devcfg) || crunch_owner == crunch_state) {
devcfg ^= EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE;
/*
* We don't use ep93xx_syscon_swlocked_write() here
* because we are on the context switch path and
* preemption is already disabled.
*/
devcfg ^= EP93XX_SYSCON_DEVCFG_CPENA;
__raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
__raw_writel(devcfg, EP93XX_SYSCON_DEVICE_CONFIG);
__raw_writel(devcfg, EP93XX_SYSCON_DEVCFG);
}
break;
}
Expand Down
24 changes: 14 additions & 10 deletions arch/arm/mach-ep93xx/clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,20 @@ static unsigned long get_uart_rate(struct clk *clk);

static struct clk clk_uart1 = {
.sw_locked = 1,
.enable_reg = EP93XX_SYSCON_DEVICE_CONFIG,
.enable_mask = EP93XX_SYSCON_DEVICE_CONFIG_U1EN,
.enable_reg = EP93XX_SYSCON_DEVCFG,
.enable_mask = EP93XX_SYSCON_DEVCFG_U1EN,
.get_rate = get_uart_rate,
};
static struct clk clk_uart2 = {
.sw_locked = 1,
.enable_reg = EP93XX_SYSCON_DEVICE_CONFIG,
.enable_mask = EP93XX_SYSCON_DEVICE_CONFIG_U2EN,
.enable_reg = EP93XX_SYSCON_DEVCFG,
.enable_mask = EP93XX_SYSCON_DEVCFG_U2EN,
.get_rate = get_uart_rate,
};
static struct clk clk_uart3 = {
.sw_locked = 1,
.enable_reg = EP93XX_SYSCON_DEVICE_CONFIG,
.enable_mask = EP93XX_SYSCON_DEVICE_CONFIG_U3EN,
.enable_reg = EP93XX_SYSCON_DEVCFG,
.enable_mask = EP93XX_SYSCON_DEVCFG_U3EN,
.get_rate = get_uart_rate,
};
static struct clk clk_pll1;
Expand Down Expand Up @@ -160,9 +160,11 @@ int clk_enable(struct clk *clk)
u32 value;

value = __raw_readl(clk->enable_reg);
value |= clk->enable_mask;
if (clk->sw_locked)
__raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
__raw_writel(value | clk->enable_mask, clk->enable_reg);
ep93xx_syscon_swlocked_write(value, clk->enable_reg);
else
__raw_writel(value, clk->enable_reg);
}

return 0;
Expand All @@ -175,9 +177,11 @@ void clk_disable(struct clk *clk)
u32 value;

value = __raw_readl(clk->enable_reg);
value &= ~clk->enable_mask;
if (clk->sw_locked)
__raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
__raw_writel(value & ~clk->enable_mask, clk->enable_reg);
ep93xx_syscon_swlocked_write(value, clk->enable_reg);
else
__raw_writel(value, clk->enable_reg);
}
}
EXPORT_SYMBOL(clk_disable);
Expand Down
52 changes: 43 additions & 9 deletions arch/arm/mach-ep93xx/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,47 @@ void __init ep93xx_init_irq(void)
}


/*************************************************************************
* EP93xx System Controller Software Locked register handling
*************************************************************************/

/*
* syscon_swlock prevents anything else from writing to the syscon
* block while a software locked register is being written.
*/
static DEFINE_SPINLOCK(syscon_swlock);

void ep93xx_syscon_swlocked_write(unsigned int val, unsigned int reg)
{
unsigned long flags;

spin_lock_irqsave(&syscon_swlock, flags);

__raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
__raw_writel(val, reg);

spin_unlock_irqrestore(&syscon_swlock, flags);
}
EXPORT_SYMBOL(ep93xx_syscon_swlocked_write);

void ep93xx_devcfg_set_clear(unsigned int set_bits, unsigned int clear_bits)
{
unsigned long flags;
unsigned int val;

spin_lock_irqsave(&syscon_swlock, flags);

val = __raw_readl(EP93XX_SYSCON_DEVCFG);
val |= set_bits;
val &= ~clear_bits;
__raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
__raw_writel(val, EP93XX_SYSCON_DEVCFG);

spin_unlock_irqrestore(&syscon_swlock, flags);
}
EXPORT_SYMBOL(ep93xx_devcfg_set_clear);


/*************************************************************************
* EP93xx peripheral handling
*************************************************************************/
Expand Down Expand Up @@ -550,15 +591,8 @@ extern void ep93xx_gpio_init(void);

void __init ep93xx_init_devices(void)
{
unsigned int v;

/*
* Disallow access to MaverickCrunch initially.
*/
v = __raw_readl(EP93XX_SYSCON_DEVICE_CONFIG);
v &= ~EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE;
__raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
__raw_writel(v, EP93XX_SYSCON_DEVICE_CONFIG);
/* Disallow access to MaverickCrunch initially */
ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_CPENA);

ep93xx_gpio_init();

Expand Down
36 changes: 31 additions & 5 deletions arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,37 @@
#define EP93XX_SYSCON_STANDBY EP93XX_SYSCON_REG(0x0c)
#define EP93XX_SYSCON_CLOCK_SET1 EP93XX_SYSCON_REG(0x20)
#define EP93XX_SYSCON_CLOCK_SET2 EP93XX_SYSCON_REG(0x24)
#define EP93XX_SYSCON_DEVICE_CONFIG EP93XX_SYSCON_REG(0x80)
#define EP93XX_SYSCON_DEVICE_CONFIG_U3EN (1<<24)
#define EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE (1<<23)
#define EP93XX_SYSCON_DEVICE_CONFIG_U2EN (1<<20)
#define EP93XX_SYSCON_DEVICE_CONFIG_U1EN (1<<18)
#define EP93XX_SYSCON_DEVCFG EP93XX_SYSCON_REG(0x80)
#define EP93XX_SYSCON_DEVCFG_SWRST (1<<31)
#define EP93XX_SYSCON_DEVCFG_D1ONG (1<<30)
#define EP93XX_SYSCON_DEVCFG_D0ONG (1<<29)
#define EP93XX_SYSCON_DEVCFG_IONU2 (1<<28)
#define EP93XX_SYSCON_DEVCFG_GONK (1<<27)
#define EP93XX_SYSCON_DEVCFG_TONG (1<<26)
#define EP93XX_SYSCON_DEVCFG_MONG (1<<25)
#define EP93XX_SYSCON_DEVCFG_U3EN (1<<24)
#define EP93XX_SYSCON_DEVCFG_CPENA (1<<23)
#define EP93XX_SYSCON_DEVCFG_A2ONG (1<<22)
#define EP93XX_SYSCON_DEVCFG_A1ONG (1<<21)
#define EP93XX_SYSCON_DEVCFG_U2EN (1<<20)
#define EP93XX_SYSCON_DEVCFG_EXVC (1<<19)
#define EP93XX_SYSCON_DEVCFG_U1EN (1<<18)
#define EP93XX_SYSCON_DEVCFG_TIN (1<<17)
#define EP93XX_SYSCON_DEVCFG_HC3IN (1<<15)
#define EP93XX_SYSCON_DEVCFG_HC3EN (1<<14)
#define EP93XX_SYSCON_DEVCFG_HC1IN (1<<13)
#define EP93XX_SYSCON_DEVCFG_HC1EN (1<<12)
#define EP93XX_SYSCON_DEVCFG_HONIDE (1<<11)
#define EP93XX_SYSCON_DEVCFG_GONIDE (1<<10)
#define EP93XX_SYSCON_DEVCFG_PONG (1<<9)
#define EP93XX_SYSCON_DEVCFG_EONIDE (1<<8)
#define EP93XX_SYSCON_DEVCFG_I2SONSSP (1<<7)
#define EP93XX_SYSCON_DEVCFG_I2SONAC97 (1<<6)
#define EP93XX_SYSCON_DEVCFG_RASONP3 (1<<4)
#define EP93XX_SYSCON_DEVCFG_RAS (1<<3)
#define EP93XX_SYSCON_DEVCFG_ADCPD (1<<2)
#define EP93XX_SYSCON_DEVCFG_KEYS (1<<1)
#define EP93XX_SYSCON_DEVCFG_SHENA (1<<0)
#define EP93XX_SYSCON_SWLOCK EP93XX_SYSCON_REG(0xc0)

#define EP93XX_WATCHDOG_BASE EP93XX_APB_IOMEM(0x00140000)
Expand Down
16 changes: 16 additions & 0 deletions arch/arm/mach-ep93xx/include/mach/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,24 @@ struct ep93xx_eth_data
void ep93xx_map_io(void);
void ep93xx_init_irq(void);
void ep93xx_init_time(unsigned long);

/* EP93xx System Controller software locked register write */
void ep93xx_syscon_swlocked_write(unsigned int val, unsigned int reg);
void ep93xx_devcfg_set_clear(unsigned int set_bits, unsigned int clear_bits);

static inline void ep93xx_devcfg_set_bits(unsigned int bits)
{
ep93xx_devcfg_set_clear(bits, 0x00);
}

static inline void ep93xx_devcfg_clear_bits(unsigned int bits)
{
ep93xx_devcfg_set_clear(0x00, bits);
}

void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr);
void ep93xx_register_i2c(struct i2c_board_info *devices, int num);

void ep93xx_init_devices(void);
extern struct sys_timer ep93xx_timer;

Expand Down
12 changes: 5 additions & 7 deletions arch/arm/mach-ep93xx/include/mach/system.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@ static inline void arch_idle(void)

static inline void arch_reset(char mode, const char *cmd)
{
u32 devicecfg;

local_irq_disable();

devicecfg = __raw_readl(EP93XX_SYSCON_DEVICE_CONFIG);
__raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
__raw_writel(devicecfg | 0x80000000, EP93XX_SYSCON_DEVICE_CONFIG);
__raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
__raw_writel(devicecfg & ~0x80000000, EP93XX_SYSCON_DEVICE_CONFIG);
/*
* Set then clear the SWRST bit to initiate a software reset
*/
ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_SWRST);
ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_SWRST);

while (1)
;
Expand Down

0 comments on commit 02239f0

Please sign in to comment.