diff options
Diffstat (limited to 'arch/sh/kernel/cpu/sh4a/ubc.c')
-rw-r--r-- | arch/sh/kernel/cpu/sh4a/ubc.c | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/arch/sh/kernel/cpu/sh4a/ubc.c b/arch/sh/kernel/cpu/sh4a/ubc.c new file mode 100644 index 000000000000..efb2745bcb36 --- /dev/null +++ b/arch/sh/kernel/cpu/sh4a/ubc.c | |||
@@ -0,0 +1,133 @@ | |||
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); | ||