1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2a8d502fdSDmitry Osipenko /* 3a8d502fdSDmitry Osipenko * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. 4a8d502fdSDmitry Osipenko */ 5a8d502fdSDmitry Osipenko 6fbd31f5aSDmitry Osipenko #include <linux/bitfield.h> 7fbd31f5aSDmitry Osipenko #include <linux/delay.h> 828947198SDmitry Osipenko #include <linux/mutex.h> 9d5ef16baSDmitry Osipenko #include <linux/of_device.h> 10d5ef16baSDmitry Osipenko #include <linux/slab.h> 11d5ef16baSDmitry Osipenko #include <linux/string.h> 12d5ef16baSDmitry Osipenko 13cb557757SDmitry Osipenko #include <dt-bindings/memory/tegra20-mc.h> 14cb557757SDmitry Osipenko 15a8d502fdSDmitry Osipenko #include "mc.h" 16a8d502fdSDmitry Osipenko 17fbd31f5aSDmitry Osipenko #define MC_STAT_CONTROL 0x90 18fbd31f5aSDmitry Osipenko #define MC_STAT_EMC_CLOCK_LIMIT 0xa0 19fbd31f5aSDmitry Osipenko #define MC_STAT_EMC_CLOCKS 0xa4 20fbd31f5aSDmitry Osipenko #define MC_STAT_EMC_CONTROL_0 0xa8 21fbd31f5aSDmitry Osipenko #define MC_STAT_EMC_CONTROL_1 0xac 22fbd31f5aSDmitry Osipenko #define MC_STAT_EMC_COUNT_0 0xb8 23fbd31f5aSDmitry Osipenko #define MC_STAT_EMC_COUNT_1 0xbc 24fbd31f5aSDmitry Osipenko 25fbd31f5aSDmitry Osipenko #define MC_STAT_CONTROL_CLIENT_ID GENMASK(13, 8) 26fbd31f5aSDmitry Osipenko #define MC_STAT_CONTROL_EVENT GENMASK(23, 16) 27fbd31f5aSDmitry Osipenko #define MC_STAT_CONTROL_PRI_EVENT GENMASK(25, 24) 28fbd31f5aSDmitry Osipenko #define MC_STAT_CONTROL_FILTER_CLIENT_ENABLE GENMASK(26, 26) 29fbd31f5aSDmitry Osipenko #define MC_STAT_CONTROL_FILTER_PRI GENMASK(29, 28) 30fbd31f5aSDmitry Osipenko 31fbd31f5aSDmitry Osipenko #define MC_STAT_CONTROL_PRI_EVENT_HP 0 32fbd31f5aSDmitry Osipenko #define MC_STAT_CONTROL_PRI_EVENT_TM 1 33fbd31f5aSDmitry Osipenko #define MC_STAT_CONTROL_PRI_EVENT_BW 2 34fbd31f5aSDmitry Osipenko 35fbd31f5aSDmitry Osipenko #define MC_STAT_CONTROL_FILTER_PRI_DISABLE 0 36fbd31f5aSDmitry Osipenko #define MC_STAT_CONTROL_FILTER_PRI_NO 1 37fbd31f5aSDmitry Osipenko #define MC_STAT_CONTROL_FILTER_PRI_YES 2 38fbd31f5aSDmitry Osipenko 39fbd31f5aSDmitry Osipenko #define MC_STAT_CONTROL_EVENT_QUALIFIED 0 40fbd31f5aSDmitry Osipenko #define MC_STAT_CONTROL_EVENT_ANY_READ 1 41fbd31f5aSDmitry Osipenko #define MC_STAT_CONTROL_EVENT_ANY_WRITE 2 42fbd31f5aSDmitry Osipenko #define MC_STAT_CONTROL_EVENT_RD_WR_CHANGE 3 43fbd31f5aSDmitry Osipenko #define MC_STAT_CONTROL_EVENT_SUCCESSIVE 4 44fbd31f5aSDmitry Osipenko #define MC_STAT_CONTROL_EVENT_ARB_BANK_AA 5 45fbd31f5aSDmitry Osipenko #define MC_STAT_CONTROL_EVENT_ARB_BANK_BB 6 46fbd31f5aSDmitry Osipenko #define MC_STAT_CONTROL_EVENT_PAGE_MISS 7 47fbd31f5aSDmitry Osipenko #define MC_STAT_CONTROL_EVENT_AUTO_PRECHARGE 8 48fbd31f5aSDmitry Osipenko 49fbd31f5aSDmitry Osipenko #define EMC_GATHER_RST (0 << 8) 50fbd31f5aSDmitry Osipenko #define EMC_GATHER_CLEAR (1 << 8) 51fbd31f5aSDmitry Osipenko #define EMC_GATHER_DISABLE (2 << 8) 52fbd31f5aSDmitry Osipenko #define EMC_GATHER_ENABLE (3 << 8) 53fbd31f5aSDmitry Osipenko 54fbd31f5aSDmitry Osipenko #define MC_STAT_SAMPLE_TIME_USEC 16000 55fbd31f5aSDmitry Osipenko 56fbd31f5aSDmitry Osipenko /* we store collected statistics as a fixed point values */ 57fbd31f5aSDmitry Osipenko #define MC_FX_FRAC_SCALE 100 58fbd31f5aSDmitry Osipenko 5928947198SDmitry Osipenko static DEFINE_MUTEX(tegra20_mc_stat_lock); 6028947198SDmitry Osipenko 61fbd31f5aSDmitry Osipenko struct tegra20_mc_stat_gather { 62fbd31f5aSDmitry Osipenko unsigned int pri_filter; 63fbd31f5aSDmitry Osipenko unsigned int pri_event; 64fbd31f5aSDmitry Osipenko unsigned int result; 65fbd31f5aSDmitry Osipenko unsigned int client; 66fbd31f5aSDmitry Osipenko unsigned int event; 67fbd31f5aSDmitry Osipenko bool client_enb; 68fbd31f5aSDmitry Osipenko }; 69fbd31f5aSDmitry Osipenko 70fbd31f5aSDmitry Osipenko struct tegra20_mc_stat { 71fbd31f5aSDmitry Osipenko struct tegra20_mc_stat_gather gather0; 72fbd31f5aSDmitry Osipenko struct tegra20_mc_stat_gather gather1; 73fbd31f5aSDmitry Osipenko unsigned int sample_time_usec; 74fbd31f5aSDmitry Osipenko const struct tegra_mc *mc; 75fbd31f5aSDmitry Osipenko }; 76fbd31f5aSDmitry Osipenko 77fbd31f5aSDmitry Osipenko struct tegra20_mc_client_stat { 78fbd31f5aSDmitry Osipenko unsigned int events; 79fbd31f5aSDmitry Osipenko unsigned int arb_high_prio; 80fbd31f5aSDmitry Osipenko unsigned int arb_timeout; 81fbd31f5aSDmitry Osipenko unsigned int arb_bandwidth; 82fbd31f5aSDmitry Osipenko unsigned int rd_wr_change; 83fbd31f5aSDmitry Osipenko unsigned int successive; 84fbd31f5aSDmitry Osipenko unsigned int page_miss; 85fbd31f5aSDmitry Osipenko unsigned int auto_precharge; 86fbd31f5aSDmitry Osipenko unsigned int arb_bank_aa; 87fbd31f5aSDmitry Osipenko unsigned int arb_bank_bb; 88fbd31f5aSDmitry Osipenko }; 89fbd31f5aSDmitry Osipenko 90a8d502fdSDmitry Osipenko static const struct tegra_mc_client tegra20_mc_clients[] = { 91a8d502fdSDmitry Osipenko { 92a8d502fdSDmitry Osipenko .id = 0x00, 93a8d502fdSDmitry Osipenko .name = "display0a", 94a8d502fdSDmitry Osipenko }, { 95a8d502fdSDmitry Osipenko .id = 0x01, 96a8d502fdSDmitry Osipenko .name = "display0ab", 97a8d502fdSDmitry Osipenko }, { 98a8d502fdSDmitry Osipenko .id = 0x02, 99a8d502fdSDmitry Osipenko .name = "display0b", 100a8d502fdSDmitry Osipenko }, { 101a8d502fdSDmitry Osipenko .id = 0x03, 102a8d502fdSDmitry Osipenko .name = "display0bb", 103a8d502fdSDmitry Osipenko }, { 104a8d502fdSDmitry Osipenko .id = 0x04, 105a8d502fdSDmitry Osipenko .name = "display0c", 106a8d502fdSDmitry Osipenko }, { 107a8d502fdSDmitry Osipenko .id = 0x05, 108a8d502fdSDmitry Osipenko .name = "display0cb", 109a8d502fdSDmitry Osipenko }, { 110a8d502fdSDmitry Osipenko .id = 0x06, 111a8d502fdSDmitry Osipenko .name = "display1b", 112a8d502fdSDmitry Osipenko }, { 113a8d502fdSDmitry Osipenko .id = 0x07, 114a8d502fdSDmitry Osipenko .name = "display1bb", 115a8d502fdSDmitry Osipenko }, { 116a8d502fdSDmitry Osipenko .id = 0x08, 117a8d502fdSDmitry Osipenko .name = "eppup", 118a8d502fdSDmitry Osipenko }, { 119a8d502fdSDmitry Osipenko .id = 0x09, 120a8d502fdSDmitry Osipenko .name = "g2pr", 121a8d502fdSDmitry Osipenko }, { 122a8d502fdSDmitry Osipenko .id = 0x0a, 123a8d502fdSDmitry Osipenko .name = "g2sr", 124a8d502fdSDmitry Osipenko }, { 125a8d502fdSDmitry Osipenko .id = 0x0b, 126a8d502fdSDmitry Osipenko .name = "mpeunifbr", 127a8d502fdSDmitry Osipenko }, { 128a8d502fdSDmitry Osipenko .id = 0x0c, 129a8d502fdSDmitry Osipenko .name = "viruv", 130a8d502fdSDmitry Osipenko }, { 131a8d502fdSDmitry Osipenko .id = 0x0d, 132a8d502fdSDmitry Osipenko .name = "avpcarm7r", 133a8d502fdSDmitry Osipenko }, { 134a8d502fdSDmitry Osipenko .id = 0x0e, 135a8d502fdSDmitry Osipenko .name = "displayhc", 136a8d502fdSDmitry Osipenko }, { 137a8d502fdSDmitry Osipenko .id = 0x0f, 138a8d502fdSDmitry Osipenko .name = "displayhcb", 139a8d502fdSDmitry Osipenko }, { 140a8d502fdSDmitry Osipenko .id = 0x10, 141a8d502fdSDmitry Osipenko .name = "fdcdrd", 142a8d502fdSDmitry Osipenko }, { 143a8d502fdSDmitry Osipenko .id = 0x11, 144a8d502fdSDmitry Osipenko .name = "g2dr", 145a8d502fdSDmitry Osipenko }, { 146a8d502fdSDmitry Osipenko .id = 0x12, 147a8d502fdSDmitry Osipenko .name = "host1xdmar", 148a8d502fdSDmitry Osipenko }, { 149a8d502fdSDmitry Osipenko .id = 0x13, 150a8d502fdSDmitry Osipenko .name = "host1xr", 151a8d502fdSDmitry Osipenko }, { 152a8d502fdSDmitry Osipenko .id = 0x14, 153a8d502fdSDmitry Osipenko .name = "idxsrd", 154a8d502fdSDmitry Osipenko }, { 155a8d502fdSDmitry Osipenko .id = 0x15, 156a8d502fdSDmitry Osipenko .name = "mpcorer", 157a8d502fdSDmitry Osipenko }, { 158a8d502fdSDmitry Osipenko .id = 0x16, 159a8d502fdSDmitry Osipenko .name = "mpe_ipred", 160a8d502fdSDmitry Osipenko }, { 161a8d502fdSDmitry Osipenko .id = 0x17, 162a8d502fdSDmitry Osipenko .name = "mpeamemrd", 163a8d502fdSDmitry Osipenko }, { 164a8d502fdSDmitry Osipenko .id = 0x18, 165a8d502fdSDmitry Osipenko .name = "mpecsrd", 166a8d502fdSDmitry Osipenko }, { 167a8d502fdSDmitry Osipenko .id = 0x19, 168a8d502fdSDmitry Osipenko .name = "ppcsahbdmar", 169a8d502fdSDmitry Osipenko }, { 170a8d502fdSDmitry Osipenko .id = 0x1a, 171a8d502fdSDmitry Osipenko .name = "ppcsahbslvr", 172a8d502fdSDmitry Osipenko }, { 173a8d502fdSDmitry Osipenko .id = 0x1b, 174a8d502fdSDmitry Osipenko .name = "texsrd", 175a8d502fdSDmitry Osipenko }, { 176a8d502fdSDmitry Osipenko .id = 0x1c, 177a8d502fdSDmitry Osipenko .name = "vdebsevr", 178a8d502fdSDmitry Osipenko }, { 179a8d502fdSDmitry Osipenko .id = 0x1d, 180a8d502fdSDmitry Osipenko .name = "vdember", 181a8d502fdSDmitry Osipenko }, { 182a8d502fdSDmitry Osipenko .id = 0x1e, 183a8d502fdSDmitry Osipenko .name = "vdemcer", 184a8d502fdSDmitry Osipenko }, { 185a8d502fdSDmitry Osipenko .id = 0x1f, 186a8d502fdSDmitry Osipenko .name = "vdetper", 187a8d502fdSDmitry Osipenko }, { 188a8d502fdSDmitry Osipenko .id = 0x20, 189a8d502fdSDmitry Osipenko .name = "eppu", 190a8d502fdSDmitry Osipenko }, { 191a8d502fdSDmitry Osipenko .id = 0x21, 192a8d502fdSDmitry Osipenko .name = "eppv", 193a8d502fdSDmitry Osipenko }, { 194a8d502fdSDmitry Osipenko .id = 0x22, 195a8d502fdSDmitry Osipenko .name = "eppy", 196a8d502fdSDmitry Osipenko }, { 197a8d502fdSDmitry Osipenko .id = 0x23, 198a8d502fdSDmitry Osipenko .name = "mpeunifbw", 199a8d502fdSDmitry Osipenko }, { 200a8d502fdSDmitry Osipenko .id = 0x24, 201a8d502fdSDmitry Osipenko .name = "viwsb", 202a8d502fdSDmitry Osipenko }, { 203a8d502fdSDmitry Osipenko .id = 0x25, 204a8d502fdSDmitry Osipenko .name = "viwu", 205a8d502fdSDmitry Osipenko }, { 206a8d502fdSDmitry Osipenko .id = 0x26, 207a8d502fdSDmitry Osipenko .name = "viwv", 208a8d502fdSDmitry Osipenko }, { 209a8d502fdSDmitry Osipenko .id = 0x27, 210a8d502fdSDmitry Osipenko .name = "viwy", 211a8d502fdSDmitry Osipenko }, { 212a8d502fdSDmitry Osipenko .id = 0x28, 213a8d502fdSDmitry Osipenko .name = "g2dw", 214a8d502fdSDmitry Osipenko }, { 215a8d502fdSDmitry Osipenko .id = 0x29, 216a8d502fdSDmitry Osipenko .name = "avpcarm7w", 217a8d502fdSDmitry Osipenko }, { 218a8d502fdSDmitry Osipenko .id = 0x2a, 219a8d502fdSDmitry Osipenko .name = "fdcdwr", 220a8d502fdSDmitry Osipenko }, { 221a8d502fdSDmitry Osipenko .id = 0x2b, 222a8d502fdSDmitry Osipenko .name = "host1xw", 223a8d502fdSDmitry Osipenko }, { 224a8d502fdSDmitry Osipenko .id = 0x2c, 225a8d502fdSDmitry Osipenko .name = "ispw", 226a8d502fdSDmitry Osipenko }, { 227a8d502fdSDmitry Osipenko .id = 0x2d, 228a8d502fdSDmitry Osipenko .name = "mpcorew", 229a8d502fdSDmitry Osipenko }, { 230a8d502fdSDmitry Osipenko .id = 0x2e, 231a8d502fdSDmitry Osipenko .name = "mpecswr", 232a8d502fdSDmitry Osipenko }, { 233a8d502fdSDmitry Osipenko .id = 0x2f, 234a8d502fdSDmitry Osipenko .name = "ppcsahbdmaw", 235a8d502fdSDmitry Osipenko }, { 236a8d502fdSDmitry Osipenko .id = 0x30, 237a8d502fdSDmitry Osipenko .name = "ppcsahbslvw", 238a8d502fdSDmitry Osipenko }, { 239a8d502fdSDmitry Osipenko .id = 0x31, 240a8d502fdSDmitry Osipenko .name = "vdebsevw", 241a8d502fdSDmitry Osipenko }, { 242a8d502fdSDmitry Osipenko .id = 0x32, 243a8d502fdSDmitry Osipenko .name = "vdembew", 244a8d502fdSDmitry Osipenko }, { 245a8d502fdSDmitry Osipenko .id = 0x33, 246a8d502fdSDmitry Osipenko .name = "vdetpmw", 247a8d502fdSDmitry Osipenko }, 248a8d502fdSDmitry Osipenko }; 249a8d502fdSDmitry Osipenko 250cb557757SDmitry Osipenko #define TEGRA20_MC_RESET(_name, _control, _status, _reset, _bit) \ 251cb557757SDmitry Osipenko { \ 252cb557757SDmitry Osipenko .name = #_name, \ 253cb557757SDmitry Osipenko .id = TEGRA20_MC_RESET_##_name, \ 254cb557757SDmitry Osipenko .control = _control, \ 255cb557757SDmitry Osipenko .status = _status, \ 256cb557757SDmitry Osipenko .reset = _reset, \ 257cb557757SDmitry Osipenko .bit = _bit, \ 258cb557757SDmitry Osipenko } 259cb557757SDmitry Osipenko 260cb557757SDmitry Osipenko static const struct tegra_mc_reset tegra20_mc_resets[] = { 261cb557757SDmitry Osipenko TEGRA20_MC_RESET(AVPC, 0x100, 0x140, 0x104, 0), 262cb557757SDmitry Osipenko TEGRA20_MC_RESET(DC, 0x100, 0x144, 0x104, 1), 263cb557757SDmitry Osipenko TEGRA20_MC_RESET(DCB, 0x100, 0x148, 0x104, 2), 264cb557757SDmitry Osipenko TEGRA20_MC_RESET(EPP, 0x100, 0x14c, 0x104, 3), 265cb557757SDmitry Osipenko TEGRA20_MC_RESET(2D, 0x100, 0x150, 0x104, 4), 266cb557757SDmitry Osipenko TEGRA20_MC_RESET(HC, 0x100, 0x154, 0x104, 5), 267cb557757SDmitry Osipenko TEGRA20_MC_RESET(ISP, 0x100, 0x158, 0x104, 6), 268cb557757SDmitry Osipenko TEGRA20_MC_RESET(MPCORE, 0x100, 0x15c, 0x104, 7), 269cb557757SDmitry Osipenko TEGRA20_MC_RESET(MPEA, 0x100, 0x160, 0x104, 8), 270cb557757SDmitry Osipenko TEGRA20_MC_RESET(MPEB, 0x100, 0x164, 0x104, 9), 271cb557757SDmitry Osipenko TEGRA20_MC_RESET(MPEC, 0x100, 0x168, 0x104, 10), 272cb557757SDmitry Osipenko TEGRA20_MC_RESET(3D, 0x100, 0x16c, 0x104, 11), 273cb557757SDmitry Osipenko TEGRA20_MC_RESET(PPCS, 0x100, 0x170, 0x104, 12), 274cb557757SDmitry Osipenko TEGRA20_MC_RESET(VDE, 0x100, 0x174, 0x104, 13), 275cb557757SDmitry Osipenko TEGRA20_MC_RESET(VI, 0x100, 0x178, 0x104, 14), 276cb557757SDmitry Osipenko }; 277cb557757SDmitry Osipenko 278cb2b5839SThierry Reding static int tegra20_mc_hotreset_assert(struct tegra_mc *mc, 279cb557757SDmitry Osipenko const struct tegra_mc_reset *rst) 280cb557757SDmitry Osipenko { 281cb557757SDmitry Osipenko unsigned long flags; 282cb557757SDmitry Osipenko u32 value; 283cb557757SDmitry Osipenko 284cb557757SDmitry Osipenko spin_lock_irqsave(&mc->lock, flags); 285cb557757SDmitry Osipenko 286cb557757SDmitry Osipenko value = mc_readl(mc, rst->reset); 287cb557757SDmitry Osipenko mc_writel(mc, value & ~BIT(rst->bit), rst->reset); 288cb557757SDmitry Osipenko 289cb557757SDmitry Osipenko spin_unlock_irqrestore(&mc->lock, flags); 290cb557757SDmitry Osipenko 291cb557757SDmitry Osipenko return 0; 292cb557757SDmitry Osipenko } 293cb557757SDmitry Osipenko 294cb2b5839SThierry Reding static int tegra20_mc_hotreset_deassert(struct tegra_mc *mc, 295cb557757SDmitry Osipenko const struct tegra_mc_reset *rst) 296cb557757SDmitry Osipenko { 297cb557757SDmitry Osipenko unsigned long flags; 298cb557757SDmitry Osipenko u32 value; 299cb557757SDmitry Osipenko 300cb557757SDmitry Osipenko spin_lock_irqsave(&mc->lock, flags); 301cb557757SDmitry Osipenko 302cb557757SDmitry Osipenko value = mc_readl(mc, rst->reset); 303cb557757SDmitry Osipenko mc_writel(mc, value | BIT(rst->bit), rst->reset); 304cb557757SDmitry Osipenko 305cb557757SDmitry Osipenko spin_unlock_irqrestore(&mc->lock, flags); 306cb557757SDmitry Osipenko 307cb557757SDmitry Osipenko return 0; 308cb557757SDmitry Osipenko } 309cb557757SDmitry Osipenko 310cb2b5839SThierry Reding static int tegra20_mc_block_dma(struct tegra_mc *mc, 311cb557757SDmitry Osipenko const struct tegra_mc_reset *rst) 312cb557757SDmitry Osipenko { 313cb557757SDmitry Osipenko unsigned long flags; 314cb557757SDmitry Osipenko u32 value; 315cb557757SDmitry Osipenko 316cb557757SDmitry Osipenko spin_lock_irqsave(&mc->lock, flags); 317cb557757SDmitry Osipenko 318cb557757SDmitry Osipenko value = mc_readl(mc, rst->control) & ~BIT(rst->bit); 319cb557757SDmitry Osipenko mc_writel(mc, value, rst->control); 320cb557757SDmitry Osipenko 321cb557757SDmitry Osipenko spin_unlock_irqrestore(&mc->lock, flags); 322cb557757SDmitry Osipenko 323cb557757SDmitry Osipenko return 0; 324cb557757SDmitry Osipenko } 325cb557757SDmitry Osipenko 326cb2b5839SThierry Reding static bool tegra20_mc_dma_idling(struct tegra_mc *mc, 327cb557757SDmitry Osipenko const struct tegra_mc_reset *rst) 328cb557757SDmitry Osipenko { 329cb557757SDmitry Osipenko return mc_readl(mc, rst->status) == 0; 330cb557757SDmitry Osipenko } 331cb557757SDmitry Osipenko 332cb2b5839SThierry Reding static int tegra20_mc_reset_status(struct tegra_mc *mc, 333cb557757SDmitry Osipenko const struct tegra_mc_reset *rst) 334cb557757SDmitry Osipenko { 335cb557757SDmitry Osipenko return (mc_readl(mc, rst->reset) & BIT(rst->bit)) == 0; 336cb557757SDmitry Osipenko } 337cb557757SDmitry Osipenko 338cb2b5839SThierry Reding static int tegra20_mc_unblock_dma(struct tegra_mc *mc, 339cb557757SDmitry Osipenko const struct tegra_mc_reset *rst) 340cb557757SDmitry Osipenko { 341cb557757SDmitry Osipenko unsigned long flags; 342cb557757SDmitry Osipenko u32 value; 343cb557757SDmitry Osipenko 344cb557757SDmitry Osipenko spin_lock_irqsave(&mc->lock, flags); 345cb557757SDmitry Osipenko 346cb557757SDmitry Osipenko value = mc_readl(mc, rst->control) | BIT(rst->bit); 347cb557757SDmitry Osipenko mc_writel(mc, value, rst->control); 348cb557757SDmitry Osipenko 349cb557757SDmitry Osipenko spin_unlock_irqrestore(&mc->lock, flags); 350cb557757SDmitry Osipenko 351cb557757SDmitry Osipenko return 0; 352cb557757SDmitry Osipenko } 353cb557757SDmitry Osipenko 354cb2b5839SThierry Reding static const struct tegra_mc_reset_ops tegra20_mc_reset_ops = { 355cb2b5839SThierry Reding .hotreset_assert = tegra20_mc_hotreset_assert, 356cb2b5839SThierry Reding .hotreset_deassert = tegra20_mc_hotreset_deassert, 357cb2b5839SThierry Reding .block_dma = tegra20_mc_block_dma, 358cb2b5839SThierry Reding .dma_idling = tegra20_mc_dma_idling, 359cb2b5839SThierry Reding .unblock_dma = tegra20_mc_unblock_dma, 360cb2b5839SThierry Reding .reset_status = tegra20_mc_reset_status, 361cb557757SDmitry Osipenko }; 362cb557757SDmitry Osipenko 363d5ef16baSDmitry Osipenko static int tegra20_mc_icc_set(struct icc_node *src, struct icc_node *dst) 364d5ef16baSDmitry Osipenko { 365d5ef16baSDmitry Osipenko /* 366d5ef16baSDmitry Osipenko * It should be possible to tune arbitration knobs here, but the 367d5ef16baSDmitry Osipenko * default values are known to work well on all devices. Hence 368d5ef16baSDmitry Osipenko * nothing to do here so far. 369d5ef16baSDmitry Osipenko */ 370d5ef16baSDmitry Osipenko return 0; 371d5ef16baSDmitry Osipenko } 372d5ef16baSDmitry Osipenko 373d5ef16baSDmitry Osipenko static int tegra20_mc_icc_aggreate(struct icc_node *node, u32 tag, u32 avg_bw, 374d5ef16baSDmitry Osipenko u32 peak_bw, u32 *agg_avg, u32 *agg_peak) 375d5ef16baSDmitry Osipenko { 376d5ef16baSDmitry Osipenko /* 377d5ef16baSDmitry Osipenko * ISO clients need to reserve extra bandwidth up-front because 378d5ef16baSDmitry Osipenko * there could be high bandwidth pressure during initial filling 379d5ef16baSDmitry Osipenko * of the client's FIFO buffers. Secondly, we need to take into 380d5ef16baSDmitry Osipenko * account impurities of the memory subsystem. 381d5ef16baSDmitry Osipenko */ 382d5ef16baSDmitry Osipenko if (tag & TEGRA_MC_ICC_TAG_ISO) 383d5ef16baSDmitry Osipenko peak_bw = tegra_mc_scale_percents(peak_bw, 300); 384d5ef16baSDmitry Osipenko 385d5ef16baSDmitry Osipenko *agg_avg += avg_bw; 386d5ef16baSDmitry Osipenko *agg_peak = max(*agg_peak, peak_bw); 387d5ef16baSDmitry Osipenko 388d5ef16baSDmitry Osipenko return 0; 389d5ef16baSDmitry Osipenko } 390d5ef16baSDmitry Osipenko 391d5ef16baSDmitry Osipenko static struct icc_node_data * 392d5ef16baSDmitry Osipenko tegra20_mc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data) 393d5ef16baSDmitry Osipenko { 394d5ef16baSDmitry Osipenko struct tegra_mc *mc = icc_provider_to_tegra_mc(data); 395d5ef16baSDmitry Osipenko unsigned int i, idx = spec->args[0]; 396d5ef16baSDmitry Osipenko struct icc_node_data *ndata; 397d5ef16baSDmitry Osipenko struct icc_node *node; 398d5ef16baSDmitry Osipenko 399d5ef16baSDmitry Osipenko list_for_each_entry(node, &mc->provider.nodes, node_list) { 400d5ef16baSDmitry Osipenko if (node->id != idx) 401d5ef16baSDmitry Osipenko continue; 402d5ef16baSDmitry Osipenko 403d5ef16baSDmitry Osipenko ndata = kzalloc(sizeof(*ndata), GFP_KERNEL); 404d5ef16baSDmitry Osipenko if (!ndata) 405d5ef16baSDmitry Osipenko return ERR_PTR(-ENOMEM); 406d5ef16baSDmitry Osipenko 407d5ef16baSDmitry Osipenko ndata->node = node; 408d5ef16baSDmitry Osipenko 409d5ef16baSDmitry Osipenko /* these clients are isochronous by default */ 410d5ef16baSDmitry Osipenko if (strstarts(node->name, "display") || 411d5ef16baSDmitry Osipenko strstarts(node->name, "vi")) 412d5ef16baSDmitry Osipenko ndata->tag = TEGRA_MC_ICC_TAG_ISO; 413d5ef16baSDmitry Osipenko else 414d5ef16baSDmitry Osipenko ndata->tag = TEGRA_MC_ICC_TAG_DEFAULT; 415d5ef16baSDmitry Osipenko 416d5ef16baSDmitry Osipenko return ndata; 417d5ef16baSDmitry Osipenko } 418d5ef16baSDmitry Osipenko 419d5ef16baSDmitry Osipenko for (i = 0; i < mc->soc->num_clients; i++) { 420d5ef16baSDmitry Osipenko if (mc->soc->clients[i].id == idx) 421d5ef16baSDmitry Osipenko return ERR_PTR(-EPROBE_DEFER); 422d5ef16baSDmitry Osipenko } 423d5ef16baSDmitry Osipenko 424d5ef16baSDmitry Osipenko dev_err(mc->dev, "invalid ICC client ID %u\n", idx); 425d5ef16baSDmitry Osipenko 426d5ef16baSDmitry Osipenko return ERR_PTR(-EINVAL); 427d5ef16baSDmitry Osipenko } 428d5ef16baSDmitry Osipenko 429d5ef16baSDmitry Osipenko static const struct tegra_mc_icc_ops tegra20_mc_icc_ops = { 430d5ef16baSDmitry Osipenko .xlate_extended = tegra20_mc_of_icc_xlate_extended, 431d5ef16baSDmitry Osipenko .aggregate = tegra20_mc_icc_aggreate, 432d5ef16baSDmitry Osipenko .set = tegra20_mc_icc_set, 433d5ef16baSDmitry Osipenko }; 434d5ef16baSDmitry Osipenko 435fbd31f5aSDmitry Osipenko static u32 tegra20_mc_stat_gather_control(const struct tegra20_mc_stat_gather *g) 436fbd31f5aSDmitry Osipenko { 437fbd31f5aSDmitry Osipenko u32 control; 438fbd31f5aSDmitry Osipenko 439fbd31f5aSDmitry Osipenko control = FIELD_PREP(MC_STAT_CONTROL_EVENT, g->event); 440fbd31f5aSDmitry Osipenko control |= FIELD_PREP(MC_STAT_CONTROL_CLIENT_ID, g->client); 441fbd31f5aSDmitry Osipenko control |= FIELD_PREP(MC_STAT_CONTROL_PRI_EVENT, g->pri_event); 442fbd31f5aSDmitry Osipenko control |= FIELD_PREP(MC_STAT_CONTROL_FILTER_PRI, g->pri_filter); 443fbd31f5aSDmitry Osipenko control |= FIELD_PREP(MC_STAT_CONTROL_FILTER_CLIENT_ENABLE, g->client_enb); 444fbd31f5aSDmitry Osipenko 445fbd31f5aSDmitry Osipenko return control; 446fbd31f5aSDmitry Osipenko } 447fbd31f5aSDmitry Osipenko 448fbd31f5aSDmitry Osipenko static void tegra20_mc_stat_gather(struct tegra20_mc_stat *stat) 449fbd31f5aSDmitry Osipenko { 450fbd31f5aSDmitry Osipenko u32 clocks, count0, count1, control_0, control_1; 451fbd31f5aSDmitry Osipenko const struct tegra_mc *mc = stat->mc; 452fbd31f5aSDmitry Osipenko 453fbd31f5aSDmitry Osipenko control_0 = tegra20_mc_stat_gather_control(&stat->gather0); 454fbd31f5aSDmitry Osipenko control_1 = tegra20_mc_stat_gather_control(&stat->gather1); 455fbd31f5aSDmitry Osipenko 456fbd31f5aSDmitry Osipenko /* 4577ebb09dbSDmitry Osipenko * Reset statistic gathers state, select statistics collection mode 4587ebb09dbSDmitry Osipenko * and set clocks counter saturation limit to maximum. 459fbd31f5aSDmitry Osipenko */ 460fbd31f5aSDmitry Osipenko mc_writel(mc, 0x00000000, MC_STAT_CONTROL); 461fbd31f5aSDmitry Osipenko mc_writel(mc, control_0, MC_STAT_EMC_CONTROL_0); 462fbd31f5aSDmitry Osipenko mc_writel(mc, control_1, MC_STAT_EMC_CONTROL_1); 463fbd31f5aSDmitry Osipenko mc_writel(mc, 0xffffffff, MC_STAT_EMC_CLOCK_LIMIT); 464fbd31f5aSDmitry Osipenko 465fbd31f5aSDmitry Osipenko mc_writel(mc, EMC_GATHER_ENABLE, MC_STAT_CONTROL); 466fbd31f5aSDmitry Osipenko fsleep(stat->sample_time_usec); 467fbd31f5aSDmitry Osipenko mc_writel(mc, EMC_GATHER_DISABLE, MC_STAT_CONTROL); 468fbd31f5aSDmitry Osipenko 469fbd31f5aSDmitry Osipenko count0 = mc_readl(mc, MC_STAT_EMC_COUNT_0); 470fbd31f5aSDmitry Osipenko count1 = mc_readl(mc, MC_STAT_EMC_COUNT_1); 471fbd31f5aSDmitry Osipenko clocks = mc_readl(mc, MC_STAT_EMC_CLOCKS); 472fbd31f5aSDmitry Osipenko clocks = max(clocks / 100 / MC_FX_FRAC_SCALE, 1u); 473fbd31f5aSDmitry Osipenko 474fbd31f5aSDmitry Osipenko stat->gather0.result = DIV_ROUND_UP(count0, clocks); 475fbd31f5aSDmitry Osipenko stat->gather1.result = DIV_ROUND_UP(count1, clocks); 476fbd31f5aSDmitry Osipenko } 477fbd31f5aSDmitry Osipenko 478fbd31f5aSDmitry Osipenko static void tegra20_mc_stat_events(const struct tegra_mc *mc, 479fbd31f5aSDmitry Osipenko const struct tegra_mc_client *client0, 480fbd31f5aSDmitry Osipenko const struct tegra_mc_client *client1, 481fbd31f5aSDmitry Osipenko unsigned int pri_filter, 482fbd31f5aSDmitry Osipenko unsigned int pri_event, 483fbd31f5aSDmitry Osipenko unsigned int event, 484fbd31f5aSDmitry Osipenko unsigned int *result0, 485fbd31f5aSDmitry Osipenko unsigned int *result1) 486fbd31f5aSDmitry Osipenko { 487fbd31f5aSDmitry Osipenko struct tegra20_mc_stat stat = {}; 488fbd31f5aSDmitry Osipenko 489fbd31f5aSDmitry Osipenko stat.gather0.client = client0 ? client0->id : 0; 490fbd31f5aSDmitry Osipenko stat.gather0.pri_filter = pri_filter; 491fbd31f5aSDmitry Osipenko stat.gather0.client_enb = !!client0; 492fbd31f5aSDmitry Osipenko stat.gather0.pri_event = pri_event; 493fbd31f5aSDmitry Osipenko stat.gather0.event = event; 494fbd31f5aSDmitry Osipenko 495fbd31f5aSDmitry Osipenko stat.gather1.client = client1 ? client1->id : 0; 496fbd31f5aSDmitry Osipenko stat.gather1.pri_filter = pri_filter; 497fbd31f5aSDmitry Osipenko stat.gather1.client_enb = !!client1; 498fbd31f5aSDmitry Osipenko stat.gather1.pri_event = pri_event; 499fbd31f5aSDmitry Osipenko stat.gather1.event = event; 500fbd31f5aSDmitry Osipenko 501fbd31f5aSDmitry Osipenko stat.sample_time_usec = MC_STAT_SAMPLE_TIME_USEC; 502fbd31f5aSDmitry Osipenko stat.mc = mc; 503fbd31f5aSDmitry Osipenko 504fbd31f5aSDmitry Osipenko tegra20_mc_stat_gather(&stat); 505fbd31f5aSDmitry Osipenko 506fbd31f5aSDmitry Osipenko *result0 = stat.gather0.result; 507fbd31f5aSDmitry Osipenko *result1 = stat.gather1.result; 508fbd31f5aSDmitry Osipenko } 509fbd31f5aSDmitry Osipenko 510fbd31f5aSDmitry Osipenko static void tegra20_mc_collect_stats(const struct tegra_mc *mc, 511fbd31f5aSDmitry Osipenko struct tegra20_mc_client_stat *stats) 512fbd31f5aSDmitry Osipenko { 513fbd31f5aSDmitry Osipenko const struct tegra_mc_client *client0, *client1; 514fbd31f5aSDmitry Osipenko unsigned int i; 515fbd31f5aSDmitry Osipenko 516fbd31f5aSDmitry Osipenko /* collect memory controller utilization percent for each client */ 517fbd31f5aSDmitry Osipenko for (i = 0; i < mc->soc->num_clients; i += 2) { 518fbd31f5aSDmitry Osipenko client0 = &mc->soc->clients[i]; 519fbd31f5aSDmitry Osipenko client1 = &mc->soc->clients[i + 1]; 520fbd31f5aSDmitry Osipenko 521fbd31f5aSDmitry Osipenko if (i + 1 == mc->soc->num_clients) 522fbd31f5aSDmitry Osipenko client1 = NULL; 523fbd31f5aSDmitry Osipenko 524fbd31f5aSDmitry Osipenko tegra20_mc_stat_events(mc, client0, client1, 525fbd31f5aSDmitry Osipenko MC_STAT_CONTROL_FILTER_PRI_DISABLE, 526fbd31f5aSDmitry Osipenko MC_STAT_CONTROL_PRI_EVENT_HP, 527fbd31f5aSDmitry Osipenko MC_STAT_CONTROL_EVENT_QUALIFIED, 528fbd31f5aSDmitry Osipenko &stats[i + 0].events, 529fbd31f5aSDmitry Osipenko &stats[i + 1].events); 530fbd31f5aSDmitry Osipenko } 531fbd31f5aSDmitry Osipenko 532fbd31f5aSDmitry Osipenko /* collect more info from active clients */ 533fbd31f5aSDmitry Osipenko for (i = 0; i < mc->soc->num_clients; i++) { 534fbd31f5aSDmitry Osipenko unsigned int clienta, clientb = mc->soc->num_clients; 535fbd31f5aSDmitry Osipenko 536fbd31f5aSDmitry Osipenko for (client0 = NULL; i < mc->soc->num_clients; i++) { 537fbd31f5aSDmitry Osipenko if (stats[i].events) { 538fbd31f5aSDmitry Osipenko client0 = &mc->soc->clients[i]; 539fbd31f5aSDmitry Osipenko clienta = i++; 540fbd31f5aSDmitry Osipenko break; 541fbd31f5aSDmitry Osipenko } 542fbd31f5aSDmitry Osipenko } 543fbd31f5aSDmitry Osipenko 544fbd31f5aSDmitry Osipenko for (client1 = NULL; i < mc->soc->num_clients; i++) { 545fbd31f5aSDmitry Osipenko if (stats[i].events) { 546fbd31f5aSDmitry Osipenko client1 = &mc->soc->clients[i]; 547fbd31f5aSDmitry Osipenko clientb = i; 548fbd31f5aSDmitry Osipenko break; 549fbd31f5aSDmitry Osipenko } 550fbd31f5aSDmitry Osipenko } 551fbd31f5aSDmitry Osipenko 552fbd31f5aSDmitry Osipenko if (!client0 && !client1) 553fbd31f5aSDmitry Osipenko break; 554fbd31f5aSDmitry Osipenko 555fbd31f5aSDmitry Osipenko tegra20_mc_stat_events(mc, client0, client1, 556fbd31f5aSDmitry Osipenko MC_STAT_CONTROL_FILTER_PRI_YES, 557fbd31f5aSDmitry Osipenko MC_STAT_CONTROL_PRI_EVENT_HP, 558fbd31f5aSDmitry Osipenko MC_STAT_CONTROL_EVENT_QUALIFIED, 559fbd31f5aSDmitry Osipenko &stats[clienta].arb_high_prio, 560fbd31f5aSDmitry Osipenko &stats[clientb].arb_high_prio); 561fbd31f5aSDmitry Osipenko 562fbd31f5aSDmitry Osipenko tegra20_mc_stat_events(mc, client0, client1, 563fbd31f5aSDmitry Osipenko MC_STAT_CONTROL_FILTER_PRI_YES, 564fbd31f5aSDmitry Osipenko MC_STAT_CONTROL_PRI_EVENT_TM, 565fbd31f5aSDmitry Osipenko MC_STAT_CONTROL_EVENT_QUALIFIED, 566fbd31f5aSDmitry Osipenko &stats[clienta].arb_timeout, 567fbd31f5aSDmitry Osipenko &stats[clientb].arb_timeout); 568fbd31f5aSDmitry Osipenko 569fbd31f5aSDmitry Osipenko tegra20_mc_stat_events(mc, client0, client1, 570fbd31f5aSDmitry Osipenko MC_STAT_CONTROL_FILTER_PRI_YES, 571fbd31f5aSDmitry Osipenko MC_STAT_CONTROL_PRI_EVENT_BW, 572fbd31f5aSDmitry Osipenko MC_STAT_CONTROL_EVENT_QUALIFIED, 573fbd31f5aSDmitry Osipenko &stats[clienta].arb_bandwidth, 574fbd31f5aSDmitry Osipenko &stats[clientb].arb_bandwidth); 575fbd31f5aSDmitry Osipenko 576fbd31f5aSDmitry Osipenko tegra20_mc_stat_events(mc, client0, client1, 577fbd31f5aSDmitry Osipenko MC_STAT_CONTROL_FILTER_PRI_DISABLE, 578fbd31f5aSDmitry Osipenko MC_STAT_CONTROL_PRI_EVENT_HP, 579fbd31f5aSDmitry Osipenko MC_STAT_CONTROL_EVENT_RD_WR_CHANGE, 580fbd31f5aSDmitry Osipenko &stats[clienta].rd_wr_change, 581fbd31f5aSDmitry Osipenko &stats[clientb].rd_wr_change); 582fbd31f5aSDmitry Osipenko 583fbd31f5aSDmitry Osipenko tegra20_mc_stat_events(mc, client0, client1, 584fbd31f5aSDmitry Osipenko MC_STAT_CONTROL_FILTER_PRI_DISABLE, 585fbd31f5aSDmitry Osipenko MC_STAT_CONTROL_PRI_EVENT_HP, 586fbd31f5aSDmitry Osipenko MC_STAT_CONTROL_EVENT_SUCCESSIVE, 587fbd31f5aSDmitry Osipenko &stats[clienta].successive, 588fbd31f5aSDmitry Osipenko &stats[clientb].successive); 589fbd31f5aSDmitry Osipenko 590fbd31f5aSDmitry Osipenko tegra20_mc_stat_events(mc, client0, client1, 591fbd31f5aSDmitry Osipenko MC_STAT_CONTROL_FILTER_PRI_DISABLE, 592fbd31f5aSDmitry Osipenko MC_STAT_CONTROL_PRI_EVENT_HP, 593fbd31f5aSDmitry Osipenko MC_STAT_CONTROL_EVENT_PAGE_MISS, 594fbd31f5aSDmitry Osipenko &stats[clienta].page_miss, 595fbd31f5aSDmitry Osipenko &stats[clientb].page_miss); 596fbd31f5aSDmitry Osipenko } 597fbd31f5aSDmitry Osipenko } 598fbd31f5aSDmitry Osipenko 599fbd31f5aSDmitry Osipenko static void tegra20_mc_printf_percents(struct seq_file *s, 600fbd31f5aSDmitry Osipenko const char *fmt, 601fbd31f5aSDmitry Osipenko unsigned int percents_fx) 602fbd31f5aSDmitry Osipenko { 603fbd31f5aSDmitry Osipenko char percents_str[8]; 604fbd31f5aSDmitry Osipenko 605fbd31f5aSDmitry Osipenko snprintf(percents_str, ARRAY_SIZE(percents_str), "%3u.%02u%%", 606fbd31f5aSDmitry Osipenko percents_fx / MC_FX_FRAC_SCALE, percents_fx % MC_FX_FRAC_SCALE); 607fbd31f5aSDmitry Osipenko 608fbd31f5aSDmitry Osipenko seq_printf(s, fmt, percents_str); 609fbd31f5aSDmitry Osipenko } 610fbd31f5aSDmitry Osipenko 611fbd31f5aSDmitry Osipenko static int tegra20_mc_stats_show(struct seq_file *s, void *unused) 612fbd31f5aSDmitry Osipenko { 613fbd31f5aSDmitry Osipenko const struct tegra_mc *mc = dev_get_drvdata(s->private); 614fbd31f5aSDmitry Osipenko struct tegra20_mc_client_stat *stats; 615fbd31f5aSDmitry Osipenko unsigned int i; 616fbd31f5aSDmitry Osipenko 617fbd31f5aSDmitry Osipenko stats = kcalloc(mc->soc->num_clients + 1, sizeof(*stats), GFP_KERNEL); 618fbd31f5aSDmitry Osipenko if (!stats) 619fbd31f5aSDmitry Osipenko return -ENOMEM; 620fbd31f5aSDmitry Osipenko 62128947198SDmitry Osipenko mutex_lock(&tegra20_mc_stat_lock); 62228947198SDmitry Osipenko 623fbd31f5aSDmitry Osipenko tegra20_mc_collect_stats(mc, stats); 624fbd31f5aSDmitry Osipenko 62528947198SDmitry Osipenko mutex_unlock(&tegra20_mc_stat_lock); 62628947198SDmitry Osipenko 627fbd31f5aSDmitry Osipenko seq_puts(s, "Memory client Events Timeout High priority Bandwidth ARB RW change Successive Page miss\n"); 628fbd31f5aSDmitry Osipenko seq_puts(s, "-----------------------------------------------------------------------------------------------------\n"); 629fbd31f5aSDmitry Osipenko 630fbd31f5aSDmitry Osipenko for (i = 0; i < mc->soc->num_clients; i++) { 631fbd31f5aSDmitry Osipenko seq_printf(s, "%-14s ", mc->soc->clients[i].name); 632fbd31f5aSDmitry Osipenko 633fbd31f5aSDmitry Osipenko /* An event is generated when client performs R/W request. */ 634fbd31f5aSDmitry Osipenko tegra20_mc_printf_percents(s, "%-9s", stats[i].events); 635fbd31f5aSDmitry Osipenko 636fbd31f5aSDmitry Osipenko /* 637fbd31f5aSDmitry Osipenko * An event is generated based on the timeout (TM) signal 638fbd31f5aSDmitry Osipenko * accompanying a request for arbitration. 639fbd31f5aSDmitry Osipenko */ 640fbd31f5aSDmitry Osipenko tegra20_mc_printf_percents(s, "%-10s", stats[i].arb_timeout); 641fbd31f5aSDmitry Osipenko 642fbd31f5aSDmitry Osipenko /* 643fbd31f5aSDmitry Osipenko * An event is generated based on the high-priority (HP) signal 644fbd31f5aSDmitry Osipenko * accompanying a request for arbitration. 645fbd31f5aSDmitry Osipenko */ 646fbd31f5aSDmitry Osipenko tegra20_mc_printf_percents(s, "%-16s", stats[i].arb_high_prio); 647fbd31f5aSDmitry Osipenko 648fbd31f5aSDmitry Osipenko /* 649fbd31f5aSDmitry Osipenko * An event is generated based on the bandwidth (BW) signal 650fbd31f5aSDmitry Osipenko * accompanying a request for arbitration. 651fbd31f5aSDmitry Osipenko */ 652fbd31f5aSDmitry Osipenko tegra20_mc_printf_percents(s, "%-16s", stats[i].arb_bandwidth); 653fbd31f5aSDmitry Osipenko 654fbd31f5aSDmitry Osipenko /* 655fbd31f5aSDmitry Osipenko * An event is generated when the memory controller switches 656fbd31f5aSDmitry Osipenko * between making a read request to making a write request. 657fbd31f5aSDmitry Osipenko */ 658fbd31f5aSDmitry Osipenko tegra20_mc_printf_percents(s, "%-12s", stats[i].rd_wr_change); 659fbd31f5aSDmitry Osipenko 660fbd31f5aSDmitry Osipenko /* 661fbd31f5aSDmitry Osipenko * An even generated when the chosen client has wins arbitration 662fbd31f5aSDmitry Osipenko * when it was also the winner at the previous request. If a 663fbd31f5aSDmitry Osipenko * client makes N requests in a row that are honored, SUCCESSIVE 664fbd31f5aSDmitry Osipenko * will be counted (N-1) times. Large values for this event 665fbd31f5aSDmitry Osipenko * imply that if we were patient enough, all of those requests 666fbd31f5aSDmitry Osipenko * could have been coalesced. 667fbd31f5aSDmitry Osipenko */ 668fbd31f5aSDmitry Osipenko tegra20_mc_printf_percents(s, "%-13s", stats[i].successive); 669fbd31f5aSDmitry Osipenko 670fbd31f5aSDmitry Osipenko /* 671fbd31f5aSDmitry Osipenko * An event is generated when the memory controller detects a 672fbd31f5aSDmitry Osipenko * page miss for the current request. 673fbd31f5aSDmitry Osipenko */ 674fbd31f5aSDmitry Osipenko tegra20_mc_printf_percents(s, "%-12s\n", stats[i].page_miss); 675fbd31f5aSDmitry Osipenko } 676fbd31f5aSDmitry Osipenko 677fbd31f5aSDmitry Osipenko kfree(stats); 678fbd31f5aSDmitry Osipenko 679fbd31f5aSDmitry Osipenko return 0; 680fbd31f5aSDmitry Osipenko } 681fbd31f5aSDmitry Osipenko 682*c64738e9SThierry Reding static int tegra20_mc_probe(struct tegra_mc *mc) 683fbd31f5aSDmitry Osipenko { 684fbd31f5aSDmitry Osipenko debugfs_create_devm_seqfile(mc->dev, "stats", mc->debugfs.root, 685fbd31f5aSDmitry Osipenko tegra20_mc_stats_show); 686fbd31f5aSDmitry Osipenko 687fbd31f5aSDmitry Osipenko return 0; 688fbd31f5aSDmitry Osipenko } 689fbd31f5aSDmitry Osipenko 6905c9016f0SThierry Reding static int tegra20_mc_suspend(struct tegra_mc *mc) 6915c9016f0SThierry Reding { 6925c9016f0SThierry Reding int err; 6935c9016f0SThierry Reding 6945c9016f0SThierry Reding if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && mc->gart) { 6955c9016f0SThierry Reding err = tegra_gart_suspend(mc->gart); 6965c9016f0SThierry Reding if (err < 0) 6975c9016f0SThierry Reding return err; 6985c9016f0SThierry Reding } 6995c9016f0SThierry Reding 7005c9016f0SThierry Reding return 0; 7015c9016f0SThierry Reding } 7025c9016f0SThierry Reding 7035c9016f0SThierry Reding static int tegra20_mc_resume(struct tegra_mc *mc) 7045c9016f0SThierry Reding { 7055c9016f0SThierry Reding int err; 7065c9016f0SThierry Reding 7075c9016f0SThierry Reding if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && mc->gart) { 7085c9016f0SThierry Reding err = tegra_gart_resume(mc->gart); 7095c9016f0SThierry Reding if (err < 0) 7105c9016f0SThierry Reding return err; 7115c9016f0SThierry Reding } 7125c9016f0SThierry Reding 7135c9016f0SThierry Reding return 0; 7145c9016f0SThierry Reding } 7155c9016f0SThierry Reding 7166cc884c1SThierry Reding static const struct tegra_mc_ops tegra20_mc_ops = { 717*c64738e9SThierry Reding .probe = tegra20_mc_probe, 7185c9016f0SThierry Reding .suspend = tegra20_mc_suspend, 7195c9016f0SThierry Reding .resume = tegra20_mc_resume, 7206cc884c1SThierry Reding }; 7216cc884c1SThierry Reding 722a8d502fdSDmitry Osipenko const struct tegra_mc_soc tegra20_mc_soc = { 723a8d502fdSDmitry Osipenko .clients = tegra20_mc_clients, 724a8d502fdSDmitry Osipenko .num_clients = ARRAY_SIZE(tegra20_mc_clients), 725a8d502fdSDmitry Osipenko .num_address_bits = 32, 726a8d502fdSDmitry Osipenko .client_id_mask = 0x3f, 727a8d502fdSDmitry Osipenko .intmask = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE | 728a8d502fdSDmitry Osipenko MC_INT_DECERR_EMEM, 729cb2b5839SThierry Reding .reset_ops = &tegra20_mc_reset_ops, 730cb557757SDmitry Osipenko .resets = tegra20_mc_resets, 731cb557757SDmitry Osipenko .num_resets = ARRAY_SIZE(tegra20_mc_resets), 732d5ef16baSDmitry Osipenko .icc_ops = &tegra20_mc_icc_ops, 7336cc884c1SThierry Reding .ops = &tegra20_mc_ops, 734a8d502fdSDmitry Osipenko }; 735