1/* 2 * ip22-mc.c: Routines for manipulating the INDY memory controller. 3 * 4 * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) 5 * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - Indigo2 changes 6 */ 7 8#include <linux/init.h> 9#include <linux/kernel.h> 10 11#include <asm/addrspace.h> 12#include <asm/ptrace.h> 13#include <asm/sgialib.h> 14#include <asm/sgi/sgimc.h> 15#include <asm/sgi/sgihpc.h> 16 17/* #define DEBUG_SGIMC */ 18 19#ifdef DEBUG_SGIMC 20extern void prom_printf(char *fmt, ...); 21#endif 22 23struct sgimc_misc_ctrl *mcmisc_regs; 24struct sgimc_dma_ctrl *dmactrlregs; 25u32 *rpsscounter; 26 27#ifdef DEBUG_SGIMC 28static inline char *mconfig_string(unsigned long val) 29{ 30 switch(val & SGIMC_MCONFIG_RMASK) { 31 case SGIMC_MCONFIG_FOURMB: 32 return "4MB"; 33 34 case SGIMC_MCONFIG_EIGHTMB: 35 return "8MB"; 36 37 case SGIMC_MCONFIG_SXTEENMB: 38 return "16MB"; 39 40 case SGIMC_MCONFIG_TTWOMB: 41 return "32MB"; 42 43 case SGIMC_MCONFIG_SFOURMB: 44 return "64MB"; 45 46 case SGIMC_MCONFIG_OTEIGHTMB: 47 return "128MB"; 48 49 default: 50 return "wheee, unknown"; 51 } 52} 53#endif 54 55void __init sgimc_init(void) 56{ 57 unsigned long tmpreg; 58 59 mcmisc_regs = (struct sgimc_misc_ctrl *)(KSEG1+0x1fa00000); 60 rpsscounter = (unsigned int *)(KSEG1+0x1fa01004); 61 dmactrlregs = (struct sgimc_dma_ctrl *)(KSEG1+0x1fa02000); 62 63 printk(KERN_INFO "MC: SGI memory controller Revision %d\n", 64 (int) mcmisc_regs->systemid & SGIMC_SYSID_MASKREV); 65 66 67#ifdef DEBUG_SGIMC 68 prom_printf("sgimc_init: memconfig0<%s> mconfig1<%s>\n", 69 mconfig_string(mcmisc_regs->mconfig0), 70 mconfig_string(mcmisc_regs->mconfig1)); 71 72 prom_printf("mcdump: cpuctrl0<%08lx> cpuctrl1<%08lx>\n", 73 mcmisc_regs->cpuctrl0, mcmisc_regs->cpuctrl1); 74 prom_printf("mcdump: divider<%08lx>, gioparm<%04x>\n", 75 mcmisc_regs->divider, mcmisc_regs->gioparm); 76#endif 77 78 /* Place the MC into a known state. This must be done before 79 * interrupts are first enabled etc. 80 */ 81 82 /* Step 0: Make sure we turn off the watchdog in case it's 83 * still running (which might be the case after a 84 * soft reboot). 85 */ 86 tmpreg = mcmisc_regs->cpuctrl0; 87 tmpreg &= ~SGIMC_CCTRL0_WDOG; 88 mcmisc_regs->cpuctrl0 = tmpreg; 89 90 /* Step 1: The CPU/GIO error status registers will not latch 91 * up a new error status until the register has been 92 * cleared by the cpu. These status registers are 93 * cleared by writing any value to them. 94 */ 95 mcmisc_regs->cstat = mcmisc_regs->gstat = 0; 96 97 /* Step 2: Enable all parity checking in cpu control register 98 * zero. 99 */ 100 tmpreg = mcmisc_regs->cpuctrl0; 101 tmpreg |= (SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM | 102 SGIMC_CCTRL0_R4KNOCHKPARR); 103 mcmisc_regs->cpuctrl0 = tmpreg; 104 105 /* Step 3: Setup the MC write buffer depth, this is controlled 106 * in cpu control register 1 in the lower 4 bits. 107 */ 108 tmpreg = mcmisc_regs->cpuctrl1; 109 tmpreg &= ~0xf; 110 tmpreg |= 0xd; 111 mcmisc_regs->cpuctrl1 = tmpreg; 112 113 /* Step 4: Initialize the RPSS divider register to run as fast 114 * as it can correctly operate. The register is laid 115 * out as follows: 116 * 117 * ---------------------------------------- 118 * | RESERVED | INCREMENT | DIVIDER | 119 * ---------------------------------------- 120 * 31 16 15 8 7 0 121 * 122 * DIVIDER determines how often a 'tick' happens, 123 * INCREMENT determines by how the RPSS increment 124 * registers value increases at each 'tick'. Thus, 125 * for IP22 we get INCREMENT=1, DIVIDER=1 == 0x101 126 */ 127 mcmisc_regs->divider = 0x101; 128 129 /* Step 5: Initialize GIO64 arbitrator configuration register. 130 * 131 * NOTE: If you dork with startup code the HPC init code in 132 * sgihpc_init() must run before us because of how we 133 * need to know Guiness vs. FullHouse and the board 134 * revision on this machine. You have been warned. 135 */ 136 137 /* First the basic invariants across all GIO64 implementations. */ 138 tmpreg = SGIMC_GIOPARM_HPC64; /* All 1st HPC's interface at 64bits. */ 139 tmpreg |= SGIMC_GIOPARM_ONEBUS; /* Only one physical GIO bus exists. */ 140 141 if(sgi_guiness) { 142 /* Guiness specific settings. */ 143 tmpreg |= SGIMC_GIOPARM_EISA64; /* MC talks to EISA at 64bits */ 144 tmpreg |= SGIMC_GIOPARM_MASTEREISA; /* EISA bus can act as master */ 145 } else { 146 /* Fullhouse specific settings. */ 147 if(sgi_boardid < 2) { 148 tmpreg |= SGIMC_GIOPARM_HPC264; /* 2nd HPC at 64bits */ 149 tmpreg |= SGIMC_GIOPARM_PLINEEXP0; /* exp0 pipelines */ 150 tmpreg |= SGIMC_GIOPARM_MASTEREXP1;/* exp1 masters */ 151 tmpreg |= SGIMC_GIOPARM_RTIMEEXP0; /* exp0 is realtime */ 152 } else { 153 tmpreg |= SGIMC_GIOPARM_HPC264; /* 2nd HPC 64bits */ 154 tmpreg |= SGIMC_GIOPARM_PLINEEXP0; /* exp[01] pipelined */ 155 tmpreg |= SGIMC_GIOPARM_PLINEEXP1; 156 tmpreg |= SGIMC_GIOPARM_MASTEREISA;/* EISA masters */ 157 tmpreg |= SGIMC_GIOPARM_GFX64; /* GFX at 64 bits */ 158 } 159 } 160 mcmisc_regs->gioparm = tmpreg; /* poof */ 161} 162