sc-rm7k.c 3.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11
/*
 * sc-rm7k.c: RM7000 cache management functions.
 *
 * Copyright (C) 1997, 2001, 2003, 2004 Ralf Baechle (ralf@linux-mips.org)
 */

#undef DEBUG

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/mm.h>
A
Atsushi Nemoto 已提交
12
#include <linux/bitops.h>
L
Linus Torvalds 已提交
13 14 15 16 17 18

#include <asm/addrspace.h>
#include <asm/bcache.h>
#include <asm/cacheops.h>
#include <asm/mipsregs.h>
#include <asm/processor.h>
19
#include <asm/cacheflush.h> /* for run_uncached() */
L
Linus Torvalds 已提交
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46

/* Primary cache parameters. */
#define sc_lsize	32
#define tc_pagesize	(32*128)

/* Secondary cache parameters. */
#define scache_size	(256*1024)	/* Fixed to 256KiB on RM7000 */

extern unsigned long icache_way_size, dcache_way_size;

#include <asm/r4kcache.h>

int rm7k_tcache_enabled;

/*
 * Writeback and invalidate the primary cache dcache before DMA.
 * (XXX These need to be fixed ...)
 */
static void rm7k_sc_wback_inv(unsigned long addr, unsigned long size)
{
	unsigned long end, a;

	pr_debug("rm7k_sc_wback_inv[%08lx,%08lx]", addr, size);

	/* Catch bad driver code */
	BUG_ON(size == 0);

A
Atsushi Nemoto 已提交
47
	blast_scache_range(addr, addr + size);
L
Linus Torvalds 已提交
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70

	if (!rm7k_tcache_enabled)
		return;

	a = addr & ~(tc_pagesize - 1);
	end = (addr + size - 1) & ~(tc_pagesize - 1);
	while(1) {
		invalidate_tcache_page(a);	/* Page_Invalidate_T */
		if (a == end)
			break;
		a += tc_pagesize;
	}
}

static void rm7k_sc_inv(unsigned long addr, unsigned long size)
{
	unsigned long end, a;

	pr_debug("rm7k_sc_inv[%08lx,%08lx]", addr, size);

	/* Catch bad driver code */
	BUG_ON(size == 0);

A
Atsushi Nemoto 已提交
71
	blast_inv_scache_range(addr, addr + size);
L
Linus Torvalds 已提交
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86

	if (!rm7k_tcache_enabled)
		return;

	a = addr & ~(tc_pagesize - 1);
	end = (addr + size - 1) & ~(tc_pagesize - 1);
	while(1) {
		invalidate_tcache_page(a);	/* Page_Invalidate_T */
		if (a == end)
			break;
		a += tc_pagesize;
	}
}

/*
87
 * This function is executed in uncached address space.
L
Linus Torvalds 已提交
88 89 90 91 92
 */
static __init void __rm7k_sc_enable(void)
{
	int i;

93
	set_c0_config(RM7K_CONF_SE);
L
Linus Torvalds 已提交
94 95 96 97 98 99 100 101 102 103 104 105

	write_c0_taglo(0);
	write_c0_taghi(0);

	for (i = 0; i < scache_size; i += sc_lsize) {
		__asm__ __volatile__ (
		      ".set noreorder\n\t"
		      ".set mips3\n\t"
		      "cache %1, (%0)\n\t"
		      ".set mips0\n\t"
		      ".set reorder"
		      :
106
		      : "r" (CKSEG0ADDR(i)), "i" (Index_Store_Tag_SD));
L
Linus Torvalds 已提交
107 108 109 110 111
	}
}

static __init void rm7k_sc_enable(void)
{
112
	if (read_c0_config() & RM7K_CONF_SE)
L
Linus Torvalds 已提交
113 114
		return;

115
	printk(KERN_INFO "Enabling secondary cache...\n");
116
	run_uncached(__rm7k_sc_enable);
L
Linus Torvalds 已提交
117 118 119 120
}

static void rm7k_sc_disable(void)
{
121
	clear_c0_config(RM7K_CONF_SE);
L
Linus Torvalds 已提交
122 123 124 125 126 127 128 129 130 131 132
}

struct bcache_ops rm7k_sc_ops = {
	.bc_enable = rm7k_sc_enable,
	.bc_disable = rm7k_sc_disable,
	.bc_wback_inv = rm7k_sc_wback_inv,
	.bc_inv = rm7k_sc_inv
};

void __init rm7k_sc_init(void)
{
A
Atsushi Nemoto 已提交
133
	struct cpuinfo_mips *c = &current_cpu_data;
L
Linus Torvalds 已提交
134 135
	unsigned int config = read_c0_config();

136
	if ((config & RM7K_CONF_SC))
L
Linus Torvalds 已提交
137 138
		return;

A
Atsushi Nemoto 已提交
139 140
	c->scache.linesz = sc_lsize;
	c->scache.ways = 4;
141
	c->scache.waybit= __ffs(scache_size / c->scache.ways);
A
Atsushi Nemoto 已提交
142 143
	c->scache.waysize = scache_size / c->scache.ways;
	c->scache.sets = scache_size / (c->scache.linesz * c->scache.ways);
L
Linus Torvalds 已提交
144 145 146
	printk(KERN_INFO "Secondary cache size %dK, linesize %d bytes.\n",
	       (scache_size >> 10), sc_lsize);

147
	if (!(config & RM7K_CONF_SE))
L
Linus Torvalds 已提交
148 149 150 151 152
		rm7k_sc_enable();

	/*
	 * While we're at it let's deal with the tertiary cache.
	 */
153
	if (!(config & RM7K_CONF_TC)) {
L
Linus Torvalds 已提交
154 155 156 157 158 159 160 161 162 163 164 165

		/*
		 * We can't enable the L3 cache yet. There may be board-specific
		 * magic necessary to turn it on, and blindly asking the CPU to
		 * start using it would may give cache errors.
		 *
		 * Also, board-specific knowledge may allow us to use the
		 * CACHE Flash_Invalidate_T instruction if the tag RAM supports
		 * it, and may specify the size of the L3 cache so we don't have
		 * to probe it.
		 */
		printk(KERN_INFO "Tertiary cache present, %s enabled\n",
166
		       (config & RM7K_CONF_TE) ? "already" : "not (yet)");
L
Linus Torvalds 已提交
167

168
		if ((config & RM7K_CONF_TE))
L
Linus Torvalds 已提交
169 170 171 172 173
			rm7k_tcache_enabled = 1;
	}

	bcops = &rm7k_sc_ops;
}