tegra_nouveau.c revision 1.11
11.11Sriastrad/* $NetBSD: tegra_nouveau.c,v 1.11 2018/08/27 15:31:51 riastradh 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.11Sriastrad__KERNEL_RCSID(0, "$NetBSD: tegra_nouveau.c,v 1.11 2018/08/27 15:31:51 riastradh 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.11Sriastradstatic const struct of_compat_data compat_data[] = { 1141.11Sriastrad { "nvidia,gk20a", (uintptr_t)&gk20a_platform_data }, 1151.11Sriastrad { "nvidia,gm20b", (uintptr_t)&gk20a_platform_data }, 1161.11Sriastrad { NULL, 0 }, 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.11Sriastrad return of_match_compat_data(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.11Sriastrad const struct of_compat_data *data = 1341.11Sriastrad of_search_compatible(faa->faa_phandle, compat_data); 1351.11Sriastrad const struct nvkm_device_tegra_func *tegra_func = 1361.11Sriastrad (const void *)data->data; 1371.1Sjmcneill int error; 1381.1Sjmcneill 1391.11Sriastrad KASSERT(tegra_func != NULL); 1401.11Sriastrad 1411.11Sriastrad if (!nouveau_driver_initialized) { 1421.11Sriastrad *nouveau_drm_driver_platform = *nouveau_drm_driver_stub; 1431.11Sriastrad nouveau_drm_driver_platform->set_busid = 1441.11Sriastrad tegra_nouveau_set_busid; 1451.11Sriastrad nouveau_driver_initialized = true; 1461.11Sriastrad } 1471.11Sriastrad 1481.1Sjmcneill sc->sc_dev = self; 1491.8Sjmcneill sc->sc_bst = faa->faa_bst; 1501.8Sjmcneill sc->sc_dmat = faa->faa_dmat; 1511.8Sjmcneill sc->sc_phandle = faa->faa_phandle; 1521.1Sjmcneill 1531.9Sjmcneill sc->sc_clk_gpu = fdtbus_clock_get(faa->faa_phandle, "gpu"); 1541.9Sjmcneill if (sc->sc_clk_gpu == NULL) { 1551.9Sjmcneill aprint_error(": couldn't get clock gpu\n"); 1561.9Sjmcneill return; 1571.9Sjmcneill } 1581.9Sjmcneill sc->sc_clk_pwr = fdtbus_clock_get(faa->faa_phandle, "pwr"); 1591.9Sjmcneill if (sc->sc_clk_pwr == NULL) { 1601.9Sjmcneill aprint_error(": couldn't get clock pwr\n"); 1611.9Sjmcneill return; 1621.9Sjmcneill } 1631.9Sjmcneill sc->sc_rst_gpu = fdtbus_reset_get(faa->faa_phandle, "gpu"); 1641.9Sjmcneill if (sc->sc_rst_gpu == NULL) { 1651.9Sjmcneill aprint_error(": couldn't get reset gpu\n"); 1661.9Sjmcneill return; 1671.9Sjmcneill } 1681.9Sjmcneill 1691.1Sjmcneill aprint_naive("\n"); 1701.1Sjmcneill aprint_normal(": GPU\n"); 1711.1Sjmcneill 1721.6Sjmcneill prop_dictionary_get_cstring(prop, "debug", &nouveau_debug); 1731.6Sjmcneill prop_dictionary_get_cstring(prop, "config", &nouveau_config); 1741.6Sjmcneill 1751.9Sjmcneill fdtbus_reset_assert(sc->sc_rst_gpu); 1761.9Sjmcneill error = clk_set_rate(sc->sc_clk_pwr, 204000000); 1771.9Sjmcneill if (error) { 1781.9Sjmcneill aprint_error_dev(self, "couldn't set clock pwr frequency: %d\n", 1791.9Sjmcneill error); 1801.9Sjmcneill return; 1811.9Sjmcneill } 1821.9Sjmcneill error = clk_enable(sc->sc_clk_pwr); 1831.9Sjmcneill if (error) { 1841.9Sjmcneill aprint_error_dev(self, "couldn't enable clock pwr: %d\n", 1851.9Sjmcneill error); 1861.9Sjmcneill return; 1871.9Sjmcneill } 1881.9Sjmcneill error = clk_enable(sc->sc_clk_gpu); 1891.9Sjmcneill if (error) { 1901.9Sjmcneill aprint_error_dev(self, "couldn't enable clock gpu: %d\n", 1911.9Sjmcneill error); 1921.9Sjmcneill return; 1931.9Sjmcneill } 1941.9Sjmcneill tegra_pmc_remove_clamping(PMC_PARTID_TD); 1951.9Sjmcneill fdtbus_reset_deassert(sc->sc_rst_gpu); 1961.1Sjmcneill 1971.11Sriastrad error = -nvkm_device_ctor(&nvkm_device_tegra_func, NULL, self, 1981.11Sriastrad NVKM_DEVICE_TEGRA, -1, device_xname(self), 1991.11Sriastrad nouveau_config, nouveau_debug, true, true, ~0ULL, &sc->sc_nv_dev); 2001.1Sjmcneill if (error) { 2011.1Sjmcneill aprint_error_dev(self, "couldn't create nouveau device: %d\n", 2021.1Sjmcneill error); 2031.1Sjmcneill return; 2041.1Sjmcneill } 2051.1Sjmcneill 2061.4Sjmcneill config_mountroot(self, tegra_nouveau_init); 2071.1Sjmcneill} 2081.1Sjmcneill 2091.4Sjmcneillstatic void 2101.4Sjmcneilltegra_nouveau_init(device_t self) 2111.1Sjmcneill{ 2121.4Sjmcneill struct tegra_nouveau_softc * const sc = device_private(self); 2131.11Sriastrad struct drm_driver * const driver = nouveau_drm_driver_platform; 2141.1Sjmcneill struct drm_device *dev; 2151.8Sjmcneill bus_addr_t addr[2], size[2]; 2161.1Sjmcneill int error; 2171.1Sjmcneill 2181.8Sjmcneill if (fdtbus_get_reg(sc->sc_phandle, 0, &addr[0], &size[0]) != 0 || 2191.8Sjmcneill fdtbus_get_reg(sc->sc_phandle, 1, &addr[1], &size[1]) != 0) { 2201.8Sjmcneill aprint_error(": couldn't get registers\n"); 2211.8Sjmcneill return; 2221.8Sjmcneill } 2231.8Sjmcneill 2241.1Sjmcneill dev = drm_dev_alloc(driver, sc->sc_dev); 2251.4Sjmcneill if (dev == NULL) { 2261.4Sjmcneill aprint_error_dev(self, "couldn't allocate DRM device\n"); 2271.4Sjmcneill return; 2281.4Sjmcneill } 2291.8Sjmcneill dev->bst = sc->sc_bst; 2301.5Sjmcneill dev->bus_dmat = sc->sc_dmat; 2311.5Sjmcneill dev->dmat = dev->bus_dmat; 2321.5Sjmcneill dev->dmat_subregion_p = false; 2331.1Sjmcneill 2341.11Sriastrad sc->sc_resources[0].addr = addr[0]; 2351.11Sriastrad sc->sc_resources[0].size = size[0]; 2361.11Sriastrad sc->sc_resources[1].addr = addr[1]; 2371.11Sriastrad sc->sc_resources[1].size = size[1]; 2381.1Sjmcneill 2391.1Sjmcneill error = -drm_dev_register(dev, 0); 2401.1Sjmcneill if (error) { 2411.1Sjmcneill drm_dev_unref(dev); 2421.4Sjmcneill aprint_error_dev(self, "couldn't register DRM device: %d\n", 2431.4Sjmcneill error); 2441.4Sjmcneill return; 2451.1Sjmcneill } 2461.1Sjmcneill 2471.4Sjmcneill aprint_normal_dev(self, "initialized %s %d.%d.%d %s on minor %d\n", 2481.1Sjmcneill driver->name, driver->major, driver->minor, driver->patchlevel, 2491.1Sjmcneill driver->date, dev->primary->index); 2501.1Sjmcneill} 2511.1Sjmcneill 2521.1Sjmcneillstatic int 2531.1Sjmcneilltegra_nouveau_set_busid(struct drm_device *dev, struct drm_master *master) 2541.1Sjmcneill{ 2551.11Sriastrad int id = 0; /* XXX device_unit(self)? */ 2561.1Sjmcneill 2571.1Sjmcneill master->unique = kmem_asprintf("platform:tegra_nouveau:%02d", id); 2581.1Sjmcneill if (master->unique == NULL) 2591.1Sjmcneill return -ENOMEM; 2601.1Sjmcneill master->unique_len = strlen(master->unique); 2611.1Sjmcneill 2621.1Sjmcneill return 0; 2631.1Sjmcneill} 2641.1Sjmcneill 2651.1Sjmcneillstatic int 2661.11Sriastradtegra_nouveau_intr(void *cookie) 2671.1Sjmcneill{ 2681.11Sriastrad struct tegra_nouveau_softc *sc = cookie; 2691.11Sriastrad struct nvkm_mc *mc = sc->sc_nv_dev.mc; 2701.11Sriastrad bool handled = false; 2711.11Sriastrad 2721.11Sriastrad if (__predict_true(mc)) { 2731.11Sriastrad nvkm_mc_intr_unarm(mc); 2741.11Sriastrad nvkm_mc_intr(mc, &handled); 2751.11Sriastrad nvkm_mc_intr_rearm(mc); 2761.11Sriastrad } 2771.11Sriastrad 2781.11Sriastrad return handled; 2791.11Sriastrad} 2801.11Sriastrad 2811.11Sriastradstatic int 2821.11Sriastradnvkm_device_tegra_init(struct nvkm_device *nvdev) 2831.11Sriastrad{ 2841.11Sriastrad struct tegra_nouveau_softc *sc = 2851.11Sriastrad container_of(nvdev, struct tegra_nouveau_softc, sc_nv_dev); 2861.11Sriastrad device_t self = sc->sc_dev; 2871.8Sjmcneill char intrstr[128]; 2881.11Sriastrad 2891.11Sriastrad if (!fdtbus_intr_str(sc->sc_phandle, 0, intrstr, sizeof(intrstr))) { 2901.11Sriastrad aprint_error_dev(self, "failed to decode interrupt\n"); 2911.8Sjmcneill return -EIO; 2921.8Sjmcneill } 2931.1Sjmcneill 2941.11Sriastrad sc->sc_ih = fdtbus_intr_establish(sc->sc_phandle, 0, IPL_VM, 2951.11Sriastrad FDT_INTR_MPSAFE, tegra_nouveau_intr, sc); 2961.11Sriastrad if (sc->sc_ih == NULL) { 2971.11Sriastrad aprint_error_dev(self, "couldn't establish interrupt on %s\n", 2981.11Sriastrad intrstr); 2991.8Sjmcneill return -EIO; 3001.8Sjmcneill } 3011.1Sjmcneill 3021.11Sriastrad aprint_normal_dev(self, "interrupting on %s\n", intrstr); 3031.1Sjmcneill return 0; 3041.1Sjmcneill} 3051.1Sjmcneill 3061.1Sjmcneillstatic void 3071.11Sriastradnvkm_device_tegra_fini(struct nvkm_device *nvdev, bool suspend) 3081.11Sriastrad{ 3091.11Sriastrad struct tegra_nouveau_softc *sc = 3101.11Sriastrad container_of(nvdev, struct tegra_nouveau_softc, sc_nv_dev); 3111.11Sriastrad 3121.11Sriastrad fdtbus_intr_disestablish(sc->sc_phandle, sc->sc_ih); 3131.11Sriastrad} 3141.11Sriastrad 3151.11Sriastradstatic bus_space_tag_t 3161.11Sriastradnvkm_device_tegra_resource_tag(struct nvkm_device *dev, unsigned bar) 3171.11Sriastrad{ 3181.11Sriastrad struct tegra_nouveau_softc *sc = 3191.11Sriastrad container_of(dev, struct tegra_nouveau_softc, sc_nv_dev); 3201.11Sriastrad 3211.11Sriastrad KASSERT(bar < 2); 3221.11Sriastrad return sc->sc_bst; 3231.11Sriastrad} 3241.11Sriastrad 3251.11Sriastradstatic bus_addr_t 3261.11Sriastradnvkm_device_tegra_resource_addr(struct nvkm_device *dev, unsigned bar) 3271.11Sriastrad{ 3281.11Sriastrad struct tegra_nouveau_softc *sc = 3291.11Sriastrad container_of(dev, struct tegra_nouveau_softc, sc_nv_dev); 3301.11Sriastrad 3311.11Sriastrad KASSERT(bar < 2); 3321.11Sriastrad return sc->sc_resources[bar].addr; 3331.11Sriastrad} 3341.11Sriastrad 3351.11Sriastradstatic bus_size_t 3361.11Sriastradnvkm_device_tegra_resource_size(struct nvkm_device *dev, unsigned bar) 3371.1Sjmcneill{ 3381.11Sriastrad struct tegra_nouveau_softc *sc = 3391.11Sriastrad container_of(dev, struct tegra_nouveau_softc, sc_nv_dev); 3401.8Sjmcneill 3411.11Sriastrad KASSERT(bar < 2); 3421.11Sriastrad return sc->sc_resources[bar].size; 3431.1Sjmcneill} 344