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