Skip to content

Commit

Permalink
[ARM] S3C64XX: Add ARM clock
Browse files Browse the repository at this point in the history
Add ARM clock to provide 'arm' from the APLL to the ARM core.

Signed-off-by: Ben Dooks <ben-linux@fluff.org>
  • Loading branch information
Ben Dooks committed May 7, 2009
1 parent 8f1ecf1 commit 496a3f0
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 4 deletions.
3 changes: 2 additions & 1 deletion arch/arm/mach-s3c6400/s3c6400.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include <plat/cpu-freq.h>
#include <plat/regs-serial.h>
#include <plat/regs-clock.h>

#include <plat/cpu.h>
#include <plat/devs.h>
Expand All @@ -54,7 +55,7 @@ void __init s3c6400_init_clocks(int xtal)
printk(KERN_DEBUG "%s: initialising clocks\n", __func__);
s3c24xx_register_baseclocks(xtal);
s3c64xx_register_clocks();
s3c6400_register_clocks();
s3c6400_register_clocks(S3C6400_CLKDIV0_ARM_MASK);
s3c6400_setup_clocks();
}

Expand Down
3 changes: 2 additions & 1 deletion arch/arm/mach-s3c6410/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

#include <plat/cpu-freq.h>
#include <plat/regs-serial.h>
#include <plat/regs-clock.h>

#include <plat/cpu.h>
#include <plat/devs.h>
Expand Down Expand Up @@ -68,7 +69,7 @@ void __init s3c6410_init_clocks(int xtal)
printk(KERN_DEBUG "%s: initialising clocks\n", __func__);
s3c24xx_register_baseclocks(xtal);
s3c64xx_register_clocks();
s3c6400_register_clocks();
s3c6400_register_clocks(S3C6410_CLKDIV0_ARM_MASK);
s3c6400_setup_clocks();
}

Expand Down
2 changes: 1 addition & 1 deletion arch/arm/plat-s3c64xx/include/plat/s3c6400.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
/* Common init code for S3C6400 related SoCs */

extern void s3c6400_common_init_uarts(struct s3c2410_uartcfg *cfg, int no);
extern void s3c6400_register_clocks(void);
extern void s3c6400_register_clocks(unsigned armclk_divlimit);
extern void s3c6400_setup_clocks(void);

#ifdef CONFIG_CPU_S3C6400
Expand Down
76 changes: 75 additions & 1 deletion arch/arm/plat-s3c64xx/s3c6400-clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,65 @@ static struct clksrc_clk clk_mout_mpll = {
.sources = &clk_src_mpll,
};

static unsigned int armclk_mask;

static unsigned long s3c64xx_clk_arm_get_rate(struct clk *clk)
{
unsigned long rate = clk_get_rate(clk->parent);
u32 clkdiv;

/* divisor mask starts at bit0, so no need to shift */
clkdiv = __raw_readl(S3C_CLK_DIV0) & armclk_mask;

return rate / (clkdiv + 1);
}

static unsigned long s3c64xx_clk_arm_round_rate(struct clk *clk,
unsigned long rate)
{
unsigned long parent = clk_get_rate(clk->parent);
u32 div;

if (parent < rate)
return rate;

div = (parent / rate) - 1;
if (div > armclk_mask)
div = armclk_mask;

return parent / (div + 1);
}

static int s3c64xx_clk_arm_set_rate(struct clk *clk, unsigned long rate)
{
unsigned long parent = clk_get_rate(clk->parent);
u32 div;
u32 val;

if (rate < parent / (armclk_mask + 1))
return -EINVAL;

rate = clk_round_rate(clk, rate);
div = clk_get_rate(clk->parent) / rate;

val = __raw_readl(S3C_CLK_DIV0);
val &= armclk_mask;
val |= (div - 1);
__raw_writel(val, S3C_CLK_DIV0);

return 0;

}

static struct clk clk_arm = {
.name = "armclk",
.id = -1,
.parent = &clk_mout_apll.clk,
.get_rate = s3c64xx_clk_arm_get_rate,
.set_rate = s3c64xx_clk_arm_set_rate,
.round_rate = s3c64xx_clk_arm_round_rate,
};

static unsigned long s3c64xx_clk_doutmpll_get_rate(struct clk *clk)
{
unsigned long rate = clk_get_rate(clk->parent);
Expand Down Expand Up @@ -665,14 +724,29 @@ static struct clk *clks[] __initdata = {
&clk_audio1.clk,
&clk_irda.clk,
&clk_camif.clk,
&clk_arm,
};

void __init s3c6400_register_clocks(void)
/**
* s3c6400_register_clocks - register clocks for s3c6400 and above
* @armclk_divlimit: Divisor mask for ARMCLK
*
* Register the clocks for the S3C6400 and above SoC range, such
* as ARMCLK and the clocks which have divider chains attached.
*
* This call does not setup the clocks, which is left to the
* s3c6400_setup_clocks() call which may be needed by the cpufreq
* or resume code to re-set the clocks if the bootloader has changed
* them.
*/
void __init s3c6400_register_clocks(unsigned armclk_divlimit)
{
struct clk *clkp;
int ret;
int ptr;

armclk_mask = armclk_divlimit;

for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
clkp = clks[ptr];
ret = s3c24xx_register_clock(clkp);
Expand Down

0 comments on commit 496a3f0

Please sign in to comment.