-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
sh: Abstracted SH-4A UBC support on hw-breakpoint core.
This is the next big chunk of hw_breakpoint support. This decouples the SH-4A support from the core and moves it out in to its own stub, following many of the conventions established with the perf events layering. In addition to extending SH-4A support to encapsulate the remainder of the UBC channels, clock framework support for handling the UBC interface clock is added as well, allowing for dynamic clock gating. This also fixes up a regression introduced by the SIGTRAP handling that broke the ksym_tracer, to the extent that the current support works well with all of the ksym_tracer/ptrace/kgdb. The kprobes singlestep code will follow in turn. With this in place, the remaining UBC variants (SH-2A and SH-4) can now be trivially plugged in. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
- Loading branch information
Paul Mundt
committed
Jan 5, 2010
1 parent
c476181
commit 4352fc1
Showing
5 changed files
with
254 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
/* | ||
* arch/sh/kernel/cpu/sh4a/ubc.c | ||
* | ||
* On-chip UBC support for SH-4A CPUs. | ||
* | ||
* Copyright (C) 2009 - 2010 Paul Mundt | ||
* | ||
* This file is subject to the terms and conditions of the GNU General Public | ||
* License. See the file "COPYING" in the main directory of this archive | ||
* for more details. | ||
*/ | ||
#include <linux/init.h> | ||
#include <linux/err.h> | ||
#include <linux/clk.h> | ||
#include <linux/io.h> | ||
#include <asm/hw_breakpoint.h> | ||
|
||
#define UBC_CBR(idx) (0xff200000 + (0x20 * idx)) | ||
#define UBC_CRR(idx) (0xff200004 + (0x20 * idx)) | ||
#define UBC_CAR(idx) (0xff200008 + (0x20 * idx)) | ||
#define UBC_CAMR(idx) (0xff20000c + (0x20 * idx)) | ||
|
||
#define UBC_CCMFR 0xff200600 | ||
#define UBC_CBCR 0xff200620 | ||
|
||
/* CRR */ | ||
#define UBC_CRR_PCB (1 << 1) | ||
#define UBC_CRR_BIE (1 << 0) | ||
|
||
/* CBR */ | ||
#define UBC_CBR_CE (1 << 0) | ||
|
||
static struct sh_ubc sh4a_ubc; | ||
|
||
static void sh4a_ubc_enable(struct arch_hw_breakpoint *info, int idx) | ||
{ | ||
__raw_writel(UBC_CBR_CE | info->len | info->type, UBC_CBR(idx)); | ||
__raw_writel(info->address, UBC_CAR(idx)); | ||
} | ||
|
||
static void sh4a_ubc_disable(struct arch_hw_breakpoint *info, int idx) | ||
{ | ||
__raw_writel(0, UBC_CBR(idx)); | ||
__raw_writel(0, UBC_CAR(idx)); | ||
} | ||
|
||
static void sh4a_ubc_enable_all(unsigned long mask) | ||
{ | ||
int i; | ||
|
||
for (i = 0; i < sh4a_ubc.num_events; i++) | ||
if (mask & (1 << i)) | ||
__raw_writel(__raw_readl(UBC_CBR(i)) | UBC_CBR_CE, | ||
UBC_CBR(i)); | ||
} | ||
|
||
static void sh4a_ubc_disable_all(void) | ||
{ | ||
int i; | ||
|
||
for (i = 0; i < sh4a_ubc.num_events; i++) | ||
__raw_writel(__raw_readl(UBC_CBR(i)) & ~UBC_CBR_CE, | ||
UBC_CBR(i)); | ||
} | ||
|
||
static unsigned long sh4a_ubc_active_mask(void) | ||
{ | ||
unsigned long active = 0; | ||
int i; | ||
|
||
for (i = 0; i < sh4a_ubc.num_events; i++) | ||
if (__raw_readl(UBC_CBR(i)) & UBC_CBR_CE) | ||
active |= (1 << i); | ||
|
||
return active; | ||
} | ||
|
||
static unsigned long sh4a_ubc_triggered_mask(void) | ||
{ | ||
return __raw_readl(UBC_CCMFR); | ||
} | ||
|
||
static void sh4a_ubc_clear_triggered_mask(unsigned long mask) | ||
{ | ||
__raw_writel(__raw_readl(UBC_CCMFR) & ~mask, UBC_CCMFR); | ||
} | ||
|
||
static struct sh_ubc sh4a_ubc = { | ||
.name = "SH-4A", | ||
.num_events = 2, | ||
.trap_nr = 0x1e0, | ||
.enable = sh4a_ubc_enable, | ||
.disable = sh4a_ubc_disable, | ||
.enable_all = sh4a_ubc_enable_all, | ||
.disable_all = sh4a_ubc_disable_all, | ||
.active_mask = sh4a_ubc_active_mask, | ||
.triggered_mask = sh4a_ubc_triggered_mask, | ||
.clear_triggered_mask = sh4a_ubc_clear_triggered_mask, | ||
}; | ||
|
||
static int __init sh4a_ubc_init(void) | ||
{ | ||
struct clk *ubc_iclk = clk_get(NULL, "ubc0"); | ||
int i; | ||
|
||
/* | ||
* The UBC MSTP bit is optional, as not all platforms will have | ||
* it. Just ignore it if we can't find it. | ||
*/ | ||
if (IS_ERR(ubc_iclk)) | ||
ubc_iclk = NULL; | ||
|
||
clk_enable(ubc_iclk); | ||
|
||
__raw_writel(0, UBC_CBCR); | ||
|
||
for (i = 0; i < sh4a_ubc.num_events; i++) { | ||
__raw_writel(0, UBC_CAMR(i)); | ||
__raw_writel(0, UBC_CBR(i)); | ||
|
||
__raw_writel(UBC_CRR_BIE | UBC_CRR_PCB, UBC_CRR(i)); | ||
|
||
/* dummy read for write posting */ | ||
(void)__raw_readl(UBC_CRR(i)); | ||
} | ||
|
||
clk_disable(ubc_iclk); | ||
|
||
sh4a_ubc.clk = ubc_iclk; | ||
|
||
return register_sh_ubc(&sh4a_ubc); | ||
} | ||
arch_initcall(sh4a_ubc_init); |
Oops, something went wrong.