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