0001
0002
0003
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
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
0129
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
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
0229
0230
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
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