tegra_nouveau.c revision 1.16
11.16Sthorpej/* $NetBSD: tegra_nouveau.c,v 1.16 2021/01/27 03:10:19 thorpej Exp $ */ 21.1Sjmcneill 31.1Sjmcneill/*- 41.1Sjmcneill * Copyright (c) 2015 Jared D. McNeill <jmcneill@invisible.ca> 51.1Sjmcneill * All rights reserved. 61.1Sjmcneill * 71.1Sjmcneill * Redistribution and use in source and binary forms, with or without 81.1Sjmcneill * modification, are permitted provided that the following conditions 91.1Sjmcneill * are met: 101.1Sjmcneill * 1. Redistributions of source code must retain the above copyright 111.1Sjmcneill * notice, this list of conditions and the following disclaimer. 121.1Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright 131.1Sjmcneill * notice, this list of conditions and the following disclaimer in the 141.1Sjmcneill * documentation and/or other materials provided with the distribution. 151.1Sjmcneill * 161.1Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 171.1Sjmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 181.1Sjmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 191.1Sjmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 201.1Sjmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 211.1Sjmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 221.1Sjmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 231.1Sjmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 241.1Sjmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 251.1Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261.1Sjmcneill * SUCH DAMAGE. 271.1Sjmcneill */ 281.1Sjmcneill 291.1Sjmcneill#include <sys/cdefs.h> 301.16Sthorpej__KERNEL_RCSID(0, "$NetBSD: tegra_nouveau.c,v 1.16 2021/01/27 03:10:19 thorpej Exp $"); 311.1Sjmcneill 321.1Sjmcneill#include <sys/param.h> 331.1Sjmcneill#include <sys/bus.h> 341.1Sjmcneill#include <sys/device.h> 351.1Sjmcneill#include <sys/intr.h> 361.1Sjmcneill#include <sys/systm.h> 371.1Sjmcneill#include <sys/kernel.h> 381.1Sjmcneill#include <sys/module.h> 391.1Sjmcneill 401.1Sjmcneill#include <arm/nvidia/tegra_reg.h> 411.9Sjmcneill#include <arm/nvidia/tegra_pmcreg.h> 421.1Sjmcneill#include <arm/nvidia/tegra_var.h> 431.10Sjmcneill#include <arm/nvidia/tegra_intr.h> 441.1Sjmcneill 451.8Sjmcneill#include <dev/fdt/fdtvar.h> 461.8Sjmcneill 471.1Sjmcneill#include <drm/drmP.h> 481.11Sriastrad#include <core/tegra.h> 491.11Sriastrad#include <nvkm/engine/device/priv.h> 501.11Sriastrad#include <nvkm/subdev/mc/priv.h> 511.1Sjmcneill 521.1Sjmcneillextern char *nouveau_config; 531.1Sjmcneillextern char *nouveau_debug; 541.11Sriastradextern struct drm_driver *const nouveau_drm_driver_stub; /* XXX */ 551.11Sriastradextern struct drm_driver *const nouveau_drm_driver_platform; /* XXX */ 561.11Sriastradstatic bool nouveau_driver_initialized = false; /* XXX */ 571.1Sjmcneill 581.1Sjmcneillstatic int tegra_nouveau_match(device_t, cfdata_t, void *); 591.1Sjmcneillstatic void tegra_nouveau_attach(device_t, device_t, void *); 601.1Sjmcneill 611.1Sjmcneillstruct tegra_nouveau_softc { 621.1Sjmcneill device_t sc_dev; 631.8Sjmcneill bus_space_tag_t sc_bst; 641.11Sriastrad struct { 651.11Sriastrad bus_addr_t addr; 661.11Sriastrad bus_size_t size; 671.11Sriastrad } sc_resources[2]; 681.3Sjmcneill bus_dma_tag_t sc_dmat; 691.8Sjmcneill int sc_phandle; 701.11Sriastrad void *sc_ih; 711.9Sjmcneill struct clk *sc_clk_gpu; 721.9Sjmcneill struct clk *sc_clk_pwr; 731.9Sjmcneill struct fdtbus_reset *sc_rst_gpu; 741.1Sjmcneill struct drm_device *sc_drm_dev; 751.11Sriastrad struct nvkm_device sc_nv_dev; 761.1Sjmcneill}; 771.1Sjmcneill 781.4Sjmcneillstatic void tegra_nouveau_init(device_t); 791.1Sjmcneill 801.1Sjmcneillstatic int tegra_nouveau_set_busid(struct drm_device *, 811.1Sjmcneill struct drm_master *); 821.11Sriastrad 831.11Sriastradstatic int tegra_nouveau_intr(void *); 841.11Sriastrad 851.11Sriastradstatic int nvkm_device_tegra_init(struct nvkm_device *); 861.11Sriastradstatic void nvkm_device_tegra_fini(struct nvkm_device *, bool); 871.11Sriastrad 881.11Sriastradstatic bus_space_tag_t 891.11Sriastrad nvkm_device_tegra_resource_tag(struct nvkm_device *, unsigned); 901.11Sriastradstatic bus_addr_t 911.11Sriastrad nvkm_device_tegra_resource_addr(struct nvkm_device *, unsigned); 921.11Sriastradstatic bus_size_t 931.11Sriastrad nvkm_device_tegra_resource_size(struct nvkm_device *, unsigned); 941.1Sjmcneill 951.1SjmcneillCFATTACH_DECL_NEW(tegra_nouveau, sizeof(struct tegra_nouveau_softc), 961.1Sjmcneill tegra_nouveau_match, tegra_nouveau_attach, NULL, NULL); 971.1Sjmcneill 981.11Sriastradstatic const struct nvkm_device_func nvkm_device_tegra_func = { 991.11Sriastrad .tegra = NULL, /* XXX */ 1001.11Sriastrad .dtor = NULL, 1011.11Sriastrad .init = nvkm_device_tegra_init, 1021.11Sriastrad .fini = nvkm_device_tegra_fini, 1031.11Sriastrad .resource_tag = nvkm_device_tegra_resource_tag, 1041.11Sriastrad .resource_addr = nvkm_device_tegra_resource_addr, 1051.11Sriastrad .resource_size = nvkm_device_tegra_resource_size, 1061.11Sriastrad .cpu_coherent = false, 1071.11Sriastrad}; 1081.11Sriastrad 1091.11Sriastradstatic const struct nvkm_device_tegra_func gk20a_platform_data = { 1101.11Sriastrad .iommu_bit = 34, 1111.11Sriastrad}; 1121.11Sriastrad 1131.14Sthorpejstatic const struct device_compatible_entry compat_data[] = { 1141.14Sthorpej { .compat = "nvidia,gk20a", .data = &gk20a_platform_data }, 1151.14Sthorpej { .compat = "nvidia,gm20b", .data = &gk20a_platform_data }, 1161.16Sthorpej DEVICE_COMPAT_EOL 1171.11Sriastrad}; 1181.11Sriastrad 1191.1Sjmcneillstatic int 1201.1Sjmcneilltegra_nouveau_match(device_t parent, cfdata_t cf, void *aux) 1211.1Sjmcneill{ 1221.8Sjmcneill struct fdt_attach_args * const faa = aux; 1231.8Sjmcneill 1241.16Sthorpej return of_compatible_match(faa->faa_phandle, compat_data); 1251.1Sjmcneill} 1261.1Sjmcneill 1271.1Sjmcneillstatic void 1281.1Sjmcneilltegra_nouveau_attach(device_t parent, device_t self, void *aux) 1291.1Sjmcneill{ 1301.1Sjmcneill struct tegra_nouveau_softc * const sc = device_private(self); 1311.8Sjmcneill struct fdt_attach_args * const faa = aux; 1321.6Sjmcneill prop_dictionary_t prop = device_properties(self); 1331.14Sthorpej const struct device_compatible_entry *data = 1341.16Sthorpej of_compatible_lookup(faa->faa_phandle, compat_data); 1351.14Sthorpej const struct nvkm_device_tegra_func *tegra_func __diagused = data->data; 1361.1Sjmcneill int error; 1371.1Sjmcneill 1381.11Sriastrad KASSERT(tegra_func != NULL); 1391.11Sriastrad 1401.11Sriastrad if (!nouveau_driver_initialized) { 1411.11Sriastrad *nouveau_drm_driver_platform = *nouveau_drm_driver_stub; 1421.11Sriastrad nouveau_drm_driver_platform->set_busid = 1431.11Sriastrad tegra_nouveau_set_busid; 1441.11Sriastrad nouveau_driver_initialized = true; 1451.11Sriastrad } 1461.11Sriastrad 1471.1Sjmcneill sc->sc_dev = self; 1481.8Sjmcneill sc->sc_bst = faa->faa_bst; 1491.8Sjmcneill sc->sc_dmat = faa->faa_dmat; 1501.8Sjmcneill sc->sc_phandle = faa->faa_phandle; 1511.1Sjmcneill 1521.9Sjmcneill sc->sc_clk_gpu = fdtbus_clock_get(faa->faa_phandle, "gpu"); 1531.9Sjmcneill if (sc->sc_clk_gpu == NULL) { 1541.9Sjmcneill aprint_error(": couldn't get clock gpu\n"); 1551.9Sjmcneill return; 1561.9Sjmcneill } 1571.9Sjmcneill sc->sc_clk_pwr = fdtbus_clock_get(faa->faa_phandle, "pwr"); 1581.9Sjmcneill if (sc->sc_clk_pwr == NULL) { 1591.9Sjmcneill aprint_error(": couldn't get clock pwr\n"); 1601.9Sjmcneill return; 1611.9Sjmcneill } 1621.9Sjmcneill sc->sc_rst_gpu = fdtbus_reset_get(faa->faa_phandle, "gpu"); 1631.9Sjmcneill if (sc->sc_rst_gpu == NULL) { 1641.9Sjmcneill aprint_error(": couldn't get reset gpu\n"); 1651.9Sjmcneill return; 1661.9Sjmcneill } 1671.9Sjmcneill 1681.1Sjmcneill aprint_naive("\n"); 1691.1Sjmcneill aprint_normal(": GPU\n"); 1701.1Sjmcneill 1711.6Sjmcneill prop_dictionary_get_cstring(prop, "debug", &nouveau_debug); 1721.6Sjmcneill prop_dictionary_get_cstring(prop, "config", &nouveau_config); 1731.6Sjmcneill 1741.9Sjmcneill fdtbus_reset_assert(sc->sc_rst_gpu); 1751.9Sjmcneill error = clk_set_rate(sc->sc_clk_pwr, 204000000); 1761.9Sjmcneill if (error) { 1771.9Sjmcneill aprint_error_dev(self, "couldn't set clock pwr frequency: %d\n", 1781.9Sjmcneill error); 1791.9Sjmcneill return; 1801.9Sjmcneill } 1811.9Sjmcneill error = clk_enable(sc->sc_clk_pwr); 1821.9Sjmcneill if (error) { 1831.9Sjmcneill aprint_error_dev(self, "couldn't enable clock pwr: %d\n", 1841.9Sjmcneill error); 1851.9Sjmcneill return; 1861.9Sjmcneill } 1871.9Sjmcneill error = clk_enable(sc->sc_clk_gpu); 1881.9Sjmcneill if (error) { 1891.9Sjmcneill aprint_error_dev(self, "couldn't enable clock gpu: %d\n", 1901.9Sjmcneill error); 1911.9Sjmcneill return; 1921.9Sjmcneill } 1931.9Sjmcneill tegra_pmc_remove_clamping(PMC_PARTID_TD); 1941.9Sjmcneill fdtbus_reset_deassert(sc->sc_rst_gpu); 1951.1Sjmcneill 1961.11Sriastrad error = -nvkm_device_ctor(&nvkm_device_tegra_func, NULL, self, 1971.11Sriastrad NVKM_DEVICE_TEGRA, -1, device_xname(self), 1981.11Sriastrad nouveau_config, nouveau_debug, true, true, ~0ULL, &sc->sc_nv_dev); 1991.1Sjmcneill if (error) { 2001.1Sjmcneill aprint_error_dev(self, "couldn't create nouveau device: %d\n", 2011.1Sjmcneill error); 2021.1Sjmcneill return; 2031.1Sjmcneill } 2041.1Sjmcneill 2051.4Sjmcneill config_mountroot(self, tegra_nouveau_init); 2061.1Sjmcneill} 2071.1Sjmcneill 2081.4Sjmcneillstatic void 2091.4Sjmcneilltegra_nouveau_init(device_t self) 2101.1Sjmcneill{ 2111.4Sjmcneill struct tegra_nouveau_softc * const sc = device_private(self); 2121.11Sriastrad struct drm_driver * const driver = nouveau_drm_driver_platform; 2131.1Sjmcneill struct drm_device *dev; 2141.8Sjmcneill bus_addr_t addr[2], size[2]; 2151.1Sjmcneill int error; 2161.1Sjmcneill 2171.8Sjmcneill if (fdtbus_get_reg(sc->sc_phandle, 0, &addr[0], &size[0]) != 0 || 2181.8Sjmcneill fdtbus_get_reg(sc->sc_phandle, 1, &addr[1], &size[1]) != 0) { 2191.8Sjmcneill aprint_error(": couldn't get registers\n"); 2201.8Sjmcneill return; 2211.8Sjmcneill } 2221.8Sjmcneill 2231.1Sjmcneill dev = drm_dev_alloc(driver, sc->sc_dev); 2241.4Sjmcneill if (dev == NULL) { 2251.4Sjmcneill aprint_error_dev(self, "couldn't allocate DRM device\n"); 2261.4Sjmcneill return; 2271.4Sjmcneill } 2281.8Sjmcneill dev->bst = sc->sc_bst; 2291.5Sjmcneill dev->bus_dmat = sc->sc_dmat; 2301.5Sjmcneill dev->dmat = dev->bus_dmat; 2311.5Sjmcneill dev->dmat_subregion_p = false; 2321.1Sjmcneill 2331.11Sriastrad sc->sc_resources[0].addr = addr[0]; 2341.11Sriastrad sc->sc_resources[0].size = size[0]; 2351.11Sriastrad sc->sc_resources[1].addr = addr[1]; 2361.11Sriastrad sc->sc_resources[1].size = size[1]; 2371.1Sjmcneill 2381.1Sjmcneill error = -drm_dev_register(dev, 0); 2391.1Sjmcneill if (error) { 2401.1Sjmcneill drm_dev_unref(dev); 2411.4Sjmcneill aprint_error_dev(self, "couldn't register DRM device: %d\n", 2421.4Sjmcneill error); 2431.4Sjmcneill return; 2441.1Sjmcneill } 2451.1Sjmcneill 2461.4Sjmcneill aprint_normal_dev(self, "initialized %s %d.%d.%d %s on minor %d\n", 2471.1Sjmcneill driver->name, driver->major, driver->minor, driver->patchlevel, 2481.1Sjmcneill driver->date, dev->primary->index); 2491.1Sjmcneill} 2501.1Sjmcneill 2511.1Sjmcneillstatic int 2521.1Sjmcneilltegra_nouveau_set_busid(struct drm_device *dev, struct drm_master *master) 2531.1Sjmcneill{ 2541.11Sriastrad int id = 0; /* XXX device_unit(self)? */ 2551.1Sjmcneill 2561.1Sjmcneill master->unique = kmem_asprintf("platform:tegra_nouveau:%02d", id); 2571.1Sjmcneill if (master->unique == NULL) 2581.1Sjmcneill return -ENOMEM; 2591.1Sjmcneill master->unique_len = strlen(master->unique); 2601.1Sjmcneill 2611.1Sjmcneill return 0; 2621.1Sjmcneill} 2631.1Sjmcneill 2641.1Sjmcneillstatic int 2651.11Sriastradtegra_nouveau_intr(void *cookie) 2661.1Sjmcneill{ 2671.11Sriastrad struct tegra_nouveau_softc *sc = cookie; 2681.11Sriastrad struct nvkm_mc *mc = sc->sc_nv_dev.mc; 2691.11Sriastrad bool handled = false; 2701.11Sriastrad 2711.11Sriastrad if (__predict_true(mc)) { 2721.11Sriastrad nvkm_mc_intr_unarm(mc); 2731.11Sriastrad nvkm_mc_intr(mc, &handled); 2741.11Sriastrad nvkm_mc_intr_rearm(mc); 2751.11Sriastrad } 2761.11Sriastrad 2771.11Sriastrad return handled; 2781.11Sriastrad} 2791.11Sriastrad 2801.11Sriastradstatic int 2811.11Sriastradnvkm_device_tegra_init(struct nvkm_device *nvdev) 2821.11Sriastrad{ 2831.11Sriastrad struct tegra_nouveau_softc *sc = 2841.11Sriastrad container_of(nvdev, struct tegra_nouveau_softc, sc_nv_dev); 2851.11Sriastrad device_t self = sc->sc_dev; 2861.8Sjmcneill char intrstr[128]; 2871.11Sriastrad 2881.11Sriastrad if (!fdtbus_intr_str(sc->sc_phandle, 0, intrstr, sizeof(intrstr))) { 2891.11Sriastrad aprint_error_dev(self, "failed to decode interrupt\n"); 2901.8Sjmcneill return -EIO; 2911.8Sjmcneill } 2921.1Sjmcneill 2931.13Sjmcneill sc->sc_ih = fdtbus_intr_establish_xname(sc->sc_phandle, 0, IPL_VM, 2941.13Sjmcneill FDT_INTR_MPSAFE, tegra_nouveau_intr, sc, device_xname(self)); 2951.11Sriastrad if (sc->sc_ih == NULL) { 2961.11Sriastrad aprint_error_dev(self, "couldn't establish interrupt on %s\n", 2971.11Sriastrad intrstr); 2981.8Sjmcneill return -EIO; 2991.8Sjmcneill } 3001.1Sjmcneill 3011.11Sriastrad aprint_normal_dev(self, "interrupting on %s\n", intrstr); 3021.1Sjmcneill return 0; 3031.1Sjmcneill} 3041.1Sjmcneill 3051.1Sjmcneillstatic void 3061.11Sriastradnvkm_device_tegra_fini(struct nvkm_device *nvdev, bool suspend) 3071.11Sriastrad{ 3081.11Sriastrad struct tegra_nouveau_softc *sc = 3091.11Sriastrad container_of(nvdev, struct tegra_nouveau_softc, sc_nv_dev); 3101.11Sriastrad 3111.11Sriastrad fdtbus_intr_disestablish(sc->sc_phandle, sc->sc_ih); 3121.11Sriastrad} 3131.11Sriastrad 3141.11Sriastradstatic bus_space_tag_t 3151.11Sriastradnvkm_device_tegra_resource_tag(struct nvkm_device *dev, unsigned bar) 3161.11Sriastrad{ 3171.11Sriastrad struct tegra_nouveau_softc *sc = 3181.11Sriastrad container_of(dev, struct tegra_nouveau_softc, sc_nv_dev); 3191.11Sriastrad 3201.11Sriastrad KASSERT(bar < 2); 3211.11Sriastrad return sc->sc_bst; 3221.11Sriastrad} 3231.11Sriastrad 3241.11Sriastradstatic bus_addr_t 3251.11Sriastradnvkm_device_tegra_resource_addr(struct nvkm_device *dev, unsigned bar) 3261.11Sriastrad{ 3271.11Sriastrad struct tegra_nouveau_softc *sc = 3281.11Sriastrad container_of(dev, struct tegra_nouveau_softc, sc_nv_dev); 3291.11Sriastrad 3301.11Sriastrad KASSERT(bar < 2); 3311.11Sriastrad return sc->sc_resources[bar].addr; 3321.11Sriastrad} 3331.11Sriastrad 3341.11Sriastradstatic bus_size_t 3351.11Sriastradnvkm_device_tegra_resource_size(struct nvkm_device *dev, unsigned bar) 3361.1Sjmcneill{ 3371.11Sriastrad struct tegra_nouveau_softc *sc = 3381.11Sriastrad container_of(dev, struct tegra_nouveau_softc, sc_nv_dev); 3391.8Sjmcneill 3401.11Sriastrad KASSERT(bar < 2); 3411.11Sriastrad return sc->sc_resources[bar].size; 3421.1Sjmcneill} 343