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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.