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