tegra_nouveau.c revision 1.17
1/* $NetBSD: tegra_nouveau.c,v 1.17 2021/12/19 11:01:21 riastradh 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.17 2021/12/19 11:01:21 riastradh 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 device_compatible_entry compat_data[] = { 114 { .compat = "nvidia,gk20a", .data = &gk20a_platform_data }, 115 { .compat = "nvidia,gm20b", .data = &gk20a_platform_data }, 116 DEVICE_COMPAT_EOL 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_compatible_match(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 device_compatible_entry *data = 134 of_compatible_lookup(faa->faa_phandle, compat_data); 135 const struct nvkm_device_tegra_func *tegra_func __diagused = data->data; 136 int error; 137 138 KASSERT(tegra_func != NULL); 139 140 if (!nouveau_driver_initialized) { 141 *nouveau_drm_driver_platform = *nouveau_drm_driver_stub; 142 nouveau_drm_driver_platform->set_busid = 143 tegra_nouveau_set_busid; 144 nouveau_driver_initialized = true; 145 } 146 147 sc->sc_dev = self; 148 sc->sc_bst = faa->faa_bst; 149 sc->sc_dmat = faa->faa_dmat; 150 sc->sc_phandle = faa->faa_phandle; 151 152 sc->sc_clk_gpu = fdtbus_clock_get(faa->faa_phandle, "gpu"); 153 if (sc->sc_clk_gpu == NULL) { 154 aprint_error(": couldn't get clock gpu\n"); 155 return; 156 } 157 sc->sc_clk_pwr = fdtbus_clock_get(faa->faa_phandle, "pwr"); 158 if (sc->sc_clk_pwr == NULL) { 159 aprint_error(": couldn't get clock pwr\n"); 160 return; 161 } 162 sc->sc_rst_gpu = fdtbus_reset_get(faa->faa_phandle, "gpu"); 163 if (sc->sc_rst_gpu == NULL) { 164 aprint_error(": couldn't get reset gpu\n"); 165 return; 166 } 167 168 aprint_naive("\n"); 169 aprint_normal(": GPU\n"); 170 171 prop_dictionary_get_cstring(prop, "debug", &nouveau_debug); 172 prop_dictionary_get_cstring(prop, "config", &nouveau_config); 173 174 fdtbus_reset_assert(sc->sc_rst_gpu); 175 error = clk_set_rate(sc->sc_clk_pwr, 204000000); 176 if (error) { 177 aprint_error_dev(self, "couldn't set clock pwr frequency: %d\n", 178 error); 179 return; 180 } 181 error = clk_enable(sc->sc_clk_pwr); 182 if (error) { 183 aprint_error_dev(self, "couldn't enable clock pwr: %d\n", 184 error); 185 return; 186 } 187 error = clk_enable(sc->sc_clk_gpu); 188 if (error) { 189 aprint_error_dev(self, "couldn't enable clock gpu: %d\n", 190 error); 191 return; 192 } 193 tegra_pmc_remove_clamping(PMC_PARTID_TD); 194 fdtbus_reset_deassert(sc->sc_rst_gpu); 195 196 error = -nvkm_device_ctor(&nvkm_device_tegra_func, NULL, self, 197 NVKM_DEVICE_TEGRA, -1, device_xname(self), 198 nouveau_config, nouveau_debug, true, true, ~0ULL, &sc->sc_nv_dev); 199 if (error) { 200 aprint_error_dev(self, "couldn't create nouveau device: %d\n", 201 error); 202 return; 203 } 204 205 config_mountroot(self, tegra_nouveau_init); 206} 207 208static void 209tegra_nouveau_init(device_t self) 210{ 211 struct tegra_nouveau_softc * const sc = device_private(self); 212 struct drm_driver * const driver = nouveau_drm_driver_platform; 213 struct drm_device *dev; 214 bus_addr_t addr[2], size[2]; 215 int error; 216 217 if (fdtbus_get_reg(sc->sc_phandle, 0, &addr[0], &size[0]) != 0 || 218 fdtbus_get_reg(sc->sc_phandle, 1, &addr[1], &size[1]) != 0) { 219 aprint_error(": couldn't get registers\n"); 220 return; 221 } 222 223 dev = drm_dev_alloc(driver, sc->sc_dev); 224 if (IS_ERR(dev)) { 225 aprint_error_dev(self, "couldn't allocate DRM device\n"); 226 return; 227 } 228 dev->bst = sc->sc_bst; 229 dev->bus_dmat = sc->sc_dmat; 230 dev->dmat = dev->bus_dmat; 231 dev->dmat_subregion_p = false; 232 233 sc->sc_resources[0].addr = addr[0]; 234 sc->sc_resources[0].size = size[0]; 235 sc->sc_resources[1].addr = addr[1]; 236 sc->sc_resources[1].size = size[1]; 237 238 error = -drm_dev_register(dev, 0); 239 if (error) { 240 drm_dev_unref(dev); 241 aprint_error_dev(self, "couldn't register DRM device: %d\n", 242 error); 243 return; 244 } 245 246 aprint_normal_dev(self, "initialized %s %d.%d.%d %s on minor %d\n", 247 driver->name, driver->major, driver->minor, driver->patchlevel, 248 driver->date, dev->primary->index); 249} 250 251static int 252tegra_nouveau_set_busid(struct drm_device *dev, struct drm_master *master) 253{ 254 int id = 0; /* XXX device_unit(self)? */ 255 256 master->unique = kmem_asprintf("platform:tegra_nouveau:%02d", id); 257 if (master->unique == NULL) 258 return -ENOMEM; 259 master->unique_len = strlen(master->unique); 260 261 return 0; 262} 263 264static int 265tegra_nouveau_intr(void *cookie) 266{ 267 struct tegra_nouveau_softc *sc = cookie; 268 struct nvkm_mc *mc = sc->sc_nv_dev.mc; 269 bool handled = false; 270 271 if (__predict_true(mc)) { 272 nvkm_mc_intr_unarm(mc); 273 nvkm_mc_intr(mc, &handled); 274 nvkm_mc_intr_rearm(mc); 275 } 276 277 return handled; 278} 279 280static int 281nvkm_device_tegra_init(struct nvkm_device *nvdev) 282{ 283 struct tegra_nouveau_softc *sc = 284 container_of(nvdev, struct tegra_nouveau_softc, sc_nv_dev); 285 device_t self = sc->sc_dev; 286 char intrstr[128]; 287 288 if (!fdtbus_intr_str(sc->sc_phandle, 0, intrstr, sizeof(intrstr))) { 289 aprint_error_dev(self, "failed to decode interrupt\n"); 290 return -EIO; 291 } 292 293 sc->sc_ih = fdtbus_intr_establish_xname(sc->sc_phandle, 0, IPL_VM, 294 FDT_INTR_MPSAFE, tegra_nouveau_intr, sc, device_xname(self)); 295 if (sc->sc_ih == NULL) { 296 aprint_error_dev(self, "couldn't establish interrupt on %s\n", 297 intrstr); 298 return -EIO; 299 } 300 301 aprint_normal_dev(self, "interrupting on %s\n", intrstr); 302 return 0; 303} 304 305static void 306nvkm_device_tegra_fini(struct nvkm_device *nvdev, bool suspend) 307{ 308 struct tegra_nouveau_softc *sc = 309 container_of(nvdev, struct tegra_nouveau_softc, sc_nv_dev); 310 311 fdtbus_intr_disestablish(sc->sc_phandle, sc->sc_ih); 312} 313 314static bus_space_tag_t 315nvkm_device_tegra_resource_tag(struct nvkm_device *dev, unsigned bar) 316{ 317 struct tegra_nouveau_softc *sc = 318 container_of(dev, struct tegra_nouveau_softc, sc_nv_dev); 319 320 KASSERT(bar < 2); 321 return sc->sc_bst; 322} 323 324static bus_addr_t 325nvkm_device_tegra_resource_addr(struct nvkm_device *dev, unsigned bar) 326{ 327 struct tegra_nouveau_softc *sc = 328 container_of(dev, struct tegra_nouveau_softc, sc_nv_dev); 329 330 KASSERT(bar < 2); 331 return sc->sc_resources[bar].addr; 332} 333 334static bus_size_t 335nvkm_device_tegra_resource_size(struct nvkm_device *dev, unsigned bar) 336{ 337 struct tegra_nouveau_softc *sc = 338 container_of(dev, struct tegra_nouveau_softc, sc_nv_dev); 339 340 KASSERT(bar < 2); 341 return sc->sc_resources[bar].size; 342} 343