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