1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 20b6d497fSChris Dearman /* 30b6d497fSChris Dearman * MIPS SPRAM support 40b6d497fSChris Dearman * 50b6d497fSChris Dearman * Copyright (C) 2007, 2008 MIPS Technologies, Inc. 60b6d497fSChris Dearman */ 70b6d497fSChris Dearman #include <linux/kernel.h> 80b6d497fSChris Dearman #include <linux/ptrace.h> 90b6d497fSChris Dearman #include <linux/stddef.h> 100b6d497fSChris Dearman 110b6d497fSChris Dearman #include <asm/fpu.h> 120b6d497fSChris Dearman #include <asm/mipsregs.h> 130b6d497fSChris Dearman #include <asm/r4kcache.h> 140b6d497fSChris Dearman #include <asm/hazards.h> 150b6d497fSChris Dearman 160b6d497fSChris Dearman /* 170b6d497fSChris Dearman * These definitions are correct for the 24K/34K/74K SPRAM sample 180b6d497fSChris Dearman * implementation. The 4KS interpreted the tags differently... 190b6d497fSChris Dearman */ 200b6d497fSChris Dearman #define SPRAM_TAG0_ENABLE 0x00000080 210b6d497fSChris Dearman #define SPRAM_TAG0_PA_MASK 0xfffff000 220b6d497fSChris Dearman #define SPRAM_TAG1_SIZE_MASK 0xfffff000 230b6d497fSChris Dearman 240b6d497fSChris Dearman #define SPRAM_TAG_STRIDE 8 250b6d497fSChris Dearman 260b6d497fSChris Dearman #define ERRCTL_SPRAM (1 << 28) 270b6d497fSChris Dearman 280b6d497fSChris Dearman /* errctl access */ 290b6d497fSChris Dearman #define read_c0_errctl(x) read_c0_ecc(x) 300b6d497fSChris Dearman #define write_c0_errctl(x) write_c0_ecc(x) 310b6d497fSChris Dearman 320b6d497fSChris Dearman /* 330b6d497fSChris Dearman * Different semantics to the set_c0_* function built by __BUILD_SET_C0 340b6d497fSChris Dearman */ 35078a55fcSPaul Gortmaker static unsigned int bis_c0_errctl(unsigned int set) 360b6d497fSChris Dearman { 370b6d497fSChris Dearman unsigned int res; 380b6d497fSChris Dearman res = read_c0_errctl(); 390b6d497fSChris Dearman write_c0_errctl(res | set); 400b6d497fSChris Dearman return res; 410b6d497fSChris Dearman } 420b6d497fSChris Dearman 43078a55fcSPaul Gortmaker static void ispram_store_tag(unsigned int offset, unsigned int data) 440b6d497fSChris Dearman { 450b6d497fSChris Dearman unsigned int errctl; 460b6d497fSChris Dearman 470b6d497fSChris Dearman /* enable SPRAM tag access */ 480b6d497fSChris Dearman errctl = bis_c0_errctl(ERRCTL_SPRAM); 490b6d497fSChris Dearman ehb(); 500b6d497fSChris Dearman 510b6d497fSChris Dearman write_c0_taglo(data); 520b6d497fSChris Dearman ehb(); 530b6d497fSChris Dearman 540b6d497fSChris Dearman cache_op(Index_Store_Tag_I, CKSEG0|offset); 550b6d497fSChris Dearman ehb(); 560b6d497fSChris Dearman 570b6d497fSChris Dearman write_c0_errctl(errctl); 580b6d497fSChris Dearman ehb(); 590b6d497fSChris Dearman } 600b6d497fSChris Dearman 610b6d497fSChris Dearman 62078a55fcSPaul Gortmaker static unsigned int ispram_load_tag(unsigned int offset) 630b6d497fSChris Dearman { 640b6d497fSChris Dearman unsigned int data; 650b6d497fSChris Dearman unsigned int errctl; 660b6d497fSChris Dearman 670b6d497fSChris Dearman /* enable SPRAM tag access */ 680b6d497fSChris Dearman errctl = bis_c0_errctl(ERRCTL_SPRAM); 690b6d497fSChris Dearman ehb(); 700b6d497fSChris Dearman cache_op(Index_Load_Tag_I, CKSEG0 | offset); 710b6d497fSChris Dearman ehb(); 720b6d497fSChris Dearman data = read_c0_taglo(); 730b6d497fSChris Dearman ehb(); 740b6d497fSChris Dearman write_c0_errctl(errctl); 750b6d497fSChris Dearman ehb(); 760b6d497fSChris Dearman 770b6d497fSChris Dearman return data; 780b6d497fSChris Dearman } 790b6d497fSChris Dearman 80078a55fcSPaul Gortmaker static void dspram_store_tag(unsigned int offset, unsigned int data) 810b6d497fSChris Dearman { 820b6d497fSChris Dearman unsigned int errctl; 830b6d497fSChris Dearman 840b6d497fSChris Dearman /* enable SPRAM tag access */ 850b6d497fSChris Dearman errctl = bis_c0_errctl(ERRCTL_SPRAM); 860b6d497fSChris Dearman ehb(); 870b6d497fSChris Dearman write_c0_dtaglo(data); 880b6d497fSChris Dearman ehb(); 890b6d497fSChris Dearman cache_op(Index_Store_Tag_D, CKSEG0 | offset); 900b6d497fSChris Dearman ehb(); 910b6d497fSChris Dearman write_c0_errctl(errctl); 920b6d497fSChris Dearman ehb(); 930b6d497fSChris Dearman } 940b6d497fSChris Dearman 950b6d497fSChris Dearman 96078a55fcSPaul Gortmaker static unsigned int dspram_load_tag(unsigned int offset) 970b6d497fSChris Dearman { 980b6d497fSChris Dearman unsigned int data; 990b6d497fSChris Dearman unsigned int errctl; 1000b6d497fSChris Dearman 1010b6d497fSChris Dearman errctl = bis_c0_errctl(ERRCTL_SPRAM); 1020b6d497fSChris Dearman ehb(); 1030b6d497fSChris Dearman cache_op(Index_Load_Tag_D, CKSEG0 | offset); 1040b6d497fSChris Dearman ehb(); 1050b6d497fSChris Dearman data = read_c0_dtaglo(); 1060b6d497fSChris Dearman ehb(); 1070b6d497fSChris Dearman write_c0_errctl(errctl); 1080b6d497fSChris Dearman ehb(); 1090b6d497fSChris Dearman 1100b6d497fSChris Dearman return data; 1110b6d497fSChris Dearman } 1120b6d497fSChris Dearman 113078a55fcSPaul Gortmaker static void probe_spram(char *type, 1140b6d497fSChris Dearman unsigned int base, 1150b6d497fSChris Dearman unsigned int (*read)(unsigned int), 1160b6d497fSChris Dearman void (*write)(unsigned int, unsigned int)) 1170b6d497fSChris Dearman { 1180b6d497fSChris Dearman unsigned int firstsize = 0, lastsize = 0; 1190b6d497fSChris Dearman unsigned int firstpa = 0, lastpa = 0, pa = 0; 1200b6d497fSChris Dearman unsigned int offset = 0; 1210b6d497fSChris Dearman unsigned int size, tag0, tag1; 1220b6d497fSChris Dearman unsigned int enabled; 1230b6d497fSChris Dearman int i; 1240b6d497fSChris Dearman 1250b6d497fSChris Dearman /* 1260b6d497fSChris Dearman * The limit is arbitrary but avoids the loop running away if 1270b6d497fSChris Dearman * the SPRAM tags are implemented differently 1280b6d497fSChris Dearman */ 1290b6d497fSChris Dearman 1300b6d497fSChris Dearman for (i = 0; i < 8; i++) { 1310b6d497fSChris Dearman tag0 = read(offset); 1320b6d497fSChris Dearman tag1 = read(offset+SPRAM_TAG_STRIDE); 1330b6d497fSChris Dearman pr_debug("DBG %s%d: tag0=%08x tag1=%08x\n", 1340b6d497fSChris Dearman type, i, tag0, tag1); 1350b6d497fSChris Dearman 1360b6d497fSChris Dearman size = tag1 & SPRAM_TAG1_SIZE_MASK; 1370b6d497fSChris Dearman 1380b6d497fSChris Dearman if (size == 0) 1390b6d497fSChris Dearman break; 1400b6d497fSChris Dearman 1410b6d497fSChris Dearman if (i != 0) { 1420b6d497fSChris Dearman /* tags may repeat... */ 1430b6d497fSChris Dearman if ((pa == firstpa && size == firstsize) || 1440b6d497fSChris Dearman (pa == lastpa && size == lastsize)) 1450b6d497fSChris Dearman break; 1460b6d497fSChris Dearman } 1470b6d497fSChris Dearman 1480b6d497fSChris Dearman /* Align base with size */ 1490b6d497fSChris Dearman base = (base + size - 1) & ~(size-1); 1500b6d497fSChris Dearman 1510b6d497fSChris Dearman /* reprogram the base address base address and enable */ 1520b6d497fSChris Dearman tag0 = (base & SPRAM_TAG0_PA_MASK) | SPRAM_TAG0_ENABLE; 1530b6d497fSChris Dearman write(offset, tag0); 1540b6d497fSChris Dearman 1550b6d497fSChris Dearman base += size; 1560b6d497fSChris Dearman 1570b6d497fSChris Dearman /* reread the tag */ 1580b6d497fSChris Dearman tag0 = read(offset); 1590b6d497fSChris Dearman pa = tag0 & SPRAM_TAG0_PA_MASK; 1600b6d497fSChris Dearman enabled = tag0 & SPRAM_TAG0_ENABLE; 1610b6d497fSChris Dearman 1620b6d497fSChris Dearman if (i == 0) { 1630b6d497fSChris Dearman firstpa = pa; 1640b6d497fSChris Dearman firstsize = size; 1650b6d497fSChris Dearman } 1660b6d497fSChris Dearman 1670b6d497fSChris Dearman lastpa = pa; 1680b6d497fSChris Dearman lastsize = size; 1690b6d497fSChris Dearman 1700b6d497fSChris Dearman if (strcmp(type, "DSPRAM") == 0) { 1710b6d497fSChris Dearman unsigned int *vp = (unsigned int *)(CKSEG1 | pa); 1720b6d497fSChris Dearman unsigned int v; 1730b6d497fSChris Dearman #define TDAT 0x5a5aa5a5 1740b6d497fSChris Dearman vp[0] = TDAT; 1750b6d497fSChris Dearman vp[1] = ~TDAT; 1760b6d497fSChris Dearman 1770b6d497fSChris Dearman mb(); 1780b6d497fSChris Dearman 1790b6d497fSChris Dearman v = vp[0]; 1800b6d497fSChris Dearman if (v != TDAT) 1810b6d497fSChris Dearman printk(KERN_ERR "vp=%p wrote=%08x got=%08x\n", 1820b6d497fSChris Dearman vp, TDAT, v); 1830b6d497fSChris Dearman v = vp[1]; 1840b6d497fSChris Dearman if (v != ~TDAT) 1850b6d497fSChris Dearman printk(KERN_ERR "vp=%p wrote=%08x got=%08x\n", 1860b6d497fSChris Dearman vp+1, ~TDAT, v); 1870b6d497fSChris Dearman } 1880b6d497fSChris Dearman 1890b6d497fSChris Dearman pr_info("%s%d: PA=%08x,Size=%08x%s\n", 1900b6d497fSChris Dearman type, i, pa, size, enabled ? ",enabled" : ""); 1910b6d497fSChris Dearman offset += 2 * SPRAM_TAG_STRIDE; 1920b6d497fSChris Dearman } 1930b6d497fSChris Dearman } 194078a55fcSPaul Gortmaker void spram_config(void) 1950b6d497fSChris Dearman { 1960b6d497fSChris Dearman unsigned int config0; 1970b6d497fSChris Dearman 198d7b12056SWu Zhangjin switch (current_cpu_type()) { 1990b6d497fSChris Dearman case CPU_24K: 2000b6d497fSChris Dearman case CPU_34K: 2010b6d497fSChris Dearman case CPU_74K: 202a4e7cac1SRalf Baechle case CPU_1004K: 203442e14a2SSteven J. Hill case CPU_1074K: 20426ab96dfSLeonid Yegoshin case CPU_INTERAPTIV: 205708ac4b8SLeonid Yegoshin case CPU_PROAPTIV: 206aced4cbdSJames Hogan case CPU_P5600: 2074695089fSLeonid Yegoshin case CPU_QEMU_GENERIC: 2084e88a862SMarkos Chandras case CPU_I6400: 2091091bfa2SPaul Burton case CPU_P6600: 2100b6d497fSChris Dearman config0 = read_c0_config(); 2110b6d497fSChris Dearman /* FIXME: addresses are Malta specific */ 2120b6d497fSChris Dearman if (config0 & (1<<24)) { 2130b6d497fSChris Dearman probe_spram("ISPRAM", 0x1c000000, 2140b6d497fSChris Dearman &ispram_load_tag, &ispram_store_tag); 2150b6d497fSChris Dearman } 2160b6d497fSChris Dearman if (config0 & (1<<23)) 2170b6d497fSChris Dearman probe_spram("DSPRAM", 0x1c100000, 2180b6d497fSChris Dearman &dspram_load_tag, &dspram_store_tag); 2190b6d497fSChris Dearman } 2200b6d497fSChris Dearman } 221