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,
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",
38 .flags
= ALWAYS_ENABLED
| CLOCK_IN_JZ4740
,
41 static struct clk osc_32K
= {
44 .flags
= ALWAYS_ENABLED
| CLOCK_IN_JZ4740
,
47 static struct clk lcd_pclk
= {
50 //.flags = ALWAYS_ENABLED | CLOCK_IN_JZ4740,
53 static struct clk pll_output
= {
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
= {
67 .parent
= &pll_output
,
68 .flags
= ALWAYS_ENABLED
| CLOCK_IN_JZ4740
,
71 static struct clk pclk
= {
73 .parent
= &pll_output
,
74 .flags
= ALWAYS_ENABLED
| CLOCK_IN_JZ4740
,
77 static struct clk hclk
= {
79 .parent
= &pll_output
,
80 .flags
= ALWAYS_ENABLED
| CLOCK_IN_JZ4740
,
83 static struct clk mclk
= {
85 .parent
= &pll_output
,
86 .flags
= ALWAYS_ENABLED
| CLOCK_IN_JZ4740
,
89 static struct clk ldclk
= {
91 .parent
= &pll_divider
,
92 .flags
= ALWAYS_ENABLED
| CLOCK_IN_JZ4740
,
95 static struct clk lpclk
= {
97 .parent
= &pll_divider
,
98 .flags
= ALWAYS_ENABLED
| CLOCK_IN_JZ4740
,
101 static struct clk i2sclk
= {
103 .parent
= &pll_divider
,
104 .flags
= ALWAYS_ENABLED
| CLOCK_IN_JZ4740
,
107 static struct clk mscclk
= {
109 .parent
= &pll_divider
,
110 .flags
= ALWAYS_ENABLED
| CLOCK_IN_JZ4740
,
113 static struct clk usbclk
= {
115 .parent
= &pll_divider
,
116 .flags
= ALWAYS_ENABLED
| CLOCK_IN_JZ4740
,
119 static struct clk ssiclk
= {
121 .parent
= &pll_divider
,
122 .flags
= ALWAYS_ENABLED
| CLOCK_IN_JZ4740
,
126 static struct clk
*onchip_clks
[] = {
144 struct clk
*jz_findclk(struct jz_state_s
*cpu
, const char *name
)
148 for (i
= cpu
->clks
; i
->name
; i
++)
149 if (!strcmp(i
->name
, name
) || (i
->alias
&& !strcmp(i
->alias
, name
)))
151 cpu_abort(cpu
->env
, "%s: %s not found\n", __FUNCTION__
, name
);
154 void jz_clk_get(struct clk
*clk
)
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
)
173 parent
= clk
->parent
->running
;
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
)
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
)
196 clk
->rate
= muldiv64(rate
, mult
, div
);
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
)
208 unsigned long int div
, mult
= div
= 1;
210 for (i
= clk
; i
->parent
; i
= i
->parent
)
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
)
225 for (p
= &clk
->parent
->child1
; *p
!= clk
; p
= &(*p
)->sibling
);
229 clk
->parent
= parent
;
232 clk
->sibling
= parent
->child1
;
233 parent
->child1
= clk
;
235 jz_clk_rate_update(clk
);
241 void jz_clk_onoff(struct clk
*clk
, int on
)
247 void jz_clk_canidle(struct clk
*clk
, int can
)
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
)
267 void jz_clk_init(struct jz_state_s
*mpu
, uint32_t osc_extal_freq
)
269 struct clk
**i
, *j
, *k
;
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
;
282 osc_extal
.rate
= osc_extal_freq
;
284 for (i
= onchip_clks
, count
= 0; *i
; i
++)
285 if ((*i
)->flags
& flag
)
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
))
296 j
->sibling
= k
->child1
;
299 else if (k
->parent
&& !strcmp(k
->parent
->name
, j
->name
))
302 k
->sibling
= j
->child1
;
305 j
->divisor
= j
->divisor
? : 1;
306 j
->multiplier
= j
->multiplier
? : 1;
309 for (j
= mpu
->clks
; count
--; j
++)
312 jz_clk_rate_update(j
);