Linux Audio

Check our new training course

Loading...
  1/*
  2 * linux/arch/unicore32/kernel/clock.c
  3 *
  4 * Code specific to PKUnity SoC and UniCore ISA
  5 *
  6 *	Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
  7 *	Copyright (C) 2001-2010 Guan Xuetao
  8 *
  9 * This program is free software; you can redistribute it and/or modify
 10 * it under the terms of the GNU General Public License version 2 as
 11 * published by the Free Software Foundation.
 12 */
 13#include <linux/module.h>
 14#include <linux/kernel.h>
 15#include <linux/device.h>
 16#include <linux/list.h>
 17#include <linux/errno.h>
 18#include <linux/err.h>
 19#include <linux/string.h>
 20#include <linux/clk.h>
 21#include <linux/mutex.h>
 22#include <linux/delay.h>
 23#include <linux/io.h>
 24
 25#include <mach/hardware.h>
 26
 27/*
 28 * Very simple clock implementation
 29 */
 30struct clk {
 31	struct list_head	node;
 32	unsigned long		rate;
 33	const char		*name;
 34};
 35
 36static struct clk clk_ost_clk = {
 37	.name		= "OST_CLK",
 38	.rate		= CLOCK_TICK_RATE,
 39};
 40
 41static struct clk clk_mclk_clk = {
 42	.name		= "MAIN_CLK",
 43};
 44
 45static struct clk clk_bclk32_clk = {
 46	.name		= "BUS32_CLK",
 47};
 48
 49static struct clk clk_ddr_clk = {
 50	.name		= "DDR_CLK",
 51};
 52
 53static struct clk clk_vga_clk = {
 54	.name		= "VGA_CLK",
 55};
 56
 57static LIST_HEAD(clocks);
 58static DEFINE_MUTEX(clocks_mutex);
 59
 60struct clk *clk_get(struct device *dev, const char *id)
 61{
 62	struct clk *p, *clk = ERR_PTR(-ENOENT);
 63
 64	mutex_lock(&clocks_mutex);
 65	list_for_each_entry(p, &clocks, node) {
 66		if (strcmp(id, p->name) == 0) {
 67			clk = p;
 68			break;
 69		}
 70	}
 71	mutex_unlock(&clocks_mutex);
 72
 73	return clk;
 74}
 75EXPORT_SYMBOL(clk_get);
 76
 77void clk_put(struct clk *clk)
 78{
 79}
 80EXPORT_SYMBOL(clk_put);
 81
 82int clk_enable(struct clk *clk)
 83{
 84	return 0;
 85}
 86EXPORT_SYMBOL(clk_enable);
 87
 88void clk_disable(struct clk *clk)
 89{
 90}
 91EXPORT_SYMBOL(clk_disable);
 92
 93unsigned long clk_get_rate(struct clk *clk)
 94{
 95	return clk->rate;
 96}
 97EXPORT_SYMBOL(clk_get_rate);
 98
 99struct {
100	unsigned long rate;
101	unsigned long cfg;
102	unsigned long div;
103} vga_clk_table[] = {
104	{.rate =  25175000, .cfg = 0x00002001, .div = 0x9},
105	{.rate =  31500000, .cfg = 0x00002001, .div = 0x7},
106	{.rate =  40000000, .cfg = 0x00003801, .div = 0x9},
107	{.rate =  49500000, .cfg = 0x00003801, .div = 0x7},
108	{.rate =  65000000, .cfg = 0x00002c01, .div = 0x4},
109	{.rate =  78750000, .cfg = 0x00002400, .div = 0x7},
110	{.rate = 108000000, .cfg = 0x00002c01, .div = 0x2},
111	{.rate = 106500000, .cfg = 0x00003c01, .div = 0x3},
112	{.rate =  50650000, .cfg = 0x00106400, .div = 0x9},
113	{.rate =  61500000, .cfg = 0x00106400, .div = 0xa},
114	{.rate =  85500000, .cfg = 0x00002800, .div = 0x6},
115};
116
117struct {
118	unsigned long mrate;
119	unsigned long prate;
120} mclk_clk_table[] = {
121	{.mrate = 500000000, .prate = 0x00109801},
122	{.mrate = 525000000, .prate = 0x00104C00},
123	{.mrate = 550000000, .prate = 0x00105000},
124	{.mrate = 575000000, .prate = 0x00105400},
125	{.mrate = 600000000, .prate = 0x00105800},
126	{.mrate = 625000000, .prate = 0x00105C00},
127	{.mrate = 650000000, .prate = 0x00106000},
128	{.mrate = 675000000, .prate = 0x00106400},
129	{.mrate = 700000000, .prate = 0x00106800},
130	{.mrate = 725000000, .prate = 0x00106C00},
131	{.mrate = 750000000, .prate = 0x00107000},
132	{.mrate = 775000000, .prate = 0x00107400},
133	{.mrate = 800000000, .prate = 0x00107800},
134};
135
136int clk_set_rate(struct clk *clk, unsigned long rate)
137{
138	if (clk == &clk_vga_clk) {
139		unsigned long pll_vgacfg, pll_vgadiv;
140		int ret, i;
141
142		/* lookup vga_clk_table */
143		ret = -EINVAL;
144		for (i = 0; i < ARRAY_SIZE(vga_clk_table); i++) {
145			if (rate == vga_clk_table[i].rate) {
146				pll_vgacfg = vga_clk_table[i].cfg;
147				pll_vgadiv = vga_clk_table[i].div;
148				ret = 0;
149				break;
150			}
151		}
152
153		if (ret)
154			return ret;
155
156		if (readl(PM_PLLVGACFG) == pll_vgacfg)
157			return 0;
158
159		/* set pll vga cfg reg. */
160		writel(pll_vgacfg, PM_PLLVGACFG);
161
162		writel(PM_PMCR_CFBVGA, PM_PMCR);
163		while ((readl(PM_PLLDFCDONE) & PM_PLLDFCDONE_VGADFC)
164				!= PM_PLLDFCDONE_VGADFC)
165			udelay(100); /* about 1ms */
166
167		/* set div cfg reg. */
168		writel(readl(PM_PCGR) | PM_PCGR_VGACLK, PM_PCGR);
169
170		writel((readl(PM_DIVCFG) & ~PM_DIVCFG_VGACLK_MASK)
171				| PM_DIVCFG_VGACLK(pll_vgadiv), PM_DIVCFG);
172
173		writel(readl(PM_SWRESET) | PM_SWRESET_VGADIV, PM_SWRESET);
174		while ((readl(PM_SWRESET) & PM_SWRESET_VGADIV)
175				== PM_SWRESET_VGADIV)
176			udelay(100); /* 65536 bclk32, about 320us */
177
178		writel(readl(PM_PCGR) & ~PM_PCGR_VGACLK, PM_PCGR);
179	}
180#ifdef CONFIG_CPU_FREQ
181	if (clk == &clk_mclk_clk) {
182		u32 pll_rate, divstatus = PM_DIVSTATUS;
183		int ret, i;
184
185		/* lookup mclk_clk_table */
186		ret = -EINVAL;
187		for (i = 0; i < ARRAY_SIZE(mclk_clk_table); i++) {
188			if (rate == mclk_clk_table[i].mrate) {
189				pll_rate = mclk_clk_table[i].prate;
190				clk_mclk_clk.rate = mclk_clk_table[i].mrate;
191				ret = 0;
192				break;
193			}
194		}
195
196		if (ret)
197			return ret;
198
199		if (clk_mclk_clk.rate)
200			clk_bclk32_clk.rate = clk_mclk_clk.rate
201				/ (((divstatus & 0x0000f000) >> 12) + 1);
202
203		/* set pll sys cfg reg. */
204		PM_PLLSYSCFG = pll_rate;
205
206		PM_PMCR = PM_PMCR_CFBSYS;
207		while ((PM_PLLDFCDONE & PM_PLLDFCDONE_SYSDFC)
208				!= PM_PLLDFCDONE_SYSDFC)
209			udelay(100);
210			/* about 1ms */
211	}
212#endif
213	return 0;
214}
215EXPORT_SYMBOL(clk_set_rate);
216
217int clk_register(struct clk *clk)
218{
219	mutex_lock(&clocks_mutex);
220	list_add(&clk->node, &clocks);
221	mutex_unlock(&clocks_mutex);
222	printk(KERN_DEFAULT "PKUnity PM: %s %lu.%02luM\n", clk->name,
223		(clk->rate)/1000000, (clk->rate)/10000 % 100);
224	return 0;
225}
226EXPORT_SYMBOL(clk_register);
227
228void clk_unregister(struct clk *clk)
229{
230	mutex_lock(&clocks_mutex);
231	list_del(&clk->node);
232	mutex_unlock(&clocks_mutex);
233}
234EXPORT_SYMBOL(clk_unregister);
235
236struct {
237	unsigned long prate;
238	unsigned long rate;
239} pllrate_table[] = {
240	{.prate = 0x00002001, .rate = 250000000},
241	{.prate = 0x00104801, .rate = 250000000},
242	{.prate = 0x00104C01, .rate = 262500000},
243	{.prate = 0x00002401, .rate = 275000000},
244	{.prate = 0x00105001, .rate = 275000000},
245	{.prate = 0x00105401, .rate = 287500000},
246	{.prate = 0x00002801, .rate = 300000000},
247	{.prate = 0x00105801, .rate = 300000000},
248	{.prate = 0x00105C01, .rate = 312500000},
249	{.prate = 0x00002C01, .rate = 325000000},
250	{.prate = 0x00106001, .rate = 325000000},
251	{.prate = 0x00106401, .rate = 337500000},
252	{.prate = 0x00003001, .rate = 350000000},
253	{.prate = 0x00106801, .rate = 350000000},
254	{.prate = 0x00106C01, .rate = 362500000},
255	{.prate = 0x00003401, .rate = 375000000},
256	{.prate = 0x00107001, .rate = 375000000},
257	{.prate = 0x00107401, .rate = 387500000},
258	{.prate = 0x00003801, .rate = 400000000},
259	{.prate = 0x00107801, .rate = 400000000},
260	{.prate = 0x00107C01, .rate = 412500000},
261	{.prate = 0x00003C01, .rate = 425000000},
262	{.prate = 0x00108001, .rate = 425000000},
263	{.prate = 0x00108401, .rate = 437500000},
264	{.prate = 0x00004001, .rate = 450000000},
265	{.prate = 0x00108801, .rate = 450000000},
266	{.prate = 0x00108C01, .rate = 462500000},
267	{.prate = 0x00004401, .rate = 475000000},
268	{.prate = 0x00109001, .rate = 475000000},
269	{.prate = 0x00109401, .rate = 487500000},
270	{.prate = 0x00004801, .rate = 500000000},
271	{.prate = 0x00109801, .rate = 500000000},
272	{.prate = 0x00104C00, .rate = 525000000},
273	{.prate = 0x00002400, .rate = 550000000},
274	{.prate = 0x00105000, .rate = 550000000},
275	{.prate = 0x00105400, .rate = 575000000},
276	{.prate = 0x00002800, .rate = 600000000},
277	{.prate = 0x00105800, .rate = 600000000},
278	{.prate = 0x00105C00, .rate = 625000000},
279	{.prate = 0x00002C00, .rate = 650000000},
280	{.prate = 0x00106000, .rate = 650000000},
281	{.prate = 0x00106400, .rate = 675000000},
282	{.prate = 0x00003000, .rate = 700000000},
283	{.prate = 0x00106800, .rate = 700000000},
284	{.prate = 0x00106C00, .rate = 725000000},
285	{.prate = 0x00003400, .rate = 750000000},
286	{.prate = 0x00107000, .rate = 750000000},
287	{.prate = 0x00107400, .rate = 775000000},
288	{.prate = 0x00003800, .rate = 800000000},
289	{.prate = 0x00107800, .rate = 800000000},
290	{.prate = 0x00107C00, .rate = 825000000},
291	{.prate = 0x00003C00, .rate = 850000000},
292	{.prate = 0x00108000, .rate = 850000000},
293	{.prate = 0x00108400, .rate = 875000000},
294	{.prate = 0x00004000, .rate = 900000000},
295	{.prate = 0x00108800, .rate = 900000000},
296	{.prate = 0x00108C00, .rate = 925000000},
297	{.prate = 0x00004400, .rate = 950000000},
298	{.prate = 0x00109000, .rate = 950000000},
299	{.prate = 0x00109400, .rate = 975000000},
300	{.prate = 0x00004800, .rate = 1000000000},
301	{.prate = 0x00109800, .rate = 1000000000},
302};
303
304struct {
305	unsigned long prate;
306	unsigned long drate;
307} pddr_table[] = {
308	{.prate = 0x00100800, .drate = 44236800},
309	{.prate = 0x00100C00, .drate = 66355200},
310	{.prate = 0x00101000, .drate = 88473600},
311	{.prate = 0x00101400, .drate = 110592000},
312	{.prate = 0x00101800, .drate = 132710400},
313	{.prate = 0x00101C01, .drate = 154828800},
314	{.prate = 0x00102001, .drate = 176947200},
315	{.prate = 0x00102401, .drate = 199065600},
316	{.prate = 0x00102801, .drate = 221184000},
317	{.prate = 0x00102C01, .drate = 243302400},
318	{.prate = 0x00103001, .drate = 265420800},
319	{.prate = 0x00103401, .drate = 287539200},
320	{.prate = 0x00103801, .drate = 309657600},
321	{.prate = 0x00103C01, .drate = 331776000},
322	{.prate = 0x00104001, .drate = 353894400},
323};
324
325static int __init clk_init(void)
326{
327#ifdef CONFIG_PUV3_PM
328	u32 pllrate, divstatus = readl(PM_DIVSTATUS);
329	u32 pcgr_val = readl(PM_PCGR);
330	int i;
331
332	pcgr_val |= PM_PCGR_BCLKMME | PM_PCGR_BCLKH264E | PM_PCGR_BCLKH264D
333			| PM_PCGR_HECLK | PM_PCGR_HDCLK;
334	writel(pcgr_val, PM_PCGR);
335
336	pllrate = readl(PM_PLLSYSSTATUS);
337
338	/* lookup pmclk_table */
339	clk_mclk_clk.rate = 0;
340	for (i = 0; i < ARRAY_SIZE(pllrate_table); i++) {
341		if (pllrate == pllrate_table[i].prate) {
342			clk_mclk_clk.rate = pllrate_table[i].rate;
343			break;
344		}
345	}
346
347	if (clk_mclk_clk.rate)
348		clk_bclk32_clk.rate = clk_mclk_clk.rate /
349			(((divstatus & 0x0000f000) >> 12) + 1);
350
351	pllrate = readl(PM_PLLDDRSTATUS);
352
353	/* lookup pddr_table */
354	clk_ddr_clk.rate = 0;
355	for (i = 0; i < ARRAY_SIZE(pddr_table); i++) {
356		if (pllrate == pddr_table[i].prate) {
357			clk_ddr_clk.rate = pddr_table[i].drate;
358			break;
359		}
360	}
361
362	pllrate = readl(PM_PLLVGASTATUS);
363
364	/* lookup pvga_table */
365	clk_vga_clk.rate = 0;
366	for (i = 0; i < ARRAY_SIZE(pllrate_table); i++) {
367		if (pllrate == pllrate_table[i].prate) {
368			clk_vga_clk.rate = pllrate_table[i].rate;
369			break;
370		}
371	}
372
373	if (clk_vga_clk.rate)
374		clk_vga_clk.rate = clk_vga_clk.rate /
375			(((divstatus & 0x00f00000) >> 20) + 1);
376
377	clk_register(&clk_vga_clk);
378#endif
379#ifdef CONFIG_ARCH_FPGA
380	clk_ddr_clk.rate = 33000000;
381	clk_mclk_clk.rate = 33000000;
382	clk_bclk32_clk.rate = 33000000;
383#endif
384	clk_register(&clk_ddr_clk);
385	clk_register(&clk_mclk_clk);
386	clk_register(&clk_bclk32_clk);
387	clk_register(&clk_ost_clk);
388	return 0;
389}
390core_initcall(clk_init);