mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-04 20:19:47 +08:00 
			
		
		
		
	 add5ca2c48
			
		
	
	
		add5ca2c48
		
	
	
	
	
		
			
			Update license to use SPDX-License-Identifier instead of verbose license text. Link: http://lkml.kernel.org/r/878t14csxy.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Reviewed-by: Simon Horman <horms+renesas@verge.net.au> Cc: Rich Felker <dalias@libc.org> Cc: Yoshinori Sato <ysato@users.sourceforge.jp> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
		
			
				
	
	
		
			131 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			131 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0
 | |
| /*
 | |
|  * arch/sh/kernel/cpu/sh4a/ubc.c
 | |
|  *
 | |
|  * On-chip UBC support for SH-4A CPUs.
 | |
|  *
 | |
|  * Copyright (C) 2009 - 2010  Paul Mundt
 | |
|  */
 | |
| #include <linux/init.h>
 | |
| #include <linux/err.h>
 | |
| #include <linux/clk.h>
 | |
| #include <linux/io.h>
 | |
| #include <asm/hw_breakpoint.h>
 | |
| 
 | |
| #define UBC_CBR(idx)	(0xff200000 + (0x20 * idx))
 | |
| #define UBC_CRR(idx)	(0xff200004 + (0x20 * idx))
 | |
| #define UBC_CAR(idx)	(0xff200008 + (0x20 * idx))
 | |
| #define UBC_CAMR(idx)	(0xff20000c + (0x20 * idx))
 | |
| 
 | |
| #define UBC_CCMFR	0xff200600
 | |
| #define UBC_CBCR	0xff200620
 | |
| 
 | |
| /* CRR */
 | |
| #define UBC_CRR_PCB	(1 << 1)
 | |
| #define UBC_CRR_BIE	(1 << 0)
 | |
| 
 | |
| /* CBR */
 | |
| #define UBC_CBR_CE	(1 << 0)
 | |
| 
 | |
| static struct sh_ubc sh4a_ubc;
 | |
| 
 | |
| static void sh4a_ubc_enable(struct arch_hw_breakpoint *info, int idx)
 | |
| {
 | |
| 	__raw_writel(UBC_CBR_CE | info->len | info->type, UBC_CBR(idx));
 | |
| 	__raw_writel(info->address, UBC_CAR(idx));
 | |
| }
 | |
| 
 | |
| static void sh4a_ubc_disable(struct arch_hw_breakpoint *info, int idx)
 | |
| {
 | |
| 	__raw_writel(0, UBC_CBR(idx));
 | |
| 	__raw_writel(0, UBC_CAR(idx));
 | |
| }
 | |
| 
 | |
| static void sh4a_ubc_enable_all(unsigned long mask)
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	for (i = 0; i < sh4a_ubc.num_events; i++)
 | |
| 		if (mask & (1 << i))
 | |
| 			__raw_writel(__raw_readl(UBC_CBR(i)) | UBC_CBR_CE,
 | |
| 				     UBC_CBR(i));
 | |
| }
 | |
| 
 | |
| static void sh4a_ubc_disable_all(void)
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	for (i = 0; i < sh4a_ubc.num_events; i++)
 | |
| 		__raw_writel(__raw_readl(UBC_CBR(i)) & ~UBC_CBR_CE,
 | |
| 			     UBC_CBR(i));
 | |
| }
 | |
| 
 | |
| static unsigned long sh4a_ubc_active_mask(void)
 | |
| {
 | |
| 	unsigned long active = 0;
 | |
| 	int i;
 | |
| 
 | |
| 	for (i = 0; i < sh4a_ubc.num_events; i++)
 | |
| 		if (__raw_readl(UBC_CBR(i)) & UBC_CBR_CE)
 | |
| 			active |= (1 << i);
 | |
| 
 | |
| 	return active;
 | |
| }
 | |
| 
 | |
| static unsigned long sh4a_ubc_triggered_mask(void)
 | |
| {
 | |
| 	return __raw_readl(UBC_CCMFR);
 | |
| }
 | |
| 
 | |
| static void sh4a_ubc_clear_triggered_mask(unsigned long mask)
 | |
| {
 | |
| 	__raw_writel(__raw_readl(UBC_CCMFR) & ~mask, UBC_CCMFR);
 | |
| }
 | |
| 
 | |
| static struct sh_ubc sh4a_ubc = {
 | |
| 	.name			= "SH-4A",
 | |
| 	.num_events		= 2,
 | |
| 	.trap_nr		= 0x1e0,
 | |
| 	.enable			= sh4a_ubc_enable,
 | |
| 	.disable		= sh4a_ubc_disable,
 | |
| 	.enable_all		= sh4a_ubc_enable_all,
 | |
| 	.disable_all		= sh4a_ubc_disable_all,
 | |
| 	.active_mask		= sh4a_ubc_active_mask,
 | |
| 	.triggered_mask		= sh4a_ubc_triggered_mask,
 | |
| 	.clear_triggered_mask	= sh4a_ubc_clear_triggered_mask,
 | |
| };
 | |
| 
 | |
| static int __init sh4a_ubc_init(void)
 | |
| {
 | |
| 	struct clk *ubc_iclk = clk_get(NULL, "ubc0");
 | |
| 	int i;
 | |
| 
 | |
| 	/*
 | |
| 	 * The UBC MSTP bit is optional, as not all platforms will have
 | |
| 	 * it. Just ignore it if we can't find it.
 | |
| 	 */
 | |
| 	if (IS_ERR(ubc_iclk))
 | |
| 		ubc_iclk = NULL;
 | |
| 
 | |
| 	clk_enable(ubc_iclk);
 | |
| 
 | |
| 	__raw_writel(0, UBC_CBCR);
 | |
| 
 | |
| 	for (i = 0; i < sh4a_ubc.num_events; i++) {
 | |
| 		__raw_writel(0, UBC_CAMR(i));
 | |
| 		__raw_writel(0, UBC_CBR(i));
 | |
| 
 | |
| 		__raw_writel(UBC_CRR_BIE | UBC_CRR_PCB, UBC_CRR(i));
 | |
| 
 | |
| 		/* dummy read for write posting */
 | |
| 		(void)__raw_readl(UBC_CRR(i));
 | |
| 	}
 | |
| 
 | |
| 	clk_disable(ubc_iclk);
 | |
| 
 | |
| 	sh4a_ubc.clk = ubc_iclk;
 | |
| 
 | |
| 	return register_sh_ubc(&sh4a_ubc);
 | |
| }
 | |
| arch_initcall(sh4a_ubc_init);
 |