146f226c9SMikko Perttunen // SPDX-License-Identifier: GPL-2.0-only 246f226c9SMikko Perttunen /* 395ffcb4cSMikko Perttunen * Copyright (c) 2015-2022, NVIDIA Corporation. 446f226c9SMikko Perttunen */ 546f226c9SMikko Perttunen 646f226c9SMikko Perttunen #include <linux/clk.h> 746f226c9SMikko Perttunen #include <linux/delay.h> 87ac1a36aSRobin Murphy #include <linux/dma-mapping.h> 946f226c9SMikko Perttunen #include <linux/host1x.h> 1046f226c9SMikko Perttunen #include <linux/iommu.h> 11fbc82b9bSMikko Perttunen #include <linux/iopoll.h> 1246f226c9SMikko Perttunen #include <linux/module.h> 1346f226c9SMikko Perttunen #include <linux/of.h> 1446f226c9SMikko Perttunen #include <linux/of_device.h> 1546f226c9SMikko Perttunen #include <linux/of_platform.h> 1646f226c9SMikko Perttunen #include <linux/platform_device.h> 1746f226c9SMikko Perttunen #include <linux/pm_runtime.h> 1846f226c9SMikko Perttunen #include <linux/reset.h> 1946f226c9SMikko Perttunen 20fbc82b9bSMikko Perttunen #include <soc/tegra/mc.h> 2146f226c9SMikko Perttunen 2246f226c9SMikko Perttunen #include "drm.h" 2346f226c9SMikko Perttunen #include "falcon.h" 24fbc82b9bSMikko Perttunen #include "riscv.h" 2546f226c9SMikko Perttunen #include "vic.h" 2646f226c9SMikko Perttunen 27fbc82b9bSMikko Perttunen #define NVDEC_FALCON_DEBUGINFO 0x1094 2888c0292fSMikko Perttunen #define NVDEC_TFBIF_TRANSCFG 0x2c44 2988c0292fSMikko Perttunen 3046f226c9SMikko Perttunen struct nvdec_config { 3146f226c9SMikko Perttunen const char *firmware; 3246f226c9SMikko Perttunen unsigned int version; 3346f226c9SMikko Perttunen bool supports_sid; 34fbc82b9bSMikko Perttunen bool has_riscv; 3595ffcb4cSMikko Perttunen bool has_extra_clocks; 3646f226c9SMikko Perttunen }; 3746f226c9SMikko Perttunen 3846f226c9SMikko Perttunen struct nvdec { 3946f226c9SMikko Perttunen struct falcon falcon; 4046f226c9SMikko Perttunen 4146f226c9SMikko Perttunen void __iomem *regs; 4246f226c9SMikko Perttunen struct tegra_drm_client client; 4346f226c9SMikko Perttunen struct host1x_channel *channel; 4446f226c9SMikko Perttunen struct device *dev; 4595ffcb4cSMikko Perttunen struct clk_bulk_data clks[3]; 4695ffcb4cSMikko Perttunen unsigned int num_clks; 47fbc82b9bSMikko Perttunen struct reset_control *reset; 4846f226c9SMikko Perttunen 4946f226c9SMikko Perttunen /* Platform configuration */ 5046f226c9SMikko Perttunen const struct nvdec_config *config; 51fbc82b9bSMikko Perttunen 52fbc82b9bSMikko Perttunen /* RISC-V specific data */ 53fbc82b9bSMikko Perttunen struct tegra_drm_riscv riscv; 54fbc82b9bSMikko Perttunen phys_addr_t carveout_base; 5546f226c9SMikko Perttunen }; 5646f226c9SMikko Perttunen 5746f226c9SMikko Perttunen static inline struct nvdec *to_nvdec(struct tegra_drm_client *client) 5846f226c9SMikko Perttunen { 5946f226c9SMikko Perttunen return container_of(client, struct nvdec, client); 6046f226c9SMikko Perttunen } 6146f226c9SMikko Perttunen 622245c2a2SArnd Bergmann static inline void nvdec_writel(struct nvdec *nvdec, u32 value, 632245c2a2SArnd Bergmann unsigned int offset) 6446f226c9SMikko Perttunen { 6546f226c9SMikko Perttunen writel(value, nvdec->regs + offset); 6646f226c9SMikko Perttunen } 6746f226c9SMikko Perttunen 68fbc82b9bSMikko Perttunen static int nvdec_boot_falcon(struct nvdec *nvdec) 6946f226c9SMikko Perttunen { 70*2abdd44eSThierry Reding u32 stream_id; 7146f226c9SMikko Perttunen int err; 7246f226c9SMikko Perttunen 73*2abdd44eSThierry Reding if (nvdec->config->supports_sid && tegra_dev_iommu_get_stream_id(nvdec->dev, &stream_id)) { 7446f226c9SMikko Perttunen u32 value; 7546f226c9SMikko Perttunen 7646f226c9SMikko Perttunen value = TRANSCFG_ATT(1, TRANSCFG_SID_FALCON) | TRANSCFG_ATT(0, TRANSCFG_SID_HW); 7788c0292fSMikko Perttunen nvdec_writel(nvdec, value, NVDEC_TFBIF_TRANSCFG); 7846f226c9SMikko Perttunen 79*2abdd44eSThierry Reding nvdec_writel(nvdec, stream_id, VIC_THI_STREAMID0); 80*2abdd44eSThierry Reding nvdec_writel(nvdec, stream_id, VIC_THI_STREAMID1); 8146f226c9SMikko Perttunen } 8246f226c9SMikko Perttunen 8346f226c9SMikko Perttunen err = falcon_boot(&nvdec->falcon); 8446f226c9SMikko Perttunen if (err < 0) 8546f226c9SMikko Perttunen return err; 8646f226c9SMikko Perttunen 8746f226c9SMikko Perttunen err = falcon_wait_idle(&nvdec->falcon); 8846f226c9SMikko Perttunen if (err < 0) { 8946f226c9SMikko Perttunen dev_err(nvdec->dev, "falcon boot timed out\n"); 9046f226c9SMikko Perttunen return err; 9146f226c9SMikko Perttunen } 9246f226c9SMikko Perttunen 9346f226c9SMikko Perttunen return 0; 9446f226c9SMikko Perttunen } 9546f226c9SMikko Perttunen 96fbc82b9bSMikko Perttunen static int nvdec_wait_debuginfo(struct nvdec *nvdec, const char *phase) 97fbc82b9bSMikko Perttunen { 98fbc82b9bSMikko Perttunen int err; 99fbc82b9bSMikko Perttunen u32 val; 100fbc82b9bSMikko Perttunen 101fbc82b9bSMikko Perttunen err = readl_poll_timeout(nvdec->regs + NVDEC_FALCON_DEBUGINFO, val, val == 0x0, 10, 100000); 102fbc82b9bSMikko Perttunen if (err) { 103fbc82b9bSMikko Perttunen dev_err(nvdec->dev, "failed to boot %s, debuginfo=0x%x\n", phase, val); 104fbc82b9bSMikko Perttunen return err; 105fbc82b9bSMikko Perttunen } 106fbc82b9bSMikko Perttunen 107fbc82b9bSMikko Perttunen return 0; 108fbc82b9bSMikko Perttunen } 109fbc82b9bSMikko Perttunen 110fbc82b9bSMikko Perttunen static int nvdec_boot_riscv(struct nvdec *nvdec) 111fbc82b9bSMikko Perttunen { 112fbc82b9bSMikko Perttunen int err; 113fbc82b9bSMikko Perttunen 114fbc82b9bSMikko Perttunen err = reset_control_acquire(nvdec->reset); 115fbc82b9bSMikko Perttunen if (err) 116fbc82b9bSMikko Perttunen return err; 117fbc82b9bSMikko Perttunen 118fbc82b9bSMikko Perttunen nvdec_writel(nvdec, 0xabcd1234, NVDEC_FALCON_DEBUGINFO); 119fbc82b9bSMikko Perttunen 120fbc82b9bSMikko Perttunen err = tegra_drm_riscv_boot_bootrom(&nvdec->riscv, nvdec->carveout_base, 1, 121fbc82b9bSMikko Perttunen &nvdec->riscv.bl_desc); 122fbc82b9bSMikko Perttunen if (err) { 123fbc82b9bSMikko Perttunen dev_err(nvdec->dev, "failed to execute bootloader\n"); 124fbc82b9bSMikko Perttunen goto release_reset; 125fbc82b9bSMikko Perttunen } 126fbc82b9bSMikko Perttunen 127fbc82b9bSMikko Perttunen err = nvdec_wait_debuginfo(nvdec, "bootloader"); 128fbc82b9bSMikko Perttunen if (err) 129fbc82b9bSMikko Perttunen goto release_reset; 130fbc82b9bSMikko Perttunen 131fbc82b9bSMikko Perttunen err = reset_control_reset(nvdec->reset); 132fbc82b9bSMikko Perttunen if (err) 133fbc82b9bSMikko Perttunen goto release_reset; 134fbc82b9bSMikko Perttunen 135fbc82b9bSMikko Perttunen nvdec_writel(nvdec, 0xabcd1234, NVDEC_FALCON_DEBUGINFO); 136fbc82b9bSMikko Perttunen 137fbc82b9bSMikko Perttunen err = tegra_drm_riscv_boot_bootrom(&nvdec->riscv, nvdec->carveout_base, 1, 138fbc82b9bSMikko Perttunen &nvdec->riscv.os_desc); 139fbc82b9bSMikko Perttunen if (err) { 140fbc82b9bSMikko Perttunen dev_err(nvdec->dev, "failed to execute firmware\n"); 141fbc82b9bSMikko Perttunen goto release_reset; 142fbc82b9bSMikko Perttunen } 143fbc82b9bSMikko Perttunen 144fbc82b9bSMikko Perttunen err = nvdec_wait_debuginfo(nvdec, "firmware"); 145fbc82b9bSMikko Perttunen if (err) 146fbc82b9bSMikko Perttunen goto release_reset; 147fbc82b9bSMikko Perttunen 148fbc82b9bSMikko Perttunen release_reset: 149fbc82b9bSMikko Perttunen reset_control_release(nvdec->reset); 150fbc82b9bSMikko Perttunen 151fbc82b9bSMikko Perttunen return err; 152fbc82b9bSMikko Perttunen } 153fbc82b9bSMikko Perttunen 15446f226c9SMikko Perttunen static int nvdec_init(struct host1x_client *client) 15546f226c9SMikko Perttunen { 15646f226c9SMikko Perttunen struct tegra_drm_client *drm = host1x_to_drm_client(client); 15746f226c9SMikko Perttunen struct drm_device *dev = dev_get_drvdata(client->host); 15846f226c9SMikko Perttunen struct tegra_drm *tegra = dev->dev_private; 15946f226c9SMikko Perttunen struct nvdec *nvdec = to_nvdec(drm); 16046f226c9SMikko Perttunen int err; 16146f226c9SMikko Perttunen 16246f226c9SMikko Perttunen err = host1x_client_iommu_attach(client); 16346f226c9SMikko Perttunen if (err < 0 && err != -ENODEV) { 16446f226c9SMikko Perttunen dev_err(nvdec->dev, "failed to attach to domain: %d\n", err); 16546f226c9SMikko Perttunen return err; 16646f226c9SMikko Perttunen } 16746f226c9SMikko Perttunen 16846f226c9SMikko Perttunen nvdec->channel = host1x_channel_request(client); 16946f226c9SMikko Perttunen if (!nvdec->channel) { 17046f226c9SMikko Perttunen err = -ENOMEM; 17146f226c9SMikko Perttunen goto detach; 17246f226c9SMikko Perttunen } 17346f226c9SMikko Perttunen 17446f226c9SMikko Perttunen client->syncpts[0] = host1x_syncpt_request(client, 0); 17546f226c9SMikko Perttunen if (!client->syncpts[0]) { 17646f226c9SMikko Perttunen err = -ENOMEM; 17746f226c9SMikko Perttunen goto free_channel; 17846f226c9SMikko Perttunen } 17946f226c9SMikko Perttunen 18028b16229SDmitry Osipenko pm_runtime_enable(client->dev); 18128b16229SDmitry Osipenko pm_runtime_use_autosuspend(client->dev); 18228b16229SDmitry Osipenko pm_runtime_set_autosuspend_delay(client->dev, 500); 18328b16229SDmitry Osipenko 18446f226c9SMikko Perttunen err = tegra_drm_register_client(tegra, drm); 18546f226c9SMikko Perttunen if (err < 0) 18628b16229SDmitry Osipenko goto disable_rpm; 18746f226c9SMikko Perttunen 18846f226c9SMikko Perttunen /* 18946f226c9SMikko Perttunen * Inherit the DMA parameters (such as maximum segment size) from the 19046f226c9SMikko Perttunen * parent host1x device. 19146f226c9SMikko Perttunen */ 19246f226c9SMikko Perttunen client->dev->dma_parms = client->host->dma_parms; 19346f226c9SMikko Perttunen 19446f226c9SMikko Perttunen return 0; 19546f226c9SMikko Perttunen 19628b16229SDmitry Osipenko disable_rpm: 19728b16229SDmitry Osipenko pm_runtime_dont_use_autosuspend(client->dev); 19828b16229SDmitry Osipenko pm_runtime_force_suspend(client->dev); 19928b16229SDmitry Osipenko 20046f226c9SMikko Perttunen host1x_syncpt_put(client->syncpts[0]); 20146f226c9SMikko Perttunen free_channel: 20246f226c9SMikko Perttunen host1x_channel_put(nvdec->channel); 20346f226c9SMikko Perttunen detach: 20446f226c9SMikko Perttunen host1x_client_iommu_detach(client); 20546f226c9SMikko Perttunen 20646f226c9SMikko Perttunen return err; 20746f226c9SMikko Perttunen } 20846f226c9SMikko Perttunen 20946f226c9SMikko Perttunen static int nvdec_exit(struct host1x_client *client) 21046f226c9SMikko Perttunen { 21146f226c9SMikko Perttunen struct tegra_drm_client *drm = host1x_to_drm_client(client); 21246f226c9SMikko Perttunen struct drm_device *dev = dev_get_drvdata(client->host); 21346f226c9SMikko Perttunen struct tegra_drm *tegra = dev->dev_private; 21446f226c9SMikko Perttunen struct nvdec *nvdec = to_nvdec(drm); 21546f226c9SMikko Perttunen int err; 21646f226c9SMikko Perttunen 21746f226c9SMikko Perttunen /* avoid a dangling pointer just in case this disappears */ 21846f226c9SMikko Perttunen client->dev->dma_parms = NULL; 21946f226c9SMikko Perttunen 22046f226c9SMikko Perttunen err = tegra_drm_unregister_client(tegra, drm); 22146f226c9SMikko Perttunen if (err < 0) 22246f226c9SMikko Perttunen return err; 22346f226c9SMikko Perttunen 22428b16229SDmitry Osipenko pm_runtime_dont_use_autosuspend(client->dev); 22528b16229SDmitry Osipenko pm_runtime_force_suspend(client->dev); 22628b16229SDmitry Osipenko 22746f226c9SMikko Perttunen host1x_syncpt_put(client->syncpts[0]); 22846f226c9SMikko Perttunen host1x_channel_put(nvdec->channel); 22946f226c9SMikko Perttunen host1x_client_iommu_detach(client); 23046f226c9SMikko Perttunen 23128b16229SDmitry Osipenko nvdec->channel = NULL; 23228b16229SDmitry Osipenko 23346f226c9SMikko Perttunen if (client->group) { 23446f226c9SMikko Perttunen dma_unmap_single(nvdec->dev, nvdec->falcon.firmware.phys, 23546f226c9SMikko Perttunen nvdec->falcon.firmware.size, DMA_TO_DEVICE); 23646f226c9SMikko Perttunen tegra_drm_free(tegra, nvdec->falcon.firmware.size, 23746f226c9SMikko Perttunen nvdec->falcon.firmware.virt, 23846f226c9SMikko Perttunen nvdec->falcon.firmware.iova); 23946f226c9SMikko Perttunen } else { 24046f226c9SMikko Perttunen dma_free_coherent(nvdec->dev, nvdec->falcon.firmware.size, 24146f226c9SMikko Perttunen nvdec->falcon.firmware.virt, 24246f226c9SMikko Perttunen nvdec->falcon.firmware.iova); 24346f226c9SMikko Perttunen } 24446f226c9SMikko Perttunen 24546f226c9SMikko Perttunen return 0; 24646f226c9SMikko Perttunen } 24746f226c9SMikko Perttunen 24846f226c9SMikko Perttunen static const struct host1x_client_ops nvdec_client_ops = { 24946f226c9SMikko Perttunen .init = nvdec_init, 25046f226c9SMikko Perttunen .exit = nvdec_exit, 25146f226c9SMikko Perttunen }; 25246f226c9SMikko Perttunen 253fbc82b9bSMikko Perttunen static int nvdec_load_falcon_firmware(struct nvdec *nvdec) 25446f226c9SMikko Perttunen { 25546f226c9SMikko Perttunen struct host1x_client *client = &nvdec->client.base; 25646f226c9SMikko Perttunen struct tegra_drm *tegra = nvdec->client.drm; 25746f226c9SMikko Perttunen dma_addr_t iova; 25846f226c9SMikko Perttunen size_t size; 25946f226c9SMikko Perttunen void *virt; 26046f226c9SMikko Perttunen int err; 26146f226c9SMikko Perttunen 26246f226c9SMikko Perttunen if (nvdec->falcon.firmware.virt) 26346f226c9SMikko Perttunen return 0; 26446f226c9SMikko Perttunen 26546f226c9SMikko Perttunen err = falcon_read_firmware(&nvdec->falcon, nvdec->config->firmware); 26646f226c9SMikko Perttunen if (err < 0) 26746f226c9SMikko Perttunen return err; 26846f226c9SMikko Perttunen 26946f226c9SMikko Perttunen size = nvdec->falcon.firmware.size; 27046f226c9SMikko Perttunen 27146f226c9SMikko Perttunen if (!client->group) { 27246f226c9SMikko Perttunen virt = dma_alloc_coherent(nvdec->dev, size, &iova, GFP_KERNEL); 27346f226c9SMikko Perttunen 27446f226c9SMikko Perttunen err = dma_mapping_error(nvdec->dev, iova); 27546f226c9SMikko Perttunen if (err < 0) 27646f226c9SMikko Perttunen return err; 27746f226c9SMikko Perttunen } else { 27846f226c9SMikko Perttunen virt = tegra_drm_alloc(tegra, size, &iova); 27946f226c9SMikko Perttunen } 28046f226c9SMikko Perttunen 28146f226c9SMikko Perttunen nvdec->falcon.firmware.virt = virt; 28246f226c9SMikko Perttunen nvdec->falcon.firmware.iova = iova; 28346f226c9SMikko Perttunen 28446f226c9SMikko Perttunen err = falcon_load_firmware(&nvdec->falcon); 28546f226c9SMikko Perttunen if (err < 0) 28646f226c9SMikko Perttunen goto cleanup; 28746f226c9SMikko Perttunen 28846f226c9SMikko Perttunen /* 28946f226c9SMikko Perttunen * In this case we have received an IOVA from the shared domain, so we 29046f226c9SMikko Perttunen * need to make sure to get the physical address so that the DMA API 29146f226c9SMikko Perttunen * knows what memory pages to flush the cache for. 29246f226c9SMikko Perttunen */ 29346f226c9SMikko Perttunen if (client->group) { 29446f226c9SMikko Perttunen dma_addr_t phys; 29546f226c9SMikko Perttunen 29646f226c9SMikko Perttunen phys = dma_map_single(nvdec->dev, virt, size, DMA_TO_DEVICE); 29746f226c9SMikko Perttunen 29846f226c9SMikko Perttunen err = dma_mapping_error(nvdec->dev, phys); 29946f226c9SMikko Perttunen if (err < 0) 30046f226c9SMikko Perttunen goto cleanup; 30146f226c9SMikko Perttunen 30246f226c9SMikko Perttunen nvdec->falcon.firmware.phys = phys; 30346f226c9SMikko Perttunen } 30446f226c9SMikko Perttunen 30546f226c9SMikko Perttunen return 0; 30646f226c9SMikko Perttunen 30746f226c9SMikko Perttunen cleanup: 30846f226c9SMikko Perttunen if (!client->group) 30946f226c9SMikko Perttunen dma_free_coherent(nvdec->dev, size, virt, iova); 31046f226c9SMikko Perttunen else 31146f226c9SMikko Perttunen tegra_drm_free(tegra, size, virt, iova); 31246f226c9SMikko Perttunen 31346f226c9SMikko Perttunen return err; 31446f226c9SMikko Perttunen } 31546f226c9SMikko Perttunen 316e1189fafSArnd Bergmann static __maybe_unused int nvdec_runtime_resume(struct device *dev) 31746f226c9SMikko Perttunen { 31846f226c9SMikko Perttunen struct nvdec *nvdec = dev_get_drvdata(dev); 31946f226c9SMikko Perttunen int err; 32046f226c9SMikko Perttunen 32195ffcb4cSMikko Perttunen err = clk_bulk_prepare_enable(nvdec->num_clks, nvdec->clks); 32246f226c9SMikko Perttunen if (err < 0) 32346f226c9SMikko Perttunen return err; 32446f226c9SMikko Perttunen 32546f226c9SMikko Perttunen usleep_range(10, 20); 32646f226c9SMikko Perttunen 327fbc82b9bSMikko Perttunen if (nvdec->config->has_riscv) { 328fbc82b9bSMikko Perttunen err = nvdec_boot_riscv(nvdec); 329fbc82b9bSMikko Perttunen if (err < 0) 330fbc82b9bSMikko Perttunen goto disable; 331fbc82b9bSMikko Perttunen } else { 332fbc82b9bSMikko Perttunen err = nvdec_load_falcon_firmware(nvdec); 33346f226c9SMikko Perttunen if (err < 0) 33446f226c9SMikko Perttunen goto disable; 33546f226c9SMikko Perttunen 336fbc82b9bSMikko Perttunen err = nvdec_boot_falcon(nvdec); 33746f226c9SMikko Perttunen if (err < 0) 33846f226c9SMikko Perttunen goto disable; 339fbc82b9bSMikko Perttunen } 34046f226c9SMikko Perttunen 34146f226c9SMikko Perttunen return 0; 34246f226c9SMikko Perttunen 34346f226c9SMikko Perttunen disable: 34495ffcb4cSMikko Perttunen clk_bulk_disable_unprepare(nvdec->num_clks, nvdec->clks); 34546f226c9SMikko Perttunen return err; 34646f226c9SMikko Perttunen } 34746f226c9SMikko Perttunen 348e1189fafSArnd Bergmann static __maybe_unused int nvdec_runtime_suspend(struct device *dev) 34946f226c9SMikko Perttunen { 35046f226c9SMikko Perttunen struct nvdec *nvdec = dev_get_drvdata(dev); 35146f226c9SMikko Perttunen 35228b16229SDmitry Osipenko host1x_channel_stop(nvdec->channel); 35328b16229SDmitry Osipenko 35495ffcb4cSMikko Perttunen clk_bulk_disable_unprepare(nvdec->num_clks, nvdec->clks); 35546f226c9SMikko Perttunen 35646f226c9SMikko Perttunen return 0; 35746f226c9SMikko Perttunen } 35846f226c9SMikko Perttunen 35946f226c9SMikko Perttunen static int nvdec_open_channel(struct tegra_drm_client *client, 36046f226c9SMikko Perttunen struct tegra_drm_context *context) 36146f226c9SMikko Perttunen { 36246f226c9SMikko Perttunen struct nvdec *nvdec = to_nvdec(client); 36346f226c9SMikko Perttunen 36446f226c9SMikko Perttunen context->channel = host1x_channel_get(nvdec->channel); 36558ed47adSDmitry Osipenko if (!context->channel) 36646f226c9SMikko Perttunen return -ENOMEM; 36746f226c9SMikko Perttunen 36846f226c9SMikko Perttunen return 0; 36946f226c9SMikko Perttunen } 37046f226c9SMikko Perttunen 37146f226c9SMikko Perttunen static void nvdec_close_channel(struct tegra_drm_context *context) 37246f226c9SMikko Perttunen { 37346f226c9SMikko Perttunen host1x_channel_put(context->channel); 37446f226c9SMikko Perttunen } 37546f226c9SMikko Perttunen 376bf0297acSMikko Perttunen static int nvdec_can_use_memory_ctx(struct tegra_drm_client *client, bool *supported) 377bf0297acSMikko Perttunen { 378bf0297acSMikko Perttunen *supported = true; 379bf0297acSMikko Perttunen 380bf0297acSMikko Perttunen return 0; 381bf0297acSMikko Perttunen } 382bf0297acSMikko Perttunen 38346f226c9SMikko Perttunen static const struct tegra_drm_client_ops nvdec_ops = { 38446f226c9SMikko Perttunen .open_channel = nvdec_open_channel, 38546f226c9SMikko Perttunen .close_channel = nvdec_close_channel, 38646f226c9SMikko Perttunen .submit = tegra_drm_submit, 387bf0297acSMikko Perttunen .get_streamid_offset = tegra_drm_get_streamid_offset_thi, 388bf0297acSMikko Perttunen .can_use_memory_ctx = nvdec_can_use_memory_ctx, 38946f226c9SMikko Perttunen }; 39046f226c9SMikko Perttunen 39146f226c9SMikko Perttunen #define NVIDIA_TEGRA_210_NVDEC_FIRMWARE "nvidia/tegra210/nvdec.bin" 39246f226c9SMikko Perttunen 39346f226c9SMikko Perttunen static const struct nvdec_config nvdec_t210_config = { 39446f226c9SMikko Perttunen .firmware = NVIDIA_TEGRA_210_NVDEC_FIRMWARE, 39546f226c9SMikko Perttunen .version = 0x21, 39646f226c9SMikko Perttunen .supports_sid = false, 39746f226c9SMikko Perttunen }; 39846f226c9SMikko Perttunen 39946f226c9SMikko Perttunen #define NVIDIA_TEGRA_186_NVDEC_FIRMWARE "nvidia/tegra186/nvdec.bin" 40046f226c9SMikko Perttunen 40146f226c9SMikko Perttunen static const struct nvdec_config nvdec_t186_config = { 40246f226c9SMikko Perttunen .firmware = NVIDIA_TEGRA_186_NVDEC_FIRMWARE, 40346f226c9SMikko Perttunen .version = 0x18, 40446f226c9SMikko Perttunen .supports_sid = true, 40546f226c9SMikko Perttunen }; 40646f226c9SMikko Perttunen 40746f226c9SMikko Perttunen #define NVIDIA_TEGRA_194_NVDEC_FIRMWARE "nvidia/tegra194/nvdec.bin" 40846f226c9SMikko Perttunen 40946f226c9SMikko Perttunen static const struct nvdec_config nvdec_t194_config = { 41046f226c9SMikko Perttunen .firmware = NVIDIA_TEGRA_194_NVDEC_FIRMWARE, 41146f226c9SMikko Perttunen .version = 0x19, 41246f226c9SMikko Perttunen .supports_sid = true, 41346f226c9SMikko Perttunen }; 41446f226c9SMikko Perttunen 415fbc82b9bSMikko Perttunen static const struct nvdec_config nvdec_t234_config = { 416fbc82b9bSMikko Perttunen .version = 0x23, 417fbc82b9bSMikko Perttunen .supports_sid = true, 418fbc82b9bSMikko Perttunen .has_riscv = true, 419fbc82b9bSMikko Perttunen .has_extra_clocks = true, 420fbc82b9bSMikko Perttunen }; 421fbc82b9bSMikko Perttunen 42246f226c9SMikko Perttunen static const struct of_device_id tegra_nvdec_of_match[] = { 42346f226c9SMikko Perttunen { .compatible = "nvidia,tegra210-nvdec", .data = &nvdec_t210_config }, 42446f226c9SMikko Perttunen { .compatible = "nvidia,tegra186-nvdec", .data = &nvdec_t186_config }, 42546f226c9SMikko Perttunen { .compatible = "nvidia,tegra194-nvdec", .data = &nvdec_t194_config }, 426fbc82b9bSMikko Perttunen { .compatible = "nvidia,tegra234-nvdec", .data = &nvdec_t234_config }, 42746f226c9SMikko Perttunen { }, 42846f226c9SMikko Perttunen }; 42946f226c9SMikko Perttunen MODULE_DEVICE_TABLE(of, tegra_nvdec_of_match); 43046f226c9SMikko Perttunen 43146f226c9SMikko Perttunen static int nvdec_probe(struct platform_device *pdev) 43246f226c9SMikko Perttunen { 43346f226c9SMikko Perttunen struct device *dev = &pdev->dev; 43446f226c9SMikko Perttunen struct host1x_syncpt **syncpts; 43546f226c9SMikko Perttunen struct nvdec *nvdec; 43646f226c9SMikko Perttunen u32 host_class; 43746f226c9SMikko Perttunen int err; 43846f226c9SMikko Perttunen 43946f226c9SMikko Perttunen /* inherit DMA mask from host1x parent */ 44046f226c9SMikko Perttunen err = dma_coerce_mask_and_coherent(dev, *dev->parent->dma_mask); 44146f226c9SMikko Perttunen if (err < 0) { 44246f226c9SMikko Perttunen dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err); 44346f226c9SMikko Perttunen return err; 44446f226c9SMikko Perttunen } 44546f226c9SMikko Perttunen 44646f226c9SMikko Perttunen nvdec = devm_kzalloc(dev, sizeof(*nvdec), GFP_KERNEL); 44746f226c9SMikko Perttunen if (!nvdec) 44846f226c9SMikko Perttunen return -ENOMEM; 44946f226c9SMikko Perttunen 45046f226c9SMikko Perttunen nvdec->config = of_device_get_match_data(dev); 45146f226c9SMikko Perttunen 45246f226c9SMikko Perttunen syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL); 45346f226c9SMikko Perttunen if (!syncpts) 45446f226c9SMikko Perttunen return -ENOMEM; 45546f226c9SMikko Perttunen 45646f226c9SMikko Perttunen nvdec->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); 45746f226c9SMikko Perttunen if (IS_ERR(nvdec->regs)) 45846f226c9SMikko Perttunen return PTR_ERR(nvdec->regs); 45946f226c9SMikko Perttunen 46095ffcb4cSMikko Perttunen nvdec->clks[0].id = "nvdec"; 46195ffcb4cSMikko Perttunen nvdec->num_clks = 1; 46295ffcb4cSMikko Perttunen 46395ffcb4cSMikko Perttunen if (nvdec->config->has_extra_clocks) { 46495ffcb4cSMikko Perttunen nvdec->num_clks = 3; 46595ffcb4cSMikko Perttunen nvdec->clks[1].id = "fuse"; 46695ffcb4cSMikko Perttunen nvdec->clks[2].id = "tsec_pka"; 46746f226c9SMikko Perttunen } 46846f226c9SMikko Perttunen 46995ffcb4cSMikko Perttunen err = devm_clk_bulk_get(dev, nvdec->num_clks, nvdec->clks); 47095ffcb4cSMikko Perttunen if (err) { 47195ffcb4cSMikko Perttunen dev_err(&pdev->dev, "failed to get clock(s)\n"); 47295ffcb4cSMikko Perttunen return err; 47395ffcb4cSMikko Perttunen } 47495ffcb4cSMikko Perttunen 47595ffcb4cSMikko Perttunen err = clk_set_rate(nvdec->clks[0].clk, ULONG_MAX); 476e97a951fSMikko Perttunen if (err < 0) { 477e97a951fSMikko Perttunen dev_err(&pdev->dev, "failed to set clock rate\n"); 478e97a951fSMikko Perttunen return err; 479e97a951fSMikko Perttunen } 480e97a951fSMikko Perttunen 48146f226c9SMikko Perttunen err = of_property_read_u32(dev->of_node, "nvidia,host1x-class", &host_class); 48246f226c9SMikko Perttunen if (err < 0) 48346f226c9SMikko Perttunen host_class = HOST1X_CLASS_NVDEC; 48446f226c9SMikko Perttunen 485fbc82b9bSMikko Perttunen if (nvdec->config->has_riscv) { 486fbc82b9bSMikko Perttunen struct tegra_mc *mc; 487fbc82b9bSMikko Perttunen 488fbc82b9bSMikko Perttunen mc = devm_tegra_memory_controller_get(dev); 489fbc82b9bSMikko Perttunen if (IS_ERR(mc)) { 490fbc82b9bSMikko Perttunen dev_err_probe(dev, PTR_ERR(mc), 491fbc82b9bSMikko Perttunen "failed to get memory controller handle\n"); 492fbc82b9bSMikko Perttunen return PTR_ERR(mc); 493fbc82b9bSMikko Perttunen } 494fbc82b9bSMikko Perttunen 495fbc82b9bSMikko Perttunen err = tegra_mc_get_carveout_info(mc, 1, &nvdec->carveout_base, NULL); 496fbc82b9bSMikko Perttunen if (err) { 497fbc82b9bSMikko Perttunen dev_err(dev, "failed to get carveout info: %d\n", err); 498fbc82b9bSMikko Perttunen return err; 499fbc82b9bSMikko Perttunen } 500fbc82b9bSMikko Perttunen 501fbc82b9bSMikko Perttunen nvdec->reset = devm_reset_control_get_exclusive_released(dev, "nvdec"); 502fbc82b9bSMikko Perttunen if (IS_ERR(nvdec->reset)) { 503fbc82b9bSMikko Perttunen dev_err_probe(dev, PTR_ERR(nvdec->reset), "failed to get reset\n"); 504fbc82b9bSMikko Perttunen return PTR_ERR(nvdec->reset); 505fbc82b9bSMikko Perttunen } 506fbc82b9bSMikko Perttunen 507fbc82b9bSMikko Perttunen nvdec->riscv.dev = dev; 508fbc82b9bSMikko Perttunen nvdec->riscv.regs = nvdec->regs; 509fbc82b9bSMikko Perttunen 510fbc82b9bSMikko Perttunen err = tegra_drm_riscv_read_descriptors(&nvdec->riscv); 511fbc82b9bSMikko Perttunen if (err < 0) 512fbc82b9bSMikko Perttunen return err; 513fbc82b9bSMikko Perttunen } else { 51446f226c9SMikko Perttunen nvdec->falcon.dev = dev; 51546f226c9SMikko Perttunen nvdec->falcon.regs = nvdec->regs; 51646f226c9SMikko Perttunen 51746f226c9SMikko Perttunen err = falcon_init(&nvdec->falcon); 51846f226c9SMikko Perttunen if (err < 0) 51946f226c9SMikko Perttunen return err; 520fbc82b9bSMikko Perttunen } 52146f226c9SMikko Perttunen 52246f226c9SMikko Perttunen platform_set_drvdata(pdev, nvdec); 52346f226c9SMikko Perttunen 52446f226c9SMikko Perttunen INIT_LIST_HEAD(&nvdec->client.base.list); 52546f226c9SMikko Perttunen nvdec->client.base.ops = &nvdec_client_ops; 52646f226c9SMikko Perttunen nvdec->client.base.dev = dev; 52746f226c9SMikko Perttunen nvdec->client.base.class = host_class; 52846f226c9SMikko Perttunen nvdec->client.base.syncpts = syncpts; 52946f226c9SMikko Perttunen nvdec->client.base.num_syncpts = 1; 53046f226c9SMikko Perttunen nvdec->dev = dev; 53146f226c9SMikko Perttunen 53246f226c9SMikko Perttunen INIT_LIST_HEAD(&nvdec->client.list); 53346f226c9SMikko Perttunen nvdec->client.version = nvdec->config->version; 53446f226c9SMikko Perttunen nvdec->client.ops = &nvdec_ops; 53546f226c9SMikko Perttunen 53646f226c9SMikko Perttunen err = host1x_client_register(&nvdec->client.base); 53746f226c9SMikko Perttunen if (err < 0) { 53846f226c9SMikko Perttunen dev_err(dev, "failed to register host1x client: %d\n", err); 53946f226c9SMikko Perttunen goto exit_falcon; 54046f226c9SMikko Perttunen } 54146f226c9SMikko Perttunen 54246f226c9SMikko Perttunen return 0; 54346f226c9SMikko Perttunen 54446f226c9SMikko Perttunen exit_falcon: 54546f226c9SMikko Perttunen falcon_exit(&nvdec->falcon); 54646f226c9SMikko Perttunen 54746f226c9SMikko Perttunen return err; 54846f226c9SMikko Perttunen } 54946f226c9SMikko Perttunen 55046f226c9SMikko Perttunen static int nvdec_remove(struct platform_device *pdev) 55146f226c9SMikko Perttunen { 55246f226c9SMikko Perttunen struct nvdec *nvdec = platform_get_drvdata(pdev); 55346f226c9SMikko Perttunen int err; 55446f226c9SMikko Perttunen 55546f226c9SMikko Perttunen err = host1x_client_unregister(&nvdec->client.base); 55646f226c9SMikko Perttunen if (err < 0) { 55746f226c9SMikko Perttunen dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 55846f226c9SMikko Perttunen err); 55946f226c9SMikko Perttunen return err; 56046f226c9SMikko Perttunen } 56146f226c9SMikko Perttunen 56246f226c9SMikko Perttunen falcon_exit(&nvdec->falcon); 56346f226c9SMikko Perttunen 56446f226c9SMikko Perttunen return 0; 56546f226c9SMikko Perttunen } 56646f226c9SMikko Perttunen 56746f226c9SMikko Perttunen static const struct dev_pm_ops nvdec_pm_ops = { 56846f226c9SMikko Perttunen SET_RUNTIME_PM_OPS(nvdec_runtime_suspend, nvdec_runtime_resume, NULL) 56928b16229SDmitry Osipenko SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 57028b16229SDmitry Osipenko pm_runtime_force_resume) 57146f226c9SMikko Perttunen }; 57246f226c9SMikko Perttunen 57346f226c9SMikko Perttunen struct platform_driver tegra_nvdec_driver = { 57446f226c9SMikko Perttunen .driver = { 57546f226c9SMikko Perttunen .name = "tegra-nvdec", 57646f226c9SMikko Perttunen .of_match_table = tegra_nvdec_of_match, 57746f226c9SMikko Perttunen .pm = &nvdec_pm_ops 57846f226c9SMikko Perttunen }, 57946f226c9SMikko Perttunen .probe = nvdec_probe, 58046f226c9SMikko Perttunen .remove = nvdec_remove, 58146f226c9SMikko Perttunen }; 58246f226c9SMikko Perttunen 58346f226c9SMikko Perttunen #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) 58446f226c9SMikko Perttunen MODULE_FIRMWARE(NVIDIA_TEGRA_210_NVDEC_FIRMWARE); 58546f226c9SMikko Perttunen #endif 58646f226c9SMikko Perttunen #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) 58746f226c9SMikko Perttunen MODULE_FIRMWARE(NVIDIA_TEGRA_186_NVDEC_FIRMWARE); 58846f226c9SMikko Perttunen #endif 58946f226c9SMikko Perttunen #if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) 59046f226c9SMikko Perttunen MODULE_FIRMWARE(NVIDIA_TEGRA_194_NVDEC_FIRMWARE); 59146f226c9SMikko Perttunen #endif 592