xref: /linux/arch/mips/sgi-ip22/ip22-mc.c (revision 0d3b051adbb72ed81956447d0d1e54d5943ee6f5)
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