10b6d497fSChris Dearman /* 20b6d497fSChris Dearman * MIPS SPRAM support 30b6d497fSChris Dearman * 40b6d497fSChris Dearman * This program is free software; you can redistribute it and/or 50b6d497fSChris Dearman * modify it under the terms of the GNU General Public License 60b6d497fSChris Dearman * as published by the Free Software Foundation; either version 70b6d497fSChris Dearman * 2 of the License, or (at your option) any later version. 80b6d497fSChris Dearman * 90b6d497fSChris Dearman * Copyright (C) 2007, 2008 MIPS Technologies, Inc. 100b6d497fSChris Dearman */ 110b6d497fSChris Dearman #include <linux/kernel.h> 120b6d497fSChris Dearman #include <linux/ptrace.h> 130b6d497fSChris Dearman #include <linux/stddef.h> 140b6d497fSChris Dearman 150b6d497fSChris Dearman #include <asm/fpu.h> 160b6d497fSChris Dearman #include <asm/mipsregs.h> 170b6d497fSChris Dearman #include <asm/r4kcache.h> 180b6d497fSChris Dearman #include <asm/hazards.h> 190b6d497fSChris Dearman 200b6d497fSChris Dearman /* 210b6d497fSChris Dearman * These definitions are correct for the 24K/34K/74K SPRAM sample 220b6d497fSChris Dearman * implementation. The 4KS interpreted the tags differently... 230b6d497fSChris Dearman */ 240b6d497fSChris Dearman #define SPRAM_TAG0_ENABLE 0x00000080 250b6d497fSChris Dearman #define SPRAM_TAG0_PA_MASK 0xfffff000 260b6d497fSChris Dearman #define SPRAM_TAG1_SIZE_MASK 0xfffff000 270b6d497fSChris Dearman 280b6d497fSChris Dearman #define SPRAM_TAG_STRIDE 8 290b6d497fSChris Dearman 300b6d497fSChris Dearman #define ERRCTL_SPRAM (1 << 28) 310b6d497fSChris Dearman 320b6d497fSChris Dearman /* errctl access */ 330b6d497fSChris Dearman #define read_c0_errctl(x) read_c0_ecc(x) 340b6d497fSChris Dearman #define write_c0_errctl(x) write_c0_ecc(x) 350b6d497fSChris Dearman 360b6d497fSChris Dearman /* 370b6d497fSChris Dearman * Different semantics to the set_c0_* function built by __BUILD_SET_C0 380b6d497fSChris Dearman */ 39078a55fcSPaul Gortmaker static unsigned int bis_c0_errctl(unsigned int set) 400b6d497fSChris Dearman { 410b6d497fSChris Dearman unsigned int res; 420b6d497fSChris Dearman res = read_c0_errctl(); 430b6d497fSChris Dearman write_c0_errctl(res | set); 440b6d497fSChris Dearman return res; 450b6d497fSChris Dearman } 460b6d497fSChris Dearman 47078a55fcSPaul Gortmaker static void ispram_store_tag(unsigned int offset, unsigned int data) 480b6d497fSChris Dearman { 490b6d497fSChris Dearman unsigned int errctl; 500b6d497fSChris Dearman 510b6d497fSChris Dearman /* enable SPRAM tag access */ 520b6d497fSChris Dearman errctl = bis_c0_errctl(ERRCTL_SPRAM); 530b6d497fSChris Dearman ehb(); 540b6d497fSChris Dearman 550b6d497fSChris Dearman write_c0_taglo(data); 560b6d497fSChris Dearman ehb(); 570b6d497fSChris Dearman 580b6d497fSChris Dearman cache_op(Index_Store_Tag_I, CKSEG0|offset); 590b6d497fSChris Dearman ehb(); 600b6d497fSChris Dearman 610b6d497fSChris Dearman write_c0_errctl(errctl); 620b6d497fSChris Dearman ehb(); 630b6d497fSChris Dearman } 640b6d497fSChris Dearman 650b6d497fSChris Dearman 66078a55fcSPaul Gortmaker static unsigned int ispram_load_tag(unsigned int offset) 670b6d497fSChris Dearman { 680b6d497fSChris Dearman unsigned int data; 690b6d497fSChris Dearman unsigned int errctl; 700b6d497fSChris Dearman 710b6d497fSChris Dearman /* enable SPRAM tag access */ 720b6d497fSChris Dearman errctl = bis_c0_errctl(ERRCTL_SPRAM); 730b6d497fSChris Dearman ehb(); 740b6d497fSChris Dearman cache_op(Index_Load_Tag_I, CKSEG0 | offset); 750b6d497fSChris Dearman ehb(); 760b6d497fSChris Dearman data = read_c0_taglo(); 770b6d497fSChris Dearman ehb(); 780b6d497fSChris Dearman write_c0_errctl(errctl); 790b6d497fSChris Dearman ehb(); 800b6d497fSChris Dearman 810b6d497fSChris Dearman return data; 820b6d497fSChris Dearman } 830b6d497fSChris Dearman 84078a55fcSPaul Gortmaker static void dspram_store_tag(unsigned int offset, unsigned int data) 850b6d497fSChris Dearman { 860b6d497fSChris Dearman unsigned int errctl; 870b6d497fSChris Dearman 880b6d497fSChris Dearman /* enable SPRAM tag access */ 890b6d497fSChris Dearman errctl = bis_c0_errctl(ERRCTL_SPRAM); 900b6d497fSChris Dearman ehb(); 910b6d497fSChris Dearman write_c0_dtaglo(data); 920b6d497fSChris Dearman ehb(); 930b6d497fSChris Dearman cache_op(Index_Store_Tag_D, CKSEG0 | offset); 940b6d497fSChris Dearman ehb(); 950b6d497fSChris Dearman write_c0_errctl(errctl); 960b6d497fSChris Dearman ehb(); 970b6d497fSChris Dearman } 980b6d497fSChris Dearman 990b6d497fSChris Dearman 100078a55fcSPaul Gortmaker static unsigned int dspram_load_tag(unsigned int offset) 1010b6d497fSChris Dearman { 1020b6d497fSChris Dearman unsigned int data; 1030b6d497fSChris Dearman unsigned int errctl; 1040b6d497fSChris Dearman 1050b6d497fSChris Dearman errctl = bis_c0_errctl(ERRCTL_SPRAM); 1060b6d497fSChris Dearman ehb(); 1070b6d497fSChris Dearman cache_op(Index_Load_Tag_D, CKSEG0 | offset); 1080b6d497fSChris Dearman ehb(); 1090b6d497fSChris Dearman data = read_c0_dtaglo(); 1100b6d497fSChris Dearman ehb(); 1110b6d497fSChris Dearman write_c0_errctl(errctl); 1120b6d497fSChris Dearman ehb(); 1130b6d497fSChris Dearman 1140b6d497fSChris Dearman return data; 1150b6d497fSChris Dearman } 1160b6d497fSChris Dearman 117078a55fcSPaul Gortmaker static void probe_spram(char *type, 1180b6d497fSChris Dearman unsigned int base, 1190b6d497fSChris Dearman unsigned int (*read)(unsigned int), 1200b6d497fSChris Dearman void (*write)(unsigned int, unsigned int)) 1210b6d497fSChris Dearman { 1220b6d497fSChris Dearman unsigned int firstsize = 0, lastsize = 0; 1230b6d497fSChris Dearman unsigned int firstpa = 0, lastpa = 0, pa = 0; 1240b6d497fSChris Dearman unsigned int offset = 0; 1250b6d497fSChris Dearman unsigned int size, tag0, tag1; 1260b6d497fSChris Dearman unsigned int enabled; 1270b6d497fSChris Dearman int i; 1280b6d497fSChris Dearman 1290b6d497fSChris Dearman /* 1300b6d497fSChris Dearman * The limit is arbitrary but avoids the loop running away if 1310b6d497fSChris Dearman * the SPRAM tags are implemented differently 1320b6d497fSChris Dearman */ 1330b6d497fSChris Dearman 1340b6d497fSChris Dearman for (i = 0; i < 8; i++) { 1350b6d497fSChris Dearman tag0 = read(offset); 1360b6d497fSChris Dearman tag1 = read(offset+SPRAM_TAG_STRIDE); 1370b6d497fSChris Dearman pr_debug("DBG %s%d: tag0=%08x tag1=%08x\n", 1380b6d497fSChris Dearman type, i, tag0, tag1); 1390b6d497fSChris Dearman 1400b6d497fSChris Dearman size = tag1 & SPRAM_TAG1_SIZE_MASK; 1410b6d497fSChris Dearman 1420b6d497fSChris Dearman if (size == 0) 1430b6d497fSChris Dearman break; 1440b6d497fSChris Dearman 1450b6d497fSChris Dearman if (i != 0) { 1460b6d497fSChris Dearman /* tags may repeat... */ 1470b6d497fSChris Dearman if ((pa == firstpa && size == firstsize) || 1480b6d497fSChris Dearman (pa == lastpa && size == lastsize)) 1490b6d497fSChris Dearman break; 1500b6d497fSChris Dearman } 1510b6d497fSChris Dearman 1520b6d497fSChris Dearman /* Align base with size */ 1530b6d497fSChris Dearman base = (base + size - 1) & ~(size-1); 1540b6d497fSChris Dearman 1550b6d497fSChris Dearman /* reprogram the base address base address and enable */ 1560b6d497fSChris Dearman tag0 = (base & SPRAM_TAG0_PA_MASK) | SPRAM_TAG0_ENABLE; 1570b6d497fSChris Dearman write(offset, tag0); 1580b6d497fSChris Dearman 1590b6d497fSChris Dearman base += size; 1600b6d497fSChris Dearman 1610b6d497fSChris Dearman /* reread the tag */ 1620b6d497fSChris Dearman tag0 = read(offset); 1630b6d497fSChris Dearman pa = tag0 & SPRAM_TAG0_PA_MASK; 1640b6d497fSChris Dearman enabled = tag0 & SPRAM_TAG0_ENABLE; 1650b6d497fSChris Dearman 1660b6d497fSChris Dearman if (i == 0) { 1670b6d497fSChris Dearman firstpa = pa; 1680b6d497fSChris Dearman firstsize = size; 1690b6d497fSChris Dearman } 1700b6d497fSChris Dearman 1710b6d497fSChris Dearman lastpa = pa; 1720b6d497fSChris Dearman lastsize = size; 1730b6d497fSChris Dearman 1740b6d497fSChris Dearman if (strcmp(type, "DSPRAM") == 0) { 1750b6d497fSChris Dearman unsigned int *vp = (unsigned int *)(CKSEG1 | pa); 1760b6d497fSChris Dearman unsigned int v; 1770b6d497fSChris Dearman #define TDAT 0x5a5aa5a5 1780b6d497fSChris Dearman vp[0] = TDAT; 1790b6d497fSChris Dearman vp[1] = ~TDAT; 1800b6d497fSChris Dearman 1810b6d497fSChris Dearman mb(); 1820b6d497fSChris Dearman 1830b6d497fSChris Dearman v = vp[0]; 1840b6d497fSChris Dearman if (v != TDAT) 1850b6d497fSChris Dearman printk(KERN_ERR "vp=%p wrote=%08x got=%08x\n", 1860b6d497fSChris Dearman vp, TDAT, v); 1870b6d497fSChris Dearman v = vp[1]; 1880b6d497fSChris Dearman if (v != ~TDAT) 1890b6d497fSChris Dearman printk(KERN_ERR "vp=%p wrote=%08x got=%08x\n", 1900b6d497fSChris Dearman vp+1, ~TDAT, v); 1910b6d497fSChris Dearman } 1920b6d497fSChris Dearman 1930b6d497fSChris Dearman pr_info("%s%d: PA=%08x,Size=%08x%s\n", 1940b6d497fSChris Dearman type, i, pa, size, enabled ? ",enabled" : ""); 1950b6d497fSChris Dearman offset += 2 * SPRAM_TAG_STRIDE; 1960b6d497fSChris Dearman } 1970b6d497fSChris Dearman } 198078a55fcSPaul Gortmaker void spram_config(void) 1990b6d497fSChris Dearman { 2000b6d497fSChris Dearman struct cpuinfo_mips *c = ¤t_cpu_data; 2010b6d497fSChris Dearman unsigned int config0; 2020b6d497fSChris Dearman 2030b6d497fSChris Dearman switch (c->cputype) { 2040b6d497fSChris Dearman case CPU_24K: 2050b6d497fSChris Dearman case CPU_34K: 2060b6d497fSChris Dearman case CPU_74K: 207a4e7cac1SRalf Baechle case CPU_1004K: 208442e14a2SSteven J. Hill case CPU_1074K: 20926ab96dfSLeonid Yegoshin case CPU_INTERAPTIV: 210708ac4b8SLeonid Yegoshin case CPU_PROAPTIV: 211*aced4cbdSJames Hogan case CPU_P5600: 2120b6d497fSChris Dearman config0 = read_c0_config(); 2130b6d497fSChris Dearman /* FIXME: addresses are Malta specific */ 2140b6d497fSChris Dearman if (config0 & (1<<24)) { 2150b6d497fSChris Dearman probe_spram("ISPRAM", 0x1c000000, 2160b6d497fSChris Dearman &ispram_load_tag, &ispram_store_tag); 2170b6d497fSChris Dearman } 2180b6d497fSChris Dearman if (config0 & (1<<23)) 2190b6d497fSChris Dearman probe_spram("DSPRAM", 0x1c100000, 2200b6d497fSChris Dearman &dspram_load_tag, &dspram_store_tag); 2210b6d497fSChris Dearman } 2220b6d497fSChris Dearman } 223