GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / arch / arm / plat-brcm / bcm5301x_dmu.c
blob66f62450db60c5c384dff0c49048ee73fe57b332
1 /*
2 * Northstar DMU (Device Management Unit),
3 * i.e. clocks, I/O pads, GPIO etc.
4 * SoC-specific hardware support features.
6 * Documents:
7 * Northstar_top_power_uarch_v1_0.pdf
9 */
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>
16 #include <linux/io.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>
26 #ifdef CONFIG_PROC_FS
27 #define DMU_PROC_NAME "dmu"
28 #endif /* CONFIG_PROC_FS */
30 static struct resource dmu_regs = {
31 .name = "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
40 * of the clocks.
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.
47 /*
48 * The CRU contains two similar PLLs: LCPLL and GENPLL,
49 * both with several output channels divided from the PLL
50 * output
54 * Get PLL running status and update output frequency
56 static int lcpll_status(struct clk * clk)
58 u32 reg;
59 u64 x;
60 unsigned pdiv, ndiv_int, ndiv_frac;
62 if( clk->type != CLK_PLL)
63 return -EINVAL;
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 )
71 clk->rate = 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);
84 if( pdiv == 0 )
85 return -EIO;
87 x = clk->parent->rate / pdiv ;
89 x = x * ( (u64) ndiv_int << 20 | ndiv_frac ) ;
91 clk->rate = x >> 20 ;
93 return 0;
96 static const struct clk_ops lcpll_ops = {
97 .status = lcpll_status,
100 static int lcpll_chan_status(struct clk * clk)
102 void * __iomem base;
103 u32 reg;
104 unsigned enable;
105 unsigned mdiv;
107 if( clk->parent == NULL || clk->type != CLK_DIV )
108 return -EINVAL;
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)))
119 clk->rate = 0;
120 return -EIO;
123 /* get divider */
124 reg = readl(base + 0x08 );
126 mdiv = 0xff & ( reg >> ((0x3^clk->chan) << 3) );
128 /* when divisor is 0, it behaves as max+1 */
129 if( mdiv == 0 )
130 mdiv = 1 << 8;
132 clk->rate = ( clk->parent->rate / mdiv);
133 return 0;
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 = {
145 .ops = &lcpll_ops,
146 .name = "LCPLL",
147 .type = CLK_PLL,
148 .chan = 4,
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,
156 * chan 3 - Unknown
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)
175 u32 reg;
176 u64 x;
177 unsigned pdiv, ndiv_int, ndiv_frac;
179 if( clk->type != CLK_PLL)
180 return -EINVAL;
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 )
188 clk->rate = 0;
189 return -EIO;
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);
201 /* get pdiv */
202 reg = readl( clk->regs_base + 0x18);
203 pdiv = (reg >> 24) & 7;
205 if( pdiv == 0 )
206 return -EIO;
208 x = clk->parent->rate / pdiv ;
210 x = x * ( (u64) ndiv_int << 20 | ndiv_frac ) ;
212 clk->rate = x >> 20 ;
214 return 0;
217 static const struct clk_ops genpll_ops = {
218 .status = genpll_status,
221 static int genpll_chan_status(struct clk * clk)
223 void * __iomem base;
224 u32 reg;
225 unsigned enable;
226 unsigned mdiv;
227 unsigned off, shift;
229 if( clk->parent == NULL || clk->type != CLK_DIV )
230 return -EINVAL;
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)))
242 clk->rate = 0;
243 return -EIO;
246 /* GENPLL has the 6 channels spread over two regs */
247 switch( clk->chan )
249 case 0:
250 off = 0x18; shift = 16;
251 break;
253 case 1:
254 off = 0x18; shift = 8;
255 break;
257 case 2:
258 off = 0x18; shift = 0;
259 break;
261 case 3:
262 off = 0x1c; shift = 16;
263 break;
265 case 4:
266 off = 0x1c; shift = 8;
267 break;
269 case 5:
270 off = 0x1c; shift = 0;
271 break;
273 default:
274 BUG_ON(clk->chan);
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 */
283 if( mdiv == 0 )
284 mdiv = 1 << 8;
286 clk->rate = clk->parent->rate / mdiv;
287 return 0;
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 = {
300 .ops = &genpll_ops,
301 .name = "GENPLL",
302 .type = CLK_PLL,
303 .chan = 6,
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,
376 struct clk * clk_ref
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__
391 int i ;
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;
397 #endif
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");
411 return;
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 )
434 unsigned i;
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)
453 int len;
454 off_t pos, begin;
455 void *__iomem pvtmon_base;
456 u32 pvtmon_control0, pvtmon_status;
457 int temperature;
459 len = 0;
460 pos = begin = 0;
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",
474 temperature, 0xF8);
476 pos = begin + len;
478 if (pos < offset) {
479 len = 0;
480 begin = pos;
483 *eof = 1;
485 *start = buffer + (offset - begin);
486 len -= (offset - begin);
488 if (len > length)
489 len = length;
491 return len;
494 static void __init dmu_proc_init(void)
496 struct proc_dir_entry *dmu, *dmu_temp;
498 dmu = proc_mkdir(DMU_PROC_NAME, NULL);
500 if (!dmu) {
501 printk(KERN_ERR "DMU create proc directory failed.\n");
502 return;
505 dmu_temp = create_proc_read_entry(DMU_PROC_NAME "/temperature", 0, NULL,
506 dmu_temperature_status, NULL);
508 if (!dmu_temp)
509 printk(KERN_ERR "DMU create proc entry failed.\n");
511 fs_initcall(dmu_proc_init);
512 #endif /* CONFIG_PROC_FS */