These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / openbios / drivers / obio.c
1 /*
2  *   OpenBIOS Sparc OBIO driver
3  *
4  *   (C) 2004 Stefan Reinauer <stepan@openbios.org>
5  *   (C) 2005 Ed Schouten <ed@fxq.nl>
6  *
7  *   This program is free software; you can redistribute it and/or
8  *   modify it under the terms of the GNU General Public License
9  *   version 2
10  *
11  */
12
13 #include "config.h"
14 #include "libopenbios/bindings.h"
15 #include "kernel/kernel.h"
16 #include "libc/byteorder.h"
17 #include "libc/vsprintf.h"
18
19 #include "drivers/drivers.h"
20 #include "arch/common/nvram.h"
21 #include "libopenbios/ofmem.h"
22 #include "obio.h"
23 #include "escc.h"
24
25 #define PROMDEV_KBD     0               /* input from keyboard */
26 #define PROMDEV_SCREEN  0               /* output to screen */
27 #define PROMDEV_TTYA    1               /* in/out to ttya */
28
29
30 void
31 ob_new_obio_device(const char *name, const char *type)
32 {
33     push_str("/obio");
34     fword("find-device");
35     fword("new-device");
36
37     push_str(name);
38     fword("device-name");
39
40     if (type) {
41         push_str(type);
42         fword("device-type");
43     }
44 }
45
46 static unsigned long
47 map_reg(uint64_t base, uint64_t offset, unsigned long size, int map,
48         int phys_hi)
49 {
50     PUSH(phys_hi);
51     fword("encode-int");
52     PUSH(offset);
53     fword("encode-int");
54     fword("encode+");
55     PUSH(size);
56     fword("encode-int");
57     fword("encode+");
58     push_str("reg");
59     fword("property");
60
61     if (map) {
62         unsigned long addr;
63
64         addr = (unsigned long)ofmem_map_io(base + offset, size);
65
66         PUSH(addr);
67         fword("encode-int");
68         push_str("address");
69         fword("property");
70         return addr;
71     }
72     return 0;
73 }
74
75 unsigned long
76 ob_reg(uint64_t base, uint64_t offset, unsigned long size, int map)
77 {
78     return map_reg(base, offset, size, map, 0);
79 }
80
81 void
82 ob_intr(int intr)
83 {
84     PUSH(intr);
85     fword("encode-int");
86     PUSH(0);
87     fword("encode-int");
88     fword("encode+");
89     push_str("intr");
90     fword("property");
91 }
92
93 void
94 ob_eccmemctl_init(uint64_t base)
95 {
96     uint32_t version, *regs;
97     const char *mc_type;
98
99     push_str("/");
100     fword("find-device");
101     fword("new-device");
102
103     push_str("eccmemctl");
104     fword("device-name");
105
106     PUSH(0x20);
107     fword("encode-int");
108     push_str("width");
109     fword("property");
110
111     regs = (uint32_t *)map_reg(ECC_BASE, 0, ECC_SIZE, 1, ECC_BASE >> 32);
112
113     version = regs[0];
114     switch (version) {
115     case 0x00000000:
116         mc_type = "MCC";
117         break;
118     case 0x10000000:
119         mc_type = "EMC";
120         break;
121     default:
122     case 0x20000000:
123         mc_type = "SMC";
124         break;
125     }
126     push_str(mc_type);
127     fword("encode-string");
128     push_str("mc-type");
129     fword("property");
130
131     fword("finish-device");
132 }
133
134 static unsigned char *nvram;
135
136 #define NVRAM_OB_START   (0)
137 #define NVRAM_OB_SIZE    ((NVRAM_IDPROM - NVRAM_OB_START) & ~15)
138
139 void
140 arch_nvram_get(char *data)
141 {
142     memcpy(data, &nvram[NVRAM_OB_START], NVRAM_OB_SIZE);
143 }
144
145 void
146 arch_nvram_put(char *data)
147 {
148     memcpy(&nvram[NVRAM_OB_START], data, NVRAM_OB_SIZE);
149 }
150
151 int
152 arch_nvram_size(void)
153 {
154     return NVRAM_OB_SIZE;
155 }
156
157 void
158 ss5_init(uint64_t base)
159 {
160     ob_new_obio_device("slavioconfig", NULL);
161
162     ob_reg(base, SLAVIO_SCONFIG, SCONFIG_REGS, 0);
163
164     fword("finish-device");
165 }
166
167 static void
168 ob_nvram_init(uint64_t base, uint64_t offset)
169 {
170     ob_new_obio_device("eeprom", NULL);
171
172     nvram = (unsigned char *)ob_reg(base, offset, NVRAM_SIZE, 1);
173
174     PUSH((unsigned long)nvram);
175     fword("encode-int");
176     push_str("address");
177     fword("property");
178
179     push_str("mk48t08");
180     fword("model");
181
182     fword("finish-device");
183
184     // Add /idprom
185     push_str("/");
186     fword("find-device");
187
188     PUSH((long)&nvram[NVRAM_IDPROM]);
189     PUSH(32);
190     fword("encode-bytes");
191     push_str("idprom");
192     fword("property");
193 }
194
195 static void
196 ob_fd_init(uint64_t base, uint64_t offset, int intr)
197 {
198     unsigned long addr;
199
200     ob_new_obio_device("SUNW,fdtwo", "block");
201
202     addr = ob_reg(base, offset, FD_REGS, 1);
203
204     ob_intr(intr);
205
206     fword("is-deblocker");
207
208     ob_floppy_init("/obio", "SUNW,fdtwo", 0, addr);
209
210     fword("finish-device");
211 }
212
213 static void
214 ob_auxio_init(uint64_t base, uint64_t offset)
215 {
216     ob_new_obio_device("auxio", NULL);
217
218     ob_reg(base, offset, AUXIO_REGS, 1);
219
220     fword("finish-device");
221 }
222
223 volatile unsigned char *power_reg;
224 volatile unsigned int *reset_reg;
225
226 static void
227 sparc32_reset_all(void)
228 {
229     *reset_reg = 1;
230 }
231
232 // AUX 2 (Software Powerdown Control) and reset
233 static void
234 ob_aux2_reset_init(uint64_t base, uint64_t offset, int intr)
235 {
236     ob_new_obio_device("power", NULL);
237
238     power_reg = (void *)ob_reg(base, offset, AUXIO2_REGS, 1);
239
240     // Not in device tree
241     reset_reg = (unsigned int *)ofmem_map_io(base + (uint64_t)SLAVIO_RESET, RESET_REGS);
242
243     bind_func("sparc32-reset-all", sparc32_reset_all);
244     push_str("' sparc32-reset-all to reset-all");
245     fword("eval");
246
247     ob_intr(intr);
248
249     fword("finish-device");
250 }
251
252 volatile struct sun4m_timer_regs *counter_regs;
253
254 static void
255 ob_counter_init(uint64_t base, unsigned long offset, int ncpu)
256 {
257     int i;
258
259     ob_new_obio_device("counter", NULL);
260
261     for (i = 0; i < ncpu; i++) {
262         PUSH(0);
263         fword("encode-int");
264         if (i != 0) fword("encode+");
265         PUSH(offset + (i * PAGE_SIZE));
266         fword("encode-int");
267         fword("encode+");
268         PUSH(COUNTER_REGS);
269         fword("encode-int");
270         fword("encode+");
271     }
272
273     PUSH(0);
274     fword("encode-int");
275     fword("encode+");
276     PUSH(offset + 0x10000);
277     fword("encode-int");
278     fword("encode+");
279     PUSH(COUNTER_REGS);
280     fword("encode-int");
281     fword("encode+");
282
283     push_str("reg");
284     fword("property");
285
286
287     counter_regs = (struct sun4m_timer_regs *)ofmem_map_io(base + (uint64_t)offset, sizeof(*counter_regs));
288     counter_regs->cfg = 0xfffffffe;
289     counter_regs->l10_timer_limit = 0;
290     counter_regs->cpu_timers[0].l14_timer_limit = 0x9c4000;    /* see comment in obio.h */
291     counter_regs->cpu_timers[0].cntrl = 1;
292
293     for (i = 0; i < ncpu; i++) {
294         PUSH((unsigned long)&counter_regs->cpu_timers[i]);
295         fword("encode-int");
296         if (i != 0)
297             fword("encode+");
298     }
299     PUSH((unsigned long)&counter_regs->l10_timer_limit);
300     fword("encode-int");
301     fword("encode+");
302     push_str("address");
303     fword("property");
304
305     fword("finish-device");
306 }
307
308 static volatile struct sun4m_intregs *intregs;
309
310 static void
311 ob_interrupt_init(uint64_t base, unsigned long offset, int ncpu)
312 {
313     int i;
314
315     ob_new_obio_device("interrupt", NULL);
316
317     for (i = 0; i < ncpu; i++) {
318         PUSH(0);
319         fword("encode-int");
320         if (i != 0) fword("encode+");
321         PUSH(offset + (i * PAGE_SIZE));
322         fword("encode-int");
323         fword("encode+");
324         PUSH(INTERRUPT_REGS);
325         fword("encode-int");
326         fword("encode+");
327     }
328
329     PUSH(0);
330     fword("encode-int");
331     fword("encode+");
332     PUSH(offset + 0x10000);
333     fword("encode-int");
334     fword("encode+");
335     PUSH(INTERRUPT_REGS);
336     fword("encode-int");
337     fword("encode+");
338
339     push_str("reg");
340     fword("property");
341
342     intregs = (struct sun4m_intregs *)ofmem_map_io(base | (uint64_t)offset, sizeof(*intregs));
343     intregs->clear = ~SUN4M_INT_MASKALL;
344     intregs->cpu_intregs[0].clear = ~0x17fff;
345
346     for (i = 0; i < ncpu; i++) {
347         PUSH((unsigned long)&intregs->cpu_intregs[i]);
348         fword("encode-int");
349         if (i != 0)
350             fword("encode+");
351     }
352     PUSH((unsigned long)&intregs->tbt);
353     fword("encode-int");
354     fword("encode+");
355     push_str("address");
356     fword("property");
357
358     fword("finish-device");
359 }
360
361 /* SMP CPU boot structure */
362 struct smp_cfg {
363     uint32_t smp_ctx;
364     uint32_t smp_ctxtbl;
365     uint32_t smp_entry;
366     uint32_t valid;
367 };
368
369 static struct smp_cfg *smp_header;
370
371 int
372 start_cpu(unsigned int pc, unsigned int context_ptr, unsigned int context, int cpu)
373 {
374     if (!cpu)
375         return -1;
376
377     cpu &= 7;
378
379     smp_header->smp_entry = pc;
380     smp_header->smp_ctxtbl = context_ptr;
381     smp_header->smp_ctx = context;
382     smp_header->valid = cpu;
383
384     intregs->cpu_intregs[cpu].set = SUN4M_SOFT_INT(14);
385
386     return 0;
387 }
388
389 static void
390 ob_smp_init(unsigned long mem_size)
391 {
392     // See arch/sparc32/entry.S for memory layout
393     smp_header = (struct smp_cfg *)ofmem_map_io((uint64_t)(mem_size - 0x100),
394                                           sizeof(struct smp_cfg));
395 }
396
397 static void
398 ob_set_obio_ranges(uint64_t base)
399 {
400     push_str("/obio");
401     fword("find-device");
402     PUSH(0);
403     fword("encode-int");
404     PUSH(0);
405     fword("encode-int");
406     fword("encode+");
407     PUSH(base >> 32);
408     fword("encode-int");
409     fword("encode+");
410     PUSH(base & 0xffffffff);
411     fword("encode-int");
412     fword("encode+");
413     PUSH(SLAVIO_SIZE);
414     fword("encode-int");
415     fword("encode+");
416     push_str("ranges");
417     fword("property");
418 }
419
420
421 int
422 ob_obio_init(uint64_t slavio_base, unsigned long fd_offset,
423              unsigned long counter_offset, unsigned long intr_offset,
424              int intr_ncpu, unsigned long aux1_offset, unsigned long aux2_offset,
425              unsigned long mem_size)
426 {
427
428     // All devices were integrated to NCR89C105, see
429     // http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
430
431     //printk("Initializing OBIO devices...\n");
432     ob_set_obio_ranges(slavio_base);
433
434     // Zilog Z8530 serial ports, see http://www.zilog.com
435     // Must be before zs@0,0 or Linux won't boot
436     ob_zs_init(slavio_base, SLAVIO_ZS1, ZS_INTR, 0, 0);
437
438     ob_zs_init(slavio_base, SLAVIO_ZS, ZS_INTR, 1, 1);
439
440     // M48T08 NVRAM, see http://www.st.com
441     ob_nvram_init(slavio_base, SLAVIO_NVRAM);
442
443     // 82078 FDC
444     if (fd_offset != (unsigned long) -1)
445         ob_fd_init(slavio_base, fd_offset, FD_INTR);
446
447     ob_auxio_init(slavio_base, aux1_offset);
448
449     if (aux2_offset != (unsigned long) -1)
450         ob_aux2_reset_init(slavio_base, aux2_offset, AUXIO2_INTR);
451
452     ob_counter_init(slavio_base, counter_offset, intr_ncpu);
453
454     ob_interrupt_init(slavio_base, intr_offset, intr_ncpu);
455
456     ob_smp_init(mem_size);
457
458     return 0;
459 }