2 * mmp2 clock framework source file
4 * Copyright (C) 2012 Marvell
5 * Chao Xie <xiechao.mail@gmail.com>
7 * This file is licensed under the terms of the GNU General Public
8 * License version 2. This program is licensed "as is" without any
9 * warranty of any kind, whether express or implied.
12 #include <linux/module.h>
13 #include <linux/kernel.h>
14 #include <linux/spinlock.h>
16 #include <linux/delay.h>
17 #include <linux/err.h>
18 #include <linux/of_address.h>
20 #include <dt-bindings/clock/marvell,mmp2.h>
26 #define APBC_TWSI0 0x4
27 #define APBC_TWSI1 0x8
28 #define APBC_TWSI2 0xc
29 #define APBC_TWSI3 0x10
30 #define APBC_TWSI4 0x7c
31 #define APBC_TWSI5 0x80
33 #define APBC_TIMER 0x24
34 #define APBC_UART0 0x2c
35 #define APBC_UART1 0x30
36 #define APBC_UART2 0x34
37 #define APBC_UART3 0x88
38 #define APBC_GPIO 0x38
39 #define APBC_PWM0 0x3c
40 #define APBC_PWM1 0x40
41 #define APBC_PWM2 0x44
42 #define APBC_PWM3 0x48
43 #define APBC_SSP0 0x50
44 #define APBC_SSP1 0x54
45 #define APBC_SSP2 0x58
46 #define APBC_SSP3 0x5c
47 #define APMU_SDH0 0x54
48 #define APMU_SDH1 0x58
49 #define APMU_SDH2 0xe8
50 #define APMU_SDH3 0xec
52 #define APMU_DISP0 0x4c
53 #define APMU_DISP1 0x110
54 #define APMU_CCIC0 0x50
55 #define APMU_CCIC1 0xf4
56 #define MPMU_UART_PLL 0x14
58 struct mmp2_clk_unit
{
59 struct mmp_clk_unit unit
;
60 void __iomem
*mpmu_base
;
61 void __iomem
*apmu_base
;
62 void __iomem
*apbc_base
;
65 static struct mmp_param_fixed_rate_clk fixed_rate_clks
[] = {
66 {MMP2_CLK_CLK32
, "clk32", NULL
, CLK_IS_ROOT
, 32768},
67 {MMP2_CLK_VCTCXO
, "vctcxo", NULL
, CLK_IS_ROOT
, 26000000},
68 {MMP2_CLK_PLL1
, "pll1", NULL
, CLK_IS_ROOT
, 800000000},
69 {MMP2_CLK_PLL2
, "pll2", NULL
, CLK_IS_ROOT
, 960000000},
70 {MMP2_CLK_USB_PLL
, "usb_pll", NULL
, CLK_IS_ROOT
, 480000000},
73 static struct mmp_param_fixed_factor_clk fixed_factor_clks
[] = {
74 {MMP2_CLK_PLL1_2
, "pll1_2", "pll1", 1, 2, 0},
75 {MMP2_CLK_PLL1_4
, "pll1_4", "pll1_2", 1, 2, 0},
76 {MMP2_CLK_PLL1_8
, "pll1_8", "pll1_4", 1, 2, 0},
77 {MMP2_CLK_PLL1_16
, "pll1_16", "pll1_8", 1, 2, 0},
78 {MMP2_CLK_PLL1_20
, "pll1_20", "pll1_4", 1, 5, 0},
79 {MMP2_CLK_PLL1_3
, "pll1_3", "pll1", 1, 3, 0},
80 {MMP2_CLK_PLL1_6
, "pll1_6", "pll1_3", 1, 2, 0},
81 {MMP2_CLK_PLL1_12
, "pll1_12", "pll1_6", 1, 2, 0},
82 {MMP2_CLK_PLL2_2
, "pll2_2", "pll2", 1, 2, 0},
83 {MMP2_CLK_PLL2_4
, "pll2_4", "pll2_2", 1, 2, 0},
84 {MMP2_CLK_PLL2_8
, "pll2_8", "pll2_4", 1, 2, 0},
85 {MMP2_CLK_PLL2_16
, "pll2_16", "pll2_8", 1, 2, 0},
86 {MMP2_CLK_PLL2_3
, "pll2_3", "pll2", 1, 3, 0},
87 {MMP2_CLK_PLL2_6
, "pll2_6", "pll2_3", 1, 2, 0},
88 {MMP2_CLK_PLL2_12
, "pll2_12", "pll2_6", 1, 2, 0},
89 {MMP2_CLK_VCTCXO_2
, "vctcxo_2", "vctcxo", 1, 2, 0},
90 {MMP2_CLK_VCTCXO_4
, "vctcxo_4", "vctcxo_2", 1, 2, 0},
93 static struct mmp_clk_factor_masks uart_factor_masks
= {
101 static struct mmp_clk_factor_tbl uart_factor_tbl
[] = {
102 {.num
= 8125, .den
= 1536}, /*14.745MHZ */
103 {.num
= 3521, .den
= 689}, /*19.23MHZ */
106 static void mmp2_pll_init(struct mmp2_clk_unit
*pxa_unit
)
109 struct mmp_clk_unit
*unit
= &pxa_unit
->unit
;
111 mmp_register_fixed_rate_clks(unit
, fixed_rate_clks
,
112 ARRAY_SIZE(fixed_rate_clks
));
114 mmp_register_fixed_factor_clks(unit
, fixed_factor_clks
,
115 ARRAY_SIZE(fixed_factor_clks
));
117 clk
= mmp_clk_register_factor("uart_pll", "pll1_4",
119 pxa_unit
->mpmu_base
+ MPMU_UART_PLL
,
120 &uart_factor_masks
, uart_factor_tbl
,
121 ARRAY_SIZE(uart_factor_tbl
), NULL
);
122 mmp_clk_add(unit
, MMP2_CLK_UART_PLL
, clk
);
125 static DEFINE_SPINLOCK(uart0_lock
);
126 static DEFINE_SPINLOCK(uart1_lock
);
127 static DEFINE_SPINLOCK(uart2_lock
);
128 static const char *uart_parent_names
[] = {"uart_pll", "vctcxo"};
130 static DEFINE_SPINLOCK(ssp0_lock
);
131 static DEFINE_SPINLOCK(ssp1_lock
);
132 static DEFINE_SPINLOCK(ssp2_lock
);
133 static DEFINE_SPINLOCK(ssp3_lock
);
134 static const char *ssp_parent_names
[] = {"vctcxo_4", "vctcxo_2", "vctcxo", "pll1_16"};
136 static DEFINE_SPINLOCK(timer_lock
);
137 static const char *timer_parent_names
[] = {"clk32", "vctcxo_2", "vctcxo_4", "vctcxo"};
139 static DEFINE_SPINLOCK(reset_lock
);
141 static struct mmp_param_mux_clk apbc_mux_clks
[] = {
142 {0, "uart0_mux", uart_parent_names
, ARRAY_SIZE(uart_parent_names
), CLK_SET_RATE_PARENT
, APBC_UART0
, 4, 3, 0, &uart0_lock
},
143 {0, "uart1_mux", uart_parent_names
, ARRAY_SIZE(uart_parent_names
), CLK_SET_RATE_PARENT
, APBC_UART1
, 4, 3, 0, &uart1_lock
},
144 {0, "uart2_mux", uart_parent_names
, ARRAY_SIZE(uart_parent_names
), CLK_SET_RATE_PARENT
, APBC_UART2
, 4, 3, 0, &uart2_lock
},
145 {0, "uart3_mux", uart_parent_names
, ARRAY_SIZE(uart_parent_names
), CLK_SET_RATE_PARENT
, APBC_UART3
, 4, 3, 0, &uart2_lock
},
146 {0, "ssp0_mux", ssp_parent_names
, ARRAY_SIZE(ssp_parent_names
), CLK_SET_RATE_PARENT
, APBC_SSP0
, 4, 3, 0, &ssp0_lock
},
147 {0, "ssp1_mux", ssp_parent_names
, ARRAY_SIZE(ssp_parent_names
), CLK_SET_RATE_PARENT
, APBC_SSP1
, 4, 3, 0, &ssp1_lock
},
148 {0, "ssp2_mux", ssp_parent_names
, ARRAY_SIZE(ssp_parent_names
), CLK_SET_RATE_PARENT
, APBC_SSP2
, 4, 3, 0, &ssp2_lock
},
149 {0, "ssp3_mux", ssp_parent_names
, ARRAY_SIZE(ssp_parent_names
), CLK_SET_RATE_PARENT
, APBC_SSP3
, 4, 3, 0, &ssp3_lock
},
150 {0, "timer_mux", timer_parent_names
, ARRAY_SIZE(timer_parent_names
), CLK_SET_RATE_PARENT
, APBC_TIMER
, 4, 3, 0, &timer_lock
},
153 static struct mmp_param_gate_clk apbc_gate_clks
[] = {
154 {MMP2_CLK_TWSI0
, "twsi0_clk", "vctcxo", CLK_SET_RATE_PARENT
, APBC_TWSI0
, 0x7, 0x3, 0x0, 0, &reset_lock
},
155 {MMP2_CLK_TWSI1
, "twsi1_clk", "vctcxo", CLK_SET_RATE_PARENT
, APBC_TWSI1
, 0x7, 0x3, 0x0, 0, &reset_lock
},
156 {MMP2_CLK_TWSI2
, "twsi2_clk", "vctcxo", CLK_SET_RATE_PARENT
, APBC_TWSI2
, 0x7, 0x3, 0x0, 0, &reset_lock
},
157 {MMP2_CLK_TWSI3
, "twsi3_clk", "vctcxo", CLK_SET_RATE_PARENT
, APBC_TWSI3
, 0x7, 0x3, 0x0, 0, &reset_lock
},
158 {MMP2_CLK_TWSI4
, "twsi4_clk", "vctcxo", CLK_SET_RATE_PARENT
, APBC_TWSI4
, 0x7, 0x3, 0x0, 0, &reset_lock
},
159 {MMP2_CLK_TWSI5
, "twsi5_clk", "vctcxo", CLK_SET_RATE_PARENT
, APBC_TWSI5
, 0x7, 0x3, 0x0, 0, &reset_lock
},
160 {MMP2_CLK_GPIO
, "gpio_clk", "vctcxo", CLK_SET_RATE_PARENT
, APBC_GPIO
, 0x7, 0x3, 0x0, 0, &reset_lock
},
161 {MMP2_CLK_KPC
, "kpc_clk", "clk32", CLK_SET_RATE_PARENT
, APBC_KPC
, 0x7, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY
, &reset_lock
},
162 {MMP2_CLK_RTC
, "rtc_clk", "clk32", CLK_SET_RATE_PARENT
, APBC_RTC
, 0x87, 0x83, 0x0, MMP_CLK_GATE_NEED_DELAY
, &reset_lock
},
163 {MMP2_CLK_PWM0
, "pwm0_clk", "pll1_48", CLK_SET_RATE_PARENT
, APBC_PWM0
, 0x7, 0x3, 0x0, 0, &reset_lock
},
164 {MMP2_CLK_PWM1
, "pwm1_clk", "pll1_48", CLK_SET_RATE_PARENT
, APBC_PWM1
, 0x7, 0x3, 0x0, 0, &reset_lock
},
165 {MMP2_CLK_PWM2
, "pwm2_clk", "pll1_48", CLK_SET_RATE_PARENT
, APBC_PWM2
, 0x7, 0x3, 0x0, 0, &reset_lock
},
166 {MMP2_CLK_PWM3
, "pwm3_clk", "pll1_48", CLK_SET_RATE_PARENT
, APBC_PWM3
, 0x7, 0x3, 0x0, 0, &reset_lock
},
167 /* The gate clocks has mux parent. */
168 {MMP2_CLK_UART0
, "uart0_clk", "uart0_mux", CLK_SET_RATE_PARENT
, APBC_UART0
, 0x7, 0x3, 0x0, 0, &uart0_lock
},
169 {MMP2_CLK_UART1
, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT
, APBC_UART1
, 0x7, 0x3, 0x0, 0, &uart1_lock
},
170 {MMP2_CLK_UART2
, "uart2_clk", "uart2_mux", CLK_SET_RATE_PARENT
, APBC_UART2
, 0x7, 0x3, 0x0, 0, &uart2_lock
},
171 {MMP2_CLK_UART3
, "uart3_clk", "uart3_mux", CLK_SET_RATE_PARENT
, APBC_UART3
, 0x7, 0x3, 0x0, 0, &uart2_lock
},
172 {MMP2_CLK_SSP0
, "ssp0_clk", "ssp0_mux", CLK_SET_RATE_PARENT
, APBC_SSP0
, 0x7, 0x3, 0x0, 0, &ssp0_lock
},
173 {MMP2_CLK_SSP1
, "ssp1_clk", "ssp1_mux", CLK_SET_RATE_PARENT
, APBC_SSP1
, 0x7, 0x3, 0x0, 0, &ssp1_lock
},
174 {MMP2_CLK_SSP2
, "ssp2_clk", "ssp2_mux", CLK_SET_RATE_PARENT
, APBC_SSP2
, 0x7, 0x3, 0x0, 0, &ssp2_lock
},
175 {MMP2_CLK_SSP3
, "ssp3_clk", "ssp3_mux", CLK_SET_RATE_PARENT
, APBC_SSP3
, 0x7, 0x3, 0x0, 0, &ssp3_lock
},
176 {MMP2_CLK_TIMER
, "timer_clk", "timer_mux", CLK_SET_RATE_PARENT
, APBC_TIMER
, 0x7, 0x3, 0x0, 0, &timer_lock
},
179 static void mmp2_apb_periph_clk_init(struct mmp2_clk_unit
*pxa_unit
)
181 struct mmp_clk_unit
*unit
= &pxa_unit
->unit
;
183 mmp_register_mux_clks(unit
, apbc_mux_clks
, pxa_unit
->apbc_base
,
184 ARRAY_SIZE(apbc_mux_clks
));
186 mmp_register_gate_clks(unit
, apbc_gate_clks
, pxa_unit
->apbc_base
,
187 ARRAY_SIZE(apbc_gate_clks
));
190 static DEFINE_SPINLOCK(sdh_lock
);
191 static const char *sdh_parent_names
[] = {"pll1_4", "pll2", "usb_pll", "pll1"};
192 static struct mmp_clk_mix_config sdh_mix_config
= {
193 .reg_info
= DEFINE_MIX_REG_INFO(4, 10, 2, 8, 32),
196 static DEFINE_SPINLOCK(usb_lock
);
198 static DEFINE_SPINLOCK(disp0_lock
);
199 static DEFINE_SPINLOCK(disp1_lock
);
200 static const char *disp_parent_names
[] = {"pll1", "pll1_16", "pll2", "vctcxo"};
202 static DEFINE_SPINLOCK(ccic0_lock
);
203 static DEFINE_SPINLOCK(ccic1_lock
);
204 static const char *ccic_parent_names
[] = {"pll1_2", "pll1_16", "vctcxo"};
205 static struct mmp_clk_mix_config ccic0_mix_config
= {
206 .reg_info
= DEFINE_MIX_REG_INFO(4, 17, 2, 6, 32),
208 static struct mmp_clk_mix_config ccic1_mix_config
= {
209 .reg_info
= DEFINE_MIX_REG_INFO(4, 16, 2, 6, 32),
212 static struct mmp_param_mux_clk apmu_mux_clks
[] = {
213 {MMP2_CLK_DISP0_MUX
, "disp0_mux", disp_parent_names
, ARRAY_SIZE(disp_parent_names
), CLK_SET_RATE_PARENT
, APMU_DISP0
, 6, 2, 0, &disp0_lock
},
214 {MMP2_CLK_DISP1_MUX
, "disp1_mux", disp_parent_names
, ARRAY_SIZE(disp_parent_names
), CLK_SET_RATE_PARENT
, APMU_DISP1
, 6, 2, 0, &disp1_lock
},
217 static struct mmp_param_div_clk apmu_div_clks
[] = {
218 {0, "disp0_div", "disp0_mux", CLK_SET_RATE_PARENT
, APMU_DISP0
, 8, 4, 0, &disp0_lock
},
219 {0, "disp0_sphy_div", "disp0_mux", CLK_SET_RATE_PARENT
, APMU_DISP0
, 15, 5, 0, &disp0_lock
},
220 {0, "disp1_div", "disp1_mux", CLK_SET_RATE_PARENT
, APMU_DISP1
, 8, 4, 0, &disp1_lock
},
221 {0, "ccic0_sphy_div", "ccic0_mix_clk", CLK_SET_RATE_PARENT
, APMU_CCIC0
, 10, 5, 0, &ccic0_lock
},
222 {0, "ccic1_sphy_div", "ccic1_mix_clk", CLK_SET_RATE_PARENT
, APMU_CCIC1
, 10, 5, 0, &ccic1_lock
},
225 static struct mmp_param_gate_clk apmu_gate_clks
[] = {
226 {MMP2_CLK_USB
, "usb_clk", "usb_pll", 0, APMU_USB
, 0x9, 0x9, 0x0, 0, &usb_lock
},
227 /* The gate clocks has mux parent. */
228 {MMP2_CLK_SDH0
, "sdh0_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT
, APMU_SDH0
, 0x1b, 0x1b, 0x0, 0, &sdh_lock
},
229 {MMP2_CLK_SDH1
, "sdh1_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT
, APMU_SDH1
, 0x1b, 0x1b, 0x0, 0, &sdh_lock
},
230 {MMP2_CLK_SDH1
, "sdh2_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT
, APMU_SDH2
, 0x1b, 0x1b, 0x0, 0, &sdh_lock
},
231 {MMP2_CLK_SDH1
, "sdh3_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT
, APMU_SDH3
, 0x1b, 0x1b, 0x0, 0, &sdh_lock
},
232 {MMP2_CLK_DISP0
, "disp0_clk", "disp0_div", CLK_SET_RATE_PARENT
, APMU_DISP0
, 0x1b, 0x1b, 0x0, 0, &disp0_lock
},
233 {MMP2_CLK_DISP0_SPHY
, "disp0_sphy_clk", "disp0_sphy_div", CLK_SET_RATE_PARENT
, APMU_DISP0
, 0x1024, 0x1024, 0x0, 0, &disp0_lock
},
234 {MMP2_CLK_DISP1
, "disp1_clk", "disp1_div", CLK_SET_RATE_PARENT
, APMU_DISP1
, 0x1b, 0x1b, 0x0, 0, &disp1_lock
},
235 {MMP2_CLK_CCIC_ARBITER
, "ccic_arbiter", "vctcxo", CLK_SET_RATE_PARENT
, APMU_CCIC0
, 0x1800, 0x1800, 0x0, 0, &ccic0_lock
},
236 {MMP2_CLK_CCIC0
, "ccic0_clk", "ccic0_mix_clk", CLK_SET_RATE_PARENT
, APMU_CCIC0
, 0x1b, 0x1b, 0x0, 0, &ccic0_lock
},
237 {MMP2_CLK_CCIC0_PHY
, "ccic0_phy_clk", "ccic0_mix_clk", CLK_SET_RATE_PARENT
, APMU_CCIC0
, 0x24, 0x24, 0x0, 0, &ccic0_lock
},
238 {MMP2_CLK_CCIC0_SPHY
, "ccic0_sphy_clk", "ccic0_sphy_div", CLK_SET_RATE_PARENT
, APMU_CCIC0
, 0x300, 0x300, 0x0, 0, &ccic0_lock
},
239 {MMP2_CLK_CCIC1
, "ccic1_clk", "ccic1_mix_clk", CLK_SET_RATE_PARENT
, APMU_CCIC1
, 0x1b, 0x1b, 0x0, 0, &ccic1_lock
},
240 {MMP2_CLK_CCIC1_PHY
, "ccic1_phy_clk", "ccic1_mix_clk", CLK_SET_RATE_PARENT
, APMU_CCIC1
, 0x24, 0x24, 0x0, 0, &ccic1_lock
},
241 {MMP2_CLK_CCIC1_SPHY
, "ccic1_sphy_clk", "ccic1_sphy_div", CLK_SET_RATE_PARENT
, APMU_CCIC1
, 0x300, 0x300, 0x0, 0, &ccic1_lock
},
244 static void mmp2_axi_periph_clk_init(struct mmp2_clk_unit
*pxa_unit
)
247 struct mmp_clk_unit
*unit
= &pxa_unit
->unit
;
249 sdh_mix_config
.reg_info
.reg_clk_ctrl
= pxa_unit
->apmu_base
+ APMU_SDH0
;
250 clk
= mmp_clk_register_mix(NULL
, "sdh_mix_clk", sdh_parent_names
,
251 ARRAY_SIZE(sdh_parent_names
),
253 &sdh_mix_config
, &sdh_lock
);
255 ccic0_mix_config
.reg_info
.reg_clk_ctrl
= pxa_unit
->apmu_base
+ APMU_CCIC0
;
256 clk
= mmp_clk_register_mix(NULL
, "ccic0_mix_clk", ccic_parent_names
,
257 ARRAY_SIZE(ccic_parent_names
),
259 &ccic0_mix_config
, &ccic0_lock
);
260 mmp_clk_add(unit
, MMP2_CLK_CCIC0_MIX
, clk
);
262 ccic1_mix_config
.reg_info
.reg_clk_ctrl
= pxa_unit
->apmu_base
+ APMU_CCIC1
;
263 clk
= mmp_clk_register_mix(NULL
, "ccic1_mix_clk", ccic_parent_names
,
264 ARRAY_SIZE(ccic_parent_names
),
266 &ccic1_mix_config
, &ccic1_lock
);
267 mmp_clk_add(unit
, MMP2_CLK_CCIC1_MIX
, clk
);
269 mmp_register_mux_clks(unit
, apmu_mux_clks
, pxa_unit
->apmu_base
,
270 ARRAY_SIZE(apmu_mux_clks
));
272 mmp_register_div_clks(unit
, apmu_div_clks
, pxa_unit
->apmu_base
,
273 ARRAY_SIZE(apmu_div_clks
));
275 mmp_register_gate_clks(unit
, apmu_gate_clks
, pxa_unit
->apmu_base
,
276 ARRAY_SIZE(apmu_gate_clks
));
279 static void mmp2_clk_reset_init(struct device_node
*np
,
280 struct mmp2_clk_unit
*pxa_unit
)
282 struct mmp_clk_reset_cell
*cells
;
285 nr_resets
= ARRAY_SIZE(apbc_gate_clks
);
286 cells
= kcalloc(nr_resets
, sizeof(*cells
), GFP_KERNEL
);
290 for (i
= 0; i
< nr_resets
; i
++) {
291 cells
[i
].clk_id
= apbc_gate_clks
[i
].id
;
292 cells
[i
].reg
= pxa_unit
->apbc_base
+ apbc_gate_clks
[i
].offset
;
294 cells
[i
].lock
= apbc_gate_clks
[i
].lock
;
298 mmp_clk_reset_register(np
, cells
, nr_resets
);
301 static void __init
mmp2_clk_init(struct device_node
*np
)
303 struct mmp2_clk_unit
*pxa_unit
;
305 pxa_unit
= kzalloc(sizeof(*pxa_unit
), GFP_KERNEL
);
309 pxa_unit
->mpmu_base
= of_iomap(np
, 0);
310 if (!pxa_unit
->mpmu_base
) {
311 pr_err("failed to map mpmu registers\n");
315 pxa_unit
->apmu_base
= of_iomap(np
, 1);
316 if (!pxa_unit
->mpmu_base
) {
317 pr_err("failed to map apmu registers\n");
321 pxa_unit
->apbc_base
= of_iomap(np
, 2);
322 if (!pxa_unit
->apbc_base
) {
323 pr_err("failed to map apbc registers\n");
327 mmp_clk_init(np
, &pxa_unit
->unit
, MMP2_NR_CLKS
);
329 mmp2_pll_init(pxa_unit
);
331 mmp2_apb_periph_clk_init(pxa_unit
);
333 mmp2_axi_periph_clk_init(pxa_unit
);
335 mmp2_clk_reset_init(np
, pxa_unit
);
338 CLK_OF_DECLARE(mmp2_clk
, "marvell,mmp2-clock", mmp2_clk_init
);