diff --git a/plat/mediatek/mt8195/aarch64/platform_common.c b/plat/mediatek/mt8195/aarch64/platform_common.c index 479274699..2b95171dd 100644 --- a/plat/mediatek/mt8195/aarch64/platform_common.c +++ b/plat/mediatek/mt8195/aarch64/platform_common.c @@ -21,6 +21,14 @@ const mmap_region_t plat_mmap[] = { MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(eDP_SEC_BASE, eDP_SEC_SIZE, MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(APUSYS_SCTRL_REVISER_BASE, APUSYS_SCTRL_REVISER_SIZE, + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(APUSYS_APU_S_S_4_BASE, APUSYS_APU_S_S_4_SIZE, + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(APUSYS_APU_PLL_BASE, APUSYS_APU_PLL_SIZE, + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(APUSYS_APU_ACC_BASE, APUSYS_APU_ACC_SIZE, + MT_DEVICE | MT_RW | MT_SECURE), { 0 } }; diff --git a/plat/mediatek/mt8195/drivers/apusys/apupll.c b/plat/mediatek/mt8195/drivers/apusys/apupll.c new file mode 100644 index 000000000..0eb8d4a5c --- /dev/null +++ b/plat/mediatek/mt8195/drivers/apusys/apupll.c @@ -0,0 +1,581 @@ +/* + * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +uint32_t mixed_con0_addr[APUPLL_MAX] = { + APU_PLL4H_PLL1_CON0, + APU_PLL4H_PLL2_CON0, + APU_PLL4H_PLL3_CON0, + APU_PLL4H_PLL4_CON0, +}; + +uint32_t mixed_con1_addr[APUPLL_MAX] = { + APU_PLL4H_PLL1_CON1, + APU_PLL4H_PLL2_CON1, + APU_PLL4H_PLL3_CON1, + APU_PLL4H_PLL4_CON1, +}; + +uint32_t mixed_con3_addr[APUPLL_MAX] = { + APU_PLL4H_PLL1_CON3, + APU_PLL4H_PLL2_CON3, + APU_PLL4H_PLL3_CON3, + APU_PLL4H_PLL4_CON3, +}; + +uint32_t fhctl_dds_addr[APUPLL_MAX] = { + APU_PLL4H_FHCTL0_DDS, + APU_PLL4H_FHCTL1_DDS, + APU_PLL4H_FHCTL2_DDS, + APU_PLL4H_FHCTL3_DDS, +}; + +uint32_t fhctl_dvfs_addr[APUPLL_MAX] = { + APU_PLL4H_FHCTL0_DVFS, + APU_PLL4H_FHCTL1_DVFS, + APU_PLL4H_FHCTL2_DVFS, + APU_PLL4H_FHCTL3_DVFS, +}; + +uint32_t fhctl_mon_addr[APUPLL_MAX] = { + APU_PLL4H_FHCTL0_MON, + APU_PLL4H_FHCTL1_MON, + APU_PLL4H_FHCTL2_MON, + APU_PLL4H_FHCTL3_MON, +}; + +uint32_t fhctl_cfg_addr[APUPLL_MAX] = { + APU_PLL4H_FHCTL0_CFG, + APU_PLL4H_FHCTL1_CFG, + APU_PLL4H_FHCTL2_CFG, + APU_PLL4H_FHCTL3_CFG, +}; + +static spinlock_t apupll_lock; +static spinlock_t npupll_lock; +static spinlock_t apupll_1_lock; +static spinlock_t apupll_2_lock; +static uint32_t pll_cnt[APUPLL_MAX]; +/** + * vd2pllidx() - voltage domain to pll idx. + * @domain: the voltage domain for getting pll index. + * + * Caller will get correspond pll index by different voltage domain. + * pll_idx[0] --> APUPLL (MDLA0/1) + * pll_idx[1] --> NPUPLL (VPU0/1) + * pll_idx[2] --> APUPLL1(CONN) + * pll_idx[3] --> APUPLL2(IOMMU) + * The longer description may have multiple paragraphs. + * + * Context: Any context. + * Return: + * * 0 ~ 3 - return the corresponding pll index + * * -EEXIST - cannot find pll idex of the specific voltage domain + * + */ +static int32_t vd2pllidx(enum dvfs_voltage_domain domain) +{ + int32_t ret; + + switch (domain) { + case V_VPU0: + case V_VPU1: + ret = NPUPLL; + break; + case V_MDLA0: + case V_MDLA1: + ret = APUPLL; + break; + case V_TOP_IOMMU: + ret = APUPLL2; + break; + case V_APU_CONN: + ret = APUPLL1; + break; + default: + ERROR("%s wrong voltage domain: %d\n", __func__, domain); + ret = -EEXIST; /* non-exist */ + break; + } + + return ret; +} + +/** + * pllidx2name() - return names of specific pll index. + * @pll_idx: input for specific pll index. + * + * Given pll index, this function will return name of it. + * + * Context: Any context. + * Return: Names of pll_idx, if found, otherwise will return "NULL" + */ +static const char *pllidx2name(int32_t pll_idx) +{ + static const char *const names[] = { + [APUPLL] = "PLL4H_PLL1", + [NPUPLL] = "PLL4H_PLL2", + [APUPLL1] = "PLL4H_PLL3", + [APUPLL2] = "PLL4H_PLL4", + [APUPLL_MAX] = "NULL", + }; + + if (pll_idx >= APUPLL_MAX) { + pll_idx = APUPLL_MAX; + } + + return names[pll_idx]; +} + +/** + * _fhctl_mon_done() - poll whether fhctl HW mode is done. + * @pll_idx: input for specific pll index. + * @tar_dds: target dds for fhctl_mon to be. + * + * Given pll index, this function will continue to poll whether fhctl_mon + * has reached the expected value within 80us. + * + * Context: Any context. + * Return: + * * 0 - OK for fhctl_mon == tar_dds + * * -ETIMEDOUT - fhctl_mon not reach tar_dds + */ +static int32_t _fhctl_mon_done(uint32_t pll_idx, unsigned long tar_dds) +{ + unsigned long mon_dds; + uint64_t timeout = timeout_init_us(PLL_READY_TIME_20US); + int32_t ret = 0; + + tar_dds &= DDS_MASK; + do { + mon_dds = apupwr_readl(fhctl_mon_addr[pll_idx]) & DDS_MASK; + if (mon_dds == tar_dds) { + break; + } + + if (timeout_elapsed(timeout)) { + ERROR("%s monitor DDS 0x%08lx != expect 0x%08lx\n", + pllidx2name(pll_idx), mon_dds, tar_dds); + ret = -ETIMEDOUT; + break; + } + } while (mon_dds != tar_dds); + + return ret; +} + +/** + * _pll_get_postdiv_reg() - return current post dividor of pll_idx + * @pll_idx: input for specific pll index. + * + * Given pll index, this function will return its current post dividor. + * + * Context: Any context. + * Return: post dividor of current pll_idx. + * + */ +static uint32_t _pll_get_postdiv_reg(uint32_t pll_idx) +{ + int32_t pll_postdiv_reg = 0; + uint32_t val; + + val = apupwr_readl(mixed_con1_addr[pll_idx]); + pll_postdiv_reg = (val >> POSDIV_SHIFT) & POSDIV_MASK; + return pll_postdiv_reg; +} + +/** + * _set_postdiv_reg() - set pll_idx's post dividor. + * @pll_idx: Which PLL to enable/disable + * @post_div: the register value of post dividor to be wrtten. + * + * Below are lists of post dividor register value and its meaning: + * [31] APUPLL_SDM_PCW_CHG + * [26:24] APUPLL_POSDIV + * [21:0] APUPLL_SDM_PCW (8bit integer + 14bit fraction) + * expected freq range ----- divider-------post divider in reg: + * >1500M (1500/ 1) -> 1 -> 0(2 to the zero power) + * > 750M (1500/ 2) -> 2 -> 1(2 to the 1st power) + * > 375M (1500/ 4) -> 4 -> 2(2 to the 2nd power) + * > 187.5M (1500/ 8) -> 8 -> 3(2 to the 3rd power) + * > 93.75M (1500/16) -> 16 -> 4(2 to the 4th power) + * + * Context: Any context. + */ +static void _set_postdiv_reg(uint32_t pll_idx, uint32_t post_div) +{ + apupwr_clrbits(POSDIV_MASK << POSDIV_SHIFT, mixed_con1_addr[pll_idx]); + apupwr_setbits((post_div & POSDIV_MASK) << POSDIV_SHIFT, + mixed_con1_addr[pll_idx]); +} + +/** + * _cal_pll_data() - input freq, calculate correspond post dividor and dds. + * @pd: address of output post dividor. + * @dds: address of output dds. + * @freq: input frequency. + * + * Given freq, this function will calculate correspond post dividor and dds. + * + * Context: Any context. + * Return: + * * 0 - done for calculating post dividor and dds. + */ +static int32_t _cal_pll_data(uint32_t *pd, uint32_t *dds, uint32_t freq) +{ + uint32_t vco, postdiv_val = 1, postdiv_reg = 0; + uint32_t pcw_val; + + vco = freq; + postdiv_val = 1; + postdiv_reg = 0; + while (vco <= FREQ_VCO_MIN) { + postdiv_val = postdiv_val << 1; + postdiv_reg = postdiv_reg + 1; + vco = vco << 1; + } + + pcw_val = vco * (1 << PCW_FRACTIONAL_SHIFT); + pcw_val = pcw_val / FREQ_FIN; + + if (postdiv_reg == 0) { /* Fvco * 2 with post_divider = 2 */ + pcw_val = pcw_val * 2; + postdiv_val = postdiv_val << 1; + postdiv_reg = postdiv_reg + 1; + } /* Post divider is 1 is not available */ + *pd = postdiv_reg; + *dds = pcw_val | RG_PLL_SDM_PCW_CHG; + + return 0; +} + +/** + * _pll_en() - enable/disable RG_PLL_EN of CON1 for pll[pll_idx] + * @pll_idx: Which PLL to enable/disable + * @on: 1 -> enable, 0 -> disable. + * + * This funciton will only change RG_PLL_EN of CON1 for pll[pll_idx]. + * + * Context: Any context. + */ +static void _pll_en(uint32_t pll_idx, bool on) +{ + if (on) { + apupwr_setbits(RG_PLL_EN, mixed_con0_addr[pll_idx]); + } else { + apupwr_clrbits(RG_PLL_EN, mixed_con0_addr[pll_idx]); + } +} + +/** + * _pll_pwr() - enable/disable PLL_SDM_PWR_ON of CON3 for pll[pll_idx] + * @pll_idx: Which PLL to enable/disable + * @on: 1 -> enable, 0 -> disable. + * + * This funciton will only change PLL_SDM_PWR_ON of CON3 for pll[pll_idx]. + * + * Context: Any context. + */ +static void _pll_pwr(uint32_t pll_idx, bool on) +{ + if (on) { + apupwr_setbits(DA_PLL_SDM_PWR_ON, mixed_con3_addr[pll_idx]); + } else { + apupwr_clrbits(DA_PLL_SDM_PWR_ON, mixed_con3_addr[pll_idx]); + } +} + +/** + * _pll_iso() - enable/disable PLL_SDM_ISO_EN of CON3 for pll[pll_idx] + * @pll_idx: Which PLL to enable/disable + * @enable: 1 -> turn on isolation, 0 -> turn off isolation. + * + * This funciton will turn on/off pll isolation by + * changing PLL_SDM_PWR_ON of CON3 for pll[pll_idx]. + * + * Context: Any context. + */ +static void _pll_iso(uint32_t pll_idx, bool enable) +{ + if (enable) { + apupwr_setbits(DA_PLL_SDM_ISO_EN, mixed_con3_addr[pll_idx]); + } else { + apupwr_clrbits(DA_PLL_SDM_ISO_EN, mixed_con3_addr[pll_idx]); + } +} + +/** + * _pll_switch() - entry point to turn whole PLL on/off + * @pll_idx: Which PLL to enable/disable + * @on: 1 -> enable, 0 -> disable. + * @fhctl_en: enable or disable fhctl function + * + * This is the entry poing for controlling pll and fhctl funciton on/off. + * Caller can chose only enable pll instead of fhctl function. + * + * Context: Any context. + * Return: + * * 0 - done for enable pll or fhctl as well. + */ +static int32_t _pll_switch(uint32_t pll_idx, bool on, bool fhctl_en) +{ + int32_t ret = 0; + + if (pll_idx >= APUPLL_MAX) { + ERROR("%s wrong pll_idx: %d\n", __func__, pll_idx); + ret = -EINVAL; + goto err; + } + + if (on) { + _pll_pwr(pll_idx, true); + udelay(PLL_CMD_READY_TIME_1US); + _pll_iso(pll_idx, false); + udelay(PLL_CMD_READY_TIME_1US); + _pll_en(pll_idx, true); + udelay(PLL_READY_TIME_20US); + } else { + _pll_en(pll_idx, false); + _pll_iso(pll_idx, true); + _pll_pwr(pll_idx, false); + } + +err: + return ret; +} + +/** + * apu_pll_enable() - API for smc function to enable/disable pll + * @pll_idx: Which pll to enable/disable. + * @enable: 1 -> enable, 0 -> disable. + * @fhctl_en: enable or disable fhctl function + * + * pll_idx[0] --> APUPLL (MDLA0/1) + * pll_idx[1] --> NPUPLL (VPU0/1) + * pll_idx[2] --> APUPLL1(CONN) + * pll_idx[3] --> APUPLL2(IOMMU) + * The differences between _pll_switch are: + * 1. Atomic update pll reference cnt to protect double enable pll & + * close pll during user is not zero. + * + * Context: Any context. + * Return: + * * 0 - done for enable pll or fhctl as well. + */ +int32_t apu_pll_enable(int32_t pll_idx, bool enable, bool fhctl_en) +{ + int32_t ret = 0; + + if (pll_idx >= APUPLL_MAX) { + ERROR("%s wrong pll_idx: %d\n", __func__, pll_idx); + ret = -EINVAL; + goto err; + } + + if (enable) { + switch (pll_idx) { + case APUPLL: + spin_lock(&apupll_lock); + if (pll_cnt[APUPLL] == 0) { + _pll_switch(pll_idx, enable, fhctl_en); + } + pll_cnt[APUPLL]++; + spin_unlock(&apupll_lock); + break; + case NPUPLL: + spin_lock(&npupll_lock); + if (pll_cnt[NPUPLL] == 0) { + _pll_switch(pll_idx, enable, fhctl_en); + } + pll_cnt[NPUPLL]++; + spin_unlock(&npupll_lock); + break; + case APUPLL1: + spin_lock(&apupll_1_lock); + if (pll_cnt[APUPLL1] == 0) { + _pll_switch(pll_idx, enable, fhctl_en); + } + pll_cnt[APUPLL1]++; + spin_unlock(&apupll_1_lock); + break; + case APUPLL2: + spin_lock(&apupll_2_lock); + if (pll_cnt[APUPLL2] == 0) { + _pll_switch(pll_idx, enable, fhctl_en); + } + pll_cnt[APUPLL2]++; + spin_unlock(&apupll_2_lock); + break; + default: + ERROR("%s invalid pll_idx: %d\n", __func__, pll_idx); + ret = -EINVAL; + break; + } + } else { + switch (pll_idx) { + case APUPLL: + spin_lock(&apupll_lock); + if (pll_cnt[APUPLL]) { + pll_cnt[APUPLL]--; + } + if (pll_cnt[APUPLL] == 0) { + _pll_switch(pll_idx, enable, fhctl_en); + } + spin_unlock(&apupll_lock); + break; + case NPUPLL: + spin_lock(&npupll_lock); + if (pll_cnt[NPUPLL]) { + pll_cnt[NPUPLL]--; + } + if (pll_cnt[NPUPLL] == 0) { + _pll_switch(pll_idx, enable, fhctl_en); + } + spin_unlock(&npupll_lock); + break; + case APUPLL1: + spin_lock(&apupll_1_lock); + if (pll_cnt[APUPLL1]) { + pll_cnt[APUPLL1]--; + } + if (pll_cnt[APUPLL1] == 0) { + _pll_switch(pll_idx, enable, fhctl_en); + } + spin_unlock(&apupll_1_lock); + break; + case APUPLL2: + spin_lock(&apupll_2_lock); + if (pll_cnt[APUPLL2]) { + pll_cnt[APUPLL2]--; + } + if (pll_cnt[APUPLL2] == 0) { + _pll_switch(pll_idx, enable, fhctl_en); + } + spin_unlock(&apupll_2_lock); + break; + default: + ERROR("%s invalid pll_idx: %d\n", __func__, pll_idx); + ret = -EINVAL; + break; + } + } + +err: + return ret; +} + +/** + * anpu_pll_set_rate() - API for smc function to set rate of voltage domain. + * @domain: Which pll of correspond voltage domain to change rate. + * @mode: which mode to use when set_rate + * @freq: which frequency to set. + * + * For V_VPU0/1, it will only allow 1 of them to modify NPUPLL + * such that there will be no race condition happen. + * + * For V_MDLA0/1, it will only allow 1 of them to modify APUPLL1 + * such that there will be no race condition happen. + * + * There are 3 kinds of modes to set pll's rate. + * 1. pure sw mode: (CON0_PCW) + * fhctl function is off and change rate by programming CON1_PCW. + * 2. fhctl sw mode: (FHCTL_SW) + * fhctl function is on and change rate by programming fhctl_dds. + * (post dividor is still need to program CON1_PCW) + * 3. fhctl hw mode: (FHCTL_HW) + * fhctl function is on and change rate by programming fhctl_dvfs. + * (post dividor is still need to program CON1_PCW) + * + * Context: Any context. + * Return: + * * 0 - done for set rate of voltage domain. + */ +int32_t anpu_pll_set_rate(enum dvfs_voltage_domain domain, + enum pll_set_rate_mode mode, int32_t freq) +{ + uint32_t pd, old_pd, dds; + int32_t pll_idx, ret = 0; + + pll_idx = vd2pllidx(domain); + if (pll_idx < 0) { + ret = pll_idx; + goto err; + } + + _cal_pll_data(&pd, &dds, freq / 1000); + + INFO("%s %s new post_div=%d, target dds=0x%08x(%dMhz) mode = %d\n", + __func__, pllidx2name(pll_idx), pd, dds, freq / 1000, mode); + + /* spin_lock for NPULL, since vpu0/1 share npupll */ + if (domain == V_VPU0 || domain == V_VPU1) { + spin_lock(&npupll_lock); + } + + /* spin_lock for APUPLL, since mdla0/1 shate apupll */ + if (domain == V_MDLA0 || domain == V_MDLA1) { + spin_lock(&apupll_lock); + } + + switch (mode) { + case CON0_PCW: + pd = RG_PLL_SDM_PCW_CHG | + (pd & POSDIV_MASK) << POSDIV_SHIFT | dds; + apupwr_writel(pd, mixed_con1_addr[pll_idx]); + udelay(PLL_READY_TIME_20US); + break; + case FHCTL_SW: + /* pll con0 disable */ + _pll_en(pll_idx, false); + apupwr_writel(dds, fhctl_dds_addr[pll_idx]); + _set_postdiv_reg(pll_idx, pd); + apupwr_setbits(PLL_TGL_ORG, fhctl_dds_addr[pll_idx]); + udelay(PLL_CMD_READY_TIME_1US); + /* pll con0 enable */ + _pll_en(pll_idx, true); + udelay(PLL_READY_TIME_20US); + break; + case FHCTL_HW: + old_pd = _pll_get_postdiv_reg(pll_idx); + if (pd > old_pd) { + _set_postdiv_reg(pll_idx, pd); + apupwr_writel(dds, fhctl_dvfs_addr[pll_idx]); + } else { + apupwr_writel(dds, fhctl_dvfs_addr[pll_idx]); + _set_postdiv_reg(pll_idx, pd); + } + ret = _fhctl_mon_done(pll_idx, dds); + break; + default: + ERROR("%s input wrong mode: %d\n", __func__, mode); + ret = -EINVAL; + break; + } + + /* spin_lock for NPULL, since vpu0/1 share npupll */ + if (domain == V_VPU0 || domain == V_VPU1) { + spin_unlock(&npupll_lock); + } + + /* spin_lock for APUPLL, since mdla0/1 share apupll */ + if (domain == V_MDLA0 || domain == V_MDLA1) { + spin_unlock(&apupll_lock); + } + +err: + return ret; +} diff --git a/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl.c b/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl.c new file mode 100644 index 000000000..465054d76 --- /dev/null +++ b/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl.c @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* 8195 use PCW mode to change freq directly */ +enum pll_set_rate_mode PLL_MODE = CON0_PCW; + +char *buck_domain_str[APUSYS_BUCK_DOMAIN_NUM] = { + "V_VPU0", + "V_VPU1", + "V_MDLA0", + "V_MDLA1", + "V_APU_CONN", + "V_TOP_IOMMU", + "V_VCORE", +}; + +uint32_t aacc_set[APUSYS_BUCK_DOMAIN_NUM] = { + APU_ACC_CONFG_SET1, APU_ACC_CONFG_SET2, + APU_ACC_CONFG_SET4, APU_ACC_CONFG_SET5, + APU_ACC_CONFG_SET0, APU_ACC_CONFG_SET7 +}; + +uint32_t aacc_clr[APUSYS_BUCK_DOMAIN_NUM] = { + APU_ACC_CONFG_CLR1, APU_ACC_CONFG_CLR2, + APU_ACC_CONFG_CLR4, APU_ACC_CONFG_CLR5, + APU_ACC_CONFG_CLR0, APU_ACC_CONFG_CLR7 +}; + +struct reg_seq { + uint32_t address; + uint32_t val; +}; + +static const struct reg_seq init_acc_cfg[] = { + { APU_ACC_CONFG_SET0, BIT(BIT_SEL_APU) }, + { APU_ACC_CONFG_CLR0, BIT(BIT_CGEN_SOC) }, + { APU_ACC_CONFG_SET0, BIT(BIT_SEL_APU_DIV2) }, + { APU_ACC_CONFG_SET7, BIT(BIT_SEL_APU) }, + { APU_ACC_CONFG_CLR7, BIT(BIT_CGEN_SOC) }, + { APU_ACC_CONFG_SET7, BIT(BIT_SEL_APU_DIV2) }, + { APU_ACC_CONFG_SET1, BIT(BIT_SEL_APU) }, + { APU_ACC_CONFG_CLR1, BIT(BIT_CGEN_SOC) }, + { APU_ACC_CONFG_SET1, BIT(BIT_SEL_APU_DIV2) }, + { APU_ACC_CONFG_SET2, BIT(BIT_INVEN_OUT) }, + { APU_ACC_CONFG_SET2, BIT(BIT_SEL_APU) }, + { APU_ACC_CONFG_CLR2, BIT(BIT_CGEN_SOC) }, + { APU_ACC_CONFG_SET2, BIT(BIT_SEL_APU_DIV2) }, + { APU_ACC_CONFG_SET4, BIT(BIT_SEL_APU) }, + { APU_ACC_CONFG_CLR4, BIT(BIT_CGEN_SOC) }, + { APU_ACC_CONFG_SET4, BIT(BIT_SEL_APU_DIV2) }, + { APU_ACC_CONFG_SET5, BIT(BIT_INVEN_OUT) }, + { APU_ACC_CONFG_SET5, BIT(BIT_SEL_APU) }, + { APU_ACC_CONFG_CLR5, BIT(BIT_CGEN_SOC) }, + { APU_ACC_CONFG_SET5, BIT(BIT_SEL_APU_DIV2) }, +}; + +int32_t apupwr_smc_acc_init_all(void) +{ + int32_t i; + + for (i = 0; i < ARRAY_SIZE(init_acc_cfg); i++) { + apupwr_writel(init_acc_cfg[i].val, + init_acc_cfg[i].address); + } + + /* Deault ACC will raise APU_DIV_2 */ + apupwr_smc_pll_set_rate(BUCK_VCONN_DOMAIN_DEFAULT_FREQ, + true, V_APU_CONN); + + apupwr_smc_pll_set_rate(BUCK_VCONN_DOMAIN_DEFAULT_FREQ, + true, V_TOP_IOMMU); + + apupwr_smc_pll_set_rate(BUCK_VVPU_DOMAIN_DEFAULT_FREQ, + true, V_VPU0); + + apupwr_smc_pll_set_rate(BUCK_VMDLA_DOMAIN_DEFAULT_FREQ, + true, V_MDLA0); + + return 0; +} + +void apupwr_smc_acc_top(bool enable) +{ + if (enable) { + apupwr_writel(BIT(BIT_CGEN_APU), aacc_set[V_APU_CONN]); + apupwr_writel(BIT(BIT_CGEN_APU), aacc_set[V_TOP_IOMMU]); + } else { + apupwr_writel(BIT(BIT_CGEN_APU), aacc_clr[V_APU_CONN]); + apupwr_writel(BIT(BIT_CGEN_APU), aacc_clr[V_TOP_IOMMU]); + } +} + +/* + * acc_clk_set_parent:ACC MUX select + * 0. freq parameters here, only ACC clksrc is valid + * 1. Switch between APUPLL <=> Parking (F26M, PARK) + * 2. Turn on/off CG_F26M, CG_PARK, CG_SOC, but no CG_APU + * 3. Clear APU Div2 while Parking + * 4. Only use clksrc of APUPLL while ACC CG_APU is on + */ +int32_t apupwr_smc_acc_set_parent(uint32_t freq, uint32_t domain) +{ + uint32_t acc_set = 0; + uint32_t acc_clr = 0; + int32_t ret = 0; + + if (freq > DVFS_FREQ_ACC_APUPLL) { + ERROR("%s wrong clksrc: %d\n", __func__, freq); + ret = -EIO; + goto err; + } + + switch (domain) { + case V_VPU1: + case V_VPU0: + case V_MDLA1: + case V_MDLA0: + case V_APU_CONN: + case V_TOP_IOMMU: + acc_set = aacc_set[domain]; + acc_clr = aacc_clr[domain]; + break; + default: + ret = -EIO; + break; + } + + /* Select park source */ + switch (freq) { + case DVFS_FREQ_ACC_PARKING: + /* Select park source */ + apupwr_writel(BIT(BIT_SEL_PARK), acc_set); + apupwr_writel(BIT(BIT_SEL_F26M), acc_clr); + /* Enable park cg */ + apupwr_writel(BIT(BIT_CGEN_PARK), acc_set); + apupwr_writel(BIT(BIT_CGEN_F26M) | BIT(BIT_CGEN_SOC), acc_clr); + /* Select park path */ + apupwr_writel(BIT(BIT_SEL_APU), acc_clr); + /* clear apu div 2 */ + apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_clr); + break; + + case DVFS_FREQ_ACC_APUPLL: + /* Select park path */ + apupwr_writel(BIT(BIT_SEL_APU), acc_set); + /* Clear park cg */ + apupwr_writel(BIT(BIT_CGEN_PARK) | BIT(BIT_CGEN_F26M) | + BIT(BIT_CGEN_SOC), acc_clr); + break; + + case DVFS_FREQ_ACC_SOC: + /* Select park source */ + apupwr_writel(BIT(BIT_SEL_PARK), acc_clr); + apupwr_writel(BIT(BIT_SEL_F26M), acc_clr); + /* Enable park cg */ + apupwr_writel(BIT(BIT_CGEN_SOC), acc_set); + apupwr_writel(BIT(BIT_CGEN_F26M) | BIT(BIT_CGEN_PARK), acc_clr); + /* Select park path */ + apupwr_writel(BIT(BIT_SEL_APU), acc_clr); + /* clear apu div 2 */ + apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_clr); + break; + + case DVFS_FREQ_ACC_26M: + case DVFS_FREQ_NOT_SUPPORT: + default: + /* Select park source */ + apupwr_writel(BIT(BIT_SEL_F26M), acc_set); + apupwr_writel(BIT(BIT_SEL_PARK), acc_clr); + /* Enable park cg */ + apupwr_writel(BIT(BIT_CGEN_F26M), acc_set); + apupwr_writel(BIT(BIT_CGEN_PARK) | BIT(BIT_CGEN_SOC), acc_clr); + /* Select park path */ + apupwr_writel(BIT(BIT_SEL_APU), acc_clr); + /* clear apu div 2 */ + apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_clr); + ERROR("[APUPWR] %s wrong ACC clksrc : %d, force assign 26M\n", + __func__, freq); + break; + } + +err: + return ret; +} + +int32_t apupwr_smc_pll_set_rate(uint32_t freq, bool div2, uint32_t domain) +{ + int32_t ret = 0; + uint32_t acc_set0 = 0, acc_set1 = 0; + + if (freq > DVFS_FREQ_MAX) { + ERROR("%s wrong freq: %d\n", __func__, freq); + ret = -EIO; + goto err; + } + + /* + * Switch to Parking src + * 1. Need to switch out all ACCs sharing the same apupll + */ + switch (domain) { + case V_MDLA0: + case V_MDLA1: + acc_set0 = APU_ACC_CONFG_SET4; + acc_set1 = APU_ACC_CONFG_SET5; + ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING, + V_MDLA0); + ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING, + V_MDLA1); + break; + case V_VPU0: + case V_VPU1: + acc_set0 = APU_ACC_CONFG_SET1; + acc_set1 = APU_ACC_CONFG_SET2; + ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING, + V_VPU0); + ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING, + V_VPU1); + break; + case V_APU_CONN: + acc_set0 = APU_ACC_CONFG_SET0; + ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING, + V_APU_CONN); + break; + case V_TOP_IOMMU: + acc_set0 = APU_ACC_CONFG_SET7; + ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING, + V_TOP_IOMMU); + break; + default: + ERROR("[APUPWR] %s %d invalid domain (%d)\n", + __func__, __LINE__, domain); + ret = -EIO; + goto err; + } + + anpu_pll_set_rate(domain, PLL_MODE, (div2) ? (freq * 2) : freq); + + if (div2) { + apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_set0); + if (acc_set1) { + apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_set1); + } + } + + /* + * Switch back to APUPLL + * Only switch back to APUPLL while CG_APU on + * And clksrc is not APUPLL + */ + switch (domain) { + case V_VPU0: + case V_VPU1: + if ((apupwr_readl(acc_set0) & BIT(BIT_CGEN_APU)) && + !(apupwr_readl(acc_set0) & BIT(BIT_SEL_APU))) { + ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL, + V_VPU0); + } + if ((apupwr_readl(acc_set1) & BIT(BIT_CGEN_APU)) && + !(apupwr_readl(acc_set1) & BIT(BIT_SEL_APU))) { + ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL, + V_VPU1); + } + break; + case V_MDLA0: + case V_MDLA1: + if ((apupwr_readl(acc_set0) & BIT(BIT_CGEN_APU)) && + !(apupwr_readl(acc_set0) & BIT(BIT_SEL_APU))) { + ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL, + V_MDLA0); + } + if ((apupwr_readl(acc_set1) & BIT(BIT_CGEN_APU)) && + !(apupwr_readl(acc_set1) & BIT(BIT_SEL_APU))) { + ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL, + V_MDLA1); + } + break; + case V_APU_CONN: + case V_TOP_IOMMU: + if ((apupwr_readl(acc_set0) & BIT(BIT_CGEN_APU)) && + !(apupwr_readl(acc_set0) & BIT(BIT_SEL_APU))) { + ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL, + domain); + } + break; + default: + ERROR("[APUPWR] %s %d invalid domain (%d)\n", + __func__, __LINE__, domain); + ret = -EIO; + break; + } + INFO("[%s][%d] set domain %d to freq %d\n", + __func__, __LINE__, domain, (div2) ? (freq * 2) : freq); + +err: + return ret; +} + +int32_t apupwr_smc_bulk_pll(bool enable) +{ + int32_t ret = 0; + int32_t pll_idx; + + if (enable) { + for (pll_idx = APUPLL; pll_idx < APUPLL_MAX; pll_idx++) { + ret = apu_pll_enable(pll_idx, enable, false); + if (ret != 0) { + goto err; + } + } + } else { + for (pll_idx = APUPLL2; pll_idx >= APUPLL; pll_idx--) { + ret = apu_pll_enable(pll_idx, enable, false); + if (ret != 0) { + goto err; + } + } + } + +err: + return ret; +} + +void apupwr_smc_bus_prot_cg_on(void) +{ + apupwr_clrbits(AO_MD32_MNOC_MASK, APU_CSR_DUMMY_0); +} diff --git a/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl.h b/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl.h new file mode 100644 index 000000000..3b27c1bb1 --- /dev/null +++ b/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef APUPWR_CLKCTL_H +#define APUPWR_CLKCTL_H + +#include +#include + +int32_t apupwr_smc_acc_init_all(void); +void apupwr_smc_acc_top(bool enable); +int32_t apupwr_smc_acc_set_parent(uint32_t freq, uint32_t domain); +int32_t apupwr_smc_pll_set_rate(uint32_t pll, bool div2, uint32_t domain); +int32_t apupwr_smc_bulk_pll(bool enable); +void apupwr_smc_bus_prot_cg_on(void); + +int32_t apu_pll_enable(int32_t pll_idx, bool enable, bool fhctl_en); +int32_t anpu_pll_set_rate(enum dvfs_voltage_domain domain, + enum pll_set_rate_mode mode, int32_t freq); +#endif /* APUPWR_CLKCTL_H */ diff --git a/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl_def.h b/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl_def.h new file mode 100644 index 000000000..6663ad9e9 --- /dev/null +++ b/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl_def.h @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef APUPWR_CLKCTL_DEF_H +#define APUPWR_CLKCTL_DEF_H + +#include + +enum dvfs_voltage_domain { + V_VPU0 = 0, + V_VPU1 = 1, + V_MDLA0 = 2, + V_MDLA1 = 3, + V_APU_CONN = 4, + V_TOP_IOMMU = 5, + V_VCORE = 6, + APUSYS_BUCK_DOMAIN_NUM = 7, +}; + +enum dvfs_freq { + DVFS_FREQ_NOT_SUPPORT = 0, + DVFS_FREQ_ACC_26M = 1, + DVFS_FREQ_ACC_PARKING = 2, + DVFS_FREQ_ACC_SOC = 3, + DVFS_FREQ_ACC_APUPLL = 4, + DVFS_FREQ_00_026000_F = 26000, + DVFS_FREQ_00_208000_F = 208000, + DVFS_FREQ_00_238000_F = 238000, + DVFS_FREQ_00_273000_F = 273000, + DVFS_FREQ_00_312000_F = 312000, + DVFS_FREQ_00_358000_F = 358000, + DVFS_FREQ_00_385000_F = 385000, + DVFS_FREQ_00_499200_F = 499200, + DVFS_FREQ_00_500000_F = 500000, + DVFS_FREQ_00_525000_F = 525000, + DVFS_FREQ_00_546000_F = 546000, + DVFS_FREQ_00_594000_F = 594000, + DVFS_FREQ_00_624000_F = 624000, + DVFS_FREQ_00_688000_F = 688000, + DVFS_FREQ_00_687500_F = 687500, + DVFS_FREQ_00_728000_F = 728000, + DVFS_FREQ_00_800000_F = 800000, + DVFS_FREQ_00_832000_F = 832000, + DVFS_FREQ_00_960000_F = 960000, + DVFS_FREQ_00_1100000_F = 1100000, +}; +#define DVFS_FREQ_MAX (DVFS_FREQ_00_1100000_F) + +enum pll_set_rate_mode { + CON0_PCW = 0, + FHCTL_SW = 1, + FHCTL_HW = 2, + PLL_SET_RATE_MODE_MAX = 3, +}; + +enum apupll { + APUPLL = 0, + NPUPLL = 1, + APUPLL1 = 2, + APUPLL2 = 3, + APUPLL_MAX = 4, +}; + +#define BUCK_VVPU_DOMAIN_DEFAULT_FREQ (DVFS_FREQ_00_273000_F) +#define BUCK_VMDLA_DOMAIN_DEFAULT_FREQ (DVFS_FREQ_00_312000_F) +#define BUCK_VCONN_DOMAIN_DEFAULT_FREQ (DVFS_FREQ_00_208000_F) + +#define apupwr_writel(VAL, REG) mmio_write_32((uintptr_t)REG, VAL) +#define apupwr_writel_relax(VAL, REG) mmio_write_32_relax((uintptr_t)REG, VAL) +#define apupwr_readl(REG) mmio_read_32((uintptr_t)REG) +#define apupwr_clrbits(VAL, REG) mmio_clrbits_32((uintptr_t)REG, VAL) +#define apupwr_setbits(VAL, REG) mmio_setbits_32((uintptr_t)REG, VAL) +#define apupwr_clrsetbits(CLR_VAL, SET_VAL, REG) \ + mmio_clrsetbits_32((uintptr_t)REG, CLR_VAL, SET_VAL) + +/* PLL and related register */ +#define APU_PLL_BASE (APUSYS_APU_PLL_BASE) +#define APU_PLL4H_PLL1_CON0 (APU_PLL_BASE + 0x008) +#define APU_PLL4H_PLL1_CON1 (APU_PLL_BASE + 0x00C) +#define APU_PLL4H_PLL1_CON3 (APU_PLL_BASE + 0x014) + +#define APU_PLL4H_PLL2_CON0 (APU_PLL_BASE + 0x018) +#define APU_PLL4H_PLL2_CON1 (APU_PLL_BASE + 0x01C) +#define APU_PLL4H_PLL2_CON3 (APU_PLL_BASE + 0x024) + +#define APU_PLL4H_PLL3_CON0 (APU_PLL_BASE + 0x028) +#define APU_PLL4H_PLL3_CON1 (APU_PLL_BASE + 0x02C) +#define APU_PLL4H_PLL3_CON3 (APU_PLL_BASE + 0x034) + +#define APU_PLL4H_PLL4_CON0 (APU_PLL_BASE + 0x038) +#define APU_PLL4H_PLL4_CON1 (APU_PLL_BASE + 0x03C) +#define APU_PLL4H_PLL4_CON3 (APU_PLL_BASE + 0x044) + +#define APU_PLL4H_FHCTL_HP_EN (APU_PLL_BASE + 0x0E00) +#define APU_PLL4H_FHCTL_UNITSLOPE_EN (APU_PLL_BASE + 0x0E04) +#define APU_PLL4H_FHCTL_CLK_CON (APU_PLL_BASE + 0x0E08) +#define APU_PLL4H_FHCTL_RST_CON (APU_PLL_BASE + 0x0E0C) +#define APU_PLL4H_FHCTL_SLOPE0 (APU_PLL_BASE + 0x0E10) +#define APU_PLL4H_FHCTL_SLOPE1 (APU_PLL_BASE + 0x0E14) +#define APU_PLL4H_FHCTL_DSSC_CFG (APU_PLL_BASE + 0x0E18) +#define APU_PLL4H_FHCTL_DSSC0_CON (APU_PLL_BASE + 0x0E1C) +#define APU_PLL4H_FHCTL_DSSC1_CON (APU_PLL_BASE + 0x0E20) +#define APU_PLL4H_FHCTL_DSSC2_CON (APU_PLL_BASE + 0x0E24) +#define APU_PLL4H_FHCTL_DSSC3_CON (APU_PLL_BASE + 0x0E28) +#define APU_PLL4H_FHCTL_DSSC4_CON (APU_PLL_BASE + 0x0E2C) +#define APU_PLL4H_FHCTL_DSSC5_CON (APU_PLL_BASE + 0x0E30) +#define APU_PLL4H_FHCTL_DSSC6_CON (APU_PLL_BASE + 0x0E34) +#define APU_PLL4H_FHCTL_DSSC7_CON (APU_PLL_BASE + 0x0E38) +#define APU_PLL4H_FHCTL0_CFG (APU_PLL_BASE + 0x0E3C) +#define APU_PLL4H_FHCTL0_UPDNLMT (APU_PLL_BASE + 0x0E40) +#define APU_PLL4H_FHCTL0_DDS (APU_PLL_BASE + 0x0E44) +#define APU_PLL4H_FHCTL0_DVFS (APU_PLL_BASE + 0x0E48) +#define APU_PLL4H_FHCTL0_MON (APU_PLL_BASE + 0x0E4C) +#define APU_PLL4H_FHCTL1_CFG (APU_PLL_BASE + 0x0E50) +#define APU_PLL4H_FHCTL1_UPDNLMT (APU_PLL_BASE + 0x0E54) +#define APU_PLL4H_FHCTL1_DDS (APU_PLL_BASE + 0x0E58) +#define APU_PLL4H_FHCTL1_DVFS (APU_PLL_BASE + 0x0E5C) +#define APU_PLL4H_FHCTL1_MON (APU_PLL_BASE + 0x0E60) +#define APU_PLL4H_FHCTL2_CFG (APU_PLL_BASE + 0x0E64) +#define APU_PLL4H_FHCTL2_UPDNLMT (APU_PLL_BASE + 0x0E68) +#define APU_PLL4H_FHCTL2_DDS (APU_PLL_BASE + 0x0E6C) +#define APU_PLL4H_FHCTL2_DVFS (APU_PLL_BASE + 0x0E70) +#define APU_PLL4H_FHCTL2_MON (APU_PLL_BASE + 0x0E74) +#define APU_PLL4H_FHCTL3_CFG (APU_PLL_BASE + 0x0E78) +#define APU_PLL4H_FHCTL3_UPDNLMT (APU_PLL_BASE + 0x0E7C) +#define APU_PLL4H_FHCTL3_DDS (APU_PLL_BASE + 0x0E80) +#define APU_PLL4H_FHCTL3_DVFS (APU_PLL_BASE + 0x0E84) +#define APU_PLL4H_FHCTL3_MON (APU_PLL_BASE + 0x0E88) + +/* PLL4H_PLLx_CON0 */ +#define RG_PLL_EN BIT(0) + +/* PLL4H_PLLx_CON1 */ +#define RG_PLL_SDM_PCW_CHG BIT(31) +#define POSDIV_SHIFT (24U) +#define POSDIV_MASK (0x7) + +/* PLL4H_PLLx_CON3 */ +#define DA_PLL_SDM_PWR_ON BIT(0) +#define DA_PLL_SDM_ISO_EN BIT(1) + +/* FHCTLx_DDS */ +#define DDS_MASK GENMASK_32(21, 0) +#define PCW_FRACTIONAL_SHIFT 14U +#define PLL_TGL_ORG BIT(31) + +#define PLL_READY_TIME_20US (20U) +#define PLL_CMD_READY_TIME_1US (1U) + +#define FREQ_VCO_MIN (1500U) /* 1500MHz*/ +#define FREQ_FIN (26U) /* 26M*/ + +/* ACC and related register */ +#define APU_ACC_BASE (APUSYS_APU_ACC_BASE) +#define APU_ACC_CONFG_SET0 (APU_ACC_BASE + 0x000) +#define APU_ACC_CONFG_SET1 (APU_ACC_BASE + 0x004) +#define APU_ACC_CONFG_SET2 (APU_ACC_BASE + 0x008) +#define APU_ACC_CONFG_SET4 (APU_ACC_BASE + 0x010) +#define APU_ACC_CONFG_SET5 (APU_ACC_BASE + 0x014) +#define APU_ACC_CONFG_SET7 (APU_ACC_BASE + 0x01C) + +#define APU_ACC_CONFG_CLR0 (APU_ACC_BASE + 0x040) +#define APU_ACC_CONFG_CLR1 (APU_ACC_BASE + 0x044) +#define APU_ACC_CONFG_CLR2 (APU_ACC_BASE + 0x048) +#define APU_ACC_CONFG_CLR4 (APU_ACC_BASE + 0x050) +#define APU_ACC_CONFG_CLR5 (APU_ACC_BASE + 0x054) +#define APU_ACC_CONFG_CLR7 (APU_ACC_BASE + 0x05C) + +#define APU_ACC_FM_CONFG_SET (APU_ACC_BASE + 0x0C0) +#define APU_ACC_FM_CONFG_CLR (APU_ACC_BASE + 0x0C4) +#define APU_ACC_FM_SEL (APU_ACC_BASE + 0x0C8) +#define APU_ACC_FM_CNT (APU_ACC_BASE + 0x0CC) + +/* APU AO control */ +#define APU_AO_CTRL_BASE (APUSYS_APU_S_S_4_BASE) +#define APU_CSR_DUMMY_0 (APU_AO_CTRL_BASE + 0x24) + +#define AO_MD32_MNOC_MASK (BIT(1) | BIT(0)) + +#define BIT_CGEN_F26M (0) +#define BIT_CGEN_PARK (1) +#define BIT_CGEN_SOC (2) +#define BIT_CGEN_APU (3) +#define BIT_CGEN_OUT (4) +#define BIT_SEL_PARK (8) +#define BIT_SEL_F26M (9) +#define BIT_SEL_APU_DIV2 (10) +#define BIT_SEL_APU (11) +#define BIT_SEL_PARK_SRC_OUT (12) +#define BIT_INVEN_OUT (15) + +#endif /* APUPWR_CLKCTL_DEF_H*/ diff --git a/plat/mediatek/mt8195/drivers/apusys/mtk_apusys.c b/plat/mediatek/mt8195/drivers/apusys/mtk_apusys.c new file mode 100644 index 000000000..3ed26a147 --- /dev/null +++ b/plat/mediatek/mt8195/drivers/apusys/mtk_apusys.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2021, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +#include +#include +#include + +int32_t apusys_kernel_ctrl(uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, + uint32_t *ret1) +{ + int32_t ret = 0L; + uint32_t request_ops; + + request_ops = (uint32_t)x1; + + switch (request_ops) { + case MTK_SIP_APU_START_MCU: + /* setup addr[33:32] in reviser */ + mmio_write_32(REVISER_SECUREFW_CTXT, 0U); + mmio_write_32(REVISER_USDRFW_CTXT, 0U); + + /* setup secure sideband */ + mmio_write_32(AO_SEC_FW, + (SEC_FW_NON_SECURE << SEC_FW_SHIFT_NS) | + (0U << SEC_FW_DOMAIN_SHIFT)); + + /* setup boot address */ + mmio_write_32(AO_MD32_BOOT_CTRL, 0U); + + /* setup pre-define region */ + mmio_write_32(AO_MD32_PRE_DEFINE, + (PRE_DEFINE_CACHE_TCM << PRE_DEFINE_SHIFT_0G) | + (PRE_DEFINE_CACHE << PRE_DEFINE_SHIFT_1G) | + (PRE_DEFINE_CACHE << PRE_DEFINE_SHIFT_2G) | + (PRE_DEFINE_CACHE << PRE_DEFINE_SHIFT_3G)); + + /* release runstall */ + mmio_write_32(AO_MD32_SYS_CTRL, SYS_CTRL_RUN); + + INFO("[APUSYS] rev(0x%08x,0x%08x)\n", + mmio_read_32(REVISER_SECUREFW_CTXT), + mmio_read_32(REVISER_USDRFW_CTXT)); + INFO("[APUSYS] ao(0x%08x,0x%08x,0x%08x,0x%08x,0x%08x)\n", + mmio_read_32(AO_SEC_FW), + mmio_read_32(AO_SEC_USR_FW), + mmio_read_32(AO_MD32_BOOT_CTRL), + mmio_read_32(AO_MD32_PRE_DEFINE), + mmio_read_32(AO_MD32_SYS_CTRL)); + break; + case MTK_SIP_APU_STOP_MCU: + /* hold runstall */ + mmio_write_32(AO_MD32_SYS_CTRL, SYS_CTRL_STALL); + + INFO("[APUSYS] md32_boot_ctrl=0x%08x,runstall=0x%08x\n", + mmio_read_32(AO_MD32_BOOT_CTRL), + mmio_read_32(AO_MD32_SYS_CTRL)); + break; + case MTK_SIP_APUPWR_BUS_PROT_CG_ON: + apupwr_smc_bus_prot_cg_on(); + break; + case MTK_SIP_APUPWR_BULK_PLL: + ret = apupwr_smc_bulk_pll((bool)x2); + break; + case MTK_SIP_APUPWR_ACC_INIT_ALL: + ret = apupwr_smc_acc_init_all(); + break; + case MTK_SIP_APUPWR_ACC_TOP: + apupwr_smc_acc_top((bool)x2); + break; + default: + ERROR("%s, unknown request_ops=0x%x\n", __func__, request_ops); + break; + } + + return ret; +} diff --git a/plat/mediatek/mt8195/drivers/apusys/mtk_apusys.h b/plat/mediatek/mt8195/drivers/apusys/mtk_apusys.h new file mode 100644 index 000000000..639abd3ab --- /dev/null +++ b/plat/mediatek/mt8195/drivers/apusys/mtk_apusys.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MTK_APUSYS_H +#define MTK_APUSYS_H + +#include + +/* setup the SMC command ops */ +#define MTK_SIP_APU_START_MCU (0x00U) +#define MTK_SIP_APU_STOP_MCU (0x01U) +#define MTK_SIP_APUPWR_BUS_PROT_CG_ON (0x02U) +#define MTK_SIP_APUPWR_BULK_PLL (0x03U) +#define MTK_SIP_APUPWR_ACC_INIT_ALL (0x04U) +#define MTK_SIP_APUPWR_ACC_TOP (0x05U) + +/* AO Register */ +#define AO_MD32_PRE_DEFINE (APUSYS_APU_S_S_4_BASE + 0x00) +#define AO_MD32_BOOT_CTRL (APUSYS_APU_S_S_4_BASE + 0x04) +#define AO_MD32_SYS_CTRL (APUSYS_APU_S_S_4_BASE + 0x08) +#define AO_SEC_FW (APUSYS_APU_S_S_4_BASE + 0x10) +#define AO_SEC_USR_FW (APUSYS_APU_S_S_4_BASE + 0x14) + +#define PRE_DEFINE_CACHE_TCM (0x3U) +#define PRE_DEFINE_CACHE (0x2U) +#define PRE_DEFINE_SHIFT_0G (0U) +#define PRE_DEFINE_SHIFT_1G (2U) +#define PRE_DEFINE_SHIFT_2G (4U) +#define PRE_DEFINE_SHIFT_3G (6U) + +#define SEC_FW_NON_SECURE (1U) +#define SEC_FW_SHIFT_NS (4U) +#define SEC_FW_DOMAIN_SHIFT (0U) + +#define SEC_USR_FW_NON_SECURE (1U) +#define SEC_USR_FW_SHIFT_NS (4U) +#define SEC_USR_FW_DOMAIN_SHIFT (0U) + +#define SYS_CTRL_RUN (0U) +#define SYS_CTRL_STALL (1U) + +/* Reviser Register */ +#define REVISER_SECUREFW_CTXT (APUSYS_SCTRL_REVISER_BASE + 0x100) +#define REVISER_USDRFW_CTXT (APUSYS_SCTRL_REVISER_BASE + 0x104) + +int32_t apusys_kernel_ctrl(uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, + uint32_t *ret1); +#endif /* MTK_APUSYS_H */ diff --git a/plat/mediatek/mt8195/include/plat_sip_calls.h b/plat/mediatek/mt8195/include/plat_sip_calls.h index ce25c6fd7..5562a6762 100644 --- a/plat/mediatek/mt8195/include/plat_sip_calls.h +++ b/plat/mediatek/mt8195/include/plat_sip_calls.h @@ -10,7 +10,7 @@ /******************************************************************************* * Plat SiP function constants ******************************************************************************/ -#define MTK_PLAT_SIP_NUM_CALLS 4 +#define MTK_PLAT_SIP_NUM_CALLS 6 /* DFD */ #define MTK_SIP_KERNEL_DFD_AARCH32 0x82000205 @@ -20,4 +20,8 @@ #define MTK_SIP_DP_CONTROL_AARCH32 0x82000523 #define MTK_SIP_DP_CONTROL_AARCH64 0xC2000523 +/* APUSYS SMC call */ +#define MTK_SIP_APUSYS_CONTROL_AARCH32 0x8200051E +#define MTK_SIP_APUSYS_CONTROL_AARCH64 0xC200051E + #endif /* PLAT_SIP_CALLS_H */ diff --git a/plat/mediatek/mt8195/include/platform_def.h b/plat/mediatek/mt8195/include/platform_def.h index 68301d6bd..d4f2f83b4 100644 --- a/plat/mediatek/mt8195/include/platform_def.h +++ b/plat/mediatek/mt8195/include/platform_def.h @@ -21,6 +21,16 @@ #define MTK_MCDI_SRAM_BASE 0x11B000 #define MTK_MCDI_SRAM_MAP_SIZE 0x1000 +#define APUSYS_BASE 0x19000000 +#define APUSYS_SCTRL_REVISER_BASE 0x19021000 +#define APUSYS_SCTRL_REVISER_SIZE 0x1000 +#define APUSYS_APU_S_S_4_BASE 0x190F2000 +#define APUSYS_APU_S_S_4_SIZE 0x1000 +#define APUSYS_APU_PLL_BASE 0x190F3000 +#define APUSYS_APU_PLL_SIZE 0x1000 +#define APUSYS_APU_ACC_BASE 0x190F4000 +#define APUSYS_APU_ACC_SIZE 0x1000 + #define TOPCKGEN_BASE (IO_PHYS + 0x00000000) #define INFRACFG_AO_BASE (IO_PHYS + 0x00001000) #define SPM_BASE (IO_PHYS + 0x00006000) diff --git a/plat/mediatek/mt8195/plat_sip_calls.c b/plat/mediatek/mt8195/plat_sip_calls.c index ddc750243..7d3c5128e 100644 --- a/plat/mediatek/mt8195/plat_sip_calls.c +++ b/plat/mediatek/mt8195/plat_sip_calls.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include "plat_sip_calls.h" @@ -41,6 +42,11 @@ uintptr_t mediatek_plat_sip_handler(uint32_t smc_fid, ret = dfd_smc_dispatcher(x1, x2, x3, x4); SMC_RET1(handle, ret); break; + case MTK_SIP_APUSYS_CONTROL_AARCH32: + case MTK_SIP_APUSYS_CONTROL_AARCH64: + ret = apusys_kernel_ctrl(x1, x2, x3, x4, &ret_val); + SMC_RET2(handle, ret, ret_val); + break; default: ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); break; diff --git a/plat/mediatek/mt8195/platform.mk b/plat/mediatek/mt8195/platform.mk index ef7ff81b5..72c71fea8 100644 --- a/plat/mediatek/mt8195/platform.mk +++ b/plat/mediatek/mt8195/platform.mk @@ -14,6 +14,7 @@ PLAT_INCLUDES := -I${MTK_PLAT}/common/ \ -I${MTK_PLAT}/common/drivers/timer/ \ -I${MTK_PLAT}/common/drivers/uart/ \ -I${MTK_PLAT}/common/lpm/ \ + -I${MTK_PLAT_SOC}/drivers/apusys/ \ -I${MTK_PLAT_SOC}/drivers/dcm \ -I${MTK_PLAT_SOC}/drivers/dfd \ -I${MTK_PLAT_SOC}/drivers/dp/ \ @@ -59,6 +60,9 @@ BL31_SOURCES += common/desc_image_load.c \ ${MTK_PLAT_SOC}/aarch64/platform_common.c \ ${MTK_PLAT_SOC}/aarch64/plat_helpers.S \ ${MTK_PLAT_SOC}/bl31_plat_setup.c \ + ${MTK_PLAT_SOC}/drivers/apusys/apupll.c \ + ${MTK_PLAT_SOC}/drivers/apusys/apupwr_clkctl.c \ + ${MTK_PLAT_SOC}/drivers/apusys/mtk_apusys.c \ ${MTK_PLAT_SOC}/drivers/dcm/mtk_dcm.c \ ${MTK_PLAT_SOC}/drivers/dcm/mtk_dcm_utils.c \ ${MTK_PLAT_SOC}/drivers/dfd/plat_dfd.c \