|
1 /* |
|
2 * Renesas SH7751R R2D-PLUS emulation |
|
3 * |
|
4 * Copyright (c) 2007 Magnus Damm |
|
5 * Copyright (c) 2008 Paul Mundt |
|
6 * |
|
7 * Permission is hereby granted, free of charge, to any person obtaining a copy |
|
8 * of this software and associated documentation files (the "Software"), to deal |
|
9 * in the Software without restriction, including without limitation the rights |
|
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
11 * copies of the Software, and to permit persons to whom the Software is |
|
12 * furnished to do so, subject to the following conditions: |
|
13 * |
|
14 * The above copyright notice and this permission notice shall be included in |
|
15 * all copies or substantial portions of the Software. |
|
16 * |
|
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
23 * THE SOFTWARE. |
|
24 */ |
|
25 |
|
26 #include "hw.h" |
|
27 #include "sh.h" |
|
28 #include "devices.h" |
|
29 #include "sysemu.h" |
|
30 #include "boards.h" |
|
31 #include "pci.h" |
|
32 #include "net.h" |
|
33 #include "sh7750_regs.h" |
|
34 |
|
35 #define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */ |
|
36 #define SDRAM_SIZE 0x04000000 |
|
37 |
|
38 #define SM501_VRAM_SIZE 0x800000 |
|
39 |
|
40 #define PA_IRLMSK 0x00 |
|
41 #define PA_POWOFF 0x30 |
|
42 #define PA_VERREG 0x32 |
|
43 #define PA_OUTPORT 0x36 |
|
44 |
|
45 typedef struct { |
|
46 uint16_t bcr; |
|
47 uint16_t irlmsk; |
|
48 uint16_t irlmon; |
|
49 uint16_t cfctl; |
|
50 uint16_t cfpow; |
|
51 uint16_t dispctl; |
|
52 uint16_t sdmpow; |
|
53 uint16_t rtcce; |
|
54 uint16_t pcicd; |
|
55 uint16_t voyagerrts; |
|
56 uint16_t cfrst; |
|
57 uint16_t admrts; |
|
58 uint16_t extrst; |
|
59 uint16_t cfcdintclr; |
|
60 uint16_t keyctlclr; |
|
61 uint16_t pad0; |
|
62 uint16_t pad1; |
|
63 uint16_t powoff; |
|
64 uint16_t verreg; |
|
65 uint16_t inport; |
|
66 uint16_t outport; |
|
67 uint16_t bverreg; |
|
68 |
|
69 /* output pin */ |
|
70 qemu_irq irl; |
|
71 } r2d_fpga_t; |
|
72 |
|
73 enum r2d_fpga_irq { |
|
74 PCI_INTD, CF_IDE, CF_CD, PCI_INTC, SM501, KEY, RTC_A, RTC_T, |
|
75 SDCARD, PCI_INTA, PCI_INTB, EXT, TP, |
|
76 NR_IRQS |
|
77 }; |
|
78 |
|
79 static const struct { short irl; uint16_t msk; } irqtab[NR_IRQS] = { |
|
80 [CF_IDE] = { 1, 1<<9 }, |
|
81 [CF_CD] = { 2, 1<<8 }, |
|
82 [PCI_INTA] = { 9, 1<<14 }, |
|
83 [PCI_INTB] = { 10, 1<<13 }, |
|
84 [PCI_INTC] = { 3, 1<<12 }, |
|
85 [PCI_INTD] = { 0, 1<<11 }, |
|
86 [SM501] = { 4, 1<<10 }, |
|
87 [KEY] = { 5, 1<<6 }, |
|
88 [RTC_A] = { 6, 1<<5 }, |
|
89 [RTC_T] = { 7, 1<<4 }, |
|
90 [SDCARD] = { 8, 1<<7 }, |
|
91 [EXT] = { 11, 1<<0 }, |
|
92 [TP] = { 12, 1<<15 }, |
|
93 }; |
|
94 |
|
95 static void update_irl(r2d_fpga_t *fpga) |
|
96 { |
|
97 int i, irl = 15; |
|
98 for (i = 0; i < NR_IRQS; i++) |
|
99 if (fpga->irlmon & fpga->irlmsk & irqtab[i].msk) |
|
100 if (irqtab[i].irl < irl) |
|
101 irl = irqtab[i].irl; |
|
102 qemu_set_irq(fpga->irl, irl ^ 15); |
|
103 } |
|
104 |
|
105 static void r2d_fpga_irq_set(void *opaque, int n, int level) |
|
106 { |
|
107 r2d_fpga_t *fpga = opaque; |
|
108 if (level) |
|
109 fpga->irlmon |= irqtab[n].msk; |
|
110 else |
|
111 fpga->irlmon &= ~irqtab[n].msk; |
|
112 update_irl(fpga); |
|
113 } |
|
114 |
|
115 static uint32_t r2d_fpga_read(void *opaque, target_phys_addr_t addr) |
|
116 { |
|
117 r2d_fpga_t *s = opaque; |
|
118 |
|
119 switch (addr) { |
|
120 case PA_IRLMSK: |
|
121 return s->irlmsk; |
|
122 case PA_OUTPORT: |
|
123 return s->outport; |
|
124 case PA_POWOFF: |
|
125 return s->powoff; |
|
126 case PA_VERREG: |
|
127 return 0x10; |
|
128 } |
|
129 |
|
130 return 0; |
|
131 } |
|
132 |
|
133 static void |
|
134 r2d_fpga_write(void *opaque, target_phys_addr_t addr, uint32_t value) |
|
135 { |
|
136 r2d_fpga_t *s = opaque; |
|
137 |
|
138 switch (addr) { |
|
139 case PA_IRLMSK: |
|
140 s->irlmsk = value; |
|
141 update_irl(s); |
|
142 break; |
|
143 case PA_OUTPORT: |
|
144 s->outport = value; |
|
145 break; |
|
146 case PA_POWOFF: |
|
147 s->powoff = value; |
|
148 break; |
|
149 case PA_VERREG: |
|
150 /* Discard writes */ |
|
151 break; |
|
152 } |
|
153 } |
|
154 |
|
155 static CPUReadMemoryFunc *r2d_fpga_readfn[] = { |
|
156 r2d_fpga_read, |
|
157 r2d_fpga_read, |
|
158 NULL, |
|
159 }; |
|
160 |
|
161 static CPUWriteMemoryFunc *r2d_fpga_writefn[] = { |
|
162 r2d_fpga_write, |
|
163 r2d_fpga_write, |
|
164 NULL, |
|
165 }; |
|
166 |
|
167 static qemu_irq *r2d_fpga_init(target_phys_addr_t base, qemu_irq irl) |
|
168 { |
|
169 int iomemtype; |
|
170 r2d_fpga_t *s; |
|
171 |
|
172 s = qemu_mallocz(sizeof(r2d_fpga_t)); |
|
173 if (!s) |
|
174 return NULL; |
|
175 |
|
176 s->irl = irl; |
|
177 |
|
178 iomemtype = cpu_register_io_memory(0, r2d_fpga_readfn, |
|
179 r2d_fpga_writefn, s); |
|
180 cpu_register_physical_memory(base, 0x40, iomemtype); |
|
181 return qemu_allocate_irqs(r2d_fpga_irq_set, s, NR_IRQS); |
|
182 } |
|
183 |
|
184 static void r2d_pci_set_irq(qemu_irq *p, int n, int l) |
|
185 { |
|
186 qemu_set_irq(p[n], l); |
|
187 } |
|
188 |
|
189 static int r2d_pci_map_irq(PCIDevice *d, int irq_num) |
|
190 { |
|
191 const int intx[] = { PCI_INTA, PCI_INTB, PCI_INTC, PCI_INTD }; |
|
192 return intx[d->devfn >> 3]; |
|
193 } |
|
194 |
|
195 static void r2d_init(ram_addr_t ram_size, int vga_ram_size, |
|
196 const char *boot_device, DisplayState * ds, |
|
197 const char *kernel_filename, const char *kernel_cmdline, |
|
198 const char *initrd_filename, const char *cpu_model) |
|
199 { |
|
200 CPUState *env; |
|
201 struct SH7750State *s; |
|
202 ram_addr_t sdram_addr, sm501_vga_ram_addr; |
|
203 qemu_irq *irq; |
|
204 PCIBus *pci; |
|
205 int i; |
|
206 |
|
207 if (!cpu_model) |
|
208 cpu_model = "SH7751R"; |
|
209 |
|
210 env = cpu_init(cpu_model); |
|
211 if (!env) { |
|
212 fprintf(stderr, "Unable to find CPU definition\n"); |
|
213 exit(1); |
|
214 } |
|
215 |
|
216 /* Allocate memory space */ |
|
217 sdram_addr = qemu_ram_alloc(SDRAM_SIZE); |
|
218 cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, sdram_addr); |
|
219 /* Register peripherals */ |
|
220 s = sh7750_init(env); |
|
221 irq = r2d_fpga_init(0x04000000, sh7750_irl(s)); |
|
222 pci = sh_pci_register_bus(r2d_pci_set_irq, r2d_pci_map_irq, irq, 0, 4); |
|
223 |
|
224 sm501_vga_ram_addr = qemu_ram_alloc(SM501_VRAM_SIZE); |
|
225 sm501_init(ds, 0x10000000, sm501_vga_ram_addr, SM501_VRAM_SIZE, |
|
226 serial_hds[2]); |
|
227 |
|
228 /* onboard CF (True IDE mode, Master only). */ |
|
229 mmio_ide_init(0x14001000, 0x1400080c, irq[CF_IDE], 1, |
|
230 drives_table[drive_get_index(IF_IDE, 0, 0)].bdrv, NULL); |
|
231 |
|
232 /* NIC: rtl8139 on-board, and 2 slots. */ |
|
233 pci_rtl8139_init(pci, &nd_table[0], 2 << 3); |
|
234 for (i = 1; i < nb_nics; i++) |
|
235 pci_nic_init(pci, &nd_table[i], -1); |
|
236 |
|
237 /* Todo: register on board registers */ |
|
238 { |
|
239 int kernel_size; |
|
240 /* initialization which should be done by firmware */ |
|
241 uint32_t bcr1 = 1 << 3; /* cs3 SDRAM */ |
|
242 uint16_t bcr2 = 3 << (3 * 2); /* cs3 32-bit */ |
|
243 cpu_physical_memory_write(SH7750_BCR1_A7, (uint8_t *)&bcr1, 4); |
|
244 cpu_physical_memory_write(SH7750_BCR2_A7, (uint8_t *)&bcr2, 2); |
|
245 |
|
246 kernel_size = load_image(kernel_filename, phys_ram_base); |
|
247 |
|
248 if (kernel_size < 0) { |
|
249 fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); |
|
250 exit(1); |
|
251 } |
|
252 |
|
253 env->pc = SDRAM_BASE | 0xa0000000; /* Start from P2 area */ |
|
254 } |
|
255 } |
|
256 |
|
257 QEMUMachine r2d_machine = { |
|
258 .name = "r2d", |
|
259 .desc = "r2d-plus board", |
|
260 .init = r2d_init, |
|
261 .ram_require = (SDRAM_SIZE + SM501_VRAM_SIZE) | RAMSIZE_FIXED, |
|
262 }; |