xref: /openbmc/linux/arch/sh/kernel/cpu/sh4a/ubc.c (revision 597473720f4dc69749542bfcfed4a927a43d935e)
1*add5ca2cSKuninori Morimoto // SPDX-License-Identifier: GPL-2.0
24352fc1bSPaul Mundt /*
34352fc1bSPaul Mundt  * arch/sh/kernel/cpu/sh4a/ubc.c
44352fc1bSPaul Mundt  *
54352fc1bSPaul Mundt  * On-chip UBC support for SH-4A CPUs.
64352fc1bSPaul Mundt  *
74352fc1bSPaul Mundt  * Copyright (C) 2009 - 2010  Paul Mundt
84352fc1bSPaul Mundt  */
94352fc1bSPaul Mundt #include <linux/init.h>
104352fc1bSPaul Mundt #include <linux/err.h>
114352fc1bSPaul Mundt #include <linux/clk.h>
124352fc1bSPaul Mundt #include <linux/io.h>
134352fc1bSPaul Mundt #include <asm/hw_breakpoint.h>
144352fc1bSPaul Mundt 
154352fc1bSPaul Mundt #define UBC_CBR(idx)	(0xff200000 + (0x20 * idx))
164352fc1bSPaul Mundt #define UBC_CRR(idx)	(0xff200004 + (0x20 * idx))
174352fc1bSPaul Mundt #define UBC_CAR(idx)	(0xff200008 + (0x20 * idx))
184352fc1bSPaul Mundt #define UBC_CAMR(idx)	(0xff20000c + (0x20 * idx))
194352fc1bSPaul Mundt 
204352fc1bSPaul Mundt #define UBC_CCMFR	0xff200600
214352fc1bSPaul Mundt #define UBC_CBCR	0xff200620
224352fc1bSPaul Mundt 
234352fc1bSPaul Mundt /* CRR */
244352fc1bSPaul Mundt #define UBC_CRR_PCB	(1 << 1)
254352fc1bSPaul Mundt #define UBC_CRR_BIE	(1 << 0)
264352fc1bSPaul Mundt 
274352fc1bSPaul Mundt /* CBR */
284352fc1bSPaul Mundt #define UBC_CBR_CE	(1 << 0)
294352fc1bSPaul Mundt 
304352fc1bSPaul Mundt static struct sh_ubc sh4a_ubc;
314352fc1bSPaul Mundt 
sh4a_ubc_enable(struct arch_hw_breakpoint * info,int idx)324352fc1bSPaul Mundt static void sh4a_ubc_enable(struct arch_hw_breakpoint *info, int idx)
334352fc1bSPaul Mundt {
344352fc1bSPaul Mundt 	__raw_writel(UBC_CBR_CE | info->len | info->type, UBC_CBR(idx));
354352fc1bSPaul Mundt 	__raw_writel(info->address, UBC_CAR(idx));
364352fc1bSPaul Mundt }
374352fc1bSPaul Mundt 
sh4a_ubc_disable(struct arch_hw_breakpoint * info,int idx)384352fc1bSPaul Mundt static void sh4a_ubc_disable(struct arch_hw_breakpoint *info, int idx)
394352fc1bSPaul Mundt {
404352fc1bSPaul Mundt 	__raw_writel(0, UBC_CBR(idx));
414352fc1bSPaul Mundt 	__raw_writel(0, UBC_CAR(idx));
424352fc1bSPaul Mundt }
434352fc1bSPaul Mundt 
sh4a_ubc_enable_all(unsigned long mask)444352fc1bSPaul Mundt static void sh4a_ubc_enable_all(unsigned long mask)
454352fc1bSPaul Mundt {
464352fc1bSPaul Mundt 	int i;
474352fc1bSPaul Mundt 
484352fc1bSPaul Mundt 	for (i = 0; i < sh4a_ubc.num_events; i++)
494352fc1bSPaul Mundt 		if (mask & (1 << i))
504352fc1bSPaul Mundt 			__raw_writel(__raw_readl(UBC_CBR(i)) | UBC_CBR_CE,
514352fc1bSPaul Mundt 				     UBC_CBR(i));
524352fc1bSPaul Mundt }
534352fc1bSPaul Mundt 
sh4a_ubc_disable_all(void)544352fc1bSPaul Mundt static void sh4a_ubc_disable_all(void)
554352fc1bSPaul Mundt {
564352fc1bSPaul Mundt 	int i;
574352fc1bSPaul Mundt 
584352fc1bSPaul Mundt 	for (i = 0; i < sh4a_ubc.num_events; i++)
594352fc1bSPaul Mundt 		__raw_writel(__raw_readl(UBC_CBR(i)) & ~UBC_CBR_CE,
604352fc1bSPaul Mundt 			     UBC_CBR(i));
614352fc1bSPaul Mundt }
624352fc1bSPaul Mundt 
sh4a_ubc_active_mask(void)634352fc1bSPaul Mundt static unsigned long sh4a_ubc_active_mask(void)
644352fc1bSPaul Mundt {
654352fc1bSPaul Mundt 	unsigned long active = 0;
664352fc1bSPaul Mundt 	int i;
674352fc1bSPaul Mundt 
684352fc1bSPaul Mundt 	for (i = 0; i < sh4a_ubc.num_events; i++)
694352fc1bSPaul Mundt 		if (__raw_readl(UBC_CBR(i)) & UBC_CBR_CE)
704352fc1bSPaul Mundt 			active |= (1 << i);
714352fc1bSPaul Mundt 
724352fc1bSPaul Mundt 	return active;
734352fc1bSPaul Mundt }
744352fc1bSPaul Mundt 
sh4a_ubc_triggered_mask(void)754352fc1bSPaul Mundt static unsigned long sh4a_ubc_triggered_mask(void)
764352fc1bSPaul Mundt {
774352fc1bSPaul Mundt 	return __raw_readl(UBC_CCMFR);
784352fc1bSPaul Mundt }
794352fc1bSPaul Mundt 
sh4a_ubc_clear_triggered_mask(unsigned long mask)804352fc1bSPaul Mundt static void sh4a_ubc_clear_triggered_mask(unsigned long mask)
814352fc1bSPaul Mundt {
824352fc1bSPaul Mundt 	__raw_writel(__raw_readl(UBC_CCMFR) & ~mask, UBC_CCMFR);
834352fc1bSPaul Mundt }
844352fc1bSPaul Mundt 
854352fc1bSPaul Mundt static struct sh_ubc sh4a_ubc = {
864352fc1bSPaul Mundt 	.name			= "SH-4A",
874352fc1bSPaul Mundt 	.num_events		= 2,
884352fc1bSPaul Mundt 	.trap_nr		= 0x1e0,
894352fc1bSPaul Mundt 	.enable			= sh4a_ubc_enable,
904352fc1bSPaul Mundt 	.disable		= sh4a_ubc_disable,
914352fc1bSPaul Mundt 	.enable_all		= sh4a_ubc_enable_all,
924352fc1bSPaul Mundt 	.disable_all		= sh4a_ubc_disable_all,
934352fc1bSPaul Mundt 	.active_mask		= sh4a_ubc_active_mask,
944352fc1bSPaul Mundt 	.triggered_mask		= sh4a_ubc_triggered_mask,
954352fc1bSPaul Mundt 	.clear_triggered_mask	= sh4a_ubc_clear_triggered_mask,
964352fc1bSPaul Mundt };
974352fc1bSPaul Mundt 
sh4a_ubc_init(void)984352fc1bSPaul Mundt static int __init sh4a_ubc_init(void)
994352fc1bSPaul Mundt {
1004352fc1bSPaul Mundt 	struct clk *ubc_iclk = clk_get(NULL, "ubc0");
1014352fc1bSPaul Mundt 	int i;
1024352fc1bSPaul Mundt 
1034352fc1bSPaul Mundt 	/*
1044352fc1bSPaul Mundt 	 * The UBC MSTP bit is optional, as not all platforms will have
1054352fc1bSPaul Mundt 	 * it. Just ignore it if we can't find it.
1064352fc1bSPaul Mundt 	 */
1074352fc1bSPaul Mundt 	if (IS_ERR(ubc_iclk))
1084352fc1bSPaul Mundt 		ubc_iclk = NULL;
1094352fc1bSPaul Mundt 
1104352fc1bSPaul Mundt 	clk_enable(ubc_iclk);
1114352fc1bSPaul Mundt 
1124352fc1bSPaul Mundt 	__raw_writel(0, UBC_CBCR);
1134352fc1bSPaul Mundt 
1144352fc1bSPaul Mundt 	for (i = 0; i < sh4a_ubc.num_events; i++) {
1154352fc1bSPaul Mundt 		__raw_writel(0, UBC_CAMR(i));
1164352fc1bSPaul Mundt 		__raw_writel(0, UBC_CBR(i));
1174352fc1bSPaul Mundt 
1184352fc1bSPaul Mundt 		__raw_writel(UBC_CRR_BIE | UBC_CRR_PCB, UBC_CRR(i));
1194352fc1bSPaul Mundt 
1204352fc1bSPaul Mundt 		/* dummy read for write posting */
1214352fc1bSPaul Mundt 		(void)__raw_readl(UBC_CRR(i));
1224352fc1bSPaul Mundt 	}
1234352fc1bSPaul Mundt 
1244352fc1bSPaul Mundt 	clk_disable(ubc_iclk);
1254352fc1bSPaul Mundt 
1264352fc1bSPaul Mundt 	sh4a_ubc.clk = ubc_iclk;
1274352fc1bSPaul Mundt 
1284352fc1bSPaul Mundt 	return register_sh_ubc(&sh4a_ubc);
1294352fc1bSPaul Mundt }
1304352fc1bSPaul Mundt arch_initcall(sh4a_ubc_init);
131