summaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/central.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel/central.c')
-rw-r--r--arch/sparc64/kernel/central.c286
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 *) &central->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);