linux/drivers/soc/bcm/brcmstb/biuctrl.c
<<
>>
Prefs
   1/*
   2 * Broadcom STB SoCs Bus Unit Interface controls
   3 *
   4 * Copyright (C) 2015, Broadcom Corporation
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13 * GNU General Public License for more details.
  14 */
  15
  16#define pr_fmt(fmt)     "brcmstb: " KBUILD_MODNAME ": " fmt
  17
  18#include <linux/kernel.h>
  19#include <linux/io.h>
  20#include <linux/of_address.h>
  21#include <linux/syscore_ops.h>
  22#include <linux/soc/brcmstb/brcmstb.h>
  23
  24#define  CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK 0x70000000
  25#define CPU_CREDIT_REG_MCPx_READ_CRED_MASK      0xf
  26#define CPU_CREDIT_REG_MCPx_WRITE_CRED_MASK     0xf
  27#define CPU_CREDIT_REG_MCPx_READ_CRED_SHIFT(x)  ((x) * 8)
  28#define CPU_CREDIT_REG_MCPx_WRITE_CRED_SHIFT(x) (((x) * 8) + 4)
  29
  30#define CPU_MCP_FLOW_REG_MCPx_RDBUFF_CRED_SHIFT(x)      ((x) * 8)
  31#define CPU_MCP_FLOW_REG_MCPx_RDBUFF_CRED_MASK          0xff
  32
  33#define CPU_WRITEBACK_CTRL_REG_WB_THROTTLE_THRESHOLD_MASK       0xf
  34#define CPU_WRITEBACK_CTRL_REG_WB_THROTTLE_TIMEOUT_MASK         0xf
  35#define CPU_WRITEBACK_CTRL_REG_WB_THROTTLE_TIMEOUT_SHIFT        4
  36#define CPU_WRITEBACK_CTRL_REG_WB_THROTTLE_ENABLE               BIT(8)
  37
  38static void __iomem *cpubiuctrl_base;
  39static bool mcp_wr_pairing_en;
  40static const int *cpubiuctrl_regs;
  41
  42static inline u32 cbc_readl(int reg)
  43{
  44        int offset = cpubiuctrl_regs[reg];
  45
  46        if (offset == -1)
  47                return (u32)-1;
  48
  49        return readl_relaxed(cpubiuctrl_base + offset);
  50}
  51
  52static inline void cbc_writel(u32 val, int reg)
  53{
  54        int offset = cpubiuctrl_regs[reg];
  55
  56        if (offset == -1)
  57                return;
  58
  59        writel_relaxed(val,  cpubiuctrl_base + offset);
  60}
  61
  62enum cpubiuctrl_regs {
  63        CPU_CREDIT_REG = 0,
  64        CPU_MCP_FLOW_REG,
  65        CPU_WRITEBACK_CTRL_REG
  66};
  67
  68static const int b15_cpubiuctrl_regs[] = {
  69        [CPU_CREDIT_REG] = 0x184,
  70        [CPU_MCP_FLOW_REG] = -1,
  71        [CPU_WRITEBACK_CTRL_REG] = -1,
  72};
  73
  74/* Odd cases, e.g: 7260 */
  75static const int b53_cpubiuctrl_no_wb_regs[] = {
  76        [CPU_CREDIT_REG] = 0x0b0,
  77        [CPU_MCP_FLOW_REG] = 0x0b4,
  78        [CPU_WRITEBACK_CTRL_REG] = -1,
  79};
  80
  81static const int b53_cpubiuctrl_regs[] = {
  82        [CPU_CREDIT_REG] = 0x0b0,
  83        [CPU_MCP_FLOW_REG] = 0x0b4,
  84        [CPU_WRITEBACK_CTRL_REG] = 0x22c,
  85};
  86
  87#define NUM_CPU_BIUCTRL_REGS    3
  88
  89static int __init mcp_write_pairing_set(void)
  90{
  91        u32 creds = 0;
  92
  93        if (!cpubiuctrl_base)
  94                return -1;
  95
  96        creds = cbc_readl(CPU_CREDIT_REG);
  97        if (mcp_wr_pairing_en) {
  98                pr_info("MCP: Enabling write pairing\n");
  99                cbc_writel(creds | CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK,
 100                           CPU_CREDIT_REG);
 101        } else if (creds & CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK) {
 102                pr_info("MCP: Disabling write pairing\n");
 103                cbc_writel(creds & ~CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK,
 104                           CPU_CREDIT_REG);
 105        } else {
 106                pr_info("MCP: Write pairing already disabled\n");
 107        }
 108
 109        return 0;
 110}
 111
 112static const u32 b53_mach_compat[] = {
 113        0x7268,
 114        0x7271,
 115        0x7278,
 116};
 117
 118static void __init mcp_b53_set(void)
 119{
 120        unsigned int i;
 121        u32 reg;
 122
 123        reg = brcmstb_get_family_id();
 124
 125        for (i = 0; i < ARRAY_SIZE(b53_mach_compat); i++) {
 126                if (BRCM_ID(reg) == b53_mach_compat[i])
 127                        break;
 128        }
 129
 130        if (i == ARRAY_SIZE(b53_mach_compat))
 131                return;
 132
 133        /* Set all 3 MCP interfaces to 8 credits */
 134        reg = cbc_readl(CPU_CREDIT_REG);
 135        for (i = 0; i < 3; i++) {
 136                reg &= ~(CPU_CREDIT_REG_MCPx_WRITE_CRED_MASK <<
 137                         CPU_CREDIT_REG_MCPx_WRITE_CRED_SHIFT(i));
 138                reg &= ~(CPU_CREDIT_REG_MCPx_READ_CRED_MASK <<
 139                         CPU_CREDIT_REG_MCPx_READ_CRED_SHIFT(i));
 140                reg |= 8 << CPU_CREDIT_REG_MCPx_WRITE_CRED_SHIFT(i);
 141                reg |= 8 << CPU_CREDIT_REG_MCPx_READ_CRED_SHIFT(i);
 142        }
 143        cbc_writel(reg, CPU_CREDIT_REG);
 144
 145        /* Max out the number of in-flight Jwords reads on the MCP interface */
 146        reg = cbc_readl(CPU_MCP_FLOW_REG);
 147        for (i = 0; i < 3; i++)
 148                reg |= CPU_MCP_FLOW_REG_MCPx_RDBUFF_CRED_MASK <<
 149                        CPU_MCP_FLOW_REG_MCPx_RDBUFF_CRED_SHIFT(i);
 150        cbc_writel(reg, CPU_MCP_FLOW_REG);
 151
 152        /* Enable writeback throttling, set timeout to 128 cycles, 256 cycles
 153         * threshold
 154         */
 155        reg = cbc_readl(CPU_WRITEBACK_CTRL_REG);
 156        reg |= CPU_WRITEBACK_CTRL_REG_WB_THROTTLE_ENABLE;
 157        reg &= ~CPU_WRITEBACK_CTRL_REG_WB_THROTTLE_THRESHOLD_MASK;
 158        reg &= ~(CPU_WRITEBACK_CTRL_REG_WB_THROTTLE_TIMEOUT_MASK <<
 159                 CPU_WRITEBACK_CTRL_REG_WB_THROTTLE_TIMEOUT_SHIFT);
 160        reg |= 8;
 161        reg |= 7 << CPU_WRITEBACK_CTRL_REG_WB_THROTTLE_TIMEOUT_SHIFT;
 162        cbc_writel(reg, CPU_WRITEBACK_CTRL_REG);
 163}
 164
 165static int __init setup_hifcpubiuctrl_regs(struct device_node *np)
 166{
 167        struct device_node *cpu_dn;
 168        int ret = 0;
 169
 170        cpubiuctrl_base = of_iomap(np, 0);
 171        if (!cpubiuctrl_base) {
 172                pr_err("failed to remap BIU control base\n");
 173                ret = -ENOMEM;
 174                goto out;
 175        }
 176
 177        mcp_wr_pairing_en = of_property_read_bool(np, "brcm,write-pairing");
 178
 179        cpu_dn = of_get_cpu_node(0, NULL);
 180        if (!cpu_dn) {
 181                pr_err("failed to obtain CPU device node\n");
 182                ret = -ENODEV;
 183                goto out;
 184        }
 185
 186        if (of_device_is_compatible(cpu_dn, "brcm,brahma-b15"))
 187                cpubiuctrl_regs = b15_cpubiuctrl_regs;
 188        else if (of_device_is_compatible(cpu_dn, "brcm,brahma-b53"))
 189                cpubiuctrl_regs = b53_cpubiuctrl_regs;
 190        else {
 191                pr_err("unsupported CPU\n");
 192                ret = -EINVAL;
 193        }
 194        of_node_put(cpu_dn);
 195
 196        if (BRCM_ID(brcmstb_get_family_id()) == 0x7260)
 197                cpubiuctrl_regs = b53_cpubiuctrl_no_wb_regs;
 198out:
 199        of_node_put(np);
 200        return ret;
 201}
 202
 203#ifdef CONFIG_PM_SLEEP
 204static u32 cpubiuctrl_reg_save[NUM_CPU_BIUCTRL_REGS];
 205
 206static int brcmstb_cpu_credit_reg_suspend(void)
 207{
 208        unsigned int i;
 209
 210        if (!cpubiuctrl_base)
 211                return 0;
 212
 213        for (i = 0; i < NUM_CPU_BIUCTRL_REGS; i++)
 214                cpubiuctrl_reg_save[i] = cbc_readl(i);
 215
 216        return 0;
 217}
 218
 219static void brcmstb_cpu_credit_reg_resume(void)
 220{
 221        unsigned int i;
 222
 223        if (!cpubiuctrl_base)
 224                return;
 225
 226        for (i = 0; i < NUM_CPU_BIUCTRL_REGS; i++)
 227                cbc_writel(cpubiuctrl_reg_save[i], i);
 228}
 229
 230static struct syscore_ops brcmstb_cpu_credit_syscore_ops = {
 231        .suspend = brcmstb_cpu_credit_reg_suspend,
 232        .resume = brcmstb_cpu_credit_reg_resume,
 233};
 234#endif
 235
 236
 237static int __init brcmstb_biuctrl_init(void)
 238{
 239        struct device_node *np;
 240        int ret;
 241
 242        /* We might be running on a multi-platform kernel, don't make this a
 243         * fatal error, just bail out early
 244         */
 245        np = of_find_compatible_node(NULL, NULL, "brcm,brcmstb-cpu-biu-ctrl");
 246        if (!np)
 247                return 0;
 248
 249        setup_hifcpubiuctrl_regs(np);
 250
 251        ret = mcp_write_pairing_set();
 252        if (ret) {
 253                pr_err("MCP: Unable to disable write pairing!\n");
 254                return ret;
 255        }
 256
 257        mcp_b53_set();
 258#ifdef CONFIG_PM_SLEEP
 259        register_syscore_ops(&brcmstb_cpu_credit_syscore_ops);
 260#endif
 261        return 0;
 262}
 263early_initcall(brcmstb_biuctrl_init);
 264