xref: /openbmc/linux/arch/sh/kernel/cpu/sh4a/ubc.c (revision cce8e04c)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * arch/sh/kernel/cpu/sh4a/ubc.c
4  *
5  * On-chip UBC support for SH-4A CPUs.
6  *
7  * Copyright (C) 2009 - 2010  Paul Mundt
8  */
9 #include <linux/init.h>
10 #include <linux/err.h>
11 #include <linux/clk.h>
12 #include <linux/io.h>
13 #include <asm/hw_breakpoint.h>
14 
15 #define UBC_CBR(idx)	(0xff200000 + (0x20 * idx))
16 #define UBC_CRR(idx)	(0xff200004 + (0x20 * idx))
17 #define UBC_CAR(idx)	(0xff200008 + (0x20 * idx))
18 #define UBC_CAMR(idx)	(0xff20000c + (0x20 * idx))
19 
20 #define UBC_CCMFR	0xff200600
21 #define UBC_CBCR	0xff200620
22 
23 /* CRR */
24 #define UBC_CRR_PCB	(1 << 1)
25 #define UBC_CRR_BIE	(1 << 0)
26 
27 /* CBR */
28 #define UBC_CBR_CE	(1 << 0)
29 
30 static struct sh_ubc sh4a_ubc;
31 
32 static void sh4a_ubc_enable(struct arch_hw_breakpoint *info, int idx)
33 {
34 	__raw_writel(UBC_CBR_CE | info->len | info->type, UBC_CBR(idx));
35 	__raw_writel(info->address, UBC_CAR(idx));
36 }
37 
38 static void sh4a_ubc_disable(struct arch_hw_breakpoint *info, int idx)
39 {
40 	__raw_writel(0, UBC_CBR(idx));
41 	__raw_writel(0, UBC_CAR(idx));
42 }
43 
44 static void sh4a_ubc_enable_all(unsigned long mask)
45 {
46 	int i;
47 
48 	for (i = 0; i < sh4a_ubc.num_events; i++)
49 		if (mask & (1 << i))
50 			__raw_writel(__raw_readl(UBC_CBR(i)) | UBC_CBR_CE,
51 				     UBC_CBR(i));
52 }
53 
54 static void sh4a_ubc_disable_all(void)
55 {
56 	int i;
57 
58 	for (i = 0; i < sh4a_ubc.num_events; i++)
59 		__raw_writel(__raw_readl(UBC_CBR(i)) & ~UBC_CBR_CE,
60 			     UBC_CBR(i));
61 }
62 
63 static unsigned long sh4a_ubc_active_mask(void)
64 {
65 	unsigned long active = 0;
66 	int i;
67 
68 	for (i = 0; i < sh4a_ubc.num_events; i++)
69 		if (__raw_readl(UBC_CBR(i)) & UBC_CBR_CE)
70 			active |= (1 << i);
71 
72 	return active;
73 }
74 
75 static unsigned long sh4a_ubc_triggered_mask(void)
76 {
77 	return __raw_readl(UBC_CCMFR);
78 }
79 
80 static void sh4a_ubc_clear_triggered_mask(unsigned long mask)
81 {
82 	__raw_writel(__raw_readl(UBC_CCMFR) & ~mask, UBC_CCMFR);
83 }
84 
85 static struct sh_ubc sh4a_ubc = {
86 	.name			= "SH-4A",
87 	.num_events		= 2,
88 	.trap_nr		= 0x1e0,
89 	.enable			= sh4a_ubc_enable,
90 	.disable		= sh4a_ubc_disable,
91 	.enable_all		= sh4a_ubc_enable_all,
92 	.disable_all		= sh4a_ubc_disable_all,
93 	.active_mask		= sh4a_ubc_active_mask,
94 	.triggered_mask		= sh4a_ubc_triggered_mask,
95 	.clear_triggered_mask	= sh4a_ubc_clear_triggered_mask,
96 };
97 
98 static int __init sh4a_ubc_init(void)
99 {
100 	struct clk *ubc_iclk = clk_get(NULL, "ubc0");
101 	int i;
102 
103 	/*
104 	 * The UBC MSTP bit is optional, as not all platforms will have
105 	 * it. Just ignore it if we can't find it.
106 	 */
107 	if (IS_ERR(ubc_iclk))
108 		ubc_iclk = NULL;
109 
110 	clk_enable(ubc_iclk);
111 
112 	__raw_writel(0, UBC_CBCR);
113 
114 	for (i = 0; i < sh4a_ubc.num_events; i++) {
115 		__raw_writel(0, UBC_CAMR(i));
116 		__raw_writel(0, UBC_CBR(i));
117 
118 		__raw_writel(UBC_CRR_BIE | UBC_CRR_PCB, UBC_CRR(i));
119 
120 		/* dummy read for write posting */
121 		(void)__raw_readl(UBC_CRR(i));
122 	}
123 
124 	clk_disable(ubc_iclk);
125 
126 	sh4a_ubc.clk = ubc_iclk;
127 
128 	return register_sh_ubc(&sh4a_ubc);
129 }
130 arch_initcall(sh4a_ubc_init);
131