tegra_nouveau.c revision 1.13
1/* $NetBSD: tegra_nouveau.c,v 1.13 2021/01/15 23:11:59 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.13 2021/01/15 23:11:59 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 <core/tegra.h> 49#include <nvkm/engine/device/priv.h> 50#include <nvkm/subdev/mc/priv.h> 51 52extern char *nouveau_config; 53extern char *nouveau_debug; 54extern struct drm_driver *const nouveau_drm_driver_stub; /* XXX */ 55extern struct drm_driver *const nouveau_drm_driver_platform; /* XXX */ 56static bool nouveau_driver_initialized = false; /* XXX */ 57 58static int tegra_nouveau_match(device_t, cfdata_t, void *); 59static void tegra_nouveau_attach(device_t, device_t, void *); 60 61struct tegra_nouveau_softc { 62 device_t sc_dev; 63 bus_space_tag_t sc_bst; 64 struct { 65 bus_addr_t addr; 66 bus_size_t size; 67 } sc_resources[2]; 68 bus_dma_tag_t sc_dmat; 69 int sc_phandle; 70 void *sc_ih; 71 struct clk *sc_clk_gpu; 72 struct clk *sc_clk_pwr; 73 struct fdtbus_reset *sc_rst_gpu; 74 struct drm_device *sc_drm_dev; 75 struct nvkm_device sc_nv_dev; 76}; 77 78static void tegra_nouveau_init(device_t); 79 80static int tegra_nouveau_set_busid(struct drm_device *, 81 struct drm_master *); 82 83static int tegra_nouveau_intr(void *); 84 85static int nvkm_device_tegra_init(struct nvkm_device *); 86static void nvkm_device_tegra_fini(struct nvkm_device *, bool); 87 88static bus_space_tag_t 89 nvkm_device_tegra_resource_tag(struct nvkm_device *, unsigned); 90static bus_addr_t 91 nvkm_device_tegra_resource_addr(struct nvkm_device *, unsigned); 92static bus_size_t 93 nvkm_device_tegra_resource_size(struct nvkm_device *, unsigned); 94 95CFATTACH_DECL_NEW(tegra_nouveau, sizeof(struct tegra_nouveau_softc), 96 tegra_nouveau_match, tegra_nouveau_attach, NULL, NULL); 97 98static const struct nvkm_device_func nvkm_device_tegra_func = { 99 .tegra = NULL, /* XXX */ 100 .dtor = NULL, 101 .init = nvkm_device_tegra_init, 102 .fini = nvkm_device_tegra_fini, 103 .resource_tag = nvkm_device_tegra_resource_tag, 104 .resource_addr = nvkm_device_tegra_resource_addr, 105 .resource_size = nvkm_device_tegra_resource_size, 106 .cpu_coherent = false, 107}; 108 109static const struct nvkm_device_tegra_func gk20a_platform_data = { 110 .iommu_bit = 34, 111}; 112 113static const struct of_compat_data compat_data[] = { 114 { "nvidia,gk20a", (uintptr_t)&gk20a_platform_data }, 115 { "nvidia,gm20b", (uintptr_t)&gk20a_platform_data }, 116 { NULL, 0 }, 117}; 118 119static int 120tegra_nouveau_match(device_t parent, cfdata_t cf, void *aux) 121{ 122 struct fdt_attach_args * const faa = aux; 123 124 return of_match_compat_data(faa->faa_phandle, compat_data); 125} 126 127static void 128tegra_nouveau_attach(device_t parent, device_t self, void *aux) 129{ 130 struct tegra_nouveau_softc * const sc = device_private(self); 131 struct fdt_attach_args * const faa = aux; 132 prop_dictionary_t prop = device_properties(self); 133 const struct of_compat_data *data = 134 of_search_compatible(faa->faa_phandle, compat_data); 135 const struct nvkm_device_tegra_func *tegra_func __diagused = 136 (const void *)data->data; 137 int error; 138 139 KASSERT(tegra_func != NULL); 140 141 if (!nouveau_driver_initialized) { 142 *nouveau_drm_driver_platform = *nouveau_drm_driver_stub; 143 nouveau_drm_driver_platform->set_busid = 144 tegra_nouveau_set_busid; 145 nouveau_driver_initialized = true; 146 } 147 148 sc->sc_dev = self; 149 sc->sc_bst = faa->faa_bst; 150 sc->sc_dmat = faa->faa_dmat; 151 sc->sc_phandle = faa->faa_phandle; 152 153 sc->sc_clk_gpu = fdtbus_clock_get(faa->faa_phandle, "gpu"); 154 if (sc->sc_clk_gpu == NULL) { 155 aprint_error(": couldn't get clock gpu\n"); 156 return; 157 } 158 sc->sc_clk_pwr = fdtbus_clock_get(faa->faa_phandle, "pwr"); 159 if (sc->sc_clk_pwr == NULL) { 160 aprint_error(": couldn't get clock pwr\n"); 161 return; 162 } 163 sc->sc_rst_gpu = fdtbus_reset_get(faa->faa_phandle, "gpu"); 164 if (sc->sc_rst_gpu == NULL) { 165 aprint_error(": couldn't get reset gpu\n"); 166 return; 167 } 168 169 aprint_naive("\n"); 170 aprint_normal(": GPU\n"); 171 172 prop_dictionary_get_cstring(prop, "debug", &nouveau_debug); 173 prop_dictionary_get_cstring(prop, "config", &nouveau_config); 174 175 fdtbus_reset_assert(sc->sc_rst_gpu); 176 error = clk_set_rate(sc->sc_clk_pwr, 204000000); 177 if (error) { 178 aprint_error_dev(self, "couldn't set clock pwr frequency: %d\n", 179 error); 180 return; 181 } 182 error = clk_enable(sc->sc_clk_pwr); 183 if (error) { 184 aprint_error_dev(self, "couldn't enable clock pwr: %d\n", 185 error); 186 return; 187 } 188 error = clk_enable(sc->sc_clk_gpu); 189 if (error) { 190 aprint_error_dev(self, "couldn't enable clock gpu: %d\n", 191 error); 192 return; 193 } 194 tegra_pmc_remove_clamping(PMC_PARTID_TD); 195 fdtbus_reset_deassert(sc->sc_rst_gpu); 196 197 error = -nvkm_device_ctor(&nvkm_device_tegra_func, NULL, self, 198 NVKM_DEVICE_TEGRA, -1, device_xname(self), 199 nouveau_config, nouveau_debug, true, true, ~0ULL, &sc->sc_nv_dev); 200 if (error) { 201 aprint_error_dev(self, "couldn't create nouveau device: %d\n", 202 error); 203 return; 204 } 205 206 config_mountroot(self, tegra_nouveau_init); 207} 208 209static void 210tegra_nouveau_init(device_t self) 211{ 212 struct tegra_nouveau_softc * const sc = device_private(self); 213 struct drm_driver * const driver = nouveau_drm_driver_platform; 214 struct drm_device *dev; 215 bus_addr_t addr[2], size[2]; 216 int error; 217 218 if (fdtbus_get_reg(sc->sc_phandle, 0, &addr[0], &size[0]) != 0 || 219 fdtbus_get_reg(sc->sc_phandle, 1, &addr[1], &size[1]) != 0) { 220 aprint_error(": couldn't get registers\n"); 221 return; 222 } 223 224 dev = drm_dev_alloc(driver, sc->sc_dev); 225 if (dev == NULL) { 226 aprint_error_dev(self, "couldn't allocate DRM device\n"); 227 return; 228 } 229 dev->bst = sc->sc_bst; 230 dev->bus_dmat = sc->sc_dmat; 231 dev->dmat = dev->bus_dmat; 232 dev->dmat_subregion_p = false; 233 234 sc->sc_resources[0].addr = addr[0]; 235 sc->sc_resources[0].size = size[0]; 236 sc->sc_resources[1].addr = addr[1]; 237 sc->sc_resources[1].size = size[1]; 238 239 error = -drm_dev_register(dev, 0); 240 if (error) { 241 drm_dev_unref(dev); 242 aprint_error_dev(self, "couldn't register DRM device: %d\n", 243 error); 244 return; 245 } 246 247 aprint_normal_dev(self, "initialized %s %d.%d.%d %s on minor %d\n", 248 driver->name, driver->major, driver->minor, driver->patchlevel, 249 driver->date, dev->primary->index); 250} 251 252static int 253tegra_nouveau_set_busid(struct drm_device *dev, struct drm_master *master) 254{ 255 int id = 0; /* XXX device_unit(self)? */ 256 257 master->unique = kmem_asprintf("platform:tegra_nouveau:%02d", id); 258 if (master->unique == NULL) 259 return -ENOMEM; 260 master->unique_len = strlen(master->unique); 261 262 return 0; 263} 264 265static int 266tegra_nouveau_intr(void *cookie) 267{ 268 struct tegra_nouveau_softc *sc = cookie; 269 struct nvkm_mc *mc = sc->sc_nv_dev.mc; 270 bool handled = false; 271 272 if (__predict_true(mc)) { 273 nvkm_mc_intr_unarm(mc); 274 nvkm_mc_intr(mc, &handled); 275 nvkm_mc_intr_rearm(mc); 276 } 277 278 return handled; 279} 280 281static int 282nvkm_device_tegra_init(struct nvkm_device *nvdev) 283{ 284 struct tegra_nouveau_softc *sc = 285 container_of(nvdev, struct tegra_nouveau_softc, sc_nv_dev); 286 device_t self = sc->sc_dev; 287 char intrstr[128]; 288 289 if (!fdtbus_intr_str(sc->sc_phandle, 0, intrstr, sizeof(intrstr))) { 290 aprint_error_dev(self, "failed to decode interrupt\n"); 291 return -EIO; 292 } 293 294 sc->sc_ih = fdtbus_intr_establish_xname(sc->sc_phandle, 0, IPL_VM, 295 FDT_INTR_MPSAFE, tegra_nouveau_intr, sc, device_xname(self)); 296 if (sc->sc_ih == NULL) { 297 aprint_error_dev(self, "couldn't establish interrupt on %s\n", 298 intrstr); 299 return -EIO; 300 } 301 302 aprint_normal_dev(self, "interrupting on %s\n", intrstr); 303 return 0; 304} 305 306static void 307nvkm_device_tegra_fini(struct nvkm_device *nvdev, bool suspend) 308{ 309 struct tegra_nouveau_softc *sc = 310 container_of(nvdev, struct tegra_nouveau_softc, sc_nv_dev); 311 312 fdtbus_intr_disestablish(sc->sc_phandle, sc->sc_ih); 313} 314 315static bus_space_tag_t 316nvkm_device_tegra_resource_tag(struct nvkm_device *dev, unsigned bar) 317{ 318 struct tegra_nouveau_softc *sc = 319 container_of(dev, struct tegra_nouveau_softc, sc_nv_dev); 320 321 KASSERT(bar < 2); 322 return sc->sc_bst; 323} 324 325static bus_addr_t 326nvkm_device_tegra_resource_addr(struct nvkm_device *dev, unsigned bar) 327{ 328 struct tegra_nouveau_softc *sc = 329 container_of(dev, struct tegra_nouveau_softc, sc_nv_dev); 330 331 KASSERT(bar < 2); 332 return sc->sc_resources[bar].addr; 333} 334 335static bus_size_t 336nvkm_device_tegra_resource_size(struct nvkm_device *dev, unsigned bar) 337{ 338 struct tegra_nouveau_softc *sc = 339 container_of(dev, struct tegra_nouveau_softc, sc_nv_dev); 340 341 KASSERT(bar < 2); 342 return sc->sc_resources[bar].size; 343} 344