162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2015-2016 MediaTek Inc. 462306a36Sopenharmony_ci * Author: Yong Wu <yong.wu@mediatek.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/arm-smccc.h> 762306a36Sopenharmony_ci#include <linux/clk.h> 862306a36Sopenharmony_ci#include <linux/component.h> 962306a36Sopenharmony_ci#include <linux/device.h> 1062306a36Sopenharmony_ci#include <linux/err.h> 1162306a36Sopenharmony_ci#include <linux/io.h> 1262306a36Sopenharmony_ci#include <linux/iopoll.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/of.h> 1562306a36Sopenharmony_ci#include <linux/of_platform.h> 1662306a36Sopenharmony_ci#include <linux/platform_device.h> 1762306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1862306a36Sopenharmony_ci#include <linux/soc/mediatek/mtk_sip_svc.h> 1962306a36Sopenharmony_ci#include <soc/mediatek/smi.h> 2062306a36Sopenharmony_ci#include <dt-bindings/memory/mt2701-larb-port.h> 2162306a36Sopenharmony_ci#include <dt-bindings/memory/mtk-memory-port.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* SMI COMMON */ 2462306a36Sopenharmony_ci#define SMI_L1LEN 0x100 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define SMI_L1_ARB 0x200 2762306a36Sopenharmony_ci#define SMI_BUS_SEL 0x220 2862306a36Sopenharmony_ci#define SMI_BUS_LARB_SHIFT(larbid) ((larbid) << 1) 2962306a36Sopenharmony_ci/* All are MMU0 defaultly. Only specialize mmu1 here. */ 3062306a36Sopenharmony_ci#define F_MMU1_LARB(larbid) (0x1 << SMI_BUS_LARB_SHIFT(larbid)) 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define SMI_READ_FIFO_TH 0x230 3362306a36Sopenharmony_ci#define SMI_M4U_TH 0x234 3462306a36Sopenharmony_ci#define SMI_FIFO_TH1 0x238 3562306a36Sopenharmony_ci#define SMI_FIFO_TH2 0x23c 3662306a36Sopenharmony_ci#define SMI_DCM 0x300 3762306a36Sopenharmony_ci#define SMI_DUMMY 0x444 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* SMI LARB */ 4062306a36Sopenharmony_ci#define SMI_LARB_SLP_CON 0xc 4162306a36Sopenharmony_ci#define SLP_PROT_EN BIT(0) 4262306a36Sopenharmony_ci#define SLP_PROT_RDY BIT(16) 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define SMI_LARB_CMD_THRT_CON 0x24 4562306a36Sopenharmony_ci#define SMI_LARB_THRT_RD_NU_LMT_MSK GENMASK(7, 4) 4662306a36Sopenharmony_ci#define SMI_LARB_THRT_RD_NU_LMT (5 << 4) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define SMI_LARB_SW_FLAG 0x40 4962306a36Sopenharmony_ci#define SMI_LARB_SW_FLAG_1 0x1 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define SMI_LARB_OSTDL_PORT 0x200 5262306a36Sopenharmony_ci#define SMI_LARB_OSTDL_PORTx(id) (SMI_LARB_OSTDL_PORT + (((id) & 0x1f) << 2)) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* Below are about mmu enable registers, they are different in SoCs */ 5562306a36Sopenharmony_ci/* gen1: mt2701 */ 5662306a36Sopenharmony_ci#define REG_SMI_SECUR_CON_BASE 0x5c0 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* every register control 8 port, register offset 0x4 */ 5962306a36Sopenharmony_ci#define REG_SMI_SECUR_CON_OFFSET(id) (((id) >> 3) << 2) 6062306a36Sopenharmony_ci#define REG_SMI_SECUR_CON_ADDR(id) \ 6162306a36Sopenharmony_ci (REG_SMI_SECUR_CON_BASE + REG_SMI_SECUR_CON_OFFSET(id)) 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* 6462306a36Sopenharmony_ci * every port have 4 bit to control, bit[port + 3] control virtual or physical, 6562306a36Sopenharmony_ci * bit[port + 2 : port + 1] control the domain, bit[port] control the security 6662306a36Sopenharmony_ci * or non-security. 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci#define SMI_SECUR_CON_VAL_MSK(id) (~(0xf << (((id) & 0x7) << 2))) 6962306a36Sopenharmony_ci#define SMI_SECUR_CON_VAL_VIRT(id) BIT((((id) & 0x7) << 2) + 3) 7062306a36Sopenharmony_ci/* mt2701 domain should be set to 3 */ 7162306a36Sopenharmony_ci#define SMI_SECUR_CON_VAL_DOMAIN(id) (0x3 << ((((id) & 0x7) << 2) + 1)) 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* gen2: */ 7462306a36Sopenharmony_ci/* mt8167 */ 7562306a36Sopenharmony_ci#define MT8167_SMI_LARB_MMU_EN 0xfc0 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* mt8173 */ 7862306a36Sopenharmony_ci#define MT8173_SMI_LARB_MMU_EN 0xf00 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* general */ 8162306a36Sopenharmony_ci#define SMI_LARB_NONSEC_CON(id) (0x380 + ((id) * 4)) 8262306a36Sopenharmony_ci#define F_MMU_EN BIT(0) 8362306a36Sopenharmony_ci#define BANK_SEL(id) ({ \ 8462306a36Sopenharmony_ci u32 _id = (id) & 0x3; \ 8562306a36Sopenharmony_ci (_id << 8 | _id << 10 | _id << 12 | _id << 14); \ 8662306a36Sopenharmony_ci}) 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#define SMI_COMMON_INIT_REGS_NR 6 8962306a36Sopenharmony_ci#define SMI_LARB_PORT_NR_MAX 32 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#define MTK_SMI_FLAG_THRT_UPDATE BIT(0) 9262306a36Sopenharmony_ci#define MTK_SMI_FLAG_SW_FLAG BIT(1) 9362306a36Sopenharmony_ci#define MTK_SMI_FLAG_SLEEP_CTL BIT(2) 9462306a36Sopenharmony_ci#define MTK_SMI_FLAG_CFG_PORT_SEC_CTL BIT(3) 9562306a36Sopenharmony_ci#define MTK_SMI_CAPS(flags, _x) (!!((flags) & (_x))) 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistruct mtk_smi_reg_pair { 9862306a36Sopenharmony_ci unsigned int offset; 9962306a36Sopenharmony_ci u32 value; 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cienum mtk_smi_type { 10362306a36Sopenharmony_ci MTK_SMI_GEN1, 10462306a36Sopenharmony_ci MTK_SMI_GEN2, /* gen2 smi common */ 10562306a36Sopenharmony_ci MTK_SMI_GEN2_SUB_COMM, /* gen2 smi sub common */ 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/* larbs: Require apb/smi clocks while gals is optional. */ 10962306a36Sopenharmony_cistatic const char * const mtk_smi_larb_clks[] = {"apb", "smi", "gals"}; 11062306a36Sopenharmony_ci#define MTK_SMI_LARB_REQ_CLK_NR 2 11162306a36Sopenharmony_ci#define MTK_SMI_LARB_OPT_CLK_NR 1 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* 11462306a36Sopenharmony_ci * common: Require these four clocks in has_gals case. Otherwise, only apb/smi are required. 11562306a36Sopenharmony_ci * sub common: Require apb/smi/gals0 clocks in has_gals case. Otherwise, only apb/smi are required. 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_cistatic const char * const mtk_smi_common_clks[] = {"apb", "smi", "gals0", "gals1"}; 11862306a36Sopenharmony_ci#define MTK_SMI_CLK_NR_MAX ARRAY_SIZE(mtk_smi_common_clks) 11962306a36Sopenharmony_ci#define MTK_SMI_COM_REQ_CLK_NR 2 12062306a36Sopenharmony_ci#define MTK_SMI_COM_GALS_REQ_CLK_NR MTK_SMI_CLK_NR_MAX 12162306a36Sopenharmony_ci#define MTK_SMI_SUB_COM_GALS_REQ_CLK_NR 3 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistruct mtk_smi_common_plat { 12462306a36Sopenharmony_ci enum mtk_smi_type type; 12562306a36Sopenharmony_ci bool has_gals; 12662306a36Sopenharmony_ci u32 bus_sel; /* Balance some larbs to enter mmu0 or mmu1 */ 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci const struct mtk_smi_reg_pair *init; 12962306a36Sopenharmony_ci}; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistruct mtk_smi_larb_gen { 13262306a36Sopenharmony_ci int port_in_larb[MTK_LARB_NR_MAX + 1]; 13362306a36Sopenharmony_ci int (*config_port)(struct device *dev); 13462306a36Sopenharmony_ci unsigned int larb_direct_to_common_mask; 13562306a36Sopenharmony_ci unsigned int flags_general; 13662306a36Sopenharmony_ci const u8 (*ostd)[SMI_LARB_PORT_NR_MAX]; 13762306a36Sopenharmony_ci}; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistruct mtk_smi { 14062306a36Sopenharmony_ci struct device *dev; 14162306a36Sopenharmony_ci unsigned int clk_num; 14262306a36Sopenharmony_ci struct clk_bulk_data clks[MTK_SMI_CLK_NR_MAX]; 14362306a36Sopenharmony_ci struct clk *clk_async; /*only needed by mt2701*/ 14462306a36Sopenharmony_ci union { 14562306a36Sopenharmony_ci void __iomem *smi_ao_base; /* only for gen1 */ 14662306a36Sopenharmony_ci void __iomem *base; /* only for gen2 */ 14762306a36Sopenharmony_ci }; 14862306a36Sopenharmony_ci struct device *smi_common_dev; /* for sub common */ 14962306a36Sopenharmony_ci const struct mtk_smi_common_plat *plat; 15062306a36Sopenharmony_ci}; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistruct mtk_smi_larb { /* larb: local arbiter */ 15362306a36Sopenharmony_ci struct mtk_smi smi; 15462306a36Sopenharmony_ci void __iomem *base; 15562306a36Sopenharmony_ci struct device *smi_common_dev; /* common or sub-common dev */ 15662306a36Sopenharmony_ci const struct mtk_smi_larb_gen *larb_gen; 15762306a36Sopenharmony_ci int larbid; 15862306a36Sopenharmony_ci u32 *mmu; 15962306a36Sopenharmony_ci unsigned char *bank; 16062306a36Sopenharmony_ci}; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic int 16362306a36Sopenharmony_cimtk_smi_larb_bind(struct device *dev, struct device *master, void *data) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci struct mtk_smi_larb *larb = dev_get_drvdata(dev); 16662306a36Sopenharmony_ci struct mtk_smi_larb_iommu *larb_mmu = data; 16762306a36Sopenharmony_ci unsigned int i; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci for (i = 0; i < MTK_LARB_NR_MAX; i++) { 17062306a36Sopenharmony_ci if (dev == larb_mmu[i].dev) { 17162306a36Sopenharmony_ci larb->larbid = i; 17262306a36Sopenharmony_ci larb->mmu = &larb_mmu[i].mmu; 17362306a36Sopenharmony_ci larb->bank = larb_mmu[i].bank; 17462306a36Sopenharmony_ci return 0; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci return -ENODEV; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic void 18162306a36Sopenharmony_cimtk_smi_larb_unbind(struct device *dev, struct device *master, void *data) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci /* Do nothing as the iommu is always enabled. */ 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic const struct component_ops mtk_smi_larb_component_ops = { 18762306a36Sopenharmony_ci .bind = mtk_smi_larb_bind, 18862306a36Sopenharmony_ci .unbind = mtk_smi_larb_unbind, 18962306a36Sopenharmony_ci}; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic int mtk_smi_larb_config_port_gen1(struct device *dev) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct mtk_smi_larb *larb = dev_get_drvdata(dev); 19462306a36Sopenharmony_ci const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen; 19562306a36Sopenharmony_ci struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev); 19662306a36Sopenharmony_ci int i, m4u_port_id, larb_port_num; 19762306a36Sopenharmony_ci u32 sec_con_val, reg_val; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci m4u_port_id = larb_gen->port_in_larb[larb->larbid]; 20062306a36Sopenharmony_ci larb_port_num = larb_gen->port_in_larb[larb->larbid + 1] 20162306a36Sopenharmony_ci - larb_gen->port_in_larb[larb->larbid]; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci for (i = 0; i < larb_port_num; i++, m4u_port_id++) { 20462306a36Sopenharmony_ci if (*larb->mmu & BIT(i)) { 20562306a36Sopenharmony_ci /* bit[port + 3] controls the virtual or physical */ 20662306a36Sopenharmony_ci sec_con_val = SMI_SECUR_CON_VAL_VIRT(m4u_port_id); 20762306a36Sopenharmony_ci } else { 20862306a36Sopenharmony_ci /* do not need to enable m4u for this port */ 20962306a36Sopenharmony_ci continue; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci reg_val = readl(common->smi_ao_base 21262306a36Sopenharmony_ci + REG_SMI_SECUR_CON_ADDR(m4u_port_id)); 21362306a36Sopenharmony_ci reg_val &= SMI_SECUR_CON_VAL_MSK(m4u_port_id); 21462306a36Sopenharmony_ci reg_val |= sec_con_val; 21562306a36Sopenharmony_ci reg_val |= SMI_SECUR_CON_VAL_DOMAIN(m4u_port_id); 21662306a36Sopenharmony_ci writel(reg_val, 21762306a36Sopenharmony_ci common->smi_ao_base 21862306a36Sopenharmony_ci + REG_SMI_SECUR_CON_ADDR(m4u_port_id)); 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci return 0; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic int mtk_smi_larb_config_port_mt8167(struct device *dev) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct mtk_smi_larb *larb = dev_get_drvdata(dev); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci writel(*larb->mmu, larb->base + MT8167_SMI_LARB_MMU_EN); 22862306a36Sopenharmony_ci return 0; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic int mtk_smi_larb_config_port_mt8173(struct device *dev) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci struct mtk_smi_larb *larb = dev_get_drvdata(dev); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci writel(*larb->mmu, larb->base + MT8173_SMI_LARB_MMU_EN); 23662306a36Sopenharmony_ci return 0; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic int mtk_smi_larb_config_port_gen2_general(struct device *dev) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci struct mtk_smi_larb *larb = dev_get_drvdata(dev); 24262306a36Sopenharmony_ci u32 reg, flags_general = larb->larb_gen->flags_general; 24362306a36Sopenharmony_ci const u8 *larbostd = larb->larb_gen->ostd ? larb->larb_gen->ostd[larb->larbid] : NULL; 24462306a36Sopenharmony_ci struct arm_smccc_res res; 24562306a36Sopenharmony_ci int i; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (BIT(larb->larbid) & larb->larb_gen->larb_direct_to_common_mask) 24862306a36Sopenharmony_ci return 0; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (MTK_SMI_CAPS(flags_general, MTK_SMI_FLAG_THRT_UPDATE)) { 25162306a36Sopenharmony_ci reg = readl_relaxed(larb->base + SMI_LARB_CMD_THRT_CON); 25262306a36Sopenharmony_ci reg &= ~SMI_LARB_THRT_RD_NU_LMT_MSK; 25362306a36Sopenharmony_ci reg |= SMI_LARB_THRT_RD_NU_LMT; 25462306a36Sopenharmony_ci writel_relaxed(reg, larb->base + SMI_LARB_CMD_THRT_CON); 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (MTK_SMI_CAPS(flags_general, MTK_SMI_FLAG_SW_FLAG)) 25862306a36Sopenharmony_ci writel_relaxed(SMI_LARB_SW_FLAG_1, larb->base + SMI_LARB_SW_FLAG); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci for (i = 0; i < SMI_LARB_PORT_NR_MAX && larbostd && !!larbostd[i]; i++) 26162306a36Sopenharmony_ci writel_relaxed(larbostd[i], larb->base + SMI_LARB_OSTDL_PORTx(i)); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* 26462306a36Sopenharmony_ci * When mmu_en bits are in security world, the bank_sel still is in the 26562306a36Sopenharmony_ci * LARB_NONSEC_CON below. And the mmu_en bits of LARB_NONSEC_CON have no 26662306a36Sopenharmony_ci * effect in this case. 26762306a36Sopenharmony_ci */ 26862306a36Sopenharmony_ci if (MTK_SMI_CAPS(flags_general, MTK_SMI_FLAG_CFG_PORT_SEC_CTL)) { 26962306a36Sopenharmony_ci arm_smccc_smc(MTK_SIP_KERNEL_IOMMU_CONTROL, IOMMU_ATF_CMD_CONFIG_SMI_LARB, 27062306a36Sopenharmony_ci larb->larbid, *larb->mmu, 0, 0, 0, 0, &res); 27162306a36Sopenharmony_ci if (res.a0 != 0) { 27262306a36Sopenharmony_ci dev_err(dev, "Enable iommu fail, ret %ld\n", res.a0); 27362306a36Sopenharmony_ci return -EINVAL; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci for_each_set_bit(i, (unsigned long *)larb->mmu, 32) { 27862306a36Sopenharmony_ci reg = readl_relaxed(larb->base + SMI_LARB_NONSEC_CON(i)); 27962306a36Sopenharmony_ci reg |= F_MMU_EN; 28062306a36Sopenharmony_ci reg |= BANK_SEL(larb->bank[i]); 28162306a36Sopenharmony_ci writel(reg, larb->base + SMI_LARB_NONSEC_CON(i)); 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci return 0; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic const u8 mtk_smi_larb_mt8188_ostd[][SMI_LARB_PORT_NR_MAX] = { 28762306a36Sopenharmony_ci [0] = {0x02, 0x18, 0x22, 0x22, 0x01, 0x02, 0x0a,}, 28862306a36Sopenharmony_ci [1] = {0x12, 0x02, 0x14, 0x14, 0x01, 0x18, 0x0a,}, 28962306a36Sopenharmony_ci [2] = {0x12, 0x12, 0x12, 0x12, 0x0a,}, 29062306a36Sopenharmony_ci [3] = {0x12, 0x12, 0x12, 0x12, 0x28, 0x28, 0x0a,}, 29162306a36Sopenharmony_ci [4] = {0x06, 0x01, 0x17, 0x06, 0x0a, 0x07, 0x07,}, 29262306a36Sopenharmony_ci [5] = {0x02, 0x01, 0x04, 0x02, 0x06, 0x01, 0x06, 0x0a,}, 29362306a36Sopenharmony_ci [6] = {0x06, 0x01, 0x06, 0x0a,}, 29462306a36Sopenharmony_ci [7] = {0x0c, 0x0c, 0x12,}, 29562306a36Sopenharmony_ci [8] = {0x0c, 0x01, 0x0a, 0x05, 0x02, 0x03, 0x01, 0x01, 0x14, 0x14, 29662306a36Sopenharmony_ci 0x0a, 0x14, 0x1e, 0x01, 0x0c, 0x0a, 0x05, 0x02, 0x02, 0x05, 29762306a36Sopenharmony_ci 0x03, 0x01, 0x1e, 0x01, 0x05,}, 29862306a36Sopenharmony_ci [9] = {0x1e, 0x01, 0x0a, 0x0a, 0x01, 0x01, 0x03, 0x1e, 0x1e, 0x10, 29962306a36Sopenharmony_ci 0x07, 0x01, 0x0a, 0x06, 0x03, 0x03, 0x0e, 0x01, 0x04, 0x28,}, 30062306a36Sopenharmony_ci [10] = {0x03, 0x20, 0x01, 0x20, 0x01, 0x01, 0x14, 0x0a, 0x0a, 0x0c, 30162306a36Sopenharmony_ci 0x0a, 0x05, 0x02, 0x03, 0x02, 0x14, 0x0a, 0x0a, 0x14, 0x14, 30262306a36Sopenharmony_ci 0x14, 0x01, 0x01, 0x14, 0x1e, 0x01, 0x05, 0x03, 0x02, 0x28,}, 30362306a36Sopenharmony_ci [11] = {0x03, 0x20, 0x01, 0x20, 0x01, 0x01, 0x14, 0x0a, 0x0a, 0x0c, 30462306a36Sopenharmony_ci 0x0a, 0x05, 0x02, 0x03, 0x02, 0x14, 0x0a, 0x0a, 0x14, 0x14, 30562306a36Sopenharmony_ci 0x14, 0x01, 0x01, 0x14, 0x1e, 0x01, 0x05, 0x03, 0x02, 0x28,}, 30662306a36Sopenharmony_ci [12] = {0x03, 0x20, 0x01, 0x20, 0x01, 0x01, 0x14, 0x0a, 0x0a, 0x0c, 30762306a36Sopenharmony_ci 0x0a, 0x05, 0x02, 0x03, 0x02, 0x14, 0x0a, 0x0a, 0x14, 0x14, 30862306a36Sopenharmony_ci 0x14, 0x01, 0x01, 0x14, 0x1e, 0x01, 0x05, 0x03, 0x02, 0x28,}, 30962306a36Sopenharmony_ci [13] = {0x07, 0x02, 0x04, 0x02, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 31062306a36Sopenharmony_ci 0x07, 0x02, 0x04, 0x02, 0x05, 0x05,}, 31162306a36Sopenharmony_ci [14] = {0x02, 0x02, 0x0c, 0x0c, 0x0c, 0x0c, 0x01, 0x01, 0x02, 0x02, 31262306a36Sopenharmony_ci 0x02, 0x02, 0x0c, 0x0c, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 31362306a36Sopenharmony_ci 0x02, 0x02, 0x01, 0x01,}, 31462306a36Sopenharmony_ci [15] = {0x0c, 0x0c, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x0c, 0x0c, 31562306a36Sopenharmony_ci 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 31662306a36Sopenharmony_ci 0x0c, 0x01, 0x01,}, 31762306a36Sopenharmony_ci [16] = {0x28, 0x28, 0x03, 0x01, 0x01, 0x03, 0x14, 0x14, 0x0a, 0x0d, 31862306a36Sopenharmony_ci 0x03, 0x05, 0x0e, 0x01, 0x01, 0x05, 0x06, 0x0d, 0x01,}, 31962306a36Sopenharmony_ci [17] = {0x28, 0x02, 0x02, 0x12, 0x02, 0x12, 0x10, 0x02, 0x02, 0x0a, 32062306a36Sopenharmony_ci 0x12, 0x02, 0x02, 0x0a, 0x16, 0x02, 0x04,}, 32162306a36Sopenharmony_ci [18] = {0x28, 0x02, 0x02, 0x12, 0x02, 0x12, 0x10, 0x02, 0x02, 0x0a, 32262306a36Sopenharmony_ci 0x12, 0x02, 0x02, 0x0a, 0x16, 0x02, 0x04,}, 32362306a36Sopenharmony_ci [19] = {0x1a, 0x0e, 0x0a, 0x0a, 0x0c, 0x0e, 0x10,}, 32462306a36Sopenharmony_ci [20] = {0x1a, 0x0e, 0x0a, 0x0a, 0x0c, 0x0e, 0x10,}, 32562306a36Sopenharmony_ci [21] = {0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x01, 32662306a36Sopenharmony_ci 0x01, 0x01, 0x04, 0x0a, 0x06, 0x01, 0x01, 0x01, 0x0a, 0x06, 32762306a36Sopenharmony_ci 0x01, 0x01, 0x05, 0x03, 0x03, 0x04, 0x01,}, 32862306a36Sopenharmony_ci [22] = {0x28, 0x19, 0x0c, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 32962306a36Sopenharmony_ci 0x01,}, 33062306a36Sopenharmony_ci [23] = {0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x18, 0x01, 0x01,}, 33162306a36Sopenharmony_ci [24] = {0x12, 0x06, 0x12, 0x06,}, 33262306a36Sopenharmony_ci [25] = {0x01}, 33362306a36Sopenharmony_ci}; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic const u8 mtk_smi_larb_mt8195_ostd[][SMI_LARB_PORT_NR_MAX] = { 33662306a36Sopenharmony_ci [0] = {0x0a, 0xc, 0x22, 0x22, 0x01, 0x0a,}, /* larb0 */ 33762306a36Sopenharmony_ci [1] = {0x0a, 0xc, 0x22, 0x22, 0x01, 0x0a,}, /* larb1 */ 33862306a36Sopenharmony_ci [2] = {0x12, 0x12, 0x12, 0x12, 0x0a,}, /* ... */ 33962306a36Sopenharmony_ci [3] = {0x12, 0x12, 0x12, 0x12, 0x28, 0x28, 0x0a,}, 34062306a36Sopenharmony_ci [4] = {0x06, 0x01, 0x17, 0x06, 0x0a,}, 34162306a36Sopenharmony_ci [5] = {0x06, 0x01, 0x17, 0x06, 0x06, 0x01, 0x06, 0x0a,}, 34262306a36Sopenharmony_ci [6] = {0x06, 0x01, 0x06, 0x0a,}, 34362306a36Sopenharmony_ci [7] = {0x0c, 0x0c, 0x12,}, 34462306a36Sopenharmony_ci [8] = {0x0c, 0x0c, 0x12,}, 34562306a36Sopenharmony_ci [9] = {0x0a, 0x08, 0x04, 0x06, 0x01, 0x01, 0x10, 0x18, 0x11, 0x0a, 34662306a36Sopenharmony_ci 0x08, 0x04, 0x11, 0x06, 0x02, 0x06, 0x01, 0x11, 0x11, 0x06,}, 34762306a36Sopenharmony_ci [10] = {0x18, 0x08, 0x01, 0x01, 0x20, 0x12, 0x18, 0x06, 0x05, 0x10, 34862306a36Sopenharmony_ci 0x08, 0x08, 0x10, 0x08, 0x08, 0x18, 0x0c, 0x09, 0x0b, 0x0d, 34962306a36Sopenharmony_ci 0x0d, 0x06, 0x10, 0x10,}, 35062306a36Sopenharmony_ci [11] = {0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x01, 0x01, 0x01, 0x01,}, 35162306a36Sopenharmony_ci [12] = {0x09, 0x09, 0x05, 0x05, 0x0c, 0x18, 0x02, 0x02, 0x04, 0x02,}, 35262306a36Sopenharmony_ci [13] = {0x02, 0x02, 0x12, 0x12, 0x02, 0x02, 0x02, 0x02, 0x08, 0x01,}, 35362306a36Sopenharmony_ci [14] = {0x12, 0x12, 0x02, 0x02, 0x02, 0x02, 0x16, 0x01, 0x16, 0x01, 35462306a36Sopenharmony_ci 0x01, 0x02, 0x02, 0x08, 0x02,}, 35562306a36Sopenharmony_ci [15] = {}, 35662306a36Sopenharmony_ci [16] = {0x28, 0x02, 0x02, 0x12, 0x02, 0x12, 0x10, 0x02, 0x02, 0x0a, 35762306a36Sopenharmony_ci 0x12, 0x02, 0x0a, 0x16, 0x02, 0x04,}, 35862306a36Sopenharmony_ci [17] = {0x1a, 0x0e, 0x0a, 0x0a, 0x0c, 0x0e, 0x10,}, 35962306a36Sopenharmony_ci [18] = {0x12, 0x06, 0x12, 0x06,}, 36062306a36Sopenharmony_ci [19] = {0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x01, 36162306a36Sopenharmony_ci 0x01, 0x01, 0x04, 0x0a, 0x06, 0x01, 0x01, 0x01, 0x0a, 0x06, 36262306a36Sopenharmony_ci 0x01, 0x01, 0x05, 0x03, 0x03, 0x04, 0x01,}, 36362306a36Sopenharmony_ci [20] = {0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x01, 36462306a36Sopenharmony_ci 0x01, 0x01, 0x04, 0x0a, 0x06, 0x01, 0x01, 0x01, 0x0a, 0x06, 36562306a36Sopenharmony_ci 0x01, 0x01, 0x05, 0x03, 0x03, 0x04, 0x01,}, 36662306a36Sopenharmony_ci [21] = {0x28, 0x19, 0x0c, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04,}, 36762306a36Sopenharmony_ci [22] = {0x28, 0x19, 0x0c, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04,}, 36862306a36Sopenharmony_ci [23] = {0x18, 0x01,}, 36962306a36Sopenharmony_ci [24] = {0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 37062306a36Sopenharmony_ci 0x01, 0x01,}, 37162306a36Sopenharmony_ci [25] = {0x02, 0x02, 0x02, 0x28, 0x16, 0x02, 0x02, 0x02, 0x12, 0x16, 37262306a36Sopenharmony_ci 0x02, 0x01,}, 37362306a36Sopenharmony_ci [26] = {0x02, 0x02, 0x02, 0x28, 0x16, 0x02, 0x02, 0x02, 0x12, 0x16, 37462306a36Sopenharmony_ci 0x02, 0x01,}, 37562306a36Sopenharmony_ci [27] = {0x02, 0x02, 0x02, 0x28, 0x16, 0x02, 0x02, 0x02, 0x12, 0x16, 37662306a36Sopenharmony_ci 0x02, 0x01,}, 37762306a36Sopenharmony_ci [28] = {0x1a, 0x0e, 0x0a, 0x0a, 0x0c, 0x0e, 0x10,}, 37862306a36Sopenharmony_ci}; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic const struct mtk_smi_larb_gen mtk_smi_larb_mt2701 = { 38162306a36Sopenharmony_ci .port_in_larb = { 38262306a36Sopenharmony_ci LARB0_PORT_OFFSET, LARB1_PORT_OFFSET, 38362306a36Sopenharmony_ci LARB2_PORT_OFFSET, LARB3_PORT_OFFSET 38462306a36Sopenharmony_ci }, 38562306a36Sopenharmony_ci .config_port = mtk_smi_larb_config_port_gen1, 38662306a36Sopenharmony_ci}; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic const struct mtk_smi_larb_gen mtk_smi_larb_mt2712 = { 38962306a36Sopenharmony_ci .config_port = mtk_smi_larb_config_port_gen2_general, 39062306a36Sopenharmony_ci .larb_direct_to_common_mask = BIT(8) | BIT(9), /* bdpsys */ 39162306a36Sopenharmony_ci}; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic const struct mtk_smi_larb_gen mtk_smi_larb_mt6779 = { 39462306a36Sopenharmony_ci .config_port = mtk_smi_larb_config_port_gen2_general, 39562306a36Sopenharmony_ci .larb_direct_to_common_mask = 39662306a36Sopenharmony_ci BIT(4) | BIT(6) | BIT(11) | BIT(12) | BIT(13), 39762306a36Sopenharmony_ci /* DUMMY | IPU0 | IPU1 | CCU | MDLA */ 39862306a36Sopenharmony_ci}; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic const struct mtk_smi_larb_gen mtk_smi_larb_mt8167 = { 40162306a36Sopenharmony_ci /* mt8167 do not need the port in larb */ 40262306a36Sopenharmony_ci .config_port = mtk_smi_larb_config_port_mt8167, 40362306a36Sopenharmony_ci}; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic const struct mtk_smi_larb_gen mtk_smi_larb_mt8173 = { 40662306a36Sopenharmony_ci /* mt8173 do not need the port in larb */ 40762306a36Sopenharmony_ci .config_port = mtk_smi_larb_config_port_mt8173, 40862306a36Sopenharmony_ci}; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic const struct mtk_smi_larb_gen mtk_smi_larb_mt8183 = { 41162306a36Sopenharmony_ci .config_port = mtk_smi_larb_config_port_gen2_general, 41262306a36Sopenharmony_ci .larb_direct_to_common_mask = BIT(2) | BIT(3) | BIT(7), 41362306a36Sopenharmony_ci /* IPU0 | IPU1 | CCU */ 41462306a36Sopenharmony_ci}; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic const struct mtk_smi_larb_gen mtk_smi_larb_mt8186 = { 41762306a36Sopenharmony_ci .config_port = mtk_smi_larb_config_port_gen2_general, 41862306a36Sopenharmony_ci .flags_general = MTK_SMI_FLAG_SLEEP_CTL, 41962306a36Sopenharmony_ci}; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic const struct mtk_smi_larb_gen mtk_smi_larb_mt8188 = { 42262306a36Sopenharmony_ci .config_port = mtk_smi_larb_config_port_gen2_general, 42362306a36Sopenharmony_ci .flags_general = MTK_SMI_FLAG_THRT_UPDATE | MTK_SMI_FLAG_SW_FLAG | 42462306a36Sopenharmony_ci MTK_SMI_FLAG_SLEEP_CTL | MTK_SMI_FLAG_CFG_PORT_SEC_CTL, 42562306a36Sopenharmony_ci .ostd = mtk_smi_larb_mt8188_ostd, 42662306a36Sopenharmony_ci}; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic const struct mtk_smi_larb_gen mtk_smi_larb_mt8192 = { 42962306a36Sopenharmony_ci .config_port = mtk_smi_larb_config_port_gen2_general, 43062306a36Sopenharmony_ci}; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic const struct mtk_smi_larb_gen mtk_smi_larb_mt8195 = { 43362306a36Sopenharmony_ci .config_port = mtk_smi_larb_config_port_gen2_general, 43462306a36Sopenharmony_ci .flags_general = MTK_SMI_FLAG_THRT_UPDATE | MTK_SMI_FLAG_SW_FLAG | 43562306a36Sopenharmony_ci MTK_SMI_FLAG_SLEEP_CTL, 43662306a36Sopenharmony_ci .ostd = mtk_smi_larb_mt8195_ostd, 43762306a36Sopenharmony_ci}; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic const struct of_device_id mtk_smi_larb_of_ids[] = { 44062306a36Sopenharmony_ci {.compatible = "mediatek,mt2701-smi-larb", .data = &mtk_smi_larb_mt2701}, 44162306a36Sopenharmony_ci {.compatible = "mediatek,mt2712-smi-larb", .data = &mtk_smi_larb_mt2712}, 44262306a36Sopenharmony_ci {.compatible = "mediatek,mt6779-smi-larb", .data = &mtk_smi_larb_mt6779}, 44362306a36Sopenharmony_ci {.compatible = "mediatek,mt6795-smi-larb", .data = &mtk_smi_larb_mt8173}, 44462306a36Sopenharmony_ci {.compatible = "mediatek,mt8167-smi-larb", .data = &mtk_smi_larb_mt8167}, 44562306a36Sopenharmony_ci {.compatible = "mediatek,mt8173-smi-larb", .data = &mtk_smi_larb_mt8173}, 44662306a36Sopenharmony_ci {.compatible = "mediatek,mt8183-smi-larb", .data = &mtk_smi_larb_mt8183}, 44762306a36Sopenharmony_ci {.compatible = "mediatek,mt8186-smi-larb", .data = &mtk_smi_larb_mt8186}, 44862306a36Sopenharmony_ci {.compatible = "mediatek,mt8188-smi-larb", .data = &mtk_smi_larb_mt8188}, 44962306a36Sopenharmony_ci {.compatible = "mediatek,mt8192-smi-larb", .data = &mtk_smi_larb_mt8192}, 45062306a36Sopenharmony_ci {.compatible = "mediatek,mt8195-smi-larb", .data = &mtk_smi_larb_mt8195}, 45162306a36Sopenharmony_ci {} 45262306a36Sopenharmony_ci}; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cistatic int mtk_smi_larb_sleep_ctrl_enable(struct mtk_smi_larb *larb) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci int ret; 45762306a36Sopenharmony_ci u32 tmp; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci writel_relaxed(SLP_PROT_EN, larb->base + SMI_LARB_SLP_CON); 46062306a36Sopenharmony_ci ret = readl_poll_timeout_atomic(larb->base + SMI_LARB_SLP_CON, 46162306a36Sopenharmony_ci tmp, !!(tmp & SLP_PROT_RDY), 10, 1000); 46262306a36Sopenharmony_ci if (ret) { 46362306a36Sopenharmony_ci /* TODO: Reset this larb if it fails here. */ 46462306a36Sopenharmony_ci dev_err(larb->smi.dev, "sleep ctrl is not ready(0x%x).\n", tmp); 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci return ret; 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic void mtk_smi_larb_sleep_ctrl_disable(struct mtk_smi_larb *larb) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci writel_relaxed(0, larb->base + SMI_LARB_SLP_CON); 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic int mtk_smi_device_link_common(struct device *dev, struct device **com_dev) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct platform_device *smi_com_pdev; 47762306a36Sopenharmony_ci struct device_node *smi_com_node; 47862306a36Sopenharmony_ci struct device *smi_com_dev; 47962306a36Sopenharmony_ci struct device_link *link; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci smi_com_node = of_parse_phandle(dev->of_node, "mediatek,smi", 0); 48262306a36Sopenharmony_ci if (!smi_com_node) 48362306a36Sopenharmony_ci return -EINVAL; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci smi_com_pdev = of_find_device_by_node(smi_com_node); 48662306a36Sopenharmony_ci of_node_put(smi_com_node); 48762306a36Sopenharmony_ci if (smi_com_pdev) { 48862306a36Sopenharmony_ci /* smi common is the supplier, Make sure it is ready before */ 48962306a36Sopenharmony_ci if (!platform_get_drvdata(smi_com_pdev)) { 49062306a36Sopenharmony_ci put_device(&smi_com_pdev->dev); 49162306a36Sopenharmony_ci return -EPROBE_DEFER; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci smi_com_dev = &smi_com_pdev->dev; 49462306a36Sopenharmony_ci link = device_link_add(dev, smi_com_dev, 49562306a36Sopenharmony_ci DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS); 49662306a36Sopenharmony_ci if (!link) { 49762306a36Sopenharmony_ci dev_err(dev, "Unable to link smi-common dev\n"); 49862306a36Sopenharmony_ci put_device(&smi_com_pdev->dev); 49962306a36Sopenharmony_ci return -ENODEV; 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci *com_dev = smi_com_dev; 50262306a36Sopenharmony_ci } else { 50362306a36Sopenharmony_ci dev_err(dev, "Failed to get the smi_common device\n"); 50462306a36Sopenharmony_ci return -EINVAL; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci return 0; 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic int mtk_smi_dts_clk_init(struct device *dev, struct mtk_smi *smi, 51062306a36Sopenharmony_ci const char * const clks[], 51162306a36Sopenharmony_ci unsigned int clk_nr_required, 51262306a36Sopenharmony_ci unsigned int clk_nr_optional) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci int i, ret; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci for (i = 0; i < clk_nr_required; i++) 51762306a36Sopenharmony_ci smi->clks[i].id = clks[i]; 51862306a36Sopenharmony_ci ret = devm_clk_bulk_get(dev, clk_nr_required, smi->clks); 51962306a36Sopenharmony_ci if (ret) 52062306a36Sopenharmony_ci return ret; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci for (i = clk_nr_required; i < clk_nr_required + clk_nr_optional; i++) 52362306a36Sopenharmony_ci smi->clks[i].id = clks[i]; 52462306a36Sopenharmony_ci ret = devm_clk_bulk_get_optional(dev, clk_nr_optional, 52562306a36Sopenharmony_ci smi->clks + clk_nr_required); 52662306a36Sopenharmony_ci smi->clk_num = clk_nr_required + clk_nr_optional; 52762306a36Sopenharmony_ci return ret; 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic int mtk_smi_larb_probe(struct platform_device *pdev) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci struct mtk_smi_larb *larb; 53362306a36Sopenharmony_ci struct device *dev = &pdev->dev; 53462306a36Sopenharmony_ci int ret; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci larb = devm_kzalloc(dev, sizeof(*larb), GFP_KERNEL); 53762306a36Sopenharmony_ci if (!larb) 53862306a36Sopenharmony_ci return -ENOMEM; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci larb->larb_gen = of_device_get_match_data(dev); 54162306a36Sopenharmony_ci larb->base = devm_platform_ioremap_resource(pdev, 0); 54262306a36Sopenharmony_ci if (IS_ERR(larb->base)) 54362306a36Sopenharmony_ci return PTR_ERR(larb->base); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci ret = mtk_smi_dts_clk_init(dev, &larb->smi, mtk_smi_larb_clks, 54662306a36Sopenharmony_ci MTK_SMI_LARB_REQ_CLK_NR, MTK_SMI_LARB_OPT_CLK_NR); 54762306a36Sopenharmony_ci if (ret) 54862306a36Sopenharmony_ci return ret; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci larb->smi.dev = dev; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci ret = mtk_smi_device_link_common(dev, &larb->smi_common_dev); 55362306a36Sopenharmony_ci if (ret < 0) 55462306a36Sopenharmony_ci return ret; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci pm_runtime_enable(dev); 55762306a36Sopenharmony_ci platform_set_drvdata(pdev, larb); 55862306a36Sopenharmony_ci ret = component_add(dev, &mtk_smi_larb_component_ops); 55962306a36Sopenharmony_ci if (ret) 56062306a36Sopenharmony_ci goto err_pm_disable; 56162306a36Sopenharmony_ci return 0; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cierr_pm_disable: 56462306a36Sopenharmony_ci pm_runtime_disable(dev); 56562306a36Sopenharmony_ci device_link_remove(dev, larb->smi_common_dev); 56662306a36Sopenharmony_ci return ret; 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_cistatic int mtk_smi_larb_remove(struct platform_device *pdev) 57062306a36Sopenharmony_ci{ 57162306a36Sopenharmony_ci struct mtk_smi_larb *larb = platform_get_drvdata(pdev); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci device_link_remove(&pdev->dev, larb->smi_common_dev); 57462306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 57562306a36Sopenharmony_ci component_del(&pdev->dev, &mtk_smi_larb_component_ops); 57662306a36Sopenharmony_ci return 0; 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_cistatic int __maybe_unused mtk_smi_larb_resume(struct device *dev) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci struct mtk_smi_larb *larb = dev_get_drvdata(dev); 58262306a36Sopenharmony_ci const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen; 58362306a36Sopenharmony_ci int ret; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci ret = clk_bulk_prepare_enable(larb->smi.clk_num, larb->smi.clks); 58662306a36Sopenharmony_ci if (ret) 58762306a36Sopenharmony_ci return ret; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci if (MTK_SMI_CAPS(larb->larb_gen->flags_general, MTK_SMI_FLAG_SLEEP_CTL)) 59062306a36Sopenharmony_ci mtk_smi_larb_sleep_ctrl_disable(larb); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci /* Configure the basic setting for this larb */ 59362306a36Sopenharmony_ci return larb_gen->config_port(dev); 59462306a36Sopenharmony_ci} 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_cistatic int __maybe_unused mtk_smi_larb_suspend(struct device *dev) 59762306a36Sopenharmony_ci{ 59862306a36Sopenharmony_ci struct mtk_smi_larb *larb = dev_get_drvdata(dev); 59962306a36Sopenharmony_ci int ret; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (MTK_SMI_CAPS(larb->larb_gen->flags_general, MTK_SMI_FLAG_SLEEP_CTL)) { 60262306a36Sopenharmony_ci ret = mtk_smi_larb_sleep_ctrl_enable(larb); 60362306a36Sopenharmony_ci if (ret) 60462306a36Sopenharmony_ci return ret; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci clk_bulk_disable_unprepare(larb->smi.clk_num, larb->smi.clks); 60862306a36Sopenharmony_ci return 0; 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_cistatic const struct dev_pm_ops smi_larb_pm_ops = { 61262306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(mtk_smi_larb_suspend, mtk_smi_larb_resume, NULL) 61362306a36Sopenharmony_ci SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 61462306a36Sopenharmony_ci pm_runtime_force_resume) 61562306a36Sopenharmony_ci}; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic struct platform_driver mtk_smi_larb_driver = { 61862306a36Sopenharmony_ci .probe = mtk_smi_larb_probe, 61962306a36Sopenharmony_ci .remove = mtk_smi_larb_remove, 62062306a36Sopenharmony_ci .driver = { 62162306a36Sopenharmony_ci .name = "mtk-smi-larb", 62262306a36Sopenharmony_ci .of_match_table = mtk_smi_larb_of_ids, 62362306a36Sopenharmony_ci .pm = &smi_larb_pm_ops, 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci}; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic const struct mtk_smi_reg_pair mtk_smi_common_mt6795_init[SMI_COMMON_INIT_REGS_NR] = { 62862306a36Sopenharmony_ci {SMI_L1_ARB, 0x1b}, 62962306a36Sopenharmony_ci {SMI_M4U_TH, 0xce810c85}, 63062306a36Sopenharmony_ci {SMI_FIFO_TH1, 0x43214c8}, 63162306a36Sopenharmony_ci {SMI_READ_FIFO_TH, 0x191f}, 63262306a36Sopenharmony_ci}; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_cistatic const struct mtk_smi_reg_pair mtk_smi_common_mt8195_init[SMI_COMMON_INIT_REGS_NR] = { 63562306a36Sopenharmony_ci {SMI_L1LEN, 0xb}, 63662306a36Sopenharmony_ci {SMI_M4U_TH, 0xe100e10}, 63762306a36Sopenharmony_ci {SMI_FIFO_TH1, 0x506090a}, 63862306a36Sopenharmony_ci {SMI_FIFO_TH2, 0x506090a}, 63962306a36Sopenharmony_ci {SMI_DCM, 0x4f1}, 64062306a36Sopenharmony_ci {SMI_DUMMY, 0x1}, 64162306a36Sopenharmony_ci}; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cistatic const struct mtk_smi_common_plat mtk_smi_common_gen1 = { 64462306a36Sopenharmony_ci .type = MTK_SMI_GEN1, 64562306a36Sopenharmony_ci}; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_cistatic const struct mtk_smi_common_plat mtk_smi_common_gen2 = { 64862306a36Sopenharmony_ci .type = MTK_SMI_GEN2, 64962306a36Sopenharmony_ci}; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_cistatic const struct mtk_smi_common_plat mtk_smi_common_mt6779 = { 65262306a36Sopenharmony_ci .type = MTK_SMI_GEN2, 65362306a36Sopenharmony_ci .has_gals = true, 65462306a36Sopenharmony_ci .bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(4) | 65562306a36Sopenharmony_ci F_MMU1_LARB(5) | F_MMU1_LARB(6) | F_MMU1_LARB(7), 65662306a36Sopenharmony_ci}; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic const struct mtk_smi_common_plat mtk_smi_common_mt6795 = { 65962306a36Sopenharmony_ci .type = MTK_SMI_GEN2, 66062306a36Sopenharmony_ci .bus_sel = F_MMU1_LARB(0), 66162306a36Sopenharmony_ci .init = mtk_smi_common_mt6795_init, 66262306a36Sopenharmony_ci}; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_cistatic const struct mtk_smi_common_plat mtk_smi_common_mt8183 = { 66562306a36Sopenharmony_ci .type = MTK_SMI_GEN2, 66662306a36Sopenharmony_ci .has_gals = true, 66762306a36Sopenharmony_ci .bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(5) | 66862306a36Sopenharmony_ci F_MMU1_LARB(7), 66962306a36Sopenharmony_ci}; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistatic const struct mtk_smi_common_plat mtk_smi_common_mt8186 = { 67262306a36Sopenharmony_ci .type = MTK_SMI_GEN2, 67362306a36Sopenharmony_ci .has_gals = true, 67462306a36Sopenharmony_ci .bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(4) | F_MMU1_LARB(7), 67562306a36Sopenharmony_ci}; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic const struct mtk_smi_common_plat mtk_smi_common_mt8188_vdo = { 67862306a36Sopenharmony_ci .type = MTK_SMI_GEN2, 67962306a36Sopenharmony_ci .bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(5) | F_MMU1_LARB(7), 68062306a36Sopenharmony_ci .init = mtk_smi_common_mt8195_init, 68162306a36Sopenharmony_ci}; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic const struct mtk_smi_common_plat mtk_smi_common_mt8188_vpp = { 68462306a36Sopenharmony_ci .type = MTK_SMI_GEN2, 68562306a36Sopenharmony_ci .bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(7), 68662306a36Sopenharmony_ci .init = mtk_smi_common_mt8195_init, 68762306a36Sopenharmony_ci}; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_cistatic const struct mtk_smi_common_plat mtk_smi_common_mt8192 = { 69062306a36Sopenharmony_ci .type = MTK_SMI_GEN2, 69162306a36Sopenharmony_ci .has_gals = true, 69262306a36Sopenharmony_ci .bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(5) | 69362306a36Sopenharmony_ci F_MMU1_LARB(6), 69462306a36Sopenharmony_ci}; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_cistatic const struct mtk_smi_common_plat mtk_smi_common_mt8195_vdo = { 69762306a36Sopenharmony_ci .type = MTK_SMI_GEN2, 69862306a36Sopenharmony_ci .has_gals = true, 69962306a36Sopenharmony_ci .bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(3) | F_MMU1_LARB(5) | 70062306a36Sopenharmony_ci F_MMU1_LARB(7), 70162306a36Sopenharmony_ci .init = mtk_smi_common_mt8195_init, 70262306a36Sopenharmony_ci}; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic const struct mtk_smi_common_plat mtk_smi_common_mt8195_vpp = { 70562306a36Sopenharmony_ci .type = MTK_SMI_GEN2, 70662306a36Sopenharmony_ci .has_gals = true, 70762306a36Sopenharmony_ci .bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(7), 70862306a36Sopenharmony_ci .init = mtk_smi_common_mt8195_init, 70962306a36Sopenharmony_ci}; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cistatic const struct mtk_smi_common_plat mtk_smi_sub_common_mt8195 = { 71262306a36Sopenharmony_ci .type = MTK_SMI_GEN2_SUB_COMM, 71362306a36Sopenharmony_ci .has_gals = true, 71462306a36Sopenharmony_ci}; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic const struct mtk_smi_common_plat mtk_smi_common_mt8365 = { 71762306a36Sopenharmony_ci .type = MTK_SMI_GEN2, 71862306a36Sopenharmony_ci .bus_sel = F_MMU1_LARB(2) | F_MMU1_LARB(4), 71962306a36Sopenharmony_ci}; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic const struct of_device_id mtk_smi_common_of_ids[] = { 72262306a36Sopenharmony_ci {.compatible = "mediatek,mt2701-smi-common", .data = &mtk_smi_common_gen1}, 72362306a36Sopenharmony_ci {.compatible = "mediatek,mt2712-smi-common", .data = &mtk_smi_common_gen2}, 72462306a36Sopenharmony_ci {.compatible = "mediatek,mt6779-smi-common", .data = &mtk_smi_common_mt6779}, 72562306a36Sopenharmony_ci {.compatible = "mediatek,mt6795-smi-common", .data = &mtk_smi_common_mt6795}, 72662306a36Sopenharmony_ci {.compatible = "mediatek,mt8167-smi-common", .data = &mtk_smi_common_gen2}, 72762306a36Sopenharmony_ci {.compatible = "mediatek,mt8173-smi-common", .data = &mtk_smi_common_gen2}, 72862306a36Sopenharmony_ci {.compatible = "mediatek,mt8183-smi-common", .data = &mtk_smi_common_mt8183}, 72962306a36Sopenharmony_ci {.compatible = "mediatek,mt8186-smi-common", .data = &mtk_smi_common_mt8186}, 73062306a36Sopenharmony_ci {.compatible = "mediatek,mt8188-smi-common-vdo", .data = &mtk_smi_common_mt8188_vdo}, 73162306a36Sopenharmony_ci {.compatible = "mediatek,mt8188-smi-common-vpp", .data = &mtk_smi_common_mt8188_vpp}, 73262306a36Sopenharmony_ci {.compatible = "mediatek,mt8192-smi-common", .data = &mtk_smi_common_mt8192}, 73362306a36Sopenharmony_ci {.compatible = "mediatek,mt8195-smi-common-vdo", .data = &mtk_smi_common_mt8195_vdo}, 73462306a36Sopenharmony_ci {.compatible = "mediatek,mt8195-smi-common-vpp", .data = &mtk_smi_common_mt8195_vpp}, 73562306a36Sopenharmony_ci {.compatible = "mediatek,mt8195-smi-sub-common", .data = &mtk_smi_sub_common_mt8195}, 73662306a36Sopenharmony_ci {.compatible = "mediatek,mt8365-smi-common", .data = &mtk_smi_common_mt8365}, 73762306a36Sopenharmony_ci {} 73862306a36Sopenharmony_ci}; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cistatic int mtk_smi_common_probe(struct platform_device *pdev) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci struct device *dev = &pdev->dev; 74362306a36Sopenharmony_ci struct mtk_smi *common; 74462306a36Sopenharmony_ci int ret, clk_required = MTK_SMI_COM_REQ_CLK_NR; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL); 74762306a36Sopenharmony_ci if (!common) 74862306a36Sopenharmony_ci return -ENOMEM; 74962306a36Sopenharmony_ci common->dev = dev; 75062306a36Sopenharmony_ci common->plat = of_device_get_match_data(dev); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci if (common->plat->has_gals) { 75362306a36Sopenharmony_ci if (common->plat->type == MTK_SMI_GEN2) 75462306a36Sopenharmony_ci clk_required = MTK_SMI_COM_GALS_REQ_CLK_NR; 75562306a36Sopenharmony_ci else if (common->plat->type == MTK_SMI_GEN2_SUB_COMM) 75662306a36Sopenharmony_ci clk_required = MTK_SMI_SUB_COM_GALS_REQ_CLK_NR; 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci ret = mtk_smi_dts_clk_init(dev, common, mtk_smi_common_clks, clk_required, 0); 75962306a36Sopenharmony_ci if (ret) 76062306a36Sopenharmony_ci return ret; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci /* 76362306a36Sopenharmony_ci * for mtk smi gen 1, we need to get the ao(always on) base to config 76462306a36Sopenharmony_ci * m4u port, and we need to enable the aync clock for transform the smi 76562306a36Sopenharmony_ci * clock into emi clock domain, but for mtk smi gen2, there's no smi ao 76662306a36Sopenharmony_ci * base. 76762306a36Sopenharmony_ci */ 76862306a36Sopenharmony_ci if (common->plat->type == MTK_SMI_GEN1) { 76962306a36Sopenharmony_ci common->smi_ao_base = devm_platform_ioremap_resource(pdev, 0); 77062306a36Sopenharmony_ci if (IS_ERR(common->smi_ao_base)) 77162306a36Sopenharmony_ci return PTR_ERR(common->smi_ao_base); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci common->clk_async = devm_clk_get(dev, "async"); 77462306a36Sopenharmony_ci if (IS_ERR(common->clk_async)) 77562306a36Sopenharmony_ci return PTR_ERR(common->clk_async); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci ret = clk_prepare_enable(common->clk_async); 77862306a36Sopenharmony_ci if (ret) 77962306a36Sopenharmony_ci return ret; 78062306a36Sopenharmony_ci } else { 78162306a36Sopenharmony_ci common->base = devm_platform_ioremap_resource(pdev, 0); 78262306a36Sopenharmony_ci if (IS_ERR(common->base)) 78362306a36Sopenharmony_ci return PTR_ERR(common->base); 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci /* link its smi-common if this is smi-sub-common */ 78762306a36Sopenharmony_ci if (common->plat->type == MTK_SMI_GEN2_SUB_COMM) { 78862306a36Sopenharmony_ci ret = mtk_smi_device_link_common(dev, &common->smi_common_dev); 78962306a36Sopenharmony_ci if (ret < 0) 79062306a36Sopenharmony_ci return ret; 79162306a36Sopenharmony_ci } 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci pm_runtime_enable(dev); 79462306a36Sopenharmony_ci platform_set_drvdata(pdev, common); 79562306a36Sopenharmony_ci return 0; 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic int mtk_smi_common_remove(struct platform_device *pdev) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci struct mtk_smi *common = dev_get_drvdata(&pdev->dev); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci if (common->plat->type == MTK_SMI_GEN2_SUB_COMM) 80362306a36Sopenharmony_ci device_link_remove(&pdev->dev, common->smi_common_dev); 80462306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 80562306a36Sopenharmony_ci return 0; 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_cistatic int __maybe_unused mtk_smi_common_resume(struct device *dev) 80962306a36Sopenharmony_ci{ 81062306a36Sopenharmony_ci struct mtk_smi *common = dev_get_drvdata(dev); 81162306a36Sopenharmony_ci const struct mtk_smi_reg_pair *init = common->plat->init; 81262306a36Sopenharmony_ci u32 bus_sel = common->plat->bus_sel; /* default is 0 */ 81362306a36Sopenharmony_ci int ret, i; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci ret = clk_bulk_prepare_enable(common->clk_num, common->clks); 81662306a36Sopenharmony_ci if (ret) 81762306a36Sopenharmony_ci return ret; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci if (common->plat->type != MTK_SMI_GEN2) 82062306a36Sopenharmony_ci return 0; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci for (i = 0; i < SMI_COMMON_INIT_REGS_NR && init && init[i].offset; i++) 82362306a36Sopenharmony_ci writel_relaxed(init[i].value, common->base + init[i].offset); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci writel(bus_sel, common->base + SMI_BUS_SEL); 82662306a36Sopenharmony_ci return 0; 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_cistatic int __maybe_unused mtk_smi_common_suspend(struct device *dev) 83062306a36Sopenharmony_ci{ 83162306a36Sopenharmony_ci struct mtk_smi *common = dev_get_drvdata(dev); 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci clk_bulk_disable_unprepare(common->clk_num, common->clks); 83462306a36Sopenharmony_ci return 0; 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_cistatic const struct dev_pm_ops smi_common_pm_ops = { 83862306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(mtk_smi_common_suspend, mtk_smi_common_resume, NULL) 83962306a36Sopenharmony_ci SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 84062306a36Sopenharmony_ci pm_runtime_force_resume) 84162306a36Sopenharmony_ci}; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_cistatic struct platform_driver mtk_smi_common_driver = { 84462306a36Sopenharmony_ci .probe = mtk_smi_common_probe, 84562306a36Sopenharmony_ci .remove = mtk_smi_common_remove, 84662306a36Sopenharmony_ci .driver = { 84762306a36Sopenharmony_ci .name = "mtk-smi-common", 84862306a36Sopenharmony_ci .of_match_table = mtk_smi_common_of_ids, 84962306a36Sopenharmony_ci .pm = &smi_common_pm_ops, 85062306a36Sopenharmony_ci } 85162306a36Sopenharmony_ci}; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cistatic struct platform_driver * const smidrivers[] = { 85462306a36Sopenharmony_ci &mtk_smi_common_driver, 85562306a36Sopenharmony_ci &mtk_smi_larb_driver, 85662306a36Sopenharmony_ci}; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_cistatic int __init mtk_smi_init(void) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci return platform_register_drivers(smidrivers, ARRAY_SIZE(smidrivers)); 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_cimodule_init(mtk_smi_init); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_cistatic void __exit mtk_smi_exit(void) 86562306a36Sopenharmony_ci{ 86662306a36Sopenharmony_ci platform_unregister_drivers(smidrivers, ARRAY_SIZE(smidrivers)); 86762306a36Sopenharmony_ci} 86862306a36Sopenharmony_cimodule_exit(mtk_smi_exit); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ciMODULE_DESCRIPTION("MediaTek SMI driver"); 87162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 872