linux/drivers/gpu/host1x/dev.c
<<
>>
Prefs
   1/*
   2 * Tegra host1x driver
   3 *
   4 * Copyright (c) 2010-2013, NVIDIA Corporation.
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms and conditions of the GNU General Public License,
   8 * version 2, as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope it will be useful, but WITHOUT
  11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  13 * more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17 */
  18
  19#include <linux/module.h>
  20#include <linux/list.h>
  21#include <linux/slab.h>
  22#include <linux/of.h>
  23#include <linux/of_device.h>
  24#include <linux/clk.h>
  25#include <linux/io.h>
  26
  27#define CREATE_TRACE_POINTS
  28#include <trace/events/host1x.h>
  29
  30#include "bus.h"
  31#include "dev.h"
  32#include "intr.h"
  33#include "channel.h"
  34#include "debug.h"
  35#include "hw/host1x01.h"
  36#include "hw/host1x02.h"
  37#include "hw/host1x04.h"
  38
  39void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r)
  40{
  41        void __iomem *sync_regs = host1x->regs + host1x->info->sync_offset;
  42
  43        writel(v, sync_regs + r);
  44}
  45
  46u32 host1x_sync_readl(struct host1x *host1x, u32 r)
  47{
  48        void __iomem *sync_regs = host1x->regs + host1x->info->sync_offset;
  49
  50        return readl(sync_regs + r);
  51}
  52
  53void host1x_ch_writel(struct host1x_channel *ch, u32 v, u32 r)
  54{
  55        writel(v, ch->regs + r);
  56}
  57
  58u32 host1x_ch_readl(struct host1x_channel *ch, u32 r)
  59{
  60        return readl(ch->regs + r);
  61}
  62
  63static const struct host1x_info host1x01_info = {
  64        .nb_channels    = 8,
  65        .nb_pts         = 32,
  66        .nb_mlocks      = 16,
  67        .nb_bases       = 8,
  68        .init           = host1x01_init,
  69        .sync_offset    = 0x3000,
  70};
  71
  72static const struct host1x_info host1x02_info = {
  73        .nb_channels = 9,
  74        .nb_pts = 32,
  75        .nb_mlocks = 16,
  76        .nb_bases = 12,
  77        .init = host1x02_init,
  78        .sync_offset = 0x3000,
  79};
  80
  81static const struct host1x_info host1x04_info = {
  82        .nb_channels = 12,
  83        .nb_pts = 192,
  84        .nb_mlocks = 16,
  85        .nb_bases = 64,
  86        .init = host1x04_init,
  87        .sync_offset = 0x2100,
  88};
  89
  90static struct of_device_id host1x_of_match[] = {
  91        { .compatible = "nvidia,tegra124-host1x", .data = &host1x04_info, },
  92        { .compatible = "nvidia,tegra114-host1x", .data = &host1x02_info, },
  93        { .compatible = "nvidia,tegra30-host1x", .data = &host1x01_info, },
  94        { .compatible = "nvidia,tegra20-host1x", .data = &host1x01_info, },
  95        { },
  96};
  97MODULE_DEVICE_TABLE(of, host1x_of_match);
  98
  99static int host1x_probe(struct platform_device *pdev)
 100{
 101        const struct of_device_id *id;
 102        struct host1x *host;
 103        struct resource *regs;
 104        int syncpt_irq;
 105        int err;
 106
 107        id = of_match_device(host1x_of_match, &pdev->dev);
 108        if (!id)
 109                return -EINVAL;
 110
 111        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 112        if (!regs) {
 113                dev_err(&pdev->dev, "failed to get registers\n");
 114                return -ENXIO;
 115        }
 116
 117        syncpt_irq = platform_get_irq(pdev, 0);
 118        if (syncpt_irq < 0) {
 119                dev_err(&pdev->dev, "failed to get IRQ\n");
 120                return -ENXIO;
 121        }
 122
 123        host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
 124        if (!host)
 125                return -ENOMEM;
 126
 127        mutex_init(&host->devices_lock);
 128        INIT_LIST_HEAD(&host->devices);
 129        INIT_LIST_HEAD(&host->list);
 130        host->dev = &pdev->dev;
 131        host->info = id->data;
 132
 133        /* set common host1x device data */
 134        platform_set_drvdata(pdev, host);
 135
 136        host->regs = devm_ioremap_resource(&pdev->dev, regs);
 137        if (IS_ERR(host->regs))
 138                return PTR_ERR(host->regs);
 139
 140        if (host->info->init) {
 141                err = host->info->init(host);
 142                if (err)
 143                        return err;
 144        }
 145
 146        host->clk = devm_clk_get(&pdev->dev, NULL);
 147        if (IS_ERR(host->clk)) {
 148                dev_err(&pdev->dev, "failed to get clock\n");
 149                err = PTR_ERR(host->clk);
 150                return err;
 151        }
 152
 153        err = host1x_channel_list_init(host);
 154        if (err) {
 155                dev_err(&pdev->dev, "failed to initialize channel list\n");
 156                return err;
 157        }
 158
 159        err = clk_prepare_enable(host->clk);
 160        if (err < 0) {
 161                dev_err(&pdev->dev, "failed to enable clock\n");
 162                return err;
 163        }
 164
 165        err = host1x_syncpt_init(host);
 166        if (err) {
 167                dev_err(&pdev->dev, "failed to initialize syncpts\n");
 168                goto fail_unprepare_disable;
 169        }
 170
 171        err = host1x_intr_init(host, syncpt_irq);
 172        if (err) {
 173                dev_err(&pdev->dev, "failed to initialize interrupts\n");
 174                goto fail_deinit_syncpt;
 175        }
 176
 177        host1x_debug_init(host);
 178
 179        err = host1x_register(host);
 180        if (err < 0)
 181                goto fail_deinit_intr;
 182
 183        return 0;
 184
 185fail_deinit_intr:
 186        host1x_intr_deinit(host);
 187fail_deinit_syncpt:
 188        host1x_syncpt_deinit(host);
 189fail_unprepare_disable:
 190        clk_disable_unprepare(host->clk);
 191        return err;
 192}
 193
 194static int host1x_remove(struct platform_device *pdev)
 195{
 196        struct host1x *host = platform_get_drvdata(pdev);
 197
 198        host1x_unregister(host);
 199        host1x_intr_deinit(host);
 200        host1x_syncpt_deinit(host);
 201        clk_disable_unprepare(host->clk);
 202
 203        return 0;
 204}
 205
 206static struct platform_driver tegra_host1x_driver = {
 207        .driver = {
 208                .name = "tegra-host1x",
 209                .of_match_table = host1x_of_match,
 210        },
 211        .probe = host1x_probe,
 212        .remove = host1x_remove,
 213};
 214
 215static int __init tegra_host1x_init(void)
 216{
 217        int err;
 218
 219        err = host1x_bus_init();
 220        if (err < 0)
 221                return err;
 222
 223        err = platform_driver_register(&tegra_host1x_driver);
 224        if (err < 0)
 225                goto unregister_bus;
 226
 227        err = platform_driver_register(&tegra_mipi_driver);
 228        if (err < 0)
 229                goto unregister_host1x;
 230
 231        return 0;
 232
 233unregister_host1x:
 234        platform_driver_unregister(&tegra_host1x_driver);
 235unregister_bus:
 236        host1x_bus_exit();
 237        return err;
 238}
 239module_init(tegra_host1x_init);
 240
 241static void __exit tegra_host1x_exit(void)
 242{
 243        platform_driver_unregister(&tegra_mipi_driver);
 244        platform_driver_unregister(&tegra_host1x_driver);
 245        host1x_bus_exit();
 246}
 247module_exit(tegra_host1x_exit);
 248
 249MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
 250MODULE_AUTHOR("Terje Bergstrom <tbergstrom@nvidia.com>");
 251MODULE_DESCRIPTION("Host1x driver for Tegra products");
 252MODULE_LICENSE("GPL");
 253
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.