239 lines
5.0 KiB
C
239 lines
5.0 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (c) 2020 MediaTek Inc.
|
|
*/
|
|
|
|
#include <linux/io.h>
|
|
#include <linux/delay.h>
|
|
#include <mt-plat/sync_write.h>
|
|
#include "adsp_platform.h"
|
|
#include "adsp_reg.h"
|
|
#include "adsp_reserved_mem.h"
|
|
#include "adsp_semaphore.h"
|
|
#include "adsp_platform_driver.h"
|
|
|
|
#ifdef ADSP_BASE
|
|
#undef ADSP_BASE
|
|
#endif
|
|
#define ADSP_BASE mt_base
|
|
#define INFRACFG_AO_BASE infracfg_ao
|
|
#define PERICFG_BASE pericfg
|
|
|
|
#define SET_BITS(addr, mask) writel(readl(addr) | (mask), addr)
|
|
#define CLR_BITS(addr, mask) writel(readl(addr) & ~(mask), addr)
|
|
|
|
#ifdef CONFIG_ARM64
|
|
#define IOMEM(a) ((void __force __iomem *)((a)))
|
|
#endif
|
|
#define adsp_reg_read(addr) __raw_readl(IOMEM(addr))
|
|
#define adsp_reg_sync_write(addr, val) mt_reg_sync_writel(val, addr)
|
|
|
|
#define MAGIC_PATTERN (0xfafafafa)
|
|
|
|
static void __iomem *mt_base;
|
|
|
|
static void __iomem *infracfg_ao;
|
|
static void __iomem *pericfg;
|
|
|
|
|
|
void adsp_mt_sw_reset(u32 cid)
|
|
{
|
|
unsigned long flags;
|
|
|
|
if (unlikely(cid >= ADSP_CORE_TOTAL))
|
|
return;
|
|
|
|
write_lock_irqsave(&access_rwlock, flags);
|
|
SET_BITS(ADSP_CFGREG_SW_RSTN, ADSP_A_SW_RSTN);
|
|
udelay(1);
|
|
CLR_BITS(ADSP_CFGREG_SW_RSTN, ADSP_A_SW_RSTN);
|
|
write_unlock_irqrestore(&access_rwlock, flags);
|
|
}
|
|
|
|
void adsp_mt_run(u32 cid)
|
|
{
|
|
int timeout = 1000;
|
|
|
|
if (unlikely(cid >= ADSP_CORE_TOTAL))
|
|
return;
|
|
|
|
/* request infra/26M/apsrc/v18/ ddr resource */
|
|
SET_BITS(ADSP_SPM_REQ, ADSP_SPM_SRC_BITS);
|
|
SET_BITS(ADSP_DDREN_REQ, ADSP_DDR_ENABLE);
|
|
|
|
/* make sure SPM return ack */
|
|
while (timeout) {
|
|
if (readl(ADSP_SPM_ACK) == ((ADSP_DDR_ENABLE << 4) | ADSP_SPM_SRC_BITS))
|
|
break;
|
|
udelay(10);
|
|
if (--timeout == 0) {
|
|
pr_err("[ADSP] timeout: cannot get SPM ack\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
CLR_BITS(ADSP_HIFI3_IO_CONFIG, ADSP_A_RUNSTALL);
|
|
}
|
|
|
|
void adsp_mt_stop(u32 cid)
|
|
{
|
|
if (unlikely(cid >= ADSP_CORE_TOTAL))
|
|
return;
|
|
SET_BITS(ADSP_HIFI3_IO_CONFIG, ADSP_A_RUNSTALL);
|
|
}
|
|
|
|
void adsp_mt_clear(void)
|
|
{
|
|
writel(0x0, ADSP_CFGREG_SW_RSTN);
|
|
writel(0xC0001002, ADSP_HIFI3_IO_CONFIG);
|
|
writel(0, ADSP_CREG_BOOTUP_MARK);
|
|
writel(0xdf, ADSP_CLK_CTRL_BASE);
|
|
writel(0x0, ADSP_IRQ_EN);
|
|
writel(0x0, ADSP_A_WDT_REG);
|
|
}
|
|
|
|
void adsp_mt_clr_spm(u32 cid)
|
|
{
|
|
if (unlikely(cid >= ADSP_CORE_TOTAL))
|
|
return;
|
|
|
|
CLR_BITS(ADSP_A_SPM_WAKEUPSRC, ADSP_WAKEUP_SPM);
|
|
}
|
|
|
|
void adsp_mt_clr_sysirq(u32 cid)
|
|
{
|
|
if (unlikely(cid >= ADSP_CORE_TOTAL))
|
|
return;
|
|
|
|
writel(ADSP_A_2HOST_IRQ_BIT, ADSP_GENERAL_IRQ_CLR);
|
|
}
|
|
|
|
bool is_adsp_genirq_idle(u32 cid)
|
|
{
|
|
if (unlikely(cid >= ADSP_CORE_TOTAL))
|
|
return false;
|
|
|
|
return ((readl(ADSP_GENERAL_IRQ_SET) & ADSP_GENERAL_IRQ_INUSED)
|
|
== ADSP_GENERAL_IRQ_INUSED);
|
|
}
|
|
|
|
void adsp_mt_disable_wdt(u32 cid)
|
|
{
|
|
if (unlikely(cid >= ADSP_CORE_TOTAL))
|
|
return;
|
|
|
|
CLR_BITS(ADSP_A_WDT_REG, WDT_EN_BIT);
|
|
}
|
|
|
|
bool check_hifi_status(u32 mask)
|
|
{
|
|
return (readl(ADSP_SLEEP_STATUS_REG) & mask);
|
|
}
|
|
|
|
bool is_adsp_axibus_idle(void)
|
|
{
|
|
/* no pending counter found when ap read this reg in mt6785 */
|
|
return (readl(ADSP_DBG_PEND_CNT) == 0x000000);
|
|
}
|
|
|
|
void adsp_mt_set_bootup_mark(u32 cid)
|
|
{
|
|
if (unlikely(cid >= ADSP_CORE_TOTAL))
|
|
return;
|
|
|
|
writel(MAGIC_PATTERN, ADSP_CREG_BOOTUP_MARK);
|
|
}
|
|
|
|
u32 switch_adsp_clk_ctrl_cg(bool en, u32 mask)
|
|
{
|
|
u32 retval = readl(ADSP_CLK_CTRL_BASE);
|
|
|
|
if (en)
|
|
SET_BITS(ADSP_CLK_CTRL_BASE, mask);
|
|
else
|
|
CLR_BITS(ADSP_CLK_CTRL_BASE, mask);
|
|
|
|
return retval;
|
|
}
|
|
|
|
u32 switch_adsp_uart_ctrl_cg(bool en, u32 mask)
|
|
{
|
|
u32 retval = readl(ADSP_UART_CTRL);
|
|
|
|
if (en)
|
|
SET_BITS(ADSP_UART_CTRL, mask);
|
|
else
|
|
CLR_BITS(ADSP_UART_CTRL, mask);
|
|
|
|
return retval;
|
|
}
|
|
|
|
void adsp_mt_clr_sw_reset(void)
|
|
{
|
|
CLR_BITS(ADSP_CFGREG_SW_RSTN, ADSP_A_SW_RSTN);
|
|
}
|
|
|
|
void adsp_mt_set_sw_int(u32 cid)
|
|
{
|
|
if (unlikely(cid >= ADSP_CORE_TOTAL))
|
|
return;
|
|
|
|
adsp_reg_sync_write(ADSP_SW_INT_SET, (1 << cid));
|
|
}
|
|
|
|
u32 adsp_mt_check_sw_int(u32 cid)
|
|
{
|
|
if (unlikely(cid >= ADSP_CORE_TOTAL))
|
|
return 0;
|
|
|
|
return (adsp_reg_read(ADSP_SW_INT_SET) & (1 << cid));
|
|
}
|
|
|
|
void adsp_platform_init(void)
|
|
{
|
|
if (unlikely(!adsp_cores[0]))
|
|
return;
|
|
mt_base = adsp_cores[0]->cfg;
|
|
infracfg_ao = adsp_common.infracfg_ao;
|
|
pericfg = adsp_common.pericfg;
|
|
|
|
adsp_init_reserve_memory();
|
|
adsp_sem_init(SEMA_WAY_BITS, SEMA_CTRL_BIT,
|
|
SEMA_TIMEOUT, ADSP_SEMAPHORE);
|
|
}
|
|
|
|
/* mt6785 only */
|
|
static bool is_adsp_bus_protect_ready(void)
|
|
{
|
|
return ((adsp_reg_read(INFRA_AXI_PROT_STA1) & ADSP_AXI_PROT_READY_MASK)
|
|
== ADSP_AXI_PROT_READY_MASK);
|
|
}
|
|
|
|
void adsp_bus_sleep_protect(uint32_t enable)
|
|
{
|
|
int timeout = 1000;
|
|
|
|
if (enable) {
|
|
/* enable adsp bus protect */
|
|
adsp_reg_sync_write(INFRA_AXI_PROT_SET, ADSP_AXI_PROT_MASK);
|
|
while (--timeout && !is_adsp_bus_protect_ready())
|
|
udelay(1);
|
|
if (!is_adsp_bus_protect_ready())
|
|
pr_err("%s() ready timeout\n", __func__);
|
|
} else {
|
|
/* disable adsp bus protect */
|
|
adsp_reg_sync_write(INFRA_AXI_PROT_CLR, ADSP_AXI_PROT_MASK);
|
|
}
|
|
}
|
|
|
|
void adsp_way_en_ctrl(uint32_t enable)
|
|
{
|
|
if (enable)
|
|
adsp_reg_sync_write(ADSP_WAY_EN_CTRL,
|
|
adsp_reg_read(ADSP_WAY_EN_CTRL) | ADSP_WAY_EN_MASK);
|
|
else
|
|
adsp_reg_sync_write(ADSP_WAY_EN_CTRL,
|
|
adsp_reg_read(ADSP_WAY_EN_CTRL) & ~ADSP_WAY_EN_MASK);
|
|
}
|
|
|