Add qemu 2.4.0
[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 /* DECLARE data structures for the nodes.  */
30 DECLARE_UNNAMED_NODE( ob_obio, INSTALL_OPEN, sizeof(int) );
31
32 void
33 ob_new_obio_device(const char *name, const char *type)
34 {
35     push_str("/obio");
36     fword("find-device");
37     fword("new-device");
38
39     push_str(name);
40     fword("device-name");
41
42     if (type) {
43         push_str(type);
44         fword("device-type");
45     }
46 }
47
48 static unsigned long
49 map_reg(uint64_t base, uint64_t offset, unsigned long size, int map,
50         int phys_hi)
51 {
52     PUSH(phys_hi);
53     fword("encode-int");
54     PUSH(offset);
55     fword("encode-int");
56     fword("encode+");
57     PUSH(size);
58     fword("encode-int");
59     fword("encode+");
60     push_str("reg");
61     fword("property");
62
63     if (map) {
64         unsigned long addr;
65
66         addr = (unsigned long)ofmem_map_io(base + offset, size);
67
68         PUSH(addr);
69         fword("encode-int");
70         push_str("address");
71         fword("property");
72         return addr;
73     }
74     return 0;
75 }
76
77 unsigned long
78 ob_reg(uint64_t base, uint64_t offset, unsigned long size, int map)
79 {
80     return map_reg(base, offset, size, map, 0);
81 }
82
83 void
84 ob_intr(int intr)
85 {
86     PUSH(intr);
87     fword("encode-int");
88     PUSH(0);
89     fword("encode-int");
90     fword("encode+");
91     push_str("intr");
92     fword("property");
93 }
94
95 void
96 ob_eccmemctl_init(uint64_t base)
97 {
98     uint32_t version, *regs;
99     const char *mc_type;
100
101     push_str("/");
102     fword("find-device");
103     fword("new-device");
104
105     push_str("eccmemctl");
106     fword("device-name");
107
108     PUSH(0x20);
109     fword("encode-int");
110     push_str("width");
111     fword("property");
112
113     regs = (uint32_t *)map_reg(ECC_BASE, 0, ECC_SIZE, 1, ECC_BASE >> 32);
114
115     version = regs[0];
116     switch (version) {
117     case 0x00000000:
118         mc_type = "MCC";
119         break;
120     case 0x10000000:
121         mc_type = "EMC";
122         break;
123     default:
124     case 0x20000000:
125         mc_type = "SMC";
126         break;
127     }
128     push_str(mc_type);
129     fword("encode-string");
130     push_str("mc-type");
131     fword("property");
132
133     fword("finish-device");
134 }
135
136 static unsigned char *nvram;
137
138 #define NVRAM_OB_START   (0)
139 #define NVRAM_OB_SIZE    ((NVRAM_IDPROM - NVRAM_OB_START) & ~15)
140
141 void
142 arch_nvram_get(char *data)
143 {
144     memcpy(data, &nvram[NVRAM_OB_START], NVRAM_OB_SIZE);
145 }
146
147 void
148 arch_nvram_put(char *data)
149 {
150     memcpy(&nvram[NVRAM_OB_START], data, NVRAM_OB_SIZE);
151 }
152
153 int
154 arch_nvram_size(void)
155 {
156     return NVRAM_OB_SIZE;
157 }
158
159 void
160 ss5_init(uint64_t base)
161 {
162     ob_new_obio_device("slavioconfig", NULL);
163
164     ob_reg(base, SLAVIO_SCONFIG, SCONFIG_REGS, 0);
165
166     fword("finish-device");
167 }
168
169 static void
170 ob_nvram_init(uint64_t base, uint64_t offset)
171 {
172     ob_new_obio_device("eeprom", NULL);
173
174     nvram = (unsigned char *)ob_reg(base, offset, NVRAM_SIZE, 1);
175
176     PUSH((unsigned long)nvram);
177     fword("encode-int");
178     push_str("address");
179     fword("property");
180
181     push_str("mk48t08");
182     fword("model");
183
184     fword("finish-device");
185
186     // Add /idprom
187     push_str("/");
188     fword("find-device");
189
190     PUSH((long)&nvram[NVRAM_IDPROM]);
191     PUSH(32);
192     fword("encode-bytes");
193     push_str("idprom");
194     fword("property");
195 }
196
197 static void
198 ob_fd_init(uint64_t base, uint64_t offset, int intr)
199 {
200     unsigned long addr;
201
202     ob_new_obio_device("SUNW,fdtwo", "block");
203
204     addr = ob_reg(base, offset, FD_REGS, 1);
205
206     ob_intr(intr);
207
208     fword("is-deblocker");
209
210     ob_floppy_init("/obio", "SUNW,fdtwo", 0, addr);
211
212     fword("finish-device");
213 }
214
215 static void
216 ob_auxio_init(uint64_t base, uint64_t offset)
217 {
218     ob_new_obio_device("auxio", NULL);
219
220     ob_reg(base, offset, AUXIO_REGS, 1);
221
222     fword("finish-device");
223 }
224
225 volatile unsigned char *power_reg;
226 volatile unsigned int *reset_reg;
227
228 static void
229 sparc32_reset_all(void)
230 {
231     *reset_reg = 1;
232 }
233
234 // AUX 2 (Software Powerdown Control) and reset
235 static void
236 ob_aux2_reset_init(uint64_t base, uint64_t offset, int intr)
237 {
238     ob_new_obio_device("power", NULL);
239
240     power_reg = (void *)ob_reg(base, offset, AUXIO2_REGS, 1);
241
242     // Not in device tree
243     reset_reg = (unsigned int *)ofmem_map_io(base + (uint64_t)SLAVIO_RESET, RESET_REGS);
244
245     bind_func("sparc32-reset-all", sparc32_reset_all);
246     push_str("' sparc32-reset-all to reset-all");
247     fword("eval");
248
249     ob_intr(intr);
250
251     fword("finish-device");
252 }
253
254 volatile struct sun4m_timer_regs *counter_regs;
255
256 static void
257 ob_counter_init(uint64_t base, unsigned long offset, int ncpu)
258 {
259     int i;
260
261     ob_new_obio_device("counter", NULL);
262
263     for (i = 0; i < ncpu; i++) {
264         PUSH(0);
265         fword("encode-int");
266         if (i != 0) fword("encode+");
267         PUSH(offset + (i * PAGE_SIZE));
268         fword("encode-int");
269         fword("encode+");
270         PUSH(COUNTER_REGS);
271         fword("encode-int");
272         fword("encode+");
273     }
274
275     PUSH(0);
276     fword("encode-int");
277     fword("encode+");
278     PUSH(offset + 0x10000);
279     fword("encode-int");
280     fword("encode+");
281     PUSH(COUNTER_REGS);
282     fword("encode-int");
283     fword("encode+");
284
285     push_str("reg");
286     fword("property");
287
288
289     counter_regs = (struct sun4m_timer_regs *)ofmem_map_io(base + (uint64_t)offset, sizeof(*counter_regs));
290     counter_regs->cfg = 0xfffffffe;
291     counter_regs->l10_timer_limit = 0;
292     counter_regs->cpu_timers[0].l14_timer_limit = 0x9c4000;    /* see comment in obio.h */
293     counter_regs->cpu_timers[0].cntrl = 1;
294
295     for (i = 0; i < ncpu; i++) {
296         PUSH((unsigned long)&counter_regs->cpu_timers[i]);
297         fword("encode-int");
298         if (i != 0)
299             fword("encode+");
300     }
301     PUSH((unsigned long)&counter_regs->l10_timer_limit);
302     fword("encode-int");
303     fword("encode+");
304     push_str("address");
305     fword("property");
306
307     fword("finish-device");
308 }
309
310 static volatile struct sun4m_intregs *intregs;
311
312 static void
313 ob_interrupt_init(uint64_t base, unsigned long offset, int ncpu)
314 {
315     int i;
316
317     ob_new_obio_device("interrupt", NULL);
318
319     for (i = 0; i < ncpu; i++) {
320         PUSH(0);
321         fword("encode-int");
322         if (i != 0) fword("encode+");
323         PUSH(offset + (i * PAGE_SIZE));
324         fword("encode-int");
325         fword("encode+");
326         PUSH(INTERRUPT_REGS);
327         fword("encode-int");
328         fword("encode+");
329     }
330
331     PUSH(0);
332     fword("encode-int");
333     fword("encode+");
334     PUSH(offset + 0x10000);
335     fword("encode-int");
336     fword("encode+");
337     PUSH(INTERRUPT_REGS);
338     fword("encode-int");
339     fword("encode+");
340
341     push_str("reg");
342     fword("property");
343
344     intregs = (struct sun4m_intregs *)ofmem_map_io(base | (uint64_t)offset, sizeof(*intregs));
345     intregs->clear = ~SUN4M_INT_MASKALL;
346     intregs->cpu_intregs[0].clear = ~0x17fff;
347
348     for (i = 0; i < ncpu; i++) {
349         PUSH((unsigned long)&intregs->cpu_intregs[i]);
350         fword("encode-int");
351         if (i != 0)
352             fword("encode+");
353     }
354     PUSH((unsigned long)&intregs->tbt);
355     fword("encode-int");
356     fword("encode+");
357     push_str("address");
358     fword("property");
359
360     fword("finish-device");
361 }
362
363 /* SMP CPU boot structure */
364 struct smp_cfg {
365     uint32_t smp_ctx;
366     uint32_t smp_ctxtbl;
367     uint32_t smp_entry;
368     uint32_t valid;
369 };
370
371 static struct smp_cfg *smp_header;
372
373 int
374 start_cpu(unsigned int pc, unsigned int context_ptr, unsigned int context, int cpu)
375 {
376     if (!cpu)
377         return -1;
378
379     cpu &= 7;
380
381     smp_header->smp_entry = pc;
382     smp_header->smp_ctxtbl = context_ptr;
383     smp_header->smp_ctx = context;
384     smp_header->valid = cpu;
385
386     intregs->cpu_intregs[cpu].set = SUN4M_SOFT_INT(14);
387
388     return 0;
389 }
390
391 static void
392 ob_smp_init(unsigned long mem_size)
393 {
394     // See arch/sparc32/entry.S for memory layout
395     smp_header = (struct smp_cfg *)ofmem_map_io((uint64_t)(mem_size - 0x100),
396                                           sizeof(struct smp_cfg));
397 }
398
399 static void
400 ob_obio_open(__attribute__((unused))int *idx)
401 {
402         int ret=1;
403         RET ( -ret );
404 }
405
406 static void
407 ob_obio_close(__attribute__((unused))int *idx)
408 {
409         selfword("close-deblocker");
410 }
411
412 static void
413 ob_obio_initialize(__attribute__((unused))int *idx)
414 {
415     push_str("/");
416     fword("find-device");
417     fword("new-device");
418
419     push_str("obio");
420     fword("device-name");
421
422     push_str("hierarchical");
423     fword("device-type");
424
425     PUSH(2);
426     fword("encode-int");
427     push_str("#address-cells");
428     fword("property");
429
430     PUSH(1);
431     fword("encode-int");
432     push_str("#size-cells");
433     fword("property");
434
435     fword("finish-device");
436 }
437
438 static void
439 ob_set_obio_ranges(uint64_t base)
440 {
441     push_str("/obio");
442     fword("find-device");
443     PUSH(0);
444     fword("encode-int");
445     PUSH(0);
446     fword("encode-int");
447     fword("encode+");
448     PUSH(base >> 32);
449     fword("encode-int");
450     fword("encode+");
451     PUSH(base & 0xffffffff);
452     fword("encode-int");
453     fword("encode+");
454     PUSH(SLAVIO_SIZE);
455     fword("encode-int");
456     fword("encode+");
457     push_str("ranges");
458     fword("property");
459 }
460
461 static void
462 ob_obio_decodeunit(__attribute__((unused)) int *idx)
463 {
464     fword("decode-unit-sbus");
465 }
466
467
468 static void
469 ob_obio_encodeunit(__attribute__((unused)) int *idx)
470 {
471     fword("encode-unit-sbus");
472 }
473
474 NODE_METHODS(ob_obio) = {
475         { NULL,                 ob_obio_initialize      },
476         { "open",               ob_obio_open            },
477         { "close",              ob_obio_close           },
478         { "encode-unit",        ob_obio_encodeunit      },
479         { "decode-unit",        ob_obio_decodeunit      },
480 };
481
482
483 int
484 ob_obio_init(uint64_t slavio_base, unsigned long fd_offset,
485              unsigned long counter_offset, unsigned long intr_offset,
486              int intr_ncpu, unsigned long aux1_offset, unsigned long aux2_offset,
487              unsigned long mem_size)
488 {
489
490     // All devices were integrated to NCR89C105, see
491     // http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
492
493     //printk("Initializing OBIO devices...\n");
494 #if 0 // XXX
495     REGISTER_NAMED_NODE(ob_obio, "/obio");
496     device_end();
497 #endif
498     ob_set_obio_ranges(slavio_base);
499
500     // Zilog Z8530 serial ports, see http://www.zilog.com
501     // Must be before zs@0,0 or Linux won't boot
502     ob_zs_init(slavio_base, SLAVIO_ZS1, ZS_INTR, 0, 0);
503
504     ob_zs_init(slavio_base, SLAVIO_ZS, ZS_INTR, 1, 1);
505
506     // M48T08 NVRAM, see http://www.st.com
507     ob_nvram_init(slavio_base, SLAVIO_NVRAM);
508
509     // 82078 FDC
510     if (fd_offset != (unsigned long) -1)
511         ob_fd_init(slavio_base, fd_offset, FD_INTR);
512
513     ob_auxio_init(slavio_base, aux1_offset);
514
515     if (aux2_offset != (unsigned long) -1)
516         ob_aux2_reset_init(slavio_base, aux2_offset, AUXIO2_INTR);
517
518     ob_counter_init(slavio_base, counter_offset, intr_ncpu);
519
520     ob_interrupt_init(slavio_base, intr_offset, intr_ncpu);
521
522     ob_smp_init(mem_size);
523
524     return 0;
525 }