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