Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2015, NVIDIA Corporation.
0004  */
0005 
0006 #include <linux/clk.h>
0007 #include <linux/delay.h>
0008 #include <linux/dma-mapping.h>
0009 #include <linux/host1x.h>
0010 #include <linux/iommu.h>
0011 #include <linux/module.h>
0012 #include <linux/of.h>
0013 #include <linux/of_device.h>
0014 #include <linux/of_platform.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/pm_runtime.h>
0017 #include <linux/reset.h>
0018 
0019 #include <soc/tegra/pmc.h>
0020 
0021 #include "drm.h"
0022 #include "falcon.h"
0023 #include "vic.h"
0024 
0025 struct vic_config {
0026     const char *firmware;
0027     unsigned int version;
0028     bool supports_sid;
0029 };
0030 
0031 struct vic {
0032     struct falcon falcon;
0033 
0034     void __iomem *regs;
0035     struct tegra_drm_client client;
0036     struct host1x_channel *channel;
0037     struct device *dev;
0038     struct clk *clk;
0039     struct reset_control *rst;
0040 
0041     bool can_use_context;
0042 
0043     /* Platform configuration */
0044     const struct vic_config *config;
0045 };
0046 
0047 static inline struct vic *to_vic(struct tegra_drm_client *client)
0048 {
0049     return container_of(client, struct vic, client);
0050 }
0051 
0052 static void vic_writel(struct vic *vic, u32 value, unsigned int offset)
0053 {
0054     writel(value, vic->regs + offset);
0055 }
0056 
0057 static int vic_boot(struct vic *vic)
0058 {
0059 #ifdef CONFIG_IOMMU_API
0060     struct iommu_fwspec *spec = dev_iommu_fwspec_get(vic->dev);
0061 #endif
0062     u32 fce_ucode_size, fce_bin_data_offset;
0063     void *hdr;
0064     int err = 0;
0065 
0066 #ifdef CONFIG_IOMMU_API
0067     if (vic->config->supports_sid && spec) {
0068         u32 value;
0069 
0070         value = TRANSCFG_ATT(1, TRANSCFG_SID_FALCON) |
0071             TRANSCFG_ATT(0, TRANSCFG_SID_HW);
0072         vic_writel(vic, value, VIC_TFBIF_TRANSCFG);
0073 
0074         if (spec->num_ids > 0) {
0075             value = spec->ids[0] & 0xffff;
0076 
0077             /*
0078              * STREAMID0 is used for input/output buffers.
0079              * Initialize it to SID_VIC in case context isolation
0080              * is not enabled, and SID_VIC is used for both firmware
0081              * and data buffers.
0082              *
0083              * If context isolation is enabled, it will be
0084              * overridden by the SETSTREAMID opcode as part of
0085              * each job.
0086              */
0087             vic_writel(vic, value, VIC_THI_STREAMID0);
0088 
0089             /* STREAMID1 is used for firmware loading. */
0090             vic_writel(vic, value, VIC_THI_STREAMID1);
0091         }
0092     }
0093 #endif
0094 
0095     /* setup clockgating registers */
0096     vic_writel(vic, CG_IDLE_CG_DLY_CNT(4) |
0097             CG_IDLE_CG_EN |
0098             CG_WAKEUP_DLY_CNT(4),
0099            NV_PVIC_MISC_PRI_VIC_CG);
0100 
0101     err = falcon_boot(&vic->falcon);
0102     if (err < 0)
0103         return err;
0104 
0105     hdr = vic->falcon.firmware.virt;
0106     fce_bin_data_offset = *(u32 *)(hdr + VIC_UCODE_FCE_DATA_OFFSET);
0107 
0108     /* Old VIC firmware needs kernel help with setting up FCE microcode. */
0109     if (fce_bin_data_offset != 0x0 && fce_bin_data_offset != 0xa5a5a5a5) {
0110         hdr = vic->falcon.firmware.virt +
0111             *(u32 *)(hdr + VIC_UCODE_FCE_HEADER_OFFSET);
0112         fce_ucode_size = *(u32 *)(hdr + FCE_UCODE_SIZE_OFFSET);
0113 
0114         falcon_execute_method(&vic->falcon, VIC_SET_FCE_UCODE_SIZE,
0115                       fce_ucode_size);
0116         falcon_execute_method(
0117             &vic->falcon, VIC_SET_FCE_UCODE_OFFSET,
0118             (vic->falcon.firmware.iova + fce_bin_data_offset) >> 8);
0119     }
0120 
0121     err = falcon_wait_idle(&vic->falcon);
0122     if (err < 0) {
0123         dev_err(vic->dev,
0124             "failed to set application ID and FCE base\n");
0125         return err;
0126     }
0127 
0128     return 0;
0129 }
0130 
0131 static int vic_init(struct host1x_client *client)
0132 {
0133     struct tegra_drm_client *drm = host1x_to_drm_client(client);
0134     struct drm_device *dev = dev_get_drvdata(client->host);
0135     struct tegra_drm *tegra = dev->dev_private;
0136     struct vic *vic = to_vic(drm);
0137     int err;
0138 
0139     err = host1x_client_iommu_attach(client);
0140     if (err < 0 && err != -ENODEV) {
0141         dev_err(vic->dev, "failed to attach to domain: %d\n", err);
0142         return err;
0143     }
0144 
0145     vic->channel = host1x_channel_request(client);
0146     if (!vic->channel) {
0147         err = -ENOMEM;
0148         goto detach;
0149     }
0150 
0151     client->syncpts[0] = host1x_syncpt_request(client, 0);
0152     if (!client->syncpts[0]) {
0153         err = -ENOMEM;
0154         goto free_channel;
0155     }
0156 
0157     pm_runtime_enable(client->dev);
0158     pm_runtime_use_autosuspend(client->dev);
0159     pm_runtime_set_autosuspend_delay(client->dev, 500);
0160 
0161     err = tegra_drm_register_client(tegra, drm);
0162     if (err < 0)
0163         goto disable_rpm;
0164 
0165     /*
0166      * Inherit the DMA parameters (such as maximum segment size) from the
0167      * parent host1x device.
0168      */
0169     client->dev->dma_parms = client->host->dma_parms;
0170 
0171     return 0;
0172 
0173 disable_rpm:
0174     pm_runtime_dont_use_autosuspend(client->dev);
0175     pm_runtime_force_suspend(client->dev);
0176 
0177     host1x_syncpt_put(client->syncpts[0]);
0178 free_channel:
0179     host1x_channel_put(vic->channel);
0180 detach:
0181     host1x_client_iommu_detach(client);
0182 
0183     return err;
0184 }
0185 
0186 static int vic_exit(struct host1x_client *client)
0187 {
0188     struct tegra_drm_client *drm = host1x_to_drm_client(client);
0189     struct drm_device *dev = dev_get_drvdata(client->host);
0190     struct tegra_drm *tegra = dev->dev_private;
0191     struct vic *vic = to_vic(drm);
0192     int err;
0193 
0194     /* avoid a dangling pointer just in case this disappears */
0195     client->dev->dma_parms = NULL;
0196 
0197     err = tegra_drm_unregister_client(tegra, drm);
0198     if (err < 0)
0199         return err;
0200 
0201     pm_runtime_dont_use_autosuspend(client->dev);
0202     pm_runtime_force_suspend(client->dev);
0203 
0204     host1x_syncpt_put(client->syncpts[0]);
0205     host1x_channel_put(vic->channel);
0206     host1x_client_iommu_detach(client);
0207 
0208     vic->channel = NULL;
0209 
0210     if (client->group) {
0211         dma_unmap_single(vic->dev, vic->falcon.firmware.phys,
0212                  vic->falcon.firmware.size, DMA_TO_DEVICE);
0213         tegra_drm_free(tegra, vic->falcon.firmware.size,
0214                    vic->falcon.firmware.virt,
0215                    vic->falcon.firmware.iova);
0216     } else {
0217         dma_free_coherent(vic->dev, vic->falcon.firmware.size,
0218                   vic->falcon.firmware.virt,
0219                   vic->falcon.firmware.iova);
0220     }
0221 
0222     return 0;
0223 }
0224 
0225 static const struct host1x_client_ops vic_client_ops = {
0226     .init = vic_init,
0227     .exit = vic_exit,
0228 };
0229 
0230 static int vic_load_firmware(struct vic *vic)
0231 {
0232     struct host1x_client *client = &vic->client.base;
0233     struct tegra_drm *tegra = vic->client.drm;
0234     static DEFINE_MUTEX(lock);
0235     u32 fce_bin_data_offset;
0236     dma_addr_t iova;
0237     size_t size;
0238     void *virt;
0239     int err;
0240 
0241     mutex_lock(&lock);
0242 
0243     if (vic->falcon.firmware.virt) {
0244         err = 0;
0245         goto unlock;
0246     }
0247 
0248     err = falcon_read_firmware(&vic->falcon, vic->config->firmware);
0249     if (err < 0)
0250         goto unlock;
0251 
0252     size = vic->falcon.firmware.size;
0253 
0254     if (!client->group) {
0255         virt = dma_alloc_coherent(vic->dev, size, &iova, GFP_KERNEL);
0256         if (!virt) {
0257             err = -ENOMEM;
0258             goto unlock;
0259         }
0260     } else {
0261         virt = tegra_drm_alloc(tegra, size, &iova);
0262         if (IS_ERR(virt)) {
0263             err = PTR_ERR(virt);
0264             goto unlock;
0265         }
0266     }
0267 
0268     vic->falcon.firmware.virt = virt;
0269     vic->falcon.firmware.iova = iova;
0270 
0271     err = falcon_load_firmware(&vic->falcon);
0272     if (err < 0)
0273         goto cleanup;
0274 
0275     /*
0276      * In this case we have received an IOVA from the shared domain, so we
0277      * need to make sure to get the physical address so that the DMA API
0278      * knows what memory pages to flush the cache for.
0279      */
0280     if (client->group) {
0281         dma_addr_t phys;
0282 
0283         phys = dma_map_single(vic->dev, virt, size, DMA_TO_DEVICE);
0284 
0285         err = dma_mapping_error(vic->dev, phys);
0286         if (err < 0)
0287             goto cleanup;
0288 
0289         vic->falcon.firmware.phys = phys;
0290     }
0291 
0292     /*
0293      * Check if firmware is new enough to not require mapping firmware
0294      * to data buffer domains.
0295      */
0296     fce_bin_data_offset = *(u32 *)(virt + VIC_UCODE_FCE_DATA_OFFSET);
0297 
0298     if (!vic->config->supports_sid) {
0299         vic->can_use_context = false;
0300     } else if (fce_bin_data_offset != 0x0 && fce_bin_data_offset != 0xa5a5a5a5) {
0301         /*
0302          * Firmware will access FCE through STREAMID0, so context
0303          * isolation cannot be used.
0304          */
0305         vic->can_use_context = false;
0306         dev_warn_once(vic->dev, "context isolation disabled due to old firmware\n");
0307     } else {
0308         vic->can_use_context = true;
0309     }
0310 
0311 unlock:
0312     mutex_unlock(&lock);
0313     return err;
0314 
0315 cleanup:
0316     if (!client->group)
0317         dma_free_coherent(vic->dev, size, virt, iova);
0318     else
0319         tegra_drm_free(tegra, size, virt, iova);
0320 
0321     mutex_unlock(&lock);
0322     return err;
0323 }
0324 
0325 
0326 static int __maybe_unused vic_runtime_resume(struct device *dev)
0327 {
0328     struct vic *vic = dev_get_drvdata(dev);
0329     int err;
0330 
0331     err = clk_prepare_enable(vic->clk);
0332     if (err < 0)
0333         return err;
0334 
0335     usleep_range(10, 20);
0336 
0337     err = reset_control_deassert(vic->rst);
0338     if (err < 0)
0339         goto disable;
0340 
0341     usleep_range(10, 20);
0342 
0343     err = vic_load_firmware(vic);
0344     if (err < 0)
0345         goto assert;
0346 
0347     err = vic_boot(vic);
0348     if (err < 0)
0349         goto assert;
0350 
0351     return 0;
0352 
0353 assert:
0354     reset_control_assert(vic->rst);
0355 disable:
0356     clk_disable_unprepare(vic->clk);
0357     return err;
0358 }
0359 
0360 static int __maybe_unused vic_runtime_suspend(struct device *dev)
0361 {
0362     struct vic *vic = dev_get_drvdata(dev);
0363     int err;
0364 
0365     host1x_channel_stop(vic->channel);
0366 
0367     err = reset_control_assert(vic->rst);
0368     if (err < 0)
0369         return err;
0370 
0371     usleep_range(2000, 4000);
0372 
0373     clk_disable_unprepare(vic->clk);
0374 
0375     return 0;
0376 }
0377 
0378 static int vic_open_channel(struct tegra_drm_client *client,
0379                 struct tegra_drm_context *context)
0380 {
0381     struct vic *vic = to_vic(client);
0382 
0383     context->channel = host1x_channel_get(vic->channel);
0384     if (!context->channel)
0385         return -ENOMEM;
0386 
0387     return 0;
0388 }
0389 
0390 static void vic_close_channel(struct tegra_drm_context *context)
0391 {
0392     host1x_channel_put(context->channel);
0393 }
0394 
0395 static int vic_can_use_memory_ctx(struct tegra_drm_client *client, bool *supported)
0396 {
0397     struct vic *vic = to_vic(client);
0398     int err;
0399 
0400     /* This doesn't access HW so it's safe to call without powering up. */
0401     err = vic_load_firmware(vic);
0402     if (err < 0)
0403         return err;
0404 
0405     *supported = vic->can_use_context;
0406 
0407     return 0;
0408 }
0409 
0410 static const struct tegra_drm_client_ops vic_ops = {
0411     .open_channel = vic_open_channel,
0412     .close_channel = vic_close_channel,
0413     .submit = tegra_drm_submit,
0414     .get_streamid_offset = tegra_drm_get_streamid_offset_thi,
0415     .can_use_memory_ctx = vic_can_use_memory_ctx,
0416 };
0417 
0418 #define NVIDIA_TEGRA_124_VIC_FIRMWARE "nvidia/tegra124/vic03_ucode.bin"
0419 
0420 static const struct vic_config vic_t124_config = {
0421     .firmware = NVIDIA_TEGRA_124_VIC_FIRMWARE,
0422     .version = 0x40,
0423     .supports_sid = false,
0424 };
0425 
0426 #define NVIDIA_TEGRA_210_VIC_FIRMWARE "nvidia/tegra210/vic04_ucode.bin"
0427 
0428 static const struct vic_config vic_t210_config = {
0429     .firmware = NVIDIA_TEGRA_210_VIC_FIRMWARE,
0430     .version = 0x21,
0431     .supports_sid = false,
0432 };
0433 
0434 #define NVIDIA_TEGRA_186_VIC_FIRMWARE "nvidia/tegra186/vic04_ucode.bin"
0435 
0436 static const struct vic_config vic_t186_config = {
0437     .firmware = NVIDIA_TEGRA_186_VIC_FIRMWARE,
0438     .version = 0x18,
0439     .supports_sid = true,
0440 };
0441 
0442 #define NVIDIA_TEGRA_194_VIC_FIRMWARE "nvidia/tegra194/vic.bin"
0443 
0444 static const struct vic_config vic_t194_config = {
0445     .firmware = NVIDIA_TEGRA_194_VIC_FIRMWARE,
0446     .version = 0x19,
0447     .supports_sid = true,
0448 };
0449 
0450 #define NVIDIA_TEGRA_234_VIC_FIRMWARE "nvidia/tegra234/vic.bin"
0451 
0452 static const struct vic_config vic_t234_config = {
0453     .firmware = NVIDIA_TEGRA_234_VIC_FIRMWARE,
0454     .version = 0x23,
0455     .supports_sid = true,
0456 };
0457 
0458 static const struct of_device_id tegra_vic_of_match[] = {
0459     { .compatible = "nvidia,tegra124-vic", .data = &vic_t124_config },
0460     { .compatible = "nvidia,tegra210-vic", .data = &vic_t210_config },
0461     { .compatible = "nvidia,tegra186-vic", .data = &vic_t186_config },
0462     { .compatible = "nvidia,tegra194-vic", .data = &vic_t194_config },
0463     { .compatible = "nvidia,tegra234-vic", .data = &vic_t234_config },
0464     { },
0465 };
0466 MODULE_DEVICE_TABLE(of, tegra_vic_of_match);
0467 
0468 static int vic_probe(struct platform_device *pdev)
0469 {
0470     struct device *dev = &pdev->dev;
0471     struct host1x_syncpt **syncpts;
0472     struct vic *vic;
0473     int err;
0474 
0475     /* inherit DMA mask from host1x parent */
0476     err = dma_coerce_mask_and_coherent(dev, *dev->parent->dma_mask);
0477     if (err < 0) {
0478         dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err);
0479         return err;
0480     }
0481 
0482     vic = devm_kzalloc(dev, sizeof(*vic), GFP_KERNEL);
0483     if (!vic)
0484         return -ENOMEM;
0485 
0486     vic->config = of_device_get_match_data(dev);
0487 
0488     syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL);
0489     if (!syncpts)
0490         return -ENOMEM;
0491 
0492     vic->regs = devm_platform_ioremap_resource(pdev, 0);
0493     if (IS_ERR(vic->regs))
0494         return PTR_ERR(vic->regs);
0495 
0496     vic->clk = devm_clk_get(dev, NULL);
0497     if (IS_ERR(vic->clk)) {
0498         dev_err(&pdev->dev, "failed to get clock\n");
0499         return PTR_ERR(vic->clk);
0500     }
0501 
0502     err = clk_set_rate(vic->clk, ULONG_MAX);
0503     if (err < 0) {
0504         dev_err(&pdev->dev, "failed to set clock rate\n");
0505         return err;
0506     }
0507 
0508     if (!dev->pm_domain) {
0509         vic->rst = devm_reset_control_get(dev, "vic");
0510         if (IS_ERR(vic->rst)) {
0511             dev_err(&pdev->dev, "failed to get reset\n");
0512             return PTR_ERR(vic->rst);
0513         }
0514     }
0515 
0516     vic->falcon.dev = dev;
0517     vic->falcon.regs = vic->regs;
0518 
0519     err = falcon_init(&vic->falcon);
0520     if (err < 0)
0521         return err;
0522 
0523     platform_set_drvdata(pdev, vic);
0524 
0525     INIT_LIST_HEAD(&vic->client.base.list);
0526     vic->client.base.ops = &vic_client_ops;
0527     vic->client.base.dev = dev;
0528     vic->client.base.class = HOST1X_CLASS_VIC;
0529     vic->client.base.syncpts = syncpts;
0530     vic->client.base.num_syncpts = 1;
0531     vic->dev = dev;
0532 
0533     INIT_LIST_HEAD(&vic->client.list);
0534     vic->client.version = vic->config->version;
0535     vic->client.ops = &vic_ops;
0536 
0537     err = host1x_client_register(&vic->client.base);
0538     if (err < 0) {
0539         dev_err(dev, "failed to register host1x client: %d\n", err);
0540         goto exit_falcon;
0541     }
0542 
0543     return 0;
0544 
0545 exit_falcon:
0546     falcon_exit(&vic->falcon);
0547 
0548     return err;
0549 }
0550 
0551 static int vic_remove(struct platform_device *pdev)
0552 {
0553     struct vic *vic = platform_get_drvdata(pdev);
0554     int err;
0555 
0556     err = host1x_client_unregister(&vic->client.base);
0557     if (err < 0) {
0558         dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
0559             err);
0560         return err;
0561     }
0562 
0563     falcon_exit(&vic->falcon);
0564 
0565     return 0;
0566 }
0567 
0568 static const struct dev_pm_ops vic_pm_ops = {
0569     RUNTIME_PM_OPS(vic_runtime_suspend, vic_runtime_resume, NULL)
0570     SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
0571 };
0572 
0573 struct platform_driver tegra_vic_driver = {
0574     .driver = {
0575         .name = "tegra-vic",
0576         .of_match_table = tegra_vic_of_match,
0577         .pm = &vic_pm_ops
0578     },
0579     .probe = vic_probe,
0580     .remove = vic_remove,
0581 };
0582 
0583 #if IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC)
0584 MODULE_FIRMWARE(NVIDIA_TEGRA_124_VIC_FIRMWARE);
0585 #endif
0586 #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
0587 MODULE_FIRMWARE(NVIDIA_TEGRA_210_VIC_FIRMWARE);
0588 #endif
0589 #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC)
0590 MODULE_FIRMWARE(NVIDIA_TEGRA_186_VIC_FIRMWARE);
0591 #endif
0592 #if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
0593 MODULE_FIRMWARE(NVIDIA_TEGRA_194_VIC_FIRMWARE);
0594 #endif
0595 #if IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
0596 MODULE_FIRMWARE(NVIDIA_TEGRA_234_VIC_FIRMWARE);
0597 #endif