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