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$"); 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 111 static struct ofw_compat_data compat_data[] = { 112 {"nvidia,tegra124-mc", 1}, 113 {"nvidia,tegra210-mc", 1}, 114 {NULL, 0} 115 }; 116 117 struct tegra_mc_softc { 118 device_t dev; 119 struct mtx mtx; 120 121 struct resource *mem_res; 122 struct resource *irq_res; 123 void *irq_h; 124 125 clk_t clk; 126 }; 127 128 static char *smmu_err_tbl[16] = { 129 "reserved", /* 0 */ 130 "reserved", /* 1 */ 131 "DRAM decode", /* 2 */ 132 "Trustzome Security", /* 3 */ 133 "Security carveout", /* 4 */ 134 "reserved", /* 5 */ 135 "Invalid SMMU page", /* 6 */ 136 "reserved", /* 7 */ 137 }; 138 139 static void 140 tegra_mc_intr(void *arg) 141 { 142 struct tegra_mc_softc *sc; 143 uint32_t stat, err; 144 uint64_t addr; 145 146 sc = (struct tegra_mc_softc *)arg; 147 148 stat = RD4(sc, MC_INTSTATUS); 149 if ((stat & MC_INT_INT_MASK) == 0) { 150 WR4(sc, MC_INTSTATUS, stat); 151 return; 152 } 153 154 device_printf(sc->dev, "Memory Controller Interrupt:\n"); 155 if (stat & MC_INT_DECERR_MTS) 156 printf(" - MTS carveout violation\n"); 157 if (stat & MC_INT_SECERR_SEC) 158 printf(" - SEC carveout violation\n"); 159 if (stat & MC_INT_DECERR_VPR) 160 printf(" - VPR requirements violated\n"); 161 if (stat & MC_INT_INVALID_APB_ASID_UPDATE) 162 printf(" - ivalid APB ASID update\n"); 163 if (stat & MC_INT_INVALID_SMMU_PAGE) 164 printf(" - SMMU address translation error\n"); 165 if (stat & MC_INT_ARBITRATION_EMEM) 166 printf(" - arbitration deadlock-prevention threshold hit\n"); 167 if (stat & MC_INT_SECURITY_VIOLATION) 168 printf(" - SMMU address translation security error\n"); 169 if (stat & MC_INT_DECERR_EMEM) 170 printf(" - SMMU address decode error\n"); 171 172 if ((stat & (MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION | 173 MC_INT_DECERR_EMEM)) != 0) { 174 err = RD4(sc, MC_ERR_STATUS); 175 addr = RD4(sc, MC_ERR_STATUS); 176 addr |= (uint64_t)(MC_ERR_ADR_HI(err)) << 32; 177 printf(" at 0x%012jX [%s %s %s] - %s error.\n", 178 (uintmax_t)addr, 179 stat & MC_ERR_SWAP ? "Swap, " : "", 180 stat & MC_ERR_SECURITY ? "Sec, " : "", 181 stat & MC_ERR_RW ? "Write" : "Read", 182 smmu_err_tbl[MC_ERR_TYPE(err)]); 183 } 184 WR4(sc, MC_INTSTATUS, stat); 185 } 186 187 static void 188 tegra_mc_init_hw(struct tegra_mc_softc *sc) 189 { 190 191 /* Disable and acknowledge all interrupts */ 192 WR4(sc, MC_INTMASK, 0); 193 WR4(sc, MC_INTSTATUS, MC_INT_INT_MASK); 194 } 195 196 static int 197 tegra_mc_probe(device_t dev) 198 { 199 if (!ofw_bus_status_okay(dev)) 200 return (ENXIO); 201 202 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 203 return (ENXIO); 204 device_set_desc(dev, "Tegra Memory Controller"); 205 return (BUS_PROBE_DEFAULT); 206 } 207 208 static int 209 tegra_mc_attach(device_t dev) 210 { 211 int rv, rid; 212 struct tegra_mc_softc *sc; 213 214 sc = device_get_softc(dev); 215 sc->dev = dev; 216 217 LOCK_INIT(sc); 218 219 /* Get the memory resource for the register mapping. */ 220 rid = 0; 221 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 222 RF_ACTIVE); 223 if (sc->mem_res == NULL) { 224 device_printf(dev, "Cannot map registers.\n"); 225 rv = ENXIO; 226 goto fail; 227 } 228 229 /* Allocate our IRQ resource. */ 230 rid = 0; 231 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 232 RF_ACTIVE); 233 if (sc->irq_res == NULL) { 234 device_printf(dev, "Cannot allocate interrupt.\n"); 235 rv = ENXIO; 236 goto fail; 237 } 238 239 /* OFW resources. */ 240 rv = clk_get_by_ofw_name(dev, 0, "mc", &sc->clk); 241 if (rv != 0) { 242 device_printf(dev, "Cannot get mc clock: %d\n", rv); 243 goto fail; 244 } 245 rv = clk_enable(sc->clk); 246 if (rv != 0) { 247 device_printf(dev, "Cannot enable clock: %d\n", rv); 248 goto fail; 249 } 250 251 /* Init hardware. */ 252 tegra_mc_init_hw(sc); 253 254 /* Setup interrupt */ 255 rv = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 256 NULL, tegra_mc_intr, sc, &sc->irq_h); 257 if (rv) { 258 device_printf(dev, "Cannot setup interrupt.\n"); 259 goto fail; 260 } 261 262 /* Enable Interrupts */ 263 WR4(sc, MC_INTMASK, MC_INT_INT_MASK); 264 265 return (bus_generic_attach(dev)); 266 267 fail: 268 if (sc->clk != NULL) 269 clk_release(sc->clk); 270 if (sc->irq_h != NULL) 271 bus_teardown_intr(dev, sc->irq_res, sc->irq_h); 272 if (sc->irq_res != NULL) 273 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 274 if (sc->mem_res != NULL) 275 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 276 LOCK_DESTROY(sc); 277 278 return (rv); 279 } 280 281 static int 282 tegra_mc_detach(device_t dev) 283 { 284 struct tegra_mc_softc *sc; 285 286 sc = device_get_softc(dev); 287 if (sc->irq_h != NULL) 288 bus_teardown_intr(dev, sc->irq_res, sc->irq_h); 289 if (sc->irq_res != NULL) 290 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 291 if (sc->mem_res != NULL) 292 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 293 294 LOCK_DESTROY(sc); 295 return (bus_generic_detach(dev)); 296 } 297 298 static device_method_t tegra_mc_methods[] = { 299 /* Device interface */ 300 DEVMETHOD(device_probe, tegra_mc_probe), 301 DEVMETHOD(device_attach, tegra_mc_attach), 302 DEVMETHOD(device_detach, tegra_mc_detach), 303 304 DEVMETHOD_END 305 }; 306 307 static devclass_t tegra_mc_devclass; 308 static DEFINE_CLASS_0(mc, tegra_mc_driver, tegra_mc_methods, 309 sizeof(struct tegra_mc_softc)); 310 DRIVER_MODULE(tegra_mc, simplebus, tegra_mc_driver, tegra_mc_devclass, 311 NULL, NULL); 312