__initfunc(void auxio_probe(void)) { int node, auxio_nd; struct linux_prom_registers auxregs[1]; 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 */ auxio_register = (unsigned char *) sparc_alloc_io(auxregs[0].phys_addr, 0, auxregs[0].reg_size, "auxiliaryIO", auxregs[0].which_io, 0x0); /* 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; }
static volatile struct bpp_regs *map_bpp(struct linux_sbus_device *dev, int idx) { volatile struct bpp_regs *regs; /* * PROM reports different numbers on Zebra and on DMA2. * We need to figure out when to apply parent ranges. * printk will show this on different machines. */ /* IPC Zebra 1.fa200000[1c] i=2 */ prom_apply_sbus_ranges(dev->my_bus, &dev->reg_addrs[0], dev->num_registers, dev); regs = sparc_alloc_io(dev->reg_addrs[0].phys_addr, 0, dev->reg_addrs[0].reg_size, "bpp", dev->reg_addrs[0].which_io, 0x0); printk("bpp%d.map_bpp: 0x%x.%p[0x%x] i=%d\n", idx, dev->reg_addrs[0].which_io, dev->reg_addrs[0].phys_addr, dev->reg_addrs[0].reg_size, dev->irqs[0]); return regs; }
__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"); }
int init_vfc_device(struct linux_sbus_device *sdev,struct vfc_dev *dev, int instance) { if(!dev) { printk(KERN_ERR "VFC: Bogus pointer passed\n"); return -ENOMEM; } printk("Initializing vfc%d\n",instance); dev->regs=NULL; prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0], sdev->num_registers, sdev); dev->regs=sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, sizeof(struct vfc_regs), vfcstr, sdev->reg_addrs[0].which_io, 0x0); dev->which_io=sdev->reg_addrs[0].which_io; dev->phys_regs=(struct vfc_regs *)sdev->reg_addrs[0].phys_addr; if(!dev->regs) return -EIO; printk("vfc%d: registers mapped at phys_addr: 0x%lx\n virt_addr: 0x%lx\n", instance,(unsigned long)sdev->reg_addrs[0].phys_addr,(unsigned long)dev->regs); if(init_vfc_devstruct(dev,instance)) return -EINVAL; if(init_vfc_hw(dev)) return -EIO; return 0; }
__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); }
__initfunc(void auxio_probe(void)) { struct linux_sbus *bus; struct linux_sbus_device *sdev = 0; struct linux_prom_registers auxregs[1]; for_each_sbus(bus) { for_each_sbusdev(sdev, bus) { if(!strcmp(sdev->prom_name, "auxio")) { break; } } } if (!sdev) { #ifdef CONFIG_PCI struct linux_ebus *ebus; struct linux_ebus_device *edev = 0; unsigned long led_auxio; for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { if (!strcmp(edev->prom_name, "auxio")) goto ebus_done; } } ebus_done: if (edev) { if (check_region(edev->base_address[0], sizeof(unsigned int))) { prom_printf("%s: Can't get region %lx, %d\n", __FUNCTION__, edev->base_address[0], sizeof(unsigned int)); prom_halt(); } request_region(edev->base_address[0], sizeof(unsigned int), "LED auxio"); led_auxio = edev->base_address[0]; outl(0x01, led_auxio); return; } #endif if(central_bus) { auxio_register = NULL; return; } prom_printf("Cannot find auxio node, cannot continue...\n"); prom_halt(); } prom_getproperty(sdev->prom_node, "reg", (char *) auxregs, sizeof(auxregs)); prom_apply_sbus_ranges(sdev->my_bus, auxregs, 0x1, sdev); /* Map the register both read and write */ auxio_register = (unsigned char *) sparc_alloc_io(auxregs[0].phys_addr, 0, auxregs[0].reg_size, "auxiliaryIO", auxregs[0].which_io, 0x0); TURN_ON_LED; }
__initfunc(void sun4m_init_IRQ(void)) { int ie_node,i; struct linux_prom_registers int_regs[PROMREG_MAX]; int num_regs; __cli(); 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; } /* Map the interrupt registers for all possible cpus. */ sun4m_interrupts = sparc_alloc_io(int_regs[0].phys_addr, 0, PAGE_SIZE*NCPUS, "interrupts_percpu", int_regs[0].which_io, 0x0); /* Map the system interrupt control registers. */ sparc_alloc_io(int_regs[4].phys_addr, 0, int_regs[4].reg_size, "interrupts_system", int_regs[4].which_io, 0x0); sun4m_interrupts->set = ~SUN4M_INT_MASKALL; for (i=0; i<linux_num_cpus; i++) sun4m_interrupts->cpu_intregs[i].clear = ~0x17fff; if (linux_num_cpus > 1) { /* 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(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); BTFIXUPSET_CALL(__irq_itoa, sun4m_irq_itoa, BTFIXUPCALL_NORM); init_timers = sun4m_init_timers; #ifdef __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. */ }
__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 }
__initfunc(char *tcxfb_init(struct fb_info_sbusfb *fb)) { struct fb_fix_screeninfo *fix = &fb->fix; struct display *disp = &fb->disp; struct fbtype *type = &fb->type; unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr; int lowdepth, i, j; #ifndef FBCON_HAS_CFB8 return NULL; #endif lowdepth = prom_getbool (fb->prom_node, "tcx-8-bit"); if (lowdepth) { strcpy(fb->info.modename, "TCX8"); strcpy(fix->id, "TCX8"); } else { strcpy(fb->info.modename, "TCX24"); strcpy(fix->id, "TCX24"); } fix->line_length = fb->var.xres_virtual; disp->scrollmode = SCROLL_YREDRAW; if (!disp->screen_base) disp->screen_base = (char *)sparc_alloc_io(phys, 0, type->fb_size, "tcx_ram", fb->iospace, 0); disp->screen_base += fix->line_length * fb->y_margin + fb->x_margin; fb->s.tcx.tec = (struct tcx_tec *)sparc_alloc_io(fb->sbdp->reg_addrs[7].phys_addr, 0, sizeof(struct tcx_tec), "tcx_tec", fb->iospace, 0); fb->s.tcx.thc = (struct tcx_thc *)sparc_alloc_io(fb->sbdp->reg_addrs[9].phys_addr, 0, sizeof(struct tcx_thc), "tcx_thc", fb->iospace, 0); fb->s.tcx.bt = (struct bt_regs *)sparc_alloc_io(fb->sbdp->reg_addrs[8].phys_addr, 0, sizeof(struct bt_regs), "tcx_dac", fb->iospace, 0); if (!lowdepth) { fb->s.tcx.cplane = (u32 *)sparc_alloc_io(fb->sbdp->reg_addrs[4].phys_addr, 0, type->fb_size*4, "tcx_cplane", fb->iospace, 0); type->fb_depth = 24; fb->switch_from_graph = tcx_switch_from_graph; } else { /* As there can be one tcx in a machine only, we can write directly into tcx_mmap_map */ tcx_mmap_map[1].size = SBUS_MMAP_EMPTY; tcx_mmap_map[4].size = SBUS_MMAP_EMPTY; tcx_mmap_map[5].size = SBUS_MMAP_EMPTY; tcx_mmap_map[6].size = SBUS_MMAP_EMPTY; } fb->dispsw = fbcon_cfb8; fb->margins = tcx_margins; fb->loadcmap = tcx_loadcmap; if (prom_getbool (fb->prom_node, "hw-cursor")) { fb->setcursor = tcx_setcursor; fb->setcursormap = tcx_setcursormap; fb->setcurshape = tcx_setcurshape; } fb->restore_palette = tcx_restore_palette; fb->blank = tcx_blank; fb->unblank = tcx_unblank; fb->reset = tcx_reset; fb->physbase = 0; for (i = 0; i < 13; i++) { /* tcx_mmap_map has to be sorted by voff, while order of phys registers from PROM differs a little bit. Here is the correction */ switch (i) { case 10: j = 12; break; case 11: case 12: j = i - 1; break; default: j = i; break; } tcx_mmap_map[i].poff = fb->sbdp->reg_addrs[j].phys_addr; } fb->mmap_map = tcx_mmap_map; /* Initialize Brooktree DAC */ fb->s.tcx.bt->addr = 0x04 << 24; /* color planes */ fb->s.tcx.bt->control = 0xff << 24; fb->s.tcx.bt->addr = 0x05 << 24; fb->s.tcx.bt->control = 0x00 << 24; fb->s.tcx.bt->addr = 0x06 << 24; /* overlay plane */ fb->s.tcx.bt->control = 0x73 << 24; fb->s.tcx.bt->addr = 0x07 << 24; fb->s.tcx.bt->control = 0x00 << 24; sprintf(idstring, "tcx at %x.%08lx Rev %d.%d %s", fb->iospace, phys, (fb->s.tcx.thc->thc_rev >> TCX_THC_REV_REV_SHIFT) & TCX_THC_REV_REV_MASK, (fb->s.tcx.thc->thc_rev >> TCX_THC_REV_MINREV_SHIFT) & TCX_THC_REV_MINREV_MASK, lowdepth ? "8-bit only" : "24-bit depth"); tcx_reset(fb); return idstring; }
__initfunc(char *cgthreefb_init(struct fb_info_sbusfb *fb)) { struct fb_fix_screeninfo *fix = &fb->fix; struct display *disp = &fb->disp; struct fbtype *type = &fb->type; unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr; int cgRDI = strstr(fb->sbdp->prom_name, "cgRDI") != NULL; #ifndef FBCON_HAS_CFB8 return NULL; #endif if (!fb->s.cg3.regs) { fb->s.cg3.regs = (struct cg3_regs *)sparc_alloc_io(phys+CG3_REGS_OFFSET, 0, sizeof(struct cg3_regs), "cg3_regs", fb->iospace, 0); if (cgRDI) { char buffer[40]; char *p; int ww, hh; *buffer = 0; prom_getstring (fb->prom_node, "params", buffer, sizeof(buffer)); if (*buffer) { ww = simple_strtoul (buffer, &p, 10); if (ww && *p == 'x') { hh = simple_strtoul (p + 1, &p, 10); if (hh && *p == '-') { if (type->fb_width != ww || type->fb_height != hh) { type->fb_width = ww; type->fb_height = hh; return SBUSFBINIT_SIZECHANGE; } } } } } } strcpy(fb->info.modename, "CGthree"); strcpy(fix->id, "CGthree"); fix->line_length = fb->var.xres_virtual; disp->scrollmode = SCROLL_YREDRAW; if (!disp->screen_base) disp->screen_base = (char *)sparc_alloc_io(phys+CG3_RAM_OFFSET, 0, type->fb_size, "cg3_ram", fb->iospace, 0); disp->screen_base += fix->line_length * fb->y_margin + fb->x_margin; fb->dispsw = fbcon_cfb8; fb->margins = cg3_margins; fb->loadcmap = cg3_loadcmap; fb->blank = cg3_blank; fb->unblank = cg3_unblank; fb->physbase = phys; fb->mmap_map = cg3_mmap_map; #ifdef __sparc_v9__ sprintf(idstring, "%s at %016lx", cgRDI ? "cgRDI" : "cgthree", phys); #else sprintf(idstring, "%s at %x.%08lx", cgRDI ? "cgRDI" : "cgthree", fb->iospace, phys); #endif if (!prom_getbool(fb->prom_node, "width")) { /* Ugh, broken PROM didn't initialize us. * Let's deal with this ourselves. */ enum cg3_type type; u8 *p; if (cgRDI) type = CG3_RDI; else { u8 status = fb->s.cg3.regs->status, mon; if ((status & CG3_SR_ID_MASK) == CG3_SR_ID_COLOR) { mon = status & CG3_SR_RES_MASK; if (mon == CG3_SR_1152_900_76_A || mon == CG3_SR_1152_900_76_B) type = CG3_AT_76HZ; else type = CG3_AT_66HZ; } else { prom_printf("cgthree: can't handle SR %02x\n", status); prom_halt(); return NULL; /* fool gcc. */ } } for (p = cg3_regvals[type]; *p; p += 2) ((u8 *)fb->s.cg3.regs)[p[0]] = p[1]; for (p = cg3_dacvals; *p; p += 2) { *(volatile u8 *)&fb->s.cg3.regs->cmap.addr = p[0]; *(volatile u8 *)&fb->s.cg3.regs->cmap.control = p[1]; } } return idstring; }