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