1 /* $NetBSD: tegra_nouveau.c,v 1.10 2017/05/30 22:00:25 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 2015 Jared D. McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: tegra_nouveau.c,v 1.10 2017/05/30 22:00:25 jmcneill Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/bus.h> 34 #include <sys/device.h> 35 #include <sys/intr.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/module.h> 39 40 #include <arm/nvidia/tegra_reg.h> 41 #include <arm/nvidia/tegra_pmcreg.h> 42 #include <arm/nvidia/tegra_var.h> 43 #include <arm/nvidia/tegra_intr.h> 44 45 #include <dev/fdt/fdtvar.h> 46 47 #include <drm/drmP.h> 48 #include <engine/device.h> 49 50 extern char *nouveau_config; 51 extern char *nouveau_debug; 52 extern struct drm_driver *const nouveau_drm_driver; 53 54 static int tegra_nouveau_match(device_t, cfdata_t, void *); 55 static void tegra_nouveau_attach(device_t, device_t, void *); 56 57 struct tegra_nouveau_softc { 58 device_t sc_dev; 59 bus_space_tag_t sc_bst; 60 bus_dma_tag_t sc_dmat; 61 int sc_phandle; 62 struct clk *sc_clk_gpu; 63 struct clk *sc_clk_pwr; 64 struct fdtbus_reset *sc_rst_gpu; 65 struct drm_device *sc_drm_dev; 66 struct platform_device sc_platform_dev; 67 struct nouveau_device *sc_nv_dev; 68 }; 69 70 static void tegra_nouveau_init(device_t); 71 72 static int tegra_nouveau_get_irq(struct drm_device *); 73 static const char *tegra_nouveau_get_name(struct drm_device *); 74 static int tegra_nouveau_set_busid(struct drm_device *, 75 struct drm_master *); 76 static int tegra_nouveau_irq_install(struct drm_device *, 77 irqreturn_t (*)(void *), 78 int, const char *, void *, 79 struct drm_bus_irq_cookie **); 80 static void tegra_nouveau_irq_uninstall(struct drm_device *, 81 struct drm_bus_irq_cookie *); 82 83 static struct drm_bus drm_tegra_nouveau_bus = { 84 .bus_type = DRIVER_BUS_PLATFORM, 85 .get_irq = tegra_nouveau_get_irq, 86 .get_name = tegra_nouveau_get_name, 87 .set_busid = tegra_nouveau_set_busid, 88 .irq_install = tegra_nouveau_irq_install, 89 .irq_uninstall = tegra_nouveau_irq_uninstall 90 }; 91 92 CFATTACH_DECL_NEW(tegra_nouveau, sizeof(struct tegra_nouveau_softc), 93 tegra_nouveau_match, tegra_nouveau_attach, NULL, NULL); 94 95 static int 96 tegra_nouveau_match(device_t parent, cfdata_t cf, void *aux) 97 { 98 const char * const compatible[] = { "nvidia,gk20a", NULL }; 99 struct fdt_attach_args * const faa = aux; 100 101 return of_match_compatible(faa->faa_phandle, compatible); 102 } 103 104 static void 105 tegra_nouveau_attach(device_t parent, device_t self, void *aux) 106 { 107 struct tegra_nouveau_softc * const sc = device_private(self); 108 struct fdt_attach_args * const faa = aux; 109 prop_dictionary_t prop = device_properties(self); 110 int error; 111 112 sc->sc_dev = self; 113 sc->sc_bst = faa->faa_bst; 114 sc->sc_dmat = faa->faa_dmat; 115 sc->sc_phandle = faa->faa_phandle; 116 117 sc->sc_clk_gpu = fdtbus_clock_get(faa->faa_phandle, "gpu"); 118 if (sc->sc_clk_gpu == NULL) { 119 aprint_error(": couldn't get clock gpu\n"); 120 return; 121 } 122 sc->sc_clk_pwr = fdtbus_clock_get(faa->faa_phandle, "pwr"); 123 if (sc->sc_clk_pwr == NULL) { 124 aprint_error(": couldn't get clock pwr\n"); 125 return; 126 } 127 sc->sc_rst_gpu = fdtbus_reset_get(faa->faa_phandle, "gpu"); 128 if (sc->sc_rst_gpu == NULL) { 129 aprint_error(": couldn't get reset gpu\n"); 130 return; 131 } 132 133 aprint_naive("\n"); 134 aprint_normal(": GPU\n"); 135 136 prop_dictionary_get_cstring(prop, "debug", &nouveau_debug); 137 prop_dictionary_get_cstring(prop, "config", &nouveau_config); 138 139 fdtbus_reset_assert(sc->sc_rst_gpu); 140 error = clk_set_rate(sc->sc_clk_pwr, 204000000); 141 if (error) { 142 aprint_error_dev(self, "couldn't set clock pwr frequency: %d\n", 143 error); 144 return; 145 } 146 error = clk_enable(sc->sc_clk_pwr); 147 if (error) { 148 aprint_error_dev(self, "couldn't enable clock pwr: %d\n", 149 error); 150 return; 151 } 152 error = clk_enable(sc->sc_clk_gpu); 153 if (error) { 154 aprint_error_dev(self, "couldn't enable clock gpu: %d\n", 155 error); 156 return; 157 } 158 tegra_pmc_remove_clamping(PMC_PARTID_TD); 159 fdtbus_reset_deassert(sc->sc_rst_gpu); 160 161 error = -nouveau_device_create(&sc->sc_platform_dev, 162 NOUVEAU_BUS_PLATFORM, -1, device_xname(self), 163 nouveau_config, nouveau_debug, &sc->sc_nv_dev); 164 if (error) { 165 aprint_error_dev(self, "couldn't create nouveau device: %d\n", 166 error); 167 return; 168 } 169 170 config_mountroot(self, tegra_nouveau_init); 171 } 172 173 static void 174 tegra_nouveau_init(device_t self) 175 { 176 struct tegra_nouveau_softc * const sc = device_private(self); 177 struct drm_driver * const driver = nouveau_drm_driver; 178 struct drm_device *dev; 179 bus_addr_t addr[2], size[2]; 180 int error; 181 182 if (fdtbus_get_reg(sc->sc_phandle, 0, &addr[0], &size[0]) != 0 || 183 fdtbus_get_reg(sc->sc_phandle, 1, &addr[1], &size[1]) != 0) { 184 aprint_error(": couldn't get registers\n"); 185 return; 186 } 187 188 driver->kdriver.platform_device = &sc->sc_platform_dev; 189 driver->bus = &drm_tegra_nouveau_bus; 190 191 dev = drm_dev_alloc(driver, sc->sc_dev); 192 if (dev == NULL) { 193 aprint_error_dev(self, "couldn't allocate DRM device\n"); 194 return; 195 } 196 dev->bst = sc->sc_bst; 197 dev->bus_dmat = sc->sc_dmat; 198 dev->dmat = dev->bus_dmat; 199 dev->dmat_subregion_p = false; 200 dev->platformdev = &sc->sc_platform_dev; 201 202 dev->platformdev->id = -1; 203 dev->platformdev->pd_dev = sc->sc_dev; 204 dev->platformdev->dmat = sc->sc_dmat; 205 dev->platformdev->nresource = 2; 206 dev->platformdev->resource[0].tag = sc->sc_bst; 207 dev->platformdev->resource[0].start = addr[0]; 208 dev->platformdev->resource[0].len = size[0]; 209 dev->platformdev->resource[1].tag = sc->sc_bst; 210 dev->platformdev->resource[1].start = addr[1]; 211 dev->platformdev->resource[1].len = size[1]; 212 213 error = -drm_dev_register(dev, 0); 214 if (error) { 215 drm_dev_unref(dev); 216 aprint_error_dev(self, "couldn't register DRM device: %d\n", 217 error); 218 return; 219 } 220 221 aprint_normal_dev(self, "initialized %s %d.%d.%d %s on minor %d\n", 222 driver->name, driver->major, driver->minor, driver->patchlevel, 223 driver->date, dev->primary->index); 224 } 225 226 static int 227 tegra_nouveau_get_irq(struct drm_device *dev) 228 { 229 return TEGRA_INTR_GPU; 230 } 231 232 static const char *tegra_nouveau_get_name(struct drm_device *dev) 233 { 234 return "tegra_nouveau"; 235 } 236 237 static int 238 tegra_nouveau_set_busid(struct drm_device *dev, struct drm_master *master) 239 { 240 int id; 241 242 id = dev->platformdev->id; 243 if (id < 0) 244 id = 0; 245 246 master->unique = kmem_asprintf("platform:tegra_nouveau:%02d", id); 247 if (master->unique == NULL) 248 return -ENOMEM; 249 master->unique_len = strlen(master->unique); 250 251 return 0; 252 } 253 254 static int 255 tegra_nouveau_irq_install(struct drm_device *dev, 256 irqreturn_t (*handler)(void *), int flags, const char *name, void *arg, 257 struct drm_bus_irq_cookie **cookiep) 258 { 259 struct tegra_nouveau_softc * const sc = device_private(dev->dev); 260 char intrstr[128]; 261 char *inames, *p; 262 u_int index; 263 void *ih; 264 int len, resid; 265 266 len = OF_getproplen(sc->sc_phandle, "interrupt-names"); 267 if (len <= 0) { 268 aprint_error_dev(dev->dev, "no interrupt-names property\n"); 269 return -EIO; 270 } 271 272 inames = kmem_alloc(len, KM_SLEEP); 273 if (OF_getprop(sc->sc_phandle, "interrupt-names", inames, len) != len) { 274 aprint_error_dev(dev->dev, "failed to get interrupt-names\n"); 275 kmem_free(inames, len); 276 return -EIO; 277 } 278 p = inames; 279 resid = len; 280 index = 0; 281 while (resid > 0) { 282 if (strcmp(name, p) == 0) 283 break; 284 const int slen = strlen(p) + 1; 285 p += slen; 286 len -= slen; 287 ++index; 288 } 289 kmem_free(inames, len); 290 if (len == 0) { 291 aprint_error_dev(dev->dev, "unknown interrupt name '%s'\n", 292 name); 293 return -EINVAL; 294 } 295 296 if (!fdtbus_intr_str(sc->sc_phandle, index, intrstr, sizeof(intrstr))) { 297 aprint_error_dev(dev->dev, "failed to decode interrupt\n"); 298 return -ENXIO; 299 } 300 301 ih = fdtbus_intr_establish(sc->sc_phandle, index, IPL_DRM, 302 FDT_INTR_MPSAFE, handler, arg); 303 if (ih == NULL) { 304 aprint_error_dev(dev->dev, 305 "failed to establish interrupt on %s\n", intrstr); 306 return -ENOENT; 307 } 308 309 aprint_normal_dev(dev->dev, "interrupting on %s\n", intrstr); 310 311 *cookiep = (struct drm_bus_irq_cookie *)ih; 312 return 0; 313 } 314 315 static void 316 tegra_nouveau_irq_uninstall(struct drm_device *dev, 317 struct drm_bus_irq_cookie *cookie) 318 { 319 struct tegra_nouveau_softc * const sc = device_private(dev->dev); 320 321 fdtbus_intr_disestablish(sc->sc_phandle, cookie); 322 } 323