2 * QEMU JZ Soc emulation
4 * Copyright (c) 2008 yajin (yajin@vm-kernel.org)
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 * The emulation target is pavo demo board.
28 * http://www.ingenic.cn/eng/productServ/kfyd/Hardware/pffaqQuestionContent.aspx?Category=2&Question=3
36 #include "qemu-timer.h"
37 #include "qemu-char.h"
40 #include "audio/audio.h"
42 #define DEBUG_CPM (1<<0x1)
44 #define DEBUG_FLAG (DEBUG_CPM)
49 static void debug_init()
51 fp
= fopen("jz4740.txt", "w+");
54 fprintf(stderr
, "can not open jz4740.txt \n");
58 static void debug_out(uint32_t flag
, const char *format
, ...)
63 if (flag
& DEBUG_FLAG
)
66 vfprintf(fp
, format
, ap
);
73 static void debug_init()
76 static void debug_out(uint32_t flag
, const char *format
, ...)
81 uint32_t jz4740_badwidth_read8(void *opaque
, target_phys_addr_t addr
)
86 cpu_physical_memory_read(addr
, (void *) &ret
, 1);
90 void jz4740_badwidth_write8(void *opaque
, target_phys_addr_t addr
,
96 cpu_physical_memory_write(addr
, (void *) &val8
, 1);
99 uint32_t jz4740_badwidth_read16(void *opaque
, target_phys_addr_t addr
)
102 JZ4740_16B_REG(addr
);
103 cpu_physical_memory_read(addr
, (void *) &ret
, 2);
107 void jz4740_badwidth_write16(void *opaque
, target_phys_addr_t addr
,
110 uint16_t val16
= value
;
112 JZ4740_16B_REG(addr
);
113 cpu_physical_memory_write(addr
, (void *) &val16
, 2);
116 uint32_t jz4740_badwidth_read32(void *opaque
, target_phys_addr_t addr
)
120 JZ4740_32B_REG(addr
);
121 cpu_physical_memory_read(addr
, (void *) &ret
, 4);
125 void jz4740_badwidth_write32(void *opaque
, target_phys_addr_t addr
,
128 JZ4740_32B_REG(addr
);
129 cpu_physical_memory_write(addr
, (void *) &value
, 4);
133 /*clock reset and power control*/
136 target_phys_addr_t base
;
137 struct jz_state_s
*soc
;
149 static inline void jz4740_dump_clocks(struct clk
*parent
)
151 struct clk
*i
= parent
;
153 debug_out(DEBUG_CPM
, "clock %x rate 0x%x \n", i
->name
, i
->rate
);
154 for (i
= clk
->child1
; i
; i
= i
->sibling
)
155 jz4740_dump_clocks(i
);
158 static inline void jz4740_cpccr_update(struct jz4740_cpm_s
*s
,
161 uint32_t ldiv
, mdiv
, pdiv
, hdiv
, cdiv
, udiv
;
162 uint32_t div_table
[10] = { 1, 2, 3, 4, 6, 8, 12, 16, 24, 32 };
164 if (unlikely(new_value
== s
->cpccr
))
167 if (new_value
& CPM_CPCCR_PCS
)
168 jz_clk_setrate(jz_findclk(s
->cpu
, "pll_divider"), 1, 1);
170 jz_clk_setrate(jz_findclk(s
->cpu
, "pll_divider"), 2, 1);
173 ldiv
= (new_value
& CPM_CPCCR_LDIV_MASK
) >> CPM_CPCCR_LDIV_BIT
;
176 mdiv
= div_table
[(new_value
& CPM_CPCCR_MDIV_MASK
) >> CPM_CPCCR_MDIV_BIT
];
177 pdiv
= div_table
[(new_value
& CPM_CPCCR_PDIV_MASK
) >> CPM_CPCCR_PDIV_BIT
];
178 hdiv
= div_table
[(new_value
& CPM_CPCCR_HDIV_MASK
) >> CPM_CPCCR_HDIV_BIT
];
179 cdiv
= div_table
[(new_value
& CPM_CPCCR_CDIV_MASK
) >> CPM_CPCCR_CDIV_BIT
];
180 udiv
= div_table
[(new_value
& CPM_CPCCR_UDIV_MASK
) >> CPM_CPCCR_UDIV_BIT
];
182 jz_clk_setrate(jz_findclk(s
->cpu
, "ldclk"), ldiv
, 1);
183 jz_clk_setrate(jz_findclk(s
->cpu
, "mclk"), mdiv
, 1);
184 jz_clk_setrate(jz_findclk(s
->cpu
, "pclk"), pdiv
, 1);
185 jz_clk_setrate(jz_findclk(s
->cpu
, "hclk"), hdiv
, 1);
186 jz_clk_setrate(jz_findclk(s
->cpu
, "cclk"), cdiv
, 1);
187 jz_clk_setrate(jz_findclk(s
->cpu
, "usbclk"), udiv
, 1);
189 if (new_value
& CPM_CPCCR_UCS
)
190 jz_clk_reparent(jz_findclk(s
->cpu
, "usbclk"),
191 jz_findclk(s
->cpu
, "pll_divider"));
193 jz_clk_reparent(jz_findclk(s
->cpu
, "usbclk"),
194 jz_findclk(s
->cpu
, "osc_extal"));
196 if (new_value
& CPM_CPCCR_I2CS
)
197 jz_clk_reparent(jz_findclk(s
->cpu
, "i2sclk"),
198 jz_findclk(s
->cpu
, "pll_divider"));
200 jz_clk_reparent(jz_findclk(s
->cpu
, "i2sclk"),
201 jz_findclk(s
->cpu
, "osc_extal"));
203 s
->cpccr
= new_value
;
205 debug_out(DEBUG_CPM
, "write to cpccr 0x%x\n", new_value
);
206 jz4740_dump_clocks(jz_findclk(s
->cpu
, "osc_extal"));
210 static inline void jz4740_cppcr_update(struct jz4740_cpm_s
*s
,
213 uint32_t pllm
, plln
, pllod
, pllbp
, pllen
, pllst
, pllen
, pllbp
;
214 uint32_t pll0
[4] = { 1, 2, 2, 4 };
217 pllen
= new_value
& CPM_CPPCR_PLLEN
;
218 pllbp
= new_value
& CPM_CPPCR_PLLBP
;
219 if ((!pllen
) || (pllen
&& pllbp
))
221 jz_clk_setrate(jz_findclk(s
->cpu
, "pll_output"), 1, 1);
222 debug_out(DEBUG_CPM
, "pll is bypassed \n");
223 s
->cppcr
= new_value
| CPM_CPPCR_PLLS
;
228 pllm
= (new_value
& CPM_CPPCR_PLLM_MASK
) >> CPM_CPPCR_PLLM_BIT
;
229 plln
= (new_value
& CPM_CPPCR_PLLN_MASK
) >> CPM_CPPCR_PLLN_BIT
;
230 pllod
= (new_value
& CPM_CPPCR_PLLOD_MASK
) >> CPM_CPPCR_PLLOD_BIT
;
231 jz_clk_setrate(jz_findclk(s
->cpu
, "pll_output"), (plln
+ 2) * pll0
[pllod
],
234 s
->cppcr
= new_value
;
236 debug_out(DEBUG_CPM
, "write to cppcr 0x%x\n", new_value
);
237 jz4740_dump_clocks(jz_findclk(s
->cpu
, "osc_extal"));
241 static inline void jz4740_i2scdr_update(struct jz4740_cpm_s
*s
,
246 i2scdr
= new_value
& CPM_I2SCDR_I2SDIV_MASK
;
247 if (unlikely(i2scdr
== s
->i2scdr
))
251 jz_clk_setrate(jz_findclk(s
->cpu
, "i2sclk"), i2scdr
+ 1, 1);
255 debug_out(DEBUG_CPM
, "write to i2scdr 0x%x\n", new_value
);
256 jz4740_dump_clocks(jz_findclk(s
->cpu
, "osc_extal"));
260 static inline void jz4740_lpcdr_update(struct jz4740_cpm_s
*s
,
265 ipcdr
= new_value
& CPM_LPCDR_PIXDIV_MASK
;
270 static inline void jz4740_msccdr_update(struct jz4740_cpm_s
*s
,
275 msccdr
= new_value
& CPM_MSCCDR_MSCDIV_MASK
;
277 if (unlikely(msccdr
== s
->msccdr
))
281 jz_clk_setrate(jz_findclk(s
->cpu
, "mscclk"), msccdr
+ 1, 1);
285 debug_out(DEBUG_CPM
, "write to msccdr 0x%x\n", new_value
);
286 jz4740_dump_clocks(jz_findclk(s
->cpu
, "osc_extal"));
290 static inline void jz4740_uhccdr_update(struct jz4740_cpm_s
*s
,
295 uhccdr
= new_value
& 0xf;
300 static void jz4740_cpm_write(void *opaque
, target_phys_addr_t addr
,
303 struct jz4740_cpm_s
*s
= (struct jz4740_cpm_s
*) opaque
;
304 int offset
= addr
- s
->base
;
309 jz4740_cpccr_update(s
, value
);
312 jz4740_cppcr_update(s
, value
);
315 jz4740_i2scdr_update(s
, value
);
318 jz4740_lpcdr_update(s
, value
);
321 jz4740_msccdr_update(s
, value
);
324 jz4740_uhccdr_update(s
, value
);
327 s
->uhctst
= value
& 0x3f;
330 s
->ssicdr
= value
& 0xf;
333 cpu_abort(s
->cpu
->env
,
334 "jz4740_cpm_write undefined addr " JZ_FMT_plx
" value %x \n",
341 static uint32_t jz474_cpm_read(void *opaque
, target_phys_addr_t addr
)
343 struct jz4740_cpm_s
*s
= (struct jz4740_cpm_s
*) opaque
;
344 int offset
= addr
- s
->base
;
365 cpu_abort(s
->cpu
->env
,
366 "jz474_cpm_read undefined addr " JZ_FMT_plx
" \n", addr
);
373 static CPUReadMemoryFunc
*jz4740_cpm_readfn
[] = {
374 jz4740_badwidth_read32
,
375 jz4740_badwidth_read32
,
379 static CPUWriteMemoryFunc
*jz4740_cpm_writefn
[] = {
380 jz4740_badwidth_write32
,
381 jz4740_badwidth_write32
,
385 static void jz4740_cpm_reset(struct jz4740_cpm_s
*s
)
387 s
->cpccr
= 0x42040000;
388 s
->cppcr
= 0x28080011;
389 s
->i2scdr
= 0x00000004;
390 s
->lpcdr
= 0x00000004;
391 s
->msccdr
= 0x00000004;
392 s
->uhccdr
= 0x00000004;
394 s
->ssicdr
= 0x00000004;
397 static struct jz4740_cpm_s
*jz4740_cpm_init(struct jz_state_s
*soc
)
400 struct jz4740_cpm_s
*s
= (struct jz4740_cpm_s
*) qemu_mallocz(sizeof(*s
));
401 s
->base
= JZ4740_PHYS_BASE(JZ4740_CPM_BASE
);
407 cpu_register_io_memory(0, jz4740_cpm_readfn
, jz4740_cpm_writefn
, s
);
408 cpu_register_physical_memory(s
->base
, 0x00001000, iomemtype
);
412 /* JZ4740 interrupt controller
413 * It issues INT2 to MIPS
419 target_phys_addr_t base
;
420 struct jz_state_s
*soc
;
429 static uint32_t jz4740_intc_read(void *opaque
, target_phys_addr_t addr
)
431 struct jz4740_intc_s
*s
= (struct jz4740_intc_s
*) opaque
;
432 int offset
= addr
- s
->base
;
446 cpu_abort(s
->cpu
->env
,
447 "jz4740_intc_read undefined addr " JZ_FMT_plx
" \n", addr
);
452 static void jz4740_intc_write(void *opaque
, target_phys_addr_t addr
,
455 struct jz4740_intc_s
*s
= (struct jz4740_intc_s
*) opaque
;
456 int offset
= addr
- s
->base
;
474 cpu_abort(s
->cpu
->env
,
475 "jz4740_intc_write undefined addr value %x" JZ_FMT_plx
" \n",
481 static CPUReadMemoryFunc
*jz4740_intc_readfn
[] = {
482 jz4740_badwidth_read32
,
483 jz4740_badwidth_read32
,
487 static CPUWriteMemoryFunc
*jz4740_intc_writefn
[] = {
488 jz4740_badwidth_write32
,
489 jz4740_badwidth_write32
,
493 static void jz4740_intc_reset(struct jz4740_intc_s
*s
)
496 s
->icmr
= 0xffffffff;
500 static void jz4740_set_irq(void *opaque
, int irq
, int level
)
502 struct jz4740_intc_s
*s
= (struct jz4740_intc_s
*) opaque
;
503 uint32_t irq_mask
= 1<<irq
;
509 if ((~s
->icmr
)&irq_mask
)
510 qemu_set_irq(s
->parent_irq
,1);
512 qemu_set_irq(s
->parent_irq
,0);
515 static qemu_irq
*jz4740_intc_init(struct jz_state_s
*soc
,qemu_irq parent_irq
)
518 struct jz4740_intc_s
*s
= (struct jz4740_intc_s
*) qemu_mallocz(sizeof(*s
));
519 s
->base
= JZ4740_PHYS_BASE(JZ4740_INTC_BASE
);
520 s
->parent_irq
= parent_irq
;
523 jz4740_intc_reset(s
);
526 cpu_register_io_memory(0, jz4740_intc_readfn
, jz4740_intc_writefn
, s
);
527 cpu_register_physical_memory(s
->base
, 0x00001000, iomemtype
);
528 return qemu_allocate_irqs(jz4740_set_irq
, s
, 32);
531 /*external memory controller*/
535 target_phys_addr_t base
;
536 struct jz_state_s
*soc
;
538 uint32_t smcr1
; /*0x13010014*/
539 uint32_t smcr2
; /*0x13010018*/
540 uint32_t smcr3
; /*0x1301001c*/
541 uint32_t smcr4
; /*0x13010020*/
542 uint32_t sacr1
; /*0x13010034*/
543 uint32_t sacr2
; /*0x13010038*/
544 uint32_t sacr3
; /*0x1301003c*/
545 uint32_t sacr4
; /*0x13010040*/
547 uint32_t nfcsr
; /*0x13010050*/
548 uint32_t nfeccr
; /*0x13010100*/
549 uint32_t nfecc
; /*0x13010104*/
550 uint32_t nfpar0
; /*0x13010108*/
551 uint32_t nfpar1
; /*0x1301010c*/
552 uint32_t nfpar2
; /*0x13010110*/
553 uint32_t nfints
; /*0x13010114*/
554 uint32_t nfinte
; /*0x13010118*/
555 uint32_t nferr0
; /*0x1301011c*/
556 uint32_t nferr1
; /*0x13010120*/
557 uint32_t nferr2
; /*0x13010124*/
558 uint32_t nferr3
; /*0x13010128*/
560 uint32_t dmcr
; /*0x13010080*/
561 uint32_t rtcsr
; /*0x13010084*/
562 uint32_t rtcnt
; /*0x13010088*/
563 uint32_t rtcor
; /*0x1301008c*/
564 uint32_t dmar
; /*0x13010090*/
565 uint32_t sdmr
; /*0x1301a000*/
569 static void jz4740_emc_init(struct jz_state_s
*soc
,qemu_irq irq
)
574 struct jz_state_s
*jz4740_init(unsigned long sdram_size
,
575 uint32_t osc_extal_freq
)
577 struct jz_state_s
*s
= (struct jz_state_s
*)
578 qemu_mallocz(sizeof(struct jz_state_s
));
579 ram_addr_t sram_base
, sdram_base
;
582 s
->mpu_model
= jz4740
;
583 s
->env
= cpu_init("jz4740");
587 fprintf(stderr
, "Unable to find CPU definition\n");
590 qemu_register_reset(main_cpu_reset
, env
);
592 s
->sdram_size
= sdram_size
;
593 s
->sram_size
= JZ4740_SRAM_SIZE
;
595 /*map sram to 0x80000000 and sdram to 0x80004000 */
596 sram_base
= qemu_ram_alloc(s
->sram_size
);
597 cpu_register_physical_memory(JZ4740_SRAM_BASE
, s
->sram_size
,
598 (sram_base
| IO_MEM_RAM
));
599 sdram_base
= qemu_ram_alloc(s
->sdram_size
);
600 cpu_register_physical_memory(JZ4740_SDRAM_BASE
, s
->sdram_size
,
601 (sdram_base
| IO_MEM_RAM
));
603 /* Init internal devices */
604 cpu_mips_irq_init_cpu(env
);
605 cpu_mips_clock_init(env
);
609 jz_clk_init(s
, osc_extal_freq
);
611 intc
= jz4740_intc_init(s
,s
->env
->irq
[2]);