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