1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * ip22-mc.c: Routines for manipulating SGI Memory Controller. 4 * 5 * Copyright (C) 1996 David S. Miller (davem@davemloft.net) 6 * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - Indigo2 changes 7 * Copyright (C) 2003 Ladislav Michl (ladis@linux-mips.org) 8 * Copyright (C) 2004 Peter Fuerst (pf@net.alphadv.de) - IP28 9 */ 10 11 #include <linux/init.h> 12 #include <linux/export.h> 13 #include <linux/kernel.h> 14 #include <linux/memblock.h> 15 #include <linux/spinlock.h> 16 17 #include <asm/io.h> 18 #include <asm/bootinfo.h> 19 #include <asm/sgialib.h> 20 #include <asm/sgi/mc.h> 21 #include <asm/sgi/hpc3.h> 22 #include <asm/sgi/ip22.h> 23 24 struct sgimc_regs *sgimc; 25 26 EXPORT_SYMBOL(sgimc); 27 28 static inline unsigned long get_bank_addr(unsigned int memconfig) 29 { 30 return (memconfig & SGIMC_MCONFIG_BASEADDR) << ((sgimc->systemid & SGIMC_SYSID_MASKREV) >= 5 ? 24 : 22); 31 } 32 33 static inline unsigned long get_bank_size(unsigned int memconfig) 34 { 35 return ((memconfig & SGIMC_MCONFIG_RMASK) + 0x0100) << ((sgimc->systemid & SGIMC_SYSID_MASKREV) >= 5 ? 16 : 14); 36 } 37 38 static inline unsigned int get_bank_config(int bank) 39 { 40 unsigned int res = bank > 1 ? sgimc->mconfig1 : sgimc->mconfig0; 41 return bank % 2 ? res & 0xffff : res >> 16; 42 } 43 44 #if defined(CONFIG_SGI_IP28) || defined(CONFIG_32BIT) 45 static void __init probe_memory(void) 46 { 47 /* prom detects all usable memory */ 48 } 49 #else 50 /* 51 * Detect installed memory, which PROM misses 52 */ 53 static void __init probe_memory(void) 54 { 55 unsigned long addr, size; 56 int i; 57 58 printk(KERN_INFO "MC: Probing memory configuration:\n"); 59 for (i = 0; i < 4; i++) { 60 unsigned int tmp = get_bank_config(i); 61 if (!(tmp & SGIMC_MCONFIG_BVALID)) 62 continue; 63 64 size = get_bank_size(tmp); 65 addr = get_bank_addr(tmp); 66 printk(KERN_INFO " bank%d: %3ldM @ %08lx\n", 67 i, size / 1024 / 1024, addr); 68 69 if (addr >= SGIMC_SEG1_BADDR) 70 memblock_add(addr, size); 71 } 72 } 73 #endif 74 75 void __init sgimc_init(void) 76 { 77 u32 tmp; 78 79 /* ioremap can't fail */ 80 sgimc = (struct sgimc_regs *) 81 ioremap(SGIMC_BASE, sizeof(struct sgimc_regs)); 82 83 printk(KERN_INFO "MC: SGI memory controller Revision %d\n", 84 (int) sgimc->systemid & SGIMC_SYSID_MASKREV); 85 86 /* Place the MC into a known state. This must be done before 87 * interrupts are first enabled etc. 88 */ 89 90 /* Step 0: Make sure we turn off the watchdog in case it's 91 * still running (which might be the case after a 92 * soft reboot). 93 */ 94 tmp = sgimc->cpuctrl0; 95 tmp &= ~SGIMC_CCTRL0_WDOG; 96 sgimc->cpuctrl0 = tmp; 97 98 /* Step 1: The CPU/GIO error status registers will not latch 99 * up a new error status until the register has been 100 * cleared by the cpu. These status registers are 101 * cleared by writing any value to them. 102 */ 103 sgimc->cstat = sgimc->gstat = 0; 104 105 /* Step 2: Enable all parity checking in cpu control register 106 * zero. 107 */ 108 /* don't touch parity settings for IP28 */ 109 tmp = sgimc->cpuctrl0; 110 #ifndef CONFIG_SGI_IP28 111 tmp |= SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM; 112 #endif 113 tmp |= SGIMC_CCTRL0_R4KNOCHKPARR; 114 sgimc->cpuctrl0 = tmp; 115 116 /* Step 3: Setup the MC write buffer depth, this is controlled 117 * in cpu control register 1 in the lower 4 bits. 118 */ 119 tmp = sgimc->cpuctrl1; 120 tmp &= ~0xf; 121 tmp |= 0xd; 122 sgimc->cpuctrl1 = tmp; 123 124 /* Step 4: Initialize the RPSS divider register to run as fast 125 * as it can correctly operate. The register is laid 126 * out as follows: 127 * 128 * ---------------------------------------- 129 * | RESERVED | INCREMENT | DIVIDER | 130 * ---------------------------------------- 131 * 31 16 15 8 7 0 132 * 133 * DIVIDER determines how often a 'tick' happens, 134 * INCREMENT determines by how the RPSS increment 135 * registers value increases at each 'tick'. Thus, 136 * for IP22 we get INCREMENT=1, DIVIDER=1 == 0x101 137 */ 138 sgimc->divider = 0x101; 139 140 /* Step 5: Initialize GIO64 arbitrator configuration register. 141 * 142 * NOTE: HPC init code in sgihpc_init() must run before us because 143 * we need to know Guiness vs. FullHouse and the board 144 * revision on this machine. You have been warned. 145 */ 146 147 /* First the basic invariants across all GIO64 implementations. */ 148 tmp = sgimc->giopar & SGIMC_GIOPAR_GFX64; /* keep gfx 64bit settings */ 149 tmp |= SGIMC_GIOPAR_HPC64; /* All 1st HPC's interface at 64bits */ 150 tmp |= SGIMC_GIOPAR_ONEBUS; /* Only one physical GIO bus exists */ 151 152 if (ip22_is_fullhouse()) { 153 /* Fullhouse specific settings. */ 154 if (SGIOC_SYSID_BOARDREV(sgioc->sysid) < 2) { 155 tmp |= SGIMC_GIOPAR_HPC264; /* 2nd HPC at 64bits */ 156 tmp |= SGIMC_GIOPAR_PLINEEXP0; /* exp0 pipelines */ 157 tmp |= SGIMC_GIOPAR_MASTEREXP1; /* exp1 masters */ 158 tmp |= SGIMC_GIOPAR_RTIMEEXP0; /* exp0 is realtime */ 159 } else { 160 tmp |= SGIMC_GIOPAR_HPC264; /* 2nd HPC 64bits */ 161 tmp |= SGIMC_GIOPAR_PLINEEXP0; /* exp[01] pipelined */ 162 tmp |= SGIMC_GIOPAR_PLINEEXP1; 163 tmp |= SGIMC_GIOPAR_MASTEREISA; /* EISA masters */ 164 } 165 } else { 166 /* Guiness specific settings. */ 167 tmp |= SGIMC_GIOPAR_EISA64; /* MC talks to EISA at 64bits */ 168 tmp |= SGIMC_GIOPAR_MASTEREISA; /* EISA bus can act as master */ 169 } 170 sgimc->giopar = tmp; /* poof */ 171 172 probe_memory(); 173 } 174 175 #ifdef CONFIG_SGI_IP28 176 void __init prom_cleanup(void) 177 { 178 u32 mconfig1; 179 unsigned long flags; 180 spinlock_t lock; 181 182 /* 183 * because ARCS accesses memory uncached we wait until ARCS 184 * isn't needed any longer, before we switch from slow to 185 * normal mode 186 */ 187 spin_lock_irqsave(&lock, flags); 188 mconfig1 = sgimc->mconfig1; 189 /* map ECC register */ 190 sgimc->mconfig1 = (mconfig1 & 0xffff0000) | 0x2060; 191 iob(); 192 /* switch to normal mode */ 193 *(unsigned long *)PHYS_TO_XKSEG_UNCACHED(0x60000000) = 0; 194 iob(); 195 /* reduce WR_COL */ 196 sgimc->cmacc = (sgimc->cmacc & ~0xf) | 4; 197 iob(); 198 /* restore old config */ 199 sgimc->mconfig1 = mconfig1; 200 iob(); 201 spin_unlock_irqrestore(&lock, flags); 202 } 203 #endif 204