1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. 4 */ 5 6 #include <linux/of_device.h> 7 #include <linux/slab.h> 8 #include <linux/string.h> 9 10 #include <dt-bindings/memory/tegra20-mc.h> 11 12 #include "mc.h" 13 14 static const struct tegra_mc_client tegra20_mc_clients[] = { 15 { 16 .id = 0x00, 17 .name = "display0a", 18 }, { 19 .id = 0x01, 20 .name = "display0ab", 21 }, { 22 .id = 0x02, 23 .name = "display0b", 24 }, { 25 .id = 0x03, 26 .name = "display0bb", 27 }, { 28 .id = 0x04, 29 .name = "display0c", 30 }, { 31 .id = 0x05, 32 .name = "display0cb", 33 }, { 34 .id = 0x06, 35 .name = "display1b", 36 }, { 37 .id = 0x07, 38 .name = "display1bb", 39 }, { 40 .id = 0x08, 41 .name = "eppup", 42 }, { 43 .id = 0x09, 44 .name = "g2pr", 45 }, { 46 .id = 0x0a, 47 .name = "g2sr", 48 }, { 49 .id = 0x0b, 50 .name = "mpeunifbr", 51 }, { 52 .id = 0x0c, 53 .name = "viruv", 54 }, { 55 .id = 0x0d, 56 .name = "avpcarm7r", 57 }, { 58 .id = 0x0e, 59 .name = "displayhc", 60 }, { 61 .id = 0x0f, 62 .name = "displayhcb", 63 }, { 64 .id = 0x10, 65 .name = "fdcdrd", 66 }, { 67 .id = 0x11, 68 .name = "g2dr", 69 }, { 70 .id = 0x12, 71 .name = "host1xdmar", 72 }, { 73 .id = 0x13, 74 .name = "host1xr", 75 }, { 76 .id = 0x14, 77 .name = "idxsrd", 78 }, { 79 .id = 0x15, 80 .name = "mpcorer", 81 }, { 82 .id = 0x16, 83 .name = "mpe_ipred", 84 }, { 85 .id = 0x17, 86 .name = "mpeamemrd", 87 }, { 88 .id = 0x18, 89 .name = "mpecsrd", 90 }, { 91 .id = 0x19, 92 .name = "ppcsahbdmar", 93 }, { 94 .id = 0x1a, 95 .name = "ppcsahbslvr", 96 }, { 97 .id = 0x1b, 98 .name = "texsrd", 99 }, { 100 .id = 0x1c, 101 .name = "vdebsevr", 102 }, { 103 .id = 0x1d, 104 .name = "vdember", 105 }, { 106 .id = 0x1e, 107 .name = "vdemcer", 108 }, { 109 .id = 0x1f, 110 .name = "vdetper", 111 }, { 112 .id = 0x20, 113 .name = "eppu", 114 }, { 115 .id = 0x21, 116 .name = "eppv", 117 }, { 118 .id = 0x22, 119 .name = "eppy", 120 }, { 121 .id = 0x23, 122 .name = "mpeunifbw", 123 }, { 124 .id = 0x24, 125 .name = "viwsb", 126 }, { 127 .id = 0x25, 128 .name = "viwu", 129 }, { 130 .id = 0x26, 131 .name = "viwv", 132 }, { 133 .id = 0x27, 134 .name = "viwy", 135 }, { 136 .id = 0x28, 137 .name = "g2dw", 138 }, { 139 .id = 0x29, 140 .name = "avpcarm7w", 141 }, { 142 .id = 0x2a, 143 .name = "fdcdwr", 144 }, { 145 .id = 0x2b, 146 .name = "host1xw", 147 }, { 148 .id = 0x2c, 149 .name = "ispw", 150 }, { 151 .id = 0x2d, 152 .name = "mpcorew", 153 }, { 154 .id = 0x2e, 155 .name = "mpecswr", 156 }, { 157 .id = 0x2f, 158 .name = "ppcsahbdmaw", 159 }, { 160 .id = 0x30, 161 .name = "ppcsahbslvw", 162 }, { 163 .id = 0x31, 164 .name = "vdebsevw", 165 }, { 166 .id = 0x32, 167 .name = "vdembew", 168 }, { 169 .id = 0x33, 170 .name = "vdetpmw", 171 }, 172 }; 173 174 #define TEGRA20_MC_RESET(_name, _control, _status, _reset, _bit) \ 175 { \ 176 .name = #_name, \ 177 .id = TEGRA20_MC_RESET_##_name, \ 178 .control = _control, \ 179 .status = _status, \ 180 .reset = _reset, \ 181 .bit = _bit, \ 182 } 183 184 static const struct tegra_mc_reset tegra20_mc_resets[] = { 185 TEGRA20_MC_RESET(AVPC, 0x100, 0x140, 0x104, 0), 186 TEGRA20_MC_RESET(DC, 0x100, 0x144, 0x104, 1), 187 TEGRA20_MC_RESET(DCB, 0x100, 0x148, 0x104, 2), 188 TEGRA20_MC_RESET(EPP, 0x100, 0x14c, 0x104, 3), 189 TEGRA20_MC_RESET(2D, 0x100, 0x150, 0x104, 4), 190 TEGRA20_MC_RESET(HC, 0x100, 0x154, 0x104, 5), 191 TEGRA20_MC_RESET(ISP, 0x100, 0x158, 0x104, 6), 192 TEGRA20_MC_RESET(MPCORE, 0x100, 0x15c, 0x104, 7), 193 TEGRA20_MC_RESET(MPEA, 0x100, 0x160, 0x104, 8), 194 TEGRA20_MC_RESET(MPEB, 0x100, 0x164, 0x104, 9), 195 TEGRA20_MC_RESET(MPEC, 0x100, 0x168, 0x104, 10), 196 TEGRA20_MC_RESET(3D, 0x100, 0x16c, 0x104, 11), 197 TEGRA20_MC_RESET(PPCS, 0x100, 0x170, 0x104, 12), 198 TEGRA20_MC_RESET(VDE, 0x100, 0x174, 0x104, 13), 199 TEGRA20_MC_RESET(VI, 0x100, 0x178, 0x104, 14), 200 }; 201 202 static int tegra20_mc_hotreset_assert(struct tegra_mc *mc, 203 const struct tegra_mc_reset *rst) 204 { 205 unsigned long flags; 206 u32 value; 207 208 spin_lock_irqsave(&mc->lock, flags); 209 210 value = mc_readl(mc, rst->reset); 211 mc_writel(mc, value & ~BIT(rst->bit), rst->reset); 212 213 spin_unlock_irqrestore(&mc->lock, flags); 214 215 return 0; 216 } 217 218 static int tegra20_mc_hotreset_deassert(struct tegra_mc *mc, 219 const struct tegra_mc_reset *rst) 220 { 221 unsigned long flags; 222 u32 value; 223 224 spin_lock_irqsave(&mc->lock, flags); 225 226 value = mc_readl(mc, rst->reset); 227 mc_writel(mc, value | BIT(rst->bit), rst->reset); 228 229 spin_unlock_irqrestore(&mc->lock, flags); 230 231 return 0; 232 } 233 234 static int tegra20_mc_block_dma(struct tegra_mc *mc, 235 const struct tegra_mc_reset *rst) 236 { 237 unsigned long flags; 238 u32 value; 239 240 spin_lock_irqsave(&mc->lock, flags); 241 242 value = mc_readl(mc, rst->control) & ~BIT(rst->bit); 243 mc_writel(mc, value, rst->control); 244 245 spin_unlock_irqrestore(&mc->lock, flags); 246 247 return 0; 248 } 249 250 static bool tegra20_mc_dma_idling(struct tegra_mc *mc, 251 const struct tegra_mc_reset *rst) 252 { 253 return mc_readl(mc, rst->status) == 0; 254 } 255 256 static int tegra20_mc_reset_status(struct tegra_mc *mc, 257 const struct tegra_mc_reset *rst) 258 { 259 return (mc_readl(mc, rst->reset) & BIT(rst->bit)) == 0; 260 } 261 262 static int tegra20_mc_unblock_dma(struct tegra_mc *mc, 263 const struct tegra_mc_reset *rst) 264 { 265 unsigned long flags; 266 u32 value; 267 268 spin_lock_irqsave(&mc->lock, flags); 269 270 value = mc_readl(mc, rst->control) | BIT(rst->bit); 271 mc_writel(mc, value, rst->control); 272 273 spin_unlock_irqrestore(&mc->lock, flags); 274 275 return 0; 276 } 277 278 static const struct tegra_mc_reset_ops tegra20_mc_reset_ops = { 279 .hotreset_assert = tegra20_mc_hotreset_assert, 280 .hotreset_deassert = tegra20_mc_hotreset_deassert, 281 .block_dma = tegra20_mc_block_dma, 282 .dma_idling = tegra20_mc_dma_idling, 283 .unblock_dma = tegra20_mc_unblock_dma, 284 .reset_status = tegra20_mc_reset_status, 285 }; 286 287 static int tegra20_mc_icc_set(struct icc_node *src, struct icc_node *dst) 288 { 289 /* 290 * It should be possible to tune arbitration knobs here, but the 291 * default values are known to work well on all devices. Hence 292 * nothing to do here so far. 293 */ 294 return 0; 295 } 296 297 static int tegra20_mc_icc_aggreate(struct icc_node *node, u32 tag, u32 avg_bw, 298 u32 peak_bw, u32 *agg_avg, u32 *agg_peak) 299 { 300 /* 301 * ISO clients need to reserve extra bandwidth up-front because 302 * there could be high bandwidth pressure during initial filling 303 * of the client's FIFO buffers. Secondly, we need to take into 304 * account impurities of the memory subsystem. 305 */ 306 if (tag & TEGRA_MC_ICC_TAG_ISO) 307 peak_bw = tegra_mc_scale_percents(peak_bw, 300); 308 309 *agg_avg += avg_bw; 310 *agg_peak = max(*agg_peak, peak_bw); 311 312 return 0; 313 } 314 315 static struct icc_node_data * 316 tegra20_mc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data) 317 { 318 struct tegra_mc *mc = icc_provider_to_tegra_mc(data); 319 unsigned int i, idx = spec->args[0]; 320 struct icc_node_data *ndata; 321 struct icc_node *node; 322 323 list_for_each_entry(node, &mc->provider.nodes, node_list) { 324 if (node->id != idx) 325 continue; 326 327 ndata = kzalloc(sizeof(*ndata), GFP_KERNEL); 328 if (!ndata) 329 return ERR_PTR(-ENOMEM); 330 331 ndata->node = node; 332 333 /* these clients are isochronous by default */ 334 if (strstarts(node->name, "display") || 335 strstarts(node->name, "vi")) 336 ndata->tag = TEGRA_MC_ICC_TAG_ISO; 337 else 338 ndata->tag = TEGRA_MC_ICC_TAG_DEFAULT; 339 340 return ndata; 341 } 342 343 for (i = 0; i < mc->soc->num_clients; i++) { 344 if (mc->soc->clients[i].id == idx) 345 return ERR_PTR(-EPROBE_DEFER); 346 } 347 348 dev_err(mc->dev, "invalid ICC client ID %u\n", idx); 349 350 return ERR_PTR(-EINVAL); 351 } 352 353 static const struct tegra_mc_icc_ops tegra20_mc_icc_ops = { 354 .xlate_extended = tegra20_mc_of_icc_xlate_extended, 355 .aggregate = tegra20_mc_icc_aggreate, 356 .set = tegra20_mc_icc_set, 357 }; 358 359 const struct tegra_mc_soc tegra20_mc_soc = { 360 .clients = tegra20_mc_clients, 361 .num_clients = ARRAY_SIZE(tegra20_mc_clients), 362 .num_address_bits = 32, 363 .client_id_mask = 0x3f, 364 .intmask = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE | 365 MC_INT_DECERR_EMEM, 366 .reset_ops = &tegra20_mc_reset_ops, 367 .resets = tegra20_mc_resets, 368 .num_resets = ARRAY_SIZE(tegra20_mc_resets), 369 .icc_ops = &tegra20_mc_icc_ops, 370 }; 371