12874c5fdSThomas 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 */
bis_c0_errctl(unsigned int set)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
ispram_store_tag(unsigned int offset,unsigned int data)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
ispram_load_tag(unsigned int offset)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
dspram_store_tag(unsigned int offset,unsigned int data)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
dspram_load_tag(unsigned int offset)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
probe_spram(char * type,unsigned int base,unsigned int (* read)(unsigned int),void (* write)(unsigned int,unsigned int))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 }
spram_config(void)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 */
212*999079c8SSerge Semin if (config0 & MIPS_CONF_ISP) {
2130b6d497fSChris Dearman probe_spram("ISPRAM", 0x1c000000,
2140b6d497fSChris Dearman &ispram_load_tag, &ispram_store_tag);
2150b6d497fSChris Dearman }
216*999079c8SSerge Semin if (config0 & MIPS_CONF_DSP)
2170b6d497fSChris Dearman probe_spram("DSPRAM", 0x1c100000,
2180b6d497fSChris Dearman &dspram_load_tag, &dspram_store_tag);
2190b6d497fSChris Dearman }
2200b6d497fSChris Dearman }
221