146f226c9SMikko Perttunen // SPDX-License-Identifier: GPL-2.0-only 246f226c9SMikko Perttunen /* 346f226c9SMikko Perttunen * Copyright (c) 2015-2021, NVIDIA Corporation. 446f226c9SMikko Perttunen */ 546f226c9SMikko Perttunen 646f226c9SMikko Perttunen #include <linux/clk.h> 746f226c9SMikko Perttunen #include <linux/delay.h> 846f226c9SMikko Perttunen #include <linux/host1x.h> 946f226c9SMikko Perttunen #include <linux/iommu.h> 1046f226c9SMikko Perttunen #include <linux/module.h> 1146f226c9SMikko Perttunen #include <linux/of.h> 1246f226c9SMikko Perttunen #include <linux/of_device.h> 1346f226c9SMikko Perttunen #include <linux/of_platform.h> 1446f226c9SMikko Perttunen #include <linux/platform_device.h> 1546f226c9SMikko Perttunen #include <linux/pm_runtime.h> 1646f226c9SMikko Perttunen #include <linux/reset.h> 1746f226c9SMikko Perttunen 1846f226c9SMikko Perttunen #include <soc/tegra/pmc.h> 1946f226c9SMikko Perttunen 2046f226c9SMikko Perttunen #include "drm.h" 2146f226c9SMikko Perttunen #include "falcon.h" 2246f226c9SMikko Perttunen #include "vic.h" 2346f226c9SMikko Perttunen 2446f226c9SMikko Perttunen struct nvdec_config { 2546f226c9SMikko Perttunen const char *firmware; 2646f226c9SMikko Perttunen unsigned int version; 2746f226c9SMikko Perttunen bool supports_sid; 2846f226c9SMikko Perttunen }; 2946f226c9SMikko Perttunen 3046f226c9SMikko Perttunen struct nvdec { 3146f226c9SMikko Perttunen struct falcon falcon; 3246f226c9SMikko Perttunen 3346f226c9SMikko Perttunen void __iomem *regs; 3446f226c9SMikko Perttunen struct tegra_drm_client client; 3546f226c9SMikko Perttunen struct host1x_channel *channel; 3646f226c9SMikko Perttunen struct device *dev; 3746f226c9SMikko Perttunen struct clk *clk; 3846f226c9SMikko Perttunen 3946f226c9SMikko Perttunen /* Platform configuration */ 4046f226c9SMikko Perttunen const struct nvdec_config *config; 4146f226c9SMikko Perttunen }; 4246f226c9SMikko Perttunen 4346f226c9SMikko Perttunen static inline struct nvdec *to_nvdec(struct tegra_drm_client *client) 4446f226c9SMikko Perttunen { 4546f226c9SMikko Perttunen return container_of(client, struct nvdec, client); 4646f226c9SMikko Perttunen } 4746f226c9SMikko Perttunen 482245c2a2SArnd Bergmann static inline void nvdec_writel(struct nvdec *nvdec, u32 value, 492245c2a2SArnd Bergmann unsigned int offset) 5046f226c9SMikko Perttunen { 5146f226c9SMikko Perttunen writel(value, nvdec->regs + offset); 5246f226c9SMikko Perttunen } 5346f226c9SMikko Perttunen 5446f226c9SMikko Perttunen static int nvdec_boot(struct nvdec *nvdec) 5546f226c9SMikko Perttunen { 5646f226c9SMikko Perttunen #ifdef CONFIG_IOMMU_API 5746f226c9SMikko Perttunen struct iommu_fwspec *spec = dev_iommu_fwspec_get(nvdec->dev); 5846f226c9SMikko Perttunen #endif 5946f226c9SMikko Perttunen int err; 6046f226c9SMikko Perttunen 6146f226c9SMikko Perttunen #ifdef CONFIG_IOMMU_API 6246f226c9SMikko Perttunen if (nvdec->config->supports_sid && spec) { 6346f226c9SMikko Perttunen u32 value; 6446f226c9SMikko Perttunen 6546f226c9SMikko Perttunen value = TRANSCFG_ATT(1, TRANSCFG_SID_FALCON) | TRANSCFG_ATT(0, TRANSCFG_SID_HW); 6646f226c9SMikko Perttunen nvdec_writel(nvdec, value, VIC_TFBIF_TRANSCFG); 6746f226c9SMikko Perttunen 6846f226c9SMikko Perttunen if (spec->num_ids > 0) { 6946f226c9SMikko Perttunen value = spec->ids[0] & 0xffff; 7046f226c9SMikko Perttunen 7146f226c9SMikko Perttunen nvdec_writel(nvdec, value, VIC_THI_STREAMID0); 7246f226c9SMikko Perttunen nvdec_writel(nvdec, value, VIC_THI_STREAMID1); 7346f226c9SMikko Perttunen } 7446f226c9SMikko Perttunen } 7546f226c9SMikko Perttunen #endif 7646f226c9SMikko Perttunen 7746f226c9SMikko Perttunen err = falcon_boot(&nvdec->falcon); 7846f226c9SMikko Perttunen if (err < 0) 7946f226c9SMikko Perttunen return err; 8046f226c9SMikko Perttunen 8146f226c9SMikko Perttunen err = falcon_wait_idle(&nvdec->falcon); 8246f226c9SMikko Perttunen if (err < 0) { 8346f226c9SMikko Perttunen dev_err(nvdec->dev, "falcon boot timed out\n"); 8446f226c9SMikko Perttunen return err; 8546f226c9SMikko Perttunen } 8646f226c9SMikko Perttunen 8746f226c9SMikko Perttunen return 0; 8846f226c9SMikko Perttunen } 8946f226c9SMikko Perttunen 9046f226c9SMikko Perttunen static int nvdec_init(struct host1x_client *client) 9146f226c9SMikko Perttunen { 9246f226c9SMikko Perttunen struct tegra_drm_client *drm = host1x_to_drm_client(client); 9346f226c9SMikko Perttunen struct drm_device *dev = dev_get_drvdata(client->host); 9446f226c9SMikko Perttunen struct tegra_drm *tegra = dev->dev_private; 9546f226c9SMikko Perttunen struct nvdec *nvdec = to_nvdec(drm); 9646f226c9SMikko Perttunen int err; 9746f226c9SMikko Perttunen 9846f226c9SMikko Perttunen err = host1x_client_iommu_attach(client); 9946f226c9SMikko Perttunen if (err < 0 && err != -ENODEV) { 10046f226c9SMikko Perttunen dev_err(nvdec->dev, "failed to attach to domain: %d\n", err); 10146f226c9SMikko Perttunen return err; 10246f226c9SMikko Perttunen } 10346f226c9SMikko Perttunen 10446f226c9SMikko Perttunen nvdec->channel = host1x_channel_request(client); 10546f226c9SMikko Perttunen if (!nvdec->channel) { 10646f226c9SMikko Perttunen err = -ENOMEM; 10746f226c9SMikko Perttunen goto detach; 10846f226c9SMikko Perttunen } 10946f226c9SMikko Perttunen 11046f226c9SMikko Perttunen client->syncpts[0] = host1x_syncpt_request(client, 0); 11146f226c9SMikko Perttunen if (!client->syncpts[0]) { 11246f226c9SMikko Perttunen err = -ENOMEM; 11346f226c9SMikko Perttunen goto free_channel; 11446f226c9SMikko Perttunen } 11546f226c9SMikko Perttunen 116*28b16229SDmitry Osipenko pm_runtime_enable(client->dev); 117*28b16229SDmitry Osipenko pm_runtime_use_autosuspend(client->dev); 118*28b16229SDmitry Osipenko pm_runtime_set_autosuspend_delay(client->dev, 500); 119*28b16229SDmitry Osipenko 12046f226c9SMikko Perttunen err = tegra_drm_register_client(tegra, drm); 12146f226c9SMikko Perttunen if (err < 0) 122*28b16229SDmitry Osipenko goto disable_rpm; 12346f226c9SMikko Perttunen 12446f226c9SMikko Perttunen /* 12546f226c9SMikko Perttunen * Inherit the DMA parameters (such as maximum segment size) from the 12646f226c9SMikko Perttunen * parent host1x device. 12746f226c9SMikko Perttunen */ 12846f226c9SMikko Perttunen client->dev->dma_parms = client->host->dma_parms; 12946f226c9SMikko Perttunen 13046f226c9SMikko Perttunen return 0; 13146f226c9SMikko Perttunen 132*28b16229SDmitry Osipenko disable_rpm: 133*28b16229SDmitry Osipenko pm_runtime_dont_use_autosuspend(client->dev); 134*28b16229SDmitry Osipenko pm_runtime_force_suspend(client->dev); 135*28b16229SDmitry Osipenko 13646f226c9SMikko Perttunen host1x_syncpt_put(client->syncpts[0]); 13746f226c9SMikko Perttunen free_channel: 13846f226c9SMikko Perttunen host1x_channel_put(nvdec->channel); 13946f226c9SMikko Perttunen detach: 14046f226c9SMikko Perttunen host1x_client_iommu_detach(client); 14146f226c9SMikko Perttunen 14246f226c9SMikko Perttunen return err; 14346f226c9SMikko Perttunen } 14446f226c9SMikko Perttunen 14546f226c9SMikko Perttunen static int nvdec_exit(struct host1x_client *client) 14646f226c9SMikko Perttunen { 14746f226c9SMikko Perttunen struct tegra_drm_client *drm = host1x_to_drm_client(client); 14846f226c9SMikko Perttunen struct drm_device *dev = dev_get_drvdata(client->host); 14946f226c9SMikko Perttunen struct tegra_drm *tegra = dev->dev_private; 15046f226c9SMikko Perttunen struct nvdec *nvdec = to_nvdec(drm); 15146f226c9SMikko Perttunen int err; 15246f226c9SMikko Perttunen 15346f226c9SMikko Perttunen /* avoid a dangling pointer just in case this disappears */ 15446f226c9SMikko Perttunen client->dev->dma_parms = NULL; 15546f226c9SMikko Perttunen 15646f226c9SMikko Perttunen err = tegra_drm_unregister_client(tegra, drm); 15746f226c9SMikko Perttunen if (err < 0) 15846f226c9SMikko Perttunen return err; 15946f226c9SMikko Perttunen 160*28b16229SDmitry Osipenko pm_runtime_dont_use_autosuspend(client->dev); 161*28b16229SDmitry Osipenko pm_runtime_force_suspend(client->dev); 162*28b16229SDmitry Osipenko 16346f226c9SMikko Perttunen host1x_syncpt_put(client->syncpts[0]); 16446f226c9SMikko Perttunen host1x_channel_put(nvdec->channel); 16546f226c9SMikko Perttunen host1x_client_iommu_detach(client); 16646f226c9SMikko Perttunen 167*28b16229SDmitry Osipenko nvdec->channel = NULL; 168*28b16229SDmitry Osipenko 16946f226c9SMikko Perttunen if (client->group) { 17046f226c9SMikko Perttunen dma_unmap_single(nvdec->dev, nvdec->falcon.firmware.phys, 17146f226c9SMikko Perttunen nvdec->falcon.firmware.size, DMA_TO_DEVICE); 17246f226c9SMikko Perttunen tegra_drm_free(tegra, nvdec->falcon.firmware.size, 17346f226c9SMikko Perttunen nvdec->falcon.firmware.virt, 17446f226c9SMikko Perttunen nvdec->falcon.firmware.iova); 17546f226c9SMikko Perttunen } else { 17646f226c9SMikko Perttunen dma_free_coherent(nvdec->dev, nvdec->falcon.firmware.size, 17746f226c9SMikko Perttunen nvdec->falcon.firmware.virt, 17846f226c9SMikko Perttunen nvdec->falcon.firmware.iova); 17946f226c9SMikko Perttunen } 18046f226c9SMikko Perttunen 18146f226c9SMikko Perttunen return 0; 18246f226c9SMikko Perttunen } 18346f226c9SMikko Perttunen 18446f226c9SMikko Perttunen static const struct host1x_client_ops nvdec_client_ops = { 18546f226c9SMikko Perttunen .init = nvdec_init, 18646f226c9SMikko Perttunen .exit = nvdec_exit, 18746f226c9SMikko Perttunen }; 18846f226c9SMikko Perttunen 18946f226c9SMikko Perttunen static int nvdec_load_firmware(struct nvdec *nvdec) 19046f226c9SMikko Perttunen { 19146f226c9SMikko Perttunen struct host1x_client *client = &nvdec->client.base; 19246f226c9SMikko Perttunen struct tegra_drm *tegra = nvdec->client.drm; 19346f226c9SMikko Perttunen dma_addr_t iova; 19446f226c9SMikko Perttunen size_t size; 19546f226c9SMikko Perttunen void *virt; 19646f226c9SMikko Perttunen int err; 19746f226c9SMikko Perttunen 19846f226c9SMikko Perttunen if (nvdec->falcon.firmware.virt) 19946f226c9SMikko Perttunen return 0; 20046f226c9SMikko Perttunen 20146f226c9SMikko Perttunen err = falcon_read_firmware(&nvdec->falcon, nvdec->config->firmware); 20246f226c9SMikko Perttunen if (err < 0) 20346f226c9SMikko Perttunen return err; 20446f226c9SMikko Perttunen 20546f226c9SMikko Perttunen size = nvdec->falcon.firmware.size; 20646f226c9SMikko Perttunen 20746f226c9SMikko Perttunen if (!client->group) { 20846f226c9SMikko Perttunen virt = dma_alloc_coherent(nvdec->dev, size, &iova, GFP_KERNEL); 20946f226c9SMikko Perttunen 21046f226c9SMikko Perttunen err = dma_mapping_error(nvdec->dev, iova); 21146f226c9SMikko Perttunen if (err < 0) 21246f226c9SMikko Perttunen return err; 21346f226c9SMikko Perttunen } else { 21446f226c9SMikko Perttunen virt = tegra_drm_alloc(tegra, size, &iova); 21546f226c9SMikko Perttunen } 21646f226c9SMikko Perttunen 21746f226c9SMikko Perttunen nvdec->falcon.firmware.virt = virt; 21846f226c9SMikko Perttunen nvdec->falcon.firmware.iova = iova; 21946f226c9SMikko Perttunen 22046f226c9SMikko Perttunen err = falcon_load_firmware(&nvdec->falcon); 22146f226c9SMikko Perttunen if (err < 0) 22246f226c9SMikko Perttunen goto cleanup; 22346f226c9SMikko Perttunen 22446f226c9SMikko Perttunen /* 22546f226c9SMikko Perttunen * In this case we have received an IOVA from the shared domain, so we 22646f226c9SMikko Perttunen * need to make sure to get the physical address so that the DMA API 22746f226c9SMikko Perttunen * knows what memory pages to flush the cache for. 22846f226c9SMikko Perttunen */ 22946f226c9SMikko Perttunen if (client->group) { 23046f226c9SMikko Perttunen dma_addr_t phys; 23146f226c9SMikko Perttunen 23246f226c9SMikko Perttunen phys = dma_map_single(nvdec->dev, virt, size, DMA_TO_DEVICE); 23346f226c9SMikko Perttunen 23446f226c9SMikko Perttunen err = dma_mapping_error(nvdec->dev, phys); 23546f226c9SMikko Perttunen if (err < 0) 23646f226c9SMikko Perttunen goto cleanup; 23746f226c9SMikko Perttunen 23846f226c9SMikko Perttunen nvdec->falcon.firmware.phys = phys; 23946f226c9SMikko Perttunen } 24046f226c9SMikko Perttunen 24146f226c9SMikko Perttunen return 0; 24246f226c9SMikko Perttunen 24346f226c9SMikko Perttunen cleanup: 24446f226c9SMikko Perttunen if (!client->group) 24546f226c9SMikko Perttunen dma_free_coherent(nvdec->dev, size, virt, iova); 24646f226c9SMikko Perttunen else 24746f226c9SMikko Perttunen tegra_drm_free(tegra, size, virt, iova); 24846f226c9SMikko Perttunen 24946f226c9SMikko Perttunen return err; 25046f226c9SMikko Perttunen } 25146f226c9SMikko Perttunen 25246f226c9SMikko Perttunen 253e1189fafSArnd Bergmann static __maybe_unused int nvdec_runtime_resume(struct device *dev) 25446f226c9SMikko Perttunen { 25546f226c9SMikko Perttunen struct nvdec *nvdec = dev_get_drvdata(dev); 25646f226c9SMikko Perttunen int err; 25746f226c9SMikko Perttunen 25846f226c9SMikko Perttunen err = clk_prepare_enable(nvdec->clk); 25946f226c9SMikko Perttunen if (err < 0) 26046f226c9SMikko Perttunen return err; 26146f226c9SMikko Perttunen 26246f226c9SMikko Perttunen usleep_range(10, 20); 26346f226c9SMikko Perttunen 26446f226c9SMikko Perttunen err = nvdec_load_firmware(nvdec); 26546f226c9SMikko Perttunen if (err < 0) 26646f226c9SMikko Perttunen goto disable; 26746f226c9SMikko Perttunen 26846f226c9SMikko Perttunen err = nvdec_boot(nvdec); 26946f226c9SMikko Perttunen if (err < 0) 27046f226c9SMikko Perttunen goto disable; 27146f226c9SMikko Perttunen 27246f226c9SMikko Perttunen return 0; 27346f226c9SMikko Perttunen 27446f226c9SMikko Perttunen disable: 27546f226c9SMikko Perttunen clk_disable_unprepare(nvdec->clk); 27646f226c9SMikko Perttunen return err; 27746f226c9SMikko Perttunen } 27846f226c9SMikko Perttunen 279e1189fafSArnd Bergmann static __maybe_unused int nvdec_runtime_suspend(struct device *dev) 28046f226c9SMikko Perttunen { 28146f226c9SMikko Perttunen struct nvdec *nvdec = dev_get_drvdata(dev); 28246f226c9SMikko Perttunen 283*28b16229SDmitry Osipenko host1x_channel_stop(nvdec->channel); 284*28b16229SDmitry Osipenko 28546f226c9SMikko Perttunen clk_disable_unprepare(nvdec->clk); 28646f226c9SMikko Perttunen 28746f226c9SMikko Perttunen return 0; 28846f226c9SMikko Perttunen } 28946f226c9SMikko Perttunen 29046f226c9SMikko Perttunen static int nvdec_open_channel(struct tegra_drm_client *client, 29146f226c9SMikko Perttunen struct tegra_drm_context *context) 29246f226c9SMikko Perttunen { 29346f226c9SMikko Perttunen struct nvdec *nvdec = to_nvdec(client); 29446f226c9SMikko Perttunen int err; 29546f226c9SMikko Perttunen 29646f226c9SMikko Perttunen err = pm_runtime_get_sync(nvdec->dev); 29746f226c9SMikko Perttunen if (err < 0) { 29846f226c9SMikko Perttunen pm_runtime_put(nvdec->dev); 29946f226c9SMikko Perttunen return err; 30046f226c9SMikko Perttunen } 30146f226c9SMikko Perttunen 30246f226c9SMikko Perttunen context->channel = host1x_channel_get(nvdec->channel); 30346f226c9SMikko Perttunen if (!context->channel) { 30446f226c9SMikko Perttunen pm_runtime_put(nvdec->dev); 30546f226c9SMikko Perttunen return -ENOMEM; 30646f226c9SMikko Perttunen } 30746f226c9SMikko Perttunen 30846f226c9SMikko Perttunen return 0; 30946f226c9SMikko Perttunen } 31046f226c9SMikko Perttunen 31146f226c9SMikko Perttunen static void nvdec_close_channel(struct tegra_drm_context *context) 31246f226c9SMikko Perttunen { 31346f226c9SMikko Perttunen struct nvdec *nvdec = to_nvdec(context->client); 31446f226c9SMikko Perttunen 31546f226c9SMikko Perttunen host1x_channel_put(context->channel); 31646f226c9SMikko Perttunen pm_runtime_put(nvdec->dev); 31746f226c9SMikko Perttunen } 31846f226c9SMikko Perttunen 31946f226c9SMikko Perttunen static const struct tegra_drm_client_ops nvdec_ops = { 32046f226c9SMikko Perttunen .open_channel = nvdec_open_channel, 32146f226c9SMikko Perttunen .close_channel = nvdec_close_channel, 32246f226c9SMikko Perttunen .submit = tegra_drm_submit, 32346f226c9SMikko Perttunen }; 32446f226c9SMikko Perttunen 32546f226c9SMikko Perttunen #define NVIDIA_TEGRA_210_NVDEC_FIRMWARE "nvidia/tegra210/nvdec.bin" 32646f226c9SMikko Perttunen 32746f226c9SMikko Perttunen static const struct nvdec_config nvdec_t210_config = { 32846f226c9SMikko Perttunen .firmware = NVIDIA_TEGRA_210_NVDEC_FIRMWARE, 32946f226c9SMikko Perttunen .version = 0x21, 33046f226c9SMikko Perttunen .supports_sid = false, 33146f226c9SMikko Perttunen }; 33246f226c9SMikko Perttunen 33346f226c9SMikko Perttunen #define NVIDIA_TEGRA_186_NVDEC_FIRMWARE "nvidia/tegra186/nvdec.bin" 33446f226c9SMikko Perttunen 33546f226c9SMikko Perttunen static const struct nvdec_config nvdec_t186_config = { 33646f226c9SMikko Perttunen .firmware = NVIDIA_TEGRA_186_NVDEC_FIRMWARE, 33746f226c9SMikko Perttunen .version = 0x18, 33846f226c9SMikko Perttunen .supports_sid = true, 33946f226c9SMikko Perttunen }; 34046f226c9SMikko Perttunen 34146f226c9SMikko Perttunen #define NVIDIA_TEGRA_194_NVDEC_FIRMWARE "nvidia/tegra194/nvdec.bin" 34246f226c9SMikko Perttunen 34346f226c9SMikko Perttunen static const struct nvdec_config nvdec_t194_config = { 34446f226c9SMikko Perttunen .firmware = NVIDIA_TEGRA_194_NVDEC_FIRMWARE, 34546f226c9SMikko Perttunen .version = 0x19, 34646f226c9SMikko Perttunen .supports_sid = true, 34746f226c9SMikko Perttunen }; 34846f226c9SMikko Perttunen 34946f226c9SMikko Perttunen static const struct of_device_id tegra_nvdec_of_match[] = { 35046f226c9SMikko Perttunen { .compatible = "nvidia,tegra210-nvdec", .data = &nvdec_t210_config }, 35146f226c9SMikko Perttunen { .compatible = "nvidia,tegra186-nvdec", .data = &nvdec_t186_config }, 35246f226c9SMikko Perttunen { .compatible = "nvidia,tegra194-nvdec", .data = &nvdec_t194_config }, 35346f226c9SMikko Perttunen { }, 35446f226c9SMikko Perttunen }; 35546f226c9SMikko Perttunen MODULE_DEVICE_TABLE(of, tegra_nvdec_of_match); 35646f226c9SMikko Perttunen 35746f226c9SMikko Perttunen static int nvdec_probe(struct platform_device *pdev) 35846f226c9SMikko Perttunen { 35946f226c9SMikko Perttunen struct device *dev = &pdev->dev; 36046f226c9SMikko Perttunen struct host1x_syncpt **syncpts; 36146f226c9SMikko Perttunen struct nvdec *nvdec; 36246f226c9SMikko Perttunen u32 host_class; 36346f226c9SMikko Perttunen int err; 36446f226c9SMikko Perttunen 36546f226c9SMikko Perttunen /* inherit DMA mask from host1x parent */ 36646f226c9SMikko Perttunen err = dma_coerce_mask_and_coherent(dev, *dev->parent->dma_mask); 36746f226c9SMikko Perttunen if (err < 0) { 36846f226c9SMikko Perttunen dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err); 36946f226c9SMikko Perttunen return err; 37046f226c9SMikko Perttunen } 37146f226c9SMikko Perttunen 37246f226c9SMikko Perttunen nvdec = devm_kzalloc(dev, sizeof(*nvdec), GFP_KERNEL); 37346f226c9SMikko Perttunen if (!nvdec) 37446f226c9SMikko Perttunen return -ENOMEM; 37546f226c9SMikko Perttunen 37646f226c9SMikko Perttunen nvdec->config = of_device_get_match_data(dev); 37746f226c9SMikko Perttunen 37846f226c9SMikko Perttunen syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL); 37946f226c9SMikko Perttunen if (!syncpts) 38046f226c9SMikko Perttunen return -ENOMEM; 38146f226c9SMikko Perttunen 38246f226c9SMikko Perttunen nvdec->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); 38346f226c9SMikko Perttunen if (IS_ERR(nvdec->regs)) 38446f226c9SMikko Perttunen return PTR_ERR(nvdec->regs); 38546f226c9SMikko Perttunen 38646f226c9SMikko Perttunen nvdec->clk = devm_clk_get(dev, NULL); 38746f226c9SMikko Perttunen if (IS_ERR(nvdec->clk)) { 38846f226c9SMikko Perttunen dev_err(&pdev->dev, "failed to get clock\n"); 38946f226c9SMikko Perttunen return PTR_ERR(nvdec->clk); 39046f226c9SMikko Perttunen } 39146f226c9SMikko Perttunen 392e97a951fSMikko Perttunen err = clk_set_rate(nvdec->clk, ULONG_MAX); 393e97a951fSMikko Perttunen if (err < 0) { 394e97a951fSMikko Perttunen dev_err(&pdev->dev, "failed to set clock rate\n"); 395e97a951fSMikko Perttunen return err; 396e97a951fSMikko Perttunen } 397e97a951fSMikko Perttunen 39846f226c9SMikko Perttunen err = of_property_read_u32(dev->of_node, "nvidia,host1x-class", &host_class); 39946f226c9SMikko Perttunen if (err < 0) 40046f226c9SMikko Perttunen host_class = HOST1X_CLASS_NVDEC; 40146f226c9SMikko Perttunen 40246f226c9SMikko Perttunen nvdec->falcon.dev = dev; 40346f226c9SMikko Perttunen nvdec->falcon.regs = nvdec->regs; 40446f226c9SMikko Perttunen 40546f226c9SMikko Perttunen err = falcon_init(&nvdec->falcon); 40646f226c9SMikko Perttunen if (err < 0) 40746f226c9SMikko Perttunen return err; 40846f226c9SMikko Perttunen 40946f226c9SMikko Perttunen platform_set_drvdata(pdev, nvdec); 41046f226c9SMikko Perttunen 41146f226c9SMikko Perttunen INIT_LIST_HEAD(&nvdec->client.base.list); 41246f226c9SMikko Perttunen nvdec->client.base.ops = &nvdec_client_ops; 41346f226c9SMikko Perttunen nvdec->client.base.dev = dev; 41446f226c9SMikko Perttunen nvdec->client.base.class = host_class; 41546f226c9SMikko Perttunen nvdec->client.base.syncpts = syncpts; 41646f226c9SMikko Perttunen nvdec->client.base.num_syncpts = 1; 41746f226c9SMikko Perttunen nvdec->dev = dev; 41846f226c9SMikko Perttunen 41946f226c9SMikko Perttunen INIT_LIST_HEAD(&nvdec->client.list); 42046f226c9SMikko Perttunen nvdec->client.version = nvdec->config->version; 42146f226c9SMikko Perttunen nvdec->client.ops = &nvdec_ops; 42246f226c9SMikko Perttunen 42346f226c9SMikko Perttunen err = host1x_client_register(&nvdec->client.base); 42446f226c9SMikko Perttunen if (err < 0) { 42546f226c9SMikko Perttunen dev_err(dev, "failed to register host1x client: %d\n", err); 42646f226c9SMikko Perttunen goto exit_falcon; 42746f226c9SMikko Perttunen } 42846f226c9SMikko Perttunen 42946f226c9SMikko Perttunen return 0; 43046f226c9SMikko Perttunen 43146f226c9SMikko Perttunen exit_falcon: 43246f226c9SMikko Perttunen falcon_exit(&nvdec->falcon); 43346f226c9SMikko Perttunen 43446f226c9SMikko Perttunen return err; 43546f226c9SMikko Perttunen } 43646f226c9SMikko Perttunen 43746f226c9SMikko Perttunen static int nvdec_remove(struct platform_device *pdev) 43846f226c9SMikko Perttunen { 43946f226c9SMikko Perttunen struct nvdec *nvdec = platform_get_drvdata(pdev); 44046f226c9SMikko Perttunen int err; 44146f226c9SMikko Perttunen 44246f226c9SMikko Perttunen err = host1x_client_unregister(&nvdec->client.base); 44346f226c9SMikko Perttunen if (err < 0) { 44446f226c9SMikko Perttunen dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 44546f226c9SMikko Perttunen err); 44646f226c9SMikko Perttunen return err; 44746f226c9SMikko Perttunen } 44846f226c9SMikko Perttunen 44946f226c9SMikko Perttunen falcon_exit(&nvdec->falcon); 45046f226c9SMikko Perttunen 45146f226c9SMikko Perttunen return 0; 45246f226c9SMikko Perttunen } 45346f226c9SMikko Perttunen 45446f226c9SMikko Perttunen static const struct dev_pm_ops nvdec_pm_ops = { 45546f226c9SMikko Perttunen SET_RUNTIME_PM_OPS(nvdec_runtime_suspend, nvdec_runtime_resume, NULL) 456*28b16229SDmitry Osipenko SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 457*28b16229SDmitry Osipenko pm_runtime_force_resume) 45846f226c9SMikko Perttunen }; 45946f226c9SMikko Perttunen 46046f226c9SMikko Perttunen struct platform_driver tegra_nvdec_driver = { 46146f226c9SMikko Perttunen .driver = { 46246f226c9SMikko Perttunen .name = "tegra-nvdec", 46346f226c9SMikko Perttunen .of_match_table = tegra_nvdec_of_match, 46446f226c9SMikko Perttunen .pm = &nvdec_pm_ops 46546f226c9SMikko Perttunen }, 46646f226c9SMikko Perttunen .probe = nvdec_probe, 46746f226c9SMikko Perttunen .remove = nvdec_remove, 46846f226c9SMikko Perttunen }; 46946f226c9SMikko Perttunen 47046f226c9SMikko Perttunen #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) 47146f226c9SMikko Perttunen MODULE_FIRMWARE(NVIDIA_TEGRA_210_NVDEC_FIRMWARE); 47246f226c9SMikko Perttunen #endif 47346f226c9SMikko Perttunen #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) 47446f226c9SMikko Perttunen MODULE_FIRMWARE(NVIDIA_TEGRA_186_NVDEC_FIRMWARE); 47546f226c9SMikko Perttunen #endif 47646f226c9SMikko Perttunen #if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) 47746f226c9SMikko Perttunen MODULE_FIRMWARE(NVIDIA_TEGRA_194_NVDEC_FIRMWARE); 47846f226c9SMikko Perttunen #endif 479