xref: /kernel/linux/linux-6.6/arch/mips/mm/sc-r5k.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org),
462306a36Sopenharmony_ci * derived from r4xx0.c by David S. Miller (davem@davemloft.net).
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include <linux/init.h>
762306a36Sopenharmony_ci#include <linux/kernel.h>
862306a36Sopenharmony_ci#include <linux/sched.h>
962306a36Sopenharmony_ci#include <linux/mm.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <asm/mipsregs.h>
1262306a36Sopenharmony_ci#include <asm/bcache.h>
1362306a36Sopenharmony_ci#include <asm/cacheops.h>
1462306a36Sopenharmony_ci#include <asm/page.h>
1562306a36Sopenharmony_ci#include <asm/mmu_context.h>
1662306a36Sopenharmony_ci#include <asm/r4kcache.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/* Secondary cache size in bytes, if present.  */
1962306a36Sopenharmony_cistatic unsigned long scache_size;
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define SC_LINE 32
2262306a36Sopenharmony_ci#define SC_PAGE (128*SC_LINE)
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic inline void blast_r5000_scache(void)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	unsigned long start = INDEX_BASE;
2762306a36Sopenharmony_ci	unsigned long end = start + scache_size;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	while(start < end) {
3062306a36Sopenharmony_ci		cache_op(R5K_Page_Invalidate_S, start);
3162306a36Sopenharmony_ci		start += SC_PAGE;
3262306a36Sopenharmony_ci	}
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic void r5k_dma_cache_inv_sc(unsigned long addr, unsigned long size)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	unsigned long end, a;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	/* Catch bad driver code */
4062306a36Sopenharmony_ci	BUG_ON(size == 0);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	if (size >= scache_size) {
4362306a36Sopenharmony_ci		blast_r5000_scache();
4462306a36Sopenharmony_ci		return;
4562306a36Sopenharmony_ci	}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	/* On the R5000 secondary cache we cannot
4862306a36Sopenharmony_ci	 * invalidate less than a page at a time.
4962306a36Sopenharmony_ci	 * The secondary cache is physically indexed, write-through.
5062306a36Sopenharmony_ci	 */
5162306a36Sopenharmony_ci	a = addr & ~(SC_PAGE - 1);
5262306a36Sopenharmony_ci	end = (addr + size - 1) & ~(SC_PAGE - 1);
5362306a36Sopenharmony_ci	while (a <= end) {
5462306a36Sopenharmony_ci		cache_op(R5K_Page_Invalidate_S, a);
5562306a36Sopenharmony_ci		a += SC_PAGE;
5662306a36Sopenharmony_ci	}
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic void r5k_sc_enable(void)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	unsigned long flags;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	local_irq_save(flags);
6462306a36Sopenharmony_ci	set_c0_config(R5K_CONF_SE);
6562306a36Sopenharmony_ci	blast_r5000_scache();
6662306a36Sopenharmony_ci	local_irq_restore(flags);
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic void r5k_sc_disable(void)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	unsigned long flags;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	local_irq_save(flags);
7462306a36Sopenharmony_ci	blast_r5000_scache();
7562306a36Sopenharmony_ci	clear_c0_config(R5K_CONF_SE);
7662306a36Sopenharmony_ci	local_irq_restore(flags);
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic inline int __init r5k_sc_probe(void)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	unsigned long config = read_c0_config();
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	if (config & CONF_SC)
8462306a36Sopenharmony_ci		return 0;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	scache_size = (512 * 1024) << ((config & R5K_CONF_SS) >> 20);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	printk("R5000 SCACHE size %ldkB, linesize 32 bytes.\n",
8962306a36Sopenharmony_ci			scache_size >> 10);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	return 1;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic struct bcache_ops r5k_sc_ops = {
9562306a36Sopenharmony_ci	.bc_enable = r5k_sc_enable,
9662306a36Sopenharmony_ci	.bc_disable = r5k_sc_disable,
9762306a36Sopenharmony_ci	.bc_wback_inv = r5k_dma_cache_inv_sc,
9862306a36Sopenharmony_ci	.bc_inv = r5k_dma_cache_inv_sc
9962306a36Sopenharmony_ci};
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_civoid r5k_sc_init(void)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	if (r5k_sc_probe()) {
10462306a36Sopenharmony_ci		r5k_sc_enable();
10562306a36Sopenharmony_ci		bcops = &r5k_sc_ops;
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci}
108