162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Tegra host1x driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2010-2013, NVIDIA Corporation. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/clk.h> 962306a36Sopenharmony_ci#include <linux/delay.h> 1062306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1162306a36Sopenharmony_ci#include <linux/io.h> 1262306a36Sopenharmony_ci#include <linux/list.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/of.h> 1562306a36Sopenharmony_ci#include <linux/of_platform.h> 1662306a36Sopenharmony_ci#include <linux/platform_device.h> 1762306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <soc/tegra/common.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define CREATE_TRACE_POINTS 2362306a36Sopenharmony_ci#include <trace/events/host1x.h> 2462306a36Sopenharmony_ci#undef CREATE_TRACE_POINTS 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) 2762306a36Sopenharmony_ci#include <asm/dma-iommu.h> 2862306a36Sopenharmony_ci#endif 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include "bus.h" 3162306a36Sopenharmony_ci#include "channel.h" 3262306a36Sopenharmony_ci#include "context.h" 3362306a36Sopenharmony_ci#include "debug.h" 3462306a36Sopenharmony_ci#include "dev.h" 3562306a36Sopenharmony_ci#include "intr.h" 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include "hw/host1x01.h" 3862306a36Sopenharmony_ci#include "hw/host1x02.h" 3962306a36Sopenharmony_ci#include "hw/host1x04.h" 4062306a36Sopenharmony_ci#include "hw/host1x05.h" 4162306a36Sopenharmony_ci#include "hw/host1x06.h" 4262306a36Sopenharmony_ci#include "hw/host1x07.h" 4362306a36Sopenharmony_ci#include "hw/host1x08.h" 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_civoid host1x_common_writel(struct host1x *host1x, u32 v, u32 r) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci writel(v, host1x->common_regs + r); 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_civoid host1x_hypervisor_writel(struct host1x *host1x, u32 v, u32 r) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci writel(v, host1x->hv_regs + r); 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ciu32 host1x_hypervisor_readl(struct host1x *host1x, u32 r) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci return readl(host1x->hv_regs + r); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_civoid host1x_sync_writel(struct host1x *host1x, u32 v, u32 r) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci void __iomem *sync_regs = host1x->regs + host1x->info->sync_offset; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci writel(v, sync_regs + r); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ciu32 host1x_sync_readl(struct host1x *host1x, u32 r) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci void __iomem *sync_regs = host1x->regs + host1x->info->sync_offset; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci return readl(sync_regs + r); 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_civoid host1x_ch_writel(struct host1x_channel *ch, u32 v, u32 r) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci writel(v, ch->regs + r); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ciu32 host1x_ch_readl(struct host1x_channel *ch, u32 r) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci return readl(ch->regs + r); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic const struct host1x_info host1x01_info = { 8562306a36Sopenharmony_ci .nb_channels = 8, 8662306a36Sopenharmony_ci .nb_pts = 32, 8762306a36Sopenharmony_ci .nb_mlocks = 16, 8862306a36Sopenharmony_ci .nb_bases = 8, 8962306a36Sopenharmony_ci .init = host1x01_init, 9062306a36Sopenharmony_ci .sync_offset = 0x3000, 9162306a36Sopenharmony_ci .dma_mask = DMA_BIT_MASK(32), 9262306a36Sopenharmony_ci .has_wide_gather = false, 9362306a36Sopenharmony_ci .has_hypervisor = false, 9462306a36Sopenharmony_ci .num_sid_entries = 0, 9562306a36Sopenharmony_ci .sid_table = NULL, 9662306a36Sopenharmony_ci .reserve_vblank_syncpts = true, 9762306a36Sopenharmony_ci}; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic const struct host1x_info host1x02_info = { 10062306a36Sopenharmony_ci .nb_channels = 9, 10162306a36Sopenharmony_ci .nb_pts = 32, 10262306a36Sopenharmony_ci .nb_mlocks = 16, 10362306a36Sopenharmony_ci .nb_bases = 12, 10462306a36Sopenharmony_ci .init = host1x02_init, 10562306a36Sopenharmony_ci .sync_offset = 0x3000, 10662306a36Sopenharmony_ci .dma_mask = DMA_BIT_MASK(32), 10762306a36Sopenharmony_ci .has_wide_gather = false, 10862306a36Sopenharmony_ci .has_hypervisor = false, 10962306a36Sopenharmony_ci .num_sid_entries = 0, 11062306a36Sopenharmony_ci .sid_table = NULL, 11162306a36Sopenharmony_ci .reserve_vblank_syncpts = true, 11262306a36Sopenharmony_ci}; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic const struct host1x_info host1x04_info = { 11562306a36Sopenharmony_ci .nb_channels = 12, 11662306a36Sopenharmony_ci .nb_pts = 192, 11762306a36Sopenharmony_ci .nb_mlocks = 16, 11862306a36Sopenharmony_ci .nb_bases = 64, 11962306a36Sopenharmony_ci .init = host1x04_init, 12062306a36Sopenharmony_ci .sync_offset = 0x2100, 12162306a36Sopenharmony_ci .dma_mask = DMA_BIT_MASK(34), 12262306a36Sopenharmony_ci .has_wide_gather = false, 12362306a36Sopenharmony_ci .has_hypervisor = false, 12462306a36Sopenharmony_ci .num_sid_entries = 0, 12562306a36Sopenharmony_ci .sid_table = NULL, 12662306a36Sopenharmony_ci .reserve_vblank_syncpts = false, 12762306a36Sopenharmony_ci}; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic const struct host1x_info host1x05_info = { 13062306a36Sopenharmony_ci .nb_channels = 14, 13162306a36Sopenharmony_ci .nb_pts = 192, 13262306a36Sopenharmony_ci .nb_mlocks = 16, 13362306a36Sopenharmony_ci .nb_bases = 64, 13462306a36Sopenharmony_ci .init = host1x05_init, 13562306a36Sopenharmony_ci .sync_offset = 0x2100, 13662306a36Sopenharmony_ci .dma_mask = DMA_BIT_MASK(34), 13762306a36Sopenharmony_ci .has_wide_gather = false, 13862306a36Sopenharmony_ci .has_hypervisor = false, 13962306a36Sopenharmony_ci .num_sid_entries = 0, 14062306a36Sopenharmony_ci .sid_table = NULL, 14162306a36Sopenharmony_ci .reserve_vblank_syncpts = false, 14262306a36Sopenharmony_ci}; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic const struct host1x_sid_entry tegra186_sid_table[] = { 14562306a36Sopenharmony_ci { 14662306a36Sopenharmony_ci /* VIC */ 14762306a36Sopenharmony_ci .base = 0x1af0, 14862306a36Sopenharmony_ci .offset = 0x30, 14962306a36Sopenharmony_ci .limit = 0x34 15062306a36Sopenharmony_ci }, 15162306a36Sopenharmony_ci { 15262306a36Sopenharmony_ci /* NVDEC */ 15362306a36Sopenharmony_ci .base = 0x1b00, 15462306a36Sopenharmony_ci .offset = 0x30, 15562306a36Sopenharmony_ci .limit = 0x34 15662306a36Sopenharmony_ci }, 15762306a36Sopenharmony_ci}; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic const struct host1x_info host1x06_info = { 16062306a36Sopenharmony_ci .nb_channels = 63, 16162306a36Sopenharmony_ci .nb_pts = 576, 16262306a36Sopenharmony_ci .nb_mlocks = 24, 16362306a36Sopenharmony_ci .nb_bases = 16, 16462306a36Sopenharmony_ci .init = host1x06_init, 16562306a36Sopenharmony_ci .sync_offset = 0x0, 16662306a36Sopenharmony_ci .dma_mask = DMA_BIT_MASK(40), 16762306a36Sopenharmony_ci .has_wide_gather = true, 16862306a36Sopenharmony_ci .has_hypervisor = true, 16962306a36Sopenharmony_ci .num_sid_entries = ARRAY_SIZE(tegra186_sid_table), 17062306a36Sopenharmony_ci .sid_table = tegra186_sid_table, 17162306a36Sopenharmony_ci .reserve_vblank_syncpts = false, 17262306a36Sopenharmony_ci}; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic const struct host1x_sid_entry tegra194_sid_table[] = { 17562306a36Sopenharmony_ci { 17662306a36Sopenharmony_ci /* VIC */ 17762306a36Sopenharmony_ci .base = 0x1af0, 17862306a36Sopenharmony_ci .offset = 0x30, 17962306a36Sopenharmony_ci .limit = 0x34 18062306a36Sopenharmony_ci }, 18162306a36Sopenharmony_ci { 18262306a36Sopenharmony_ci /* NVDEC */ 18362306a36Sopenharmony_ci .base = 0x1b00, 18462306a36Sopenharmony_ci .offset = 0x30, 18562306a36Sopenharmony_ci .limit = 0x34 18662306a36Sopenharmony_ci }, 18762306a36Sopenharmony_ci { 18862306a36Sopenharmony_ci /* NVDEC1 */ 18962306a36Sopenharmony_ci .base = 0x1bc0, 19062306a36Sopenharmony_ci .offset = 0x30, 19162306a36Sopenharmony_ci .limit = 0x34 19262306a36Sopenharmony_ci }, 19362306a36Sopenharmony_ci}; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic const struct host1x_info host1x07_info = { 19662306a36Sopenharmony_ci .nb_channels = 63, 19762306a36Sopenharmony_ci .nb_pts = 704, 19862306a36Sopenharmony_ci .nb_mlocks = 32, 19962306a36Sopenharmony_ci .nb_bases = 0, 20062306a36Sopenharmony_ci .init = host1x07_init, 20162306a36Sopenharmony_ci .sync_offset = 0x0, 20262306a36Sopenharmony_ci .dma_mask = DMA_BIT_MASK(40), 20362306a36Sopenharmony_ci .has_wide_gather = true, 20462306a36Sopenharmony_ci .has_hypervisor = true, 20562306a36Sopenharmony_ci .num_sid_entries = ARRAY_SIZE(tegra194_sid_table), 20662306a36Sopenharmony_ci .sid_table = tegra194_sid_table, 20762306a36Sopenharmony_ci .reserve_vblank_syncpts = false, 20862306a36Sopenharmony_ci}; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci/* 21162306a36Sopenharmony_ci * Tegra234 has two stream ID protection tables, one for setting stream IDs 21262306a36Sopenharmony_ci * through the channel path via SETSTREAMID, and one for setting them via 21362306a36Sopenharmony_ci * MMIO. We program each engine's data stream ID in the channel path table 21462306a36Sopenharmony_ci * and firmware stream ID in the MMIO path table. 21562306a36Sopenharmony_ci */ 21662306a36Sopenharmony_cistatic const struct host1x_sid_entry tegra234_sid_table[] = { 21762306a36Sopenharmony_ci { 21862306a36Sopenharmony_ci /* VIC channel */ 21962306a36Sopenharmony_ci .base = 0x17b8, 22062306a36Sopenharmony_ci .offset = 0x30, 22162306a36Sopenharmony_ci .limit = 0x30 22262306a36Sopenharmony_ci }, 22362306a36Sopenharmony_ci { 22462306a36Sopenharmony_ci /* VIC MMIO */ 22562306a36Sopenharmony_ci .base = 0x1688, 22662306a36Sopenharmony_ci .offset = 0x34, 22762306a36Sopenharmony_ci .limit = 0x34 22862306a36Sopenharmony_ci }, 22962306a36Sopenharmony_ci { 23062306a36Sopenharmony_ci /* NVDEC channel */ 23162306a36Sopenharmony_ci .base = 0x17c8, 23262306a36Sopenharmony_ci .offset = 0x30, 23362306a36Sopenharmony_ci .limit = 0x30, 23462306a36Sopenharmony_ci }, 23562306a36Sopenharmony_ci { 23662306a36Sopenharmony_ci /* NVDEC MMIO */ 23762306a36Sopenharmony_ci .base = 0x1698, 23862306a36Sopenharmony_ci .offset = 0x34, 23962306a36Sopenharmony_ci .limit = 0x34, 24062306a36Sopenharmony_ci }, 24162306a36Sopenharmony_ci}; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic const struct host1x_info host1x08_info = { 24462306a36Sopenharmony_ci .nb_channels = 63, 24562306a36Sopenharmony_ci .nb_pts = 1024, 24662306a36Sopenharmony_ci .nb_mlocks = 24, 24762306a36Sopenharmony_ci .nb_bases = 0, 24862306a36Sopenharmony_ci .init = host1x08_init, 24962306a36Sopenharmony_ci .sync_offset = 0x0, 25062306a36Sopenharmony_ci .dma_mask = DMA_BIT_MASK(40), 25162306a36Sopenharmony_ci .has_wide_gather = true, 25262306a36Sopenharmony_ci .has_hypervisor = true, 25362306a36Sopenharmony_ci .has_common = true, 25462306a36Sopenharmony_ci .num_sid_entries = ARRAY_SIZE(tegra234_sid_table), 25562306a36Sopenharmony_ci .sid_table = tegra234_sid_table, 25662306a36Sopenharmony_ci .streamid_vm_table = { 0x1004, 128 }, 25762306a36Sopenharmony_ci .classid_vm_table = { 0x1404, 25 }, 25862306a36Sopenharmony_ci .mmio_vm_table = { 0x1504, 25 }, 25962306a36Sopenharmony_ci .reserve_vblank_syncpts = false, 26062306a36Sopenharmony_ci}; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic const struct of_device_id host1x_of_match[] = { 26362306a36Sopenharmony_ci { .compatible = "nvidia,tegra234-host1x", .data = &host1x08_info, }, 26462306a36Sopenharmony_ci { .compatible = "nvidia,tegra194-host1x", .data = &host1x07_info, }, 26562306a36Sopenharmony_ci { .compatible = "nvidia,tegra186-host1x", .data = &host1x06_info, }, 26662306a36Sopenharmony_ci { .compatible = "nvidia,tegra210-host1x", .data = &host1x05_info, }, 26762306a36Sopenharmony_ci { .compatible = "nvidia,tegra124-host1x", .data = &host1x04_info, }, 26862306a36Sopenharmony_ci { .compatible = "nvidia,tegra114-host1x", .data = &host1x02_info, }, 26962306a36Sopenharmony_ci { .compatible = "nvidia,tegra30-host1x", .data = &host1x01_info, }, 27062306a36Sopenharmony_ci { .compatible = "nvidia,tegra20-host1x", .data = &host1x01_info, }, 27162306a36Sopenharmony_ci { }, 27262306a36Sopenharmony_ci}; 27362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, host1x_of_match); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic void host1x_setup_virtualization_tables(struct host1x *host) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci const struct host1x_info *info = host->info; 27862306a36Sopenharmony_ci unsigned int i; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (!info->has_hypervisor) 28162306a36Sopenharmony_ci return; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci for (i = 0; i < info->num_sid_entries; i++) { 28462306a36Sopenharmony_ci const struct host1x_sid_entry *entry = &info->sid_table[i]; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci host1x_hypervisor_writel(host, entry->offset, entry->base); 28762306a36Sopenharmony_ci host1x_hypervisor_writel(host, entry->limit, entry->base + 4); 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci for (i = 0; i < info->streamid_vm_table.count; i++) { 29162306a36Sopenharmony_ci /* Allow access to all stream IDs to all VMs. */ 29262306a36Sopenharmony_ci host1x_hypervisor_writel(host, 0xff, info->streamid_vm_table.base + 4 * i); 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci for (i = 0; i < info->classid_vm_table.count; i++) { 29662306a36Sopenharmony_ci /* Allow access to all classes to all VMs. */ 29762306a36Sopenharmony_ci host1x_hypervisor_writel(host, 0xff, info->classid_vm_table.base + 4 * i); 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci for (i = 0; i < info->mmio_vm_table.count; i++) { 30162306a36Sopenharmony_ci /* Use VM1 (that's us) as originator VMID for engine MMIO accesses. */ 30262306a36Sopenharmony_ci host1x_hypervisor_writel(host, 0x1, info->mmio_vm_table.base + 4 * i); 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic bool host1x_wants_iommu(struct host1x *host1x) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci /* Our IOMMU usage policy doesn't currently play well with GART */ 30962306a36Sopenharmony_ci if (of_machine_is_compatible("nvidia,tegra20")) 31062306a36Sopenharmony_ci return false; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* 31362306a36Sopenharmony_ci * If we support addressing a maximum of 32 bits of physical memory 31462306a36Sopenharmony_ci * and if the host1x firewall is enabled, there's no need to enable 31562306a36Sopenharmony_ci * IOMMU support. This can happen for example on Tegra20, Tegra30 31662306a36Sopenharmony_ci * and Tegra114. 31762306a36Sopenharmony_ci * 31862306a36Sopenharmony_ci * Tegra124 and later can address up to 34 bits of physical memory and 31962306a36Sopenharmony_ci * many platforms come equipped with more than 2 GiB of system memory, 32062306a36Sopenharmony_ci * which requires crossing the 4 GiB boundary. But there's a catch: on 32162306a36Sopenharmony_ci * SoCs before Tegra186 (i.e. Tegra124 and Tegra210), the host1x can 32262306a36Sopenharmony_ci * only address up to 32 bits of memory in GATHER opcodes, which means 32362306a36Sopenharmony_ci * that command buffers need to either be in the first 2 GiB of system 32462306a36Sopenharmony_ci * memory (which could quickly lead to memory exhaustion), or command 32562306a36Sopenharmony_ci * buffers need to be treated differently from other buffers (which is 32662306a36Sopenharmony_ci * not possible with the current ABI). 32762306a36Sopenharmony_ci * 32862306a36Sopenharmony_ci * A third option is to use the IOMMU in these cases to make sure all 32962306a36Sopenharmony_ci * buffers will be mapped into a 32-bit IOVA space that host1x can 33062306a36Sopenharmony_ci * address. This allows all of the system memory to be used and works 33162306a36Sopenharmony_ci * within the limitations of the host1x on these SoCs. 33262306a36Sopenharmony_ci * 33362306a36Sopenharmony_ci * In summary, default to enable IOMMU on Tegra124 and later. For any 33462306a36Sopenharmony_ci * of the earlier SoCs, only use the IOMMU for additional safety when 33562306a36Sopenharmony_ci * the host1x firewall is disabled. 33662306a36Sopenharmony_ci */ 33762306a36Sopenharmony_ci if (host1x->info->dma_mask <= DMA_BIT_MASK(32)) { 33862306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL)) 33962306a36Sopenharmony_ci return false; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci return true; 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic struct iommu_domain *host1x_iommu_attach(struct host1x *host) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci struct iommu_domain *domain = iommu_get_domain_for_dev(host->dev); 34862306a36Sopenharmony_ci int err; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) 35162306a36Sopenharmony_ci if (host->dev->archdata.mapping) { 35262306a36Sopenharmony_ci struct dma_iommu_mapping *mapping = 35362306a36Sopenharmony_ci to_dma_iommu_mapping(host->dev); 35462306a36Sopenharmony_ci arm_iommu_detach_device(host->dev); 35562306a36Sopenharmony_ci arm_iommu_release_mapping(mapping); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci domain = iommu_get_domain_for_dev(host->dev); 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci#endif 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* 36262306a36Sopenharmony_ci * We may not always want to enable IOMMU support (for example if the 36362306a36Sopenharmony_ci * host1x firewall is already enabled and we don't support addressing 36462306a36Sopenharmony_ci * more than 32 bits of physical memory), so check for that first. 36562306a36Sopenharmony_ci * 36662306a36Sopenharmony_ci * Similarly, if host1x is already attached to an IOMMU (via the DMA 36762306a36Sopenharmony_ci * API), don't try to attach again. 36862306a36Sopenharmony_ci */ 36962306a36Sopenharmony_ci if (!host1x_wants_iommu(host) || domain) 37062306a36Sopenharmony_ci return domain; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci host->group = iommu_group_get(host->dev); 37362306a36Sopenharmony_ci if (host->group) { 37462306a36Sopenharmony_ci struct iommu_domain_geometry *geometry; 37562306a36Sopenharmony_ci dma_addr_t start, end; 37662306a36Sopenharmony_ci unsigned long order; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci err = iova_cache_get(); 37962306a36Sopenharmony_ci if (err < 0) 38062306a36Sopenharmony_ci goto put_group; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci host->domain = iommu_domain_alloc(&platform_bus_type); 38362306a36Sopenharmony_ci if (!host->domain) { 38462306a36Sopenharmony_ci err = -ENOMEM; 38562306a36Sopenharmony_ci goto put_cache; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci err = iommu_attach_group(host->domain, host->group); 38962306a36Sopenharmony_ci if (err) { 39062306a36Sopenharmony_ci if (err == -ENODEV) 39162306a36Sopenharmony_ci err = 0; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci goto free_domain; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci geometry = &host->domain->geometry; 39762306a36Sopenharmony_ci start = geometry->aperture_start & host->info->dma_mask; 39862306a36Sopenharmony_ci end = geometry->aperture_end & host->info->dma_mask; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci order = __ffs(host->domain->pgsize_bitmap); 40162306a36Sopenharmony_ci init_iova_domain(&host->iova, 1UL << order, start >> order); 40262306a36Sopenharmony_ci host->iova_end = end; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci domain = host->domain; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci return domain; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cifree_domain: 41062306a36Sopenharmony_ci iommu_domain_free(host->domain); 41162306a36Sopenharmony_ci host->domain = NULL; 41262306a36Sopenharmony_ciput_cache: 41362306a36Sopenharmony_ci iova_cache_put(); 41462306a36Sopenharmony_ciput_group: 41562306a36Sopenharmony_ci iommu_group_put(host->group); 41662306a36Sopenharmony_ci host->group = NULL; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci return ERR_PTR(err); 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic int host1x_iommu_init(struct host1x *host) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci u64 mask = host->info->dma_mask; 42462306a36Sopenharmony_ci struct iommu_domain *domain; 42562306a36Sopenharmony_ci int err; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci domain = host1x_iommu_attach(host); 42862306a36Sopenharmony_ci if (IS_ERR(domain)) { 42962306a36Sopenharmony_ci err = PTR_ERR(domain); 43062306a36Sopenharmony_ci dev_err(host->dev, "failed to attach to IOMMU: %d\n", err); 43162306a36Sopenharmony_ci return err; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci /* 43562306a36Sopenharmony_ci * If we're not behind an IOMMU make sure we don't get push buffers 43662306a36Sopenharmony_ci * that are allocated outside of the range addressable by the GATHER 43762306a36Sopenharmony_ci * opcode. 43862306a36Sopenharmony_ci * 43962306a36Sopenharmony_ci * Newer generations of Tegra (Tegra186 and later) support a wide 44062306a36Sopenharmony_ci * variant of the GATHER opcode that allows addressing more bits. 44162306a36Sopenharmony_ci */ 44262306a36Sopenharmony_ci if (!domain && !host->info->has_wide_gather) 44362306a36Sopenharmony_ci mask = DMA_BIT_MASK(32); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci err = dma_coerce_mask_and_coherent(host->dev, mask); 44662306a36Sopenharmony_ci if (err < 0) { 44762306a36Sopenharmony_ci dev_err(host->dev, "failed to set DMA mask: %d\n", err); 44862306a36Sopenharmony_ci return err; 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci return 0; 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cistatic void host1x_iommu_exit(struct host1x *host) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci if (host->domain) { 45762306a36Sopenharmony_ci put_iova_domain(&host->iova); 45862306a36Sopenharmony_ci iommu_detach_group(host->domain, host->group); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci iommu_domain_free(host->domain); 46162306a36Sopenharmony_ci host->domain = NULL; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci iova_cache_put(); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci iommu_group_put(host->group); 46662306a36Sopenharmony_ci host->group = NULL; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic int host1x_get_resets(struct host1x *host) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci int err; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci host->resets[0].id = "mc"; 47562306a36Sopenharmony_ci host->resets[1].id = "host1x"; 47662306a36Sopenharmony_ci host->nresets = ARRAY_SIZE(host->resets); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci err = devm_reset_control_bulk_get_optional_exclusive_released( 47962306a36Sopenharmony_ci host->dev, host->nresets, host->resets); 48062306a36Sopenharmony_ci if (err) { 48162306a36Sopenharmony_ci dev_err(host->dev, "failed to get reset: %d\n", err); 48262306a36Sopenharmony_ci return err; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci return 0; 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic int host1x_probe(struct platform_device *pdev) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci struct host1x *host; 49162306a36Sopenharmony_ci int err; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); 49462306a36Sopenharmony_ci if (!host) 49562306a36Sopenharmony_ci return -ENOMEM; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci host->info = of_device_get_match_data(&pdev->dev); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (host->info->has_hypervisor) { 50062306a36Sopenharmony_ci host->regs = devm_platform_ioremap_resource_byname(pdev, "vm"); 50162306a36Sopenharmony_ci if (IS_ERR(host->regs)) 50262306a36Sopenharmony_ci return PTR_ERR(host->regs); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci host->hv_regs = devm_platform_ioremap_resource_byname(pdev, "hypervisor"); 50562306a36Sopenharmony_ci if (IS_ERR(host->hv_regs)) 50662306a36Sopenharmony_ci return PTR_ERR(host->hv_regs); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (host->info->has_common) { 50962306a36Sopenharmony_ci host->common_regs = devm_platform_ioremap_resource_byname(pdev, "common"); 51062306a36Sopenharmony_ci if (IS_ERR(host->common_regs)) 51162306a36Sopenharmony_ci return PTR_ERR(host->common_regs); 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci } else { 51462306a36Sopenharmony_ci host->regs = devm_platform_ioremap_resource(pdev, 0); 51562306a36Sopenharmony_ci if (IS_ERR(host->regs)) 51662306a36Sopenharmony_ci return PTR_ERR(host->regs); 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci host->syncpt_irq = platform_get_irq(pdev, 0); 52062306a36Sopenharmony_ci if (host->syncpt_irq < 0) 52162306a36Sopenharmony_ci return host->syncpt_irq; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci mutex_init(&host->devices_lock); 52462306a36Sopenharmony_ci INIT_LIST_HEAD(&host->devices); 52562306a36Sopenharmony_ci INIT_LIST_HEAD(&host->list); 52662306a36Sopenharmony_ci host->dev = &pdev->dev; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci /* set common host1x device data */ 52962306a36Sopenharmony_ci platform_set_drvdata(pdev, host); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci host->dev->dma_parms = &host->dma_parms; 53262306a36Sopenharmony_ci dma_set_max_seg_size(host->dev, UINT_MAX); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci if (host->info->init) { 53562306a36Sopenharmony_ci err = host->info->init(host); 53662306a36Sopenharmony_ci if (err) 53762306a36Sopenharmony_ci return err; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci host->clk = devm_clk_get(&pdev->dev, NULL); 54162306a36Sopenharmony_ci if (IS_ERR(host->clk)) { 54262306a36Sopenharmony_ci err = PTR_ERR(host->clk); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci if (err != -EPROBE_DEFER) 54562306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to get clock: %d\n", err); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci return err; 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci err = host1x_get_resets(host); 55162306a36Sopenharmony_ci if (err) 55262306a36Sopenharmony_ci return err; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci host1x_bo_cache_init(&host->cache); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci err = host1x_iommu_init(host); 55762306a36Sopenharmony_ci if (err < 0) { 55862306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to setup IOMMU: %d\n", err); 55962306a36Sopenharmony_ci goto destroy_cache; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci err = host1x_channel_list_init(&host->channel_list, 56362306a36Sopenharmony_ci host->info->nb_channels); 56462306a36Sopenharmony_ci if (err) { 56562306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to initialize channel list\n"); 56662306a36Sopenharmony_ci goto iommu_exit; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci err = host1x_memory_context_list_init(host); 57062306a36Sopenharmony_ci if (err) { 57162306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to initialize context list\n"); 57262306a36Sopenharmony_ci goto free_channels; 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci err = host1x_syncpt_init(host); 57662306a36Sopenharmony_ci if (err) { 57762306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to initialize syncpts\n"); 57862306a36Sopenharmony_ci goto free_contexts; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci err = host1x_intr_init(host); 58262306a36Sopenharmony_ci if (err) { 58362306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to initialize interrupts\n"); 58462306a36Sopenharmony_ci goto deinit_syncpt; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci pm_runtime_enable(&pdev->dev); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev); 59062306a36Sopenharmony_ci if (err) 59162306a36Sopenharmony_ci goto pm_disable; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci /* the driver's code isn't ready yet for the dynamic RPM */ 59462306a36Sopenharmony_ci err = pm_runtime_resume_and_get(&pdev->dev); 59562306a36Sopenharmony_ci if (err) 59662306a36Sopenharmony_ci goto pm_disable; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci host1x_debug_init(host); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci err = host1x_register(host); 60162306a36Sopenharmony_ci if (err < 0) 60262306a36Sopenharmony_ci goto deinit_debugfs; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci err = devm_of_platform_populate(&pdev->dev); 60562306a36Sopenharmony_ci if (err < 0) 60662306a36Sopenharmony_ci goto unregister; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci return 0; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ciunregister: 61162306a36Sopenharmony_ci host1x_unregister(host); 61262306a36Sopenharmony_cideinit_debugfs: 61362306a36Sopenharmony_ci host1x_debug_deinit(host); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci pm_runtime_put_sync_suspend(&pdev->dev); 61662306a36Sopenharmony_cipm_disable: 61762306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci host1x_intr_deinit(host); 62062306a36Sopenharmony_cideinit_syncpt: 62162306a36Sopenharmony_ci host1x_syncpt_deinit(host); 62262306a36Sopenharmony_cifree_contexts: 62362306a36Sopenharmony_ci host1x_memory_context_list_free(&host->context_list); 62462306a36Sopenharmony_cifree_channels: 62562306a36Sopenharmony_ci host1x_channel_list_free(&host->channel_list); 62662306a36Sopenharmony_ciiommu_exit: 62762306a36Sopenharmony_ci host1x_iommu_exit(host); 62862306a36Sopenharmony_cidestroy_cache: 62962306a36Sopenharmony_ci host1x_bo_cache_destroy(&host->cache); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci return err; 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_cistatic int host1x_remove(struct platform_device *pdev) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci struct host1x *host = platform_get_drvdata(pdev); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci host1x_unregister(host); 63962306a36Sopenharmony_ci host1x_debug_deinit(host); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci pm_runtime_force_suspend(&pdev->dev); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci host1x_intr_deinit(host); 64462306a36Sopenharmony_ci host1x_syncpt_deinit(host); 64562306a36Sopenharmony_ci host1x_memory_context_list_free(&host->context_list); 64662306a36Sopenharmony_ci host1x_channel_list_free(&host->channel_list); 64762306a36Sopenharmony_ci host1x_iommu_exit(host); 64862306a36Sopenharmony_ci host1x_bo_cache_destroy(&host->cache); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci return 0; 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic int __maybe_unused host1x_runtime_suspend(struct device *dev) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci struct host1x *host = dev_get_drvdata(dev); 65662306a36Sopenharmony_ci int err; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci host1x_intr_stop(host); 65962306a36Sopenharmony_ci host1x_syncpt_save(host); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci err = reset_control_bulk_assert(host->nresets, host->resets); 66262306a36Sopenharmony_ci if (err) { 66362306a36Sopenharmony_ci dev_err(dev, "failed to assert reset: %d\n", err); 66462306a36Sopenharmony_ci goto resume_host1x; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci usleep_range(1000, 2000); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci clk_disable_unprepare(host->clk); 67062306a36Sopenharmony_ci reset_control_bulk_release(host->nresets, host->resets); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci return 0; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ciresume_host1x: 67562306a36Sopenharmony_ci host1x_setup_virtualization_tables(host); 67662306a36Sopenharmony_ci host1x_syncpt_restore(host); 67762306a36Sopenharmony_ci host1x_intr_start(host); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci return err; 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic int __maybe_unused host1x_runtime_resume(struct device *dev) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci struct host1x *host = dev_get_drvdata(dev); 68562306a36Sopenharmony_ci int err; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci err = reset_control_bulk_acquire(host->nresets, host->resets); 68862306a36Sopenharmony_ci if (err) { 68962306a36Sopenharmony_ci dev_err(dev, "failed to acquire reset: %d\n", err); 69062306a36Sopenharmony_ci return err; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci err = clk_prepare_enable(host->clk); 69462306a36Sopenharmony_ci if (err) { 69562306a36Sopenharmony_ci dev_err(dev, "failed to enable clock: %d\n", err); 69662306a36Sopenharmony_ci goto release_reset; 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci err = reset_control_bulk_deassert(host->nresets, host->resets); 70062306a36Sopenharmony_ci if (err < 0) { 70162306a36Sopenharmony_ci dev_err(dev, "failed to deassert reset: %d\n", err); 70262306a36Sopenharmony_ci goto disable_clk; 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci host1x_setup_virtualization_tables(host); 70662306a36Sopenharmony_ci host1x_syncpt_restore(host); 70762306a36Sopenharmony_ci host1x_intr_start(host); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci return 0; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cidisable_clk: 71262306a36Sopenharmony_ci clk_disable_unprepare(host->clk); 71362306a36Sopenharmony_cirelease_reset: 71462306a36Sopenharmony_ci reset_control_bulk_release(host->nresets, host->resets); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci return err; 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_cistatic const struct dev_pm_ops host1x_pm_ops = { 72062306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(host1x_runtime_suspend, host1x_runtime_resume, 72162306a36Sopenharmony_ci NULL) 72262306a36Sopenharmony_ci /* TODO: add system suspend-resume once driver will be ready for that */ 72362306a36Sopenharmony_ci}; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_cistatic struct platform_driver tegra_host1x_driver = { 72662306a36Sopenharmony_ci .driver = { 72762306a36Sopenharmony_ci .name = "tegra-host1x", 72862306a36Sopenharmony_ci .of_match_table = host1x_of_match, 72962306a36Sopenharmony_ci .pm = &host1x_pm_ops, 73062306a36Sopenharmony_ci }, 73162306a36Sopenharmony_ci .probe = host1x_probe, 73262306a36Sopenharmony_ci .remove = host1x_remove, 73362306a36Sopenharmony_ci}; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_cistatic struct platform_driver * const drivers[] = { 73662306a36Sopenharmony_ci &tegra_host1x_driver, 73762306a36Sopenharmony_ci &tegra_mipi_driver, 73862306a36Sopenharmony_ci}; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cistatic int __init tegra_host1x_init(void) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci int err; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci err = bus_register(&host1x_bus_type); 74562306a36Sopenharmony_ci if (err < 0) 74662306a36Sopenharmony_ci return err; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci err = platform_register_drivers(drivers, ARRAY_SIZE(drivers)); 74962306a36Sopenharmony_ci if (err < 0) 75062306a36Sopenharmony_ci bus_unregister(&host1x_bus_type); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci return err; 75362306a36Sopenharmony_ci} 75462306a36Sopenharmony_cimodule_init(tegra_host1x_init); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_cistatic void __exit tegra_host1x_exit(void) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci platform_unregister_drivers(drivers, ARRAY_SIZE(drivers)); 75962306a36Sopenharmony_ci bus_unregister(&host1x_bus_type); 76062306a36Sopenharmony_ci} 76162306a36Sopenharmony_cimodule_exit(tegra_host1x_exit); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci/** 76462306a36Sopenharmony_ci * host1x_get_dma_mask() - query the supported DMA mask for host1x 76562306a36Sopenharmony_ci * @host1x: host1x instance 76662306a36Sopenharmony_ci * 76762306a36Sopenharmony_ci * Note that this returns the supported DMA mask for host1x, which can be 76862306a36Sopenharmony_ci * different from the applicable DMA mask under certain circumstances. 76962306a36Sopenharmony_ci */ 77062306a36Sopenharmony_ciu64 host1x_get_dma_mask(struct host1x *host1x) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci return host1x->info->dma_mask; 77362306a36Sopenharmony_ci} 77462306a36Sopenharmony_ciEXPORT_SYMBOL(host1x_get_dma_mask); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ciMODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); 77762306a36Sopenharmony_ciMODULE_AUTHOR("Terje Bergstrom <tbergstrom@nvidia.com>"); 77862306a36Sopenharmony_ciMODULE_DESCRIPTION("Host1x driver for Tegra products"); 77962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 780