diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-17 15:50:54 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-17 15:50:54 -0400 |
commit | bfaf245022b4b8661af2e35f467cf0e91943c24c (patch) | |
tree | b5a6ee49a047557a791eb897c8c9545a155e36b7 /drivers/clk | |
parent | 96d928ed75c4ba4253e82910a697ec7b06ace8b4 (diff) | |
parent | 3e20a26b02bd4f24945c87407df51948dd488620 (diff) |
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS updates from Ralf Baechle:
"This is the main pull request for MIPS for Linux 4.1. Most
noteworthy:
- Add more Octeon-optimized crypto functions
- Octeon crypto preemption and locking fixes
- Little endian support for Octeon
- Use correct CSR to soft reset Octeons
- Support LEDs on the Octeon-based DSR-1000N
- Fix PCI interrupt mapping for the Octeon-based DSR-1000N
- Mark prom_free_prom_memory() as __init for a number of systems
- Support for Imagination's Pistachio SOC. This includes arch and
CLK bits. I'd like to merge pinctrl bits later
- Improve parallelism of csum_partial for certain pipelines
- Organize DTB files in subdirs like other architectures
- Implement read_sched_clock for all MIPS platforms other than
Octeon
- Massive series of 38 fixes and cleanups for the FPU emulator /
kernel
- Further FPU remulator work to support new features. This sits on a
separate branch which also has been pulled into the 4.1 KVM branch
- Clean up and fixes for the SEAD3 eval board; remove unused file
- Various updates for Netlogic platforms
- A number of small updates for Loongson 3 platforms
- Increase the memory limit for ATH79 platforms to 256MB
- A fair number of fixes and updates for BCM47xx platforms
- Finish the implementation of XPA support
- MIPS FDC support. No, not floppy controller but Fast Debug Channel :)
- Detect the R16000 used in SGI legacy platforms
- Fix Kconfig dependencies for the SSB bus support"
* 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (265 commits)
MIPS: Makefile: Fix MIPS ASE detection code
MIPS: asm: elf: Set O32 default FPU flags
MIPS: BCM47XX: Fix detecting Microsoft MN-700 & Asus WL500G
MIPS: Kconfig: Disable SMP/CPS for 64-bit
MIPS: Hibernate: flush TLB entries earlier
MIPS: smp-cps: cpu_set FPU mask if FPU present
MIPS: lose_fpu(): Disable FPU when MSA enabled
MIPS: ralink: add missing symbol for RALINK_ILL_ACC
MIPS: ralink: Fix bad config symbol in PCI makefile.
SSB: fix Kconfig dependencies
MIPS: Malta: Detect and fix bad memsize values
Revert "MIPS: Avoid pipeline stalls on some MIPS32R2 cores."
MIPS: Octeon: Delete override of cpu_has_mips_r2_exec_hazard.
MIPS: Fix cpu_has_mips_r2_exec_hazard.
MIPS: kernel: entry.S: Set correct ISA level for mips_ihb
MIPS: asm: spinlock: Fix addiu instruction for R10000_LLSC_WAR case
MIPS: r4kcache: Use correct base register for MIPS R6 cache flushes
MIPS: Kconfig: Fix typo for the r2-to-r6 emulator kernel parameter
MIPS: unaligned: Fix regular load/store instruction emulation for EVA
MIPS: unaligned: Surround load/store macros in do {} while statements
...
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/pistachio/Makefile | 3 | ||||
-rw-r--r-- | drivers/clk/pistachio/clk-pistachio.c | 329 | ||||
-rw-r--r-- | drivers/clk/pistachio/clk-pll.c | 401 | ||||
-rw-r--r-- | drivers/clk/pistachio/clk.c | 140 | ||||
-rw-r--r-- | drivers/clk/pistachio/clk.h | 174 |
6 files changed, 1048 insertions, 0 deletions
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index d478ceb69c5f..e43ff53f85a6 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile | |||
@@ -54,6 +54,7 @@ obj-$(CONFIG_ARCH_MMP) += mmp/ | |||
54 | endif | 54 | endif |
55 | obj-$(CONFIG_PLAT_ORION) += mvebu/ | 55 | obj-$(CONFIG_PLAT_ORION) += mvebu/ |
56 | obj-$(CONFIG_ARCH_MXS) += mxs/ | 56 | obj-$(CONFIG_ARCH_MXS) += mxs/ |
57 | obj-$(CONFIG_MACH_PISTACHIO) += pistachio/ | ||
57 | obj-$(CONFIG_COMMON_CLK_PXA) += pxa/ | 58 | obj-$(CONFIG_COMMON_CLK_PXA) += pxa/ |
58 | obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ | 59 | obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ |
59 | obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ | 60 | obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ |
diff --git a/drivers/clk/pistachio/Makefile b/drivers/clk/pistachio/Makefile new file mode 100644 index 000000000000..f1e151fbef65 --- /dev/null +++ b/drivers/clk/pistachio/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | obj-y += clk.o | ||
2 | obj-y += clk-pll.o | ||
3 | obj-y += clk-pistachio.o | ||
diff --git a/drivers/clk/pistachio/clk-pistachio.c b/drivers/clk/pistachio/clk-pistachio.c new file mode 100644 index 000000000000..8c0fe8828f99 --- /dev/null +++ b/drivers/clk/pistachio/clk-pistachio.c | |||
@@ -0,0 +1,329 @@ | |||
1 | /* | ||
2 | * Pistachio SoC clock controllers | ||
3 | * | ||
4 | * Copyright (C) 2014 Google, Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/clk-provider.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/io.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/of.h> | ||
16 | |||
17 | #include <dt-bindings/clock/pistachio-clk.h> | ||
18 | |||
19 | #include "clk.h" | ||
20 | |||
21 | static struct pistachio_gate pistachio_gates[] __initdata = { | ||
22 | GATE(CLK_MIPS, "mips", "mips_div", 0x104, 0), | ||
23 | GATE(CLK_AUDIO_IN, "audio_in", "audio_clk_in_gate", 0x104, 1), | ||
24 | GATE(CLK_AUDIO, "audio", "audio_div", 0x104, 2), | ||
25 | GATE(CLK_I2S, "i2s", "i2s_div", 0x104, 3), | ||
26 | GATE(CLK_SPDIF, "spdif", "spdif_div", 0x104, 4), | ||
27 | GATE(CLK_AUDIO_DAC, "audio_dac", "audio_dac_div", 0x104, 5), | ||
28 | GATE(CLK_RPU_V, "rpu_v", "rpu_v_div", 0x104, 6), | ||
29 | GATE(CLK_RPU_L, "rpu_l", "rpu_l_div", 0x104, 7), | ||
30 | GATE(CLK_RPU_SLEEP, "rpu_sleep", "rpu_sleep_div", 0x104, 8), | ||
31 | GATE(CLK_WIFI_PLL_GATE, "wifi_pll_gate", "wifi_pll_mux", 0x104, 9), | ||
32 | GATE(CLK_RPU_CORE, "rpu_core", "rpu_core_div", 0x104, 10), | ||
33 | GATE(CLK_WIFI_ADC, "wifi_adc", "wifi_div8_mux", 0x104, 11), | ||
34 | GATE(CLK_WIFI_DAC, "wifi_dac", "wifi_div4_mux", 0x104, 12), | ||
35 | GATE(CLK_USB_PHY, "usb_phy", "usb_phy_div", 0x104, 13), | ||
36 | GATE(CLK_ENET_IN, "enet_in", "enet_clk_in_gate", 0x104, 14), | ||
37 | GATE(CLK_ENET, "enet", "enet_div", 0x104, 15), | ||
38 | GATE(CLK_UART0, "uart0", "uart0_div", 0x104, 16), | ||
39 | GATE(CLK_UART1, "uart1", "uart1_div", 0x104, 17), | ||
40 | GATE(CLK_PERIPH_SYS, "periph_sys", "sys_internal_div", 0x104, 18), | ||
41 | GATE(CLK_SPI0, "spi0", "spi0_div", 0x104, 19), | ||
42 | GATE(CLK_SPI1, "spi1", "spi1_div", 0x104, 20), | ||
43 | GATE(CLK_EVENT_TIMER, "event_timer", "event_timer_div", 0x104, 21), | ||
44 | GATE(CLK_AUX_ADC_INTERNAL, "aux_adc_internal", "sys_internal_div", | ||
45 | 0x104, 22), | ||
46 | GATE(CLK_AUX_ADC, "aux_adc", "aux_adc_div", 0x104, 23), | ||
47 | GATE(CLK_SD_HOST, "sd_host", "sd_host_div", 0x104, 24), | ||
48 | GATE(CLK_BT, "bt", "bt_div", 0x104, 25), | ||
49 | GATE(CLK_BT_DIV4, "bt_div4", "bt_div4_div", 0x104, 26), | ||
50 | GATE(CLK_BT_DIV8, "bt_div8", "bt_div8_div", 0x104, 27), | ||
51 | GATE(CLK_BT_1MHZ, "bt_1mhz", "bt_1mhz_div", 0x104, 28), | ||
52 | }; | ||
53 | |||
54 | static struct pistachio_fixed_factor pistachio_ffs[] __initdata = { | ||
55 | FIXED_FACTOR(CLK_WIFI_DIV4, "wifi_div4", "wifi_pll", 4), | ||
56 | FIXED_FACTOR(CLK_WIFI_DIV8, "wifi_div8", "wifi_pll", 8), | ||
57 | }; | ||
58 | |||
59 | static struct pistachio_div pistachio_divs[] __initdata = { | ||
60 | DIV(CLK_MIPS_INTERNAL_DIV, "mips_internal_div", "mips_pll_mux", | ||
61 | 0x204, 2), | ||
62 | DIV(CLK_MIPS_DIV, "mips_div", "mips_internal_div", 0x208, 8), | ||
63 | DIV_F(CLK_AUDIO_DIV, "audio_div", "audio_mux", | ||
64 | 0x20c, 8, CLK_DIVIDER_ROUND_CLOSEST), | ||
65 | DIV_F(CLK_I2S_DIV, "i2s_div", "audio_pll_mux", | ||
66 | 0x210, 8, CLK_DIVIDER_ROUND_CLOSEST), | ||
67 | DIV_F(CLK_SPDIF_DIV, "spdif_div", "audio_pll_mux", | ||
68 | 0x214, 8, CLK_DIVIDER_ROUND_CLOSEST), | ||
69 | DIV_F(CLK_AUDIO_DAC_DIV, "audio_dac_div", "audio_pll_mux", | ||
70 | 0x218, 8, CLK_DIVIDER_ROUND_CLOSEST), | ||
71 | DIV(CLK_RPU_V_DIV, "rpu_v_div", "rpu_v_pll_mux", 0x21c, 2), | ||
72 | DIV(CLK_RPU_L_DIV, "rpu_l_div", "rpu_l_mux", 0x220, 2), | ||
73 | DIV(CLK_RPU_SLEEP_DIV, "rpu_sleep_div", "xtal", 0x224, 10), | ||
74 | DIV(CLK_RPU_CORE_DIV, "rpu_core_div", "rpu_core_mux", 0x228, 3), | ||
75 | DIV(CLK_USB_PHY_DIV, "usb_phy_div", "sys_internal_div", 0x22c, 6), | ||
76 | DIV(CLK_ENET_DIV, "enet_div", "enet_mux", 0x230, 6), | ||
77 | DIV_F(CLK_UART0_INTERNAL_DIV, "uart0_internal_div", "sys_pll_mux", | ||
78 | 0x234, 3, CLK_DIVIDER_ROUND_CLOSEST), | ||
79 | DIV_F(CLK_UART0_DIV, "uart0_div", "uart0_internal_div", 0x238, 10, | ||
80 | CLK_DIVIDER_ROUND_CLOSEST), | ||
81 | DIV_F(CLK_UART1_INTERNAL_DIV, "uart1_internal_div", "sys_pll_mux", | ||
82 | 0x23c, 3, CLK_DIVIDER_ROUND_CLOSEST), | ||
83 | DIV_F(CLK_UART1_DIV, "uart1_div", "uart1_internal_div", 0x240, 10, | ||
84 | CLK_DIVIDER_ROUND_CLOSEST), | ||
85 | DIV(CLK_SYS_INTERNAL_DIV, "sys_internal_div", "sys_pll_mux", 0x244, 3), | ||
86 | DIV(CLK_SPI0_INTERNAL_DIV, "spi0_internal_div", "sys_pll_mux", | ||
87 | 0x248, 3), | ||
88 | DIV(CLK_SPI0_DIV, "spi0_div", "spi0_internal_div", 0x24c, 7), | ||
89 | DIV(CLK_SPI1_INTERNAL_DIV, "spi1_internal_div", "sys_pll_mux", | ||
90 | 0x250, 3), | ||
91 | DIV(CLK_SPI1_DIV, "spi1_div", "spi1_internal_div", 0x254, 7), | ||
92 | DIV(CLK_EVENT_TIMER_INTERNAL_DIV, "event_timer_internal_div", | ||
93 | "event_timer_mux", 0x258, 3), | ||
94 | DIV(CLK_EVENT_TIMER_DIV, "event_timer_div", "event_timer_internal_div", | ||
95 | 0x25c, 12), | ||
96 | DIV(CLK_AUX_ADC_INTERNAL_DIV, "aux_adc_internal_div", | ||
97 | "aux_adc_internal", 0x260, 3), | ||
98 | DIV(CLK_AUX_ADC_DIV, "aux_adc_div", "aux_adc_internal_div", 0x264, 10), | ||
99 | DIV(CLK_SD_HOST_DIV, "sd_host_div", "sd_host_mux", 0x268, 6), | ||
100 | DIV(CLK_BT_DIV, "bt_div", "bt_pll_mux", 0x26c, 6), | ||
101 | DIV(CLK_BT_DIV4_DIV, "bt_div4_div", "bt_pll_mux", 0x270, 6), | ||
102 | DIV(CLK_BT_DIV8_DIV, "bt_div8_div", "bt_pll_mux", 0x274, 6), | ||
103 | DIV(CLK_BT_1MHZ_INTERNAL_DIV, "bt_1mhz_internal_div", "bt_pll_mux", | ||
104 | 0x278, 3), | ||
105 | DIV(CLK_BT_1MHZ_DIV, "bt_1mhz_div", "bt_1mhz_internal_div", 0x27c, 10), | ||
106 | }; | ||
107 | |||
108 | PNAME(mux_xtal_audio_refclk) = { "xtal", "audio_clk_in_gate" }; | ||
109 | PNAME(mux_xtal_mips) = { "xtal", "mips_pll" }; | ||
110 | PNAME(mux_xtal_audio) = { "xtal", "audio_pll", "audio_in" }; | ||
111 | PNAME(mux_audio_debug) = { "audio_pll_mux", "debug_mux" }; | ||
112 | PNAME(mux_xtal_rpu_v) = { "xtal", "rpu_v_pll" }; | ||
113 | PNAME(mux_xtal_rpu_l) = { "xtal", "rpu_l_pll" }; | ||
114 | PNAME(mux_rpu_l_mips) = { "rpu_l_pll_mux", "mips_pll_mux" }; | ||
115 | PNAME(mux_xtal_wifi) = { "xtal", "wifi_pll" }; | ||
116 | PNAME(mux_xtal_wifi_div4) = { "xtal", "wifi_div4" }; | ||
117 | PNAME(mux_xtal_wifi_div8) = { "xtal", "wifi_div8" }; | ||
118 | PNAME(mux_wifi_div4_rpu_l) = { "wifi_pll_gate", "wifi_div4_mux", | ||
119 | "rpu_l_pll_mux" }; | ||
120 | PNAME(mux_xtal_sys) = { "xtal", "sys_pll" }; | ||
121 | PNAME(mux_sys_enet) = { "sys_internal_div", "enet_in" }; | ||
122 | PNAME(mux_audio_sys) = { "audio_pll_mux", "sys_internal_div" }; | ||
123 | PNAME(mux_sys_bt) = { "sys_internal_div", "bt_pll_mux" }; | ||
124 | PNAME(mux_xtal_bt) = { "xtal", "bt_pll" }; | ||
125 | |||
126 | static struct pistachio_mux pistachio_muxes[] __initdata = { | ||
127 | MUX(CLK_AUDIO_REF_MUX, "audio_refclk_mux", mux_xtal_audio_refclk, | ||
128 | 0x200, 0), | ||
129 | MUX(CLK_MIPS_PLL_MUX, "mips_pll_mux", mux_xtal_mips, 0x200, 1), | ||
130 | MUX(CLK_AUDIO_PLL_MUX, "audio_pll_mux", mux_xtal_audio, 0x200, 2), | ||
131 | MUX(CLK_AUDIO_MUX, "audio_mux", mux_audio_debug, 0x200, 4), | ||
132 | MUX(CLK_RPU_V_PLL_MUX, "rpu_v_pll_mux", mux_xtal_rpu_v, 0x200, 5), | ||
133 | MUX(CLK_RPU_L_PLL_MUX, "rpu_l_pll_mux", mux_xtal_rpu_l, 0x200, 6), | ||
134 | MUX(CLK_RPU_L_MUX, "rpu_l_mux", mux_rpu_l_mips, 0x200, 7), | ||
135 | MUX(CLK_WIFI_PLL_MUX, "wifi_pll_mux", mux_xtal_wifi, 0x200, 8), | ||
136 | MUX(CLK_WIFI_DIV4_MUX, "wifi_div4_mux", mux_xtal_wifi_div4, 0x200, 9), | ||
137 | MUX(CLK_WIFI_DIV8_MUX, "wifi_div8_mux", mux_xtal_wifi_div8, 0x200, 10), | ||
138 | MUX(CLK_RPU_CORE_MUX, "rpu_core_mux", mux_wifi_div4_rpu_l, 0x200, 11), | ||
139 | MUX(CLK_SYS_PLL_MUX, "sys_pll_mux", mux_xtal_sys, 0x200, 13), | ||
140 | MUX(CLK_ENET_MUX, "enet_mux", mux_sys_enet, 0x200, 14), | ||
141 | MUX(CLK_EVENT_TIMER_MUX, "event_timer_mux", mux_audio_sys, 0x200, 15), | ||
142 | MUX(CLK_SD_HOST_MUX, "sd_host_mux", mux_sys_bt, 0x200, 16), | ||
143 | MUX(CLK_BT_PLL_MUX, "bt_pll_mux", mux_xtal_bt, 0x200, 17), | ||
144 | }; | ||
145 | |||
146 | static struct pistachio_pll pistachio_plls[] __initdata = { | ||
147 | PLL_FIXED(CLK_MIPS_PLL, "mips_pll", "xtal", PLL_GF40LP_LAINT, 0x0), | ||
148 | PLL_FIXED(CLK_AUDIO_PLL, "audio_pll", "audio_refclk_mux", | ||
149 | PLL_GF40LP_FRAC, 0xc), | ||
150 | PLL_FIXED(CLK_RPU_V_PLL, "rpu_v_pll", "xtal", PLL_GF40LP_LAINT, 0x20), | ||
151 | PLL_FIXED(CLK_RPU_L_PLL, "rpu_l_pll", "xtal", PLL_GF40LP_LAINT, 0x2c), | ||
152 | PLL_FIXED(CLK_SYS_PLL, "sys_pll", "xtal", PLL_GF40LP_FRAC, 0x38), | ||
153 | PLL_FIXED(CLK_WIFI_PLL, "wifi_pll", "xtal", PLL_GF40LP_FRAC, 0x4c), | ||
154 | PLL_FIXED(CLK_BT_PLL, "bt_pll", "xtal", PLL_GF40LP_LAINT, 0x60), | ||
155 | }; | ||
156 | |||
157 | PNAME(mux_debug) = { "mips_pll_mux", "rpu_v_pll_mux", | ||
158 | "rpu_l_pll_mux", "sys_pll_mux", | ||
159 | "wifi_pll_mux", "bt_pll_mux" }; | ||
160 | static u32 mux_debug_idx[] = { 0x0, 0x1, 0x2, 0x4, 0x8, 0x10 }; | ||
161 | |||
162 | static unsigned int pistachio_critical_clks[] __initdata = { | ||
163 | CLK_MIPS, | ||
164 | CLK_PERIPH_SYS, | ||
165 | }; | ||
166 | |||
167 | static void __init pistachio_clk_init(struct device_node *np) | ||
168 | { | ||
169 | struct pistachio_clk_provider *p; | ||
170 | struct clk *debug_clk; | ||
171 | |||
172 | p = pistachio_clk_alloc_provider(np, CLK_NR_CLKS); | ||
173 | if (!p) | ||
174 | return; | ||
175 | |||
176 | pistachio_clk_register_pll(p, pistachio_plls, | ||
177 | ARRAY_SIZE(pistachio_plls)); | ||
178 | pistachio_clk_register_mux(p, pistachio_muxes, | ||
179 | ARRAY_SIZE(pistachio_muxes)); | ||
180 | pistachio_clk_register_div(p, pistachio_divs, | ||
181 | ARRAY_SIZE(pistachio_divs)); | ||
182 | pistachio_clk_register_fixed_factor(p, pistachio_ffs, | ||
183 | ARRAY_SIZE(pistachio_ffs)); | ||
184 | pistachio_clk_register_gate(p, pistachio_gates, | ||
185 | ARRAY_SIZE(pistachio_gates)); | ||
186 | |||
187 | debug_clk = clk_register_mux_table(NULL, "debug_mux", mux_debug, | ||
188 | ARRAY_SIZE(mux_debug), | ||
189 | CLK_SET_RATE_NO_REPARENT, | ||
190 | p->base + 0x200, 18, 0x1f, 0, | ||
191 | mux_debug_idx, NULL); | ||
192 | p->clk_data.clks[CLK_DEBUG_MUX] = debug_clk; | ||
193 | |||
194 | pistachio_clk_register_provider(p); | ||
195 | |||
196 | pistachio_clk_force_enable(p, pistachio_critical_clks, | ||
197 | ARRAY_SIZE(pistachio_critical_clks)); | ||
198 | } | ||
199 | CLK_OF_DECLARE(pistachio_clk, "img,pistachio-clk", pistachio_clk_init); | ||
200 | |||
201 | static struct pistachio_gate pistachio_periph_gates[] __initdata = { | ||
202 | GATE(PERIPH_CLK_SYS, "sys", "periph_sys", 0x100, 0), | ||
203 | GATE(PERIPH_CLK_SYS_BUS, "bus_sys", "periph_sys", 0x100, 1), | ||
204 | GATE(PERIPH_CLK_DDR, "ddr", "periph_sys", 0x100, 2), | ||
205 | GATE(PERIPH_CLK_ROM, "rom", "rom_div", 0x100, 3), | ||
206 | GATE(PERIPH_CLK_COUNTER_FAST, "counter_fast", "counter_fast_div", | ||
207 | 0x100, 4), | ||
208 | GATE(PERIPH_CLK_COUNTER_SLOW, "counter_slow", "counter_slow_div", | ||
209 | 0x100, 5), | ||
210 | GATE(PERIPH_CLK_IR, "ir", "ir_div", 0x100, 6), | ||
211 | GATE(PERIPH_CLK_WD, "wd", "wd_div", 0x100, 7), | ||
212 | GATE(PERIPH_CLK_PDM, "pdm", "pdm_div", 0x100, 8), | ||
213 | GATE(PERIPH_CLK_PWM, "pwm", "pwm_div", 0x100, 9), | ||
214 | GATE(PERIPH_CLK_I2C0, "i2c0", "i2c0_div", 0x100, 10), | ||
215 | GATE(PERIPH_CLK_I2C1, "i2c1", "i2c1_div", 0x100, 11), | ||
216 | GATE(PERIPH_CLK_I2C2, "i2c2", "i2c2_div", 0x100, 12), | ||
217 | GATE(PERIPH_CLK_I2C3, "i2c3", "i2c3_div", 0x100, 13), | ||
218 | }; | ||
219 | |||
220 | static struct pistachio_div pistachio_periph_divs[] __initdata = { | ||
221 | DIV(PERIPH_CLK_ROM_DIV, "rom_div", "periph_sys", 0x10c, 7), | ||
222 | DIV(PERIPH_CLK_COUNTER_FAST_DIV, "counter_fast_div", "periph_sys", | ||
223 | 0x110, 7), | ||
224 | DIV(PERIPH_CLK_COUNTER_SLOW_PRE_DIV, "counter_slow_pre_div", | ||
225 | "periph_sys", 0x114, 7), | ||
226 | DIV(PERIPH_CLK_COUNTER_SLOW_DIV, "counter_slow_div", | ||
227 | "counter_slow_pre_div", 0x118, 7), | ||
228 | DIV_F(PERIPH_CLK_IR_PRE_DIV, "ir_pre_div", "periph_sys", 0x11c, 7, | ||
229 | CLK_DIVIDER_ROUND_CLOSEST), | ||
230 | DIV_F(PERIPH_CLK_IR_DIV, "ir_div", "ir_pre_div", 0x120, 7, | ||
231 | CLK_DIVIDER_ROUND_CLOSEST), | ||
232 | DIV_F(PERIPH_CLK_WD_PRE_DIV, "wd_pre_div", "periph_sys", 0x124, 7, | ||
233 | CLK_DIVIDER_ROUND_CLOSEST), | ||
234 | DIV_F(PERIPH_CLK_WD_DIV, "wd_div", "wd_pre_div", 0x128, 7, | ||
235 | CLK_DIVIDER_ROUND_CLOSEST), | ||
236 | DIV(PERIPH_CLK_PDM_PRE_DIV, "pdm_pre_div", "periph_sys", 0x12c, 7), | ||
237 | DIV(PERIPH_CLK_PDM_DIV, "pdm_div", "pdm_pre_div", 0x130, 7), | ||
238 | DIV(PERIPH_CLK_PWM_PRE_DIV, "pwm_pre_div", "periph_sys", 0x134, 7), | ||
239 | DIV(PERIPH_CLK_PWM_DIV, "pwm_div", "pwm_pre_div", 0x138, 7), | ||
240 | DIV(PERIPH_CLK_I2C0_PRE_DIV, "i2c0_pre_div", "periph_sys", 0x13c, 7), | ||
241 | DIV(PERIPH_CLK_I2C0_DIV, "i2c0_div", "i2c0_pre_div", 0x140, 7), | ||
242 | DIV(PERIPH_CLK_I2C1_PRE_DIV, "i2c1_pre_div", "periph_sys", 0x144, 7), | ||
243 | DIV(PERIPH_CLK_I2C1_DIV, "i2c1_div", "i2c1_pre_div", 0x148, 7), | ||
244 | DIV(PERIPH_CLK_I2C2_PRE_DIV, "i2c2_pre_div", "periph_sys", 0x14c, 7), | ||
245 | DIV(PERIPH_CLK_I2C2_DIV, "i2c2_div", "i2c2_pre_div", 0x150, 7), | ||
246 | DIV(PERIPH_CLK_I2C3_PRE_DIV, "i2c3_pre_div", "periph_sys", 0x154, 7), | ||
247 | DIV(PERIPH_CLK_I2C3_DIV, "i2c3_div", "i2c3_pre_div", 0x158, 7), | ||
248 | }; | ||
249 | |||
250 | static void __init pistachio_clk_periph_init(struct device_node *np) | ||
251 | { | ||
252 | struct pistachio_clk_provider *p; | ||
253 | |||
254 | p = pistachio_clk_alloc_provider(np, PERIPH_CLK_NR_CLKS); | ||
255 | if (!p) | ||
256 | return; | ||
257 | |||
258 | pistachio_clk_register_div(p, pistachio_periph_divs, | ||
259 | ARRAY_SIZE(pistachio_periph_divs)); | ||
260 | pistachio_clk_register_gate(p, pistachio_periph_gates, | ||
261 | ARRAY_SIZE(pistachio_periph_gates)); | ||
262 | |||
263 | pistachio_clk_register_provider(p); | ||
264 | } | ||
265 | CLK_OF_DECLARE(pistachio_clk_periph, "img,pistachio-clk-periph", | ||
266 | pistachio_clk_periph_init); | ||
267 | |||
268 | static struct pistachio_gate pistachio_sys_gates[] __initdata = { | ||
269 | GATE(SYS_CLK_I2C0, "i2c0_sys", "sys", 0x8, 0), | ||
270 | GATE(SYS_CLK_I2C1, "i2c1_sys", "sys", 0x8, 1), | ||
271 | GATE(SYS_CLK_I2C2, "i2c2_sys", "sys", 0x8, 2), | ||
272 | GATE(SYS_CLK_I2C3, "i2c3_sys", "sys", 0x8, 3), | ||
273 | GATE(SYS_CLK_I2S_IN, "i2s_in_sys", "sys", 0x8, 4), | ||
274 | GATE(SYS_CLK_PAUD_OUT, "paud_out_sys", "sys", 0x8, 5), | ||
275 | GATE(SYS_CLK_SPDIF_OUT, "spdif_out_sys", "sys", 0x8, 6), | ||
276 | GATE(SYS_CLK_SPI0_MASTER, "spi0_master_sys", "sys", 0x8, 7), | ||
277 | GATE(SYS_CLK_SPI0_SLAVE, "spi0_slave_sys", "sys", 0x8, 8), | ||
278 | GATE(SYS_CLK_PWM, "pwm_sys", "sys", 0x8, 9), | ||
279 | GATE(SYS_CLK_UART0, "uart0_sys", "sys", 0x8, 10), | ||
280 | GATE(SYS_CLK_UART1, "uart1_sys", "sys", 0x8, 11), | ||
281 | GATE(SYS_CLK_SPI1, "spi1_sys", "sys", 0x8, 12), | ||
282 | GATE(SYS_CLK_MDC, "mdc_sys", "sys", 0x8, 13), | ||
283 | GATE(SYS_CLK_SD_HOST, "sd_host_sys", "sys", 0x8, 14), | ||
284 | GATE(SYS_CLK_ENET, "enet_sys", "sys", 0x8, 15), | ||
285 | GATE(SYS_CLK_IR, "ir_sys", "sys", 0x8, 16), | ||
286 | GATE(SYS_CLK_WD, "wd_sys", "sys", 0x8, 17), | ||
287 | GATE(SYS_CLK_TIMER, "timer_sys", "sys", 0x8, 18), | ||
288 | GATE(SYS_CLK_I2S_OUT, "i2s_out_sys", "sys", 0x8, 24), | ||
289 | GATE(SYS_CLK_SPDIF_IN, "spdif_in_sys", "sys", 0x8, 25), | ||
290 | GATE(SYS_CLK_EVENT_TIMER, "event_timer_sys", "sys", 0x8, 26), | ||
291 | GATE(SYS_CLK_HASH, "hash_sys", "sys", 0x8, 27), | ||
292 | }; | ||
293 | |||
294 | static void __init pistachio_cr_periph_init(struct device_node *np) | ||
295 | { | ||
296 | struct pistachio_clk_provider *p; | ||
297 | |||
298 | p = pistachio_clk_alloc_provider(np, SYS_CLK_NR_CLKS); | ||
299 | if (!p) | ||
300 | return; | ||
301 | |||
302 | pistachio_clk_register_gate(p, pistachio_sys_gates, | ||
303 | ARRAY_SIZE(pistachio_sys_gates)); | ||
304 | |||
305 | pistachio_clk_register_provider(p); | ||
306 | } | ||
307 | CLK_OF_DECLARE(pistachio_cr_periph, "img,pistachio-cr-periph", | ||
308 | pistachio_cr_periph_init); | ||
309 | |||
310 | static struct pistachio_gate pistachio_ext_gates[] __initdata = { | ||
311 | GATE(EXT_CLK_ENET_IN, "enet_clk_in_gate", "enet_clk_in", 0x58, 5), | ||
312 | GATE(EXT_CLK_AUDIO_IN, "audio_clk_in_gate", "audio_clk_in", 0x58, 8) | ||
313 | }; | ||
314 | |||
315 | static void __init pistachio_cr_top_init(struct device_node *np) | ||
316 | { | ||
317 | struct pistachio_clk_provider *p; | ||
318 | |||
319 | p = pistachio_clk_alloc_provider(np, EXT_CLK_NR_CLKS); | ||
320 | if (!p) | ||
321 | return; | ||
322 | |||
323 | pistachio_clk_register_gate(p, pistachio_ext_gates, | ||
324 | ARRAY_SIZE(pistachio_ext_gates)); | ||
325 | |||
326 | pistachio_clk_register_provider(p); | ||
327 | } | ||
328 | CLK_OF_DECLARE(pistachio_cr_top, "img,pistachio-cr-top", | ||
329 | pistachio_cr_top_init); | ||
diff --git a/drivers/clk/pistachio/clk-pll.c b/drivers/clk/pistachio/clk-pll.c new file mode 100644 index 000000000000..de537560bf70 --- /dev/null +++ b/drivers/clk/pistachio/clk-pll.c | |||
@@ -0,0 +1,401 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Google, Inc. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/clk-provider.h> | ||
10 | #include <linux/io.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/slab.h> | ||
13 | |||
14 | #include "clk.h" | ||
15 | |||
16 | #define PLL_STATUS 0x0 | ||
17 | #define PLL_STATUS_LOCK BIT(0) | ||
18 | |||
19 | #define PLL_CTRL1 0x4 | ||
20 | #define PLL_CTRL1_REFDIV_SHIFT 0 | ||
21 | #define PLL_CTRL1_REFDIV_MASK 0x3f | ||
22 | #define PLL_CTRL1_FBDIV_SHIFT 6 | ||
23 | #define PLL_CTRL1_FBDIV_MASK 0xfff | ||
24 | #define PLL_INT_CTRL1_POSTDIV1_SHIFT 18 | ||
25 | #define PLL_INT_CTRL1_POSTDIV1_MASK 0x7 | ||
26 | #define PLL_INT_CTRL1_POSTDIV2_SHIFT 21 | ||
27 | #define PLL_INT_CTRL1_POSTDIV2_MASK 0x7 | ||
28 | #define PLL_INT_CTRL1_PD BIT(24) | ||
29 | #define PLL_INT_CTRL1_DSMPD BIT(25) | ||
30 | #define PLL_INT_CTRL1_FOUTPOSTDIVPD BIT(26) | ||
31 | #define PLL_INT_CTRL1_FOUTVCOPD BIT(27) | ||
32 | |||
33 | #define PLL_CTRL2 0x8 | ||
34 | #define PLL_FRAC_CTRL2_FRAC_SHIFT 0 | ||
35 | #define PLL_FRAC_CTRL2_FRAC_MASK 0xffffff | ||
36 | #define PLL_FRAC_CTRL2_POSTDIV1_SHIFT 24 | ||
37 | #define PLL_FRAC_CTRL2_POSTDIV1_MASK 0x7 | ||
38 | #define PLL_FRAC_CTRL2_POSTDIV2_SHIFT 27 | ||
39 | #define PLL_FRAC_CTRL2_POSTDIV2_MASK 0x7 | ||
40 | #define PLL_INT_CTRL2_BYPASS BIT(28) | ||
41 | |||
42 | #define PLL_CTRL3 0xc | ||
43 | #define PLL_FRAC_CTRL3_PD BIT(0) | ||
44 | #define PLL_FRAC_CTRL3_DACPD BIT(1) | ||
45 | #define PLL_FRAC_CTRL3_DSMPD BIT(2) | ||
46 | #define PLL_FRAC_CTRL3_FOUTPOSTDIVPD BIT(3) | ||
47 | #define PLL_FRAC_CTRL3_FOUT4PHASEPD BIT(4) | ||
48 | #define PLL_FRAC_CTRL3_FOUTVCOPD BIT(5) | ||
49 | |||
50 | #define PLL_CTRL4 0x10 | ||
51 | #define PLL_FRAC_CTRL4_BYPASS BIT(28) | ||
52 | |||
53 | struct pistachio_clk_pll { | ||
54 | struct clk_hw hw; | ||
55 | void __iomem *base; | ||
56 | struct pistachio_pll_rate_table *rates; | ||
57 | unsigned int nr_rates; | ||
58 | }; | ||
59 | |||
60 | static inline u32 pll_readl(struct pistachio_clk_pll *pll, u32 reg) | ||
61 | { | ||
62 | return readl(pll->base + reg); | ||
63 | } | ||
64 | |||
65 | static inline void pll_writel(struct pistachio_clk_pll *pll, u32 val, u32 reg) | ||
66 | { | ||
67 | writel(val, pll->base + reg); | ||
68 | } | ||
69 | |||
70 | static inline u32 do_div_round_closest(u64 dividend, u32 divisor) | ||
71 | { | ||
72 | dividend += divisor / 2; | ||
73 | do_div(dividend, divisor); | ||
74 | |||
75 | return dividend; | ||
76 | } | ||
77 | |||
78 | static inline struct pistachio_clk_pll *to_pistachio_pll(struct clk_hw *hw) | ||
79 | { | ||
80 | return container_of(hw, struct pistachio_clk_pll, hw); | ||
81 | } | ||
82 | |||
83 | static struct pistachio_pll_rate_table * | ||
84 | pll_get_params(struct pistachio_clk_pll *pll, unsigned long fref, | ||
85 | unsigned long fout) | ||
86 | { | ||
87 | unsigned int i; | ||
88 | |||
89 | for (i = 0; i < pll->nr_rates; i++) { | ||
90 | if (pll->rates[i].fref == fref && pll->rates[i].fout == fout) | ||
91 | return &pll->rates[i]; | ||
92 | } | ||
93 | |||
94 | return NULL; | ||
95 | } | ||
96 | |||
97 | static long pll_round_rate(struct clk_hw *hw, unsigned long rate, | ||
98 | unsigned long *parent_rate) | ||
99 | { | ||
100 | struct pistachio_clk_pll *pll = to_pistachio_pll(hw); | ||
101 | unsigned int i; | ||
102 | |||
103 | for (i = 0; i < pll->nr_rates; i++) { | ||
104 | if (i > 0 && pll->rates[i].fref == *parent_rate && | ||
105 | pll->rates[i].fout <= rate) | ||
106 | return pll->rates[i - 1].fout; | ||
107 | } | ||
108 | |||
109 | return pll->rates[0].fout; | ||
110 | } | ||
111 | |||
112 | static int pll_gf40lp_frac_enable(struct clk_hw *hw) | ||
113 | { | ||
114 | struct pistachio_clk_pll *pll = to_pistachio_pll(hw); | ||
115 | u32 val; | ||
116 | |||
117 | val = pll_readl(pll, PLL_CTRL3); | ||
118 | val &= ~(PLL_FRAC_CTRL3_PD | PLL_FRAC_CTRL3_DACPD | | ||
119 | PLL_FRAC_CTRL3_DSMPD | PLL_FRAC_CTRL3_FOUTPOSTDIVPD | | ||
120 | PLL_FRAC_CTRL3_FOUT4PHASEPD | PLL_FRAC_CTRL3_FOUTVCOPD); | ||
121 | pll_writel(pll, val, PLL_CTRL3); | ||
122 | |||
123 | val = pll_readl(pll, PLL_CTRL4); | ||
124 | val &= ~PLL_FRAC_CTRL4_BYPASS; | ||
125 | pll_writel(pll, val, PLL_CTRL4); | ||
126 | |||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | static void pll_gf40lp_frac_disable(struct clk_hw *hw) | ||
131 | { | ||
132 | struct pistachio_clk_pll *pll = to_pistachio_pll(hw); | ||
133 | u32 val; | ||
134 | |||
135 | val = pll_readl(pll, PLL_CTRL3); | ||
136 | val |= PLL_FRAC_CTRL3_PD; | ||
137 | pll_writel(pll, val, PLL_CTRL3); | ||
138 | } | ||
139 | |||
140 | static int pll_gf40lp_frac_is_enabled(struct clk_hw *hw) | ||
141 | { | ||
142 | struct pistachio_clk_pll *pll = to_pistachio_pll(hw); | ||
143 | |||
144 | return !(pll_readl(pll, PLL_CTRL3) & PLL_FRAC_CTRL3_PD); | ||
145 | } | ||
146 | |||
147 | static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate, | ||
148 | unsigned long parent_rate) | ||
149 | { | ||
150 | struct pistachio_clk_pll *pll = to_pistachio_pll(hw); | ||
151 | struct pistachio_pll_rate_table *params; | ||
152 | bool was_enabled; | ||
153 | u32 val; | ||
154 | |||
155 | params = pll_get_params(pll, parent_rate, rate); | ||
156 | if (!params) | ||
157 | return -EINVAL; | ||
158 | |||
159 | was_enabled = pll_gf40lp_frac_is_enabled(hw); | ||
160 | if (!was_enabled) | ||
161 | pll_gf40lp_frac_enable(hw); | ||
162 | |||
163 | val = pll_readl(pll, PLL_CTRL1); | ||
164 | val &= ~((PLL_CTRL1_REFDIV_MASK << PLL_CTRL1_REFDIV_SHIFT) | | ||
165 | (PLL_CTRL1_FBDIV_MASK << PLL_CTRL1_FBDIV_SHIFT)); | ||
166 | val |= (params->refdiv << PLL_CTRL1_REFDIV_SHIFT) | | ||
167 | (params->fbdiv << PLL_CTRL1_FBDIV_SHIFT); | ||
168 | pll_writel(pll, val, PLL_CTRL1); | ||
169 | |||
170 | val = pll_readl(pll, PLL_CTRL2); | ||
171 | val &= ~((PLL_FRAC_CTRL2_FRAC_MASK << PLL_FRAC_CTRL2_FRAC_SHIFT) | | ||
172 | (PLL_FRAC_CTRL2_POSTDIV1_MASK << | ||
173 | PLL_FRAC_CTRL2_POSTDIV1_SHIFT) | | ||
174 | (PLL_FRAC_CTRL2_POSTDIV2_MASK << | ||
175 | PLL_FRAC_CTRL2_POSTDIV2_SHIFT)); | ||
176 | val |= (params->frac << PLL_FRAC_CTRL2_FRAC_SHIFT) | | ||
177 | (params->postdiv1 << PLL_FRAC_CTRL2_POSTDIV1_SHIFT) | | ||
178 | (params->postdiv2 << PLL_FRAC_CTRL2_POSTDIV2_SHIFT); | ||
179 | pll_writel(pll, val, PLL_CTRL2); | ||
180 | |||
181 | while (!(pll_readl(pll, PLL_STATUS) & PLL_STATUS_LOCK)) | ||
182 | cpu_relax(); | ||
183 | |||
184 | if (!was_enabled) | ||
185 | pll_gf40lp_frac_disable(hw); | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static unsigned long pll_gf40lp_frac_recalc_rate(struct clk_hw *hw, | ||
191 | unsigned long parent_rate) | ||
192 | { | ||
193 | struct pistachio_clk_pll *pll = to_pistachio_pll(hw); | ||
194 | u32 val, prediv, fbdiv, frac, postdiv1, postdiv2; | ||
195 | u64 rate = parent_rate; | ||
196 | |||
197 | val = pll_readl(pll, PLL_CTRL1); | ||
198 | prediv = (val >> PLL_CTRL1_REFDIV_SHIFT) & PLL_CTRL1_REFDIV_MASK; | ||
199 | fbdiv = (val >> PLL_CTRL1_FBDIV_SHIFT) & PLL_CTRL1_FBDIV_MASK; | ||
200 | |||
201 | val = pll_readl(pll, PLL_CTRL2); | ||
202 | postdiv1 = (val >> PLL_FRAC_CTRL2_POSTDIV1_SHIFT) & | ||
203 | PLL_FRAC_CTRL2_POSTDIV1_MASK; | ||
204 | postdiv2 = (val >> PLL_FRAC_CTRL2_POSTDIV2_SHIFT) & | ||
205 | PLL_FRAC_CTRL2_POSTDIV2_MASK; | ||
206 | frac = (val >> PLL_FRAC_CTRL2_FRAC_SHIFT) & PLL_FRAC_CTRL2_FRAC_MASK; | ||
207 | |||
208 | rate *= (fbdiv << 24) + frac; | ||
209 | rate = do_div_round_closest(rate, (prediv * postdiv1 * postdiv2) << 24); | ||
210 | |||
211 | return rate; | ||
212 | } | ||
213 | |||
214 | static struct clk_ops pll_gf40lp_frac_ops = { | ||
215 | .enable = pll_gf40lp_frac_enable, | ||
216 | .disable = pll_gf40lp_frac_disable, | ||
217 | .is_enabled = pll_gf40lp_frac_is_enabled, | ||
218 | .recalc_rate = pll_gf40lp_frac_recalc_rate, | ||
219 | .round_rate = pll_round_rate, | ||
220 | .set_rate = pll_gf40lp_frac_set_rate, | ||
221 | }; | ||
222 | |||
223 | static struct clk_ops pll_gf40lp_frac_fixed_ops = { | ||
224 | .enable = pll_gf40lp_frac_enable, | ||
225 | .disable = pll_gf40lp_frac_disable, | ||
226 | .is_enabled = pll_gf40lp_frac_is_enabled, | ||
227 | .recalc_rate = pll_gf40lp_frac_recalc_rate, | ||
228 | }; | ||
229 | |||
230 | static int pll_gf40lp_laint_enable(struct clk_hw *hw) | ||
231 | { | ||
232 | struct pistachio_clk_pll *pll = to_pistachio_pll(hw); | ||
233 | u32 val; | ||
234 | |||
235 | val = pll_readl(pll, PLL_CTRL1); | ||
236 | val &= ~(PLL_INT_CTRL1_PD | PLL_INT_CTRL1_DSMPD | | ||
237 | PLL_INT_CTRL1_FOUTPOSTDIVPD | PLL_INT_CTRL1_FOUTVCOPD); | ||
238 | pll_writel(pll, val, PLL_CTRL1); | ||
239 | |||
240 | val = pll_readl(pll, PLL_CTRL2); | ||
241 | val &= ~PLL_INT_CTRL2_BYPASS; | ||
242 | pll_writel(pll, val, PLL_CTRL2); | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static void pll_gf40lp_laint_disable(struct clk_hw *hw) | ||
248 | { | ||
249 | struct pistachio_clk_pll *pll = to_pistachio_pll(hw); | ||
250 | u32 val; | ||
251 | |||
252 | val = pll_readl(pll, PLL_CTRL1); | ||
253 | val |= PLL_INT_CTRL1_PD; | ||
254 | pll_writel(pll, val, PLL_CTRL1); | ||
255 | } | ||
256 | |||
257 | static int pll_gf40lp_laint_is_enabled(struct clk_hw *hw) | ||
258 | { | ||
259 | struct pistachio_clk_pll *pll = to_pistachio_pll(hw); | ||
260 | |||
261 | return !(pll_readl(pll, PLL_CTRL1) & PLL_INT_CTRL1_PD); | ||
262 | } | ||
263 | |||
264 | static int pll_gf40lp_laint_set_rate(struct clk_hw *hw, unsigned long rate, | ||
265 | unsigned long parent_rate) | ||
266 | { | ||
267 | struct pistachio_clk_pll *pll = to_pistachio_pll(hw); | ||
268 | struct pistachio_pll_rate_table *params; | ||
269 | bool was_enabled; | ||
270 | u32 val; | ||
271 | |||
272 | params = pll_get_params(pll, parent_rate, rate); | ||
273 | if (!params) | ||
274 | return -EINVAL; | ||
275 | |||
276 | was_enabled = pll_gf40lp_laint_is_enabled(hw); | ||
277 | if (!was_enabled) | ||
278 | pll_gf40lp_laint_enable(hw); | ||
279 | |||
280 | val = pll_readl(pll, PLL_CTRL1); | ||
281 | val &= ~((PLL_CTRL1_REFDIV_MASK << PLL_CTRL1_REFDIV_SHIFT) | | ||
282 | (PLL_CTRL1_FBDIV_MASK << PLL_CTRL1_FBDIV_SHIFT) | | ||
283 | (PLL_INT_CTRL1_POSTDIV1_MASK << PLL_INT_CTRL1_POSTDIV1_SHIFT) | | ||
284 | (PLL_INT_CTRL1_POSTDIV2_MASK << PLL_INT_CTRL1_POSTDIV2_SHIFT)); | ||
285 | val |= (params->refdiv << PLL_CTRL1_REFDIV_SHIFT) | | ||
286 | (params->fbdiv << PLL_CTRL1_FBDIV_SHIFT) | | ||
287 | (params->postdiv1 << PLL_INT_CTRL1_POSTDIV1_SHIFT) | | ||
288 | (params->postdiv2 << PLL_INT_CTRL1_POSTDIV2_SHIFT); | ||
289 | pll_writel(pll, val, PLL_CTRL1); | ||
290 | |||
291 | while (!(pll_readl(pll, PLL_STATUS) & PLL_STATUS_LOCK)) | ||
292 | cpu_relax(); | ||
293 | |||
294 | if (!was_enabled) | ||
295 | pll_gf40lp_laint_disable(hw); | ||
296 | |||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static unsigned long pll_gf40lp_laint_recalc_rate(struct clk_hw *hw, | ||
301 | unsigned long parent_rate) | ||
302 | { | ||
303 | struct pistachio_clk_pll *pll = to_pistachio_pll(hw); | ||
304 | u32 val, prediv, fbdiv, postdiv1, postdiv2; | ||
305 | u64 rate = parent_rate; | ||
306 | |||
307 | val = pll_readl(pll, PLL_CTRL1); | ||
308 | prediv = (val >> PLL_CTRL1_REFDIV_SHIFT) & PLL_CTRL1_REFDIV_MASK; | ||
309 | fbdiv = (val >> PLL_CTRL1_FBDIV_SHIFT) & PLL_CTRL1_FBDIV_MASK; | ||
310 | postdiv1 = (val >> PLL_INT_CTRL1_POSTDIV1_SHIFT) & | ||
311 | PLL_INT_CTRL1_POSTDIV1_MASK; | ||
312 | postdiv2 = (val >> PLL_INT_CTRL1_POSTDIV2_SHIFT) & | ||
313 | PLL_INT_CTRL1_POSTDIV2_MASK; | ||
314 | |||
315 | rate *= fbdiv; | ||
316 | rate = do_div_round_closest(rate, prediv * postdiv1 * postdiv2); | ||
317 | |||
318 | return rate; | ||
319 | } | ||
320 | |||
321 | static struct clk_ops pll_gf40lp_laint_ops = { | ||
322 | .enable = pll_gf40lp_laint_enable, | ||
323 | .disable = pll_gf40lp_laint_disable, | ||
324 | .is_enabled = pll_gf40lp_laint_is_enabled, | ||
325 | .recalc_rate = pll_gf40lp_laint_recalc_rate, | ||
326 | .round_rate = pll_round_rate, | ||
327 | .set_rate = pll_gf40lp_laint_set_rate, | ||
328 | }; | ||
329 | |||
330 | static struct clk_ops pll_gf40lp_laint_fixed_ops = { | ||
331 | .enable = pll_gf40lp_laint_enable, | ||
332 | .disable = pll_gf40lp_laint_disable, | ||
333 | .is_enabled = pll_gf40lp_laint_is_enabled, | ||
334 | .recalc_rate = pll_gf40lp_laint_recalc_rate, | ||
335 | }; | ||
336 | |||
337 | static struct clk *pll_register(const char *name, const char *parent_name, | ||
338 | unsigned long flags, void __iomem *base, | ||
339 | enum pistachio_pll_type type, | ||
340 | struct pistachio_pll_rate_table *rates, | ||
341 | unsigned int nr_rates) | ||
342 | { | ||
343 | struct pistachio_clk_pll *pll; | ||
344 | struct clk_init_data init; | ||
345 | struct clk *clk; | ||
346 | |||
347 | pll = kzalloc(sizeof(*pll), GFP_KERNEL); | ||
348 | if (!pll) | ||
349 | return ERR_PTR(-ENOMEM); | ||
350 | |||
351 | init.name = name; | ||
352 | init.flags = flags | CLK_GET_RATE_NOCACHE; | ||
353 | init.parent_names = &parent_name; | ||
354 | init.num_parents = 1; | ||
355 | |||
356 | switch (type) { | ||
357 | case PLL_GF40LP_FRAC: | ||
358 | if (rates) | ||
359 | init.ops = &pll_gf40lp_frac_ops; | ||
360 | else | ||
361 | init.ops = &pll_gf40lp_frac_fixed_ops; | ||
362 | break; | ||
363 | case PLL_GF40LP_LAINT: | ||
364 | if (rates) | ||
365 | init.ops = &pll_gf40lp_laint_ops; | ||
366 | else | ||
367 | init.ops = &pll_gf40lp_laint_fixed_ops; | ||
368 | break; | ||
369 | default: | ||
370 | pr_err("Unrecognized PLL type %u\n", type); | ||
371 | kfree(pll); | ||
372 | return ERR_PTR(-EINVAL); | ||
373 | } | ||
374 | |||
375 | pll->hw.init = &init; | ||
376 | pll->base = base; | ||
377 | pll->rates = rates; | ||
378 | pll->nr_rates = nr_rates; | ||
379 | |||
380 | clk = clk_register(NULL, &pll->hw); | ||
381 | if (IS_ERR(clk)) | ||
382 | kfree(pll); | ||
383 | |||
384 | return clk; | ||
385 | } | ||
386 | |||
387 | void pistachio_clk_register_pll(struct pistachio_clk_provider *p, | ||
388 | struct pistachio_pll *pll, | ||
389 | unsigned int num) | ||
390 | { | ||
391 | struct clk *clk; | ||
392 | unsigned int i; | ||
393 | |||
394 | for (i = 0; i < num; i++) { | ||
395 | clk = pll_register(pll[i].name, pll[i].parent, | ||
396 | 0, p->base + pll[i].reg_base, | ||
397 | pll[i].type, pll[i].rates, | ||
398 | pll[i].nr_rates); | ||
399 | p->clk_data.clks[pll[i].id] = clk; | ||
400 | } | ||
401 | } | ||
diff --git a/drivers/clk/pistachio/clk.c b/drivers/clk/pistachio/clk.c new file mode 100644 index 000000000000..85faa83e1bd7 --- /dev/null +++ b/drivers/clk/pistachio/clk.c | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Google, Inc. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/clk-provider.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/of.h> | ||
12 | #include <linux/of_address.h> | ||
13 | #include <linux/slab.h> | ||
14 | |||
15 | #include "clk.h" | ||
16 | |||
17 | struct pistachio_clk_provider * | ||
18 | pistachio_clk_alloc_provider(struct device_node *node, unsigned int num_clks) | ||
19 | { | ||
20 | struct pistachio_clk_provider *p; | ||
21 | |||
22 | p = kzalloc(sizeof(*p), GFP_KERNEL); | ||
23 | if (!p) | ||
24 | return p; | ||
25 | |||
26 | p->clk_data.clks = kcalloc(num_clks, sizeof(struct clk *), GFP_KERNEL); | ||
27 | if (!p->clk_data.clks) | ||
28 | goto free_provider; | ||
29 | p->clk_data.clk_num = num_clks; | ||
30 | p->node = node; | ||
31 | p->base = of_iomap(node, 0); | ||
32 | if (!p->base) { | ||
33 | pr_err("Failed to map clock provider registers\n"); | ||
34 | goto free_clks; | ||
35 | } | ||
36 | |||
37 | return p; | ||
38 | |||
39 | free_clks: | ||
40 | kfree(p->clk_data.clks); | ||
41 | free_provider: | ||
42 | kfree(p); | ||
43 | return NULL; | ||
44 | } | ||
45 | |||
46 | void pistachio_clk_register_provider(struct pistachio_clk_provider *p) | ||
47 | { | ||
48 | unsigned int i; | ||
49 | |||
50 | for (i = 0; i < p->clk_data.clk_num; i++) { | ||
51 | if (IS_ERR(p->clk_data.clks[i])) | ||
52 | pr_warn("Failed to register clock %d: %ld\n", i, | ||
53 | PTR_ERR(p->clk_data.clks[i])); | ||
54 | } | ||
55 | |||
56 | of_clk_add_provider(p->node, of_clk_src_onecell_get, &p->clk_data); | ||
57 | } | ||
58 | |||
59 | void pistachio_clk_register_gate(struct pistachio_clk_provider *p, | ||
60 | struct pistachio_gate *gate, | ||
61 | unsigned int num) | ||
62 | { | ||
63 | struct clk *clk; | ||
64 | unsigned int i; | ||
65 | |||
66 | for (i = 0; i < num; i++) { | ||
67 | clk = clk_register_gate(NULL, gate[i].name, gate[i].parent, | ||
68 | CLK_SET_RATE_PARENT, | ||
69 | p->base + gate[i].reg, gate[i].shift, | ||
70 | 0, NULL); | ||
71 | p->clk_data.clks[gate[i].id] = clk; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | void pistachio_clk_register_mux(struct pistachio_clk_provider *p, | ||
76 | struct pistachio_mux *mux, | ||
77 | unsigned int num) | ||
78 | { | ||
79 | struct clk *clk; | ||
80 | unsigned int i; | ||
81 | |||
82 | for (i = 0; i < num; i++) { | ||
83 | clk = clk_register_mux(NULL, mux[i].name, mux[i].parents, | ||
84 | mux[i].num_parents, | ||
85 | CLK_SET_RATE_NO_REPARENT, | ||
86 | p->base + mux[i].reg, mux[i].shift, | ||
87 | get_count_order(mux[i].num_parents), | ||
88 | 0, NULL); | ||
89 | p->clk_data.clks[mux[i].id] = clk; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | void pistachio_clk_register_div(struct pistachio_clk_provider *p, | ||
94 | struct pistachio_div *div, | ||
95 | unsigned int num) | ||
96 | { | ||
97 | struct clk *clk; | ||
98 | unsigned int i; | ||
99 | |||
100 | for (i = 0; i < num; i++) { | ||
101 | clk = clk_register_divider(NULL, div[i].name, div[i].parent, | ||
102 | 0, p->base + div[i].reg, 0, | ||
103 | div[i].width, div[i].div_flags, | ||
104 | NULL); | ||
105 | p->clk_data.clks[div[i].id] = clk; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | void pistachio_clk_register_fixed_factor(struct pistachio_clk_provider *p, | ||
110 | struct pistachio_fixed_factor *ff, | ||
111 | unsigned int num) | ||
112 | { | ||
113 | struct clk *clk; | ||
114 | unsigned int i; | ||
115 | |||
116 | for (i = 0; i < num; i++) { | ||
117 | clk = clk_register_fixed_factor(NULL, ff[i].name, ff[i].parent, | ||
118 | 0, 1, ff[i].div); | ||
119 | p->clk_data.clks[ff[i].id] = clk; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | void pistachio_clk_force_enable(struct pistachio_clk_provider *p, | ||
124 | unsigned int *clk_ids, unsigned int num) | ||
125 | { | ||
126 | unsigned int i; | ||
127 | int err; | ||
128 | |||
129 | for (i = 0; i < num; i++) { | ||
130 | struct clk *clk = p->clk_data.clks[clk_ids[i]]; | ||
131 | |||
132 | if (IS_ERR(clk)) | ||
133 | continue; | ||
134 | |||
135 | err = clk_prepare_enable(clk); | ||
136 | if (err) | ||
137 | pr_err("Failed to enable clock %s: %d\n", | ||
138 | __clk_get_name(clk), err); | ||
139 | } | ||
140 | } | ||
diff --git a/drivers/clk/pistachio/clk.h b/drivers/clk/pistachio/clk.h new file mode 100644 index 000000000000..52fabbc24624 --- /dev/null +++ b/drivers/clk/pistachio/clk.h | |||
@@ -0,0 +1,174 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Google, Inc. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef __PISTACHIO_CLK_H | ||
10 | #define __PISTACHIO_CLK_H | ||
11 | |||
12 | #include <linux/clk-provider.h> | ||
13 | |||
14 | struct pistachio_gate { | ||
15 | unsigned int id; | ||
16 | unsigned long reg; | ||
17 | unsigned int shift; | ||
18 | const char *name; | ||
19 | const char *parent; | ||
20 | }; | ||
21 | |||
22 | #define GATE(_id, _name, _pname, _reg, _shift) \ | ||
23 | { \ | ||
24 | .id = _id, \ | ||
25 | .reg = _reg, \ | ||
26 | .shift = _shift, \ | ||
27 | .name = _name, \ | ||
28 | .parent = _pname, \ | ||
29 | } | ||
30 | |||
31 | struct pistachio_mux { | ||
32 | unsigned int id; | ||
33 | unsigned long reg; | ||
34 | unsigned int shift; | ||
35 | unsigned int num_parents; | ||
36 | const char *name; | ||
37 | const char **parents; | ||
38 | }; | ||
39 | |||
40 | #define PNAME(x) static const char *x[] __initconst | ||
41 | |||
42 | #define MUX(_id, _name, _pnames, _reg, _shift) \ | ||
43 | { \ | ||
44 | .id = _id, \ | ||
45 | .reg = _reg, \ | ||
46 | .shift = _shift, \ | ||
47 | .name = _name, \ | ||
48 | .parents = _pnames, \ | ||
49 | .num_parents = ARRAY_SIZE(_pnames) \ | ||
50 | } | ||
51 | |||
52 | |||
53 | struct pistachio_div { | ||
54 | unsigned int id; | ||
55 | unsigned long reg; | ||
56 | unsigned int width; | ||
57 | unsigned int div_flags; | ||
58 | const char *name; | ||
59 | const char *parent; | ||
60 | }; | ||
61 | |||
62 | #define DIV(_id, _name, _pname, _reg, _width) \ | ||
63 | { \ | ||
64 | .id = _id, \ | ||
65 | .reg = _reg, \ | ||
66 | .width = _width, \ | ||
67 | .div_flags = 0, \ | ||
68 | .name = _name, \ | ||
69 | .parent = _pname, \ | ||
70 | } | ||
71 | |||
72 | #define DIV_F(_id, _name, _pname, _reg, _width, _div_flags) \ | ||
73 | { \ | ||
74 | .id = _id, \ | ||
75 | .reg = _reg, \ | ||
76 | .width = _width, \ | ||
77 | .div_flags = _div_flags, \ | ||
78 | .name = _name, \ | ||
79 | .parent = _pname, \ | ||
80 | } | ||
81 | |||
82 | struct pistachio_fixed_factor { | ||
83 | unsigned int id; | ||
84 | unsigned int div; | ||
85 | const char *name; | ||
86 | const char *parent; | ||
87 | }; | ||
88 | |||
89 | #define FIXED_FACTOR(_id, _name, _pname, _div) \ | ||
90 | { \ | ||
91 | .id = _id, \ | ||
92 | .div = _div, \ | ||
93 | .name = _name, \ | ||
94 | .parent = _pname, \ | ||
95 | } | ||
96 | |||
97 | struct pistachio_pll_rate_table { | ||
98 | unsigned long fref; | ||
99 | unsigned long fout; | ||
100 | unsigned int refdiv; | ||
101 | unsigned int fbdiv; | ||
102 | unsigned int postdiv1; | ||
103 | unsigned int postdiv2; | ||
104 | unsigned int frac; | ||
105 | }; | ||
106 | |||
107 | enum pistachio_pll_type { | ||
108 | PLL_GF40LP_LAINT, | ||
109 | PLL_GF40LP_FRAC, | ||
110 | }; | ||
111 | |||
112 | struct pistachio_pll { | ||
113 | unsigned int id; | ||
114 | unsigned long reg_base; | ||
115 | enum pistachio_pll_type type; | ||
116 | struct pistachio_pll_rate_table *rates; | ||
117 | unsigned int nr_rates; | ||
118 | const char *name; | ||
119 | const char *parent; | ||
120 | }; | ||
121 | |||
122 | #define PLL(_id, _name, _pname, _type, _reg, _rates) \ | ||
123 | { \ | ||
124 | .id = _id, \ | ||
125 | .reg_base = _reg, \ | ||
126 | .type = _type, \ | ||
127 | .rates = _rates, \ | ||
128 | .nr_rates = ARRAY_SIZE(_rates), \ | ||
129 | .name = _name, \ | ||
130 | .parent = _pname, \ | ||
131 | } | ||
132 | |||
133 | #define PLL_FIXED(_id, _name, _pname, _type, _reg) \ | ||
134 | { \ | ||
135 | .id = _id, \ | ||
136 | .reg_base = _reg, \ | ||
137 | .type = _type, \ | ||
138 | .rates = NULL, \ | ||
139 | .nr_rates = 0, \ | ||
140 | .name = _name, \ | ||
141 | .parent = _pname, \ | ||
142 | } | ||
143 | |||
144 | struct pistachio_clk_provider { | ||
145 | struct device_node *node; | ||
146 | void __iomem *base; | ||
147 | struct clk_onecell_data clk_data; | ||
148 | }; | ||
149 | |||
150 | extern struct pistachio_clk_provider * | ||
151 | pistachio_clk_alloc_provider(struct device_node *node, unsigned int num_clks); | ||
152 | extern void pistachio_clk_register_provider(struct pistachio_clk_provider *p); | ||
153 | |||
154 | extern void pistachio_clk_register_gate(struct pistachio_clk_provider *p, | ||
155 | struct pistachio_gate *gate, | ||
156 | unsigned int num); | ||
157 | extern void pistachio_clk_register_mux(struct pistachio_clk_provider *p, | ||
158 | struct pistachio_mux *mux, | ||
159 | unsigned int num); | ||
160 | extern void pistachio_clk_register_div(struct pistachio_clk_provider *p, | ||
161 | struct pistachio_div *div, | ||
162 | unsigned int num); | ||
163 | extern void | ||
164 | pistachio_clk_register_fixed_factor(struct pistachio_clk_provider *p, | ||
165 | struct pistachio_fixed_factor *ff, | ||
166 | unsigned int num); | ||
167 | extern void pistachio_clk_register_pll(struct pistachio_clk_provider *p, | ||
168 | struct pistachio_pll *pll, | ||
169 | unsigned int num); | ||
170 | |||
171 | extern void pistachio_clk_force_enable(struct pistachio_clk_provider *p, | ||
172 | unsigned int *clk_ids, unsigned int num); | ||
173 | |||
174 | #endif | ||