root/drivers/gpu/drm/tegra/vic.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. to_vic
  2. vic_writel
  3. vic_runtime_resume
  4. vic_runtime_suspend
  5. vic_boot
  6. vic_falcon_alloc
  7. vic_falcon_free
  8. vic_init
  9. vic_exit
  10. vic_load_firmware
  11. vic_open_channel
  12. vic_close_channel
  13. vic_probe
  14. vic_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (c) 2015, NVIDIA Corporation.
   4  */
   5 
   6 #include <linux/clk.h>
   7 #include <linux/delay.h>
   8 #include <linux/host1x.h>
   9 #include <linux/iommu.h>
  10 #include <linux/module.h>
  11 #include <linux/of.h>
  12 #include <linux/of_device.h>
  13 #include <linux/of_platform.h>
  14 #include <linux/platform_device.h>
  15 #include <linux/pm_runtime.h>
  16 #include <linux/reset.h>
  17 
  18 #include <soc/tegra/pmc.h>
  19 
  20 #include "drm.h"
  21 #include "falcon.h"
  22 #include "vic.h"
  23 
  24 struct vic_config {
  25         const char *firmware;
  26         unsigned int version;
  27         bool supports_sid;
  28 };
  29 
  30 struct vic {
  31         struct falcon falcon;
  32         bool booted;
  33 
  34         void __iomem *regs;
  35         struct tegra_drm_client client;
  36         struct host1x_channel *channel;
  37         struct iommu_domain *domain;
  38         struct device *dev;
  39         struct clk *clk;
  40         struct reset_control *rst;
  41 
  42         /* Platform configuration */
  43         const struct vic_config *config;
  44 };
  45 
  46 static inline struct vic *to_vic(struct tegra_drm_client *client)
  47 {
  48         return container_of(client, struct vic, client);
  49 }
  50 
  51 static void vic_writel(struct vic *vic, u32 value, unsigned int offset)
  52 {
  53         writel(value, vic->regs + offset);
  54 }
  55 
  56 static int vic_runtime_resume(struct device *dev)
  57 {
  58         struct vic *vic = dev_get_drvdata(dev);
  59         int err;
  60 
  61         err = clk_prepare_enable(vic->clk);
  62         if (err < 0)
  63                 return err;
  64 
  65         usleep_range(10, 20);
  66 
  67         err = reset_control_deassert(vic->rst);
  68         if (err < 0)
  69                 goto disable;
  70 
  71         usleep_range(10, 20);
  72 
  73         return 0;
  74 
  75 disable:
  76         clk_disable_unprepare(vic->clk);
  77         return err;
  78 }
  79 
  80 static int vic_runtime_suspend(struct device *dev)
  81 {
  82         struct vic *vic = dev_get_drvdata(dev);
  83         int err;
  84 
  85         err = reset_control_assert(vic->rst);
  86         if (err < 0)
  87                 return err;
  88 
  89         usleep_range(2000, 4000);
  90 
  91         clk_disable_unprepare(vic->clk);
  92 
  93         vic->booted = false;
  94 
  95         return 0;
  96 }
  97 
  98 static int vic_boot(struct vic *vic)
  99 {
 100         u32 fce_ucode_size, fce_bin_data_offset;
 101         void *hdr;
 102         int err = 0;
 103 
 104         if (vic->booted)
 105                 return 0;
 106 
 107 #ifdef CONFIG_IOMMU_API
 108         if (vic->config->supports_sid) {
 109                 struct iommu_fwspec *spec = dev_iommu_fwspec_get(vic->dev);
 110                 u32 value;
 111 
 112                 value = TRANSCFG_ATT(1, TRANSCFG_SID_FALCON) |
 113                         TRANSCFG_ATT(0, TRANSCFG_SID_HW);
 114                 vic_writel(vic, value, VIC_TFBIF_TRANSCFG);
 115 
 116                 if (spec && spec->num_ids > 0) {
 117                         value = spec->ids[0] & 0xffff;
 118 
 119                         vic_writel(vic, value, VIC_THI_STREAMID0);
 120                         vic_writel(vic, value, VIC_THI_STREAMID1);
 121                 }
 122         }
 123 #endif
 124 
 125         /* setup clockgating registers */
 126         vic_writel(vic, CG_IDLE_CG_DLY_CNT(4) |
 127                         CG_IDLE_CG_EN |
 128                         CG_WAKEUP_DLY_CNT(4),
 129                    NV_PVIC_MISC_PRI_VIC_CG);
 130 
 131         err = falcon_boot(&vic->falcon);
 132         if (err < 0)
 133                 return err;
 134 
 135         hdr = vic->falcon.firmware.vaddr;
 136         fce_bin_data_offset = *(u32 *)(hdr + VIC_UCODE_FCE_DATA_OFFSET);
 137         hdr = vic->falcon.firmware.vaddr +
 138                 *(u32 *)(hdr + VIC_UCODE_FCE_HEADER_OFFSET);
 139         fce_ucode_size = *(u32 *)(hdr + FCE_UCODE_SIZE_OFFSET);
 140 
 141         falcon_execute_method(&vic->falcon, VIC_SET_APPLICATION_ID, 1);
 142         falcon_execute_method(&vic->falcon, VIC_SET_FCE_UCODE_SIZE,
 143                               fce_ucode_size);
 144         falcon_execute_method(&vic->falcon, VIC_SET_FCE_UCODE_OFFSET,
 145                               (vic->falcon.firmware.paddr + fce_bin_data_offset)
 146                                 >> 8);
 147 
 148         err = falcon_wait_idle(&vic->falcon);
 149         if (err < 0) {
 150                 dev_err(vic->dev,
 151                         "failed to set application ID and FCE base\n");
 152                 return err;
 153         }
 154 
 155         vic->booted = true;
 156 
 157         return 0;
 158 }
 159 
 160 static void *vic_falcon_alloc(struct falcon *falcon, size_t size,
 161                               dma_addr_t *iova)
 162 {
 163         struct tegra_drm *tegra = falcon->data;
 164 
 165         return tegra_drm_alloc(tegra, size, iova);
 166 }
 167 
 168 static void vic_falcon_free(struct falcon *falcon, size_t size,
 169                             dma_addr_t iova, void *va)
 170 {
 171         struct tegra_drm *tegra = falcon->data;
 172 
 173         return tegra_drm_free(tegra, size, va, iova);
 174 }
 175 
 176 static const struct falcon_ops vic_falcon_ops = {
 177         .alloc = vic_falcon_alloc,
 178         .free = vic_falcon_free
 179 };
 180 
 181 static int vic_init(struct host1x_client *client)
 182 {
 183         struct tegra_drm_client *drm = host1x_to_drm_client(client);
 184         struct iommu_group *group = iommu_group_get(client->dev);
 185         struct drm_device *dev = dev_get_drvdata(client->parent);
 186         struct tegra_drm *tegra = dev->dev_private;
 187         struct vic *vic = to_vic(drm);
 188         int err;
 189 
 190         if (group && tegra->domain) {
 191                 err = iommu_attach_group(tegra->domain, group);
 192                 if (err < 0) {
 193                         dev_err(vic->dev, "failed to attach to domain: %d\n",
 194                                 err);
 195                         return err;
 196                 }
 197 
 198                 vic->domain = tegra->domain;
 199         }
 200 
 201         vic->channel = host1x_channel_request(client->dev);
 202         if (!vic->channel) {
 203                 err = -ENOMEM;
 204                 goto detach;
 205         }
 206 
 207         client->syncpts[0] = host1x_syncpt_request(client, 0);
 208         if (!client->syncpts[0]) {
 209                 err = -ENOMEM;
 210                 goto free_channel;
 211         }
 212 
 213         err = tegra_drm_register_client(tegra, drm);
 214         if (err < 0)
 215                 goto free_syncpt;
 216 
 217         return 0;
 218 
 219 free_syncpt:
 220         host1x_syncpt_free(client->syncpts[0]);
 221 free_channel:
 222         host1x_channel_put(vic->channel);
 223 detach:
 224         if (group && tegra->domain)
 225                 iommu_detach_group(tegra->domain, group);
 226 
 227         return err;
 228 }
 229 
 230 static int vic_exit(struct host1x_client *client)
 231 {
 232         struct tegra_drm_client *drm = host1x_to_drm_client(client);
 233         struct iommu_group *group = iommu_group_get(client->dev);
 234         struct drm_device *dev = dev_get_drvdata(client->parent);
 235         struct tegra_drm *tegra = dev->dev_private;
 236         struct vic *vic = to_vic(drm);
 237         int err;
 238 
 239         err = tegra_drm_unregister_client(tegra, drm);
 240         if (err < 0)
 241                 return err;
 242 
 243         host1x_syncpt_free(client->syncpts[0]);
 244         host1x_channel_put(vic->channel);
 245 
 246         if (vic->domain) {
 247                 iommu_detach_group(vic->domain, group);
 248                 vic->domain = NULL;
 249         }
 250 
 251         return 0;
 252 }
 253 
 254 static const struct host1x_client_ops vic_client_ops = {
 255         .init = vic_init,
 256         .exit = vic_exit,
 257 };
 258 
 259 static int vic_load_firmware(struct vic *vic)
 260 {
 261         int err;
 262 
 263         if (vic->falcon.data)
 264                 return 0;
 265 
 266         vic->falcon.data = vic->client.drm;
 267 
 268         err = falcon_read_firmware(&vic->falcon, vic->config->firmware);
 269         if (err < 0)
 270                 goto cleanup;
 271 
 272         err = falcon_load_firmware(&vic->falcon);
 273         if (err < 0)
 274                 goto cleanup;
 275 
 276         return 0;
 277 
 278 cleanup:
 279         vic->falcon.data = NULL;
 280         return err;
 281 }
 282 
 283 static int vic_open_channel(struct tegra_drm_client *client,
 284                             struct tegra_drm_context *context)
 285 {
 286         struct vic *vic = to_vic(client);
 287         int err;
 288 
 289         err = pm_runtime_get_sync(vic->dev);
 290         if (err < 0)
 291                 return err;
 292 
 293         err = vic_load_firmware(vic);
 294         if (err < 0)
 295                 goto rpm_put;
 296 
 297         err = vic_boot(vic);
 298         if (err < 0)
 299                 goto rpm_put;
 300 
 301         context->channel = host1x_channel_get(vic->channel);
 302         if (!context->channel) {
 303                 err = -ENOMEM;
 304                 goto rpm_put;
 305         }
 306 
 307         return 0;
 308 
 309 rpm_put:
 310         pm_runtime_put(vic->dev);
 311         return err;
 312 }
 313 
 314 static void vic_close_channel(struct tegra_drm_context *context)
 315 {
 316         struct vic *vic = to_vic(context->client);
 317 
 318         host1x_channel_put(context->channel);
 319 
 320         pm_runtime_put(vic->dev);
 321 }
 322 
 323 static const struct tegra_drm_client_ops vic_ops = {
 324         .open_channel = vic_open_channel,
 325         .close_channel = vic_close_channel,
 326         .submit = tegra_drm_submit,
 327 };
 328 
 329 #define NVIDIA_TEGRA_124_VIC_FIRMWARE "nvidia/tegra124/vic03_ucode.bin"
 330 
 331 static const struct vic_config vic_t124_config = {
 332         .firmware = NVIDIA_TEGRA_124_VIC_FIRMWARE,
 333         .version = 0x40,
 334         .supports_sid = false,
 335 };
 336 
 337 #define NVIDIA_TEGRA_210_VIC_FIRMWARE "nvidia/tegra210/vic04_ucode.bin"
 338 
 339 static const struct vic_config vic_t210_config = {
 340         .firmware = NVIDIA_TEGRA_210_VIC_FIRMWARE,
 341         .version = 0x21,
 342         .supports_sid = false,
 343 };
 344 
 345 #define NVIDIA_TEGRA_186_VIC_FIRMWARE "nvidia/tegra186/vic04_ucode.bin"
 346 
 347 static const struct vic_config vic_t186_config = {
 348         .firmware = NVIDIA_TEGRA_186_VIC_FIRMWARE,
 349         .version = 0x18,
 350         .supports_sid = true,
 351 };
 352 
 353 #define NVIDIA_TEGRA_194_VIC_FIRMWARE "nvidia/tegra194/vic.bin"
 354 
 355 static const struct vic_config vic_t194_config = {
 356         .firmware = NVIDIA_TEGRA_194_VIC_FIRMWARE,
 357         .version = 0x19,
 358         .supports_sid = true,
 359 };
 360 
 361 static const struct of_device_id vic_match[] = {
 362         { .compatible = "nvidia,tegra124-vic", .data = &vic_t124_config },
 363         { .compatible = "nvidia,tegra210-vic", .data = &vic_t210_config },
 364         { .compatible = "nvidia,tegra186-vic", .data = &vic_t186_config },
 365         { .compatible = "nvidia,tegra194-vic", .data = &vic_t194_config },
 366         { },
 367 };
 368 
 369 static int vic_probe(struct platform_device *pdev)
 370 {
 371         struct device *dev = &pdev->dev;
 372         struct host1x_syncpt **syncpts;
 373         struct resource *regs;
 374         struct vic *vic;
 375         int err;
 376 
 377         vic = devm_kzalloc(dev, sizeof(*vic), GFP_KERNEL);
 378         if (!vic)
 379                 return -ENOMEM;
 380 
 381         vic->config = of_device_get_match_data(dev);
 382 
 383         syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL);
 384         if (!syncpts)
 385                 return -ENOMEM;
 386 
 387         regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 388         if (!regs) {
 389                 dev_err(&pdev->dev, "failed to get registers\n");
 390                 return -ENXIO;
 391         }
 392 
 393         vic->regs = devm_ioremap_resource(dev, regs);
 394         if (IS_ERR(vic->regs))
 395                 return PTR_ERR(vic->regs);
 396 
 397         vic->clk = devm_clk_get(dev, NULL);
 398         if (IS_ERR(vic->clk)) {
 399                 dev_err(&pdev->dev, "failed to get clock\n");
 400                 return PTR_ERR(vic->clk);
 401         }
 402 
 403         if (!dev->pm_domain) {
 404                 vic->rst = devm_reset_control_get(dev, "vic");
 405                 if (IS_ERR(vic->rst)) {
 406                         dev_err(&pdev->dev, "failed to get reset\n");
 407                         return PTR_ERR(vic->rst);
 408                 }
 409         }
 410 
 411         vic->falcon.dev = dev;
 412         vic->falcon.regs = vic->regs;
 413         vic->falcon.ops = &vic_falcon_ops;
 414 
 415         err = falcon_init(&vic->falcon);
 416         if (err < 0)
 417                 return err;
 418 
 419         platform_set_drvdata(pdev, vic);
 420 
 421         INIT_LIST_HEAD(&vic->client.base.list);
 422         vic->client.base.ops = &vic_client_ops;
 423         vic->client.base.dev = dev;
 424         vic->client.base.class = HOST1X_CLASS_VIC;
 425         vic->client.base.syncpts = syncpts;
 426         vic->client.base.num_syncpts = 1;
 427         vic->dev = dev;
 428 
 429         INIT_LIST_HEAD(&vic->client.list);
 430         vic->client.version = vic->config->version;
 431         vic->client.ops = &vic_ops;
 432 
 433         err = host1x_client_register(&vic->client.base);
 434         if (err < 0) {
 435                 dev_err(dev, "failed to register host1x client: %d\n", err);
 436                 goto exit_falcon;
 437         }
 438 
 439         pm_runtime_enable(&pdev->dev);
 440         if (!pm_runtime_enabled(&pdev->dev)) {
 441                 err = vic_runtime_resume(&pdev->dev);
 442                 if (err < 0)
 443                         goto unregister_client;
 444         }
 445 
 446         return 0;
 447 
 448 unregister_client:
 449         host1x_client_unregister(&vic->client.base);
 450 exit_falcon:
 451         falcon_exit(&vic->falcon);
 452 
 453         return err;
 454 }
 455 
 456 static int vic_remove(struct platform_device *pdev)
 457 {
 458         struct vic *vic = platform_get_drvdata(pdev);
 459         int err;
 460 
 461         err = host1x_client_unregister(&vic->client.base);
 462         if (err < 0) {
 463                 dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
 464                         err);
 465                 return err;
 466         }
 467 
 468         if (pm_runtime_enabled(&pdev->dev))
 469                 pm_runtime_disable(&pdev->dev);
 470         else
 471                 vic_runtime_suspend(&pdev->dev);
 472 
 473         falcon_exit(&vic->falcon);
 474 
 475         return 0;
 476 }
 477 
 478 static const struct dev_pm_ops vic_pm_ops = {
 479         SET_RUNTIME_PM_OPS(vic_runtime_suspend, vic_runtime_resume, NULL)
 480 };
 481 
 482 struct platform_driver tegra_vic_driver = {
 483         .driver = {
 484                 .name = "tegra-vic",
 485                 .of_match_table = vic_match,
 486                 .pm = &vic_pm_ops
 487         },
 488         .probe = vic_probe,
 489         .remove = vic_remove,
 490 };
 491 
 492 #if IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC)
 493 MODULE_FIRMWARE(NVIDIA_TEGRA_124_VIC_FIRMWARE);
 494 #endif
 495 #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
 496 MODULE_FIRMWARE(NVIDIA_TEGRA_210_VIC_FIRMWARE);
 497 #endif
 498 #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC)
 499 MODULE_FIRMWARE(NVIDIA_TEGRA_186_VIC_FIRMWARE);
 500 #endif
 501 #if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
 502 MODULE_FIRMWARE(NVIDIA_TEGRA_194_VIC_FIRMWARE);
 503 #endif

/* [<][>][^][v][top][bottom][index][help] */