Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/sh/kernel/cpu/sh4a/ubc.c
26498 views
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
132