diff --git a/drivers/platform/tegra/nvadsp/acast.c b/drivers/platform/tegra/nvadsp/acast.c index 0fab3403..061cacfa 100644 --- a/drivers/platform/tegra/nvadsp/acast.c +++ b/drivers/platform/tegra/nvadsp/acast.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2017 NVIDIA CORPORATION. All rights reserved. + * Copyright (C) 2016-2021 NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -15,7 +15,9 @@ */ #include +#include #include +#include "dev.h" #include "dev-t18x.h" #define AST_CONTROL 0x000 @@ -35,44 +37,50 @@ #define AST_PHY_SID_IDX 0 #define AST_APE_SID_IDX 1 #define AST_NS (1 << 3) +#define AST_CARVEOUTID(ID) (ID << 5) #define AST_VMINDEX(IDX) (IDX << 15) +#define AST_PHSICAL(PHY) (PHY << 19) +#define AST_STREAMID(ID) (ID << 8) +#define AST_VMINDEX_ENABLE (1 << 0) #define AST_RGN_ENABLE (1 << 0) #define AST_RGN_OFFSET 0x20 struct acast_region { - u64 rgn; - u64 rgn_ctrl; + u32 rgn; + u32 rgn_ctrl; + u32 strmid_reg; + u32 strmid_ctrl; u64 slave; u64 size; u64 master; }; -#define ACAST_REGIONS 1 -#define ACAST_BASE 0x02994000 -#define ACAST_SIZE 0x1FFF +#define NUM_MAX_ACAST 2 -#define ACAST_GLOBAL_CTRL_VAL 0x07b80009 -#define ACAST_STREAMID_CTL_0_VAL 0x00007f01 -#define ACAST_STREAMID_CTL_1_VAL 0x00001e01 +#define ACAST_RGN_PHY 0x0 +#define ACAST_RGN_CTL_PHY (AST_PHSICAL(1) | AST_CARVEOUTID(0x7)) -static struct acast_region acast_regions[ACAST_REGIONS] = { - { - 0x2, - 0x00008008, - 0x40000000, - 0x20000000, - 0x40000000, - }, -}; +#define ACAST_RGN_VM 0x2 +#define ACAST_VMINDEX 1 +#define ACAST_RGN_CTL_VM(IDX) AST_VMINDEX(IDX) +#define ACAST_SID_REG_EVAL(IDX) AST_STREAMID_CTL_##IDX +#define ACAST_STRMID_REG(IDX) ACAST_SID_REG_EVAL(IDX) -static void __iomem *acast_base; +#if KERNEL_VERSION(4, 14, 0) > LINUX_VERSION_CODE +/* Older kernels do not have this function, so stubbing it */ +static inline int of_property_read_u64_index(const struct device_node *np, + const char *propname, u32 index, u64 *out_value) +{ + return -ENOSYS; +} +#endif static inline void acast_write(void __iomem *acast, u32 reg, u32 val) { writel(val, acast + reg); } -static inline u32 __maybe_unused acast_read(void __iomem *acast, u32 reg) +static inline u32 acast_read(void __iomem *acast, u32 reg) { return readl(acast + reg); } @@ -82,18 +90,12 @@ static inline u32 acast_rgn_reg(u32 rgn, u32 reg) return rgn * AST_RGN_OFFSET + reg; } -static void tegra18x_acast_map(void __iomem *acast, u64 rgn, u64 rgn_ctrl, +static void tegra18x_acast_map(void __iomem *acast, u32 rgn, u32 rgn_ctrl, + u32 strmid_reg, u32 strmid_ctrl, u64 slave, u64 size, u64 master) { u32 val; - val = (slave & AST_LO_MASK) | AST_RGN_ENABLE; - acast_write(acast, - acast_rgn_reg(rgn, AST_RGN_SLAVE_BASE_LO), val); - val = slave >> AST_LO_SHIFT; - acast_write(acast, - acast_rgn_reg(rgn, AST_RGN_SLAVE_BASE_HI), val); - val = master & AST_LO_MASK; acast_write(acast, acast_rgn_reg(rgn, AST_RGN_MASTER_BASE_LO), val); @@ -108,33 +110,51 @@ static void tegra18x_acast_map(void __iomem *acast, u64 rgn, u64 rgn_ctrl, acast_write(acast, acast_rgn_reg(rgn, AST_RGN_MASK_BASE_HI), val); + val = acast_read(acast, acast_rgn_reg(rgn, AST_RGN_CONTOL)); + val |= rgn_ctrl; acast_write(acast, - acast_rgn_reg(rgn, AST_RGN_CONTOL), rgn_ctrl); + acast_rgn_reg(rgn, AST_RGN_CONTOL), val); + + if (strmid_reg) + acast_write(acast, strmid_reg, strmid_ctrl); + + val = slave >> AST_LO_SHIFT; + acast_write(acast, + acast_rgn_reg(rgn, AST_RGN_SLAVE_BASE_HI), val); + val = (slave & AST_LO_MASK) | AST_RGN_ENABLE; + acast_write(acast, + acast_rgn_reg(rgn, AST_RGN_SLAVE_BASE_LO), val); } -int nvadsp_acast_init(struct platform_device *pdev) +static int tegra18x_acast_init(struct platform_device *pdev, + uint32_t acast_addr, uint32_t acast_size, + struct acast_region *acast_regions, uint32_t num_regions) { struct device *dev = &pdev->dev; + void __iomem *acast_base; int i; - if (!acast_base) { - acast_base = devm_ioremap(dev, ACAST_BASE, ACAST_SIZE); - if (IS_ERR_OR_NULL(acast_base)) { - dev_err(dev, "failed to map ACAST\n"); - return PTR_ERR(acast_base); - } + acast_base = devm_ioremap(dev, acast_addr, acast_size); + if (IS_ERR_OR_NULL(acast_base)) { + dev_err(dev, "failed to map ACAST 0x%x\n", acast_addr); + return PTR_ERR(acast_base); } - for (i = 0; i < ACAST_REGIONS; i++) { + for (i = 0; i < num_regions; i++) { tegra18x_acast_map(acast_base, acast_regions[i].rgn, acast_regions[i].rgn_ctrl, + acast_regions[i].strmid_reg, + acast_regions[i].strmid_ctrl, acast_regions[i].slave, acast_regions[i].size, acast_regions[i].master); - dev_dbg(dev, "i:%d rgn:0x%llx rgn_ctrl:0x%llx ", + dev_dbg(dev, "i:%d rgn:0x%x rgn_ctrl:0x%x ", i, acast_regions[i].rgn, acast_regions[i].rgn_ctrl); + dev_dbg(dev, "strmid_reg:0x%x strmid_ctrl:0x%x ", + acast_regions[i].strmid_reg, + acast_regions[i].strmid_ctrl); dev_dbg(dev, "slave:0x%llx size:0x%llx master:0x%llx\n", acast_regions[i].slave, acast_regions[i].size, acast_regions[i].master); @@ -142,3 +162,73 @@ int nvadsp_acast_init(struct platform_device *pdev) return 0; } + +int nvadsp_acast_t18x_init(struct platform_device *pdev) +{ + struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + struct resource *co_mem = &drv_data->co_mem; + uint32_t acast_addr, acast_size; + int iter, num_acast = 0, ret = 0; + struct acast_region acast_config; + + if (co_mem->start) { + acast_config.rgn = ACAST_RGN_PHY; + acast_config.rgn_ctrl = ACAST_RGN_CTL_PHY; + acast_config.strmid_reg = 0; + acast_config.strmid_ctrl = 0; + acast_config.slave = drv_data->adsp_mem[ADSP_OS_ADDR]; + acast_config.size = drv_data->adsp_mem[ADSP_OS_SIZE]; + acast_config.master = co_mem->start; + } else { + uint32_t stream_id; + uint64_t iommu_addr_start, iommu_addr_end; + + if (of_property_read_u32_index(dev->of_node, + "iommus", 1, &stream_id)) { + dev_warn(dev, "no SMMU stream ID found\n"); + goto exit; + } + if (of_property_read_u64_index(dev->of_node, + "iommu-resv-regions", 1, &iommu_addr_start)) { + dev_warn(dev, "no IOMMU reserved region\n"); + goto exit; + } + if (of_property_read_u64_index(dev->of_node, + "iommu-resv-regions", 2, &iommu_addr_end)) { + dev_warn(dev, "no IOMMU reserved region\n"); + goto exit; + } + + acast_config.rgn = ACAST_RGN_VM; + acast_config.rgn_ctrl = ACAST_RGN_CTL_VM(ACAST_VMINDEX); + acast_config.strmid_reg = ACAST_STRMID_REG(ACAST_VMINDEX); + acast_config.strmid_ctrl = AST_STREAMID(stream_id) | + AST_VMINDEX_ENABLE; + acast_config.slave = iommu_addr_start; + acast_config.size = (iommu_addr_end - acast_config.slave); + acast_config.master = iommu_addr_start; + } + + for (iter = 0; iter < (NUM_MAX_ACAST * 2); iter += 2) { + if (of_property_read_u32_index(dev->of_node, + "nvidia,acast_config", iter, &acast_addr)) + continue; + if (of_property_read_u32_index(dev->of_node, + "nvidia,acast_config", (iter + 1), &acast_size)) + continue; + + ret = tegra18x_acast_init(pdev, acast_addr, acast_size, + &acast_config, 1); + if (ret) + goto exit; + + num_acast++; + } + + if (num_acast == 0) + dev_warn(dev, "no ACAST configurations found\n"); + +exit: + return ret; +} diff --git a/drivers/platform/tegra/nvadsp/dev-t18x.c b/drivers/platform/tegra/nvadsp/dev-t18x.c index e6e40b4a..2e70ebd0 100644 --- a/drivers/platform/tegra/nvadsp/dev-t18x.c +++ b/drivers/platform/tegra/nvadsp/dev-t18x.c @@ -118,7 +118,6 @@ static int nvadsp_t18x_clocks_enable(struct platform_device *pdev) static int __nvadsp_t18x_runtime_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); - struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev); int ret; dev_dbg(dev, "at %s:%d\n", __func__, __LINE__); @@ -129,14 +128,6 @@ static int __nvadsp_t18x_runtime_resume(struct device *dev) return ret; } - if (!drv_data->adsp_os_secload) { - ret = nvadsp_acast_init(pdev); - if (ret) { - dev_err(dev, "failed in nvadsp_acast_init\n"); - return ret; - } - } - return ret; } diff --git a/drivers/platform/tegra/nvadsp/dev-t18x.h b/drivers/platform/tegra/nvadsp/dev-t18x.h index b4b216de..fe0dd8fb 100644 --- a/drivers/platform/tegra/nvadsp/dev-t18x.h +++ b/drivers/platform/tegra/nvadsp/dev-t18x.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2017, NVIDIA Corporation. All rights reserved. + * Copyright (C) 2015-2021, NVIDIA Corporation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -15,7 +15,7 @@ #ifndef __TEGRA_NVADSP_DEV_T18X_H #define __TEGRA_NVADSP_DEV_T18X_H -int nvadsp_acast_init(struct platform_device *pdev); +int nvadsp_acast_t18x_init(struct platform_device *pdev); int nvadsp_reset_t18x_init(struct platform_device *pdev); int nvadsp_os_t18x_init(struct platform_device *pdev); int nvadsp_pm_t18x_init(struct platform_device *pdev); diff --git a/drivers/platform/tegra/nvadsp/dev.c b/drivers/platform/tegra/nvadsp/dev.c index 3d050b2d..667f8e3e 100644 --- a/drivers/platform/tegra/nvadsp/dev.c +++ b/drivers/platform/tegra/nvadsp/dev.c @@ -483,6 +483,13 @@ static int __init nvadsp_probe(struct platform_device *pdev) dev_err(dev, "Failed to init aram\n"); nvadsp_bw_register(drv_data); + + if (!drv_data->adsp_os_secload) { + ret = nvadsp_acast_init(pdev); + if (ret) + goto err; + } + err: #ifdef CONFIG_PM ret = pm_runtime_put_sync(dev); @@ -556,6 +563,7 @@ static struct nvadsp_chipdata tegrat18x_adsp_chipdata = { .adsp_thread_hwmbox = 0x20000, /* HWMBOX4 */ .adsp_state_hwmbox = 0x30000, /* HWMBOX6 */ .adsp_irq_hwmbox = 0x38000, /* HWMBOX7 */ + .acast_init = nvadsp_acast_t18x_init, .reset_init = nvadsp_reset_t18x_init, .os_init = nvadsp_os_t18x_init, #ifdef CONFIG_PM diff --git a/drivers/platform/tegra/nvadsp/dev.h b/drivers/platform/tegra/nvadsp/dev.h index 1e91746c..8fc8aee9 100644 --- a/drivers/platform/tegra/nvadsp/dev.h +++ b/drivers/platform/tegra/nvadsp/dev.h @@ -135,6 +135,7 @@ struct nvadsp_hwmb { }; +typedef int (*acast_init) (struct platform_device *pdev); typedef int (*reset_init) (struct platform_device *pdev); typedef int (*os_init) (struct platform_device *pdev); #ifdef CONFIG_PM @@ -147,6 +148,7 @@ struct nvadsp_chipdata { u32 adsp_thread_hwmbox; u32 adsp_irq_hwmbox; u32 adsp_shared_mem_hwmbox; + acast_init acast_init; reset_init reset_init; os_init os_init; #ifdef CONFIG_PM @@ -305,6 +307,16 @@ static inline int __init nvadsp_reset_init(struct platform_device *pdev) return -EINVAL; } +static inline int __init nvadsp_acast_init(struct platform_device *pdev) +{ + struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev); + + if (drv_data->chip_data->acast_init) + return drv_data->chip_data->acast_init(pdev); + + return 0; +} + #ifdef CONFIG_TEGRA_ADSP_LPTHREAD int adsp_lpthread_init(bool is_adsp_suspended); int adsp_lpthread_resume(void);