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