xref: /openbmc/linux/arch/mips/kernel/spram.c (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
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