Loading...
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
33static struct sh_ubc sh4a_ubc;
34
35static 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
41static 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
47static 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
57static 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
66static 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
78static unsigned long sh4a_ubc_triggered_mask(void)
79{
80 return __raw_readl(UBC_CCMFR);
81}
82
83static void sh4a_ubc_clear_triggered_mask(unsigned long mask)
84{
85 __raw_writel(__raw_readl(UBC_CCMFR) & ~mask, UBC_CCMFR);
86}
87
88static 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
101static 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}
133arch_initcall(sh4a_ubc_init);
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
30static struct sh_ubc sh4a_ubc;
31
32static 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
38static 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
44static 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
54static 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
63static 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
75static unsigned long sh4a_ubc_triggered_mask(void)
76{
77 return __raw_readl(UBC_CCMFR);
78}
79
80static void sh4a_ubc_clear_triggered_mask(unsigned long mask)
81{
82 __raw_writel(__raw_readl(UBC_CCMFR) & ~mask, UBC_CCMFR);
83}
84
85static 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
98static 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}
130arch_initcall(sh4a_ubc_init);