c5ac296a24e6aea8085e862c4b646d8f218b8b84
[qemu/qemu-JZ.git] / hw / mips_jz_clk.c
blobc5ac296a24e6aea8085e862c4b646d8f218b8b84
1 /*
2 * JZ Soc clocks.
4 * Copyright (C) 2006-2008 yajin <yajin@vm-kernel.org>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 * MA 02111-1307 USA
23 #include "hw.h"
24 #include "mips_jz.h"
28 #define ALWAYS_ENABLED (1 << 0)
29 #define CLOCK_IN_JZ4730 (1 << 10)
30 #define CLOCK_IN_JZ4740 (1 << 11)
31 #define CLOCK_IN_JZ4750 (1 << 12)
35 static struct clk osc_extal = {
36 .name = "osc_extal_12M",
37 .rate = 12000000,
38 .flags = ALWAYS_ENABLED | CLOCK_IN_JZ4740,
41 static struct clk osc_32K = {
42 .name = "osc_32K",
43 .rate = 32768,
44 .flags = ALWAYS_ENABLED | CLOCK_IN_JZ4740,
47 static struct clk lcd_pclk = {
48 .name = "lcd_pclk",
49 //.rate = ??,
50 //.flags = ALWAYS_ENABLED | CLOCK_IN_JZ4740,
53 static struct clk pll_output = {
54 .name = "pll_output",
55 .parent = &osc_extal,
56 .flags = ALWAYS_ENABLED | CLOCK_IN_JZ4740,
59 static struct clk pll_divider = {
60 .name = "pll_divider",
61 .parent = &pll_output,
62 .flags = ALWAYS_ENABLED | CLOCK_IN_JZ4740,
65 static struct clk cclk = {
66 .name = "cclk",
67 .parent = &pll_output,
68 .flags = ALWAYS_ENABLED | CLOCK_IN_JZ4740,
71 static struct clk pclk = {
72 .name = "pclk",
73 .parent = &pll_output,
74 .flags = ALWAYS_ENABLED | CLOCK_IN_JZ4740,
77 static struct clk hclk = {
78 .name = "hclk",
79 .parent = &pll_output,
80 .flags = ALWAYS_ENABLED | CLOCK_IN_JZ4740,
83 static struct clk mclk = {
84 .name = "mclk",
85 .parent = &pll_output,
86 .flags = ALWAYS_ENABLED | CLOCK_IN_JZ4740,
89 static struct clk ldclk = {
90 .name = "ldclk",
91 .parent = &pll_divider,
92 .flags = ALWAYS_ENABLED | CLOCK_IN_JZ4740,
95 static struct clk lpclk = {
96 .name = "lpclk",
97 .parent = &pll_divider,
98 .flags = ALWAYS_ENABLED | CLOCK_IN_JZ4740,
101 static struct clk i2sclk = {
102 .name = "i2sclk",
103 .parent = &pll_divider,
104 .flags = ALWAYS_ENABLED | CLOCK_IN_JZ4740,
107 static struct clk mscclk = {
108 .name = "mscclk",
109 .parent = &pll_divider,
110 .flags = ALWAYS_ENABLED | CLOCK_IN_JZ4740,
113 static struct clk usbclk = {
114 .name = "usbclk",
115 .parent = &pll_divider,
116 .flags = ALWAYS_ENABLED | CLOCK_IN_JZ4740,
119 static struct clk ssiclk = {
120 .name = "ssiclk",
121 .parent = &pll_divider,
122 .flags = ALWAYS_ENABLED | CLOCK_IN_JZ4740,
126 static struct clk *onchip_clks[] = {
127 &osc_extal,
128 &lcd_pclk,
129 &osc_32K,
130 &pll_output,
131 &pll_divider,
132 &cclk,
133 &pclk,
134 &hclk,
135 &mclk,
136 &ldclk,
137 &lpclk,
138 &i2sclk,
139 &mscclk,
140 &usbclk,
141 &ssiclk,
144 struct clk *jz_findclk(struct jz_state_s *cpu, const char *name)
146 struct clk *i;
148 for (i = cpu->clks; i->name; i++)
149 if (!strcmp(i->name, name) || (i->alias && !strcmp(i->alias, name)))
150 return i;
151 cpu_abort(cpu->env, "%s: %s not found\n", __FUNCTION__, name);
154 void jz_clk_get(struct clk *clk)
156 clk->usecount++;
159 void jz_clk_put(struct clk *clk)
161 if (!(clk->usecount--))
162 cpu_abort(cpu_single_env, "%s: %s is not in use\n",
163 __FUNCTION__, clk->name);
166 static void jz_clk_update(struct clk *clk)
168 int parent, running;
169 //qemu_irq *user;
170 struct clk *i;
172 if (clk->parent)
173 parent = clk->parent->running;
174 else
175 parent = 1;
177 running = parent && (clk->enabled ||
178 ((clk->flags & ALWAYS_ENABLED) && clk->usecount));
179 if (clk->running != running)
181 clk->running = running;
182 //for (user = clk->users; *user; user ++)
183 // qemu_set_irq(*user, running);
184 for (i = clk->child1; i; i = i->sibling)
185 jz_clk_update(i);
189 static void jz_clk_rate_update_full(struct clk *clk, unsigned long int rate,
190 unsigned long int div,
191 unsigned long int mult)
193 struct clk *i;
194 //qemu_irq *user;
196 clk->rate = muldiv64(rate, mult, div);
197 if (clk->running)
198 //for (user = clk->users; *user; user ++)
199 // qemu_irq_raise(*user);
200 for (i = clk->child1; i; i = i->sibling)
201 jz_clk_rate_update_full(i, rate,
202 div * i->divisor, mult * i->multiplier);
205 static void jz_clk_rate_update(struct clk *clk)
207 struct clk *i;
208 unsigned long int div, mult = div = 1;
210 for (i = clk; i->parent; i = i->parent)
212 div *= i->divisor;
213 mult *= i->multiplier;
216 jz_clk_rate_update_full(clk, i->rate, div, mult);
219 void jz_clk_reparent(struct clk *clk, struct clk *parent)
221 struct clk **p;
223 if (clk->parent)
225 for (p = &clk->parent->child1; *p != clk; p = &(*p)->sibling);
226 *p = clk->sibling;
229 clk->parent = parent;
230 if (parent)
232 clk->sibling = parent->child1;
233 parent->child1 = clk;
234 jz_clk_update(clk);
235 jz_clk_rate_update(clk);
237 else
238 clk->sibling = 0;
241 void jz_clk_onoff(struct clk *clk, int on)
243 clk->enabled = on;
244 jz_clk_update(clk);
247 void jz_clk_canidle(struct clk *clk, int can)
249 if (can)
250 jz_clk_put(clk);
251 else
252 jz_clk_get(clk);
255 void jz_clk_setrate(struct clk *clk, int divide, int multiply)
257 clk->divisor = divide;
258 clk->multiplier = multiply;
259 jz_clk_rate_update(clk);
262 int64_t jz_clk_getrate(struct clk *clk)
264 return clk->rate;
267 void jz_clk_init(struct jz_state_s *mpu, uint32_t osc_extal_freq)
269 struct clk **i, *j, *k;
270 int count;
271 int flag;
273 if (cpu_is_jz4730(mpu))
274 flag = CLOCK_IN_JZ4730;
275 else if (cpu_is_jz4740(mpu))
276 flag = CLOCK_IN_JZ4740;
277 else if (cpu_is_jz4750(mpu))
278 flag = CLOCK_IN_JZ4750;
279 else
280 return;
282 osc_extal.rate = osc_extal_freq;
284 for (i = onchip_clks, count = 0; *i; i++)
285 if ((*i)->flags & flag)
286 count++;
287 mpu->clks = (struct clk *) qemu_mallocz(sizeof(struct clk) * (count + 1));
288 for (i = onchip_clks, j = mpu->clks; *i; i++)
289 if ((*i)->flags & flag)
291 memcpy(j, *i, sizeof(struct clk));
292 for (k = mpu->clks; k < j; k++)
293 if (j->parent && !strcmp(j->parent->name, k->name))
295 j->parent = k;
296 j->sibling = k->child1;
297 k->child1 = j;
299 else if (k->parent && !strcmp(k->parent->name, j->name))
301 k->parent = j;
302 k->sibling = j->child1;
303 j->child1 = k;
305 j->divisor = j->divisor ? : 1;
306 j->multiplier = j->multiplier ? : 1;
307 j++;
309 for (j = mpu->clks; count--; j++)
311 jz_clk_update(j);
312 jz_clk_rate_update(j);