tegra_nouveau.c revision 1.3
11.3Sjmcneill/* $NetBSD: tegra_nouveau.c,v 1.3 2015/10/18 14:04:32 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.3Sjmcneill__KERNEL_RCSID(0, "$NetBSD: tegra_nouveau.c,v 1.3 2015/10/18 14:04:32 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.1Sjmcneillstatic int tegra_nouveau_init(struct tegra_nouveau_softc *); 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.1Sjmcneill error = tegra_nouveau_init(sc); 1221.1Sjmcneill if (error) { 1231.1Sjmcneill aprint_error_dev(self, "couldn't attach drm: %d\n", error); 1241.1Sjmcneill return; 1251.1Sjmcneill } 1261.1Sjmcneill} 1271.1Sjmcneill 1281.1Sjmcneillstatic int 1291.1Sjmcneilltegra_nouveau_init(struct tegra_nouveau_softc *sc) 1301.1Sjmcneill{ 1311.1Sjmcneill struct drm_driver * const driver = nouveau_drm_driver; 1321.1Sjmcneill struct drm_device *dev; 1331.1Sjmcneill bus_space_tag_t bst = &armv7_generic_bs_tag; 1341.1Sjmcneill int error; 1351.1Sjmcneill 1361.1Sjmcneill driver->kdriver.platform_device = &sc->sc_platform_dev; 1371.1Sjmcneill driver->bus = &drm_tegra_nouveau_bus; 1381.1Sjmcneill 1391.1Sjmcneill dev = drm_dev_alloc(driver, sc->sc_dev); 1401.1Sjmcneill if (dev == NULL) 1411.1Sjmcneill return ENOMEM; 1421.1Sjmcneill dev->platformdev = &sc->sc_platform_dev; 1431.1Sjmcneill 1441.1Sjmcneill dev->platformdev->id = -1; 1451.3Sjmcneill dev->platformdev->dev = *sc->sc_dev; /* XXX */ 1461.3Sjmcneill dev->platformdev->dmat = sc->sc_dmat; 1471.1Sjmcneill dev->platformdev->nresource = 2; 1481.1Sjmcneill dev->platformdev->resource[0].tag = bst; 1491.1Sjmcneill dev->platformdev->resource[0].start = TEGRA_GPU_BASE; 1501.1Sjmcneill dev->platformdev->resource[0].len = 0x01000000; 1511.1Sjmcneill dev->platformdev->resource[1].tag = bst; 1521.1Sjmcneill dev->platformdev->resource[1].start = TEGRA_GPU_BASE + 1531.1Sjmcneill dev->platformdev->resource[0].len; 1541.1Sjmcneill dev->platformdev->resource[1].len = 0x01000000; 1551.1Sjmcneill 1561.1Sjmcneill error = -drm_dev_register(dev, 0); 1571.1Sjmcneill if (error) { 1581.1Sjmcneill drm_dev_unref(dev); 1591.1Sjmcneill return error; 1601.1Sjmcneill } 1611.1Sjmcneill 1621.1Sjmcneill device_printf(sc->sc_dev, "initialized %s %d.%d.%d %s on minor %d\n", 1631.1Sjmcneill driver->name, driver->major, driver->minor, driver->patchlevel, 1641.1Sjmcneill driver->date, dev->primary->index); 1651.1Sjmcneill 1661.1Sjmcneill return 0; 1671.1Sjmcneill} 1681.1Sjmcneill 1691.1Sjmcneillstatic int 1701.1Sjmcneilltegra_nouveau_get_irq(struct drm_device *dev) 1711.1Sjmcneill{ 1721.1Sjmcneill return TEGRA_INTR_GPU; 1731.1Sjmcneill} 1741.1Sjmcneill 1751.1Sjmcneillstatic const char *tegra_nouveau_get_name(struct drm_device *dev) 1761.1Sjmcneill{ 1771.1Sjmcneill return "tegra_nouveau"; 1781.1Sjmcneill} 1791.1Sjmcneill 1801.1Sjmcneillstatic int 1811.1Sjmcneilltegra_nouveau_set_busid(struct drm_device *dev, struct drm_master *master) 1821.1Sjmcneill{ 1831.1Sjmcneill int id; 1841.1Sjmcneill 1851.1Sjmcneill id = dev->platformdev->id; 1861.1Sjmcneill if (id < 0) 1871.1Sjmcneill id = 0; 1881.1Sjmcneill 1891.1Sjmcneill master->unique = kmem_asprintf("platform:tegra_nouveau:%02d", id); 1901.1Sjmcneill if (master->unique == NULL) 1911.1Sjmcneill return -ENOMEM; 1921.1Sjmcneill master->unique_len = strlen(master->unique); 1931.1Sjmcneill 1941.1Sjmcneill return 0; 1951.1Sjmcneill} 1961.1Sjmcneill 1971.1Sjmcneillstatic int 1981.1Sjmcneilltegra_nouveau_irq_install(struct drm_device *dev, 1991.1Sjmcneill irqreturn_t (*handler)(void *), int flags, const char *name, void *arg, 2001.1Sjmcneill struct drm_bus_irq_cookie **cookiep) 2011.1Sjmcneill{ 2021.1Sjmcneill void *ih; 2031.1Sjmcneill int irq = TEGRA_INTR_GPU; 2041.1Sjmcneill 2051.1Sjmcneill ih = intr_establish(irq, IPL_DRM, IST_LEVEL, handler, arg); 2061.1Sjmcneill if (ih == NULL) { 2071.1Sjmcneill aprint_error_dev(dev->dev, 2081.1Sjmcneill "couldn't establish interrupt (%s)\n", name); 2091.1Sjmcneill return -ENOENT; 2101.1Sjmcneill } 2111.1Sjmcneill 2121.1Sjmcneill aprint_normal_dev(dev->dev, "interrupting on irq %d (%s)\n", 2131.1Sjmcneill irq, name); 2141.1Sjmcneill *cookiep = (struct drm_bus_irq_cookie *)ih; 2151.1Sjmcneill return 0; 2161.1Sjmcneill} 2171.1Sjmcneill 2181.1Sjmcneillstatic void 2191.1Sjmcneilltegra_nouveau_irq_uninstall(struct drm_device *dev, 2201.1Sjmcneill struct drm_bus_irq_cookie *cookie) 2211.1Sjmcneill{ 2221.1Sjmcneill intr_disestablish(cookie); 2231.1Sjmcneill} 224