diff --git a/drivers/platform/tegra/nvadsp/amc.c b/drivers/platform/tegra/nvadsp/amc.c index 55ba22ea..86f26b9f 100644 --- a/drivers/platform/tegra/nvadsp/amc.c +++ b/drivers/platform/tegra/nvadsp/amc.c @@ -1,7 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** - * Copyright (c) 2014-2023, NVIDIA CORPORATION. All rights reserved. - */ +// SPDX-FileCopyrightText: Copyright (c) 2014-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. #include #include @@ -158,6 +156,9 @@ void nvadsp_free_amc_interrupts(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *node; + if (drv->chip_data->amc_not_avlbl) + return; + node = dev->of_node; if (!is_tegra_hypervisor_mode()) @@ -171,6 +172,9 @@ int nvadsp_setup_amc_interrupts(struct platform_device *pdev) struct device_node *node; int ret = 0; + if (drv->chip_data->amc_not_avlbl) + return ret; + node = dev->of_node; nvadsp_pdev = pdev; nvadsp_drv_data = drv; diff --git a/drivers/platform/tegra/nvadsp/dev.c b/drivers/platform/tegra/nvadsp/dev.c index 0726aabe..8f0df6a0 100644 --- a/drivers/platform/tegra/nvadsp/dev.c +++ b/drivers/platform/tegra/nvadsp/dev.c @@ -1,7 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** - * Copyright (c) 2014-2023, NVIDIA CORPORATION. All rights reserved. - */ +// SPDX-FileCopyrightText: Copyright (c) 2014-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. #include #include @@ -394,7 +392,7 @@ static int __init nvadsp_probe(struct platform_device *pdev) goto out; } - for (iter = 0; iter < APE_MAX_REG; iter++) { + for (iter = 0; iter < drv_data->chip_data->num_regs ; iter++) { res = platform_get_resource(pdev, IORESOURCE_MEM, iter); if (!res) { dev_err(dev, @@ -418,7 +416,7 @@ static int __init nvadsp_probe(struct platform_device *pdev) drv_data->base_regs_saved = drv_data->base_regs; - for (irq_iter = 0; irq_iter < NVADSP_VIRQ_MAX; irq_iter++) { + for (irq_iter = 0; irq_iter < drv_data->chip_data->num_irqs; irq_iter++) { irq_num = platform_get_irq(pdev, irq_iter); if (irq_num < 0) { dev_err(dev, "Failed to get irq number for index %d\n", @@ -495,14 +493,16 @@ out: static int nvadsp_remove(struct platform_device *pdev) { struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev); + uint32_t aram_size = drv_data->adsp_mem[ARAM_ALIAS_0_SIZE]; nvadsp_bw_unregister(drv_data); - nvadsp_aram_exit(); - - pm_runtime_disable(&pdev->dev); + if (aram_size) + nvadsp_aram_exit(); #ifdef CONFIG_PM + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) nvadsp_runtime_suspend(&pdev->dev); #endif @@ -537,6 +537,8 @@ static struct nvadsp_chipdata tegrat18x_adsp_chipdata = { #endif .amc_err_war = true, + .num_irqs = NVADSP_VIRQ_MAX, + .num_regs = APE_MAX_REG, }; static struct nvadsp_chipdata tegra239_adsp_chipdata = { @@ -568,6 +570,8 @@ static struct nvadsp_chipdata tegra239_adsp_chipdata = { /* Populate Chip ID Major Revision as well */ .chipid_ext = true, + .num_irqs = NVADSP_VIRQ_MAX, + .num_regs = APE_MAX_REG, }; static const struct of_device_id nvadsp_of_match[] = { diff --git a/drivers/platform/tegra/nvadsp/dev.h b/drivers/platform/tegra/nvadsp/dev.h index 345b834e..c1e08bc9 100644 --- a/drivers/platform/tegra/nvadsp/dev.h +++ b/drivers/platform/tegra/nvadsp/dev.h @@ -1,7 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/** - * Copyright (c) 2014-2024, NVIDIA CORPORATION. All rights reserved. - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2014-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. #ifndef __TEGRA_NVADSP_DEV_H #define __TEGRA_NVADSP_DEV_H @@ -32,6 +30,11 @@ enum { APE_MAX_REG }; +enum { + AO_MISC, + AON_HSP, + AON_MAX_REG, +}; /* * Note: These enums should be aligned to the adsp_mem node mentioned in the * device tree @@ -90,6 +93,7 @@ enum nvadsp_virqs { WDT_VIRQ, WFI_VIRQ, AMC_ERR_VIRQ, + NVAON_VIRQ_MAX = AMC_ERR_VIRQ, ACTMON_VIRQ, NVADSP_VIRQ_MAX, }; @@ -149,11 +153,14 @@ struct nvadsp_chipdata { int start_irq; int end_irq; + bool amc_not_avlbl; bool amc_err_war; bool chipid_ext; u32 adsp_prid; char *adsp_elf; + size_t num_irqs; + size_t num_regs; }; struct nvadsp_drv_data { @@ -191,6 +198,8 @@ struct nvadsp_drv_data { struct reset_control *ape_tke_rst; int (*set_boot_vec)(struct nvadsp_drv_data *drv_data); int (*set_boot_freqs)(struct nvadsp_drv_data *drv_data); + bool (*check_wfi_status)(struct nvadsp_drv_data *drv_data); + int (*map_hwmbox_interrupts)(struct nvadsp_drv_data *drv_data); struct nvadsp_pm_state state; bool adsp_os_running; diff --git a/drivers/platform/tegra/nvadsp/hwmailbox.c b/drivers/platform/tegra/nvadsp/hwmailbox.c index a217bce4..860c36dc 100644 --- a/drivers/platform/tegra/nvadsp/hwmailbox.c +++ b/drivers/platform/tegra/nvadsp/hwmailbox.c @@ -1,7 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** - * Copyright (c) 2014-2023, NVIDIA CORPORATION. All rights reserved. - */ +// SPDX-FileCopyrightText: Copyright (c) 2014-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. #include #include @@ -121,6 +119,7 @@ static status_t hwmboxq_enqueue(struct hwmbox_queue *queue, status_t nvadsp_hwmbox_send_data(uint16_t mid, uint32_t data, uint32_t flags) { spinlock_t *lock = &nvadsp_drv_data->hwmbox_send_queue.lock; + u32 empty_int_ie = nvadsp_drv_data->chip_data->hwmb.empty_int_ie; unsigned long lockflags; int ret = 0; @@ -140,6 +139,8 @@ status_t nvadsp_hwmbox_send_data(uint16_t mid, uint32_t data, uint32_t flags) hwmbox_last_msg = data; #endif hwmbox_writel(data, send_hwmbox()); + if (empty_int_ie) + hwmbox_writel(INT_ENABLE, send_hwmbox() + empty_int_ie); } else { pr_debug("nvadsp_mbox_send: enqueue data\n"); ret = hwmboxq_enqueue(&nvadsp_drv_data->hwmbox_send_queue, @@ -175,6 +176,7 @@ static irqreturn_t hwmbox_send_empty_int_handler(int irq, void *devid) { spinlock_t *lock = &nvadsp_drv_data->hwmbox_send_queue.lock; struct device *dev = &nvadsp_pdev->dev; + u32 empty_int_ie = nvadsp_drv_data->chip_data->hwmb.empty_int_ie; unsigned long lockflags; uint32_t data; int ret; @@ -214,6 +216,9 @@ static irqreturn_t hwmbox_send_empty_int_handler(int irq, void *devid) dev_dbg(dev, "Writing 0x%x to SEND_HWMBOX\n", data); } else { is_hwmbox_busy = false; + if (empty_int_ie) + hwmbox_writel(INT_DISABLE, + send_hwmbox() + empty_int_ie); } spin_unlock_irqrestore(lock, lockflags); @@ -281,6 +286,12 @@ int nvadsp_setup_hwmbox_interrupts(struct platform_device *pdev) int recv_virq, send_virq; int ret; + if (drv->map_hwmbox_interrupts) { + ret = drv->map_hwmbox_interrupts(drv); + if (ret) + goto err; + } + recv_virq = drv->agic_irqs[MBOX_RECV_VIRQ]; send_virq = drv->agic_irqs[MBOX_SEND_VIRQ]; @@ -290,12 +301,11 @@ int nvadsp_setup_hwmbox_interrupts(struct platform_device *pdev) goto err; if (empty_int_ie) - hwmbox_writel(0x0, send_hwmbox() + empty_int_ie); + hwmbox_writel(INT_DISABLE, + send_hwmbox() + empty_int_ie); ret = devm_request_irq(dev, send_virq, hwmbox_send_empty_int_handler, IRQF_TRIGGER_RISING, "hwmbox1_send_empty", pdev); - if (empty_int_ie) - hwmbox_writel(0x1, send_hwmbox() + empty_int_ie); if (ret) goto free_interrupts; diff --git a/drivers/platform/tegra/nvadsp/hwmailbox.h b/drivers/platform/tegra/nvadsp/hwmailbox.h index dc1122d7..c0322cc7 100644 --- a/drivers/platform/tegra/nvadsp/hwmailbox.h +++ b/drivers/platform/tegra/nvadsp/hwmailbox.h @@ -1,7 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/** - * Copyright (c) 2014-2023, NVIDIA CORPORATION. All rights reserved. - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2014-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. #ifndef __HWMAILBOX_H #define __HWMAILBOX_H @@ -80,6 +78,10 @@ /* Prepare empty mailbox value */ #define PREPARE_HWMBOX_EMPTY_MSG() (HWMBOX_TAG_INVALID | 0x0) +/* Enable and Disable macros for interrupt */ +#define INT_ENABLE 0x1 +#define INT_DISABLE 0x0 + /* * Queue size must be power of 2 as '&' op * is being used to manage circular queues diff --git a/drivers/platform/tegra/nvadsp/os.c b/drivers/platform/tegra/nvadsp/os.c index e6d7a40a..f5dc9865 100644 --- a/drivers/platform/tegra/nvadsp/os.c +++ b/drivers/platform/tegra/nvadsp/os.c @@ -2205,12 +2205,44 @@ end: } EXPORT_SYMBOL(nvadsp_os_start); +static bool nvadsp_check_wfi_status(struct nvadsp_drv_data *drv_data) +{ + int cnt = 0; + bool wfi_status = true; + u32 adsp_status; + + if (drv_data->check_wfi_status) + wfi_status = drv_data->check_wfi_status(drv_data); + else { + /* + * Check L2_IDLE and L2_CLKSTOPPED in ADSP_STATUS + * NOTE: Standby mode in ADSP L2CC Power Control + * register should be enabled for this + */ + do { + adsp_status = amisc_readl(drv_data, AMISC_ADSP_STATUS); + if ((adsp_status & AMISC_ADSP_L2_IDLE) && + (adsp_status & AMISC_ADSP_L2_CLKSTOPPED)) + break; + cnt++; + mdelay(1); + } while (cnt < 5); + + if (cnt >= 5) { + pr_err("ADSP L2C clock not halted: 0x%x\n", adsp_status); + wfi_status = false; + } + } + + return wfi_status; +} + static int __nvadsp_os_suspend(void) { struct device *dev = &priv.pdev->dev; struct nvadsp_drv_data *drv_data; - int ret, cnt = 0; - u32 adsp_status; + int ret; + bool status = false; drv_data = platform_get_drvdata(priv.pdev); @@ -2242,21 +2274,8 @@ static int __nvadsp_os_suspend(void) goto out; } - /* - * Check L2_IDLE and L2_CLKSTOPPED in ADSP_STATUS - * NOTE: Standby mode in ADSP L2CC Power Control - * register should be enabled for this - */ - do { - adsp_status = amisc_readl(drv_data, AMISC_ADSP_STATUS); - if ((adsp_status & AMISC_ADSP_L2_IDLE) && - (adsp_status & AMISC_ADSP_L2_CLKSTOPPED)) - break; - cnt++; - mdelay(1); - } while (cnt < 5); - if (cnt >= 5) { - dev_err(dev, "ADSP L2C clock not halted: 0x%x\n", adsp_status); + status = nvadsp_check_wfi_status(drv_data); + if (!status) { ret = -EDEADLK; goto out; } @@ -2655,7 +2674,7 @@ int __init nvadsp_os_probe(struct platform_device *pdev) #endif /* CONFIG_DEBUG_FS */ - devm_tegrafw_register(dev, "APE", TFW_DONT_CACHE, + devm_tegrafw_register(dev, NULL, TFW_DONT_CACHE, tegrafw_read_adsp, NULL); end: return ret;