Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: integrator: convert to common clock

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.

Cc: Russell King <linux@arm.linux.org.uk>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
[mturquette@linaro.org: use 'select' instead of versatile Kconfig]
Signed-off-by: Mike Turquette <mturquette@linaro.org>

authored by

Linus Walleij and committed by
Mike Turquette
a613163d 91b87a47

+131 -136
+5 -2
arch/arm/Kconfig
··· 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 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 ··· 296 295 select ARCH_WANT_OPTIONAL_GPIOLIB 297 296 select NEED_MACH_IO_H if PCI 298 297 select PLAT_VERSATILE 298 + select PLAT_VERSATILE_CLOCK 299 299 select PLAT_VERSATILE_CLCD 300 300 select PLAT_VERSATILE_FPGA_IRQ 301 301 select ARM_TIMER_SP804 ··· 316 314 select ICST 317 315 select NO_IOPORT 318 316 select PLAT_VERSATILE 317 + select PLAT_VERSATILE_CLOCK 319 318 select PLAT_VERSATILE_CLCD 320 319 help 321 320 This enables support for the ARM Ltd Versatile Express boards.
-45
arch/arm/mach-integrator/core.c
··· 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> ··· 59 60 &kmi0_device, 60 61 &kmi1_device, 61 62 }; 62 - 63 - /* 64 - * These are fixed clocks. 65 - */ 66 - static struct clk clk24mhz = { 67 - .rate = 24000000, 68 - }; 69 - 70 - static struct clk uartclk = { 71 - .rate = 14745600, 72 - }; 73 - 74 - static struct clk dummy_apb_pclk; 75 - 76 - static struct clk_lookup lookups[] = { 77 - { /* Bus clock */ 78 - .con_id = "apb_pclk", 79 - .clk = &dummy_apb_pclk, 80 - }, { 81 - /* Integrator/AP timer frequency */ 82 - .dev_id = "ap_timer", 83 - .clk = &clk24mhz, 84 - }, { /* UART0 */ 85 - .dev_id = "uart0", 86 - .clk = &uartclk, 87 - }, { /* UART1 */ 88 - .dev_id = "uart1", 89 - .clk = &uartclk, 90 - }, { /* KMI0 */ 91 - .dev_id = "kmi0", 92 - .clk = &clk24mhz, 93 - }, { /* KMI1 */ 94 - .dev_id = "kmi1", 95 - .clk = &clk24mhz, 96 - }, { /* MMCI - IntegratorCP */ 97 - .dev_id = "mmci", 98 - .clk = &uartclk, 99 - } 100 - }; 101 - 102 - void __init integrator_init_early(void) 103 - { 104 - clkdev_add_table(lookups, ARRAY_SIZE(lookups)); 105 - } 106 63 107 64 static int __init integrator_init(void) 108 65 {
-26
arch/arm/mach-integrator/include/mach/clkdev.h
··· 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
+7 -1
arch/arm/mach-integrator/integrator_ap.c
··· 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> ··· 175 174 176 175 fpga_irq_init(VA_IC_BASE, "SC", IRQ_PIC_START, 177 176 -1, INTEGRATOR_SC_VALID_INT, NULL); 177 + integrator_clk_init(false); 178 178 } 179 179 180 180 #ifdef CONFIG_PM ··· 442 440 0xffffU); 443 441 } 444 442 443 + void __init ap_init_early(void) 444 + { 445 + } 446 + 445 447 /* 446 448 * Set up timer(s). 447 449 */ ··· 477 471 .reserve = integrator_reserve, 478 472 .map_io = ap_map_io, 479 473 .nr_irqs = NR_IRQS_INTEGRATOR_AP, 480 - .init_early = integrator_init_early, 474 + .init_early = ap_init_early, 481 475 .init_irq = ap_init_irq, 482 476 .handle_irq = fpga_handle_irq, 483 477 .timer = &ap_timer,
+2 -61
arch/arm/mach-integrator/integrator_cp.c
··· 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 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 - /* 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 176 232 177 /* 233 178 * Flash handling. ··· 351 406 352 407 static void __init intcp_init_early(void) 353 408 { 354 - clkdev_add_table(cp_lookups, ARRAY_SIZE(cp_lookups)); 355 - 356 - integrator_init_early(); 357 - 358 409 #ifdef CONFIG_PLAT_VERSATILE_SCHED_CLOCK 359 410 versatile_sched_clock_init(REFCOUNTER, 24000000); 360 411 #endif
+3
arch/arm/plat-versatile/Kconfig
··· 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 -1
arch/arm/plat-versatile/Makefile
··· 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
drivers/clk/versatile/Makefile
··· 1 1 # Makefile for Versatile-specific clocks 2 2 obj-$(CONFIG_ICST) += clk-icst.o 3 + obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o
+111
drivers/clk/versatile/clk-integrator.c
··· 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 + }
+1
include/linux/platform_data/clk-integrator.h
··· 1 + void integrator_clk_init(bool is_cp);