• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/arch/arm/plat-brcm/
1/*
2 * Northstar DMU (Device Management Unit),
3 * i.e. clocks, I/O pads, GPIO etc.
4 * SoC-specific hardware support features.
5 *
6 * Documents:
7 * Northstar_top_power_uarch_v1_0.pdf
8 *
9 * Copyright (C) 2014, Broadcom Corporation. All Rights Reserved.
10 *
11 * Permission to use, copy, modify, and/or distribute this software for any
12 * purpose with or without fee is hereby granted, provided that the above
13 * copyright notice and this permission notice appear in all copies.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 *
23 * $Id: $
24 */
25#include <linux/kernel.h>
26#include <linux/init.h>
27#include <linux/module.h>
28#include <linux/errno.h>
29#include <linux/err.h>
30#include <linux/clk.h>
31#include <linux/io.h>
32#include <linux/ioport.h>
33#include <linux/delay.h>
34#include <linux/proc_fs.h>
35
36#include <asm/clkdev.h>
37#include <mach/clkdev.h>
38#include <mach/io_map.h>
39#include <plat/plat-bcm5301x.h>
40
41#ifdef CONFIG_PROC_FS
42#define DMU_PROC_NAME	"dmu"
43#endif /* CONFIG_PROC_FS */
44
45static struct resource dmu_regs = {
46	.name = "dmu_regs",
47	.start = SOC_DMU_BASE_PA,
48	.end = SOC_DMU_BASE_PA + SZ_4K -1,
49	.flags = IORESOURCE_MEM,
50};
51
52/*
53 * Clock management scheme is a provisional implementation
54 * only intended to retreive the pre-set frequencies for each
55 * of the clocks.
56 * Better handling of post-dividers and fractional part of
57 * feedbeck dividers need to be added.
58 * Need to understand what diagnostics from CRU registers could
59 * be handy, and export that via a sysfs interface.
60 */
61
62/*
63 * The CRU contains two similar PLLs: LCPLL and GENPLL,
64 * both with several output channels divided from the PLL
65 * output
66 */
67
68/*
69 * Get PLL running status and update output frequency
70 */
71static int lcpll_status(struct clk * clk)
72{
73	u32 reg;
74	u64 x;
75	unsigned pdiv, ndiv_int, ndiv_frac;
76
77	if (clk->type != CLK_PLL)
78		return -EINVAL;
79
80	/* read status register */
81	reg = readl(clk->regs_base + 0x10);
82
83	/* bit 12 is "lock" signal, has to be "1" for proper PLL operation */
84	if ((reg & (1 << 12)) == 0) {
85		clk->rate = 0;
86	}
87
88	/* Update PLL frequency */
89
90	/* control1 register */
91	reg = readl(clk->regs_base + 0x04);
92
93	/* feedback divider integer and fraction parts */
94	pdiv = (reg >> 28) & 7;
95	ndiv_int = (reg >> 20) & 0xff;
96	ndiv_frac = reg & ((1<<20)-1);
97
98	if (pdiv == 0)
99		return -EIO;
100
101	x = clk->parent->rate / pdiv;
102
103	x = x * ((u64) ndiv_int << 20 | ndiv_frac);
104
105	clk->rate = x >> 20;
106
107	return 0;
108}
109
110static const struct clk_ops lcpll_ops = {
111	.status = lcpll_status,
112};
113
114static int lcpll_chan_status(struct clk * clk)
115{
116	void * __iomem base;
117	u32 reg;
118	unsigned enable;
119	unsigned mdiv;
120
121	if (clk->parent == NULL || clk->type != CLK_DIV)
122		return -EINVAL;
123
124	/* Register address is only stored in PLL structure */
125	base = clk->parent->regs_base;
126	BUG_ON(base == NULL);
127
128	/* enable bit is in enableb_ch[] inversed */
129	enable = ((readl(base + 0) >> 6) & 7) ^ 7;
130
131	if ((enable & (1 << clk->chan)) == 0) {
132		clk->rate = 0;
133		return -EIO;
134	}
135
136	/* get divider */
137	reg = readl(base + 0x08);
138
139	mdiv = 0xff & (reg >> ((0x3^clk->chan) << 3));
140
141	/* when divisor is 0, it behaves as max+1 */
142	if (mdiv == 0)
143		mdiv = 1 << 8;
144
145	clk->rate = (clk->parent->rate / mdiv);
146	return 0;
147}
148
149
150static const struct clk_ops lcpll_chan_ops = {
151	.status = lcpll_chan_status,
152};
153
154/*
155 * LCPLL has 4 output channels
156 */
157static struct clk clk_lcpll = {
158	.ops 	= &lcpll_ops,
159	.name 	= "LCPLL",
160	.type	= CLK_PLL,
161	.chan	=	4,
162};
163
164/*
165 * LCPLL output clocks -
166 * chan 0 - PCIe ref clock, should be 1 GHz,
167 * chan 1 - SDIO clock, e.g. 200 MHz,
168 * chan 2 - DDR clock, typical 166.667 MHz for DDR667,
169 * chan 3 - Unknown
170 */
171
172static struct clk clk_lcpll_ch[4] = {
173	{.ops = &lcpll_chan_ops, .parent = &clk_lcpll, .type = CLK_DIV,
174	.name = "lcpll_ch0", .chan = 0},
175	{.ops = &lcpll_chan_ops, .parent = &clk_lcpll, .type = CLK_DIV,
176	.name = "lcpll_ch1", .chan = 1},
177	{.ops = &lcpll_chan_ops, .parent = &clk_lcpll, .type = CLK_DIV,
178	.name = "lcpll_ch2", .chan = 2},
179	{.ops = &lcpll_chan_ops, .parent = &clk_lcpll, .type = CLK_DIV,
180	.name = "lcpll_ch3", .chan = 3},
181};
182
183/*
184 * Get PLL running status and update output frequency
185 */
186static int genpll_status(struct clk * clk)
187{
188	u32 reg;
189	u64 x;
190	unsigned pdiv, ndiv_int, ndiv_frac;
191
192	if (clk->type != CLK_PLL)
193		return -EINVAL;
194
195	/* Offset of the PLL status register */
196	reg = readl(clk->regs_base + 0x20);
197
198	/* bit 12 is "lock" signal, has to be "1" for proper PLL operation */
199	if ((reg & (1 << 12)) == 0) {
200		clk->rate = 0;
201		return -EIO;
202	}
203
204	/* Update PLL frequency */
205
206	/* get PLL feedback divider values from control5 */
207	reg = readl(clk->regs_base + 0x14);
208
209	/* feedback divider integer and fraction parts */
210	ndiv_int = reg >> 20;
211	ndiv_frac = reg & ((1<<20)-1);
212
213	/* get pdiv */
214	reg = readl(clk->regs_base + 0x18);
215	pdiv = (reg >> 24) & 7;
216
217	if (pdiv == 0)
218		return -EIO;
219
220	x = clk->parent->rate / pdiv;
221
222	x = x * ((u64)ndiv_int << 20 | ndiv_frac);
223
224	clk->rate = x >> 20;
225
226	return 0;
227}
228
229static const struct clk_ops genpll_ops = {
230	.status = genpll_status,
231};
232
233static int genpll_chan_status(struct clk * clk)
234{
235	void * __iomem base;
236	u32 reg;
237	unsigned enable;
238	unsigned mdiv;
239	unsigned off, shift;
240
241	if (clk->parent == NULL || clk->type != CLK_DIV)
242		return -EINVAL;
243
244	/* Register address is only stored in PLL structure */
245	base = clk->parent->regs_base;
246
247	BUG_ON(base == NULL);
248
249	/* enable bit is in enableb_ch[0..5] inversed */
250	enable = ((readl(base + 0x04) >> 12) & 0x3f) ^ 0x3f;
251
252	if ((enable & (1 << clk->chan)) == 0) {
253		clk->rate = 0;
254		return -EIO;
255	}
256
257	/* GENPLL has the 6 channels spread over two regs */
258	switch (clk->chan)
259		{
260		case 0:
261			off = 0x18; shift = 16;
262			break;
263
264		case 1:
265			off = 0x18; shift = 8;
266			break;
267
268		case 2:
269			off = 0x18; shift = 0;
270			break;
271
272		case 3:
273			off = 0x1c; shift = 16;
274			break;
275
276		case 4:
277			off = 0x1c; shift = 8;
278			break;
279
280		case 5:
281			off = 0x1c; shift = 0;
282			break;
283
284		default:
285			BUG_ON(clk->chan);
286			off = shift = 0;	/* fend off warnings */
287		}
288
289	reg = readl(base + off);
290
291	mdiv = 0xff & (reg >> shift);
292
293	/* when divisor is 0, it behaves as max+1 */
294	if (mdiv == 0)
295		mdiv = 1 << 8;
296
297	clk->rate = clk->parent->rate / mdiv;
298	return 0;
299}
300
301
302static const struct clk_ops genpll_chan_ops = {
303	.status = genpll_chan_status,
304};
305
306
307/*
308 * GENPLL has 6 output channels
309 */
310static struct clk clk_genpll = {
311	.ops	= &genpll_ops,
312	.name	= "GENPLL",
313	.type	= CLK_PLL,
314	.chan	= 6,
315};
316
317/*
318 * chan 0 - Ethernet switch and MAC, RGMII, need 250 MHz
319 * chan 1 - Ethernet switch slow clock, 150 Mhz
320 * chan 2 - USB PHY clock, need 30 MHz
321 * chan 3 - iProc N MHz clock, set from OTP
322 * chan 4 - iProc N/2 MHz clock, set from OTP
323 * chan 5 - iProc N/4 MHz clock, set from OTP
324 *
325 */
326
327static struct clk clk_genpll_ch[6] = {
328	{.ops = &genpll_chan_ops, .parent = &clk_genpll, .type = CLK_DIV,
329	.name = "genpll_ch0", .chan = 0},
330	{.ops = &genpll_chan_ops, .parent = &clk_genpll, .type = CLK_DIV,
331	.name = "genpll_ch1", .chan = 1},
332	{.ops = &genpll_chan_ops, .parent = &clk_genpll, .type = CLK_DIV,
333	.name = "genpll_ch2", .chan = 2},
334	{.ops = &genpll_chan_ops, .parent = &clk_genpll, .type = CLK_DIV,
335	.name = "genpll_ch3", .chan = 3},
336	{.ops = &genpll_chan_ops, .parent = &clk_genpll, .type = CLK_DIV,
337	.name = "genpll_ch4", .chan = 4},
338	{.ops = &genpll_chan_ops, .parent = &clk_genpll, .type = CLK_DIV,
339	.name = "genpll_ch5", .chan = 5}
340};
341
342/*
343 * This table is used to locate clock sources
344 * from device drivers
345 */
346
347static struct clk_lookup soc_clk_lookups[] = {
348	/* a.k.a. "c_clk100" */
349	{.con_id = "pcie_clk", .clk = &clk_lcpll_ch[0]},
350	/* a.k.a. "c_clk200" */
351	{.con_id = "sdio_clk", .clk = &clk_lcpll_ch[1]},
352	/* a.k.a. "c_clk400" */
353	{.con_id = "ddr_clk", .clk = &clk_lcpll_ch[2]},
354	/* unassigned ? */
355	{.con_id = "c_clk120", .clk = &clk_lcpll_ch[3]},
356	/* "c_clk250" */
357	{.con_id = "en_phy_clk", .clk = &clk_genpll_ch[0]},
358	/* "c_clk150" */
359	{.con_id = "en_clk", .clk = &clk_genpll_ch[1]},
360	/* "c_clk30" */
361	{.con_id = "usb_phy_clk", .clk = &clk_genpll_ch[2]},
362	/* "c_clk500" */
363	{.con_id = "iproc_fast_clk", .clk = &clk_genpll_ch[3]},
364	/* "c_clk250" */
365	{.con_id = "iproc_med_clk", .clk = &clk_genpll_ch[4]},
366	/* "c_clk125" */
367	{.con_id = "iproc_slow_clk", .clk = &clk_genpll_ch[5]}
368};
369
370void dmu_gpiomux_init(void)
371{
372#ifdef CONFIG_PLAT_MUX_CONSOLE
373	void * __iomem reg_addr;
374	u32 reg;
375
376	/* CRU_RESET register */
377	reg_addr = (void *)(SOC_DMU_BASE_VA + 0x1c0);
378
379	/* set iproc_reset_n to 0 to use UART1, but it never comes back */
380	reg = readl(reg_addr);
381	reg &= ~((u32)0xf << 12);
382	writel(reg, reg_addr);
383#endif /* CONFIG_PLAT_MUX_CONSOLE */
384}
385
386/*
387 * Install above clocks into clock lookup table
388 * and initialize the register base address for each
389*/
390static void __init soc_clocks_init(void * __iomem cru_regs_base,
391	struct clk * clk_ref)
392{
393	void * __iomem reg;
394	u32 val;
395
396	/* registers are already mapped with the rest of DMU block */
397	/* Update register base address */
398	clk_lcpll.regs_base = cru_regs_base + 0x00;
399	clk_genpll.regs_base = cru_regs_base + 0x40;
400
401	/* Set parent as reference ckock */
402	clk_lcpll.parent = clk_ref;
403	clk_genpll.parent = clk_ref;
404
405#ifdef	__DEPRECATED__
406	{
407	int i;
408	/* We need to clear dev_id fields in the lookups,
409	 * because if it is set, it will not match by con_id
410	 */
411	for (i = 0; i < ARRAY_SIZE(soc_clk_lookups); i++)
412		soc_clk_lookups[i].dev_id = NULL;
413	}
414#endif
415
416	/* Install clock sources into the lookup table */
417	clkdev_add_table(soc_clk_lookups, ARRAY_SIZE(soc_clk_lookups));
418
419	/* Correct GMAC 2.66G line rate issue, it should be 2Gbps */
420	/* This incorrect setting only exist in OTP present 4708 chip */
421	/* is a OTPed 4708 chip which Ndiv == 0x50 */
422	reg = clk_genpll.regs_base + 0x14;
423	val = readl(reg);
424	if (((val >> 20) & 0x3ff) == 0x50) {
425		/* CRU_CLKSET_KEY, unlock */
426		reg = clk_genpll.regs_base + 0x40;
427		val = 0x0000ea68;
428		writel(val, reg);
429
430		/* Change CH0_MDIV to 8 */
431		/* After changing the CH0_MDIV to 8, the customer has been reporting that
432		 * there are differences between input throughput vs. output throughput.
433		 * The output throughput is slightly lower (927.537 mbps input rate vs. 927.49
434		 * mbps output rate).  Below is the solution to fix it.
435		 * 1. Change the oscillator on WLAN reference board from 25.000 to 25.001
436		 * 2. Change the CH0_MDIV to 7
437		 */
438		reg = clk_genpll.regs_base + 0x18;
439		val = readl(reg);
440		val &= ~((u32)0xff << 16);
441		val |= ((u32)0x7 << 16);
442		writel(val, reg);
443
444		/* Load Enable CH0 */
445		reg = clk_genpll.regs_base + 0x4;
446		val = readl(reg);
447		val &= ~(u32)0x1;
448		writel(val, reg);
449		val |= (u32)0x1;
450		writel(val, reg);
451		val &= ~(u32)0x1;
452		writel(val, reg);
453
454		/* CRU_CLKSET_KEY, lock */
455		reg = clk_genpll.regs_base + 0x40;
456		val = 0x0;
457		writel(val, reg);
458	}
459}
460
461void __init soc_dmu_init(struct clk *clk_ref)
462{
463	void * __iomem 	reg_base;
464
465	if (IS_ERR_OR_NULL(clk_ref)) {
466		printk(KERN_ERR "DMU no clock source - skip init\n");
467		return;
468	}
469
470	BUG_ON(request_resource(&iomem_resource, &dmu_regs));
471
472	/* DMU regs are mapped as part of the fixed mapping with CCA+CCB */
473	reg_base = (void *)SOC_DMU_BASE_VA;
474
475	BUG_ON(IS_ERR_OR_NULL(reg_base));
476
477	/* Initialize clocks */
478	soc_clocks_init(reg_base + 0x100, clk_ref); /* CRU LCPLL control0 */
479
480	dmu_gpiomux_init();
481}
482
483
484
485
486
487
488void soc_clocks_show(void)
489{
490	unsigned i;
491
492	printk("DMU Clocks:\n");
493	for (i = 0; i < ARRAY_SIZE(soc_clk_lookups); i++) {
494		printk("%s, %s: (%s) %lu\n",
495			soc_clk_lookups[i].con_id,
496			soc_clk_lookups[i].dev_id,
497			soc_clk_lookups[i].clk->name,
498			clk_get_rate(soc_clk_lookups[i].clk));
499	}
500
501	printk("DMU Clocks# %u\n", i);
502}
503
504#ifdef CONFIG_PROC_FS
505static int dmu_temperature_status(char * buffer, char **start,
506	off_t offset, int length, int * eof, void * data)
507{
508	int len;
509	off_t pos, begin;
510	void *__iomem pvtmon_base;
511	u32 pvtmon_control0, pvtmon_status;
512	int temperature;
513
514	len = 0;
515	pos = begin = 0;
516
517	pvtmon_base = (void *)(SOC_DMU_BASE_VA + 0x2c0);	/* PVTMON control0 */
518
519	pvtmon_control0 = readl(pvtmon_base);
520	if (pvtmon_control0 & 0xf) {
521		pvtmon_control0 &= ~0xf;
522		writel(pvtmon_control0, pvtmon_base);
523	}
524
525	pvtmon_status = readl(pvtmon_base + 0x8);
526	temperature = 418 - ((5556 * pvtmon_status) / 10000);
527
528	len += sprintf(buffer + len, "CPU temperature\t: %d%cC\n\n",
529		temperature, 0xF8);
530
531	pos = begin + len;
532
533	if (pos < offset) {
534		len = 0;
535		begin = pos;
536	}
537
538	*eof = 1;
539
540	*start = buffer + (offset - begin);
541	len -= (offset - begin);
542
543	if (len > length)
544		len = length;
545
546	return len;
547}
548
549static void __init dmu_proc_init(void)
550{
551	struct proc_dir_entry *dmu, *dmu_temp;
552
553	dmu = proc_mkdir(DMU_PROC_NAME, NULL);
554
555	if (!dmu) {
556		printk(KERN_ERR "DMU create proc directory failed.\n");
557		return;
558	}
559
560	dmu_temp = create_proc_read_entry(DMU_PROC_NAME "/temperature", 0, NULL,
561		dmu_temperature_status, NULL);
562
563	if (!dmu_temp)
564		printk(KERN_ERR "DMU create proc entry failed.\n");
565}
566fs_initcall(dmu_proc_init);
567#endif /* CONFIG_PROC_FS */
568