diff options
Diffstat (limited to 'arch/sparc64/kernel/central.c')
-rw-r--r-- | arch/sparc64/kernel/central.c | 286 |
1 files changed, 176 insertions, 110 deletions
diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c index 198841f89..2c4fb1355 100644 --- a/arch/sparc64/kernel/central.c +++ b/arch/sparc64/kernel/central.c @@ -1,7 +1,7 @@ -/* $Id: central.c,v 1.11 1998/12/14 12:18:16 davem Exp $ +/* $Id: central.c,v 1.13 1999/12/01 10:44:43 davem Exp $ * central.c: Central FHC driver for Sunfire/Starfire/Wildfire. * - * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1997, 1999 David S. Miller (davem@redhat.com) */ #include <linux/kernel.h> @@ -10,6 +10,8 @@ #include <linux/timer.h> #include <linux/sched.h> #include <linux/delay.h> +#include <linux/init.h> +#include <linux/bootmem.h> #include <asm/page.h> #include <asm/fhc.h> @@ -25,10 +27,80 @@ static inline unsigned long long_align(unsigned long addr) ~(sizeof(unsigned long) - 1)); } -extern void prom_central_ranges_init(int cnode, struct linux_central *central); -extern void prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc); +static void central_ranges_init(int cnode, struct linux_central *central) +{ + int success; + + central->num_central_ranges = 0; + success = prom_getproperty(central->prom_node, "ranges", + (char *) central->central_ranges, + sizeof (central->central_ranges)); + if (success != -1) + central->num_central_ranges = (success/sizeof(struct linux_prom_ranges)); +} -static unsigned long probe_other_fhcs(unsigned long memory_start) +static void fhc_ranges_init(int fnode, struct linux_fhc *fhc) +{ + int success; + + fhc->num_fhc_ranges = 0; + success = prom_getproperty(fhc->prom_node, "ranges", + (char *) fhc->fhc_ranges, + sizeof (fhc->fhc_ranges)); + if (success != -1) + fhc->num_fhc_ranges = (success/sizeof(struct linux_prom_ranges)); +} + +/* Range application routines are exported to various drivers, + * so do not __init this. + */ +static void adjust_regs(struct linux_prom_registers *regp, int nregs, + struct linux_prom_ranges *rangep, int nranges) +{ + int regc, rngc; + + for (regc = 0; regc < nregs; regc++) { + for (rngc = 0; rngc < nranges; rngc++) + if (regp[regc].which_io == rangep[rngc].ot_child_space) + break; /* Fount it */ + if (rngc == nranges) /* oops */ + prom_printf("adjust_regs: Could not find range with matching bus type...\n"); + regp[regc].which_io = rangep[rngc].ot_parent_space; + regp[regc].phys_addr += rangep[rngc].ot_parent_base; + } +} + +/* Apply probed fhc ranges to registers passed, if no ranges return. */ +void apply_fhc_ranges(struct linux_fhc *fhc, + struct linux_prom_registers *regs, + int nregs) +{ + if(fhc->num_fhc_ranges) + adjust_regs(regs, nregs, fhc->fhc_ranges, + fhc->num_fhc_ranges); +} + +/* Apply probed central ranges to registers passed, if no ranges return. */ +void apply_central_ranges(struct linux_central *central, + struct linux_prom_registers *regs, int nregs) +{ + if(central->num_central_ranges) + adjust_regs(regs, nregs, central->central_ranges, + central->num_central_ranges); +} + +void * __init central_alloc_bootmem(unsigned long size) +{ + void *ret; + + ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL); + if (ret != NULL) + memset(ret, 0, size); + + return ret; +} + +static void probe_other_fhcs(void) { struct linux_prom64_registers fpregs[6]; char namebuf[128]; @@ -45,9 +117,12 @@ static unsigned long probe_other_fhcs(unsigned long memory_start) int board; u32 tmp; - fhc = (struct linux_fhc *)memory_start; - memory_start += sizeof(struct linux_fhc); - memory_start = long_align(memory_start); + fhc = (struct linux_fhc *) + central_alloc_bootmem(sizeof(struct linux_fhc)); + if (fhc == NULL) { + prom_printf("probe_other_fhcs: Cannot alloc fhc.\n"); + prom_halt(); + } /* Link it into the FHC chain. */ fhc->next = fhc_list; @@ -59,7 +134,7 @@ static unsigned long probe_other_fhcs(unsigned long memory_start) fhc->prom_node = node; prom_getstring(node, "name", namebuf, sizeof(namebuf)); strcpy(fhc->prom_name, namebuf); - prom_fhc_ranges_init(node, fhc); + fhc_ranges_init(node, fhc); /* Non-central FHC's have 64-bit OBP format registers. */ if(prom_getproperty(node, "reg", @@ -69,29 +144,23 @@ static unsigned long probe_other_fhcs(unsigned long memory_start) } /* Only central FHC needs special ranges applied. */ - fhc->fhc_regs.pregs = (struct fhc_internal_regs *) - __va(fpregs[0].phys_addr); - fhc->fhc_regs.ireg = (struct fhc_ign_reg *) - __va(fpregs[1].phys_addr); - fhc->fhc_regs.ffregs = (struct fhc_fanfail_regs *) - __va(fpregs[2].phys_addr); - fhc->fhc_regs.sregs = (struct fhc_system_regs *) - __va(fpregs[3].phys_addr); - fhc->fhc_regs.uregs = (struct fhc_uart_regs *) - __va(fpregs[4].phys_addr); - fhc->fhc_regs.tregs = (struct fhc_tod_regs *) - __va(fpregs[5].phys_addr); + fhc->fhc_regs.pregs = fpregs[0].phys_addr; + fhc->fhc_regs.ireg = fpregs[1].phys_addr; + fhc->fhc_regs.ffregs = fpregs[2].phys_addr; + fhc->fhc_regs.sregs = fpregs[3].phys_addr; + fhc->fhc_regs.uregs = fpregs[4].phys_addr; + fhc->fhc_regs.tregs = fpregs[5].phys_addr; board = prom_getintdefault(node, "board#", -1); fhc->board = board; - tmp = fhc->fhc_regs.pregs->fhc_jtag_ctrl; + tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_JCTRL); if((tmp & FHC_JTAG_CTRL_MENAB) != 0) fhc->jtag_master = 1; else fhc->jtag_master = 0; - tmp = fhc->fhc_regs.pregs->fhc_id; + tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID); printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] %s\n", board, (tmp & FHC_ID_VERS) >> 28, @@ -103,7 +172,9 @@ static unsigned long probe_other_fhcs(unsigned long memory_start) * the system. When it is clear, this identifies * the central board. */ - fhc->fhc_regs.pregs->fhc_control |= FHC_CONTROL_IXIST; + tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); + tmp |= FHC_CONTROL_IXIST; + upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL); /* Look for the next FHC. */ node = prom_getsibling(node); @@ -113,8 +184,6 @@ static unsigned long probe_other_fhcs(unsigned long memory_start) if(node == 0) break; } - - return memory_start; } static void probe_clock_board(struct linux_central *central, @@ -135,22 +204,20 @@ static void probe_clock_board(struct linux_central *central, prom_halt(); } nregs /= sizeof(struct linux_prom_registers); - prom_apply_fhc_ranges(fhc, &cregs[0], nregs); - prom_apply_central_ranges(central, &cregs[0], nregs); - central->cfreg = (volatile u8 *) - __va((((unsigned long)cregs[0].which_io) << 32) | - (((unsigned long)cregs[0].phys_addr)+0x02)); - central->clkregs = (struct clock_board_regs *) - __va((((unsigned long)cregs[1].which_io) << 32) | - (((unsigned long)cregs[1].phys_addr))); + apply_fhc_ranges(fhc, &cregs[0], nregs); + apply_central_ranges(central, &cregs[0], nregs); + central->cfreg = ((((unsigned long)cregs[0].which_io) << 32UL) | + ((unsigned long)cregs[0].phys_addr)); + central->clkregs = ((((unsigned long)cregs[1].which_io) << 32UL) | + ((unsigned long)cregs[1].phys_addr)); + if(nregs == 2) - central->clkver = NULL; + central->clkver = 0UL; else - central->clkver = (volatile u8 *) - __va((((unsigned long)cregs[2].which_io) << 32) | - (((unsigned long)cregs[2].phys_addr))); + central->clkver = ((((unsigned long)cregs[2].which_io) << 32UL) | + ((unsigned long)cregs[2].phys_addr)); - tmp = central->clkregs->stat1; + tmp = upa_readb(central->clkregs + CLOCK_STAT1); tmp &= 0xc0; switch(tmp) { case 0x40: @@ -160,9 +227,9 @@ static void probe_clock_board(struct linux_central *central, nslots = 8; break; case 0x80: - if(central->clkver != NULL && - *(central->clkver) != 0) { - if((*(central->clkver) & 0x80) != 0) + if(central->clkver != 0UL && + upa_readb(central->clkver) != 0) { + if((upa_readb(central->clkver) & 0x80) != 0) nslots = 4; else nslots = 5; @@ -174,11 +241,11 @@ static void probe_clock_board(struct linux_central *central, }; central->slots = nslots; printk("CENTRAL: Detected %d slot Enterprise system. cfreg[%02x] cver[%02x]\n", - central->slots, *(central->cfreg), - (central->clkver ? *(central->clkver) : 0x00)); + central->slots, upa_readb(central->cfreg), + (central->clkver ? upa_readb(central->clkver) : 0x00)); } -unsigned long central_probe(unsigned long memory_start) +void central_probe(void) { struct linux_prom_registers fpregs[6]; struct linux_fhc *fhc; @@ -190,18 +257,23 @@ unsigned long central_probe(unsigned long memory_start) extern void starfire_check(void); starfire_check(); - return memory_start; + return; } /* Ok we got one, grab some memory for software state. */ - memory_start = long_align(memory_start); - central_bus = (struct linux_central *) (memory_start); + central_bus = (struct linux_central *) + central_alloc_bootmem(sizeof(struct linux_central)); + if (central_bus == NULL) { + prom_printf("central_probe: Cannot alloc central_bus.\n"); + prom_halt(); + } - memory_start += sizeof(struct linux_central); - memory_start = long_align(memory_start); - fhc = (struct linux_fhc *)(memory_start); - memory_start += sizeof(struct linux_fhc); - memory_start = long_align(memory_start); + fhc = (struct linux_fhc *) + central_alloc_bootmem(sizeof(struct linux_fhc)); + if (fhc == NULL) { + prom_printf("central_probe: Cannot alloc central fhc.\n"); + prom_halt(); + } /* First init central. */ central_bus->child = fhc; @@ -210,7 +282,7 @@ unsigned long central_probe(unsigned long memory_start) prom_getstring(cnode, "name", namebuf, sizeof(namebuf)); strcpy(central_bus->prom_name, namebuf); - prom_central_ranges_init(cnode, central_bus); + central_ranges_init(cnode, central_bus); /* And then central's FHC. */ fhc->next = fhc_list; @@ -226,38 +298,32 @@ unsigned long central_probe(unsigned long memory_start) prom_getstring(fnode, "name", namebuf, sizeof(namebuf)); strcpy(fhc->prom_name, namebuf); - prom_fhc_ranges_init(fnode, fhc); + fhc_ranges_init(fnode, fhc); /* Now, map in FHC register set. */ if (prom_getproperty(fnode, "reg", (char *)&fpregs[0], sizeof(fpregs)) == -1) { prom_printf("CENTRAL: Fatal error, cannot get fhc regs.\n"); prom_halt(); } - prom_apply_central_ranges(central_bus, &fpregs[0], 6); + apply_central_ranges(central_bus, &fpregs[0], 6); - fhc->fhc_regs.pregs = (struct fhc_internal_regs *) - __va((((unsigned long)fpregs[0].which_io)<<32) | - (((unsigned long)fpregs[0].phys_addr))); - fhc->fhc_regs.ireg = (struct fhc_ign_reg *) - __va((((unsigned long)fpregs[1].which_io)<<32) | - (((unsigned long)fpregs[1].phys_addr))); - fhc->fhc_regs.ffregs = (struct fhc_fanfail_regs *) - __va((((unsigned long)fpregs[2].which_io)<<32) | - (((unsigned long)fpregs[2].phys_addr))); - fhc->fhc_regs.sregs = (struct fhc_system_regs *) - __va((((unsigned long)fpregs[3].which_io)<<32) | - (((unsigned long)fpregs[3].phys_addr))); - fhc->fhc_regs.uregs = (struct fhc_uart_regs *) - __va((((unsigned long)fpregs[4].which_io)<<32) | - (((unsigned long)fpregs[4].phys_addr))); - fhc->fhc_regs.tregs = (struct fhc_tod_regs *) - __va((((unsigned long)fpregs[5].which_io)<<32) | - (((unsigned long)fpregs[5].phys_addr))); + fhc->fhc_regs.pregs = ((((unsigned long)fpregs[0].which_io)<<32UL) | + ((unsigned long)fpregs[0].phys_addr)); + fhc->fhc_regs.ireg = ((((unsigned long)fpregs[1].which_io)<<32UL) | + ((unsigned long)fpregs[1].phys_addr)); + fhc->fhc_regs.ffregs = ((((unsigned long)fpregs[2].which_io)<<32UL) | + ((unsigned long)fpregs[2].phys_addr)); + fhc->fhc_regs.sregs = ((((unsigned long)fpregs[3].which_io)<<32UL) | + ((unsigned long)fpregs[3].phys_addr)); + fhc->fhc_regs.uregs = ((((unsigned long)fpregs[4].which_io)<<32UL) | + ((unsigned long)fpregs[4].phys_addr)); + fhc->fhc_regs.tregs = ((((unsigned long)fpregs[5].which_io)<<32UL) | + ((unsigned long)fpregs[5].phys_addr)); /* Obtain board number from board status register, Central's * FHC lacks "board#" property. */ - err = fhc->fhc_regs.pregs->fhc_bsr; + err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_BSR); fhc->board = (((err >> 16) & 0x01) | ((err >> 12) & 0x0e)); @@ -266,23 +332,21 @@ unsigned long central_probe(unsigned long memory_start) /* Attach the clock board registers for CENTRAL. */ probe_clock_board(central_bus, fhc, cnode, fnode); - err = fhc->fhc_regs.pregs->fhc_id; + err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID); printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] (CENTRAL)\n", fhc->board, ((err & FHC_ID_VERS) >> 28), ((err & FHC_ID_PARTID) >> 12), ((err & FHC_ID_MANUF) >> 1)); - return probe_other_fhcs(memory_start); + probe_other_fhcs(); } static __inline__ void fhc_ledblink(struct linux_fhc *fhc, int on) { - volatile u32 *ctrl = (volatile u32 *) - &fhc->fhc_regs.pregs->fhc_control; u32 tmp; - tmp = *ctrl; + tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); /* NOTE: reverse logic on this bit */ if (on) @@ -291,16 +355,15 @@ static __inline__ void fhc_ledblink(struct linux_fhc *fhc, int on) tmp |= FHC_CONTROL_RLED; tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | FHC_CONTROL_SLINE); - *ctrl = tmp; - tmp = *ctrl; + upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL); + upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); } static __inline__ void central_ledblink(struct linux_central *central, int on) { - volatile u8 *ctrl = (volatile u8 *) ¢ral->clkregs->control; - int tmp; + u8 tmp; - tmp = *ctrl; + tmp = upa_readb(central->clkregs + CLOCK_CTRL); /* NOTE: reverse logic on this bit */ if(on) @@ -308,8 +371,8 @@ static __inline__ void central_ledblink(struct linux_central *central, int on) else tmp |= CLOCK_CTRL_RLED; - *ctrl = tmp; - tmp = *ctrl; + upa_writeb(tmp, central->clkregs + CLOCK_CTRL); + upa_readb(central->clkregs + CLOCK_CTRL); } static struct timer_list sftimer; @@ -335,41 +398,41 @@ void firetruck_init(void) { struct linux_central *central = central_bus; struct linux_fhc *fhc; + u8 ctrl; /* No central bus, nothing to do. */ if (central == NULL) return; for(fhc = fhc_list; fhc != NULL; fhc = fhc->next) { - volatile u32 *ctrl = (volatile u32 *) - &fhc->fhc_regs.pregs->fhc_control; u32 tmp; /* Clear all of the interrupt mapping registers * just in case OBP left them in a foul state. */ -#define ZAP(REG1, REG2) \ -do { volatile u32 *__iclr = (volatile u32 *)(&(REG1)); \ - volatile u32 *__imap = (volatile u32 *)(&(REG2)); \ - *(__iclr) = 0; \ - (void) *(__iclr); \ - *(__imap) &= ~(0x80000000); \ - (void) *(__imap); \ -} while(0) - - ZAP(fhc->fhc_regs.ffregs->fhc_ff_iclr, - fhc->fhc_regs.ffregs->fhc_ff_imap); - ZAP(fhc->fhc_regs.sregs->fhc_sys_iclr, - fhc->fhc_regs.sregs->fhc_sys_imap); - ZAP(fhc->fhc_regs.uregs->fhc_uart_iclr, - fhc->fhc_regs.uregs->fhc_uart_imap); - ZAP(fhc->fhc_regs.tregs->fhc_tod_iclr, - fhc->fhc_regs.tregs->fhc_tod_imap); +#define ZAP(ICLR, IMAP) \ +do { u32 imap_tmp; \ + upa_writel(0, (ICLR)); \ + upa_readl(ICLR); \ + imap_tmp = upa_readl(IMAP); \ + imap_tmp &= ~(0x80000000); \ + upa_writel(imap_tmp, (IMAP)); \ + upa_readl(IMAP); \ +} while (0) + + ZAP(fhc->fhc_regs.ffregs + FHC_FFREGS_ICLR, + fhc->fhc_regs.ffregs + FHC_FFREGS_IMAP); + ZAP(fhc->fhc_regs.sregs + FHC_SREGS_ICLR, + fhc->fhc_regs.sregs + FHC_SREGS_IMAP); + ZAP(fhc->fhc_regs.uregs + FHC_UREGS_ICLR, + fhc->fhc_regs.uregs + FHC_UREGS_IMAP); + ZAP(fhc->fhc_regs.tregs + FHC_TREGS_ICLR, + fhc->fhc_regs.tregs + FHC_TREGS_IMAP); #undef ZAP /* Setup FHC control register. */ - tmp = *ctrl; + tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); /* All non-central boards have this bit set. */ if(! IS_CENTRAL_FHC(fhc)) @@ -379,14 +442,17 @@ do { volatile u32 *__iclr = (volatile u32 *)(&(REG1)); \ * line and both low power mode enables. */ tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | FHC_CONTROL_SLINE); - *ctrl = tmp; - tmp = *ctrl; /* Ensure completion */ + + upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL); + upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); } /* OBP leaves it on, turn it off so clock board timer LED * is in sync with FHC ones. */ - central->clkregs->control &= ~(CLOCK_CTRL_RLED); + ctrl = upa_readb(central->clkregs + CLOCK_CTRL); + ctrl &= ~(CLOCK_CTRL_RLED); + upa_writeb(ctrl, central->clkregs + CLOCK_CTRL); led_state = 0; init_timer(&sftimer); |