2 * Northstar DMU (Device Management Unit),
3 * i.e. clocks, I/O pads, GPIO etc.
4 * SoC-specific hardware support features.
7 * Northstar_top_power_uarch_v1_0.pdf
10 #include <linux/kernel.h>
11 #include <linux/init.h>
12 #include <linux/module.h>
13 #include <linux/errno.h>
14 #include <linux/err.h>
15 #include <linux/clk.h>
17 #include <linux/ioport.h>
18 #include <linux/delay.h>
19 #include <linux/proc_fs.h>
21 #include <asm/clkdev.h>
22 #include <mach/clkdev.h>
23 #include <mach/io_map.h>
24 #include <plat/plat-bcm5301x.h>
27 #define DMU_PROC_NAME "dmu"
28 #endif /* CONFIG_PROC_FS */
30 static struct resource dmu_regs
= {
32 .start
= SOC_DMU_BASE_PA
,
33 .end
= SOC_DMU_BASE_PA
+ SZ_4K
-1,
34 .flags
= IORESOURCE_MEM
,
38 * Clock management scheme is a provisional implementation
39 * only intended to retreive the pre-set frequencies for each
41 * Better handling of post-dividers and fractional part of
42 * feedbeck dividers need to be added.
43 * Need to understand what diagnostics from CRU registers could
44 * be handy, and export that via a sysfs interface.
48 * The CRU contains two similar PLLs: LCPLL and GENPLL,
49 * both with several output channels divided from the PLL
54 * Get PLL running status and update output frequency
56 static int lcpll_status(struct clk
* clk
)
60 unsigned pdiv
, ndiv_int
, ndiv_frac
;
62 if( clk
->type
!= CLK_PLL
)
65 /* read status register */
66 reg
= readl( clk
->regs_base
+ 0x10 );
68 /* bit 12 is "lock" signal, has to be "1" for proper PLL operation */
69 if( (reg
& (1 << 12)) == 0 )
74 /* Update PLL frequency */
76 /* control1 register */
77 reg
= readl( clk
->regs_base
+ 0x04);
79 /* feedback divider integer and fraction parts */
80 pdiv
= ( reg
>> 28 ) & 7 ;
81 ndiv_int
= ( reg
>> 20) & 0xff;
82 ndiv_frac
= reg
& ((1<<20)-1);
87 x
= clk
->parent
->rate
/ pdiv
;
89 x
= x
* ( (u64
) ndiv_int
<< 20 | ndiv_frac
) ;
96 static const struct clk_ops lcpll_ops
= {
97 .status
= lcpll_status
,
100 static int lcpll_chan_status(struct clk
* clk
)
107 if( clk
->parent
== NULL
|| clk
->type
!= CLK_DIV
)
110 /* Register address is only stored in PLL structure */
111 base
= clk
->parent
->regs_base
;
112 BUG_ON( base
== NULL
);
114 /* enable bit is in enableb_ch[] inversed */
115 enable
= ((readl( base
+ 0 ) >> 6) & 7) ^ 7;
117 if( 0 == (enable
& (1 << clk
->chan
)))
124 reg
= readl(base
+ 0x08 );
126 mdiv
= 0xff & ( reg
>> ((0x3^clk
->chan
) << 3) );
128 /* when divisor is 0, it behaves as max+1 */
132 clk
->rate
= ( clk
->parent
->rate
/ mdiv
);
137 static const struct clk_ops lcpll_chan_ops
= {
138 .status
= lcpll_chan_status
,
142 * LCPLL has 4 output channels
144 static struct clk clk_lcpll
= {
152 * LCPLL output clocks -
153 * chan 0 - PCIe ref clock, should be 1 GHz,
154 * chan 1 - SDIO clock, e.g. 200 MHz,
155 * chan 2 - DDR clock, typical 166.667 MHz for DDR667,
159 static struct clk clk_lcpll_ch
[4] = {
160 { .ops
= &lcpll_chan_ops
, .parent
= &clk_lcpll
, .type
= CLK_DIV
,
161 .name
= "lcpll_ch0", .chan
= 0, },
162 { .ops
= &lcpll_chan_ops
, .parent
= &clk_lcpll
, .type
= CLK_DIV
,
163 .name
= "lcpll_ch1", .chan
= 1, },
164 { .ops
= &lcpll_chan_ops
, .parent
= &clk_lcpll
, .type
= CLK_DIV
,
165 .name
= "lcpll_ch2", .chan
= 2, },
166 { .ops
= &lcpll_chan_ops
, .parent
= &clk_lcpll
, .type
= CLK_DIV
,
167 .name
= "lcpll_ch3", .chan
= 3, },
171 * Get PLL running status and update output frequency
173 static int genpll_status(struct clk
* clk
)
177 unsigned pdiv
, ndiv_int
, ndiv_frac
;
179 if( clk
->type
!= CLK_PLL
)
182 /* Offset of the PLL status register */
183 reg
= readl( clk
->regs_base
+ 0x20 );
185 /* bit 12 is "lock" signal, has to be "1" for proper PLL operation */
186 if( (reg
& (1 << 12)) == 0 )
192 /* Update PLL frequency */
194 /* get PLL feedback divider values from control5 */
195 reg
= readl( clk
->regs_base
+ 0x14);
197 /* feedback divider integer and fraction parts */
198 ndiv_int
= reg
>> 20;
199 ndiv_frac
= reg
& ((1<<20)-1);
202 reg
= readl( clk
->regs_base
+ 0x18);
203 pdiv
= (reg
>> 24) & 7;
208 x
= clk
->parent
->rate
/ pdiv
;
210 x
= x
* ( (u64
) ndiv_int
<< 20 | ndiv_frac
) ;
212 clk
->rate
= x
>> 20 ;
217 static const struct clk_ops genpll_ops
= {
218 .status
= genpll_status
,
221 static int genpll_chan_status(struct clk
* clk
)
229 if( clk
->parent
== NULL
|| clk
->type
!= CLK_DIV
)
232 /* Register address is only stored in PLL structure */
233 base
= clk
->parent
->regs_base
;
235 BUG_ON( base
== NULL
);
237 /* enable bit is in enableb_ch[0..5] inversed */
238 enable
= ((readl( base
+ 0x04 ) >> 12) & 0x3f) ^ 0x3f ;
240 if( 0 == (enable
& (1 << clk
->chan
)))
246 /* GENPLL has the 6 channels spread over two regs */
250 off
= 0x18; shift
= 16;
254 off
= 0x18; shift
= 8;
258 off
= 0x18; shift
= 0;
262 off
= 0x1c; shift
= 16;
266 off
= 0x1c; shift
= 8;
270 off
= 0x1c; shift
= 0;
275 off
= shift
= 0; /* fend off warnings */
278 reg
= readl( base
+ off
);
280 mdiv
= 0xff & ( reg
>> shift
);
282 /* when divisor is 0, it behaves as max+1 */
286 clk
->rate
= clk
->parent
->rate
/ mdiv
;
291 static const struct clk_ops genpll_chan_ops
= {
292 .status
= genpll_chan_status
,
297 * GENPLL has 6 output channels
299 static struct clk clk_genpll
= {
307 * chan 0 - Ethernet switch and MAC, RGMII, need 250 MHz
308 * chan 1 - Ethernet switch slow clock, 150 Mhz
309 * chan 2 - USB PHY clock, need 30 MHz
310 * chan 3 - iProc N MHz clock, set from OTP
311 * chan 4 - iProc N/2 MHz clock, set from OTP
312 * chan 5 - iProc N/4 MHz clock, set from OTP
316 static struct clk clk_genpll_ch
[6] = {
317 { .ops
= &genpll_chan_ops
, .parent
= &clk_genpll
, .type
= CLK_DIV
,
318 .name
= "genpll_ch0", .chan
= 0, },
319 { .ops
= &genpll_chan_ops
, .parent
= &clk_genpll
, .type
= CLK_DIV
,
320 .name
= "genpll_ch1", .chan
= 1, },
321 { .ops
= &genpll_chan_ops
, .parent
= &clk_genpll
, .type
= CLK_DIV
,
322 .name
= "genpll_ch2", .chan
= 2, },
323 { .ops
= &genpll_chan_ops
, .parent
= &clk_genpll
, .type
= CLK_DIV
,
324 .name
= "genpll_ch3", .chan
= 3, },
325 { .ops
= &genpll_chan_ops
, .parent
= &clk_genpll
, .type
= CLK_DIV
,
326 .name
= "genpll_ch4", .chan
= 4, },
327 { .ops
= &genpll_chan_ops
, .parent
= &clk_genpll
, .type
= CLK_DIV
,
328 .name
= "genpll_ch5", .chan
= 5, },
332 * This table is used to locate clock sources
333 * from device drivers
336 static struct clk_lookup soc_clk_lookups
[] = {
338 .con_id
= "pcie_clk", /* a.k.a. "c_clk100" */
339 .clk
= &clk_lcpll_ch
[0],
341 .con_id
= "sdio_clk", /* a.k.a. "c_clk200" */
342 .clk
= &clk_lcpll_ch
[1],
344 .con_id
= "ddr_clk", /* a.k.a. "c_clk400" */
345 .clk
= &clk_lcpll_ch
[2],
347 .con_id
= "c_clk120", /* unassigned ? */
348 .clk
= &clk_lcpll_ch
[3],
350 .con_id
= "en_phy_clk", /* "c_clk250" */
351 .clk
= &clk_genpll_ch
[0],
353 .con_id
= "en_clk", /* "c_clk150" */
354 .clk
= &clk_genpll_ch
[1],
356 .con_id
= "usb_phy_clk", /* "c_clk30" */
357 .clk
= &clk_genpll_ch
[2],
359 .con_id
= "iproc_fast_clk", /* "c_clk500" */
360 .clk
= &clk_genpll_ch
[3],
362 .con_id
= "iproc_med_clk", /* "c_clk250" */
363 .clk
= &clk_genpll_ch
[4],
365 .con_id
= "iproc_slow_clk", /* "c_clk125" */
366 .clk
= &clk_genpll_ch
[5],
371 * Install above clocks into clock lookup table
372 * and initialize the register base address for each
374 static void __init
soc_clocks_init(
375 void * __iomem cru_regs_base
,
380 /* registers are already mapped with the rest of DMU block */
381 /* Update register base address */
382 clk_lcpll
.regs_base
= cru_regs_base
+ 0x00 ;
383 clk_genpll
.regs_base
= cru_regs_base
+ 0x40 ;
385 /* Set parent as reference ckock */
386 clk_lcpll
.parent
= clk_ref
;
387 clk_genpll
.parent
= clk_ref
;
389 #ifdef __DEPRECATED__
392 /* We need to clear dev_id fields in the lookups,
393 because if it is set, it will not match by con_id */
394 for(i
= 0; i
< ARRAY_SIZE(soc_clk_lookups
); i
++ )
395 soc_clk_lookups
[i
].dev_id
= NULL
;
399 /* Install clock sources into the lookup table */
400 clkdev_add_table(soc_clk_lookups
,
401 ARRAY_SIZE(soc_clk_lookups
));
404 void __init
soc_dmu_init( struct clk
* clk_ref
)
406 void * __iomem reg_base
;
408 if( IS_ERR_OR_NULL( clk_ref
))
410 printk( KERN_ERR
"DMU no clock source - skip init\n");
414 BUG_ON( request_resource( &iomem_resource
, &dmu_regs
));
416 /* DMU regs are mapped as part of the fixed mapping with CCA+CCB */
417 reg_base
= (void *) SOC_DMU_BASE_VA
;
419 BUG_ON( IS_ERR_OR_NULL(reg_base
));
421 /* Initialize clocks */
422 soc_clocks_init( reg_base
+ 0x100, clk_ref
); /* CRU LCPLL control0 */
432 void soc_clocks_show( void )
436 printk( "DMU Clocks:\n" );
437 for(i
= 0; i
< ARRAY_SIZE( soc_clk_lookups
); i
++ )
439 printk( "%s, %s: (%s) %lu\n",
440 soc_clk_lookups
[i
].con_id
,
441 soc_clk_lookups
[i
].dev_id
,
442 soc_clk_lookups
[i
].clk
->name
,
443 clk_get_rate( soc_clk_lookups
[i
].clk
)
446 printk( "DMU Clocks# %u\n", i
);
449 #ifdef CONFIG_PROC_FS
450 static int dmu_temperature_status(char * buffer
, char **start
,
451 off_t offset
, int length
, int * eof
, void * data
)
455 void *__iomem pvtmon_base
;
456 u32 pvtmon_control0
, pvtmon_status
;
462 pvtmon_base
= (void *)(SOC_DMU_BASE_VA
+ 0x2c0); /* PVTMON control0 */
464 pvtmon_control0
= readl(pvtmon_base
);
465 if (pvtmon_control0
& 0xf) {
466 pvtmon_control0
&= ~0xf;
467 writel(pvtmon_control0
, pvtmon_base
);
470 pvtmon_status
= readl(pvtmon_base
+ 0x8);
471 temperature
= 418 - ((5556 * pvtmon_status
) / 10000);
473 len
+= sprintf(buffer
+ len
, "CPU temperature\t: %d%cC\n\n",
485 *start
= buffer
+ (offset
- begin
);
486 len
-= (offset
- begin
);
494 static void __init
dmu_proc_init(void)
496 struct proc_dir_entry
*dmu
, *dmu_temp
;
498 dmu
= proc_mkdir(DMU_PROC_NAME
, NULL
);
501 printk(KERN_ERR
"DMU create proc directory failed.\n");
505 dmu_temp
= create_proc_read_entry(DMU_PROC_NAME
"/temperature", 0, NULL
,
506 dmu_temperature_status
, NULL
);
509 printk(KERN_ERR
"DMU create proc entry failed.\n");
511 fs_initcall(dmu_proc_init
);
512 #endif /* CONFIG_PROC_FS */