nvadsp: ACAST settings from DT

ACAST settings are expected to be done by the driver in backdoor
boot. Provision is added to read the ACAST address ranges and
the SMMU stream ID from DT.

ACAST settings are done either for physical memory, or for SMMU
mapped memory, as per the backdoor boot configuration.

Also, call to ACAST init function is moved from runtime resume
to device probe.

Bug 200745795
Bug 200746669
Bug 200773359

Change-Id: Ia53820968ce4d48966c39d72b4c2106be99815fa
Signed-off-by: Viswanath L <viswanathl@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2644989
Reviewed-by: svc_kernel_abi <svc_kernel_abi@nvidia.com>
Reviewed-by: Mohan Kumar D <mkumard@nvidia.com>
Reviewed-by: Sharad Gupta <sharadg@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Viswanath L
2021-12-21 11:41:11 +05:30
committed by Laxman Dewangan
parent cadec46986
commit f5feadcb43
5 changed files with 150 additions and 49 deletions

View File

@@ -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 <linux/platform_device.h>
#include <linux/of.h>
#include <linux/io.h>
#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;
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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);