The AM34 CPU core provides an automated way of purging the cache rather than manually iterating over all the tags in the cache. Make it possible to use these. Signed-off-by: Akira Takeuchi <takeuchi.akr@jp.panasonic.com> Signed-off-by: Kiyoshi Owada <owada.kiyoshi@jp.panasonic.com> Signed-off-by: David Howells <dhowells@redhat.com>
		
			
				
	
	
		
			308 lines
		
	
	
	
		
			7.6 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			308 lines
		
	
	
	
		
			7.6 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
/* MN10300 CPU core caching routines, using indirect regs on cache controller
 | 
						|
 *
 | 
						|
 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
 | 
						|
 * Written by David Howells (dhowells@redhat.com)
 | 
						|
 *
 | 
						|
 * This program is free software; you can redistribute it and/or
 | 
						|
 * modify it under the terms of the GNU General Public Licence
 | 
						|
 * as published by the Free Software Foundation; either version
 | 
						|
 * 2 of the Licence, or (at your option) any later version.
 | 
						|
 */
 | 
						|
 | 
						|
#include <linux/sys.h>
 | 
						|
#include <linux/linkage.h>
 | 
						|
#include <asm/smp.h>
 | 
						|
#include <asm/page.h>
 | 
						|
#include <asm/cache.h>
 | 
						|
#include <asm/irqflags.h>
 | 
						|
 | 
						|
	.am33_2
 | 
						|
 | 
						|
#ifndef CONFIG_SMP
 | 
						|
	.globl mn10300_dcache_flush
 | 
						|
	.globl mn10300_dcache_flush_page
 | 
						|
	.globl mn10300_dcache_flush_range
 | 
						|
	.globl mn10300_dcache_flush_range2
 | 
						|
	.globl mn10300_dcache_flush_inv
 | 
						|
	.globl mn10300_dcache_flush_inv_page
 | 
						|
	.globl mn10300_dcache_flush_inv_range
 | 
						|
	.globl mn10300_dcache_flush_inv_range2
 | 
						|
 | 
						|
mn10300_dcache_flush		= mn10300_local_dcache_flush
 | 
						|
mn10300_dcache_flush_page	= mn10300_local_dcache_flush_page
 | 
						|
mn10300_dcache_flush_range	= mn10300_local_dcache_flush_range
 | 
						|
mn10300_dcache_flush_range2	= mn10300_local_dcache_flush_range2
 | 
						|
mn10300_dcache_flush_inv	= mn10300_local_dcache_flush_inv
 | 
						|
mn10300_dcache_flush_inv_page	= mn10300_local_dcache_flush_inv_page
 | 
						|
mn10300_dcache_flush_inv_range	= mn10300_local_dcache_flush_inv_range
 | 
						|
mn10300_dcache_flush_inv_range2	= mn10300_local_dcache_flush_inv_range2
 | 
						|
 | 
						|
#endif /* !CONFIG_SMP */
 | 
						|
 | 
						|
###############################################################################
 | 
						|
#
 | 
						|
# void mn10300_local_dcache_flush(void)
 | 
						|
# Flush the entire data cache back to RAM
 | 
						|
#
 | 
						|
###############################################################################
 | 
						|
	ALIGN
 | 
						|
	.globl	mn10300_local_dcache_flush
 | 
						|
        .type	mn10300_local_dcache_flush,@function
 | 
						|
mn10300_local_dcache_flush:
 | 
						|
	movhu	(CHCTR),d0
 | 
						|
	btst	CHCTR_DCEN,d0
 | 
						|
	beq	mn10300_local_dcache_flush_end
 | 
						|
 | 
						|
	mov	DCPGCR,a0
 | 
						|
 | 
						|
	LOCAL_CLI_SAVE(d1)
 | 
						|
 | 
						|
	# wait for busy bit of area purge
 | 
						|
	setlb
 | 
						|
	mov	(a0),d0
 | 
						|
	btst	DCPGCR_DCPGBSY,d0
 | 
						|
	lne
 | 
						|
 | 
						|
	# set mask
 | 
						|
	clr	d0
 | 
						|
	mov	d0,(DCPGMR)
 | 
						|
 | 
						|
	# area purge
 | 
						|
	#
 | 
						|
	# DCPGCR = DCPGCR_DCP
 | 
						|
	#
 | 
						|
	mov	DCPGCR_DCP,d0
 | 
						|
	mov	d0,(a0)
 | 
						|
 | 
						|
	# wait for busy bit of area purge
 | 
						|
	setlb
 | 
						|
	mov	(a0),d0
 | 
						|
	btst	DCPGCR_DCPGBSY,d0
 | 
						|
	lne
 | 
						|
 | 
						|
	LOCAL_IRQ_RESTORE(d1)
 | 
						|
 | 
						|
mn10300_local_dcache_flush_end:
 | 
						|
	ret	[],0
 | 
						|
	.size	mn10300_local_dcache_flush,.-mn10300_local_dcache_flush
 | 
						|
 | 
						|
###############################################################################
 | 
						|
#
 | 
						|
# void mn10300_local_dcache_flush_page(unsigned long start)
 | 
						|
# void mn10300_local_dcache_flush_range(unsigned long start, unsigned long end)
 | 
						|
# void mn10300_local_dcache_flush_range2(unsigned long start, unsigned long size)
 | 
						|
# Flush a range of addresses on a page in the dcache
 | 
						|
#
 | 
						|
###############################################################################
 | 
						|
	ALIGN
 | 
						|
	.globl	mn10300_local_dcache_flush_page
 | 
						|
	.globl	mn10300_local_dcache_flush_range
 | 
						|
	.globl	mn10300_local_dcache_flush_range2
 | 
						|
	.type	mn10300_local_dcache_flush_page,@function
 | 
						|
	.type	mn10300_local_dcache_flush_range,@function
 | 
						|
	.type	mn10300_local_dcache_flush_range2,@function
 | 
						|
mn10300_local_dcache_flush_page:
 | 
						|
	and	~(PAGE_SIZE-1),d0
 | 
						|
	mov	PAGE_SIZE,d1
 | 
						|
mn10300_local_dcache_flush_range2:
 | 
						|
	add	d0,d1
 | 
						|
mn10300_local_dcache_flush_range:
 | 
						|
	movm	[d2,d3,a2],(sp)
 | 
						|
 | 
						|
	movhu	(CHCTR),d2
 | 
						|
	btst	CHCTR_DCEN,d2
 | 
						|
	beq	mn10300_local_dcache_flush_range_end
 | 
						|
 | 
						|
	# calculate alignsize
 | 
						|
	#
 | 
						|
	# alignsize = L1_CACHE_BYTES;
 | 
						|
	# for (i = (end - start - 1) / L1_CACHE_BYTES ;  i > 0; i >>= 1)
 | 
						|
	#     alignsize <<= 1;
 | 
						|
	# d2 = alignsize;
 | 
						|
	#
 | 
						|
	mov	L1_CACHE_BYTES,d2
 | 
						|
	sub	d0,d1,d3
 | 
						|
	add	-1,d3
 | 
						|
	lsr	L1_CACHE_SHIFT,d3
 | 
						|
	beq	2f
 | 
						|
1:
 | 
						|
	add     d2,d2
 | 
						|
	lsr     1,d3
 | 
						|
	bne     1b
 | 
						|
2:
 | 
						|
	mov	d1,a1		# a1 = end
 | 
						|
 | 
						|
	LOCAL_CLI_SAVE(d3)
 | 
						|
	mov	DCPGCR,a0
 | 
						|
 | 
						|
	# wait for busy bit of area purge
 | 
						|
	setlb
 | 
						|
	mov	(a0),d1
 | 
						|
	btst	DCPGCR_DCPGBSY,d1
 | 
						|
	lne
 | 
						|
 | 
						|
	# determine the mask
 | 
						|
	mov	d2,d1
 | 
						|
	add	-1,d1
 | 
						|
	not	d1		# d1 = mask = ~(alignsize-1)
 | 
						|
	mov	d1,(DCPGMR)
 | 
						|
 | 
						|
	and	d1,d0,a2	# a2 = mask & start
 | 
						|
 | 
						|
dcpgloop:
 | 
						|
	# area purge
 | 
						|
	mov	a2,d0
 | 
						|
	or	DCPGCR_DCP,d0
 | 
						|
	mov	d0,(a0)		# DCPGCR = (mask & start) | DCPGCR_DCP
 | 
						|
 | 
						|
	# wait for busy bit of area purge
 | 
						|
	setlb
 | 
						|
	mov	(a0),d1
 | 
						|
	btst	DCPGCR_DCPGBSY,d1
 | 
						|
	lne
 | 
						|
 | 
						|
	# check purge of end address
 | 
						|
	add	d2,a2		# a2 += alignsize
 | 
						|
	cmp	a1,a2		# if (a2 < end) goto dcpgloop
 | 
						|
	bns	dcpgloop
 | 
						|
 | 
						|
	LOCAL_IRQ_RESTORE(d3)
 | 
						|
 | 
						|
mn10300_local_dcache_flush_range_end:
 | 
						|
	ret	[d2,d3,a2],12
 | 
						|
 | 
						|
	.size	mn10300_local_dcache_flush_page,.-mn10300_local_dcache_flush_page
 | 
						|
	.size	mn10300_local_dcache_flush_range,.-mn10300_local_dcache_flush_range
 | 
						|
	.size	mn10300_local_dcache_flush_range2,.-mn10300_local_dcache_flush_range2
 | 
						|
 | 
						|
###############################################################################
 | 
						|
#
 | 
						|
# void mn10300_local_dcache_flush_inv(void)
 | 
						|
# Flush the entire data cache and invalidate all entries
 | 
						|
#
 | 
						|
###############################################################################
 | 
						|
	ALIGN
 | 
						|
	.globl	mn10300_local_dcache_flush_inv
 | 
						|
	.type	mn10300_local_dcache_flush_inv,@function
 | 
						|
mn10300_local_dcache_flush_inv:
 | 
						|
	movhu	(CHCTR),d0
 | 
						|
	btst	CHCTR_DCEN,d0
 | 
						|
	beq	mn10300_local_dcache_flush_inv_end
 | 
						|
 | 
						|
	mov	DCPGCR,a0
 | 
						|
 | 
						|
	LOCAL_CLI_SAVE(d1)
 | 
						|
 | 
						|
	# wait for busy bit of area purge & invalidate
 | 
						|
	setlb
 | 
						|
	mov	(a0),d0
 | 
						|
	btst	DCPGCR_DCPGBSY,d0
 | 
						|
	lne
 | 
						|
 | 
						|
	# set the mask to cover everything
 | 
						|
	clr	d0
 | 
						|
	mov	d0,(DCPGMR)
 | 
						|
 | 
						|
	# area purge & invalidate
 | 
						|
	mov	DCPGCR_DCP|DCPGCR_DCI,d0
 | 
						|
	mov	d0,(a0)
 | 
						|
 | 
						|
	# wait for busy bit of area purge & invalidate
 | 
						|
	setlb
 | 
						|
	mov	(a0),d0
 | 
						|
	btst	DCPGCR_DCPGBSY,d0
 | 
						|
	lne
 | 
						|
 | 
						|
	LOCAL_IRQ_RESTORE(d1)
 | 
						|
 | 
						|
mn10300_local_dcache_flush_inv_end:
 | 
						|
	ret	[],0
 | 
						|
	.size	mn10300_local_dcache_flush_inv,.-mn10300_local_dcache_flush_inv
 | 
						|
 | 
						|
###############################################################################
 | 
						|
#
 | 
						|
# void mn10300_local_dcache_flush_inv_page(unsigned long start)
 | 
						|
# void mn10300_local_dcache_flush_inv_range(unsigned long start, unsigned long end)
 | 
						|
# void mn10300_local_dcache_flush_inv_range2(unsigned long start, unsigned long size)
 | 
						|
# Flush and invalidate a range of addresses on a page in the dcache
 | 
						|
#
 | 
						|
###############################################################################
 | 
						|
	ALIGN
 | 
						|
	.globl	mn10300_local_dcache_flush_inv_page
 | 
						|
	.globl	mn10300_local_dcache_flush_inv_range
 | 
						|
	.globl	mn10300_local_dcache_flush_inv_range2
 | 
						|
	.type	mn10300_local_dcache_flush_inv_page,@function
 | 
						|
	.type	mn10300_local_dcache_flush_inv_range,@function
 | 
						|
	.type	mn10300_local_dcache_flush_inv_range2,@function
 | 
						|
mn10300_local_dcache_flush_inv_page:
 | 
						|
	and	~(PAGE_SIZE-1),d0
 | 
						|
	mov	PAGE_SIZE,d1
 | 
						|
mn10300_local_dcache_flush_inv_range2:
 | 
						|
	add	d0,d1
 | 
						|
mn10300_local_dcache_flush_inv_range:
 | 
						|
	movm	[d2,d3,a2],(sp)
 | 
						|
 | 
						|
	movhu	(CHCTR),d2
 | 
						|
	btst	CHCTR_DCEN,d2
 | 
						|
	beq	mn10300_local_dcache_flush_inv_range_end
 | 
						|
 | 
						|
	# calculate alignsize
 | 
						|
	#
 | 
						|
	# alignsize = L1_CACHE_BYTES;
 | 
						|
	# for (i = (end - start - 1) / L1_CACHE_BYTES; i > 0; i >>= 1)
 | 
						|
	#     alignsize <<= 1;
 | 
						|
	# d2 = alignsize
 | 
						|
	#
 | 
						|
	mov	L1_CACHE_BYTES,d2
 | 
						|
	sub	d0,d1,d3
 | 
						|
	add	-1,d3
 | 
						|
	lsr	L1_CACHE_SHIFT,d3
 | 
						|
	beq	2f
 | 
						|
1:
 | 
						|
	add     d2,d2
 | 
						|
	lsr     1,d3
 | 
						|
	bne     1b
 | 
						|
2:
 | 
						|
	mov	d1,a1		# a1 = end
 | 
						|
 | 
						|
	LOCAL_CLI_SAVE(d3)
 | 
						|
	mov	DCPGCR,a0
 | 
						|
 | 
						|
	# wait for busy bit of area purge & invalidate
 | 
						|
	setlb
 | 
						|
	mov	(a0),d1
 | 
						|
	btst	DCPGCR_DCPGBSY,d1
 | 
						|
	lne
 | 
						|
 | 
						|
	# set the mask
 | 
						|
	mov	d2,d1
 | 
						|
	add	-1,d1
 | 
						|
	not	d1		# d1 = mask = ~(alignsize-1)
 | 
						|
	mov	d1,(DCPGMR)
 | 
						|
 | 
						|
	and	d1,d0,a2	# a2 = mask & start
 | 
						|
 | 
						|
dcpgivloop:
 | 
						|
	# area purge & invalidate
 | 
						|
	mov	a2,d0
 | 
						|
	or	DCPGCR_DCP|DCPGCR_DCI,d0
 | 
						|
	mov	d0,(a0)		# DCPGCR = (mask & start)|DCPGCR_DCP|DCPGCR_DCI
 | 
						|
 | 
						|
	# wait for busy bit of area purge & invalidate
 | 
						|
	setlb
 | 
						|
	mov	(a0),d1
 | 
						|
	btst	DCPGCR_DCPGBSY,d1
 | 
						|
	lne
 | 
						|
 | 
						|
	# check purge & invalidate of end address
 | 
						|
	add	d2,a2		# a2 += alignsize
 | 
						|
	cmp	a1,a2		# if (a2 < end) goto dcpgivloop
 | 
						|
	bns	dcpgivloop
 | 
						|
 | 
						|
	LOCAL_IRQ_RESTORE(d3)
 | 
						|
 | 
						|
mn10300_local_dcache_flush_inv_range_end:
 | 
						|
	ret	[d2,d3,a2],12
 | 
						|
	.size	mn10300_local_dcache_flush_inv_page,.-mn10300_local_dcache_flush_inv_page
 | 
						|
	.size	mn10300_local_dcache_flush_inv_range,.-mn10300_local_dcache_flush_inv_range
 | 
						|
	.size	mn10300_local_dcache_flush_inv_range2,.-mn10300_local_dcache_flush_inv_range2
 |