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