This converts the Integrator platform to use common clock and the ICST driver. Since from this point not all ARM reference platforms use the clock, we define CONFIG_PLAT_VERSATILE_CLOCK and select it for all platforms except the Integrator. Open issue: I could not use the .init_early() field of the machine descriptor to initialize the clocks, but had to move them to .init_irq(), so presumably .init_early() is so early that common clock is not up, and .init_machine() is too late since it's needed for the clockevent/clocksource initialization. Any suggestions on how to solve this is very welcome.
Unified · Split
| @@ -254,8 +254,8 @@ config ARCH_INTEGRATOR · 253 unmodified lines | ||
| 254 | 254 | bool "ARM Ltd. Integrator family" |
| 255 | 255 | select ARM_AMBA |
| 256 | 256 | select ARCH_HAS_CPUFREQ |
| 257 | − select CLKDEV_LOOKUP | |
| 258 | − select HAVE_MACH_CLKDEV | |
| 257 | + select COMMON_CLK | |
| 258 | + select CLK_VERSATILE | |
| 259 | 259 | select HAVE_TCM |
| 260 | 260 | select ICST |
| 261 | 261 | select GENERIC_CLOCKEVENTS |
| @@ -277,6 +277,7 @@ config ARCH_REALVIEW · 15 unmodified lines | ||
| 277 | 277 | select GENERIC_CLOCKEVENTS |
| 278 | 278 | select ARCH_WANT_OPTIONAL_GPIOLIB |
| 279 | 279 | select PLAT_VERSATILE |
| 280 | + select PLAT_VERSATILE_CLOCK | |
| 280 | 281 | select PLAT_VERSATILE_CLCD |
| 281 | 282 | select ARM_TIMER_SP804 |
| 282 | 283 | select GPIO_PL061 if GPIOLIB |
| @@ -295,6 +296,7 @@ config ARCH_VERSATILE · 12 unmodified lines | ||
| 295 | 296 | select ARCH_WANT_OPTIONAL_GPIOLIB |
| 296 | 297 | select NEED_MACH_IO_H if PCI |
| 297 | 298 | select PLAT_VERSATILE |
| 299 | + select PLAT_VERSATILE_CLOCK | |
| 298 | 300 | select PLAT_VERSATILE_CLCD |
| 299 | 301 | select PLAT_VERSATILE_FPGA_IRQ |
| 300 | 302 | select ARM_TIMER_SP804 |
| @@ -314,6 +316,7 @@ config ARCH_VEXPRESS · 13 unmodified lines | ||
| 314 | 316 | select ICST |
| 315 | 317 | select NO_IOPORT |
| 316 | 318 | select PLAT_VERSATILE |
| 319 | + select PLAT_VERSATILE_CLOCK | |
| 317 | 320 | select PLAT_VERSATILE_CLCD |
| 318 | 321 | help |
| 319 | 322 | This enables support for the ARM Ltd Versatile Express boards. |
| @@ -21,7 +21,6 @@ · 20 unmodified lines | ||
| 21 | 21 | #include <linux/amba/bus.h> |
| 22 | 22 | #include <linux/amba/serial.h> |
| 23 | 23 | #include <linux/io.h> |
| 24 | −#include <linux/clkdev.h> | |
| 25 | 24 | |
| 26 | 25 | #include <mach/hardware.h> |
| 27 | 26 | #include <mach/platform.h> |
| @@ -61,50 +60,6 @@ static struct amba_device *amba_devs[] __initdata = { · 33 unmodified lines | ||
| 61 | 60 | &kmi1_device, |
| 62 | 61 | }; |
| 63 | 62 | |
| 64 | −/* | |
| 65 | − * These are fixed clocks. | |
| 66 | − */ | |
| 67 | −static struct clk clk24mhz = { | |
| 68 | − .rate = 24000000, | |
| 69 | −}; | |
| 70 | − | |
| 71 | −static struct clk uartclk = { | |
| 72 | − .rate = 14745600, | |
| 73 | −}; | |
| 74 | − | |
| 75 | −static struct clk dummy_apb_pclk; | |
| 76 | − | |
| 77 | −static struct clk_lookup lookups[] = { | |
| 78 | − { /* Bus clock */ | |
| 79 | − .con_id = "apb_pclk", | |
| 80 | − .clk = &dummy_apb_pclk, | |
| 81 | − }, { | |
| 82 | − /* Integrator/AP timer frequency */ | |
| 83 | − .dev_id = "ap_timer", | |
| 84 | − .clk = &clk24mhz, | |
| 85 | − }, { /* UART0 */ | |
| 86 | − .dev_id = "uart0", | |
| 87 | − .clk = &uartclk, | |
| 88 | − }, { /* UART1 */ | |
| 89 | − .dev_id = "uart1", | |
| 90 | − .clk = &uartclk, | |
| 91 | − }, { /* KMI0 */ | |
| 92 | − .dev_id = "kmi0", | |
| 93 | − .clk = &clk24mhz, | |
| 94 | − }, { /* KMI1 */ | |
| 95 | − .dev_id = "kmi1", | |
| 96 | − .clk = &clk24mhz, | |
| 97 | − }, { /* MMCI - IntegratorCP */ | |
| 98 | − .dev_id = "mmci", | |
| 99 | − .clk = &uartclk, | |
| 100 | − } | |
| 101 | −}; | |
| 102 | − | |
| 103 | −void __init integrator_init_early(void) | |
| 104 | −{ | |
| 105 | − clkdev_add_table(lookups, ARRAY_SIZE(lookups)); | |
| 106 | −} | |
| 107 | − | |
| 108 | 63 | static int __init integrator_init(void) |
| 109 | 64 | { |
| 110 | 65 | int i; |
| @@ -1,26 +0,0 @@ | ||
| 1 | −#ifndef __ASM_MACH_CLKDEV_H | |
| 2 | −#define __ASM_MACH_CLKDEV_H | |
| 3 | − | |
| 4 | −#include <linux/module.h> | |
| 5 | −#include <plat/clock.h> | |
| 6 | − | |
| 7 | −struct clk { | |
| 8 | − unsigned long rate; | |
| 9 | − const struct clk_ops *ops; | |
| 10 | − struct module *owner; | |
| 11 | − const struct icst_params *params; | |
| 12 | − void __iomem *vcoreg; | |
| 13 | − void *data; | |
| 14 | −}; | |
| 15 | − | |
| 16 | −static inline int __clk_get(struct clk *clk) | |
| 17 | −{ | |
| 18 | − return try_module_get(clk->owner); | |
| 19 | −} | |
| 20 | − | |
| 21 | −static inline void __clk_put(struct clk *clk) | |
| 22 | −{ | |
| 23 | − module_put(clk->owner); | |
| 24 | −} | |
| 25 | − | |
| 26 | −#endif | |
| @@ -33,6 +33,7 @@ · 32 unmodified lines | ||
| 33 | 33 | #include <linux/io.h> |
| 34 | 34 | #include <linux/mtd/physmap.h> |
| 35 | 35 | #include <linux/clk.h> |
| 36 | +#include <linux/platform_data/clk-integrator.h> | |
| 36 | 37 | #include <video/vga.h> |
| 37 | 38 | |
| 38 | 39 | #include <mach/hardware.h> |
| @@ -174,6 +175,7 @@ static void __init ap_init_irq(void) · 135 unmodified lines | ||
| 174 | 175 | |
| 175 | 176 | fpga_irq_init(VA_IC_BASE, "SC", IRQ_PIC_START, |
| 176 | 177 | -1, INTEGRATOR_SC_VALID_INT, NULL); |
| 178 | + integrator_clk_init(false); | |
| 177 | 179 | } |
| 178 | 180 | |
| 179 | 181 | #ifdef CONFIG_PM |
| @@ -440,6 +442,10 @@ static void integrator_clockevent_init(unsigned long inrate) · 260 unmodified lines | ||
| 440 | 442 | 0xffffU); |
| 441 | 443 | } |
| 442 | 444 | |
| 445 | +void __init ap_init_early(void) | |
| 446 | +{ | |
| 447 | +} | |
| 448 | + | |
| 443 | 449 | /* |
| 444 | 450 | * Set up timer(s). |
| 445 | 451 | */ |
| @@ -471,7 +477,7 @@ MACHINE_START(INTEGRATOR, "ARM-Integrator") · 25 unmodified lines | ||
| 471 | 477 | .reserve = integrator_reserve, |
| 472 | 478 | .map_io = ap_map_io, |
| 473 | 479 | .nr_irqs = NR_IRQS_INTEGRATOR_AP, |
| 474 | − .init_early = integrator_init_early, | |
| 480 | + .init_early = ap_init_early, | |
| 475 | 481 | .init_irq = ap_init_irq, |
| 476 | 482 | .handle_irq = fpga_handle_irq, |
| 477 | 483 | .timer = &ap_timer, |
| @@ -21,8 +21,8 @@ · 20 unmodified lines | ||
| 21 | 21 | #include <linux/amba/mmci.h> |
| 22 | 22 | #include <linux/io.h> |
| 23 | 23 | #include <linux/gfp.h> |
| 24 | −#include <linux/clkdev.h> | |
| 25 | 24 | #include <linux/mtd/physmap.h> |
| 25 | +#include <linux/platform_data/clk-integrator.h> | |
| 26 | 26 | |
| 27 | 27 | #include <mach/hardware.h> |
| 28 | 28 | #include <mach/platform.h> |
| @@ -171,64 +171,9 @@ static void __init intcp_init_irq(void) · 142 unmodified lines | ||
| 171 | 171 | |
| 172 | 172 | fpga_irq_init(INTCP_VA_SIC_BASE, "SIC", IRQ_SIC_START, |
| 173 | 173 | IRQ_CP_CPPLDINT, sic_mask, NULL); |
| 174 | + integrator_clk_init(true); | |
| 174 | 175 | } |
| 175 | 176 | |
| 176 | −/* | |
| 177 | − * Clock handling | |
| 178 | − */ | |
| 179 | −#define CM_LOCK (__io_address(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET) | |
| 180 | −#define CM_AUXOSC (__io_address(INTEGRATOR_HDR_BASE)+0x1c) | |
| 181 | − | |
| 182 | −static const struct icst_params cp_auxvco_params = { | |
| 183 | − .ref = 24000000, | |
| 184 | − .vco_max = ICST525_VCO_MAX_5V, | |
| 185 | − .vco_min = ICST525_VCO_MIN, | |
| 186 | − .vd_min = 8, | |
| 187 | − .vd_max = 263, | |
| 188 | − .rd_min = 3, | |
| 189 | − .rd_max = 65, | |
| 190 | − .s2div = icst525_s2div, | |
| 191 | − .idx2s = icst525_idx2s, | |
| 192 | −}; | |
| 193 | − | |
| 194 | −static void cp_auxvco_set(struct clk *clk, struct icst_vco vco) | |
| 195 | −{ | |
| 196 | − u32 val; | |
| 197 | − | |
| 198 | − val = readl(clk->vcoreg) & ~0x7ffff; | |
| 199 | − val |= vco.v | (vco.r << 9) | (vco.s << 16); | |
| 200 | − | |
| 201 | − writel(0xa05f, CM_LOCK); | |
| 202 | − writel(val, clk->vcoreg); | |
| 203 | − writel(0, CM_LOCK); | |
| 204 | −} | |
| 205 | − | |
| 206 | −static const struct clk_ops cp_auxclk_ops = { | |
| 207 | − .round = icst_clk_round, | |
| 208 | − .set = icst_clk_set, | |
| 209 | − .setvco = cp_auxvco_set, | |
| 210 | −}; | |
| 211 | − | |
| 212 | −static struct clk cp_auxclk = { | |
| 213 | − .ops = &cp_auxclk_ops, | |
| 214 | − .params = &cp_auxvco_params, | |
| 215 | − .vcoreg = CM_AUXOSC, | |
| 216 | −}; | |
| 217 | − | |
| 218 | −static struct clk sp804_clk = { | |
| 219 | − .rate = 1000000, | |
| 220 | −}; | |
| 221 | − | |
| 222 | −static struct clk_lookup cp_lookups[] = { | |
| 223 | − { /* CLCD */ | |
| 224 | − .dev_id = "clcd", | |
| 225 | − .clk = &cp_auxclk, | |
| 226 | − }, { /* SP804 timers */ | |
| 227 | − .dev_id = "sp804", | |
| 228 | − .clk = &sp804_clk, | |
| 229 | − }, | |
| 230 | −}; | |
| 231 | − | |
| 232 | 177 | /* |
| 233 | 178 | * Flash handling. |
| 234 | 179 | */ |
| @@ -406,10 +351,6 @@ static struct amba_device *amba_devs[] __initdata = { · 171 unmodified lines | ||
| 406 | 351 | |
| 407 | 352 | static void __init intcp_init_early(void) |
| 408 | 353 | { |
| 409 | − clkdev_add_table(cp_lookups, ARRAY_SIZE(cp_lookups)); | |
| 410 | − | |
| 411 | − integrator_init_early(); | |
| 412 | − | |
| 413 | 354 | #ifdef CONFIG_PLAT_VERSATILE_SCHED_CLOCK |
| 414 | 355 | versatile_sched_clock_init(REFCOUNTER, 24000000); |
| 415 | 356 | #endif |
| @@ -1,5 +1,8 @@ | ||
| 1 | 1 | if PLAT_VERSATILE |
| 2 | 2 | |
| 3 | +config PLAT_VERSATILE_CLOCK | |
| 4 | + bool | |
| 5 | + | |
| 3 | 6 | config PLAT_VERSATILE_CLCD |
| 4 | 7 | bool |
| 5 | 8 | |
| @@ -1,4 +1,4 @@ | ||
| 1 | −obj-y := clock.o | |
| 1 | +obj-$(CONFIG_PLAT_VERSATILE_CLOCK) += clock.o | |
| 2 | 2 | obj-$(CONFIG_PLAT_VERSATILE_CLCD) += clcd.o |
| 3 | 3 | obj-$(CONFIG_PLAT_VERSATILE_FPGA_IRQ) += fpga-irq.o |
| 4 | 4 | obj-$(CONFIG_PLAT_VERSATILE_LEDS) += leds.o |
| @@ -1,2 +1,3 @@ | ||
| 1 | 1 | # Makefile for Versatile-specific clocks |
| 2 | 2 | obj-$(CONFIG_ICST) += clk-icst.o |
| 3 | +obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o | |
| @@ -0,0 +1,111 @@ | ||
| 1 | +#include <linux/clk.h> | |
| 2 | +#include <linux/clkdev.h> | |
| 3 | +#include <linux/err.h> | |
| 4 | +#include <linux/io.h> | |
| 5 | +#include <linux/clk-provider.h> | |
| 6 | + | |
| 7 | +#include <mach/hardware.h> | |
| 8 | +#include <mach/platform.h> | |
| 9 | + | |
| 10 | +#include "clk-icst.h" | |
| 11 | + | |
| 12 | +/* | |
| 13 | + * Implementation of the ARM Integrator/AP and Integrator/CP clock tree. | |
| 14 | + * Inspired by portions of: | |
| 15 | + * plat-versatile/clock.c and plat-versatile/include/plat/clock.h | |
| 16 | + */ | |
| 17 | +#define CM_LOCK (__io_address(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET) | |
| 18 | +#define CM_AUXOSC (__io_address(INTEGRATOR_HDR_BASE)+0x1c) | |
| 19 | + | |
| 20 | +/** | |
| 21 | + * cp_auxvco_get() - get ICST VCO settings for the Integrator/CP | |
| 22 | + * @vco: ICST VCO parameters to update with hardware status | |
| 23 | + */ | |
| 24 | +static struct icst_vco cp_auxvco_get(void) | |
| 25 | +{ | |
| 26 | + u32 val; | |
| 27 | + struct icst_vco vco; | |
| 28 | + | |
| 29 | + val = readl(CM_AUXOSC); | |
| 30 | + vco.v = val & 0x1ff; | |
| 31 | + vco.r = (val >> 9) & 0x7f; | |
| 32 | + vco.s = (val >> 16) & 03; | |
| 33 | + return vco; | |
| 34 | +} | |
| 35 | + | |
| 36 | +/** | |
| 37 | + * cp_auxvco_set() - commit changes to Integrator/CP ICST VCO | |
| 38 | + * @vco: ICST VCO parameters to commit | |
| 39 | + */ | |
| 40 | +static void cp_auxvco_set(struct icst_vco vco) | |
| 41 | +{ | |
| 42 | + u32 val; | |
| 43 | + | |
| 44 | + val = readl(CM_AUXOSC) & ~0x7ffff; | |
| 45 | + val |= vco.v | (vco.r << 9) | (vco.s << 16); | |
| 46 | + | |
| 47 | + /* This magic unlocks the CM VCO so it can be controlled */ | |
| 48 | + writel(0xa05f, CM_LOCK); | |
| 49 | + writel(val, CM_AUXOSC); | |
| 50 | + /* This locks the CM again */ | |
| 51 | + writel(0, CM_LOCK); | |
| 52 | +} | |
| 53 | + | |
| 54 | +static const struct icst_params cp_auxvco_params = { | |
| 55 | + .ref = 24000000, | |
| 56 | + .vco_max = ICST525_VCO_MAX_5V, | |
| 57 | + .vco_min = ICST525_VCO_MIN, | |
| 58 | + .vd_min = 8, | |
| 59 | + .vd_max = 263, | |
| 60 | + .rd_min = 3, | |
| 61 | + .rd_max = 65, | |
| 62 | + .s2div = icst525_s2div, | |
| 63 | + .idx2s = icst525_idx2s, | |
| 64 | +}; | |
| 65 | + | |
| 66 | +static const struct clk_icst_desc __initdata cp_icst_desc = { | |
| 67 | + .params = &cp_auxvco_params, | |
| 68 | + .getvco = cp_auxvco_get, | |
| 69 | + .setvco = cp_auxvco_set, | |
| 70 | +}; | |
| 71 | + | |
| 72 | +/* | |
| 73 | + * integrator_clk_init() - set up the integrator clock tree | |
| 74 | + * @is_cp: pass true if it's the Integrator/CP else AP is assumed | |
| 75 | + */ | |
| 76 | +void __init integrator_clk_init(bool is_cp) | |
| 77 | +{ | |
| 78 | + struct clk *clk; | |
| 79 | + | |
| 80 | + /* APB clock dummy */ | |
| 81 | + clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); | |
| 82 | + clk_register_clkdev(clk, "apb_pclk", NULL); | |
| 83 | + | |
| 84 | + /* UART reference clock */ | |
| 85 | + clk = clk_register_fixed_rate(NULL, "uartclk", NULL, CLK_IS_ROOT, | |
| 86 | + 14745600); | |
| 87 | + clk_register_clkdev(clk, NULL, "uart0"); | |
| 88 | + clk_register_clkdev(clk, NULL, "uart1"); | |
| 89 | + if (is_cp) | |
| 90 | + clk_register_clkdev(clk, NULL, "mmci"); | |
| 91 | + | |
| 92 | + /* 24 MHz clock */ | |
| 93 | + clk = clk_register_fixed_rate(NULL, "clk24mhz", NULL, CLK_IS_ROOT, | |
| 94 | + 24000000); | |
| 95 | + clk_register_clkdev(clk, NULL, "kmi0"); | |
| 96 | + clk_register_clkdev(clk, NULL, "kmi1"); | |
| 97 | + if (!is_cp) | |
| 98 | + clk_register_clkdev(clk, NULL, "ap_timer"); | |
| 99 | + | |
| 100 | + if (!is_cp) | |
| 101 | + return; | |
| 102 | + | |
| 103 | + /* 1 MHz clock */ | |
| 104 | + clk = clk_register_fixed_rate(NULL, "clk1mhz", NULL, CLK_IS_ROOT, | |
| 105 | + 1000000); | |
| 106 | + clk_register_clkdev(clk, NULL, "sp804"); | |
| 107 | + | |
| 108 | + /* ICST VCO clock used on the Integrator/CP CLCD */ | |
| 109 | + clk = icst_clk_register(NULL, &cp_icst_desc); | |
| 110 | + clk_register_clkdev(clk, NULL, "clcd"); | |
| 111 | +} | |
| @@ -0,0 +1 @@ | ||
| 1 | +void integrator_clk_init(bool is_cp); | |