merage qemu master
[qemu/qemu-JZ.git] / hw / mips_jz_clk.c
blob60e85e290d3cf474650f2bafb07f8459d48b4e5e
1 /*
2 * JZ Soc clocks.
4 * Copyright (C) 2009 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",
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 static void jz_clk_update(struct clk *clk)
156 int parent, running;
157 //qemu_irq *user;
158 struct clk *i;
160 if (clk->parent)
161 parent = clk->parent->running;
162 else
163 parent = 1;
165 running = parent && (clk->enabled ||
166 ((clk->flags & ALWAYS_ENABLED)));
167 if (clk->running != running)
169 clk->running = running;
170 //for (user = clk->users; *user; user ++)
171 // qemu_set_irq(*user, running);
172 for (i = clk->child1; i; i = i->sibling)
173 jz_clk_update(i);
177 static void jz_clk_rate_update_full(struct clk *clk, unsigned long int rate,
178 unsigned long int div,
179 unsigned long int mult)
181 struct clk *i;
182 //qemu_irq *user;
184 clk->rate = muldiv64(rate, mult, div);
185 if (clk->running)
186 //for (user = clk->users; *user; user ++)
187 // qemu_irq_raise(*user);
188 for (i = clk->child1; i; i = i->sibling)
189 jz_clk_rate_update_full(i, rate,
190 div * i->divisor, mult * i->multiplier);
193 static void jz_clk_rate_update(struct clk *clk)
195 struct clk *i;
196 unsigned long int div, mult = div = 1;
198 for (i = clk; i->parent; i = i->parent)
200 div *= i->divisor;
201 mult *= i->multiplier;
204 jz_clk_rate_update_full(clk, i->rate, div, mult);
207 void jz_clk_reparent(struct clk *clk, struct clk *parent)
209 struct clk **p;
211 if (clk->parent)
213 for (p = &clk->parent->child1; *p != clk; p = &(*p)->sibling);
214 *p = clk->sibling;
217 clk->parent = parent;
218 if (parent)
220 clk->sibling = parent->child1;
221 parent->child1 = clk;
222 jz_clk_update(clk);
223 jz_clk_rate_update(clk);
225 else
226 clk->sibling = 0;
229 void jz_clk_onoff(struct clk *clk, int on)
231 clk->enabled = on;
232 jz_clk_update(clk);
235 void jz_clk_setrate(struct clk *clk, int divide, int multiply)
237 clk->divisor = divide;
238 clk->multiplier = multiply;
239 jz_clk_rate_update(clk);
242 int64_t jz_clk_getrate(struct clk *clk)
244 return clk->rate;
247 void jz_clk_init(struct jz_state_s *mpu, uint32_t osc_extal_freq)
249 struct clk **i, *j, *k;
250 int count;
251 int flag;
253 if (cpu_is_jz4730(mpu))
254 flag = CLOCK_IN_JZ4730;
255 else if (cpu_is_jz4740(mpu))
256 flag = CLOCK_IN_JZ4740;
257 else if (cpu_is_jz4750(mpu))
258 flag = CLOCK_IN_JZ4750;
259 else
260 return;
262 osc_extal.rate = osc_extal_freq;
264 for (i = onchip_clks, count = 0; *i; i++)
265 if ((*i)->flags & flag)
266 count++;
267 mpu->clks = (struct clk *) qemu_mallocz(sizeof(struct clk) * (count + 1));
268 for (i = onchip_clks, j = mpu->clks; *i; i++)
269 if ((*i)->flags & flag)
271 memcpy(j, *i, sizeof(struct clk));
272 for (k = mpu->clks; k < j; k++)
273 if (j->parent && !strcmp(j->parent->name, k->name))
275 j->parent = k;
276 j->sibling = k->child1;
277 k->child1 = j;
279 else if (k->parent && !strcmp(k->parent->name, j->name))
281 k->parent = j;
282 k->sibling = j->child1;
283 j->child1 = k;
285 j->divisor = j->divisor ? : 1;
286 j->multiplier = j->multiplier ? : 1;
287 j++;
289 for (j = mpu->clks; count--; j++)
291 jz_clk_update(j);
292 jz_clk_rate_update(j);