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 {NULL, 0} 114 }; 115 116 struct 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 127 static 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 138 static void 139 tegra_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 186 static void 187 tegra_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 195 static int 196 tegra_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 207 static int 208 tegra_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 266 fail: 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 280 static int 281 tegra_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 297 static 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 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