tegra_mc.c revision 317012
1/*- 2 * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: stable/11/sys/arm/nvidia/tegra_mc.c 317012 2017-04-16 08:18:37Z mmel $"); 29 30/* 31 * Memory controller driver for Tegra SoCs. 32 */ 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/bus.h> 36#include <sys/kernel.h> 37#include <sys/limits.h> 38#include <sys/lock.h> 39#include <sys/mutex.h> 40#include <sys/module.h> 41#include <sys/resource.h> 42 43#include <machine/bus.h> 44#include <machine/resource.h> 45#include <sys/rman.h> 46 47#include <dev/extres/clk/clk.h> 48#include <dev/ofw/ofw_bus.h> 49#include <dev/ofw/ofw_bus_subr.h> 50 51#include "clock_if.h" 52 53#define MC_INTSTATUS 0x000 54#define MC_INTMASK 0x004 55#define MC_INT_DECERR_MTS (1 << 16) 56#define MC_INT_SECERR_SEC (1 << 13) 57#define MC_INT_DECERR_VPR (1 << 12) 58#define MC_INT_INVALID_APB_ASID_UPDATE (1 << 11) 59#define MC_INT_INVALID_SMMU_PAGE (1 << 10) 60#define MC_INT_ARBITRATION_EMEM (1 << 9) 61#define MC_INT_SECURITY_VIOLATION (1 << 8) 62#define MC_INT_DECERR_EMEM (1 << 6) 63#define MC_INT_INT_MASK (MC_INT_DECERR_MTS | \ 64 MC_INT_SECERR_SEC | \ 65 MC_INT_DECERR_VPR | \ 66 MC_INT_INVALID_APB_ASID_UPDATE | \ 67 MC_INT_INVALID_SMMU_PAGE | \ 68 MC_INT_ARBITRATION_EMEM | \ 69 MC_INT_SECURITY_VIOLATION | \ 70 MC_INT_DECERR_EMEM) 71 72#define MC_ERR_STATUS 0x008 73#define MC_ERR_TYPE(x) (((x) >> 28) & 0x7) 74#define MC_ERR_TYPE_DECERR_EMEM 2 75#define MC_ERR_TYPE_SECURITY_TRUSTZONE 3 76#define MC_ERR_TYPE_SECURITY_CARVEOUT 4 77#define MC_ERR_TYPE_INVALID_SMMU_PAGE 6 78#define MC_ERR_INVALID_SMMU_PAGE_READABLE (1 << 27) 79#define MC_ERR_INVALID_SMMU_PAGE_WRITABLE (1 << 26) 80#define MC_ERR_INVALID_SMMU_PAGE_NONSECURE (1 << 25) 81#define MC_ERR_ADR_HI(x) (((x) >> 20) & 0x3) 82#define MC_ERR_SWAP (1 << 18) 83#define MC_ERR_SECURITY (1 << 17) 84#define MC_ERR_RW (1 << 16) 85#define MC_ERR_ADR1(x) (((x) >> 12) & 0x7) 86#define MC_ERR_ID(x) (((x) >> 0) & 07F) 87 88#define MC_ERR_ADDR 0x00C 89#define MC_EMEM_CFG 0x050 90#define MC_EMEM_ADR_CFG 0x054 91#define MC_EMEM_NUMDEV(x) (((x) >> 0 ) & 0x1) 92 93#define MC_EMEM_ADR_CFG_DEV0 0x058 94#define MC_EMEM_ADR_CFG_DEV1 0x05C 95#define EMEM_DEV_DEVSIZE(x) (((x) >> 16) & 0xF) 96#define EMEM_DEV_BANKWIDTH(x) (((x) >> 8) & 0x3) 97#define EMEM_DEV_COLWIDTH(x) (((x) >> 8) & 0x3) 98 99#define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, (_r), (_v)) 100#define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_r)) 101 102#define LOCK(_sc) mtx_lock(&(_sc)->mtx) 103#define UNLOCK(_sc) mtx_unlock(&(_sc)->mtx) 104#define SLEEP(_sc, timeout) mtx_sleep(sc, &sc->mtx, 0, "tegra_mc", timeout); 105#define LOCK_INIT(_sc) \ 106 mtx_init(&_sc->mtx, device_get_nameunit(_sc->dev), "tegra_mc", MTX_DEF) 107#define LOCK_DESTROY(_sc) mtx_destroy(&_sc->mtx) 108#define ASSERT_LOCKED(_sc) mtx_assert(&_sc->mtx, MA_OWNED) 109#define ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->mtx, MA_NOTOWNED) 110 111static struct ofw_compat_data compat_data[] = { 112 {"nvidia,tegra124-mc", 1}, 113 {NULL, 0} 114}; 115 116struct tegra_mc_softc { 117 device_t dev; 118 struct mtx mtx; 119 120 struct resource *mem_res; 121 struct resource *irq_res; 122 void *irq_h; 123 124 clk_t clk; 125}; 126 127static char *smmu_err_tbl[16] = { 128 "reserved", /* 0 */ 129 "reserved", /* 1 */ 130 "DRAM decode", /* 2 */ 131 "Trustzome Security", /* 3 */ 132 "Security carveout", /* 4 */ 133 "reserved", /* 5 */ 134 "Invalid SMMU page", /* 6 */ 135 "reserved", /* 7 */ 136}; 137 138static void 139tegra_mc_intr(void *arg) 140{ 141 struct tegra_mc_softc *sc; 142 uint32_t stat, err; 143 uint64_t addr; 144 145 sc = (struct tegra_mc_softc *)arg; 146 147 stat = RD4(sc, MC_INTSTATUS); 148 if ((stat & MC_INT_INT_MASK) == 0) { 149 WR4(sc, MC_INTSTATUS, stat); 150 return; 151 } 152 153 device_printf(sc->dev, "Memory Controller Interrupt:\n"); 154 if (stat & MC_INT_DECERR_MTS) 155 printf(" - MTS carveout violation\n"); 156 if (stat & MC_INT_SECERR_SEC) 157 printf(" - SEC carveout violation\n"); 158 if (stat & MC_INT_DECERR_VPR) 159 printf(" - VPR requirements violated\n"); 160 if (stat & MC_INT_INVALID_APB_ASID_UPDATE) 161 printf(" - ivalid APB ASID update\n"); 162 if (stat & MC_INT_INVALID_SMMU_PAGE) 163 printf(" - SMMU address translation error\n"); 164 if (stat & MC_INT_ARBITRATION_EMEM) 165 printf(" - arbitration deadlock-prevention threshold hit\n"); 166 if (stat & MC_INT_SECURITY_VIOLATION) 167 printf(" - SMMU address translation security error\n"); 168 if (stat & MC_INT_DECERR_EMEM) 169 printf(" - SMMU address decode error\n"); 170 171 if ((stat & (MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION | 172 MC_INT_DECERR_EMEM)) != 0) { 173 err = RD4(sc, MC_ERR_STATUS); 174 addr = RD4(sc, MC_ERR_STATUS); 175 addr |= (uint64_t)(MC_ERR_ADR_HI(err)) << 32; 176 printf(" at 0x%012llX [%s %s %s] - %s error.\n", 177 addr, 178 stat & MC_ERR_SWAP ? "Swap, " : "", 179 stat & MC_ERR_SECURITY ? "Sec, " : "", 180 stat & MC_ERR_RW ? "Write" : "Read", 181 smmu_err_tbl[MC_ERR_TYPE(err)]); 182 } 183 WR4(sc, MC_INTSTATUS, stat); 184} 185 186static void 187tegra_mc_init_hw(struct tegra_mc_softc *sc) 188{ 189 190 /* Disable and acknowledge all interrupts */ 191 WR4(sc, MC_INTMASK, 0); 192 WR4(sc, MC_INTSTATUS, MC_INT_INT_MASK); 193} 194 195static int 196tegra_mc_probe(device_t dev) 197{ 198 if (!ofw_bus_status_okay(dev)) 199 return (ENXIO); 200 201 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 202 return (ENXIO); 203 device_set_desc(dev, "Tegra Memory Controller"); 204 return (BUS_PROBE_DEFAULT); 205} 206 207static int 208tegra_mc_attach(device_t dev) 209{ 210 int rv, rid; 211 struct tegra_mc_softc *sc; 212 213 sc = device_get_softc(dev); 214 sc->dev = dev; 215 216 LOCK_INIT(sc); 217 218 /* Get the memory resource for the register mapping. */ 219 rid = 0; 220 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 221 RF_ACTIVE); 222 if (sc->mem_res == NULL) { 223 device_printf(dev, "Cannot map registers.\n"); 224 rv = ENXIO; 225 goto fail; 226 } 227 228 /* Allocate our IRQ resource. */ 229 rid = 0; 230 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 231 RF_ACTIVE); 232 if (sc->irq_res == NULL) { 233 device_printf(dev, "Cannot allocate interrupt.\n"); 234 rv = ENXIO; 235 goto fail; 236 } 237 238 /* OFW resources. */ 239 rv = clk_get_by_ofw_name(dev, 0, "mc", &sc->clk); 240 if (rv != 0) { 241 device_printf(dev, "Cannot get mc clock: %d\n", rv); 242 goto fail; 243 } 244 rv = clk_enable(sc->clk); 245 if (rv != 0) { 246 device_printf(dev, "Cannot enable clock: %d\n", rv); 247 goto fail; 248 } 249 250 /* Init hardware. */ 251 tegra_mc_init_hw(sc); 252 253 /* Setup interrupt */ 254 rv = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 255 NULL, tegra_mc_intr, sc, &sc->irq_h); 256 if (rv) { 257 device_printf(dev, "Cannot setup interrupt.\n"); 258 goto fail; 259 } 260 261 /* Enable Interrupts */ 262 WR4(sc, MC_INTMASK, MC_INT_INT_MASK); 263 264 return (bus_generic_attach(dev)); 265 266fail: 267 if (sc->clk != NULL) 268 clk_release(sc->clk); 269 if (sc->irq_h != NULL) 270 bus_teardown_intr(dev, sc->irq_res, sc->irq_h); 271 if (sc->irq_res != NULL) 272 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 273 if (sc->mem_res != NULL) 274 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 275 LOCK_DESTROY(sc); 276 277 return (rv); 278} 279 280static int 281tegra_mc_detach(device_t dev) 282{ 283 struct tegra_mc_softc *sc; 284 285 sc = device_get_softc(dev); 286 if (sc->irq_h != NULL) 287 bus_teardown_intr(dev, sc->irq_res, sc->irq_h); 288 if (sc->irq_res != NULL) 289 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 290 if (sc->mem_res != NULL) 291 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 292 293 LOCK_DESTROY(sc); 294 return (bus_generic_detach(dev)); 295} 296 297static device_method_t tegra_mc_methods[] = { 298 /* Device interface */ 299 DEVMETHOD(device_probe, tegra_mc_probe), 300 DEVMETHOD(device_attach, tegra_mc_attach), 301 DEVMETHOD(device_detach, tegra_mc_detach), 302 303 304 DEVMETHOD_END 305}; 306 307static devclass_t tegra_mc_devclass; 308static DEFINE_CLASS_0(mc, tegra_mc_driver, tegra_mc_methods, 309 sizeof(struct tegra_mc_softc)); 310DRIVER_MODULE(tegra_mc, simplebus, tegra_mc_driver, tegra_mc_devclass, 311 NULL, NULL); 312