tegra_nouveau.c revision 1.12
11.12Sskrll/* $NetBSD: tegra_nouveau.c,v 1.12 2018/11/01 16:14:54 skrll 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.12Sskrll__KERNEL_RCSID(0, "$NetBSD: tegra_nouveau.c,v 1.12 2018/11/01 16:14:54 skrll 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.12Sskrll	const struct nvkm_device_tegra_func *tegra_func __diagused =
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