2 * iProc Clock Control Unit
3 * The software model repsresents the hardware clock hierarchy
6 #include <linux/kernel.h>
7 #include <linux/init.h>
8 #include <linux/module.h>
9 #include <linux/errno.h>
10 #include <linux/err.h>
11 #include <linux/clk.h>
13 #include <linux/ioport.h>
14 #include <linux/delay.h>
16 #include <asm/clkdev.h>
17 #include <mach/clkdev.h>
19 static struct resource ccu_regs
= {
23 .flags
= IORESOURCE_MEM
,
27 * Clock management scheme is a provisional implementation
28 * only intended to retreive the pre-set frequencies for each
33 * Get PLL running status and update output frequency
34 * for ARMPLL channel 0
36 static int a9pll0_status(struct clk
* clk
)
39 u32 pdiv
, ndiv_int
, ndiv_frac
, mdiv
;
42 if( clk
->type
!= CLK_PLL
)
45 BUG_ON( ! clk
->regs_base
);
46 BUG_ON( ! clk
->parent
);
48 /* read status register */
49 regA
= readl( clk
->regs_base
+ 0x0c00 );/* IHOST_PROC_CLK_PLLARMA */
50 regB
= readl( clk
->regs_base
+ 0x0c04 );/* IHOST_PROC_CLK_PLLARMB */
51 regC
= readl( clk
->regs_base
+ 0x0c08 );/* IHOST_PROC_CLK_PLLARMB */
53 /* reg C bit 8 is bypass mode - input frequency to output */
54 if( (regC
& (1 << 8)) == 1 )
56 clk
->rate
= clk
->parent
->rate
;
60 /* reg A bit 28 is "lock" signal, has to be "1" for proper operation */
61 if( (regA
& (1 << 28)) == 0 )
67 /* Update PLL frequency */
70 /* pdiv in bits 24..27 (4 bits) */
71 pdiv
= ( regA
>> 24 ) & 0xf ;
72 if( pdiv
== 0 ) pdiv
= 0x10 ;
74 /* feedback divider (int) in bits 8..17 (10 bits) */
75 ndiv_int
= ( regA
>> 8) & ((1<<10)-1);
76 if( ndiv_int
== 0 ) ndiv_int
= 1 << 10 ;
78 /* feedback divider fraction in reg B, bits 0..19 */
79 ndiv_frac
= regB
& ((1<<20)-1);
81 /* post-divider is in reg C bits 0..7 */
83 if(mdiv
== 0) mdiv
= 0x100;
85 x
= ((u64
) ndiv_int
<< 20) | ndiv_frac
;
86 x
= (x
* clk
->parent
->rate
) >> 20 ;
87 (void) do_div( x
, pdiv
);
90 (void) do_div(x
, mdiv
);
98 * Get PLL running status and update output frequency
99 * for ARMPLL channel 1
101 static int a9pll1_status(struct clk
* clk
)
103 u32 regA
, regB
, regC
, regD
;
104 unsigned pdiv
, ndiv_int
, ndiv_frac
, mdiv
;
107 if( clk
->type
!= CLK_PLL
)
110 BUG_ON( ! clk
->regs_base
);
111 BUG_ON( ! clk
->parent
);
113 /* read status register */
114 regA
= readl( clk
->regs_base
+0xc00 );/* IHOST_PROC_CLK_PLLARMB */
115 regB
= readl( clk
->regs_base
+0xc04 );/* IHOST_PROC_CLK_PLLARMB */
116 regC
= readl( clk
->regs_base
+0xc20 );/* IHOST_PROC_CLK_PLLARMCTRL5 */
117 regD
= readl( clk
->regs_base
+0xc24 );/* IHOST_PROC_CLK_PLLARM_OFFSET*/
119 /* reg C bit 8 is bypass mode - input frequency to output */
120 if( (regC
& (1 << 8)) == 1 )
122 clk
->rate
= clk
->parent
->rate
;
126 /* reg A bit 28 is "lock" signal, has to be "1" for proper operation */
127 if( (regA
& (1 << 28)) == 0 )
133 /* Update PLL frequency */
136 /* pdiv in bits 24..27 (4 bits) */
137 pdiv
= ( regA
>> 24 ) & 0xf ;
138 if( pdiv
== 0 ) pdiv
= 0x10 ;
140 /* Check if offset mode is active */
143 /* pllarm_ndiv_int_offset bits 27:20 */
144 ndiv_int
= ( regD
>> 20 ) & 0xff ;
145 if( ndiv_int
== 0 ) ndiv_int
= 1 << 8 ;
147 /* pllarm_ndiv_frac_offset bits 19:0 */
148 ndiv_frac
= regD
& ((1<<20)-1);
150 /* If offset not active, channel 0 parameters are used */
153 /* feedback divider (int) in bits 8..17 (10 bits) */
154 ndiv_int
= ( regA
>> 8) & ((1<<10)-1);
155 if( ndiv_int
== 0 ) ndiv_int
= 1 << 10 ;
157 /* feedback divider fraction in reg B, bits 0..19 */
158 ndiv_frac
= regB
& ((1<<20)-1);
160 /* post-divider is in reg C bits 0..7 */
162 if(mdiv
== 0) mdiv
= 0x100;
165 x
= ((u64
) ndiv_int
<< 20) | ndiv_frac
;
166 x
= (x
* clk
->parent
->rate
) >> 20 ;
167 (void) do_div( x
, pdiv
);
169 (void) do_div(x
, mdiv
);
170 clk
->rate
= (u32
)(x
);
176 static const struct clk_ops a9pll0_ops
= {
177 .status
= a9pll0_status
,
180 static const struct clk_ops a9pll1_ops
= {
181 .status
= a9pll1_status
,
187 * could be used as source for generated clocks
189 static struct clk clk_a9pll
[2] = {
192 .name
= "arm_cpu_clk",
198 .name
= "arm_cpu_h_clk",
205 * Decode the Frequency ID setting for arm_clk
207 static int iproc_cru_arm_freq_id( void * __iomem regs_base
)
210 unsigned policy
, fid
, i
;
211 u8 arm_clk_policy_mask
= 0, apb0_clk_policy_mask
= 0 ;
213 /* bits 0..2 freq# for policy0, 8..10 for policy1,
214 * 16..18 policy2, 24..26 policy 3
216 reg_f
= readl( regs_base
+0x008 );/*IHOST_PROC_CLK_POLICY_FREQ*/
218 for(i
= 0; i
< 4; i
++ ) {
219 /* Reg IHOST_PROC_CLK_POLICY<i>_MASK*/
220 /* bit 20 arm policy mask, bit 21 apb0 policy mask */
221 reg
= readl( regs_base
+0x010+i
*4 );
222 arm_clk_policy_mask
|= (1 & ( reg
>> 20 )) << i
;
223 apb0_clk_policy_mask
|= (1 & ( reg
>> 21 )) << i
;
226 /* TBD: Where to get hardware policy setting ? */
229 /* Check for PLL policy software override */
230 reg
= readl( regs_base
+0xe00 );/* IHOST_PROC_CLK_ARM_DIV */
234 fid
= (reg_f
>> (8 * policy
)) & 0xf;
236 /* Verify freq_id from debug register */
237 reg
= readl( regs_base
+0xec0 );/* IHOST_PROC_CLK_POLICY_DBG */
238 /* Bits 12..14 contain active frequency_id */
239 i
= 0x7 & (reg
>> 12);
243 "IPROC CRU clock frequency id override %d->%d\n",
252 * Get status of any of the ARMPLL output channels
254 static int a9pll_chan_status(struct clk
* clk
)
257 unsigned freq_id
, div
;
259 if( clk
->type
!= CLK_DIV
)
262 BUG_ON( ! clk
->regs_base
);
264 freq_id
= iproc_cru_arm_freq_id( clk
->regs_base
);
272 case 0x3a: /* arm_clk */
274 clk
->parent
= &clk_a9pll
[1]; /* arm_clk_h */
277 else if( freq_id
== 6 ) {
278 clk
->parent
= &clk_a9pll
[0]; /* arm_clk */
281 else if( freq_id
== 2 ) {
282 struct clk
* clk_lcpll_200
;
284 clk_get_sys( NULL
, "sdio_clk");
285 BUG_ON( ! clk_lcpll_200
);
286 clk
->parent
= clk_lcpll_200
;
290 clk
->parent
= clk_a9pll
[0].parent
;
295 case 0x0f: /* periph_clk */
300 /* IHOST_PROC_CLK_ARM_DIV */
301 reg
= readl( clk
->regs_base
+0xe00 );
302 /* apb0_free_div bits 10:8 */
303 div
= ( reg
>> 8 ) & 0x7;
304 if( div
== 0 ) div
= 8;
308 /* IHOST_PROC_CLK_ARM_DIV */
309 reg
= readl( clk
->regs_base
+0xe00 );
310 /* arm_switch_div bits 6:5 */
311 div
= ( reg
>> 5 ) & 0x3 ;
312 if( div
== 0 ) div
= 4;
316 /* IHOST_PROC_CLK_APB_DIV apb_clk_div bits 1:0 */
317 reg
= readl( clk
->regs_base
+0xa10 );
319 if( div
== 0 ) div
= 4;
324 BUG_ON( ! clk
->parent
);
325 /* Parent may have changed, use top-level API to force recursion */
326 clk
->rate
= clk_get_rate( clk
->parent
) / div
;
332 static const struct clk_ops a9pll_chan_ops
= {
333 .status
= a9pll_chan_status
,
337 * iProc A9 PLL output clocks
339 static struct clk clk_a9chan
[] = {
340 { .ops
= &a9pll_chan_ops
, .type
= CLK_DIV
, .parent
= &clk_a9pll
[0],
341 .name
= "arm_clk", .chan
= 0x3a },
342 { .ops
= &a9pll_chan_ops
, .type
= CLK_DIV
, .parent
= &clk_a9chan
[0],
343 .name
= "periph_clk", .chan
= 0x0f },
344 { .ops
= &a9pll_chan_ops
, .type
= CLK_DIV
, .parent
= &clk_a9chan
[0],
345 .name
= "apb0_free", .chan
= 0x0a },
346 { .ops
= &a9pll_chan_ops
, .type
= CLK_DIV
, .parent
= &clk_a9chan
[0],
347 .name
= "arm_switch", .chan
= 0x0b },
348 { .ops
= &a9pll_chan_ops
, .type
= CLK_DIV
, .parent
= &clk_a9chan
[0],
349 .name
= "apb_clk", .chan
= 0x1a },
352 static struct clk_lookup cru_clk_lookups
[] = {
353 { .con_id
= "armpll_clk", .clk
= &clk_a9pll
[0], },
354 { .con_id
= "armpll_h_clk", .clk
= &clk_a9pll
[1], },
355 { .con_id
= "arm_clk", .clk
= &clk_a9chan
[0], },
356 { .con_id
= "periph_clk",.clk
= &clk_a9chan
[1], },
357 { .con_id
= "apb0_free", .clk
= &clk_a9chan
[2], },
358 { .con_id
= "axi_clk", .clk
= &clk_a9chan
[3], },
359 { .con_id
= "apb_clk", .clk
= &clk_a9chan
[4], },
362 void __init
soc_cru_init( struct clk
* src_clk
)
364 void * __iomem reg_base
;
367 BUG_ON( request_resource( &iomem_resource
, &ccu_regs
));
369 reg_base
= ioremap( ccu_regs
.start
, resource_size(&ccu_regs
));
371 BUG_ON( IS_ERR_OR_NULL(reg_base
));
373 /* Initialize clocks */
374 for(i
= 0; i
< ARRAY_SIZE(clk_a9pll
); i
++ )
376 clk_a9pll
[i
].regs_base
= reg_base
;
377 clk_a9pll
[i
].parent
= src_clk
;
380 for(i
= 0; i
< ARRAY_SIZE(clk_a9chan
); i
++ )
382 clk_a9chan
[i
].regs_base
= reg_base
;
385 /* Install clock sources into the lookup table */
386 clkdev_add_table(cru_clk_lookups
,
387 ARRAY_SIZE(cru_clk_lookups
));
390 void cru_clocks_show( void )
394 printk( "CRU Clocks:\n" );
395 for(i
= 0; i
< ARRAY_SIZE( cru_clk_lookups
); i
++ )
397 printk( "%s: (%s) %lu\n",
398 cru_clk_lookups
[i
].con_id
,
399 cru_clk_lookups
[i
].clk
->name
,
400 clk_get_rate( cru_clk_lookups
[i
].clk
)
403 printk( "CRU Clocks# %u\n", i
);
407 * Perform reset of one of the two cores by means of the IPROC CRU
409 int soc_cpu_reset(unsigned cpu
, bool reset
)
411 void * __iomem reg_base
;
414 reg_base
= clk_a9pll
[0].regs_base
;
416 if( cpu
>= 2 || ! reg_base
)
420 register IHOST_PROC_RST_WR_ACCESS 0x19000F00
421 <password> bits[23:8] Read will return 0. 0x0000
422 <rstmgr_acc> bits[0] Reset manager access enable.
423 This bit must be 1 for any write access to the remaining Reset
424 manager registers. This field is protected from accidental
425 modification. Writing is allowed only when write data
426 bits [23:8] contain A5A5.
429 /* Enable writing to reset control bits */
430 writel( 0xa5a5 << 8 | 0x1, reg_base
+ 0xf00 );
433 register IHOST_PROC_RST_A9_CORE_SOFT_RSTN 0x19000F08
434 <a9_core_1_soft_rstn> bit[1] - Soft reset for a9_core_1.
435 When this bit is 0 a9_core_1 will be in reset state. Default=1
436 <a9_core_0_soft_rstn> bit[0] - Soft reset for a9_core_0.
437 When this bit is 0 a9_core_0 will be in reset state. Default=1
439 reg
= 0x3 ^ (1 << cpu
) ;
440 writel( reg
, reg_base
+ 0xf00 );
441 writel( 0x3, reg_base
+ 0xf00 );
443 /* Disable writing to reset control bits */
444 writel( 0x0, reg_base
+ 0xf00 );