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