diff options
Diffstat (limited to 'arch/arm/plat-s3c')
-rw-r--r-- | arch/arm/plat-s3c/Kconfig | 12 | ||||
-rw-r--r-- | arch/arm/plat-s3c/clock.c | 10 | ||||
-rw-r--r-- | arch/arm/plat-s3c/include/plat/clock.h | 16 | ||||
-rw-r--r-- | arch/arm/plat-s3c/include/plat/cpu.h | 2 | ||||
-rw-r--r-- | arch/arm/plat-s3c/include/plat/debug-macro.S | 2 | ||||
-rw-r--r-- | arch/arm/plat-s3c/include/plat/devs.h | 1 | ||||
-rw-r--r-- | arch/arm/plat-s3c/include/plat/map-base.h (renamed from arch/arm/plat-s3c/include/plat/map.h) | 0 | ||||
-rw-r--r-- | arch/arm/plat-s3c/include/plat/regs-serial.h | 14 | ||||
-rw-r--r-- | arch/arm/plat-s3c/include/plat/regs-timer.h | 11 | ||||
-rw-r--r-- | arch/arm/plat-s3c/include/plat/uncompress.h | 2 | ||||
-rw-r--r-- | arch/arm/plat-s3c/pwm-clock.c | 71 | ||||
-rw-r--r-- | arch/arm/plat-s3c/time.c | 81 |
12 files changed, 140 insertions, 82 deletions
diff --git a/arch/arm/plat-s3c/Kconfig b/arch/arm/plat-s3c/Kconfig index 10c1dd3cd46..adb9060ec91 100644 --- a/arch/arm/plat-s3c/Kconfig +++ b/arch/arm/plat-s3c/Kconfig @@ -6,8 +6,8 @@ config PLAT_S3C bool - depends on ARCH_S3C2410 - default y if ARCH_S3C2410 + depends on ARCH_S3C2410 || ARCH_S3C24A0 || ARCH_S3C64XX + default y select NO_IOPORT help Base platform code for any Samsung S3C device @@ -16,24 +16,24 @@ config PLAT_S3C config CPU_LLSERIAL_S3C2410_ONLY bool - depends on ARCH_S3C2410 + depends on PLAT_S3C default y if CPU_LLSERIAL_S3C2410 && !CPU_LLSERIAL_S3C2440 config CPU_LLSERIAL_S3C2440_ONLY bool - depends on ARCH_S3C2410 + depends on PLAT_S3C default y if CPU_LLSERIAL_S3C2440 && !CPU_LLSERIAL_S3C2410 config CPU_LLSERIAL_S3C2410 bool - depends on ARCH_S3C2410 + depends on PLAT_S3C help Selected if there is an S3C2410 (or register compatible) serial low-level implementation needed config CPU_LLSERIAL_S3C2440 bool - depends on ARCH_S3C2410 + depends on PLAT_S3C help Selected if there is an S3C2440 (or register compatible) serial low-level implementation needed diff --git a/arch/arm/plat-s3c/clock.c b/arch/arm/plat-s3c/clock.c index da7ac07c7a0..1054d18828f 100644 --- a/arch/arm/plat-s3c/clock.c +++ b/arch/arm/plat-s3c/clock.c @@ -239,6 +239,16 @@ struct clk clk_xtal = { .ctrlbit = 0, }; +struct clk clk_ext = { + .name = "ext", + .id = -1, +}; + +struct clk clk_epll = { + .name = "epll", + .id = -1, +}; + struct clk clk_mpll = { .name = "mpll", .id = -1, diff --git a/arch/arm/plat-s3c/include/plat/clock.h b/arch/arm/plat-s3c/include/plat/clock.h index d871609738f..a10622eed43 100644 --- a/arch/arm/plat-s3c/include/plat/clock.h +++ b/arch/arm/plat-s3c/include/plat/clock.h @@ -45,7 +45,13 @@ extern struct clk clk_h; extern struct clk clk_p; extern struct clk clk_mpll; extern struct clk clk_upll; +extern struct clk clk_epll; extern struct clk clk_xtal; +extern struct clk clk_ext; + +/* S3C64XX specific clocks */ +extern struct clk clk_27m; +extern struct clk clk_48m; /* exports for arch/arm/mach-s3c2410 * @@ -61,6 +67,8 @@ extern int s3c24xx_register_clocks(struct clk **clk, int nr_clks); extern int s3c24xx_register_baseclocks(unsigned long xtal); +extern void s3c64xx_register_clocks(void); + extern void s3c24xx_setup_clocks(unsigned long fclk, unsigned long hclk, unsigned long pclk); @@ -70,3 +78,11 @@ extern void s3c2412_setup_clocks(void); extern void s3c244x_setup_clocks(void); extern void s3c2443_setup_clocks(void); +/* S3C64XX specific functions and clocks */ + +extern int s3c64xx_sclk_ctrl(struct clk *clk, int enable); + +/* Init for pwm clock code */ + +extern void s3c_pwmclk_init(void); + diff --git a/arch/arm/plat-s3c/include/plat/cpu.h b/arch/arm/plat-s3c/include/plat/cpu.h index 011157ea871..e62ae0fcfe5 100644 --- a/arch/arm/plat-s3c/include/plat/cpu.h +++ b/arch/arm/plat-s3c/include/plat/cpu.h @@ -44,8 +44,10 @@ extern void s3c_init_cpu(unsigned long idcode, /* core initialisation functions */ extern void s3c24xx_init_irq(void); +extern void s3c64xx_init_irq(u32 vic0, u32 vic1); extern void s3c24xx_init_io(struct map_desc *mach_desc, int size); +extern void s3c64xx_init_io(struct map_desc *mach_desc, int size); extern void s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no); diff --git a/arch/arm/plat-s3c/include/plat/debug-macro.S b/arch/arm/plat-s3c/include/plat/debug-macro.S index 4aa7e2e6c00..3634d4e3708 100644 --- a/arch/arm/plat-s3c/include/plat/debug-macro.S +++ b/arch/arm/plat-s3c/include/plat/debug-macro.S @@ -20,7 +20,7 @@ .endm #ifndef fifo_level -#define fifo_level fifo_level_s3c2410 +#define fifo_level fifo_level_s3c2440 #endif .macro fifo_full_s3c2440 rd, rx diff --git a/arch/arm/plat-s3c/include/plat/devs.h b/arch/arm/plat-s3c/include/plat/devs.h index badaac9d64a..a689c7c5ac2 100644 --- a/arch/arm/plat-s3c/include/plat/devs.h +++ b/arch/arm/plat-s3c/include/plat/devs.h @@ -17,6 +17,7 @@ struct s3c24xx_uart_resources { }; extern struct s3c24xx_uart_resources s3c2410_uart_resources[]; +extern struct s3c24xx_uart_resources s3c64xx_uart_resources[]; extern struct platform_device *s3c24xx_uart_devs[]; extern struct platform_device *s3c24xx_uart_src[]; diff --git a/arch/arm/plat-s3c/include/plat/map.h b/arch/arm/plat-s3c/include/plat/map-base.h index b84289d32a5..b84289d32a5 100644 --- a/arch/arm/plat-s3c/include/plat/map.h +++ b/arch/arm/plat-s3c/include/plat/map-base.h diff --git a/arch/arm/plat-s3c/include/plat/regs-serial.h b/arch/arm/plat-s3c/include/plat/regs-serial.h index a0daa647b92..3ca28585cf8 100644 --- a/arch/arm/plat-s3c/include/plat/regs-serial.h +++ b/arch/arm/plat-s3c/include/plat/regs-serial.h @@ -77,6 +77,12 @@ #define S3C2440_UCON_FCLK (3<<10) #define S3C2443_UCON_EPLL (3<<10) +#define S3C6400_UCON_CLKMASK (3<<10) +#define S3C6400_UCON_PCLK (0<<10) +#define S3C6400_UCON_PCLK2 (2<<10) +#define S3C6400_UCON_UCLK0 (1<<10) +#define S3C6400_UCON_UCLK1 (3<<10) + #define S3C2440_UCON2_FCLK_EN (1<<15) #define S3C2440_UCON0_DIVMASK (15 << 12) #define S3C2440_UCON1_DIVMASK (15 << 12) @@ -149,6 +155,14 @@ #define S3C2410_UFSTAT_RXMASK (15<<0) #define S3C2410_UFSTAT_RXSHIFT (0) +/* UFSTAT S3C24A0 */ +#define S3C24A0_UFSTAT_TXFULL (1 << 14) +#define S3C24A0_UFSTAT_RXFULL (1 << 6) +#define S3C24A0_UFSTAT_TXMASK (63 << 8) +#define S3C24A0_UFSTAT_TXSHIFT (8) +#define S3C24A0_UFSTAT_RXMASK (63) +#define S3C24A0_UFSTAT_RXSHIFT (0) + /* UFSTAT S3C2443 same as S3C2440 */ #define S3C2440_UFSTAT_TXFULL (1<<14) #define S3C2440_UFSTAT_RXFULL (1<<6) diff --git a/arch/arm/plat-s3c/include/plat/regs-timer.h b/arch/arm/plat-s3c/include/plat/regs-timer.h index cc0eedd53e3..d097d92f8cc 100644 --- a/arch/arm/plat-s3c/include/plat/regs-timer.h +++ b/arch/arm/plat-s3c/include/plat/regs-timer.h @@ -10,7 +10,6 @@ * S3C2410 Timer configuration */ - #ifndef __ASM_ARCH_REGS_TIMER_H #define __ASM_ARCH_REGS_TIMER_H @@ -21,6 +20,8 @@ #define S3C2410_TCFG1 S3C_TIMERREG(0x04) #define S3C2410_TCON S3C_TIMERREG(0x08) +#define S3C64XX_TINT_CSTAT S3C_TIMERREG(0x44) + #define S3C2410_TCFG_PRESCALER0_MASK (255<<0) #define S3C2410_TCFG_PRESCALER1_MASK (255<<8) #define S3C2410_TCFG_PRESCALER1_SHIFT (8) @@ -72,6 +73,14 @@ #define S3C2410_TCFG1_MUX_TCLK (4<<0) #define S3C2410_TCFG1_MUX_MASK (15<<0) +#define S3C64XX_TCFG1_MUX_DIV1 (0<<0) +#define S3C64XX_TCFG1_MUX_DIV2 (1<<0) +#define S3C64XX_TCFG1_MUX_DIV4 (2<<0) +#define S3C64XX_TCFG1_MUX_DIV8 (3<<0) +#define S3C64XX_TCFG1_MUX_DIV16 (4<<0) +#define S3C64XX_TCFG1_MUX_TCLK (5<<0) /* 3 sets of TCLK */ +#define S3C64XX_TCFG1_MUX_MASK (15<<0) + #define S3C2410_TCFG1_SHIFT(x) ((x) * 4) /* for each timer, we have an count buffer, an compare buffer and diff --git a/arch/arm/plat-s3c/include/plat/uncompress.h b/arch/arm/plat-s3c/include/plat/uncompress.h index 2c39a309aeb..6061de87f22 100644 --- a/arch/arm/plat-s3c/include/plat/uncompress.h +++ b/arch/arm/plat-s3c/include/plat/uncompress.h @@ -37,7 +37,7 @@ static void arch_detect_cpu(void); /* how many bytes we allow into the FIFO at a time in FIFO mode */ #define FIFO_MAX (14) -#define uart_base S3C24XX_PA_UART + (0x4000*CONFIG_S3C_LOWLEVEL_UART_PORT) +#define uart_base S3C_PA_UART + (S3C_UART_OFFSET * CONFIG_S3C_LOWLEVEL_UART_PORT) static __inline__ void uart_wr(unsigned int reg, unsigned int val) diff --git a/arch/arm/plat-s3c/pwm-clock.c b/arch/arm/plat-s3c/pwm-clock.c index e07d82891a9..a318215ab53 100644 --- a/arch/arm/plat-s3c/pwm-clock.c +++ b/arch/arm/plat-s3c/pwm-clock.c @@ -14,20 +14,20 @@ #include <linux/kernel.h> #include <linux/list.h> #include <linux/errno.h> +#include <linux/log2.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/io.h> #include <mach/hardware.h> +#include <mach/map.h> #include <asm/irq.h> -#include <mach/regs-clock.h> -#include <mach/regs-gpio.h> - #include <plat/clock.h> #include <plat/cpu.h> #include <plat/regs-timer.h> +#include <mach/pwm-clock.h> /* Each of the timers 0 through 5 go through the following * clock tree, with the inputs depending on the timers. @@ -168,11 +168,6 @@ static inline struct pwm_tdiv_clk *to_tdiv(struct clk *clk) return container_of(clk, struct pwm_tdiv_clk, clk); } -static inline unsigned long tcfg_to_divisor(unsigned long tcfg1) -{ - return 1 << (1 + tcfg1); -} - static unsigned long clk_pwm_tdiv_get_rate(struct clk *clk) { unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1); @@ -181,7 +176,7 @@ static unsigned long clk_pwm_tdiv_get_rate(struct clk *clk) tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id); tcfg1 &= S3C2410_TCFG1_MUX_MASK; - if (tcfg1 == S3C2410_TCFG1_MUX_TCLK) + if (pwm_cfg_src_is_tclk(tcfg1)) divisor = to_tdiv(clk)->divisor; else divisor = tcfg_to_divisor(tcfg1); @@ -198,7 +193,9 @@ static unsigned long clk_pwm_tdiv_round_rate(struct clk *clk, parent_rate = clk_get_rate(clk->parent); divisor = parent_rate / rate; - if (divisor <= 2) + if (divisor <= 1 && pwm_tdiv_has_div1()) + divisor = 1; + else if (divisor <= 2) divisor = 2; else if (divisor <= 4) divisor = 4; @@ -212,25 +209,7 @@ static unsigned long clk_pwm_tdiv_round_rate(struct clk *clk, static unsigned long clk_pwm_tdiv_bits(struct pwm_tdiv_clk *divclk) { - unsigned long bits; - - switch (divclk->divisor) { - case 2: - bits = S3C2410_TCFG1_MUX_DIV2; - break; - case 4: - bits = S3C2410_TCFG1_MUX_DIV4; - break; - case 8: - bits = S3C2410_TCFG1_MUX_DIV8; - break; - case 16: - default: - bits = S3C2410_TCFG1_MUX_DIV16; - break; - } - - return bits; + return pwm_tdiv_div_bits(divclk->divisor); } static void clk_pwm_tdiv_update(struct pwm_tdiv_clk *divclk) @@ -271,7 +250,7 @@ static int clk_pwm_tdiv_set_rate(struct clk *clk, unsigned long rate) /* Update the current MUX settings if we are currently * selected as the clock source for this clock. */ - if (tcfg1 != S3C2410_TCFG1_MUX_TCLK) + if (!pwm_cfg_src_is_tclk(tcfg1)) clk_pwm_tdiv_update(divclk); return 0; @@ -358,7 +337,7 @@ static int clk_pwm_tin_set_parent(struct clk *clk, struct clk *parent) unsigned long shift = S3C2410_TCFG1_SHIFT(id); if (parent == s3c24xx_pwmclk_tclk(id)) - bits = S3C2410_TCFG1_MUX_TCLK << shift; + bits = S3C_TCFG1_MUX_TCLK << shift; else if (parent == s3c24xx_pwmclk_tdiv(id)) bits = clk_pwm_tdiv_bits(to_tdiv(parent)) << shift; else @@ -420,7 +399,7 @@ static __init int clk_pwm_tin_register(struct clk *pwm) tcfg1 >>= S3C2410_TCFG1_SHIFT(id); tcfg1 &= S3C2410_TCFG1_MUX_MASK; - if (tcfg1 == S3C2410_TCFG1_MUX_TCLK) + if (pwm_cfg_src_is_tclk(tcfg1)) parent = s3c24xx_pwmclk_tclk(id); else parent = s3c24xx_pwmclk_tdiv(id); @@ -428,7 +407,16 @@ static __init int clk_pwm_tin_register(struct clk *pwm) return clk_set_parent(pwm, parent); } -static __init int s3c24xx_pwmclk_init(void) +/** + * s3c_pwmclk_init() - initialise pwm clocks + * + * Initialise and register the clocks which provide the inputs for the + * pwm timer blocks. + * + * Note, this call is required by the time core, so must be called after + * the base clocks are added and before any of the initcalls are run. + */ +__init void s3c_pwmclk_init(void) { struct clk *clk_timers; unsigned int clk; @@ -437,7 +425,7 @@ static __init int s3c24xx_pwmclk_init(void) clk_timers = clk_get(NULL, "timers"); if (IS_ERR(clk_timers)) { printk(KERN_ERR "%s: no parent clock\n", __func__); - return -EINVAL; + return; } for (clk = 0; clk < ARRAY_SIZE(clk_timer_scaler); clk++) { @@ -445,7 +433,7 @@ static __init int s3c24xx_pwmclk_init(void) ret = s3c24xx_register_clock(&clk_timer_scaler[clk]); if (ret < 0) { printk(KERN_ERR "error adding pwm scaler%d clock\n", clk); - goto err; + return; } } @@ -453,7 +441,7 @@ static __init int s3c24xx_pwmclk_init(void) ret = s3c24xx_register_clock(&clk_timer_tclk[clk]); if (ret < 0) { printk(KERN_ERR "error adding pww tclk%d\n", clk); - goto err; + return; } } @@ -461,7 +449,7 @@ static __init int s3c24xx_pwmclk_init(void) ret = clk_pwm_tdiv_register(clk); if (ret < 0) { printk(KERN_ERR "error adding pwm%d tdiv clock\n", clk); - goto err; + return; } } @@ -469,14 +457,7 @@ static __init int s3c24xx_pwmclk_init(void) ret = clk_pwm_tin_register(&clk_tin[clk]); if (ret < 0) { printk(KERN_ERR "error adding pwm%d tin clock\n", clk); - goto err; + return; } } - - return 0; - - err: - return ret; } - -arch_initcall(s3c24xx_pwmclk_init); diff --git a/arch/arm/plat-s3c/time.c b/arch/arm/plat-s3c/time.c index c6861a05a29..3b27b29da47 100644 --- a/arch/arm/plat-s3c/time.c +++ b/arch/arm/plat-s3c/time.c @@ -26,6 +26,7 @@ #include <linux/err.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/platform_device.h> #include <asm/system.h> #include <asm/leds.h> @@ -36,6 +37,7 @@ #include <plat/regs-timer.h> #include <mach/regs-irq.h> #include <asm/mach/time.h> +#include <mach/tick.h> #include <plat/clock.h> #include <plat/cpu.h> @@ -43,6 +45,10 @@ static unsigned long timer_startval; static unsigned long timer_usec_ticks; +#ifndef TICK_MAX +#define TICK_MAX (0xffff) +#endif + #define TIMER_USEC_SHIFT 16 /* we use the shifted arithmetic to work out the ratio of timer ticks @@ -91,12 +97,9 @@ static inline unsigned long timer_ticks_to_usec(unsigned long ticks) * IRQs are disabled before entering here from do_gettimeofday() */ -#define SRCPND_TIMER4 (1<<(IRQ_TIMER4 - IRQ_EINT0)) - static unsigned long s3c2410_gettimeoffset (void) { unsigned long tdone; - unsigned long irqpend; unsigned long tval; /* work out how many ticks have gone since last timer interrupt */ @@ -106,8 +109,7 @@ static unsigned long s3c2410_gettimeoffset (void) /* check to see if there is an interrupt pending */ - irqpend = __raw_readl(S3C2410_SRCPND); - if (irqpend & SRCPND_TIMER4) { + if (s3c24xx_ostimer_pending()) { /* re-read the timer, and try and fix up for the missed * interrupt. Note, the interrupt may go off before the * timer has re-loaded from wrapping. @@ -146,6 +148,10 @@ static struct irqaction s3c2410_timer_irq = { machine_is_anubis() || \ machine_is_osiris()) +static struct clk *tin; +static struct clk *tdiv; +static struct clk *timerclk; + /* * Set up timer interrupt, and return the current time in seconds. * @@ -159,13 +165,7 @@ static void s3c2410_timer_setup (void) unsigned long tcfg1; unsigned long tcfg0; - tcnt = 0xffff; /* default value for tcnt */ - - /* read the current timer configuration bits */ - - tcon = __raw_readl(S3C2410_TCON); - tcfg1 = __raw_readl(S3C2410_TCFG1); - tcfg0 = __raw_readl(S3C2410_TCFG0); + tcnt = TICK_MAX; /* default value for tcnt */ /* configure the system for whichever machine is in use */ @@ -174,11 +174,13 @@ static void s3c2410_timer_setup (void) timer_usec_ticks = timer_mask_usec_ticks(1, 12000000); tcnt = 12000000 / HZ; + tcfg1 = __raw_readl(S3C2410_TCFG1); tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK; tcfg1 |= S3C2410_TCFG1_MUX4_TCLK1; + __raw_writel(tcfg1, S3C2410_TCFG1); } else { unsigned long pclk; - struct clk *clk; + struct clk *tscaler; /* for the h1940 (and others), we use the pclk from the core * to generate the timer values. since values around 50 to @@ -189,29 +191,25 @@ static void s3c2410_timer_setup (void) * (8.45 ticks per usec) */ - /* this is used as default if no other timer can be found */ - - clk = clk_get(NULL, "timers"); - if (IS_ERR(clk)) - panic("failed to get clock for system timer"); - - clk_enable(clk); - - pclk = clk_get_rate(clk); + pclk = clk_get_rate(timerclk); /* configure clock tick */ timer_usec_ticks = timer_mask_usec_ticks(6, pclk); - tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK; - tcfg1 |= S3C2410_TCFG1_MUX4_DIV2; + tscaler = clk_get_parent(tdiv); - tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK; - tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT; + clk_set_rate(tscaler, pclk / 3); + clk_set_rate(tdiv, pclk / 6); + clk_set_parent(tin, tdiv); - tcnt = (pclk / 6) / HZ; + tcnt = clk_get_rate(tin) / HZ; } + tcon = __raw_readl(S3C2410_TCON); + tcfg0 = __raw_readl(S3C2410_TCFG0); + tcfg1 = __raw_readl(S3C2410_TCFG1); + /* timers reload after counting zero, so reduce the count by 1 */ tcnt--; @@ -220,7 +218,7 @@ static void s3c2410_timer_setup (void) tcon, tcnt, tcfg0, tcfg1, timer_usec_ticks); /* check to see if timer is within 16bit range... */ - if (tcnt > 0xffff) { + if (tcnt > TICK_MAX) { panic("setup_timer: HZ is too small, cannot configure timer!"); return; } @@ -247,8 +245,35 @@ static void s3c2410_timer_setup (void) __raw_writel(tcon, S3C2410_TCON); } +static void __init s3c2410_timer_resources(void) +{ + struct platform_device tmpdev; + + tmpdev.dev.bus = &platform_bus_type; + tmpdev.id = 4; + + timerclk = clk_get(NULL, "timers"); + if (IS_ERR(timerclk)) + panic("failed to get clock for system timer"); + + clk_enable(timerclk); + + if (!use_tclk1_12()) { + tin = clk_get(&tmpdev.dev, "pwm-tin"); + if (IS_ERR(tin)) + panic("failed to get pwm-tin clock for system timer"); + + tdiv = clk_get(&tmpdev.dev, "pwm-tdiv"); + if (IS_ERR(tdiv)) + panic("failed to get pwm-tdiv clock for system timer"); + } + + clk_enable(tin); +} + static void __init s3c2410_timer_init(void) { + s3c2410_timer_resources(); s3c2410_timer_setup(); setup_irq(IRQ_TIMER4, &s3c2410_timer_irq); } |