void __init auxio_power_probe(void) { struct linux_prom_registers regs; int node; struct resource r; /* Attempt to find the sun4m power control node. */ node = prom_getchild(prom_root_node); node = prom_searchsiblings(node, "obio"); node = prom_getchild(node); node = prom_searchsiblings(node, "power"); if (node == 0 || node == -1) return; /* Map the power control register. */ if (prom_getproperty(node, "reg", (char *)®s, sizeof(regs)) <= 0) return; prom_apply_obio_ranges(®s, 1); memset(&r, 0, sizeof(r)); r.flags = regs.which_io & 0xF; r.start = regs.phys_addr; r.end = regs.phys_addr + regs.reg_size - 1; auxio_power_register = (unsigned char *) of_ioremap(&r, 0, regs.reg_size, "auxpower"); /* Display a quick message on the console. */ if (auxio_power_register) printk(KERN_INFO "Power off control detected.\n"); }
void __init auxio_power_probe(void) { struct linux_prom_registers regs; phandle node; struct resource r; node = prom_getchild(prom_root_node); node = prom_searchsiblings(node, "obio"); node = prom_getchild(node); node = prom_searchsiblings(node, "power"); if (node == 0 || (s32)node == -1) return; if (prom_getproperty(node, "reg", (char *)®s, sizeof(regs)) <= 0) return; prom_apply_obio_ranges(®s, 1); memset(&r, 0, sizeof(r)); r.flags = regs.which_io & 0xF; r.start = regs.phys_addr; r.end = regs.phys_addr + regs.reg_size - 1; auxio_power_register = (unsigned char *) of_ioremap(&r, 0, regs.reg_size, "auxpower"); if (auxio_power_register) printk(KERN_INFO "Power off control detected.\n"); }
static int __init ts102_uctrl_init(void) { struct uctrl_driver *driver = &drv; int len, i; struct linux_prom_irqs tmp_irq[2]; unsigned int vaddr[2] = { 0, 0 }; int tmpnode, uctrlnode = prom_getchild(prom_root_node); int err; tmpnode = prom_searchsiblings(uctrlnode, "obio"); if (tmpnode) uctrlnode = prom_getchild(tmpnode); uctrlnode = prom_searchsiblings(uctrlnode, "uctrl"); if (!uctrlnode) return -ENODEV; /* the prom mapped it for us */ len = prom_getproperty(uctrlnode, "address", (void *) vaddr, sizeof(vaddr)); driver->regs = (struct uctrl_regs *)vaddr[0]; len = prom_getproperty(uctrlnode, "intr", (char *) tmp_irq, sizeof(tmp_irq)); /* Flush device */ READUCTLDATA(len); if(!driver->irq) driver->irq = tmp_irq[0].pri; err = request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver); if (err) { printk("%s: unable to register irq %d\n", __FUNCTION__, driver->irq); return err; } if (misc_register(&uctrl_dev)) { printk("%s: unable to get misc minor %d\n", __FUNCTION__, uctrl_dev.minor); free_irq(driver->irq, driver); return -ENODEV; } driver->regs->uctrl_intr = UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK; printk("uctrl: 0x%p (irq %d)\n", driver->regs, driver->irq); uctrl_get_event_status(); uctrl_get_external_status(); return 0; }
void __init auxio_probe(void) { int node, auxio_nd; struct linux_prom_registers auxregs[1]; struct resource r; switch (sparc_cpu_model) { case sun4d: case sun4: auxio_register = 0; return; default: break; } node = prom_getchild(prom_root_node); auxio_nd = prom_searchsiblings(node, "auxiliary-io"); if(!auxio_nd) { node = prom_searchsiblings(node, "obio"); node = prom_getchild(node); auxio_nd = prom_searchsiblings(node, "auxio"); if(!auxio_nd) { #ifdef CONFIG_PCI /* There may be auxio on Ebus */ auxio_register = 0; return; #else if(prom_searchsiblings(node, "leds")) { /* VME chassis sun4m machine, no auxio exists. */ auxio_register = 0; return; } prom_printf("Cannot find auxio node, cannot continue...\n"); prom_halt(); #endif } } prom_getproperty(auxio_nd, "reg", (char *) auxregs, sizeof(auxregs)); prom_apply_obio_ranges(auxregs, 0x1); /* Map the register both read and write */ r.flags = auxregs[0].which_io & 0xF; r.start = auxregs[0].phys_addr; r.end = auxregs[0].phys_addr + auxregs[0].reg_size - 1; auxio_register = (unsigned char *) sbus_ioremap(&r, 0, auxregs[0].reg_size, "auxio"); /* Fix the address on sun4m and sun4c. */ if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 || sparc_cpu_model == sun4c) auxio_register = (unsigned char *) ((int)auxio_register | 3); TURN_ON_LED; }
void __init auxio_probe(void) { phandle node, auxio_nd; struct linux_prom_registers auxregs[1]; struct resource r; switch (sparc_cpu_model) { case sparc_leon: case sun4d: case sun4: return; default: break; } node = prom_getchild(prom_root_node); auxio_nd = prom_searchsiblings(node, "auxiliary-io"); if(!auxio_nd) { node = prom_searchsiblings(node, "obio"); node = prom_getchild(node); auxio_nd = prom_searchsiblings(node, "auxio"); if(!auxio_nd) { #ifdef CONFIG_PCI return; #else if(prom_searchsiblings(node, "leds")) { return; } prom_printf("Cannot find auxio node, cannot continue...\n"); prom_halt(); #endif } } if(prom_getproperty(auxio_nd, "reg", (char *) auxregs, sizeof(auxregs)) <= 0) return; prom_apply_obio_ranges(auxregs, 0x1); r.flags = auxregs[0].which_io & 0xF; r.start = auxregs[0].phys_addr; r.end = auxregs[0].phys_addr + auxregs[0].reg_size - 1; auxio_register = of_ioremap(&r, 0, auxregs[0].reg_size, "auxio"); if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 || sparc_cpu_model == sun4c) auxio_register += (3 - ((unsigned long)auxio_register & 3)); set_auxio(AUXIO_LED, 0); }
static int pci_controller_scan(int (*handler)(char *, int, int)) { char namebuf[64]; int node; int count = 0; node = prom_getchild(prom_root_node); while ((node = prom_searchsiblings(node, "pci")) != 0) { int len; if ((len = prom_getproperty(node, "model", namebuf, sizeof(namebuf))) > 0 || (len = prom_getproperty(node, "compatible", namebuf, sizeof(namebuf))) > 0) { int item_len = 0; /* Our value may be a multi-valued string in the * case of some compatible properties. For sanity, * only try the first one. */ while (namebuf[item_len] && len) { len--; item_len++; } if (handler(namebuf, item_len, node)) count++; } node = prom_getsibling(node); if (!node) break; } return count; }
/* Find each controller in the system, attach and initialize * software state structure for each and link into the * pci_controller_root. Setup the controller enough such * that bus scanning can be done. */ static void pci_controller_probe(void) { char namebuf[16]; int node; printk("PCI: Probing for controllers.\n"); node = prom_getchild(prom_root_node); while ((node = prom_searchsiblings(node, "pci")) != 0) { int len; len = prom_getproperty(node, "model", namebuf, sizeof(namebuf)); if (len > 0) pci_controller_init(namebuf, len, node); else { len = prom_getproperty(node, "compatible", namebuf, sizeof(namebuf)); if (len > 0) pci_controller_init(namebuf, len, node); } node = prom_getsibling(node); if (!node) break; } }
int prom_finddevice(char *name) { char nbuf[128]; char *s = name, *d; int node = prom_root_node, node2; unsigned int which_io, phys_addr; struct linux_prom_registers reg[PROMREG_MAX]; while (*s++) { if (!*s) return node; /* path '.../' is legal */ node = prom_getchild(node); for (d = nbuf; *s != 0 && *s != '@' && *s != '/';) *d++ = *s++; *d = 0; node = prom_searchsiblings(node, nbuf); if (!node) return 0; if (*s == '@') { if (isxdigit(s[1]) && s[2] == ',') { which_io = simple_strtoul(s+1, NULL, 16); phys_addr = simple_strtoul(s+3, &d, 16); if (d != s + 3 && (!*d || *d == '/') && d <= s + 3 + 8) { node2 = node; while (node2 && node2 != -1) { if (prom_getproperty (node2, "reg", (char *)reg, sizeof (reg)) > 0) { if (which_io == reg[0].which_io && phys_addr == reg[0].phys_addr) { node = node2; break; } } node2 = prom_getsibling(node2); if (!node2 || node2 == -1) break; node2 = prom_searchsiblings(prom_getsibling(node2), nbuf); } } } while (*s != 0 && *s != '/') s++; } } return node; }
static inline int d7s_obpflipped(void) { int opt_node; opt_node = prom_getchild(prom_root_node); opt_node = prom_searchsiblings(opt_node, "options"); return ((-1 != prom_getintdefault(opt_node, "d7s-flipped?", -1)) ? 0 : 1); }
void prom_ranges_init(void) { int node, obio_node, sbus_node; int success; num_obio_ranges = 0; num_sbus_ranges = 0; /* Check for obio and sbus ranges. */ node = prom_getchild(prom_root_node); obio_node = prom_searchsiblings(node, "obio"); sbus_node = prom_searchsiblings(node, "iommu"); if(sbus_node) { sbus_node = prom_getchild(sbus_node); sbus_node = prom_searchsiblings(sbus_node, "sbus"); } if(obio_node) { success = prom_getproperty(obio_node, "ranges", (char *) promlib_obio_ranges, sizeof(promlib_obio_ranges)); if(success != -1) num_obio_ranges = (success/sizeof(struct linux_prom_ranges)); } if(sbus_node) { success = prom_getproperty(sbus_node, "ranges", (char *) promlib_sbus_ranges, sizeof(promlib_sbus_ranges)); if(success != -1) num_sbus_ranges = (success/sizeof(struct linux_prom_ranges)); } if(num_obio_ranges || num_sbus_ranges) prom_printf("PROMLIB: obio_ranges %d sbus_ranges %d\n", num_obio_ranges, num_sbus_ranges); return; }
__initfunc(void auxio_power_probe(void)) { struct linux_prom_registers regs; int node; /* Attempt to find the sun4m power control node. */ node = prom_getchild(prom_root_node); node = prom_searchsiblings(node, "obio"); node = prom_getchild(node); node = prom_searchsiblings(node, "power"); if (node == 0 || node == -1) return; /* Map the power control register. */ prom_getproperty(node, "reg", (char *)®s, sizeof(regs)); prom_apply_obio_ranges(®s, 1); auxio_power_register = (volatile unsigned char *) sparc_alloc_io(regs.phys_addr, 0, regs.reg_size, "power off control", regs.which_io, 0); /* Display a quick message on the console. */ if (auxio_power_register) printk(KERN_INFO "Power off control detected.\n"); }
static char *serial(char *buffer) { int node = prom_getchild(prom_root_node); int len; node = prom_searchsiblings(node, "options"); *buffer = 0; len = prom_getproperty(node, "system-board-serial#", buffer, 256); if(len > 0) buffer[len] = 0; if (!*buffer) return "4512348717234"; else return buffer; }
static int __init prom_meminit_v2(void) { struct linux_prom_registers reg[64]; int node, size, num_ents, i; node = prom_searchsiblings(prom_getchild(prom_root_node), "memory"); size = prom_getproperty(node, "available", (char *) reg, sizeof(reg)); num_ents = size / sizeof(struct linux_prom_registers); for (i = 0; i < num_ents; i++) { sp_banks[i].base_addr = reg[i].phys_addr; sp_banks[i].num_bytes = reg[i].reg_size; } return num_ents; }
void __init sun4c_init_IRQ(void) { struct linux_prom_registers int_regs[2]; int ie_node; if (ARCH_SUN4) { interrupt_enable = (char *) ioremap(sun4_ie_physaddr, PAGE_SIZE); } else { struct resource phyres; ie_node = prom_searchsiblings (prom_getchild(prom_root_node), "interrupt-enable"); if(ie_node == 0) panic("Cannot find /interrupt-enable node"); /* Depending on the "address" property is bad news... */ prom_getproperty(ie_node, "reg", (char *) int_regs, sizeof(int_regs)); memset(&phyres, 0, sizeof(struct resource)); phyres.flags = int_regs[0].which_io; phyres.start = int_regs[0].phys_addr; interrupt_enable = (char *) sbus_ioremap(&phyres, 0, int_regs[0].reg_size, "sun4c_intr"); } BTFIXUPSET_CALL(sbint_to_irq, sun4c_sbint_to_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(disable_irq, sun4c_disable_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(enable_pil_irq, sun4c_enable_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(disable_pil_irq, sun4c_disable_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_profile_irq, sun4c_clear_profile_irq, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(__irq_itoa, sun4m_irq_itoa, BTFIXUPCALL_NORM); sparc_init_timers = sun4c_init_timers; #ifdef CONFIG_SMP BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(clear_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(set_irq_udt, sun4c_nop, BTFIXUPCALL_NOP); #endif *interrupt_enable = (SUN4C_INT_ENABLE); /* Cannot enable interrupts until OBP ticker is disabled. */ }
static int __init openprom_init(void) { int error; error = misc_register(&openprom_dev); if (error) { printk(KERN_ERR "openprom: unable to get misc minor\n"); return error; } options_node = prom_getchild(prom_root_node); options_node = prom_searchsiblings(options_node,"options"); if (options_node == 0 || options_node == -1) { printk(KERN_ERR "openprom: unable to find options node\n"); misc_deregister(&openprom_dev); return -EIO; } return 0; }
const char *promcon_startup(void) { const char *display_desc = "PROM"; int node; char buf[40]; node = prom_getchild(prom_root_node); node = prom_searchsiblings(node, "options"); if (prom_getproperty(node, "screen-#columns", buf, 40) != -1) { pw = simple_strtoul(buf, NULL, 0); if (pw < 10 || pw > 256) pw = 80; pw--; } if (prom_getproperty(node, "screen-#rows", buf, 40) != -1) { ph = simple_strtoul(buf, NULL, 0); if (ph < 10 || ph > 256) ph = 34; ph--; } promcon_puts("\033[H\033[J", 6); return display_desc; }
__initfunc(int sun_kbd_init(void)) { int i, opt_node; struct kbd_struct kbd0; extern struct tty_driver console_driver; kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS; kbd0.ledmode = LED_SHOW_FLAGS; kbd0.lockstate = KBD_DEFLOCK; kbd0.slockstate = 0; kbd0.modeflags = KBD_DEFMODE; kbd0.kbdmode = VC_XLATE; for (i = 0 ; i < MAX_NR_CONSOLES ; i++) kbd_table[i] = kbd0; ttytab = console_driver.table; kd_mksound = sunkbd_kd_mksound; /* XXX Check keyboard-click? property in 'options' PROM node XXX */ if(sparc_cpu_model != sun4) { opt_node = prom_getchild(prom_root_node); opt_node = prom_searchsiblings(opt_node, "options"); i = prom_getintdefault(opt_node, "keyboard-click?", -1); if(i != -1) sunkbd_clickp = 1; else sunkbd_clickp = 0; } else { sunkbd_clickp = 0; } init_bh(KEYBOARD_BH, kbd_bh); mark_bh(KEYBOARD_BH); return 0; }
void sunserial_console_termios(struct console *con) { char mode[16], buf[16], *s; char *mode_prop = "ttyX-mode"; char *cd_prop = "ttyX-ignore-cd"; char *dtr_prop = "ttyX-rts-dtr-off"; int baud, bits, stop, cflag; char parity; int carrier = 0; int rtsdtr = 1; int topnd, nd; if (!serial_console) return; if (serial_console == 1) { mode_prop[3] = 'a'; cd_prop[3] = 'a'; dtr_prop[3] = 'a'; } else { mode_prop[3] = 'b'; cd_prop[3] = 'b'; dtr_prop[3] = 'b'; } topnd = prom_getchild(prom_root_node); nd = prom_searchsiblings(topnd, "options"); if (!nd) { strcpy(mode, "9600,8,n,1,-"); goto no_options; } if (!prom_node_has_property(nd, mode_prop)) { strcpy(mode, "9600,8,n,1,-"); goto no_options; } memset(mode, 0, sizeof(mode)); prom_getstring(nd, mode_prop, mode, sizeof(mode)); if (prom_node_has_property(nd, cd_prop)) { memset(buf, 0, sizeof(buf)); prom_getstring(nd, cd_prop, buf, sizeof(buf)); if (!strcmp(buf, "false")) carrier = 1; /* XXX: this is unused below. */ } if (prom_node_has_property(nd, cd_prop)) { memset(buf, 0, sizeof(buf)); prom_getstring(nd, cd_prop, buf, sizeof(buf)); if (!strcmp(buf, "false")) rtsdtr = 0; /* XXX: this is unused below. */ } no_options: cflag = CREAD | HUPCL | CLOCAL; s = mode; baud = simple_strtoul(s, 0, 0); s = strchr(s, ','); bits = simple_strtoul(++s, 0, 0); s = strchr(s, ','); parity = *(++s); s = strchr(s, ','); stop = simple_strtoul(++s, 0, 0); s = strchr(s, ','); /* XXX handshake is not handled here. */ switch (baud) { case 150: cflag |= B150; break; case 300: cflag |= B300; break; case 600: cflag |= B600; break; case 1200: cflag |= B1200; break; case 2400: cflag |= B2400; break; case 4800: cflag |= B4800; break; case 9600: cflag |= B9600; break; case 19200: cflag |= B19200; break; case 38400: cflag |= B38400; break; default: baud = 9600; cflag |= B9600; break; } switch (bits) { case 5: cflag |= CS5; break; case 6: cflag |= CS6; break; case 7: cflag |= CS7; break; case 8: cflag |= CS8; break; default: cflag |= CS8; break; } switch (parity) { case 'o': cflag |= (PARENB | PARODD); break; case 'e': cflag |= PARENB; break; case 'n': default: break; } switch (stop) { case 2: cflag |= CSTOPB; break; case 1: default: break; } con->cflag = cflag; }
/* Probe for the mostek real time clock chip. */ static __inline__ void clock_probe(void) { struct linux_prom_registers clk_reg[2]; char model[128]; register int node, cpuunit, bootbus; struct resource r; cpuunit = bootbus = 0; memset(&r, 0, sizeof(r)); /* Determine the correct starting PROM node for the probe. */ node = prom_getchild(prom_root_node); switch (sparc_cpu_model) { case sun4c: break; case sun4m: node = prom_getchild(prom_searchsiblings(node, "obio")); break; case sun4d: node = prom_getchild(bootbus = prom_searchsiblings(prom_getchild(cpuunit = prom_searchsiblings(node, "cpu-unit")), "bootbus")); break; default: prom_printf("CLOCK: Unsupported architecture!\n"); prom_halt(); } /* Find the PROM node describing the real time clock. */ sp_clock_typ = MSTK_INVALID; node = prom_searchsiblings(node,"eeprom"); if (!node) { prom_printf("CLOCK: No clock found!\n"); prom_halt(); } /* Get the model name and setup everything up. */ model[0] = '\0'; prom_getstring(node, "model", model, sizeof(model)); if (strcmp(model, "mk48t02") == 0) { sp_clock_typ = MSTK48T02; if (prom_getproperty(node, "reg", (char *) clk_reg, sizeof(clk_reg)) == -1) { prom_printf("clock_probe: FAILED!\n"); prom_halt(); } if (sparc_cpu_model == sun4d) prom_apply_generic_ranges (bootbus, cpuunit, clk_reg, 1); else prom_apply_obio_ranges(clk_reg, 1); /* Map the clock register io area read-only */ r.flags = clk_reg[0].which_io; r.start = clk_reg[0].phys_addr; mstk48t02_regs = sbus_ioremap(&r, 0, sizeof(struct mostek48t02), "mk48t02"); mstk48t08_regs = NULL; /* To catch weirdness */ } else if (strcmp(model, "mk48t08") == 0) { sp_clock_typ = MSTK48T08; if(prom_getproperty(node, "reg", (char *) clk_reg, sizeof(clk_reg)) == -1) { prom_printf("clock_probe: FAILED!\n"); prom_halt(); } if (sparc_cpu_model == sun4d) prom_apply_generic_ranges (bootbus, cpuunit, clk_reg, 1); else prom_apply_obio_ranges(clk_reg, 1); /* Map the clock register io area read-only */ /* XXX r/o attribute is somewhere in r.flags */ r.flags = clk_reg[0].which_io; r.start = clk_reg[0].phys_addr; mstk48t08_regs = (struct mostek48t08 *) sbus_ioremap(&r, 0, sizeof(struct mostek48t08), "mk48t08"); mstk48t02_regs = &mstk48t08_regs->regs; } else { prom_printf("CLOCK: Unknown model name '%s'\n",model); prom_halt(); } /* Report a low battery voltage condition. */ if (has_low_battery()) printk(KERN_CRIT "NVRAM: Low battery voltage!\n"); /* Kick start the clock if it is completely stopped. */ if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP) kick_start_clock(); }
__initfunc(static void sun4m_init_timers(void (*counter_fn)(int, void *, struct pt_regs *))) { int reg_count, irq, cpu; struct linux_prom_registers cnt_regs[PROMREG_MAX]; int obio_node, cnt_node; cnt_node = 0; if((obio_node = prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 || (obio_node = prom_getchild (obio_node)) == 0 || (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) { prom_printf("Cannot find /obio/counter node\n"); prom_halt(); } reg_count = prom_getproperty(cnt_node, "reg", (void *) cnt_regs, sizeof(cnt_regs)); reg_count = (reg_count/sizeof(struct linux_prom_registers)); /* Apply the obio ranges to the timer registers. */ prom_apply_obio_ranges(cnt_regs, reg_count); cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr; cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size; cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io; for(obio_node = 1; obio_node < 4; obio_node++) { cnt_regs[obio_node].phys_addr = cnt_regs[obio_node-1].phys_addr + PAGE_SIZE; cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size; cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io; } /* Map the per-cpu Counter registers. */ sun4m_timers = sparc_alloc_io(cnt_regs[0].phys_addr, 0, PAGE_SIZE*NCPUS, "counters_percpu", cnt_regs[0].which_io, 0x0); /* Map the system Counter register. */ sparc_alloc_io(cnt_regs[4].phys_addr, 0, cnt_regs[4].reg_size, "counters_system", cnt_regs[4].which_io, 0x0); sun4m_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10); master_l10_counter = &sun4m_timers->l10_cur_count; master_l10_limit = &sun4m_timers->l10_timer_limit; irq = request_irq(TIMER_IRQ, counter_fn, (SA_INTERRUPT | SA_STATIC_ALLOC), "timer", NULL); if (irq) { prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ); prom_halt(); } if(linux_num_cpus > 1) { for(cpu = 0; cpu < 4; cpu++) sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0; sun4m_interrupts->set = SUN4M_INT_E14; } else { sun4m_timers->cpu_timers[0].l14_timer_limit = 0; } #ifdef __SMP__ { unsigned long flags; extern unsigned long lvl14_save[4]; struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)]; /* For SMP we use the level 14 ticker, however the bootup code * has copied the firmwares level 14 vector into boot cpu's * trap table, we must fix this now or we get squashed. */ __save_and_cli(flags); trap_table->inst_one = lvl14_save[0]; trap_table->inst_two = lvl14_save[1]; trap_table->inst_three = lvl14_save[2]; trap_table->inst_four = lvl14_save[3]; local_flush_cache_all(); __restore_flags(flags); } #endif }
static void __init sun4m_init_timers(irqreturn_t (*counter_fn)(int, void *, struct pt_regs *)) { int reg_count, irq, cpu; struct linux_prom_registers cnt_regs[PROMREG_MAX]; int obio_node, cnt_node; struct resource r; cnt_node = 0; if((obio_node = prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 || (obio_node = prom_getchild (obio_node)) == 0 || (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) { prom_printf("Cannot find /obio/counter node\n"); prom_halt(); } reg_count = prom_getproperty(cnt_node, "reg", (void *) cnt_regs, sizeof(cnt_regs)); reg_count = (reg_count/sizeof(struct linux_prom_registers)); /* Apply the obio ranges to the timer registers. */ prom_apply_obio_ranges(cnt_regs, reg_count); cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr; cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size; cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io; for(obio_node = 1; obio_node < 4; obio_node++) { cnt_regs[obio_node].phys_addr = cnt_regs[obio_node-1].phys_addr + PAGE_SIZE; cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size; cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io; } memset((char*)&r, 0, sizeof(struct resource)); /* Map the per-cpu Counter registers. */ r.flags = cnt_regs[0].which_io; r.start = cnt_regs[0].phys_addr; sun4m_timers = (struct sun4m_timer_regs *) sbus_ioremap(&r, 0, PAGE_SIZE*SUN4M_NCPUS, "sun4m_cpu_cnt"); /* Map the system Counter register. */ /* XXX Here we expect consequent calls to yeld adjusent maps. */ r.flags = cnt_regs[4].which_io; r.start = cnt_regs[4].phys_addr; sbus_ioremap(&r, 0, cnt_regs[4].reg_size, "sun4m_sys_cnt"); sun4m_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10); master_l10_counter = &sun4m_timers->l10_cur_count; master_l10_limit = &sun4m_timers->l10_timer_limit; irq = request_irq(TIMER_IRQ, counter_fn, (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); if (irq) { prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ); prom_halt(); } if (!cpu_find_by_instance(1, NULL, NULL)) { for(cpu = 0; cpu < 4; cpu++) sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0; sun4m_interrupts->set = SUN4M_INT_E14; } else { sun4m_timers->cpu_timers[0].l14_timer_limit = 0; } #ifdef CONFIG_SMP { unsigned long flags; extern unsigned long lvl14_save[4]; struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)]; /* For SMP we use the level 14 ticker, however the bootup code * has copied the firmwares level 14 vector into boot cpu's * trap table, we must fix this now or we get squashed. */ local_irq_save(flags); trap_table->inst_one = lvl14_save[0]; trap_table->inst_two = lvl14_save[1]; trap_table->inst_three = lvl14_save[2]; trap_table->inst_four = lvl14_save[3]; local_flush_cache_all(); local_irq_restore(flags); } #endif }
void __init sun4m_init_IRQ(void) { int ie_node,i; struct linux_prom_registers int_regs[PROMREG_MAX]; int num_regs; struct resource r; int mid; local_irq_disable(); if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 || (ie_node = prom_getchild (ie_node)) == 0 || (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) { prom_printf("Cannot find /obio/interrupt node\n"); prom_halt(); } num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs, sizeof(int_regs)); num_regs = (num_regs/sizeof(struct linux_prom_registers)); /* Apply the obio ranges to these registers. */ prom_apply_obio_ranges(int_regs, num_regs); int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr; int_regs[4].reg_size = int_regs[num_regs-1].reg_size; int_regs[4].which_io = int_regs[num_regs-1].which_io; for(ie_node = 1; ie_node < 4; ie_node++) { int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE; int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size; int_regs[ie_node].which_io = int_regs[ie_node-1].which_io; } memset((char *)&r, 0, sizeof(struct resource)); /* Map the interrupt registers for all possible cpus. */ r.flags = int_regs[0].which_io; r.start = int_regs[0].phys_addr; sun4m_interrupts = (struct sun4m_intregs *) sbus_ioremap(&r, 0, PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu"); /* Map the system interrupt control registers. */ r.flags = int_regs[4].which_io; r.start = int_regs[4].phys_addr; sbus_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system"); sun4m_interrupts->set = ~SUN4M_INT_MASKALL; for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++) sun4m_interrupts->cpu_intregs[mid].clear = ~0x17fff; if (!cpu_find_by_instance(1, NULL, NULL)) { /* system wide interrupts go to cpu 0, this should always * be safe because it is guaranteed to be fitted or OBP doesn't * come up * * Not sure, but writing here on SLAVIO systems may puke * so I don't do it unless there is more than 1 cpu. */ irq_rcvreg = (unsigned long *) &sun4m_interrupts->undirected_target; sun4m_interrupts->undirected_target = 0; } BTFIXUPSET_CALL(sbint_to_irq, sun4m_sbint_to_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM); sparc_init_timers = sun4m_init_timers; #ifdef CONFIG_SMP BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM); #endif /* Cannot enable interrupts until OBP ticker is disabled. */ }
/* Initialize the memory lists based upon the prom version. */ __initfunc(void prom_meminit(void)) { int node = 0; unsigned int iter, num_regs; struct linux_mlist_v0 *mptr; /* ptr for traversal */ switch(prom_vers) { case PROM_V0: /* Nice, kind of easier to do in this case. */ /* First, the total physical descriptors. */ for(mptr = (*(romvec->pv_v0mem.v0_totphys)), iter=0; mptr; mptr=mptr->theres_more, iter++) { prom_phys_total[iter].start_adr = mptr->start_adr; prom_phys_total[iter].num_bytes = mptr->num_bytes; prom_phys_total[iter].theres_more = &prom_phys_total[iter+1]; } prom_phys_total[iter-1].theres_more = 0x0; /* Second, the total prom taken descriptors. */ for(mptr = (*(romvec->pv_v0mem.v0_prommap)), iter=0; mptr; mptr=mptr->theres_more, iter++) { prom_prom_taken[iter].start_adr = mptr->start_adr; prom_prom_taken[iter].num_bytes = mptr->num_bytes; prom_prom_taken[iter].theres_more = &prom_prom_taken[iter+1]; } prom_prom_taken[iter-1].theres_more = 0x0; /* Last, the available physical descriptors. */ for(mptr = (*(romvec->pv_v0mem.v0_available)), iter=0; mptr; mptr=mptr->theres_more, iter++) { prom_phys_avail[iter].start_adr = mptr->start_adr; prom_phys_avail[iter].num_bytes = mptr->num_bytes; prom_phys_avail[iter].theres_more = &prom_phys_avail[iter+1]; } prom_phys_avail[iter-1].theres_more = 0x0; /* Sort all the lists. */ prom_sortmemlist(prom_phys_total); prom_sortmemlist(prom_prom_taken); prom_sortmemlist(prom_phys_avail); break; case PROM_V2: case PROM_V3: /* Grrr, have to traverse the prom device tree ;( */ node = prom_getchild(prom_root_node); node = prom_searchsiblings(node, "memory"); num_regs = prom_getproperty(node, "available", (char *) prom_reg_memlist, sizeof(prom_reg_memlist)); num_regs = (num_regs/sizeof(struct linux_prom_registers)); for(iter=0; iter<num_regs; iter++) { prom_phys_avail[iter].start_adr = (char *) prom_reg_memlist[iter].phys_addr; prom_phys_avail[iter].num_bytes = (unsigned long) prom_reg_memlist[iter].reg_size; prom_phys_avail[iter].theres_more = &prom_phys_avail[iter+1]; } prom_phys_avail[iter-1].theres_more = 0x0; num_regs = prom_getproperty(node, "reg", (char *) prom_reg_memlist, sizeof(prom_reg_memlist)); num_regs = (num_regs/sizeof(struct linux_prom_registers)); for(iter=0; iter<num_regs; iter++) { prom_phys_total[iter].start_adr = (char *) prom_reg_memlist[iter].phys_addr; prom_phys_total[iter].num_bytes = (unsigned long) prom_reg_memlist[iter].reg_size; prom_phys_total[iter].theres_more = &prom_phys_total[iter+1]; } prom_phys_total[iter-1].theres_more = 0x0; node = prom_getchild(prom_root_node); node = prom_searchsiblings(node, "virtual-memory"); num_regs = prom_getproperty(node, "available", (char *) prom_reg_memlist, sizeof(prom_reg_memlist)); num_regs = (num_regs/sizeof(struct linux_prom_registers)); /* Convert available virtual areas to taken virtual * areas. First sort, then convert. */ for(iter=0; iter<num_regs; iter++) { prom_prom_taken[iter].start_adr = (char *) prom_reg_memlist[iter].phys_addr; prom_prom_taken[iter].num_bytes = (unsigned long) prom_reg_memlist[iter].reg_size; prom_prom_taken[iter].theres_more = &prom_phys_total[iter+1]; } prom_prom_taken[iter-1].theres_more = 0x0; prom_sortmemlist(prom_prom_taken); /* Finally, convert. */ for(iter=0; iter<num_regs; iter++) { prom_prom_taken[iter].start_adr = prom_prom_taken[iter].start_adr + prom_prom_taken[iter].num_bytes; prom_prom_taken[iter].num_bytes = prom_prom_taken[iter+1].start_adr - prom_prom_taken[iter].start_adr; } prom_prom_taken[iter-1].num_bytes = 0xffffffff - (unsigned long) prom_prom_taken[iter-1].start_adr; /* Sort the other two lists. */ prom_sortmemlist(prom_phys_total); prom_sortmemlist(prom_phys_avail); break; case PROM_SUN4: #ifdef CONFIG_SUN4 /* how simple :) */ prom_phys_total[0].start_adr = 0x0; prom_phys_total[0].num_bytes = *(sun4_romvec->memorysize); prom_phys_total[0].theres_more = 0x0; prom_prom_taken[0].start_adr = 0x0; prom_prom_taken[0].num_bytes = 0x0; prom_prom_taken[0].theres_more = 0x0; prom_phys_avail[0].start_adr = 0x0; prom_phys_avail[0].num_bytes = *(sun4_romvec->memoryavail); prom_phys_avail[0].theres_more = 0x0; #endif break; case PROM_AP1000: #if CONFIG_AP1000 /* really simple memory map */ prom_phys_total[0].start_adr = 0x00000000; prom_phys_total[0].num_bytes = ap_memory_size(); prom_phys_total[0].theres_more = 0x0; prom_prom_taken[0].start_adr = 0x00000000; prom_prom_taken[0].num_bytes = 0x00000000; prom_prom_taken[0].theres_more = 0x0; prom_phys_avail[0].start_adr = 0x00000000; prom_phys_avail[0].num_bytes = prom_phys_total[0].num_bytes; prom_phys_avail[0].theres_more = 0x0; #endif default: break; }; /* Link all the lists into the top-level descriptor. */ prom_memlist.v0_totphys=&prom_ptot_ptr; prom_memlist.v0_prommap=&prom_ptak_ptr; prom_memlist.v0_available=&prom_pavl_ptr; return; }
__initfunc(void pcic_probe(void)) { struct linux_prom_registers regs[PROMREG_MAX]; struct linux_pbm_info* pbm; char namebuf[64]; int node; int err; if (pcibios_present()) { prom_printf("PCIC: called twice!\n"); prom_halt(); } node = prom_getchild (prom_root_node); node = prom_searchsiblings (node, "pci"); if (node == 0) return; /* * Map in PCIC register set, config space, and IO base */ err = prom_getproperty(node, "reg", (char*)regs, sizeof(regs)); if (err == 0 || err == -1) { prom_printf("PCIC: Error, cannot get PCIC registers " "from PROM.\n"); prom_halt(); } pcic = &PCIC; pcic->pcic_regs = (unsigned long)sparc_alloc_io(regs[0].phys_addr, NULL, regs[0].reg_size, "PCIC Registers", 0, 0); if (!pcic->pcic_regs) { prom_printf("PCIC: Error, cannot map PCIC registers.\n"); prom_halt(); } pcic->pcic_io_phys = regs[1].phys_addr; pcic->pcic_io = (unsigned long)sparc_alloc_io(regs[1].phys_addr, NULL, regs[1].reg_size, "PCIC IO Base", 0, 0); if (pcic->pcic_io == 0UL) { prom_printf("PCIC: Error, cannot map PCIC IO Base.\n"); prom_halt(); } pcic->pcic_config_space_addr = (unsigned long)sparc_alloc_io (regs[2].phys_addr, NULL, regs[2].reg_size * 2, "PCI Config Space Address", 0, 0); if (pcic->pcic_config_space_addr == 0UL) { prom_printf("PCIC: Error, cannot map" "PCI Configuration Space Address.\n"); prom_halt(); } /* * Docs say three least significant bits in address and data * must be the same. Thus, we need adjust size of data. */ pcic->pcic_config_space_data = (unsigned long)sparc_alloc_io (regs[3].phys_addr, NULL, regs[3].reg_size * 2, "PCI Config Space Data", 0, 0); if (pcic->pcic_config_space_data == 0UL) { prom_printf("PCIC: Error, cannot map" "PCI Configuration Space Data.\n"); prom_halt(); } pbm = &pcic->pbm; pbm->prom_node = node; prom_getstring(node, "name", namebuf, sizeof(namebuf)); strcpy(pbm->prom_name, namebuf); }
void __init sbus_init(void) { int nd, this_sbus, sbus_devs, topnd, iommund; unsigned int sbus_clock; struct sbus_bus *sbus; struct sbus_dev *this_dev; int num_sbus = 0; /* How many did we find? */ #ifndef __sparc_v9__ register_proc_sparc_ioport(); #endif #ifdef CONFIG_SUN4 return sun4_dvma_init(); #endif topnd = prom_getchild(prom_root_node); /* Finding the first sbus is a special case... */ iommund = 0; if(sparc_cpu_model == sun4u) { nd = prom_searchsiblings(topnd, "sbus"); if(nd == 0) { #ifdef CONFIG_PCI if (!pcibios_present()) { prom_printf("Neither SBUS nor PCI found.\n"); prom_halt(); } else { #ifdef __sparc_v9__ firetruck_init(); #endif } return; #else prom_printf("YEEE, UltraSparc sbus not found\n"); prom_halt(); #endif } } else if(sparc_cpu_model == sun4d) { if((iommund = prom_searchsiblings(topnd, "io-unit")) == 0 || (nd = prom_getchild(iommund)) == 0 || (nd = prom_searchsiblings(nd, "sbi")) == 0) { panic("sbi not found"); } } else if((nd = prom_searchsiblings(topnd, "sbus")) == 0) { if((iommund = prom_searchsiblings(topnd, "iommu")) == 0 || (nd = prom_getchild(iommund)) == 0 || (nd = prom_searchsiblings(nd, "sbus")) == 0) { #ifdef CONFIG_PCI if (!pcibios_present()) { prom_printf("Neither SBUS nor PCI found.\n"); prom_halt(); } return; #else /* No reason to run further - the data access trap will occur. */ panic("sbus not found"); #endif } } /* Ok, we've found the first one, allocate first SBus struct * and place in chain. */ sbus = sbus_root = kmalloc(sizeof(struct sbus_bus), GFP_ATOMIC); sbus->next = NULL; sbus->prom_node = nd; this_sbus = nd; if(iommund && sparc_cpu_model != sun4u && sparc_cpu_model != sun4d) iommu_init(iommund, sbus); /* Loop until we find no more SBUS's */ while(this_sbus) { #ifdef __sparc_v9__ /* IOMMU hides inside SBUS/SYSIO prom node on Ultra. */ if(sparc_cpu_model == sun4u) { extern void sbus_iommu_init(int prom_node, struct sbus_bus *sbus); sbus_iommu_init(this_sbus, sbus); } #endif #ifndef __sparc_v9__ if (sparc_cpu_model == sun4d) iounit_init(this_sbus, iommund, sbus); #endif printk("sbus%d: ", num_sbus); sbus_clock = prom_getint(this_sbus, "clock-frequency"); if(sbus_clock == -1) sbus_clock = (25*1000*1000); printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000), (int) (((sbus_clock/1000)%1000 != 0) ? (((sbus_clock/1000)%1000) + 1000) : 0)); prom_getstring(this_sbus, "name", sbus->prom_name, sizeof(sbus->prom_name)); sbus->clock_freq = sbus_clock; #ifndef __sparc_v9__ if (sparc_cpu_model == sun4d) { sbus->devid = prom_getint(iommund, "device-id"); sbus->board = prom_getint(iommund, "board#"); } #endif sbus_bus_ranges_init(iommund, sbus); sbus_devs = prom_getchild(this_sbus); if (!sbus_devs) { sbus->devices = NULL; goto next_bus; } sbus->devices = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC); this_dev = sbus->devices; this_dev->next = NULL; this_dev->bus = sbus; this_dev->parent = NULL; fill_sbus_device(sbus_devs, this_dev); /* Should we traverse for children? */ if(prom_getchild(sbus_devs)) { /* Allocate device node */ this_dev->child = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC); /* Fill it */ this_dev->child->bus = sbus; this_dev->child->next = 0; fill_sbus_device(prom_getchild(sbus_devs), this_dev->child); sbus_do_child_siblings(prom_getchild(sbus_devs), this_dev->child, this_dev, sbus); } else { this_dev->child = NULL; } while((sbus_devs = prom_getsibling(sbus_devs)) != 0) { /* Allocate device node */ this_dev->next = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC); this_dev = this_dev->next; this_dev->next = NULL; /* Fill it */ this_dev->bus = sbus; this_dev->parent = NULL; fill_sbus_device(sbus_devs, this_dev); /* Is there a child node hanging off of us? */ if(prom_getchild(sbus_devs)) { /* Get new device struct */ this_dev->child = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC); /* Fill it */ this_dev->child->bus = sbus; this_dev->child->next = 0; fill_sbus_device(prom_getchild(sbus_devs), this_dev->child); sbus_do_child_siblings(prom_getchild(sbus_devs), this_dev->child, this_dev, sbus); } else { this_dev->child = NULL; } } /* Walk all devices and apply parent ranges. */ sbus_fixup_all_regs(sbus->devices); dvma_init(sbus); next_bus: num_sbus++; if(sparc_cpu_model == sun4u) { this_sbus = prom_getsibling(this_sbus); if(!this_sbus) break; this_sbus = prom_searchsiblings(this_sbus, "sbus"); } else if(sparc_cpu_model == sun4d) { iommund = prom_getsibling(iommund); if(!iommund) break; iommund = prom_searchsiblings(iommund, "io-unit"); if(!iommund) break; this_sbus = prom_searchsiblings(prom_getchild(iommund), "sbi"); } else { this_sbus = prom_getsibling(this_sbus); if(!this_sbus) break; this_sbus = prom_searchsiblings(this_sbus, "sbus"); } if(this_sbus) { sbus->next = kmalloc(sizeof(struct sbus_bus), GFP_ATOMIC); sbus = sbus->next; sbus->next = NULL; sbus->prom_node = this_sbus; } else { break; } } /* while(this_sbus) */ if (sparc_cpu_model == sun4d) { extern void sun4d_init_sbi_irq(void); sun4d_init_sbi_irq(); } rs_init(); #ifdef __sparc_v9__ if (sparc_cpu_model == sun4u) { firetruck_init(); } #endif #ifdef CONFIG_SUN_AUXIO if (sparc_cpu_model == sun4u) auxio_probe (); #endif #ifdef __sparc_v9__ if (sparc_cpu_model == sun4u) { extern void clock_probe(void); clock_probe(); } #endif }