1 /* $NetBSD: tegra_nouveau.c,v 1.9 2015/12/22 22:10:36 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.9 2015/12/22 22:10:36 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 44 #include <dev/fdt/fdtvar.h> 45 46 #include <drm/drmP.h> 47 #include <engine/device.h> 48 49 extern char *nouveau_config; 50 extern char *nouveau_debug; 51 extern struct drm_driver *const nouveau_drm_driver; 52 53 static int tegra_nouveau_match(device_t, cfdata_t, void *); 54 static void tegra_nouveau_attach(device_t, device_t, void *); 55 56 struct tegra_nouveau_softc { 57 device_t sc_dev; 58 bus_space_tag_t sc_bst; 59 bus_dma_tag_t sc_dmat; 60 int sc_phandle; 61 struct clk *sc_clk_gpu; 62 struct clk *sc_clk_pwr; 63 struct fdtbus_reset *sc_rst_gpu; 64 struct drm_device *sc_drm_dev; 65 struct platform_device sc_platform_dev; 66 struct nouveau_device *sc_nv_dev; 67 }; 68 69 static void tegra_nouveau_init(device_t); 70 71 static int tegra_nouveau_get_irq(struct drm_device *); 72 static const char *tegra_nouveau_get_name(struct drm_device *); 73 static int tegra_nouveau_set_busid(struct drm_device *, 74 struct drm_master *); 75 static int tegra_nouveau_irq_install(struct drm_device *, 76 irqreturn_t (*)(void *), 77 int, const char *, void *, 78 struct drm_bus_irq_cookie **); 79 static void tegra_nouveau_irq_uninstall(struct drm_device *, 80 struct drm_bus_irq_cookie *); 81 82 static struct drm_bus drm_tegra_nouveau_bus = { 83 .bus_type = DRIVER_BUS_PLATFORM, 84 .get_irq = tegra_nouveau_get_irq, 85 .get_name = tegra_nouveau_get_name, 86 .set_busid = tegra_nouveau_set_busid, 87 .irq_install = tegra_nouveau_irq_install, 88 .irq_uninstall = tegra_nouveau_irq_uninstall 89 }; 90 91 CFATTACH_DECL_NEW(tegra_nouveau, sizeof(struct tegra_nouveau_softc), 92 tegra_nouveau_match, tegra_nouveau_attach, NULL, NULL); 93 94 static int 95 tegra_nouveau_match(device_t parent, cfdata_t cf, void *aux) 96 { 97 const char * const compatible[] = { "nvidia,gk20a", NULL }; 98 struct fdt_attach_args * const faa = aux; 99 100 return of_match_compatible(faa->faa_phandle, compatible); 101 } 102 103 static void 104 tegra_nouveau_attach(device_t parent, device_t self, void *aux) 105 { 106 struct tegra_nouveau_softc * const sc = device_private(self); 107 struct fdt_attach_args * const faa = aux; 108 prop_dictionary_t prop = device_properties(self); 109 int error; 110 111 sc->sc_dev = self; 112 sc->sc_bst = faa->faa_bst; 113 sc->sc_dmat = faa->faa_dmat; 114 sc->sc_phandle = faa->faa_phandle; 115 116 sc->sc_clk_gpu = fdtbus_clock_get(faa->faa_phandle, "gpu"); 117 if (sc->sc_clk_gpu == NULL) { 118 aprint_error(": couldn't get clock gpu\n"); 119 return; 120 } 121 sc->sc_clk_pwr = fdtbus_clock_get(faa->faa_phandle, "pwr"); 122 if (sc->sc_clk_pwr == NULL) { 123 aprint_error(": couldn't get clock pwr\n"); 124 return; 125 } 126 sc->sc_rst_gpu = fdtbus_reset_get(faa->faa_phandle, "gpu"); 127 if (sc->sc_rst_gpu == NULL) { 128 aprint_error(": couldn't get reset gpu\n"); 129 return; 130 } 131 132 aprint_naive("\n"); 133 aprint_normal(": GPU\n"); 134 135 prop_dictionary_get_cstring(prop, "debug", &nouveau_debug); 136 prop_dictionary_get_cstring(prop, "config", &nouveau_config); 137 138 fdtbus_reset_assert(sc->sc_rst_gpu); 139 error = clk_set_rate(sc->sc_clk_pwr, 204000000); 140 if (error) { 141 aprint_error_dev(self, "couldn't set clock pwr frequency: %d\n", 142 error); 143 return; 144 } 145 error = clk_enable(sc->sc_clk_pwr); 146 if (error) { 147 aprint_error_dev(self, "couldn't enable clock pwr: %d\n", 148 error); 149 return; 150 } 151 error = clk_enable(sc->sc_clk_gpu); 152 if (error) { 153 aprint_error_dev(self, "couldn't enable clock gpu: %d\n", 154 error); 155 return; 156 } 157 tegra_pmc_remove_clamping(PMC_PARTID_TD); 158 fdtbus_reset_deassert(sc->sc_rst_gpu); 159 160 error = -nouveau_device_create(&sc->sc_platform_dev, 161 NOUVEAU_BUS_PLATFORM, -1, device_xname(self), 162 nouveau_config, nouveau_debug, &sc->sc_nv_dev); 163 if (error) { 164 aprint_error_dev(self, "couldn't create nouveau device: %d\n", 165 error); 166 return; 167 } 168 169 config_mountroot(self, tegra_nouveau_init); 170 } 171 172 static void 173 tegra_nouveau_init(device_t self) 174 { 175 struct tegra_nouveau_softc * const sc = device_private(self); 176 struct drm_driver * const driver = nouveau_drm_driver; 177 struct drm_device *dev; 178 bus_addr_t addr[2], size[2]; 179 int error; 180 181 if (fdtbus_get_reg(sc->sc_phandle, 0, &addr[0], &size[0]) != 0 || 182 fdtbus_get_reg(sc->sc_phandle, 1, &addr[1], &size[1]) != 0) { 183 aprint_error(": couldn't get registers\n"); 184 return; 185 } 186 187 driver->kdriver.platform_device = &sc->sc_platform_dev; 188 driver->bus = &drm_tegra_nouveau_bus; 189 190 dev = drm_dev_alloc(driver, sc->sc_dev); 191 if (dev == NULL) { 192 aprint_error_dev(self, "couldn't allocate DRM device\n"); 193 return; 194 } 195 dev->bst = sc->sc_bst; 196 dev->bus_dmat = sc->sc_dmat; 197 dev->dmat = dev->bus_dmat; 198 dev->dmat_subregion_p = false; 199 dev->platformdev = &sc->sc_platform_dev; 200 201 dev->platformdev->id = -1; 202 dev->platformdev->pd_dev = sc->sc_dev; 203 dev->platformdev->dmat = sc->sc_dmat; 204 dev->platformdev->nresource = 2; 205 dev->platformdev->resource[0].tag = sc->sc_bst; 206 dev->platformdev->resource[0].start = addr[0]; 207 dev->platformdev->resource[0].len = size[0]; 208 dev->platformdev->resource[1].tag = sc->sc_bst; 209 dev->platformdev->resource[1].start = addr[1]; 210 dev->platformdev->resource[1].len = size[1]; 211 212 error = -drm_dev_register(dev, 0); 213 if (error) { 214 drm_dev_unref(dev); 215 aprint_error_dev(self, "couldn't register DRM device: %d\n", 216 error); 217 return; 218 } 219 220 aprint_normal_dev(self, "initialized %s %d.%d.%d %s on minor %d\n", 221 driver->name, driver->major, driver->minor, driver->patchlevel, 222 driver->date, dev->primary->index); 223 } 224 225 static int 226 tegra_nouveau_get_irq(struct drm_device *dev) 227 { 228 return TEGRA_INTR_GPU; 229 } 230 231 static const char *tegra_nouveau_get_name(struct drm_device *dev) 232 { 233 return "tegra_nouveau"; 234 } 235 236 static int 237 tegra_nouveau_set_busid(struct drm_device *dev, struct drm_master *master) 238 { 239 int id; 240 241 id = dev->platformdev->id; 242 if (id < 0) 243 id = 0; 244 245 master->unique = kmem_asprintf("platform:tegra_nouveau:%02d", id); 246 if (master->unique == NULL) 247 return -ENOMEM; 248 master->unique_len = strlen(master->unique); 249 250 return 0; 251 } 252 253 static int 254 tegra_nouveau_irq_install(struct drm_device *dev, 255 irqreturn_t (*handler)(void *), int flags, const char *name, void *arg, 256 struct drm_bus_irq_cookie **cookiep) 257 { 258 struct tegra_nouveau_softc * const sc = device_private(dev->dev); 259 char intrstr[128]; 260 char *inames, *p; 261 u_int index; 262 void *ih; 263 int len, resid; 264 265 len = OF_getproplen(sc->sc_phandle, "interrupt-names"); 266 if (len <= 0) { 267 aprint_error_dev(dev->dev, "no interrupt-names property\n"); 268 return -EIO; 269 } 270 271 inames = kmem_alloc(len, KM_SLEEP); 272 if (OF_getprop(sc->sc_phandle, "interrupt-names", inames, len) != len) { 273 aprint_error_dev(dev->dev, "failed to get interrupt-names\n"); 274 kmem_free(inames, len); 275 return -EIO; 276 } 277 p = inames; 278 resid = len; 279 index = 0; 280 while (resid > 0) { 281 if (strcmp(name, p) == 0) 282 break; 283 const int slen = strlen(p) + 1; 284 p += slen; 285 len -= slen; 286 ++index; 287 } 288 kmem_free(inames, len); 289 if (len == 0) { 290 aprint_error_dev(dev->dev, "unknown interrupt name '%s'\n", 291 name); 292 return -EINVAL; 293 } 294 295 if (!fdtbus_intr_str(sc->sc_phandle, index, intrstr, sizeof(intrstr))) { 296 aprint_error_dev(dev->dev, "failed to decode interrupt\n"); 297 return -ENXIO; 298 } 299 300 ih = fdtbus_intr_establish(sc->sc_phandle, index, IPL_DRM, 301 FDT_INTR_MPSAFE, handler, arg); 302 if (ih == NULL) { 303 aprint_error_dev(dev->dev, 304 "failed to establish interrupt on %s\n", intrstr); 305 return -ENOENT; 306 } 307 308 aprint_normal_dev(dev->dev, "interrupting on %s\n", intrstr); 309 310 *cookiep = (struct drm_bus_irq_cookie *)ih; 311 return 0; 312 } 313 314 static void 315 tegra_nouveau_irq_uninstall(struct drm_device *dev, 316 struct drm_bus_irq_cookie *cookie) 317 { 318 struct tegra_nouveau_softc * const sc = device_private(dev->dev); 319 320 fdtbus_intr_disestablish(sc->sc_phandle, cookie); 321 } 322