linux/drivers/gpu/drm/tegra/gr3d.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2013 Avionic Design GmbH
   3 * Copyright (C) 2013 NVIDIA Corporation
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 as
   7 * published by the Free Software Foundation.
   8 */
   9
  10#include <linux/clk.h>
  11#include <linux/host1x.h>
  12#include <linux/module.h>
  13#include <linux/platform_device.h>
  14#include <linux/reset.h>
  15
  16#include <soc/tegra/pmc.h>
  17
  18#include "drm.h"
  19#include "gem.h"
  20#include "gr3d.h"
  21
  22struct gr3d {
  23        struct tegra_drm_client client;
  24        struct host1x_channel *channel;
  25        struct clk *clk_secondary;
  26        struct clk *clk;
  27        struct reset_control *rst_secondary;
  28        struct reset_control *rst;
  29
  30        DECLARE_BITMAP(addr_regs, GR3D_NUM_REGS);
  31};
  32
  33static inline struct gr3d *to_gr3d(struct tegra_drm_client *client)
  34{
  35        return container_of(client, struct gr3d, client);
  36}
  37
  38static int gr3d_init(struct host1x_client *client)
  39{
  40        struct tegra_drm_client *drm = host1x_to_drm_client(client);
  41        struct drm_device *dev = dev_get_drvdata(client->parent);
  42        unsigned long flags = HOST1X_SYNCPT_HAS_BASE;
  43        struct gr3d *gr3d = to_gr3d(drm);
  44
  45        gr3d->channel = host1x_channel_request(client->dev);
  46        if (!gr3d->channel)
  47                return -ENOMEM;
  48
  49        client->syncpts[0] = host1x_syncpt_request(client->dev, flags);
  50        if (!client->syncpts[0]) {
  51                host1x_channel_free(gr3d->channel);
  52                return -ENOMEM;
  53        }
  54
  55        return tegra_drm_register_client(dev->dev_private, drm);
  56}
  57
  58static int gr3d_exit(struct host1x_client *client)
  59{
  60        struct tegra_drm_client *drm = host1x_to_drm_client(client);
  61        struct drm_device *dev = dev_get_drvdata(client->parent);
  62        struct gr3d *gr3d = to_gr3d(drm);
  63        int err;
  64
  65        err = tegra_drm_unregister_client(dev->dev_private, drm);
  66        if (err < 0)
  67                return err;
  68
  69        host1x_syncpt_free(client->syncpts[0]);
  70        host1x_channel_free(gr3d->channel);
  71
  72        return 0;
  73}
  74
  75static const struct host1x_client_ops gr3d_client_ops = {
  76        .init = gr3d_init,
  77        .exit = gr3d_exit,
  78};
  79
  80static int gr3d_open_channel(struct tegra_drm_client *client,
  81                             struct tegra_drm_context *context)
  82{
  83        struct gr3d *gr3d = to_gr3d(client);
  84
  85        context->channel = host1x_channel_get(gr3d->channel);
  86        if (!context->channel)
  87                return -ENOMEM;
  88
  89        return 0;
  90}
  91
  92static void gr3d_close_channel(struct tegra_drm_context *context)
  93{
  94        host1x_channel_put(context->channel);
  95}
  96
  97static int gr3d_is_addr_reg(struct device *dev, u32 class, u32 offset)
  98{
  99        struct gr3d *gr3d = dev_get_drvdata(dev);
 100
 101        switch (class) {
 102        case HOST1X_CLASS_HOST1X:
 103                if (offset == 0x2b)
 104                        return 1;
 105
 106                break;
 107
 108        case HOST1X_CLASS_GR3D:
 109                if (offset >= GR3D_NUM_REGS)
 110                        break;
 111
 112                if (test_bit(offset, gr3d->addr_regs))
 113                        return 1;
 114
 115                break;
 116        }
 117
 118        return 0;
 119}
 120
 121static const struct tegra_drm_client_ops gr3d_ops = {
 122        .open_channel = gr3d_open_channel,
 123        .close_channel = gr3d_close_channel,
 124        .is_addr_reg = gr3d_is_addr_reg,
 125        .submit = tegra_drm_submit,
 126};
 127
 128static const struct of_device_id tegra_gr3d_match[] = {
 129        { .compatible = "nvidia,tegra114-gr3d" },
 130        { .compatible = "nvidia,tegra30-gr3d" },
 131        { .compatible = "nvidia,tegra20-gr3d" },
 132        { }
 133};
 134MODULE_DEVICE_TABLE(of, tegra_gr3d_match);
 135
 136static const u32 gr3d_addr_regs[] = {
 137        GR3D_IDX_ATTRIBUTE( 0),
 138        GR3D_IDX_ATTRIBUTE( 1),
 139        GR3D_IDX_ATTRIBUTE( 2),
 140        GR3D_IDX_ATTRIBUTE( 3),
 141        GR3D_IDX_ATTRIBUTE( 4),
 142        GR3D_IDX_ATTRIBUTE( 5),
 143        GR3D_IDX_ATTRIBUTE( 6),
 144        GR3D_IDX_ATTRIBUTE( 7),
 145        GR3D_IDX_ATTRIBUTE( 8),
 146        GR3D_IDX_ATTRIBUTE( 9),
 147        GR3D_IDX_ATTRIBUTE(10),
 148        GR3D_IDX_ATTRIBUTE(11),
 149        GR3D_IDX_ATTRIBUTE(12),
 150        GR3D_IDX_ATTRIBUTE(13),
 151        GR3D_IDX_ATTRIBUTE(14),
 152        GR3D_IDX_ATTRIBUTE(15),
 153        GR3D_IDX_INDEX_BASE,
 154        GR3D_QR_ZTAG_ADDR,
 155        GR3D_QR_CTAG_ADDR,
 156        GR3D_QR_CZ_ADDR,
 157        GR3D_TEX_TEX_ADDR( 0),
 158        GR3D_TEX_TEX_ADDR( 1),
 159        GR3D_TEX_TEX_ADDR( 2),
 160        GR3D_TEX_TEX_ADDR( 3),
 161        GR3D_TEX_TEX_ADDR( 4),
 162        GR3D_TEX_TEX_ADDR( 5),
 163        GR3D_TEX_TEX_ADDR( 6),
 164        GR3D_TEX_TEX_ADDR( 7),
 165        GR3D_TEX_TEX_ADDR( 8),
 166        GR3D_TEX_TEX_ADDR( 9),
 167        GR3D_TEX_TEX_ADDR(10),
 168        GR3D_TEX_TEX_ADDR(11),
 169        GR3D_TEX_TEX_ADDR(12),
 170        GR3D_TEX_TEX_ADDR(13),
 171        GR3D_TEX_TEX_ADDR(14),
 172        GR3D_TEX_TEX_ADDR(15),
 173        GR3D_DW_MEMORY_OUTPUT_ADDRESS,
 174        GR3D_GLOBAL_SURFADDR( 0),
 175        GR3D_GLOBAL_SURFADDR( 1),
 176        GR3D_GLOBAL_SURFADDR( 2),
 177        GR3D_GLOBAL_SURFADDR( 3),
 178        GR3D_GLOBAL_SURFADDR( 4),
 179        GR3D_GLOBAL_SURFADDR( 5),
 180        GR3D_GLOBAL_SURFADDR( 6),
 181        GR3D_GLOBAL_SURFADDR( 7),
 182        GR3D_GLOBAL_SURFADDR( 8),
 183        GR3D_GLOBAL_SURFADDR( 9),
 184        GR3D_GLOBAL_SURFADDR(10),
 185        GR3D_GLOBAL_SURFADDR(11),
 186        GR3D_GLOBAL_SURFADDR(12),
 187        GR3D_GLOBAL_SURFADDR(13),
 188        GR3D_GLOBAL_SURFADDR(14),
 189        GR3D_GLOBAL_SURFADDR(15),
 190        GR3D_GLOBAL_SPILLSURFADDR,
 191        GR3D_GLOBAL_SURFOVERADDR( 0),
 192        GR3D_GLOBAL_SURFOVERADDR( 1),
 193        GR3D_GLOBAL_SURFOVERADDR( 2),
 194        GR3D_GLOBAL_SURFOVERADDR( 3),
 195        GR3D_GLOBAL_SURFOVERADDR( 4),
 196        GR3D_GLOBAL_SURFOVERADDR( 5),
 197        GR3D_GLOBAL_SURFOVERADDR( 6),
 198        GR3D_GLOBAL_SURFOVERADDR( 7),
 199        GR3D_GLOBAL_SURFOVERADDR( 8),
 200        GR3D_GLOBAL_SURFOVERADDR( 9),
 201        GR3D_GLOBAL_SURFOVERADDR(10),
 202        GR3D_GLOBAL_SURFOVERADDR(11),
 203        GR3D_GLOBAL_SURFOVERADDR(12),
 204        GR3D_GLOBAL_SURFOVERADDR(13),
 205        GR3D_GLOBAL_SURFOVERADDR(14),
 206        GR3D_GLOBAL_SURFOVERADDR(15),
 207        GR3D_GLOBAL_SAMP01SURFADDR( 0),
 208        GR3D_GLOBAL_SAMP01SURFADDR( 1),
 209        GR3D_GLOBAL_SAMP01SURFADDR( 2),
 210        GR3D_GLOBAL_SAMP01SURFADDR( 3),
 211        GR3D_GLOBAL_SAMP01SURFADDR( 4),
 212        GR3D_GLOBAL_SAMP01SURFADDR( 5),
 213        GR3D_GLOBAL_SAMP01SURFADDR( 6),
 214        GR3D_GLOBAL_SAMP01SURFADDR( 7),
 215        GR3D_GLOBAL_SAMP01SURFADDR( 8),
 216        GR3D_GLOBAL_SAMP01SURFADDR( 9),
 217        GR3D_GLOBAL_SAMP01SURFADDR(10),
 218        GR3D_GLOBAL_SAMP01SURFADDR(11),
 219        GR3D_GLOBAL_SAMP01SURFADDR(12),
 220        GR3D_GLOBAL_SAMP01SURFADDR(13),
 221        GR3D_GLOBAL_SAMP01SURFADDR(14),
 222        GR3D_GLOBAL_SAMP01SURFADDR(15),
 223        GR3D_GLOBAL_SAMP23SURFADDR( 0),
 224        GR3D_GLOBAL_SAMP23SURFADDR( 1),
 225        GR3D_GLOBAL_SAMP23SURFADDR( 2),
 226        GR3D_GLOBAL_SAMP23SURFADDR( 3),
 227        GR3D_GLOBAL_SAMP23SURFADDR( 4),
 228        GR3D_GLOBAL_SAMP23SURFADDR( 5),
 229        GR3D_GLOBAL_SAMP23SURFADDR( 6),
 230        GR3D_GLOBAL_SAMP23SURFADDR( 7),
 231        GR3D_GLOBAL_SAMP23SURFADDR( 8),
 232        GR3D_GLOBAL_SAMP23SURFADDR( 9),
 233        GR3D_GLOBAL_SAMP23SURFADDR(10),
 234        GR3D_GLOBAL_SAMP23SURFADDR(11),
 235        GR3D_GLOBAL_SAMP23SURFADDR(12),
 236        GR3D_GLOBAL_SAMP23SURFADDR(13),
 237        GR3D_GLOBAL_SAMP23SURFADDR(14),
 238        GR3D_GLOBAL_SAMP23SURFADDR(15),
 239};
 240
 241static int gr3d_probe(struct platform_device *pdev)
 242{
 243        struct device_node *np = pdev->dev.of_node;
 244        struct host1x_syncpt **syncpts;
 245        struct gr3d *gr3d;
 246        unsigned int i;
 247        int err;
 248
 249        gr3d = devm_kzalloc(&pdev->dev, sizeof(*gr3d), GFP_KERNEL);
 250        if (!gr3d)
 251                return -ENOMEM;
 252
 253        syncpts = devm_kzalloc(&pdev->dev, sizeof(*syncpts), GFP_KERNEL);
 254        if (!syncpts)
 255                return -ENOMEM;
 256
 257        gr3d->clk = devm_clk_get(&pdev->dev, NULL);
 258        if (IS_ERR(gr3d->clk)) {
 259                dev_err(&pdev->dev, "cannot get clock\n");
 260                return PTR_ERR(gr3d->clk);
 261        }
 262
 263        gr3d->rst = devm_reset_control_get(&pdev->dev, "3d");
 264        if (IS_ERR(gr3d->rst)) {
 265                dev_err(&pdev->dev, "cannot get reset\n");
 266                return PTR_ERR(gr3d->rst);
 267        }
 268
 269        if (of_device_is_compatible(np, "nvidia,tegra30-gr3d")) {
 270                gr3d->clk_secondary = devm_clk_get(&pdev->dev, "3d2");
 271                if (IS_ERR(gr3d->clk)) {
 272                        dev_err(&pdev->dev, "cannot get secondary clock\n");
 273                        return PTR_ERR(gr3d->clk);
 274                }
 275
 276                gr3d->rst_secondary = devm_reset_control_get(&pdev->dev,
 277                                                                "3d2");
 278                if (IS_ERR(gr3d->rst_secondary)) {
 279                        dev_err(&pdev->dev, "cannot get secondary reset\n");
 280                        return PTR_ERR(gr3d->rst_secondary);
 281                }
 282        }
 283
 284        err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D, gr3d->clk,
 285                                                gr3d->rst);
 286        if (err < 0) {
 287                dev_err(&pdev->dev, "failed to power up 3D unit\n");
 288                return err;
 289        }
 290
 291        if (gr3d->clk_secondary) {
 292                err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D1,
 293                                                        gr3d->clk_secondary,
 294                                                        gr3d->rst_secondary);
 295                if (err < 0) {
 296                        dev_err(&pdev->dev,
 297                                "failed to power up secondary 3D unit\n");
 298                        return err;
 299                }
 300        }
 301
 302        INIT_LIST_HEAD(&gr3d->client.base.list);
 303        gr3d->client.base.ops = &gr3d_client_ops;
 304        gr3d->client.base.dev = &pdev->dev;
 305        gr3d->client.base.class = HOST1X_CLASS_GR3D;
 306        gr3d->client.base.syncpts = syncpts;
 307        gr3d->client.base.num_syncpts = 1;
 308
 309        INIT_LIST_HEAD(&gr3d->client.list);
 310        gr3d->client.ops = &gr3d_ops;
 311
 312        err = host1x_client_register(&gr3d->client.base);
 313        if (err < 0) {
 314                dev_err(&pdev->dev, "failed to register host1x client: %d\n",
 315                        err);
 316                return err;
 317        }
 318
 319        /* initialize address register map */
 320        for (i = 0; i < ARRAY_SIZE(gr3d_addr_regs); i++)
 321                set_bit(gr3d_addr_regs[i], gr3d->addr_regs);
 322
 323        platform_set_drvdata(pdev, gr3d);
 324
 325        return 0;
 326}
 327
 328static int gr3d_remove(struct platform_device *pdev)
 329{
 330        struct gr3d *gr3d = platform_get_drvdata(pdev);
 331        int err;
 332
 333        err = host1x_client_unregister(&gr3d->client.base);
 334        if (err < 0) {
 335                dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
 336                        err);
 337                return err;
 338        }
 339
 340        if (gr3d->clk_secondary) {
 341                tegra_powergate_power_off(TEGRA_POWERGATE_3D1);
 342                clk_disable_unprepare(gr3d->clk_secondary);
 343        }
 344
 345        tegra_powergate_power_off(TEGRA_POWERGATE_3D);
 346        clk_disable_unprepare(gr3d->clk);
 347
 348        return 0;
 349}
 350
 351struct platform_driver tegra_gr3d_driver = {
 352        .driver = {
 353                .name = "tegra-gr3d",
 354                .of_match_table = tegra_gr3d_match,
 355        },
 356        .probe = gr3d_probe,
 357        .remove = gr3d_remove,
 358};
 359