Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2015-2021, 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 #define NVDEC_TFBIF_TRANSCFG            0x2c44
0026 
0027 struct nvdec_config {
0028     const char *firmware;
0029     unsigned int version;
0030     bool supports_sid;
0031 };
0032 
0033 struct nvdec {
0034     struct falcon falcon;
0035 
0036     void __iomem *regs;
0037     struct tegra_drm_client client;
0038     struct host1x_channel *channel;
0039     struct device *dev;
0040     struct clk *clk;
0041 
0042     /* Platform configuration */
0043     const struct nvdec_config *config;
0044 };
0045 
0046 static inline struct nvdec *to_nvdec(struct tegra_drm_client *client)
0047 {
0048     return container_of(client, struct nvdec, client);
0049 }
0050 
0051 static inline void nvdec_writel(struct nvdec *nvdec, u32 value,
0052                 unsigned int offset)
0053 {
0054     writel(value, nvdec->regs + offset);
0055 }
0056 
0057 static int nvdec_boot(struct nvdec *nvdec)
0058 {
0059 #ifdef CONFIG_IOMMU_API
0060     struct iommu_fwspec *spec = dev_iommu_fwspec_get(nvdec->dev);
0061 #endif
0062     int err;
0063 
0064 #ifdef CONFIG_IOMMU_API
0065     if (nvdec->config->supports_sid && spec) {
0066         u32 value;
0067 
0068         value = TRANSCFG_ATT(1, TRANSCFG_SID_FALCON) | TRANSCFG_ATT(0, TRANSCFG_SID_HW);
0069         nvdec_writel(nvdec, value, NVDEC_TFBIF_TRANSCFG);
0070 
0071         if (spec->num_ids > 0) {
0072             value = spec->ids[0] & 0xffff;
0073 
0074             nvdec_writel(nvdec, value, VIC_THI_STREAMID0);
0075             nvdec_writel(nvdec, value, VIC_THI_STREAMID1);
0076         }
0077     }
0078 #endif
0079 
0080     err = falcon_boot(&nvdec->falcon);
0081     if (err < 0)
0082         return err;
0083 
0084     err = falcon_wait_idle(&nvdec->falcon);
0085     if (err < 0) {
0086         dev_err(nvdec->dev, "falcon boot timed out\n");
0087         return err;
0088     }
0089 
0090     return 0;
0091 }
0092 
0093 static int nvdec_init(struct host1x_client *client)
0094 {
0095     struct tegra_drm_client *drm = host1x_to_drm_client(client);
0096     struct drm_device *dev = dev_get_drvdata(client->host);
0097     struct tegra_drm *tegra = dev->dev_private;
0098     struct nvdec *nvdec = to_nvdec(drm);
0099     int err;
0100 
0101     err = host1x_client_iommu_attach(client);
0102     if (err < 0 && err != -ENODEV) {
0103         dev_err(nvdec->dev, "failed to attach to domain: %d\n", err);
0104         return err;
0105     }
0106 
0107     nvdec->channel = host1x_channel_request(client);
0108     if (!nvdec->channel) {
0109         err = -ENOMEM;
0110         goto detach;
0111     }
0112 
0113     client->syncpts[0] = host1x_syncpt_request(client, 0);
0114     if (!client->syncpts[0]) {
0115         err = -ENOMEM;
0116         goto free_channel;
0117     }
0118 
0119     pm_runtime_enable(client->dev);
0120     pm_runtime_use_autosuspend(client->dev);
0121     pm_runtime_set_autosuspend_delay(client->dev, 500);
0122 
0123     err = tegra_drm_register_client(tegra, drm);
0124     if (err < 0)
0125         goto disable_rpm;
0126 
0127     /*
0128      * Inherit the DMA parameters (such as maximum segment size) from the
0129      * parent host1x device.
0130      */
0131     client->dev->dma_parms = client->host->dma_parms;
0132 
0133     return 0;
0134 
0135 disable_rpm:
0136     pm_runtime_dont_use_autosuspend(client->dev);
0137     pm_runtime_force_suspend(client->dev);
0138 
0139     host1x_syncpt_put(client->syncpts[0]);
0140 free_channel:
0141     host1x_channel_put(nvdec->channel);
0142 detach:
0143     host1x_client_iommu_detach(client);
0144 
0145     return err;
0146 }
0147 
0148 static int nvdec_exit(struct host1x_client *client)
0149 {
0150     struct tegra_drm_client *drm = host1x_to_drm_client(client);
0151     struct drm_device *dev = dev_get_drvdata(client->host);
0152     struct tegra_drm *tegra = dev->dev_private;
0153     struct nvdec *nvdec = to_nvdec(drm);
0154     int err;
0155 
0156     /* avoid a dangling pointer just in case this disappears */
0157     client->dev->dma_parms = NULL;
0158 
0159     err = tegra_drm_unregister_client(tegra, drm);
0160     if (err < 0)
0161         return err;
0162 
0163     pm_runtime_dont_use_autosuspend(client->dev);
0164     pm_runtime_force_suspend(client->dev);
0165 
0166     host1x_syncpt_put(client->syncpts[0]);
0167     host1x_channel_put(nvdec->channel);
0168     host1x_client_iommu_detach(client);
0169 
0170     nvdec->channel = NULL;
0171 
0172     if (client->group) {
0173         dma_unmap_single(nvdec->dev, nvdec->falcon.firmware.phys,
0174                  nvdec->falcon.firmware.size, DMA_TO_DEVICE);
0175         tegra_drm_free(tegra, nvdec->falcon.firmware.size,
0176                    nvdec->falcon.firmware.virt,
0177                    nvdec->falcon.firmware.iova);
0178     } else {
0179         dma_free_coherent(nvdec->dev, nvdec->falcon.firmware.size,
0180                   nvdec->falcon.firmware.virt,
0181                   nvdec->falcon.firmware.iova);
0182     }
0183 
0184     return 0;
0185 }
0186 
0187 static const struct host1x_client_ops nvdec_client_ops = {
0188     .init = nvdec_init,
0189     .exit = nvdec_exit,
0190 };
0191 
0192 static int nvdec_load_firmware(struct nvdec *nvdec)
0193 {
0194     struct host1x_client *client = &nvdec->client.base;
0195     struct tegra_drm *tegra = nvdec->client.drm;
0196     dma_addr_t iova;
0197     size_t size;
0198     void *virt;
0199     int err;
0200 
0201     if (nvdec->falcon.firmware.virt)
0202         return 0;
0203 
0204     err = falcon_read_firmware(&nvdec->falcon, nvdec->config->firmware);
0205     if (err < 0)
0206         return err;
0207 
0208     size = nvdec->falcon.firmware.size;
0209 
0210     if (!client->group) {
0211         virt = dma_alloc_coherent(nvdec->dev, size, &iova, GFP_KERNEL);
0212 
0213         err = dma_mapping_error(nvdec->dev, iova);
0214         if (err < 0)
0215             return err;
0216     } else {
0217         virt = tegra_drm_alloc(tegra, size, &iova);
0218     }
0219 
0220     nvdec->falcon.firmware.virt = virt;
0221     nvdec->falcon.firmware.iova = iova;
0222 
0223     err = falcon_load_firmware(&nvdec->falcon);
0224     if (err < 0)
0225         goto cleanup;
0226 
0227     /*
0228      * In this case we have received an IOVA from the shared domain, so we
0229      * need to make sure to get the physical address so that the DMA API
0230      * knows what memory pages to flush the cache for.
0231      */
0232     if (client->group) {
0233         dma_addr_t phys;
0234 
0235         phys = dma_map_single(nvdec->dev, virt, size, DMA_TO_DEVICE);
0236 
0237         err = dma_mapping_error(nvdec->dev, phys);
0238         if (err < 0)
0239             goto cleanup;
0240 
0241         nvdec->falcon.firmware.phys = phys;
0242     }
0243 
0244     return 0;
0245 
0246 cleanup:
0247     if (!client->group)
0248         dma_free_coherent(nvdec->dev, size, virt, iova);
0249     else
0250         tegra_drm_free(tegra, size, virt, iova);
0251 
0252     return err;
0253 }
0254 
0255 
0256 static __maybe_unused int nvdec_runtime_resume(struct device *dev)
0257 {
0258     struct nvdec *nvdec = dev_get_drvdata(dev);
0259     int err;
0260 
0261     err = clk_prepare_enable(nvdec->clk);
0262     if (err < 0)
0263         return err;
0264 
0265     usleep_range(10, 20);
0266 
0267     err = nvdec_load_firmware(nvdec);
0268     if (err < 0)
0269         goto disable;
0270 
0271     err = nvdec_boot(nvdec);
0272     if (err < 0)
0273         goto disable;
0274 
0275     return 0;
0276 
0277 disable:
0278     clk_disable_unprepare(nvdec->clk);
0279     return err;
0280 }
0281 
0282 static __maybe_unused int nvdec_runtime_suspend(struct device *dev)
0283 {
0284     struct nvdec *nvdec = dev_get_drvdata(dev);
0285 
0286     host1x_channel_stop(nvdec->channel);
0287 
0288     clk_disable_unprepare(nvdec->clk);
0289 
0290     return 0;
0291 }
0292 
0293 static int nvdec_open_channel(struct tegra_drm_client *client,
0294                 struct tegra_drm_context *context)
0295 {
0296     struct nvdec *nvdec = to_nvdec(client);
0297 
0298     context->channel = host1x_channel_get(nvdec->channel);
0299     if (!context->channel)
0300         return -ENOMEM;
0301 
0302     return 0;
0303 }
0304 
0305 static void nvdec_close_channel(struct tegra_drm_context *context)
0306 {
0307     host1x_channel_put(context->channel);
0308 }
0309 
0310 static int nvdec_can_use_memory_ctx(struct tegra_drm_client *client, bool *supported)
0311 {
0312     *supported = true;
0313 
0314     return 0;
0315 }
0316 
0317 static const struct tegra_drm_client_ops nvdec_ops = {
0318     .open_channel = nvdec_open_channel,
0319     .close_channel = nvdec_close_channel,
0320     .submit = tegra_drm_submit,
0321     .get_streamid_offset = tegra_drm_get_streamid_offset_thi,
0322     .can_use_memory_ctx = nvdec_can_use_memory_ctx,
0323 };
0324 
0325 #define NVIDIA_TEGRA_210_NVDEC_FIRMWARE "nvidia/tegra210/nvdec.bin"
0326 
0327 static const struct nvdec_config nvdec_t210_config = {
0328     .firmware = NVIDIA_TEGRA_210_NVDEC_FIRMWARE,
0329     .version = 0x21,
0330     .supports_sid = false,
0331 };
0332 
0333 #define NVIDIA_TEGRA_186_NVDEC_FIRMWARE "nvidia/tegra186/nvdec.bin"
0334 
0335 static const struct nvdec_config nvdec_t186_config = {
0336     .firmware = NVIDIA_TEGRA_186_NVDEC_FIRMWARE,
0337     .version = 0x18,
0338     .supports_sid = true,
0339 };
0340 
0341 #define NVIDIA_TEGRA_194_NVDEC_FIRMWARE "nvidia/tegra194/nvdec.bin"
0342 
0343 static const struct nvdec_config nvdec_t194_config = {
0344     .firmware = NVIDIA_TEGRA_194_NVDEC_FIRMWARE,
0345     .version = 0x19,
0346     .supports_sid = true,
0347 };
0348 
0349 static const struct of_device_id tegra_nvdec_of_match[] = {
0350     { .compatible = "nvidia,tegra210-nvdec", .data = &nvdec_t210_config },
0351     { .compatible = "nvidia,tegra186-nvdec", .data = &nvdec_t186_config },
0352     { .compatible = "nvidia,tegra194-nvdec", .data = &nvdec_t194_config },
0353     { },
0354 };
0355 MODULE_DEVICE_TABLE(of, tegra_nvdec_of_match);
0356 
0357 static int nvdec_probe(struct platform_device *pdev)
0358 {
0359     struct device *dev = &pdev->dev;
0360     struct host1x_syncpt **syncpts;
0361     struct nvdec *nvdec;
0362     u32 host_class;
0363     int err;
0364 
0365     /* inherit DMA mask from host1x parent */
0366     err = dma_coerce_mask_and_coherent(dev, *dev->parent->dma_mask);
0367     if (err < 0) {
0368         dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err);
0369         return err;
0370     }
0371 
0372     nvdec = devm_kzalloc(dev, sizeof(*nvdec), GFP_KERNEL);
0373     if (!nvdec)
0374         return -ENOMEM;
0375 
0376     nvdec->config = of_device_get_match_data(dev);
0377 
0378     syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL);
0379     if (!syncpts)
0380         return -ENOMEM;
0381 
0382     nvdec->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
0383     if (IS_ERR(nvdec->regs))
0384         return PTR_ERR(nvdec->regs);
0385 
0386     nvdec->clk = devm_clk_get(dev, NULL);
0387     if (IS_ERR(nvdec->clk)) {
0388         dev_err(&pdev->dev, "failed to get clock\n");
0389         return PTR_ERR(nvdec->clk);
0390     }
0391 
0392     err = clk_set_rate(nvdec->clk, ULONG_MAX);
0393     if (err < 0) {
0394         dev_err(&pdev->dev, "failed to set clock rate\n");
0395         return err;
0396     }
0397 
0398     err = of_property_read_u32(dev->of_node, "nvidia,host1x-class", &host_class);
0399     if (err < 0)
0400         host_class = HOST1X_CLASS_NVDEC;
0401 
0402     nvdec->falcon.dev = dev;
0403     nvdec->falcon.regs = nvdec->regs;
0404 
0405     err = falcon_init(&nvdec->falcon);
0406     if (err < 0)
0407         return err;
0408 
0409     platform_set_drvdata(pdev, nvdec);
0410 
0411     INIT_LIST_HEAD(&nvdec->client.base.list);
0412     nvdec->client.base.ops = &nvdec_client_ops;
0413     nvdec->client.base.dev = dev;
0414     nvdec->client.base.class = host_class;
0415     nvdec->client.base.syncpts = syncpts;
0416     nvdec->client.base.num_syncpts = 1;
0417     nvdec->dev = dev;
0418 
0419     INIT_LIST_HEAD(&nvdec->client.list);
0420     nvdec->client.version = nvdec->config->version;
0421     nvdec->client.ops = &nvdec_ops;
0422 
0423     err = host1x_client_register(&nvdec->client.base);
0424     if (err < 0) {
0425         dev_err(dev, "failed to register host1x client: %d\n", err);
0426         goto exit_falcon;
0427     }
0428 
0429     return 0;
0430 
0431 exit_falcon:
0432     falcon_exit(&nvdec->falcon);
0433 
0434     return err;
0435 }
0436 
0437 static int nvdec_remove(struct platform_device *pdev)
0438 {
0439     struct nvdec *nvdec = platform_get_drvdata(pdev);
0440     int err;
0441 
0442     err = host1x_client_unregister(&nvdec->client.base);
0443     if (err < 0) {
0444         dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
0445             err);
0446         return err;
0447     }
0448 
0449     falcon_exit(&nvdec->falcon);
0450 
0451     return 0;
0452 }
0453 
0454 static const struct dev_pm_ops nvdec_pm_ops = {
0455     SET_RUNTIME_PM_OPS(nvdec_runtime_suspend, nvdec_runtime_resume, NULL)
0456     SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
0457                 pm_runtime_force_resume)
0458 };
0459 
0460 struct platform_driver tegra_nvdec_driver = {
0461     .driver = {
0462         .name = "tegra-nvdec",
0463         .of_match_table = tegra_nvdec_of_match,
0464         .pm = &nvdec_pm_ops
0465     },
0466     .probe = nvdec_probe,
0467     .remove = nvdec_remove,
0468 };
0469 
0470 #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
0471 MODULE_FIRMWARE(NVIDIA_TEGRA_210_NVDEC_FIRMWARE);
0472 #endif
0473 #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC)
0474 MODULE_FIRMWARE(NVIDIA_TEGRA_186_NVDEC_FIRMWARE);
0475 #endif
0476 #if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
0477 MODULE_FIRMWARE(NVIDIA_TEGRA_194_NVDEC_FIRMWARE);
0478 #endif