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 /* 29 * Memory controller driver for Tegra SoCs. 30 */ 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/bus.h> 34 #include <sys/kernel.h> 35 #include <sys/limits.h> 36 #include <sys/lock.h> 37 #include <sys/mutex.h> 38 #include <sys/module.h> 39 #include <sys/resource.h> 40 41 #include <machine/bus.h> 42 #include <machine/resource.h> 43 #include <sys/rman.h> 44 45 #include <dev/clk/clk.h> 46 #include <dev/ofw/ofw_bus.h> 47 #include <dev/ofw/ofw_bus_subr.h> 48 49 #include "clock_if.h" 50 51 #define MC_INTSTATUS 0x000 52 #define MC_INTMASK 0x004 53 #define MC_INT_DECERR_MTS (1 << 16) 54 #define MC_INT_SECERR_SEC (1 << 13) 55 #define MC_INT_DECERR_VPR (1 << 12) 56 #define MC_INT_INVALID_APB_ASID_UPDATE (1 << 11) 57 #define MC_INT_INVALID_SMMU_PAGE (1 << 10) 58 #define MC_INT_ARBITRATION_EMEM (1 << 9) 59 #define MC_INT_SECURITY_VIOLATION (1 << 8) 60 #define MC_INT_DECERR_EMEM (1 << 6) 61 #define MC_INT_INT_MASK (MC_INT_DECERR_MTS | \ 62 MC_INT_SECERR_SEC | \ 63 MC_INT_DECERR_VPR | \ 64 MC_INT_INVALID_APB_ASID_UPDATE | \ 65 MC_INT_INVALID_SMMU_PAGE | \ 66 MC_INT_ARBITRATION_EMEM | \ 67 MC_INT_SECURITY_VIOLATION | \ 68 MC_INT_DECERR_EMEM) 69 70 #define MC_ERR_STATUS 0x008 71 #define MC_ERR_TYPE(x) (((x) >> 28) & 0x7) 72 #define MC_ERR_TYPE_DECERR_EMEM 2 73 #define MC_ERR_TYPE_SECURITY_TRUSTZONE 3 74 #define MC_ERR_TYPE_SECURITY_CARVEOUT 4 75 #define MC_ERR_TYPE_INVALID_SMMU_PAGE 6 76 #define MC_ERR_INVALID_SMMU_PAGE_READABLE (1 << 27) 77 #define MC_ERR_INVALID_SMMU_PAGE_WRITABLE (1 << 26) 78 #define MC_ERR_INVALID_SMMU_PAGE_NONSECURE (1 << 25) 79 #define MC_ERR_ADR_HI(x) (((x) >> 20) & 0x3) 80 #define MC_ERR_SWAP (1 << 18) 81 #define MC_ERR_SECURITY (1 << 17) 82 #define MC_ERR_RW (1 << 16) 83 #define MC_ERR_ADR1(x) (((x) >> 12) & 0x7) 84 #define MC_ERR_ID(x) (((x) >> 0) & 07F) 85 86 #define MC_ERR_ADDR 0x00C 87 #define MC_EMEM_CFG 0x050 88 #define MC_EMEM_ADR_CFG 0x054 89 #define MC_EMEM_NUMDEV(x) (((x) >> 0 ) & 0x1) 90 91 #define MC_EMEM_ADR_CFG_DEV0 0x058 92 #define MC_EMEM_ADR_CFG_DEV1 0x05C 93 #define EMEM_DEV_DEVSIZE(x) (((x) >> 16) & 0xF) 94 #define EMEM_DEV_BANKWIDTH(x) (((x) >> 8) & 0x3) 95 #define EMEM_DEV_COLWIDTH(x) (((x) >> 8) & 0x3) 96 97 #define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, (_r), (_v)) 98 #define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_r)) 99 100 #define LOCK(_sc) mtx_lock(&(_sc)->mtx) 101 #define UNLOCK(_sc) mtx_unlock(&(_sc)->mtx) 102 #define SLEEP(_sc, timeout) mtx_sleep(sc, &sc->mtx, 0, "tegra_mc", timeout); 103 #define LOCK_INIT(_sc) \ 104 mtx_init(&_sc->mtx, device_get_nameunit(_sc->dev), "tegra_mc", MTX_DEF) 105 #define LOCK_DESTROY(_sc) mtx_destroy(&_sc->mtx) 106 #define ASSERT_LOCKED(_sc) mtx_assert(&_sc->mtx, MA_OWNED) 107 #define ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->mtx, MA_NOTOWNED) 108 109 static struct ofw_compat_data compat_data[] = { 110 {"nvidia,tegra124-mc", 1}, 111 {"nvidia,tegra210-mc", 1}, 112 {NULL, 0} 113 }; 114 115 struct tegra_mc_softc { 116 device_t dev; 117 struct mtx mtx; 118 119 struct resource *mem_res; 120 struct resource *irq_res; 121 void *irq_h; 122 123 clk_t clk; 124 }; 125 126 static char *smmu_err_tbl[16] = { 127 "reserved", /* 0 */ 128 "reserved", /* 1 */ 129 "DRAM decode", /* 2 */ 130 "Trustzome Security", /* 3 */ 131 "Security carveout", /* 4 */ 132 "reserved", /* 5 */ 133 "Invalid SMMU page", /* 6 */ 134 "reserved", /* 7 */ 135 }; 136 137 static void 138 tegra_mc_intr(void *arg) 139 { 140 struct tegra_mc_softc *sc; 141 uint32_t stat, err; 142 uint64_t addr; 143 144 sc = (struct tegra_mc_softc *)arg; 145 146 stat = RD4(sc, MC_INTSTATUS); 147 if ((stat & MC_INT_INT_MASK) == 0) { 148 WR4(sc, MC_INTSTATUS, stat); 149 return; 150 } 151 152 device_printf(sc->dev, "Memory Controller Interrupt:\n"); 153 if (stat & MC_INT_DECERR_MTS) 154 printf(" - MTS carveout violation\n"); 155 if (stat & MC_INT_SECERR_SEC) 156 printf(" - SEC carveout violation\n"); 157 if (stat & MC_INT_DECERR_VPR) 158 printf(" - VPR requirements violated\n"); 159 if (stat & MC_INT_INVALID_APB_ASID_UPDATE) 160 printf(" - ivalid APB ASID update\n"); 161 if (stat & MC_INT_INVALID_SMMU_PAGE) 162 printf(" - SMMU address translation error\n"); 163 if (stat & MC_INT_ARBITRATION_EMEM) 164 printf(" - arbitration deadlock-prevention threshold hit\n"); 165 if (stat & MC_INT_SECURITY_VIOLATION) 166 printf(" - SMMU address translation security error\n"); 167 if (stat & MC_INT_DECERR_EMEM) 168 printf(" - SMMU address decode error\n"); 169 170 if ((stat & (MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION | 171 MC_INT_DECERR_EMEM)) != 0) { 172 err = RD4(sc, MC_ERR_STATUS); 173 addr = RD4(sc, MC_ERR_STATUS); 174 addr |= (uint64_t)(MC_ERR_ADR_HI(err)) << 32; 175 printf(" at 0x%012jX [%s %s %s] - %s error.\n", 176 (uintmax_t)addr, 177 stat & MC_ERR_SWAP ? "Swap, " : "", 178 stat & MC_ERR_SECURITY ? "Sec, " : "", 179 stat & MC_ERR_RW ? "Write" : "Read", 180 smmu_err_tbl[MC_ERR_TYPE(err)]); 181 } 182 WR4(sc, MC_INTSTATUS, stat); 183 } 184 185 static void 186 tegra_mc_init_hw(struct tegra_mc_softc *sc) 187 { 188 189 /* Disable and acknowledge all interrupts */ 190 WR4(sc, MC_INTMASK, 0); 191 WR4(sc, MC_INTSTATUS, MC_INT_INT_MASK); 192 } 193 194 static int 195 tegra_mc_probe(device_t dev) 196 { 197 if (!ofw_bus_status_okay(dev)) 198 return (ENXIO); 199 200 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 201 return (ENXIO); 202 device_set_desc(dev, "Tegra Memory Controller"); 203 return (BUS_PROBE_DEFAULT); 204 } 205 206 static int 207 tegra_mc_attach(device_t dev) 208 { 209 int rv, rid; 210 struct tegra_mc_softc *sc; 211 212 sc = device_get_softc(dev); 213 sc->dev = dev; 214 215 LOCK_INIT(sc); 216 217 /* Get the memory resource for the register mapping. */ 218 rid = 0; 219 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 220 RF_ACTIVE); 221 if (sc->mem_res == NULL) { 222 device_printf(dev, "Cannot map registers.\n"); 223 rv = ENXIO; 224 goto fail; 225 } 226 227 /* Allocate our IRQ resource. */ 228 rid = 0; 229 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 230 RF_ACTIVE); 231 if (sc->irq_res == NULL) { 232 device_printf(dev, "Cannot allocate interrupt.\n"); 233 rv = ENXIO; 234 goto fail; 235 } 236 237 /* OFW resources. */ 238 rv = clk_get_by_ofw_name(dev, 0, "mc", &sc->clk); 239 if (rv != 0) { 240 device_printf(dev, "Cannot get mc clock: %d\n", rv); 241 goto fail; 242 } 243 rv = clk_enable(sc->clk); 244 if (rv != 0) { 245 device_printf(dev, "Cannot enable clock: %d\n", rv); 246 goto fail; 247 } 248 249 /* Init hardware. */ 250 tegra_mc_init_hw(sc); 251 252 /* Setup interrupt */ 253 rv = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 254 NULL, tegra_mc_intr, sc, &sc->irq_h); 255 if (rv) { 256 device_printf(dev, "Cannot setup interrupt.\n"); 257 goto fail; 258 } 259 260 /* Enable Interrupts */ 261 WR4(sc, MC_INTMASK, MC_INT_INT_MASK); 262 263 return (bus_generic_attach(dev)); 264 265 fail: 266 if (sc->clk != NULL) 267 clk_release(sc->clk); 268 if (sc->irq_h != NULL) 269 bus_teardown_intr(dev, sc->irq_res, sc->irq_h); 270 if (sc->irq_res != NULL) 271 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 272 if (sc->mem_res != NULL) 273 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 274 LOCK_DESTROY(sc); 275 276 return (rv); 277 } 278 279 static int 280 tegra_mc_detach(device_t dev) 281 { 282 struct tegra_mc_softc *sc; 283 284 sc = device_get_softc(dev); 285 if (sc->irq_h != NULL) 286 bus_teardown_intr(dev, sc->irq_res, sc->irq_h); 287 if (sc->irq_res != NULL) 288 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 289 if (sc->mem_res != NULL) 290 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 291 292 LOCK_DESTROY(sc); 293 return (bus_generic_detach(dev)); 294 } 295 296 static device_method_t tegra_mc_methods[] = { 297 /* Device interface */ 298 DEVMETHOD(device_probe, tegra_mc_probe), 299 DEVMETHOD(device_attach, tegra_mc_attach), 300 DEVMETHOD(device_detach, tegra_mc_detach), 301 302 DEVMETHOD_END 303 }; 304 305 static DEFINE_CLASS_0(mc, tegra_mc_driver, tegra_mc_methods, 306 sizeof(struct tegra_mc_softc)); 307 DRIVER_MODULE(tegra_mc, simplebus, tegra_mc_driver, NULL, NULL); 308