linux/arch/sh/kernel/cpu/sh4a/ubc.c
<<
>>
Prefs
   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);
 134