1 /* 2 * MIPS SPRAM support 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Copyright (C) 2007, 2008 MIPS Technologies, Inc. 10 */ 11 #include <linux/init.h> 12 #include <linux/kernel.h> 13 #include <linux/ptrace.h> 14 #include <linux/stddef.h> 15 16 #include <asm/fpu.h> 17 #include <asm/mipsregs.h> 18 #include <asm/system.h> 19 #include <asm/r4kcache.h> 20 #include <asm/hazards.h> 21 22 /* 23 * These definitions are correct for the 24K/34K/74K SPRAM sample 24 * implementation. The 4KS interpreted the tags differently... 25 */ 26 #define SPRAM_TAG0_ENABLE 0x00000080 27 #define SPRAM_TAG0_PA_MASK 0xfffff000 28 #define SPRAM_TAG1_SIZE_MASK 0xfffff000 29 30 #define SPRAM_TAG_STRIDE 8 31 32 #define ERRCTL_SPRAM (1 << 28) 33 34 /* errctl access */ 35 #define read_c0_errctl(x) read_c0_ecc(x) 36 #define write_c0_errctl(x) write_c0_ecc(x) 37 38 /* 39 * Different semantics to the set_c0_* function built by __BUILD_SET_C0 40 */ 41 static __cpuinit unsigned int bis_c0_errctl(unsigned int set) 42 { 43 unsigned int res; 44 res = read_c0_errctl(); 45 write_c0_errctl(res | set); 46 return res; 47 } 48 49 static __cpuinit void ispram_store_tag(unsigned int offset, unsigned int data) 50 { 51 unsigned int errctl; 52 53 /* enable SPRAM tag access */ 54 errctl = bis_c0_errctl(ERRCTL_SPRAM); 55 ehb(); 56 57 write_c0_taglo(data); 58 ehb(); 59 60 cache_op(Index_Store_Tag_I, CKSEG0|offset); 61 ehb(); 62 63 write_c0_errctl(errctl); 64 ehb(); 65 } 66 67 68 static __cpuinit unsigned int ispram_load_tag(unsigned int offset) 69 { 70 unsigned int data; 71 unsigned int errctl; 72 73 /* enable SPRAM tag access */ 74 errctl = bis_c0_errctl(ERRCTL_SPRAM); 75 ehb(); 76 cache_op(Index_Load_Tag_I, CKSEG0 | offset); 77 ehb(); 78 data = read_c0_taglo(); 79 ehb(); 80 write_c0_errctl(errctl); 81 ehb(); 82 83 return data; 84 } 85 86 static __cpuinit void dspram_store_tag(unsigned int offset, unsigned int data) 87 { 88 unsigned int errctl; 89 90 /* enable SPRAM tag access */ 91 errctl = bis_c0_errctl(ERRCTL_SPRAM); 92 ehb(); 93 write_c0_dtaglo(data); 94 ehb(); 95 cache_op(Index_Store_Tag_D, CKSEG0 | offset); 96 ehb(); 97 write_c0_errctl(errctl); 98 ehb(); 99 } 100 101 102 static __cpuinit unsigned int dspram_load_tag(unsigned int offset) 103 { 104 unsigned int data; 105 unsigned int errctl; 106 107 errctl = bis_c0_errctl(ERRCTL_SPRAM); 108 ehb(); 109 cache_op(Index_Load_Tag_D, CKSEG0 | offset); 110 ehb(); 111 data = read_c0_dtaglo(); 112 ehb(); 113 write_c0_errctl(errctl); 114 ehb(); 115 116 return data; 117 } 118 119 static __cpuinit void probe_spram(char *type, 120 unsigned int base, 121 unsigned int (*read)(unsigned int), 122 void (*write)(unsigned int, unsigned int)) 123 { 124 unsigned int firstsize = 0, lastsize = 0; 125 unsigned int firstpa = 0, lastpa = 0, pa = 0; 126 unsigned int offset = 0; 127 unsigned int size, tag0, tag1; 128 unsigned int enabled; 129 int i; 130 131 /* 132 * The limit is arbitrary but avoids the loop running away if 133 * the SPRAM tags are implemented differently 134 */ 135 136 for (i = 0; i < 8; i++) { 137 tag0 = read(offset); 138 tag1 = read(offset+SPRAM_TAG_STRIDE); 139 pr_debug("DBG %s%d: tag0=%08x tag1=%08x\n", 140 type, i, tag0, tag1); 141 142 size = tag1 & SPRAM_TAG1_SIZE_MASK; 143 144 if (size == 0) 145 break; 146 147 if (i != 0) { 148 /* tags may repeat... */ 149 if ((pa == firstpa && size == firstsize) || 150 (pa == lastpa && size == lastsize)) 151 break; 152 } 153 154 /* Align base with size */ 155 base = (base + size - 1) & ~(size-1); 156 157 /* reprogram the base address base address and enable */ 158 tag0 = (base & SPRAM_TAG0_PA_MASK) | SPRAM_TAG0_ENABLE; 159 write(offset, tag0); 160 161 base += size; 162 163 /* reread the tag */ 164 tag0 = read(offset); 165 pa = tag0 & SPRAM_TAG0_PA_MASK; 166 enabled = tag0 & SPRAM_TAG0_ENABLE; 167 168 if (i == 0) { 169 firstpa = pa; 170 firstsize = size; 171 } 172 173 lastpa = pa; 174 lastsize = size; 175 176 if (strcmp(type, "DSPRAM") == 0) { 177 unsigned int *vp = (unsigned int *)(CKSEG1 | pa); 178 unsigned int v; 179 #define TDAT 0x5a5aa5a5 180 vp[0] = TDAT; 181 vp[1] = ~TDAT; 182 183 mb(); 184 185 v = vp[0]; 186 if (v != TDAT) 187 printk(KERN_ERR "vp=%p wrote=%08x got=%08x\n", 188 vp, TDAT, v); 189 v = vp[1]; 190 if (v != ~TDAT) 191 printk(KERN_ERR "vp=%p wrote=%08x got=%08x\n", 192 vp+1, ~TDAT, v); 193 } 194 195 pr_info("%s%d: PA=%08x,Size=%08x%s\n", 196 type, i, pa, size, enabled ? ",enabled" : ""); 197 offset += 2 * SPRAM_TAG_STRIDE; 198 } 199 } 200 void __cpuinit spram_config(void) 201 { 202 struct cpuinfo_mips *c = ¤t_cpu_data; 203 unsigned int config0; 204 205 switch (c->cputype) { 206 case CPU_24K: 207 case CPU_34K: 208 case CPU_74K: 209 case CPU_1004K: 210 config0 = read_c0_config(); 211 /* FIXME: addresses are Malta specific */ 212 if (config0 & (1<<24)) { 213 probe_spram("ISPRAM", 0x1c000000, 214 &ispram_load_tag, &ispram_store_tag); 215 } 216 if (config0 & (1<<23)) 217 probe_spram("DSPRAM", 0x1c100000, 218 &dspram_load_tag, &dspram_store_tag); 219 } 220 } 221