217 lines · 4.4 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * MIPS SPRAM support * * Copyright (C) 2007, 2008 MIPS Technologies, Inc. */#include <linux/kernel.h>#include <linux/ptrace.h>#include <linux/stddef.h> #include <asm/fpu.h>#include <asm/mipsregs.h>#include <asm/r4kcache.h>#include <asm/hazards.h>#include <asm/spram.h> /* * These definitions are correct for the 24K/34K/74K SPRAM sample * implementation. The 4KS interpreted the tags differently... */#define SPRAM_TAG0_ENABLE	0x00000080#define SPRAM_TAG0_PA_MASK	0xfffff000#define SPRAM_TAG1_SIZE_MASK	0xfffff000 #define SPRAM_TAG_STRIDE	8 #define ERRCTL_SPRAM		(1 << 28) /* * Different semantics to the set_c0_* function built by __BUILD_SET_C0 */static unsigned int bis_c0_errctl(unsigned int set){	unsigned int res;	res = read_c0_errctl();	write_c0_errctl(res | set);	return res;} static void ispram_store_tag(unsigned int offset, unsigned int data){	unsigned int errctl; 	/* enable SPRAM tag access */	errctl = bis_c0_errctl(ERRCTL_SPRAM);	ehb(); 	write_c0_taglo(data);	ehb(); 	cache_op(Index_Store_Tag_I, CKSEG0|offset);	ehb(); 	write_c0_errctl(errctl);	ehb();}  static unsigned int ispram_load_tag(unsigned int offset){	unsigned int data;	unsigned int errctl; 	/* enable SPRAM tag access */	errctl = bis_c0_errctl(ERRCTL_SPRAM);	ehb();	cache_op(Index_Load_Tag_I, CKSEG0 | offset);	ehb();	data = read_c0_taglo();	ehb();	write_c0_errctl(errctl);	ehb(); 	return data;} static void dspram_store_tag(unsigned int offset, unsigned int data){	unsigned int errctl; 	/* enable SPRAM tag access */	errctl = bis_c0_errctl(ERRCTL_SPRAM);	ehb();	write_c0_dtaglo(data);	ehb();	cache_op(Index_Store_Tag_D, CKSEG0 | offset);	ehb();	write_c0_errctl(errctl);	ehb();}  static unsigned int dspram_load_tag(unsigned int offset){	unsigned int data;	unsigned int errctl; 	errctl = bis_c0_errctl(ERRCTL_SPRAM);	ehb();	cache_op(Index_Load_Tag_D, CKSEG0 | offset);	ehb();	data = read_c0_dtaglo();	ehb();	write_c0_errctl(errctl);	ehb(); 	return data;} static void probe_spram(char *type,	    unsigned int base,	    unsigned int (*read)(unsigned int),	    void (*write)(unsigned int, unsigned int)){	unsigned int firstsize = 0, lastsize = 0;	unsigned int firstpa = 0, lastpa = 0, pa = 0;	unsigned int offset = 0;	unsigned int size, tag0, tag1;	unsigned int enabled;	int i; 	/*	 * The limit is arbitrary but avoids the loop running away if	 * the SPRAM tags are implemented differently	 */ 	for (i = 0; i < 8; i++) {		tag0 = read(offset);		tag1 = read(offset+SPRAM_TAG_STRIDE);		pr_debug("DBG %s%d: tag0=%08x tag1=%08x\n",			 type, i, tag0, tag1); 		size = tag1 & SPRAM_TAG1_SIZE_MASK; 		if (size == 0)			break; 		if (i != 0) {			/* tags may repeat... */			if ((pa == firstpa && size == firstsize) ||			    (pa == lastpa && size == lastsize))				break;		} 		/* Align base with size */		base = (base + size - 1) & ~(size-1); 		/* reprogram the base address base address and enable */		tag0 = (base & SPRAM_TAG0_PA_MASK) | SPRAM_TAG0_ENABLE;		write(offset, tag0); 		base += size; 		/* reread the tag */		tag0 = read(offset);		pa = tag0 & SPRAM_TAG0_PA_MASK;		enabled = tag0 & SPRAM_TAG0_ENABLE; 		if (i == 0) {			firstpa = pa;			firstsize = size;		} 		lastpa = pa;		lastsize = size; 		if (strcmp(type, "DSPRAM") == 0) {			unsigned int *vp = (unsigned int *)(CKSEG1 | pa);			unsigned int v;#define TDAT	0x5a5aa5a5			vp[0] = TDAT;			vp[1] = ~TDAT; 			mb(); 			v = vp[0];			if (v != TDAT)				printk(KERN_ERR "vp=%p wrote=%08x got=%08x\n",				       vp, TDAT, v);			v = vp[1];			if (v != ~TDAT)				printk(KERN_ERR "vp=%p wrote=%08x got=%08x\n",				       vp+1, ~TDAT, v);		} 		pr_info("%s%d: PA=%08x,Size=%08x%s\n",			type, i, pa, size, enabled ? ",enabled" : "");		offset += 2 * SPRAM_TAG_STRIDE;	}}void spram_config(void){	unsigned int config0; 	switch (current_cpu_type()) {	case CPU_24K:	case CPU_34K:	case CPU_74K:	case CPU_1004K:	case CPU_1074K:	case CPU_INTERAPTIV:	case CPU_PROAPTIV:	case CPU_P5600:	case CPU_QEMU_GENERIC:	case CPU_I6400:	case CPU_P6600:		config0 = read_c0_config();		/* FIXME: addresses are Malta specific */		if (config0 & MIPS_CONF_ISP) {			probe_spram("ISPRAM", 0x1c000000,				    &ispram_load_tag, &ispram_store_tag);		}		if (config0 & MIPS_CONF_DSP)			probe_spram("DSPRAM", 0x1c100000,				    &dspram_load_tag, &dspram_store_tag);	}}