tegra_nouveau.c revision 1.4
11.4Sjmcneill/* $NetBSD: tegra_nouveau.c,v 1.4 2015/10/18 14:20:22 jmcneill 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 "locators.h" 301.1Sjmcneill 311.1Sjmcneill#include <sys/cdefs.h> 321.4Sjmcneill__KERNEL_RCSID(0, "$NetBSD: tegra_nouveau.c,v 1.4 2015/10/18 14:20:22 jmcneill Exp $"); 331.1Sjmcneill 341.1Sjmcneill#include <sys/param.h> 351.1Sjmcneill#include <sys/bus.h> 361.1Sjmcneill#include <sys/device.h> 371.1Sjmcneill#include <sys/intr.h> 381.1Sjmcneill#include <sys/systm.h> 391.1Sjmcneill#include <sys/kernel.h> 401.1Sjmcneill#include <sys/module.h> 411.1Sjmcneill 421.1Sjmcneill#include <arm/nvidia/tegra_reg.h> 431.1Sjmcneill#include <arm/nvidia/tegra_var.h> 441.1Sjmcneill 451.1Sjmcneill#include <drm/drmP.h> 461.1Sjmcneill#include <engine/device.h> 471.1Sjmcneill 481.1Sjmcneillextern char *nouveau_config; 491.1Sjmcneillextern char *nouveau_debug; 501.1Sjmcneillextern struct drm_driver *const nouveau_drm_driver; 511.1Sjmcneill 521.1Sjmcneillstatic int tegra_nouveau_match(device_t, cfdata_t, void *); 531.1Sjmcneillstatic void tegra_nouveau_attach(device_t, device_t, void *); 541.1Sjmcneill 551.1Sjmcneillstruct tegra_nouveau_softc { 561.1Sjmcneill device_t sc_dev; 571.3Sjmcneill bus_dma_tag_t sc_dmat; 581.1Sjmcneill struct drm_device *sc_drm_dev; 591.1Sjmcneill struct platform_device sc_platform_dev; 601.1Sjmcneill struct nouveau_device *sc_nv_dev; 611.1Sjmcneill}; 621.1Sjmcneill 631.4Sjmcneillstatic void tegra_nouveau_init(device_t); 641.1Sjmcneill 651.1Sjmcneillstatic int tegra_nouveau_get_irq(struct drm_device *); 661.1Sjmcneillstatic const char *tegra_nouveau_get_name(struct drm_device *); 671.1Sjmcneillstatic int tegra_nouveau_set_busid(struct drm_device *, 681.1Sjmcneill struct drm_master *); 691.1Sjmcneillstatic int tegra_nouveau_irq_install(struct drm_device *, 701.1Sjmcneill irqreturn_t (*)(void *), 711.1Sjmcneill int, const char *, void *, 721.1Sjmcneill struct drm_bus_irq_cookie **); 731.1Sjmcneillstatic void tegra_nouveau_irq_uninstall(struct drm_device *, 741.1Sjmcneill struct drm_bus_irq_cookie *); 751.1Sjmcneill 761.1Sjmcneillstatic struct drm_bus drm_tegra_nouveau_bus = { 771.1Sjmcneill .bus_type = DRIVER_BUS_PLATFORM, 781.1Sjmcneill .get_irq = tegra_nouveau_get_irq, 791.1Sjmcneill .get_name = tegra_nouveau_get_name, 801.1Sjmcneill .set_busid = tegra_nouveau_set_busid, 811.1Sjmcneill .irq_install = tegra_nouveau_irq_install, 821.1Sjmcneill .irq_uninstall = tegra_nouveau_irq_uninstall 831.1Sjmcneill}; 841.1Sjmcneill 851.1SjmcneillCFATTACH_DECL_NEW(tegra_nouveau, sizeof(struct tegra_nouveau_softc), 861.1Sjmcneill tegra_nouveau_match, tegra_nouveau_attach, NULL, NULL); 871.1Sjmcneill 881.1Sjmcneillstatic int 891.1Sjmcneilltegra_nouveau_match(device_t parent, cfdata_t cf, void *aux) 901.1Sjmcneill{ 911.1Sjmcneill return 1; 921.1Sjmcneill} 931.1Sjmcneill 941.1Sjmcneillstatic void 951.1Sjmcneilltegra_nouveau_attach(device_t parent, device_t self, void *aux) 961.1Sjmcneill{ 971.1Sjmcneill struct tegra_nouveau_softc * const sc = device_private(self); 981.3Sjmcneill struct tegraio_attach_args * const tio = aux; 991.1Sjmcneill#if notyet 1001.1Sjmcneill const struct tegra_locators * const loc = &tio->tio_loc; 1011.1Sjmcneill#endif 1021.1Sjmcneill int error; 1031.1Sjmcneill 1041.1Sjmcneill sc->sc_dev = self; 1051.3Sjmcneill sc->sc_dmat = tio->tio_dmat; 1061.1Sjmcneill 1071.1Sjmcneill aprint_naive("\n"); 1081.1Sjmcneill aprint_normal(": GPU\n"); 1091.1Sjmcneill 1101.1Sjmcneill tegra_car_gpu_enable(); 1111.1Sjmcneill 1121.1Sjmcneill error = -nouveau_device_create(&sc->sc_platform_dev, 1131.1Sjmcneill NOUVEAU_BUS_PLATFORM, -1, device_xname(self), 1141.1Sjmcneill nouveau_config, nouveau_debug, &sc->sc_nv_dev); 1151.1Sjmcneill if (error) { 1161.1Sjmcneill aprint_error_dev(self, "couldn't create nouveau device: %d\n", 1171.1Sjmcneill error); 1181.1Sjmcneill return; 1191.1Sjmcneill } 1201.1Sjmcneill 1211.4Sjmcneill config_mountroot(self, tegra_nouveau_init); 1221.1Sjmcneill} 1231.1Sjmcneill 1241.4Sjmcneillstatic void 1251.4Sjmcneilltegra_nouveau_init(device_t self) 1261.1Sjmcneill{ 1271.4Sjmcneill struct tegra_nouveau_softc * const sc = device_private(self); 1281.1Sjmcneill struct drm_driver * const driver = nouveau_drm_driver; 1291.1Sjmcneill struct drm_device *dev; 1301.1Sjmcneill bus_space_tag_t bst = &armv7_generic_bs_tag; 1311.1Sjmcneill int error; 1321.1Sjmcneill 1331.1Sjmcneill driver->kdriver.platform_device = &sc->sc_platform_dev; 1341.1Sjmcneill driver->bus = &drm_tegra_nouveau_bus; 1351.1Sjmcneill 1361.1Sjmcneill dev = drm_dev_alloc(driver, sc->sc_dev); 1371.4Sjmcneill if (dev == NULL) { 1381.4Sjmcneill aprint_error_dev(self, "couldn't allocate DRM device\n"); 1391.4Sjmcneill return; 1401.4Sjmcneill } 1411.1Sjmcneill dev->platformdev = &sc->sc_platform_dev; 1421.1Sjmcneill 1431.1Sjmcneill dev->platformdev->id = -1; 1441.3Sjmcneill dev->platformdev->dev = *sc->sc_dev; /* XXX */ 1451.3Sjmcneill dev->platformdev->dmat = sc->sc_dmat; 1461.1Sjmcneill dev->platformdev->nresource = 2; 1471.1Sjmcneill dev->platformdev->resource[0].tag = bst; 1481.1Sjmcneill dev->platformdev->resource[0].start = TEGRA_GPU_BASE; 1491.1Sjmcneill dev->platformdev->resource[0].len = 0x01000000; 1501.1Sjmcneill dev->platformdev->resource[1].tag = bst; 1511.1Sjmcneill dev->platformdev->resource[1].start = TEGRA_GPU_BASE + 1521.1Sjmcneill dev->platformdev->resource[0].len; 1531.1Sjmcneill dev->platformdev->resource[1].len = 0x01000000; 1541.1Sjmcneill 1551.1Sjmcneill error = -drm_dev_register(dev, 0); 1561.1Sjmcneill if (error) { 1571.1Sjmcneill drm_dev_unref(dev); 1581.4Sjmcneill aprint_error_dev(self, "couldn't register DRM device: %d\n", 1591.4Sjmcneill error); 1601.4Sjmcneill return; 1611.1Sjmcneill } 1621.1Sjmcneill 1631.4Sjmcneill aprint_normal_dev(self, "initialized %s %d.%d.%d %s on minor %d\n", 1641.1Sjmcneill driver->name, driver->major, driver->minor, driver->patchlevel, 1651.1Sjmcneill driver->date, dev->primary->index); 1661.1Sjmcneill} 1671.1Sjmcneill 1681.1Sjmcneillstatic int 1691.1Sjmcneilltegra_nouveau_get_irq(struct drm_device *dev) 1701.1Sjmcneill{ 1711.1Sjmcneill return TEGRA_INTR_GPU; 1721.1Sjmcneill} 1731.1Sjmcneill 1741.1Sjmcneillstatic const char *tegra_nouveau_get_name(struct drm_device *dev) 1751.1Sjmcneill{ 1761.1Sjmcneill return "tegra_nouveau"; 1771.1Sjmcneill} 1781.1Sjmcneill 1791.1Sjmcneillstatic int 1801.1Sjmcneilltegra_nouveau_set_busid(struct drm_device *dev, struct drm_master *master) 1811.1Sjmcneill{ 1821.1Sjmcneill int id; 1831.1Sjmcneill 1841.1Sjmcneill id = dev->platformdev->id; 1851.1Sjmcneill if (id < 0) 1861.1Sjmcneill id = 0; 1871.1Sjmcneill 1881.1Sjmcneill master->unique = kmem_asprintf("platform:tegra_nouveau:%02d", id); 1891.1Sjmcneill if (master->unique == NULL) 1901.1Sjmcneill return -ENOMEM; 1911.1Sjmcneill master->unique_len = strlen(master->unique); 1921.1Sjmcneill 1931.1Sjmcneill return 0; 1941.1Sjmcneill} 1951.1Sjmcneill 1961.1Sjmcneillstatic int 1971.1Sjmcneilltegra_nouveau_irq_install(struct drm_device *dev, 1981.1Sjmcneill irqreturn_t (*handler)(void *), int flags, const char *name, void *arg, 1991.1Sjmcneill struct drm_bus_irq_cookie **cookiep) 2001.1Sjmcneill{ 2011.1Sjmcneill void *ih; 2021.1Sjmcneill int irq = TEGRA_INTR_GPU; 2031.1Sjmcneill 2041.1Sjmcneill ih = intr_establish(irq, IPL_DRM, IST_LEVEL, handler, arg); 2051.1Sjmcneill if (ih == NULL) { 2061.1Sjmcneill aprint_error_dev(dev->dev, 2071.1Sjmcneill "couldn't establish interrupt (%s)\n", name); 2081.1Sjmcneill return -ENOENT; 2091.1Sjmcneill } 2101.1Sjmcneill 2111.1Sjmcneill aprint_normal_dev(dev->dev, "interrupting on irq %d (%s)\n", 2121.1Sjmcneill irq, name); 2131.1Sjmcneill *cookiep = (struct drm_bus_irq_cookie *)ih; 2141.1Sjmcneill return 0; 2151.1Sjmcneill} 2161.1Sjmcneill 2171.1Sjmcneillstatic void 2181.1Sjmcneilltegra_nouveau_irq_uninstall(struct drm_device *dev, 2191.1Sjmcneill struct drm_bus_irq_cookie *cookie) 2201.1Sjmcneill{ 2211.1Sjmcneill intr_disestablish(cookie); 2221.1Sjmcneill} 223