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/init.h> 120b6d497fSChris Dearman #include <linux/kernel.h> 130b6d497fSChris Dearman #include <linux/ptrace.h> 140b6d497fSChris Dearman #include <linux/stddef.h> 150b6d497fSChris Dearman 160b6d497fSChris Dearman #include <asm/fpu.h> 170b6d497fSChris Dearman #include <asm/mipsregs.h> 180b6d497fSChris Dearman #include <asm/r4kcache.h> 190b6d497fSChris Dearman #include <asm/hazards.h> 200b6d497fSChris Dearman 210b6d497fSChris Dearman /* 220b6d497fSChris Dearman * These definitions are correct for the 24K/34K/74K SPRAM sample 230b6d497fSChris Dearman * implementation. The 4KS interpreted the tags differently... 240b6d497fSChris Dearman */ 250b6d497fSChris Dearman #define SPRAM_TAG0_ENABLE 0x00000080 260b6d497fSChris Dearman #define SPRAM_TAG0_PA_MASK 0xfffff000 270b6d497fSChris Dearman #define SPRAM_TAG1_SIZE_MASK 0xfffff000 280b6d497fSChris Dearman 290b6d497fSChris Dearman #define SPRAM_TAG_STRIDE 8 300b6d497fSChris Dearman 310b6d497fSChris Dearman #define ERRCTL_SPRAM (1 << 28) 320b6d497fSChris Dearman 330b6d497fSChris Dearman /* errctl access */ 340b6d497fSChris Dearman #define read_c0_errctl(x) read_c0_ecc(x) 350b6d497fSChris Dearman #define write_c0_errctl(x) write_c0_ecc(x) 360b6d497fSChris Dearman 370b6d497fSChris Dearman /* 380b6d497fSChris Dearman * Different semantics to the set_c0_* function built by __BUILD_SET_C0 390b6d497fSChris Dearman */ 40*078a55fcSPaul Gortmaker static unsigned int bis_c0_errctl(unsigned int set) 410b6d497fSChris Dearman { 420b6d497fSChris Dearman unsigned int res; 430b6d497fSChris Dearman res = read_c0_errctl(); 440b6d497fSChris Dearman write_c0_errctl(res | set); 450b6d497fSChris Dearman return res; 460b6d497fSChris Dearman } 470b6d497fSChris Dearman 48*078a55fcSPaul Gortmaker static void ispram_store_tag(unsigned int offset, unsigned int data) 490b6d497fSChris Dearman { 500b6d497fSChris Dearman unsigned int errctl; 510b6d497fSChris Dearman 520b6d497fSChris Dearman /* enable SPRAM tag access */ 530b6d497fSChris Dearman errctl = bis_c0_errctl(ERRCTL_SPRAM); 540b6d497fSChris Dearman ehb(); 550b6d497fSChris Dearman 560b6d497fSChris Dearman write_c0_taglo(data); 570b6d497fSChris Dearman ehb(); 580b6d497fSChris Dearman 590b6d497fSChris Dearman cache_op(Index_Store_Tag_I, CKSEG0|offset); 600b6d497fSChris Dearman ehb(); 610b6d497fSChris Dearman 620b6d497fSChris Dearman write_c0_errctl(errctl); 630b6d497fSChris Dearman ehb(); 640b6d497fSChris Dearman } 650b6d497fSChris Dearman 660b6d497fSChris Dearman 67*078a55fcSPaul Gortmaker static unsigned int ispram_load_tag(unsigned int offset) 680b6d497fSChris Dearman { 690b6d497fSChris Dearman unsigned int data; 700b6d497fSChris Dearman unsigned int errctl; 710b6d497fSChris Dearman 720b6d497fSChris Dearman /* enable SPRAM tag access */ 730b6d497fSChris Dearman errctl = bis_c0_errctl(ERRCTL_SPRAM); 740b6d497fSChris Dearman ehb(); 750b6d497fSChris Dearman cache_op(Index_Load_Tag_I, CKSEG0 | offset); 760b6d497fSChris Dearman ehb(); 770b6d497fSChris Dearman data = read_c0_taglo(); 780b6d497fSChris Dearman ehb(); 790b6d497fSChris Dearman write_c0_errctl(errctl); 800b6d497fSChris Dearman ehb(); 810b6d497fSChris Dearman 820b6d497fSChris Dearman return data; 830b6d497fSChris Dearman } 840b6d497fSChris Dearman 85*078a55fcSPaul Gortmaker static void dspram_store_tag(unsigned int offset, unsigned int data) 860b6d497fSChris Dearman { 870b6d497fSChris Dearman unsigned int errctl; 880b6d497fSChris Dearman 890b6d497fSChris Dearman /* enable SPRAM tag access */ 900b6d497fSChris Dearman errctl = bis_c0_errctl(ERRCTL_SPRAM); 910b6d497fSChris Dearman ehb(); 920b6d497fSChris Dearman write_c0_dtaglo(data); 930b6d497fSChris Dearman ehb(); 940b6d497fSChris Dearman cache_op(Index_Store_Tag_D, CKSEG0 | offset); 950b6d497fSChris Dearman ehb(); 960b6d497fSChris Dearman write_c0_errctl(errctl); 970b6d497fSChris Dearman ehb(); 980b6d497fSChris Dearman } 990b6d497fSChris Dearman 1000b6d497fSChris Dearman 101*078a55fcSPaul Gortmaker static unsigned int dspram_load_tag(unsigned int offset) 1020b6d497fSChris Dearman { 1030b6d497fSChris Dearman unsigned int data; 1040b6d497fSChris Dearman unsigned int errctl; 1050b6d497fSChris Dearman 1060b6d497fSChris Dearman errctl = bis_c0_errctl(ERRCTL_SPRAM); 1070b6d497fSChris Dearman ehb(); 1080b6d497fSChris Dearman cache_op(Index_Load_Tag_D, CKSEG0 | offset); 1090b6d497fSChris Dearman ehb(); 1100b6d497fSChris Dearman data = read_c0_dtaglo(); 1110b6d497fSChris Dearman ehb(); 1120b6d497fSChris Dearman write_c0_errctl(errctl); 1130b6d497fSChris Dearman ehb(); 1140b6d497fSChris Dearman 1150b6d497fSChris Dearman return data; 1160b6d497fSChris Dearman } 1170b6d497fSChris Dearman 118*078a55fcSPaul Gortmaker static void probe_spram(char *type, 1190b6d497fSChris Dearman unsigned int base, 1200b6d497fSChris Dearman unsigned int (*read)(unsigned int), 1210b6d497fSChris Dearman void (*write)(unsigned int, unsigned int)) 1220b6d497fSChris Dearman { 1230b6d497fSChris Dearman unsigned int firstsize = 0, lastsize = 0; 1240b6d497fSChris Dearman unsigned int firstpa = 0, lastpa = 0, pa = 0; 1250b6d497fSChris Dearman unsigned int offset = 0; 1260b6d497fSChris Dearman unsigned int size, tag0, tag1; 1270b6d497fSChris Dearman unsigned int enabled; 1280b6d497fSChris Dearman int i; 1290b6d497fSChris Dearman 1300b6d497fSChris Dearman /* 1310b6d497fSChris Dearman * The limit is arbitrary but avoids the loop running away if 1320b6d497fSChris Dearman * the SPRAM tags are implemented differently 1330b6d497fSChris Dearman */ 1340b6d497fSChris Dearman 1350b6d497fSChris Dearman for (i = 0; i < 8; i++) { 1360b6d497fSChris Dearman tag0 = read(offset); 1370b6d497fSChris Dearman tag1 = read(offset+SPRAM_TAG_STRIDE); 1380b6d497fSChris Dearman pr_debug("DBG %s%d: tag0=%08x tag1=%08x\n", 1390b6d497fSChris Dearman type, i, tag0, tag1); 1400b6d497fSChris Dearman 1410b6d497fSChris Dearman size = tag1 & SPRAM_TAG1_SIZE_MASK; 1420b6d497fSChris Dearman 1430b6d497fSChris Dearman if (size == 0) 1440b6d497fSChris Dearman break; 1450b6d497fSChris Dearman 1460b6d497fSChris Dearman if (i != 0) { 1470b6d497fSChris Dearman /* tags may repeat... */ 1480b6d497fSChris Dearman if ((pa == firstpa && size == firstsize) || 1490b6d497fSChris Dearman (pa == lastpa && size == lastsize)) 1500b6d497fSChris Dearman break; 1510b6d497fSChris Dearman } 1520b6d497fSChris Dearman 1530b6d497fSChris Dearman /* Align base with size */ 1540b6d497fSChris Dearman base = (base + size - 1) & ~(size-1); 1550b6d497fSChris Dearman 1560b6d497fSChris Dearman /* reprogram the base address base address and enable */ 1570b6d497fSChris Dearman tag0 = (base & SPRAM_TAG0_PA_MASK) | SPRAM_TAG0_ENABLE; 1580b6d497fSChris Dearman write(offset, tag0); 1590b6d497fSChris Dearman 1600b6d497fSChris Dearman base += size; 1610b6d497fSChris Dearman 1620b6d497fSChris Dearman /* reread the tag */ 1630b6d497fSChris Dearman tag0 = read(offset); 1640b6d497fSChris Dearman pa = tag0 & SPRAM_TAG0_PA_MASK; 1650b6d497fSChris Dearman enabled = tag0 & SPRAM_TAG0_ENABLE; 1660b6d497fSChris Dearman 1670b6d497fSChris Dearman if (i == 0) { 1680b6d497fSChris Dearman firstpa = pa; 1690b6d497fSChris Dearman firstsize = size; 1700b6d497fSChris Dearman } 1710b6d497fSChris Dearman 1720b6d497fSChris Dearman lastpa = pa; 1730b6d497fSChris Dearman lastsize = size; 1740b6d497fSChris Dearman 1750b6d497fSChris Dearman if (strcmp(type, "DSPRAM") == 0) { 1760b6d497fSChris Dearman unsigned int *vp = (unsigned int *)(CKSEG1 | pa); 1770b6d497fSChris Dearman unsigned int v; 1780b6d497fSChris Dearman #define TDAT 0x5a5aa5a5 1790b6d497fSChris Dearman vp[0] = TDAT; 1800b6d497fSChris Dearman vp[1] = ~TDAT; 1810b6d497fSChris Dearman 1820b6d497fSChris Dearman mb(); 1830b6d497fSChris Dearman 1840b6d497fSChris Dearman v = vp[0]; 1850b6d497fSChris Dearman if (v != TDAT) 1860b6d497fSChris Dearman printk(KERN_ERR "vp=%p wrote=%08x got=%08x\n", 1870b6d497fSChris Dearman vp, TDAT, v); 1880b6d497fSChris Dearman v = vp[1]; 1890b6d497fSChris Dearman if (v != ~TDAT) 1900b6d497fSChris Dearman printk(KERN_ERR "vp=%p wrote=%08x got=%08x\n", 1910b6d497fSChris Dearman vp+1, ~TDAT, v); 1920b6d497fSChris Dearman } 1930b6d497fSChris Dearman 1940b6d497fSChris Dearman pr_info("%s%d: PA=%08x,Size=%08x%s\n", 1950b6d497fSChris Dearman type, i, pa, size, enabled ? ",enabled" : ""); 1960b6d497fSChris Dearman offset += 2 * SPRAM_TAG_STRIDE; 1970b6d497fSChris Dearman } 1980b6d497fSChris Dearman } 199*078a55fcSPaul Gortmaker void spram_config(void) 2000b6d497fSChris Dearman { 2010b6d497fSChris Dearman struct cpuinfo_mips *c = ¤t_cpu_data; 2020b6d497fSChris Dearman unsigned int config0; 2030b6d497fSChris Dearman 2040b6d497fSChris Dearman switch (c->cputype) { 2050b6d497fSChris Dearman case CPU_24K: 2060b6d497fSChris Dearman case CPU_34K: 2070b6d497fSChris Dearman case CPU_74K: 208a4e7cac1SRalf Baechle case CPU_1004K: 2090b6d497fSChris Dearman config0 = read_c0_config(); 2100b6d497fSChris Dearman /* FIXME: addresses are Malta specific */ 2110b6d497fSChris Dearman if (config0 & (1<<24)) { 2120b6d497fSChris Dearman probe_spram("ISPRAM", 0x1c000000, 2130b6d497fSChris Dearman &ispram_load_tag, &ispram_store_tag); 2140b6d497fSChris Dearman } 2150b6d497fSChris Dearman if (config0 & (1<<23)) 2160b6d497fSChris Dearman probe_spram("DSPRAM", 0x1c100000, 2170b6d497fSChris Dearman &dspram_load_tag, &dspram_store_tag); 2180b6d497fSChris Dearman } 2190b6d497fSChris Dearman } 220