diff options
Diffstat (limited to 'drivers/soc/mediatek')
-rw-r--r-- | drivers/soc/mediatek/Kconfig | 54 | ||||
-rw-r--r-- | drivers/soc/mediatek/Makefile | 6 | ||||
-rw-r--r-- | drivers/soc/mediatek/mtk-cmdq-helper.c | 537 | ||||
-rw-r--r-- | drivers/soc/mediatek/mtk-infracfg.c | 79 | ||||
-rw-r--r-- | drivers/soc/mediatek/mtk-mmsys.c | 376 | ||||
-rw-r--r-- | drivers/soc/mediatek/mtk-pmic-wrap.c | 2186 | ||||
-rw-r--r-- | drivers/soc/mediatek/mtk-scpsys.c | 1147 |
7 files changed, 4385 insertions, 0 deletions
diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig new file mode 100644 index 000000000..59a56cd79 --- /dev/null +++ b/drivers/soc/mediatek/Kconfig @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# MediaTek SoC drivers +# +menu "MediaTek SoC drivers" + depends on ARCH_MEDIATEK || COMPILE_TEST + +config MTK_CMDQ + tristate "MediaTek CMDQ Support" + depends on ARCH_MEDIATEK || COMPILE_TEST + select MAILBOX + select MTK_CMDQ_MBOX + select MTK_INFRACFG + help + Say yes here to add support for the MediaTek Command Queue (CMDQ) + driver. The CMDQ is used to help read/write registers with critical + time limitation, such as updating display configuration during the + vblank. + +config MTK_INFRACFG + bool "MediaTek INFRACFG Support" + select REGMAP + help + Say yes here to add support for the MediaTek INFRACFG controller. The + INFRACFG controller contains various infrastructure registers not + directly associated to any device. + +config MTK_PMIC_WRAP + tristate "MediaTek PMIC Wrapper Support" + depends on RESET_CONTROLLER + select REGMAP + help + Say yes here to add support for MediaTek PMIC Wrapper found + on different MediaTek SoCs. The PMIC wrapper is a proprietary + hardware to connect the PMIC. + +config MTK_SCPSYS + bool "MediaTek SCPSYS Support" + default ARCH_MEDIATEK + select REGMAP + select MTK_INFRACFG + select PM_GENERIC_DOMAINS if PM + help + Say yes here to add support for the MediaTek SCPSYS power domain + driver. + +config MTK_MMSYS + bool "MediaTek MMSYS Support" + default ARCH_MEDIATEK + help + Say yes here to add support for the MediaTek Multimedia + Subsystem (MMSYS). + +endmenu diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile new file mode 100644 index 000000000..01f9f8736 --- /dev/null +++ b/drivers/soc/mediatek/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq-helper.o +obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o +obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o +obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o +obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o diff --git a/drivers/soc/mediatek/mtk-cmdq-helper.c b/drivers/soc/mediatek/mtk-cmdq-helper.c new file mode 100644 index 000000000..505651b0d --- /dev/null +++ b/drivers/soc/mediatek/mtk-cmdq-helper.c @@ -0,0 +1,537 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2018 MediaTek Inc. + +#include <linux/completion.h> +#include <linux/errno.h> +#include <linux/dma-mapping.h> +#include <linux/module.h> +#include <linux/mailbox_controller.h> +#include <linux/soc/mediatek/mtk-cmdq.h> + +#define CMDQ_WRITE_ENABLE_MASK BIT(0) +#define CMDQ_POLL_ENABLE_MASK BIT(0) +#define CMDQ_EOC_IRQ_EN BIT(0) +#define CMDQ_REG_TYPE 1 +#define CMDQ_JUMP_RELATIVE 1 + +struct cmdq_instruction { + union { + u32 value; + u32 mask; + struct { + u16 arg_c; + u16 src_reg; + }; + }; + union { + u16 offset; + u16 event; + u16 reg_dst; + }; + union { + u8 subsys; + struct { + u8 sop:5; + u8 arg_c_t:1; + u8 src_t:1; + u8 dst_t:1; + }; + }; + u8 op; +}; + +int cmdq_dev_get_client_reg(struct device *dev, + struct cmdq_client_reg *client_reg, int idx) +{ + struct of_phandle_args spec; + int err; + + if (!client_reg) + return -ENOENT; + + err = of_parse_phandle_with_fixed_args(dev->of_node, + "mediatek,gce-client-reg", + 3, idx, &spec); + if (err < 0) { + dev_err(dev, + "error %d can't parse gce-client-reg property (%d)", + err, idx); + + return err; + } + + client_reg->subsys = (u8)spec.args[0]; + client_reg->offset = (u16)spec.args[1]; + client_reg->size = (u16)spec.args[2]; + of_node_put(spec.np); + + return 0; +} +EXPORT_SYMBOL(cmdq_dev_get_client_reg); + +static void cmdq_client_timeout(struct timer_list *t) +{ + struct cmdq_client *client = from_timer(client, t, timer); + + dev_err(client->client.dev, "cmdq timeout!\n"); +} + +struct cmdq_client *cmdq_mbox_create(struct device *dev, int index, u32 timeout) +{ + struct cmdq_client *client; + + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return (struct cmdq_client *)-ENOMEM; + + client->timeout_ms = timeout; + if (timeout != CMDQ_NO_TIMEOUT) { + spin_lock_init(&client->lock); + timer_setup(&client->timer, cmdq_client_timeout, 0); + } + client->pkt_cnt = 0; + client->client.dev = dev; + client->client.tx_block = false; + client->client.knows_txdone = true; + client->chan = mbox_request_channel(&client->client, index); + + if (IS_ERR(client->chan)) { + long err; + + dev_err(dev, "failed to request channel\n"); + err = PTR_ERR(client->chan); + kfree(client); + + return ERR_PTR(err); + } + + return client; +} +EXPORT_SYMBOL(cmdq_mbox_create); + +void cmdq_mbox_destroy(struct cmdq_client *client) +{ + if (client->timeout_ms != CMDQ_NO_TIMEOUT) { + spin_lock(&client->lock); + del_timer_sync(&client->timer); + spin_unlock(&client->lock); + } + mbox_free_channel(client->chan); + kfree(client); +} +EXPORT_SYMBOL(cmdq_mbox_destroy); + +struct cmdq_pkt *cmdq_pkt_create(struct cmdq_client *client, size_t size) +{ + struct cmdq_pkt *pkt; + struct device *dev; + dma_addr_t dma_addr; + + pkt = kzalloc(sizeof(*pkt), GFP_KERNEL); + if (!pkt) + return ERR_PTR(-ENOMEM); + pkt->va_base = kzalloc(size, GFP_KERNEL); + if (!pkt->va_base) { + kfree(pkt); + return ERR_PTR(-ENOMEM); + } + pkt->buf_size = size; + pkt->cl = (void *)client; + + dev = client->chan->mbox->dev; + dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, dma_addr)) { + dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size); + kfree(pkt->va_base); + kfree(pkt); + return ERR_PTR(-ENOMEM); + } + + pkt->pa_base = dma_addr; + + return pkt; +} +EXPORT_SYMBOL(cmdq_pkt_create); + +void cmdq_pkt_destroy(struct cmdq_pkt *pkt) +{ + struct cmdq_client *client = (struct cmdq_client *)pkt->cl; + + dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size, + DMA_TO_DEVICE); + kfree(pkt->va_base); + kfree(pkt); +} +EXPORT_SYMBOL(cmdq_pkt_destroy); + +static int cmdq_pkt_append_command(struct cmdq_pkt *pkt, + struct cmdq_instruction inst) +{ + struct cmdq_instruction *cmd_ptr; + + if (unlikely(pkt->cmd_buf_size + CMDQ_INST_SIZE > pkt->buf_size)) { + /* + * In the case of allocated buffer size (pkt->buf_size) is used + * up, the real required size (pkt->cmdq_buf_size) is still + * increased, so that the user knows how much memory should be + * ultimately allocated after appending all commands and + * flushing the command packet. Therefor, the user can call + * cmdq_pkt_create() again with the real required buffer size. + */ + pkt->cmd_buf_size += CMDQ_INST_SIZE; + WARN_ONCE(1, "%s: buffer size %u is too small !\n", + __func__, (u32)pkt->buf_size); + return -ENOMEM; + } + + cmd_ptr = pkt->va_base + pkt->cmd_buf_size; + *cmd_ptr = inst; + pkt->cmd_buf_size += CMDQ_INST_SIZE; + + return 0; +} + +int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value) +{ + struct cmdq_instruction inst; + + inst.op = CMDQ_CODE_WRITE; + inst.value = value; + inst.offset = offset; + inst.subsys = subsys; + + return cmdq_pkt_append_command(pkt, inst); +} +EXPORT_SYMBOL(cmdq_pkt_write); + +int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys, + u16 offset, u32 value, u32 mask) +{ + struct cmdq_instruction inst = { {0} }; + u16 offset_mask = offset; + int err; + + if (mask != 0xffffffff) { + inst.op = CMDQ_CODE_MASK; + inst.mask = ~mask; + err = cmdq_pkt_append_command(pkt, inst); + if (err < 0) + return err; + + offset_mask |= CMDQ_WRITE_ENABLE_MASK; + } + err = cmdq_pkt_write(pkt, subsys, offset_mask, value); + + return err; +} +EXPORT_SYMBOL(cmdq_pkt_write_mask); + +int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, u16 addr_low, + u16 reg_idx) +{ + struct cmdq_instruction inst = {}; + + inst.op = CMDQ_CODE_READ_S; + inst.dst_t = CMDQ_REG_TYPE; + inst.sop = high_addr_reg_idx; + inst.reg_dst = reg_idx; + inst.src_reg = addr_low; + + return cmdq_pkt_append_command(pkt, inst); +} +EXPORT_SYMBOL(cmdq_pkt_read_s); + +int cmdq_pkt_write_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, + u16 addr_low, u16 src_reg_idx) +{ + struct cmdq_instruction inst = {}; + + inst.op = CMDQ_CODE_WRITE_S; + inst.src_t = CMDQ_REG_TYPE; + inst.sop = high_addr_reg_idx; + inst.offset = addr_low; + inst.src_reg = src_reg_idx; + + return cmdq_pkt_append_command(pkt, inst); +} +EXPORT_SYMBOL(cmdq_pkt_write_s); + +int cmdq_pkt_write_s_mask(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, + u16 addr_low, u16 src_reg_idx, u32 mask) +{ + struct cmdq_instruction inst = {}; + int err; + + inst.op = CMDQ_CODE_MASK; + inst.mask = ~mask; + err = cmdq_pkt_append_command(pkt, inst); + if (err < 0) + return err; + + inst.mask = 0; + inst.op = CMDQ_CODE_WRITE_S_MASK; + inst.src_t = CMDQ_REG_TYPE; + inst.sop = high_addr_reg_idx; + inst.offset = addr_low; + inst.src_reg = src_reg_idx; + + return cmdq_pkt_append_command(pkt, inst); +} +EXPORT_SYMBOL(cmdq_pkt_write_s_mask); + +int cmdq_pkt_write_s_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx, + u16 addr_low, u32 value) +{ + struct cmdq_instruction inst = {}; + + inst.op = CMDQ_CODE_WRITE_S; + inst.sop = high_addr_reg_idx; + inst.offset = addr_low; + inst.value = value; + + return cmdq_pkt_append_command(pkt, inst); +} +EXPORT_SYMBOL(cmdq_pkt_write_s_value); + +int cmdq_pkt_write_s_mask_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx, + u16 addr_low, u32 value, u32 mask) +{ + struct cmdq_instruction inst = {}; + int err; + + inst.op = CMDQ_CODE_MASK; + inst.mask = ~mask; + err = cmdq_pkt_append_command(pkt, inst); + if (err < 0) + return err; + + inst.op = CMDQ_CODE_WRITE_S_MASK; + inst.sop = high_addr_reg_idx; + inst.offset = addr_low; + inst.value = value; + + return cmdq_pkt_append_command(pkt, inst); +} +EXPORT_SYMBOL(cmdq_pkt_write_s_mask_value); + +int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event, bool clear) +{ + struct cmdq_instruction inst = { {0} }; + u32 clear_option = clear ? CMDQ_WFE_UPDATE : 0; + + if (event >= CMDQ_MAX_EVENT) + return -EINVAL; + + inst.op = CMDQ_CODE_WFE; + inst.value = CMDQ_WFE_OPTION | clear_option; + inst.event = event; + + return cmdq_pkt_append_command(pkt, inst); +} +EXPORT_SYMBOL(cmdq_pkt_wfe); + +int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event) +{ + struct cmdq_instruction inst = { {0} }; + + if (event >= CMDQ_MAX_EVENT) + return -EINVAL; + + inst.op = CMDQ_CODE_WFE; + inst.value = CMDQ_WFE_UPDATE; + inst.event = event; + + return cmdq_pkt_append_command(pkt, inst); +} +EXPORT_SYMBOL(cmdq_pkt_clear_event); + +int cmdq_pkt_set_event(struct cmdq_pkt *pkt, u16 event) +{ + struct cmdq_instruction inst = {}; + + if (event >= CMDQ_MAX_EVENT) + return -EINVAL; + + inst.op = CMDQ_CODE_WFE; + inst.value = CMDQ_WFE_UPDATE | CMDQ_WFE_UPDATE_VALUE; + inst.event = event; + + return cmdq_pkt_append_command(pkt, inst); +} +EXPORT_SYMBOL(cmdq_pkt_set_event); + +int cmdq_pkt_poll(struct cmdq_pkt *pkt, u8 subsys, + u16 offset, u32 value) +{ + struct cmdq_instruction inst = { {0} }; + int err; + + inst.op = CMDQ_CODE_POLL; + inst.value = value; + inst.offset = offset; + inst.subsys = subsys; + err = cmdq_pkt_append_command(pkt, inst); + + return err; +} +EXPORT_SYMBOL(cmdq_pkt_poll); + +int cmdq_pkt_poll_mask(struct cmdq_pkt *pkt, u8 subsys, + u16 offset, u32 value, u32 mask) +{ + struct cmdq_instruction inst = { {0} }; + int err; + + inst.op = CMDQ_CODE_MASK; + inst.mask = ~mask; + err = cmdq_pkt_append_command(pkt, inst); + if (err < 0) + return err; + + offset = offset | CMDQ_POLL_ENABLE_MASK; + err = cmdq_pkt_poll(pkt, subsys, offset, value); + + return err; +} +EXPORT_SYMBOL(cmdq_pkt_poll_mask); + +int cmdq_pkt_assign(struct cmdq_pkt *pkt, u16 reg_idx, u32 value) +{ + struct cmdq_instruction inst = {}; + + inst.op = CMDQ_CODE_LOGIC; + inst.dst_t = CMDQ_REG_TYPE; + inst.reg_dst = reg_idx; + inst.value = value; + return cmdq_pkt_append_command(pkt, inst); +} +EXPORT_SYMBOL(cmdq_pkt_assign); + +int cmdq_pkt_jump(struct cmdq_pkt *pkt, dma_addr_t addr) +{ + struct cmdq_instruction inst = {}; + + inst.op = CMDQ_CODE_JUMP; + inst.offset = CMDQ_JUMP_RELATIVE; + inst.value = addr >> + cmdq_get_shift_pa(((struct cmdq_client *)pkt->cl)->chan); + return cmdq_pkt_append_command(pkt, inst); +} +EXPORT_SYMBOL(cmdq_pkt_jump); + +int cmdq_pkt_finalize(struct cmdq_pkt *pkt) +{ + struct cmdq_instruction inst = { {0} }; + int err; + + /* insert EOC and generate IRQ for each command iteration */ + inst.op = CMDQ_CODE_EOC; + inst.value = CMDQ_EOC_IRQ_EN; + err = cmdq_pkt_append_command(pkt, inst); + if (err < 0) + return err; + + /* JUMP to end */ + inst.op = CMDQ_CODE_JUMP; + inst.value = CMDQ_JUMP_PASS >> + cmdq_get_shift_pa(((struct cmdq_client *)pkt->cl)->chan); + err = cmdq_pkt_append_command(pkt, inst); + + return err; +} +EXPORT_SYMBOL(cmdq_pkt_finalize); + +static void cmdq_pkt_flush_async_cb(struct cmdq_cb_data data) +{ + struct cmdq_pkt *pkt = (struct cmdq_pkt *)data.data; + struct cmdq_task_cb *cb = &pkt->cb; + struct cmdq_client *client = (struct cmdq_client *)pkt->cl; + + if (client->timeout_ms != CMDQ_NO_TIMEOUT) { + unsigned long flags = 0; + + spin_lock_irqsave(&client->lock, flags); + if (--client->pkt_cnt == 0) + del_timer(&client->timer); + else + mod_timer(&client->timer, jiffies + + msecs_to_jiffies(client->timeout_ms)); + spin_unlock_irqrestore(&client->lock, flags); + } + + dma_sync_single_for_cpu(client->chan->mbox->dev, pkt->pa_base, + pkt->cmd_buf_size, DMA_TO_DEVICE); + if (cb->cb) { + data.data = cb->data; + cb->cb(data); + } +} + +int cmdq_pkt_flush_async(struct cmdq_pkt *pkt, cmdq_async_flush_cb cb, + void *data) +{ + int err; + unsigned long flags = 0; + struct cmdq_client *client = (struct cmdq_client *)pkt->cl; + + pkt->cb.cb = cb; + pkt->cb.data = data; + pkt->async_cb.cb = cmdq_pkt_flush_async_cb; + pkt->async_cb.data = pkt; + + dma_sync_single_for_device(client->chan->mbox->dev, pkt->pa_base, + pkt->cmd_buf_size, DMA_TO_DEVICE); + + if (client->timeout_ms != CMDQ_NO_TIMEOUT) { + spin_lock_irqsave(&client->lock, flags); + if (client->pkt_cnt++ == 0) + mod_timer(&client->timer, jiffies + + msecs_to_jiffies(client->timeout_ms)); + spin_unlock_irqrestore(&client->lock, flags); + } + + err = mbox_send_message(client->chan, pkt); + if (err < 0) + return err; + /* We can send next packet immediately, so just call txdone. */ + mbox_client_txdone(client->chan, 0); + + return 0; +} +EXPORT_SYMBOL(cmdq_pkt_flush_async); + +struct cmdq_flush_completion { + struct completion cmplt; + bool err; +}; + +static void cmdq_pkt_flush_cb(struct cmdq_cb_data data) +{ + struct cmdq_flush_completion *cmplt; + + cmplt = (struct cmdq_flush_completion *)data.data; + if (data.sta != CMDQ_CB_NORMAL) + cmplt->err = true; + else + cmplt->err = false; + complete(&cmplt->cmplt); +} + +int cmdq_pkt_flush(struct cmdq_pkt *pkt) +{ + struct cmdq_flush_completion cmplt; + int err; + + init_completion(&cmplt.cmplt); + err = cmdq_pkt_flush_async(pkt, cmdq_pkt_flush_cb, &cmplt); + if (err < 0) + return err; + wait_for_completion(&cmplt.cmplt); + + return cmplt.err ? -EFAULT : 0; +} +EXPORT_SYMBOL(cmdq_pkt_flush); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/mediatek/mtk-infracfg.c b/drivers/soc/mediatek/mtk-infracfg.c new file mode 100644 index 000000000..4a123796a --- /dev/null +++ b/drivers/soc/mediatek/mtk-infracfg.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015 Pengutronix, Sascha Hauer <kernel@pengutronix.de> + */ + +#include <linux/export.h> +#include <linux/jiffies.h> +#include <linux/regmap.h> +#include <linux/soc/mediatek/infracfg.h> +#include <asm/processor.h> + +#define MTK_POLL_DELAY_US 10 +#define MTK_POLL_TIMEOUT (jiffies_to_usecs(HZ)) + +#define INFRA_TOPAXI_PROTECTEN 0x0220 +#define INFRA_TOPAXI_PROTECTSTA1 0x0228 +#define INFRA_TOPAXI_PROTECTEN_SET 0x0260 +#define INFRA_TOPAXI_PROTECTEN_CLR 0x0264 + +/** + * mtk_infracfg_set_bus_protection - enable bus protection + * @infracfg: The infracfg regmap + * @mask: The mask containing the protection bits to be enabled. + * @reg_update: The boolean flag determines to set the protection bits + * by regmap_update_bits with enable register(PROTECTEN) or + * by regmap_write with set register(PROTECTEN_SET). + * + * This function enables the bus protection bits for disabled power + * domains so that the system does not hang when some unit accesses the + * bus while in power down. + */ +int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask, + bool reg_update) +{ + u32 val; + int ret; + + if (reg_update) + regmap_update_bits(infracfg, INFRA_TOPAXI_PROTECTEN, mask, + mask); + else + regmap_write(infracfg, INFRA_TOPAXI_PROTECTEN_SET, mask); + + ret = regmap_read_poll_timeout(infracfg, INFRA_TOPAXI_PROTECTSTA1, + val, (val & mask) == mask, + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); + + return ret; +} + +/** + * mtk_infracfg_clear_bus_protection - disable bus protection + * @infracfg: The infracfg regmap + * @mask: The mask containing the protection bits to be disabled. + * @reg_update: The boolean flag determines to clear the protection bits + * by regmap_update_bits with enable register(PROTECTEN) or + * by regmap_write with clear register(PROTECTEN_CLR). + * + * This function disables the bus protection bits previously enabled with + * mtk_infracfg_set_bus_protection. + */ + +int mtk_infracfg_clear_bus_protection(struct regmap *infracfg, u32 mask, + bool reg_update) +{ + int ret; + u32 val; + + if (reg_update) + regmap_update_bits(infracfg, INFRA_TOPAXI_PROTECTEN, mask, 0); + else + regmap_write(infracfg, INFRA_TOPAXI_PROTECTEN_CLR, mask); + + ret = regmap_read_poll_timeout(infracfg, INFRA_TOPAXI_PROTECTSTA1, + val, !(val & mask), + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); + + return ret; +} diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c new file mode 100644 index 000000000..36ad66bb2 --- /dev/null +++ b/drivers/soc/mediatek/mtk-mmsys.c @@ -0,0 +1,376 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2014 MediaTek Inc. + * Author: James Liao <jamesjj.liao@mediatek.com> + */ + +#include <linux/device.h> +#include <linux/io.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/soc/mediatek/mtk-mmsys.h> + +#define DISP_REG_CONFIG_DISP_OVL0_MOUT_EN 0x040 +#define DISP_REG_CONFIG_DISP_OVL1_MOUT_EN 0x044 +#define DISP_REG_CONFIG_DISP_OD_MOUT_EN 0x048 +#define DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN 0x04c +#define DISP_REG_CONFIG_DISP_UFOE_MOUT_EN 0x050 +#define DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0x084 +#define DISP_REG_CONFIG_DISP_COLOR1_SEL_IN 0x088 +#define DISP_REG_CONFIG_DSIE_SEL_IN 0x0a4 +#define DISP_REG_CONFIG_DSIO_SEL_IN 0x0a8 +#define DISP_REG_CONFIG_DPI_SEL_IN 0x0ac +#define DISP_REG_CONFIG_DISP_RDMA2_SOUT 0x0b8 +#define DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN 0x0c4 +#define DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN 0x0c8 +#define DISP_REG_CONFIG_MMSYS_CG_CON0 0x100 + +#define DISP_REG_CONFIG_DISP_OVL_MOUT_EN 0x030 +#define DISP_REG_CONFIG_OUT_SEL 0x04c +#define DISP_REG_CONFIG_DSI_SEL 0x050 +#define DISP_REG_CONFIG_DPI_SEL 0x064 + +#define OVL0_MOUT_EN_COLOR0 0x1 +#define OD_MOUT_EN_RDMA0 0x1 +#define OD1_MOUT_EN_RDMA1 BIT(16) +#define UFOE_MOUT_EN_DSI0 0x1 +#define COLOR0_SEL_IN_OVL0 0x1 +#define OVL1_MOUT_EN_COLOR1 0x1 +#define GAMMA_MOUT_EN_RDMA1 0x1 +#define RDMA0_SOUT_DPI0 0x2 +#define RDMA0_SOUT_DPI1 0x3 +#define RDMA0_SOUT_DSI1 0x1 +#define RDMA0_SOUT_DSI2 0x4 +#define RDMA0_SOUT_DSI3 0x5 +#define RDMA1_SOUT_DPI0 0x2 +#define RDMA1_SOUT_DPI1 0x3 +#define RDMA1_SOUT_DSI1 0x1 +#define RDMA1_SOUT_DSI2 0x4 +#define RDMA1_SOUT_DSI3 0x5 +#define RDMA2_SOUT_DPI0 0x2 +#define RDMA2_SOUT_DPI1 0x3 +#define RDMA2_SOUT_DSI1 0x1 +#define RDMA2_SOUT_DSI2 0x4 +#define RDMA2_SOUT_DSI3 0x5 +#define DPI0_SEL_IN_RDMA1 0x1 +#define DPI0_SEL_IN_RDMA2 0x3 +#define DPI1_SEL_IN_RDMA1 (0x1 << 8) +#define DPI1_SEL_IN_RDMA2 (0x3 << 8) +#define DSI0_SEL_IN_RDMA1 0x1 +#define DSI0_SEL_IN_RDMA2 0x4 +#define DSI1_SEL_IN_RDMA1 0x1 +#define DSI1_SEL_IN_RDMA2 0x4 +#define DSI2_SEL_IN_RDMA1 (0x1 << 16) +#define DSI2_SEL_IN_RDMA2 (0x4 << 16) +#define DSI3_SEL_IN_RDMA1 (0x1 << 16) +#define DSI3_SEL_IN_RDMA2 (0x4 << 16) +#define COLOR1_SEL_IN_OVL1 0x1 + +#define OVL_MOUT_EN_RDMA 0x1 +#define BLS_TO_DSI_RDMA1_TO_DPI1 0x8 +#define BLS_TO_DPI_RDMA1_TO_DSI 0x2 +#define DSI_SEL_IN_BLS 0x0 +#define DPI_SEL_IN_BLS 0x0 +#define DSI_SEL_IN_RDMA 0x1 + +struct mtk_mmsys_driver_data { + const char *clk_driver; +}; + +static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = { + .clk_driver = "clk-mt2701-mm", +}; + +static const struct mtk_mmsys_driver_data mt2712_mmsys_driver_data = { + .clk_driver = "clk-mt2712-mm", +}; + +static const struct mtk_mmsys_driver_data mt6779_mmsys_driver_data = { + .clk_driver = "clk-mt6779-mm", +}; + +static const struct mtk_mmsys_driver_data mt6797_mmsys_driver_data = { + .clk_driver = "clk-mt6797-mm", +}; + +static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = { + .clk_driver = "clk-mt8173-mm", +}; + +static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = { + .clk_driver = "clk-mt8183-mm", +}; + +static unsigned int mtk_mmsys_ddp_mout_en(enum mtk_ddp_comp_id cur, + enum mtk_ddp_comp_id next, + unsigned int *addr) +{ + unsigned int value; + + if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_COLOR0) { + *addr = DISP_REG_CONFIG_DISP_OVL0_MOUT_EN; + value = OVL0_MOUT_EN_COLOR0; + } else if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_RDMA0) { + *addr = DISP_REG_CONFIG_DISP_OVL_MOUT_EN; + value = OVL_MOUT_EN_RDMA; + } else if (cur == DDP_COMPONENT_OD0 && next == DDP_COMPONENT_RDMA0) { + *addr = DISP_REG_CONFIG_DISP_OD_MOUT_EN; + value = OD_MOUT_EN_RDMA0; + } else if (cur == DDP_COMPONENT_UFOE && next == DDP_COMPONENT_DSI0) { + *addr = DISP_REG_CONFIG_DISP_UFOE_MOUT_EN; + value = UFOE_MOUT_EN_DSI0; + } else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) { + *addr = DISP_REG_CONFIG_DISP_OVL1_MOUT_EN; + value = OVL1_MOUT_EN_COLOR1; + } else if (cur == DDP_COMPONENT_GAMMA && next == DDP_COMPONENT_RDMA1) { + *addr = DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN; + value = GAMMA_MOUT_EN_RDMA1; + } else if (cur == DDP_COMPONENT_OD1 && next == DDP_COMPONENT_RDMA1) { + *addr = DISP_REG_CONFIG_DISP_OD_MOUT_EN; + value = OD1_MOUT_EN_RDMA1; + } else if (cur == DDP_COMPONENT_RDMA0 && next == DDP_COMPONENT_DPI0) { + *addr = DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN; + value = RDMA0_SOUT_DPI0; + } else if (cur == DDP_COMPONENT_RDMA0 && next == DDP_COMPONENT_DPI1) { + *addr = DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN; + value = RDMA0_SOUT_DPI1; + } else if (cur == DDP_COMPONENT_RDMA0 && next == DDP_COMPONENT_DSI1) { + *addr = DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN; + value = RDMA0_SOUT_DSI1; + } else if (cur == DDP_COMPONENT_RDMA0 && next == DDP_COMPONENT_DSI2) { + *addr = DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN; + value = RDMA0_SOUT_DSI2; + } else if (cur == DDP_COMPONENT_RDMA0 && next == DDP_COMPONENT_DSI3) { + *addr = DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN; + value = RDMA0_SOUT_DSI3; + } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI1) { + *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; + value = RDMA1_SOUT_DSI1; + } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI2) { + *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; + value = RDMA1_SOUT_DSI2; + } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI3) { + *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; + value = RDMA1_SOUT_DSI3; + } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) { + *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; + value = RDMA1_SOUT_DPI0; + } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI1) { + *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; + value = RDMA1_SOUT_DPI1; + } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DPI0) { + *addr = DISP_REG_CONFIG_DISP_RDMA2_SOUT; + value = RDMA2_SOUT_DPI0; + } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DPI1) { + *addr = DISP_REG_CONFIG_DISP_RDMA2_SOUT; + value = RDMA2_SOUT_DPI1; + } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI1) { + *addr = DISP_REG_CONFIG_DISP_RDMA2_SOUT; + value = RDMA2_SOUT_DSI1; + } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI2) { + *addr = DISP_REG_CONFIG_DISP_RDMA2_SOUT; + value = RDMA2_SOUT_DSI2; + } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI3) { + *addr = DISP_REG_CONFIG_DISP_RDMA2_SOUT; + value = RDMA2_SOUT_DSI3; + } else { + value = 0; + } + + return value; +} + +static unsigned int mtk_mmsys_ddp_sel_in(enum mtk_ddp_comp_id cur, + enum mtk_ddp_comp_id next, + unsigned int *addr) +{ + unsigned int value; + + if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_COLOR0) { + *addr = DISP_REG_CONFIG_DISP_COLOR0_SEL_IN; + value = COLOR0_SEL_IN_OVL0; + } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) { + *addr = DISP_REG_CONFIG_DPI_SEL_IN; + value = DPI0_SEL_IN_RDMA1; + } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI1) { + *addr = DISP_REG_CONFIG_DPI_SEL_IN; + value = DPI1_SEL_IN_RDMA1; + } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI0) { + *addr = DISP_REG_CONFIG_DSIE_SEL_IN; + value = DSI0_SEL_IN_RDMA1; + } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI1) { + *addr = DISP_REG_CONFIG_DSIO_SEL_IN; + value = DSI1_SEL_IN_RDMA1; + } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI2) { + *addr = DISP_REG_CONFIG_DSIE_SEL_IN; + value = DSI2_SEL_IN_RDMA1; + } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI3) { + *addr = DISP_REG_CONFIG_DSIO_SEL_IN; + value = DSI3_SEL_IN_RDMA1; + } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DPI0) { + *addr = DISP_REG_CONFIG_DPI_SEL_IN; + value = DPI0_SEL_IN_RDMA2; + } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DPI1) { + *addr = DISP_REG_CONFIG_DPI_SEL_IN; + value = DPI1_SEL_IN_RDMA2; + } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI0) { + *addr = DISP_REG_CONFIG_DSIE_SEL_IN; + value = DSI0_SEL_IN_RDMA2; + } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI1) { + *addr = DISP_REG_CONFIG_DSIO_SEL_IN; + value = DSI1_SEL_IN_RDMA2; + } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI2) { + *addr = DISP_REG_CONFIG_DSIE_SEL_IN; + value = DSI2_SEL_IN_RDMA2; + } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI3) { + *addr = DISP_REG_CONFIG_DSIE_SEL_IN; + value = DSI3_SEL_IN_RDMA2; + } else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) { + *addr = DISP_REG_CONFIG_DISP_COLOR1_SEL_IN; + value = COLOR1_SEL_IN_OVL1; + } else if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0) { + *addr = DISP_REG_CONFIG_DSI_SEL; + value = DSI_SEL_IN_BLS; + } else { + value = 0; + } + + return value; +} + +static void mtk_mmsys_ddp_sout_sel(void __iomem *config_regs, + enum mtk_ddp_comp_id cur, + enum mtk_ddp_comp_id next) +{ + if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0) { + writel_relaxed(BLS_TO_DSI_RDMA1_TO_DPI1, + config_regs + DISP_REG_CONFIG_OUT_SEL); + } else if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DPI0) { + writel_relaxed(BLS_TO_DPI_RDMA1_TO_DSI, + config_regs + DISP_REG_CONFIG_OUT_SEL); + writel_relaxed(DSI_SEL_IN_RDMA, + config_regs + DISP_REG_CONFIG_DSI_SEL); + writel_relaxed(DPI_SEL_IN_BLS, + config_regs + DISP_REG_CONFIG_DPI_SEL); + } +} + +void mtk_mmsys_ddp_connect(struct device *dev, + enum mtk_ddp_comp_id cur, + enum mtk_ddp_comp_id next) +{ + void __iomem *config_regs = dev_get_drvdata(dev); + unsigned int addr, value, reg; + + value = mtk_mmsys_ddp_mout_en(cur, next, &addr); + if (value) { + reg = readl_relaxed(config_regs + addr) | value; + writel_relaxed(reg, config_regs + addr); + } + + mtk_mmsys_ddp_sout_sel(config_regs, cur, next); + + value = mtk_mmsys_ddp_sel_in(cur, next, &addr); + if (value) { + reg = readl_relaxed(config_regs + addr) | value; + writel_relaxed(reg, config_regs + addr); + } +} +EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_connect); + +void mtk_mmsys_ddp_disconnect(struct device *dev, + enum mtk_ddp_comp_id cur, + enum mtk_ddp_comp_id next) +{ + void __iomem *config_regs = dev_get_drvdata(dev); + unsigned int addr, value, reg; + + value = mtk_mmsys_ddp_mout_en(cur, next, &addr); + if (value) { + reg = readl_relaxed(config_regs + addr) & ~value; + writel_relaxed(reg, config_regs + addr); + } + + value = mtk_mmsys_ddp_sel_in(cur, next, &addr); + if (value) { + reg = readl_relaxed(config_regs + addr) & ~value; + writel_relaxed(reg, config_regs + addr); + } +} +EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_disconnect); + +static int mtk_mmsys_probe(struct platform_device *pdev) +{ + const struct mtk_mmsys_driver_data *data; + struct device *dev = &pdev->dev; + struct platform_device *clks; + struct platform_device *drm; + void __iomem *config_regs; + struct resource *mem; + int ret; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + config_regs = devm_ioremap_resource(dev, mem); + if (IS_ERR(config_regs)) { + ret = PTR_ERR(config_regs); + dev_err(dev, "Failed to ioremap mmsys-config resource: %d\n", + ret); + return ret; + } + + platform_set_drvdata(pdev, config_regs); + + data = of_device_get_match_data(&pdev->dev); + + clks = platform_device_register_data(&pdev->dev, data->clk_driver, + PLATFORM_DEVID_AUTO, NULL, 0); + if (IS_ERR(clks)) + return PTR_ERR(clks); + + drm = platform_device_register_data(&pdev->dev, "mediatek-drm", + PLATFORM_DEVID_AUTO, NULL, 0); + if (IS_ERR(drm)) { + platform_device_unregister(clks); + return PTR_ERR(drm); + } + + return 0; +} + +static const struct of_device_id of_match_mtk_mmsys[] = { + { + .compatible = "mediatek,mt2701-mmsys", + .data = &mt2701_mmsys_driver_data, + }, + { + .compatible = "mediatek,mt2712-mmsys", + .data = &mt2712_mmsys_driver_data, + }, + { + .compatible = "mediatek,mt6779-mmsys", + .data = &mt6779_mmsys_driver_data, + }, + { + .compatible = "mediatek,mt6797-mmsys", + .data = &mt6797_mmsys_driver_data, + }, + { + .compatible = "mediatek,mt8173-mmsys", + .data = &mt8173_mmsys_driver_data, + }, + { + .compatible = "mediatek,mt8183-mmsys", + .data = &mt8183_mmsys_driver_data, + }, + { } +}; + +static struct platform_driver mtk_mmsys_drv = { + .driver = { + .name = "mtk-mmsys", + .of_match_table = of_match_mtk_mmsys, + }, + .probe = mtk_mmsys_probe, +}; + +builtin_platform_driver(mtk_mmsys_drv); diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c new file mode 100644 index 000000000..5d34e8b9c --- /dev/null +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -0,0 +1,2186 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2014 MediaTek Inc. + * Author: Flora Fu, MediaTek + */ +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/reset.h> + +#define PWRAP_MT8135_BRIDGE_IORD_ARB_EN 0x4 +#define PWRAP_MT8135_BRIDGE_WACS3_EN 0x10 +#define PWRAP_MT8135_BRIDGE_INIT_DONE3 0x14 +#define PWRAP_MT8135_BRIDGE_WACS4_EN 0x24 +#define PWRAP_MT8135_BRIDGE_INIT_DONE4 0x28 +#define PWRAP_MT8135_BRIDGE_INT_EN 0x38 +#define PWRAP_MT8135_BRIDGE_TIMER_EN 0x48 +#define PWRAP_MT8135_BRIDGE_WDT_UNIT 0x50 +#define PWRAP_MT8135_BRIDGE_WDT_SRC_EN 0x54 + +/* macro for wrapper status */ +#define PWRAP_GET_WACS_RDATA(x) (((x) >> 0) & 0x0000ffff) +#define PWRAP_GET_WACS_FSM(x) (((x) >> 16) & 0x00000007) +#define PWRAP_GET_WACS_REQ(x) (((x) >> 19) & 0x00000001) +#define PWRAP_STATE_SYNC_IDLE0 (1 << 20) +#define PWRAP_STATE_INIT_DONE0 (1 << 21) + +/* macro for WACS FSM */ +#define PWRAP_WACS_FSM_IDLE 0x00 +#define PWRAP_WACS_FSM_REQ 0x02 +#define PWRAP_WACS_FSM_WFDLE 0x04 +#define PWRAP_WACS_FSM_WFVLDCLR 0x06 +#define PWRAP_WACS_INIT_DONE 0x01 +#define PWRAP_WACS_WACS_SYNC_IDLE 0x01 +#define PWRAP_WACS_SYNC_BUSY 0x00 + +/* macro for device wrapper default value */ +#define PWRAP_DEW_READ_TEST_VAL 0x5aa5 +#define PWRAP_DEW_WRITE_TEST_VAL 0xa55a + +/* macro for manual command */ +#define PWRAP_MAN_CMD_SPI_WRITE_NEW (1 << 14) +#define PWRAP_MAN_CMD_SPI_WRITE (1 << 13) +#define PWRAP_MAN_CMD_OP_CSH (0x0 << 8) +#define PWRAP_MAN_CMD_OP_CSL (0x1 << 8) +#define PWRAP_MAN_CMD_OP_CK (0x2 << 8) +#define PWRAP_MAN_CMD_OP_OUTS (0x8 << 8) +#define PWRAP_MAN_CMD_OP_OUTD (0x9 << 8) +#define PWRAP_MAN_CMD_OP_OUTQ (0xa << 8) + +/* macro for Watch Dog Timer Source */ +#define PWRAP_WDT_SRC_EN_STAUPD_TRIG (1 << 25) +#define PWRAP_WDT_SRC_EN_HARB_STAUPD_DLE (1 << 20) +#define PWRAP_WDT_SRC_EN_HARB_STAUPD_ALE (1 << 6) +#define PWRAP_WDT_SRC_MASK_ALL 0xffffffff +#define PWRAP_WDT_SRC_MASK_NO_STAUPD ~(PWRAP_WDT_SRC_EN_STAUPD_TRIG | \ + PWRAP_WDT_SRC_EN_HARB_STAUPD_DLE | \ + PWRAP_WDT_SRC_EN_HARB_STAUPD_ALE) + +/* Group of bits used for shown slave capability */ +#define PWRAP_SLV_CAP_SPI BIT(0) +#define PWRAP_SLV_CAP_DUALIO BIT(1) +#define PWRAP_SLV_CAP_SECURITY BIT(2) +#define HAS_CAP(_c, _x) (((_c) & (_x)) == (_x)) + +/* Group of bits used for shown pwrap capability */ +#define PWRAP_CAP_BRIDGE BIT(0) +#define PWRAP_CAP_RESET BIT(1) +#define PWRAP_CAP_DCM BIT(2) +#define PWRAP_CAP_INT1_EN BIT(3) +#define PWRAP_CAP_WDT_SRC1 BIT(4) + +/* defines for slave device wrapper registers */ +enum dew_regs { + PWRAP_DEW_BASE, + PWRAP_DEW_DIO_EN, + PWRAP_DEW_READ_TEST, + PWRAP_DEW_WRITE_TEST, + PWRAP_DEW_CRC_EN, + PWRAP_DEW_CRC_VAL, + PWRAP_DEW_MON_GRP_SEL, + PWRAP_DEW_CIPHER_KEY_SEL, + PWRAP_DEW_CIPHER_IV_SEL, + PWRAP_DEW_CIPHER_RDY, + PWRAP_DEW_CIPHER_MODE, + PWRAP_DEW_CIPHER_SWRST, + + /* MT6323 only regs */ + PWRAP_DEW_CIPHER_EN, + PWRAP_DEW_RDDMY_NO, + + /* MT6358 only regs */ + PWRAP_SMT_CON1, + PWRAP_DRV_CON1, + PWRAP_FILTER_CON0, + PWRAP_GPIO_PULLEN0_CLR, + PWRAP_RG_SPI_CON0, + PWRAP_RG_SPI_RECORD0, + PWRAP_RG_SPI_CON2, + PWRAP_RG_SPI_CON3, + PWRAP_RG_SPI_CON4, + PWRAP_RG_SPI_CON5, + PWRAP_RG_SPI_CON6, + PWRAP_RG_SPI_CON7, + PWRAP_RG_SPI_CON8, + PWRAP_RG_SPI_CON13, + PWRAP_SPISLV_KEY, + + /* MT6359 only regs */ + PWRAP_DEW_CRC_SWRST, + PWRAP_DEW_RG_EN_RECORD, + PWRAP_DEW_RECORD_CMD0, + PWRAP_DEW_RECORD_CMD1, + PWRAP_DEW_RECORD_CMD2, + PWRAP_DEW_RECORD_CMD3, + PWRAP_DEW_RECORD_CMD4, + PWRAP_DEW_RECORD_CMD5, + PWRAP_DEW_RECORD_WDATA0, + PWRAP_DEW_RECORD_WDATA1, + PWRAP_DEW_RECORD_WDATA2, + PWRAP_DEW_RECORD_WDATA3, + PWRAP_DEW_RECORD_WDATA4, + PWRAP_DEW_RECORD_WDATA5, + PWRAP_DEW_RG_ADDR_TARGET, + PWRAP_DEW_RG_ADDR_MASK, + PWRAP_DEW_RG_WDATA_TARGET, + PWRAP_DEW_RG_WDATA_MASK, + PWRAP_DEW_RG_SPI_RECORD_CLR, + PWRAP_DEW_RG_CMD_ALERT_CLR, + + /* MT6397 only regs */ + PWRAP_DEW_EVENT_OUT_EN, + PWRAP_DEW_EVENT_SRC_EN, + PWRAP_DEW_EVENT_SRC, + PWRAP_DEW_EVENT_FLAG, + PWRAP_DEW_MON_FLAG_SEL, + PWRAP_DEW_EVENT_TEST, + PWRAP_DEW_CIPHER_LOAD, + PWRAP_DEW_CIPHER_START, +}; + +static const u32 mt6323_regs[] = { + [PWRAP_DEW_BASE] = 0x0000, + [PWRAP_DEW_DIO_EN] = 0x018a, + [PWRAP_DEW_READ_TEST] = 0x018c, + [PWRAP_DEW_WRITE_TEST] = 0x018e, + [PWRAP_DEW_CRC_EN] = 0x0192, + [PWRAP_DEW_CRC_VAL] = 0x0194, + [PWRAP_DEW_MON_GRP_SEL] = 0x0196, + [PWRAP_DEW_CIPHER_KEY_SEL] = 0x0198, + [PWRAP_DEW_CIPHER_IV_SEL] = 0x019a, + [PWRAP_DEW_CIPHER_EN] = 0x019c, + [PWRAP_DEW_CIPHER_RDY] = 0x019e, + [PWRAP_DEW_CIPHER_MODE] = 0x01a0, + [PWRAP_DEW_CIPHER_SWRST] = 0x01a2, + [PWRAP_DEW_RDDMY_NO] = 0x01a4, +}; + +static const u32 mt6351_regs[] = { + [PWRAP_DEW_DIO_EN] = 0x02F2, + [PWRAP_DEW_READ_TEST] = 0x02F4, + [PWRAP_DEW_WRITE_TEST] = 0x02F6, + [PWRAP_DEW_CRC_EN] = 0x02FA, + [PWRAP_DEW_CRC_VAL] = 0x02FC, + [PWRAP_DEW_CIPHER_KEY_SEL] = 0x0300, + [PWRAP_DEW_CIPHER_IV_SEL] = 0x0302, + [PWRAP_DEW_CIPHER_EN] = 0x0304, + [PWRAP_DEW_CIPHER_RDY] = 0x0306, + [PWRAP_DEW_CIPHER_MODE] = 0x0308, + [PWRAP_DEW_CIPHER_SWRST] = 0x030A, + [PWRAP_DEW_RDDMY_NO] = 0x030C, +}; + +static const u32 mt6357_regs[] = { + [PWRAP_DEW_DIO_EN] = 0x040A, + [PWRAP_DEW_READ_TEST] = 0x040C, + [PWRAP_DEW_WRITE_TEST] = 0x040E, + [PWRAP_DEW_CRC_EN] = 0x0412, + [PWRAP_DEW_CRC_VAL] = 0x0414, + [PWRAP_DEW_CIPHER_KEY_SEL] = 0x0418, + [PWRAP_DEW_CIPHER_IV_SEL] = 0x041A, + [PWRAP_DEW_CIPHER_EN] = 0x041C, + [PWRAP_DEW_CIPHER_RDY] = 0x041E, + [PWRAP_DEW_CIPHER_MODE] = 0x0420, + [PWRAP_DEW_CIPHER_SWRST] = 0x0422, + [PWRAP_DEW_RDDMY_NO] = 0x0424, +}; + +static const u32 mt6358_regs[] = { + [PWRAP_SMT_CON1] = 0x0030, + [PWRAP_DRV_CON1] = 0x0038, + [PWRAP_FILTER_CON0] = 0x0040, + [PWRAP_GPIO_PULLEN0_CLR] = 0x0098, + [PWRAP_RG_SPI_CON0] = 0x0408, + [PWRAP_RG_SPI_RECORD0] = 0x040a, + [PWRAP_DEW_DIO_EN] = 0x040c, + [PWRAP_DEW_READ_TEST] = 0x040e, + [PWRAP_DEW_WRITE_TEST] = 0x0410, + [PWRAP_DEW_CRC_EN] = 0x0414, + [PWRAP_DEW_CIPHER_KEY_SEL] = 0x041a, + [PWRAP_DEW_CIPHER_IV_SEL] = 0x041c, + [PWRAP_DEW_CIPHER_EN] = 0x041e, + [PWRAP_DEW_CIPHER_RDY] = 0x0420, + [PWRAP_DEW_CIPHER_MODE] = 0x0422, + [PWRAP_DEW_CIPHER_SWRST] = 0x0424, + [PWRAP_RG_SPI_CON2] = 0x0432, + [PWRAP_RG_SPI_CON3] = 0x0434, + [PWRAP_RG_SPI_CON4] = 0x0436, + [PWRAP_RG_SPI_CON5] = 0x0438, + [PWRAP_RG_SPI_CON6] = 0x043a, + [PWRAP_RG_SPI_CON7] = 0x043c, + [PWRAP_RG_SPI_CON8] = 0x043e, + [PWRAP_RG_SPI_CON13] = 0x0448, + [PWRAP_SPISLV_KEY] = 0x044a, +}; + +static const u32 mt6359_regs[] = { + [PWRAP_DEW_RG_EN_RECORD] = 0x040a, + [PWRAP_DEW_DIO_EN] = 0x040c, + [PWRAP_DEW_READ_TEST] = 0x040e, + [PWRAP_DEW_WRITE_TEST] = 0x0410, + [PWRAP_DEW_CRC_SWRST] = 0x0412, + [PWRAP_DEW_CRC_EN] = 0x0414, + [PWRAP_DEW_CRC_VAL] = 0x0416, + [PWRAP_DEW_CIPHER_KEY_SEL] = 0x0418, + [PWRAP_DEW_CIPHER_IV_SEL] = 0x041a, + [PWRAP_DEW_CIPHER_EN] = 0x041c, + [PWRAP_DEW_CIPHER_RDY] = 0x041e, + [PWRAP_DEW_CIPHER_MODE] = 0x0420, + [PWRAP_DEW_CIPHER_SWRST] = 0x0422, + [PWRAP_DEW_RDDMY_NO] = 0x0424, + [PWRAP_DEW_RECORD_CMD0] = 0x0428, + [PWRAP_DEW_RECORD_CMD1] = 0x042a, + [PWRAP_DEW_RECORD_CMD2] = 0x042c, + [PWRAP_DEW_RECORD_CMD3] = 0x042e, + [PWRAP_DEW_RECORD_CMD4] = 0x0430, + [PWRAP_DEW_RECORD_CMD5] = 0x0432, + [PWRAP_DEW_RECORD_WDATA0] = 0x0434, + [PWRAP_DEW_RECORD_WDATA1] = 0x0436, + [PWRAP_DEW_RECORD_WDATA2] = 0x0438, + [PWRAP_DEW_RECORD_WDATA3] = 0x043a, + [PWRAP_DEW_RECORD_WDATA4] = 0x043c, + [PWRAP_DEW_RECORD_WDATA5] = 0x043e, + [PWRAP_DEW_RG_ADDR_TARGET] = 0x0440, + [PWRAP_DEW_RG_ADDR_MASK] = 0x0442, + [PWRAP_DEW_RG_WDATA_TARGET] = 0x0444, + [PWRAP_DEW_RG_WDATA_MASK] = 0x0446, + [PWRAP_DEW_RG_SPI_RECORD_CLR] = 0x0448, + [PWRAP_DEW_RG_CMD_ALERT_CLR] = 0x0448, + [PWRAP_SPISLV_KEY] = 0x044a, +}; + +static const u32 mt6397_regs[] = { + [PWRAP_DEW_BASE] = 0xbc00, + [PWRAP_DEW_EVENT_OUT_EN] = 0xbc00, + [PWRAP_DEW_DIO_EN] = 0xbc02, + [PWRAP_DEW_EVENT_SRC_EN] = 0xbc04, + [PWRAP_DEW_EVENT_SRC] = 0xbc06, + [PWRAP_DEW_EVENT_FLAG] = 0xbc08, + [PWRAP_DEW_READ_TEST] = 0xbc0a, + [PWRAP_DEW_WRITE_TEST] = 0xbc0c, + [PWRAP_DEW_CRC_EN] = 0xbc0e, + [PWRAP_DEW_CRC_VAL] = 0xbc10, + [PWRAP_DEW_MON_GRP_SEL] = 0xbc12, + [PWRAP_DEW_MON_FLAG_SEL] = 0xbc14, + [PWRAP_DEW_EVENT_TEST] = 0xbc16, + [PWRAP_DEW_CIPHER_KEY_SEL] = 0xbc18, + [PWRAP_DEW_CIPHER_IV_SEL] = 0xbc1a, + [PWRAP_DEW_CIPHER_LOAD] = 0xbc1c, + [PWRAP_DEW_CIPHER_START] = 0xbc1e, + [PWRAP_DEW_CIPHER_RDY] = 0xbc20, + [PWRAP_DEW_CIPHER_MODE] = 0xbc22, + [PWRAP_DEW_CIPHER_SWRST] = 0xbc24, +}; + +enum pwrap_regs { + PWRAP_MUX_SEL, + PWRAP_WRAP_EN, + PWRAP_DIO_EN, + PWRAP_SIDLY, + PWRAP_CSHEXT_WRITE, + PWRAP_CSHEXT_READ, + PWRAP_CSLEXT_START, + PWRAP_CSLEXT_END, + PWRAP_STAUPD_PRD, + PWRAP_STAUPD_GRPEN, + PWRAP_STAUPD_MAN_TRIG, + PWRAP_STAUPD_STA, + PWRAP_WRAP_STA, + PWRAP_HARB_INIT, + PWRAP_HARB_HPRIO, + PWRAP_HIPRIO_ARB_EN, + PWRAP_HARB_STA0, + PWRAP_HARB_STA1, + PWRAP_MAN_EN, + PWRAP_MAN_CMD, + PWRAP_MAN_RDATA, + PWRAP_MAN_VLDCLR, + PWRAP_WACS0_EN, + PWRAP_INIT_DONE0, + PWRAP_WACS0_CMD, + PWRAP_WACS0_RDATA, + PWRAP_WACS0_VLDCLR, + PWRAP_WACS1_EN, + PWRAP_INIT_DONE1, + PWRAP_WACS1_CMD, + PWRAP_WACS1_RDATA, + PWRAP_WACS1_VLDCLR, + PWRAP_WACS2_EN, + PWRAP_INIT_DONE2, + PWRAP_WACS2_CMD, + PWRAP_WACS2_RDATA, + PWRAP_WACS2_VLDCLR, + PWRAP_INT_EN, + PWRAP_INT_FLG_RAW, + PWRAP_INT_FLG, + PWRAP_INT_CLR, + PWRAP_SIG_ADR, + PWRAP_SIG_MODE, + PWRAP_SIG_VALUE, + PWRAP_SIG_ERRVAL, + PWRAP_CRC_EN, + PWRAP_TIMER_EN, + PWRAP_TIMER_STA, + PWRAP_WDT_UNIT, + PWRAP_WDT_SRC_EN, + PWRAP_WDT_FLG, + PWRAP_DEBUG_INT_SEL, + PWRAP_CIPHER_KEY_SEL, + PWRAP_CIPHER_IV_SEL, + PWRAP_CIPHER_RDY, + PWRAP_CIPHER_MODE, + PWRAP_CIPHER_SWRST, + PWRAP_DCM_EN, + PWRAP_DCM_DBC_PRD, + PWRAP_EINT_STA0_ADR, + PWRAP_EINT_STA1_ADR, + + /* MT2701 only regs */ + PWRAP_ADC_CMD_ADDR, + PWRAP_PWRAP_ADC_CMD, + PWRAP_ADC_RDY_ADDR, + PWRAP_ADC_RDATA_ADDR1, + PWRAP_ADC_RDATA_ADDR2, + + /* MT7622 only regs */ + PWRAP_STA, + PWRAP_CLR, + PWRAP_DVFS_ADR8, + PWRAP_DVFS_WDATA8, + PWRAP_DVFS_ADR9, + PWRAP_DVFS_WDATA9, + PWRAP_DVFS_ADR10, + PWRAP_DVFS_WDATA10, + PWRAP_DVFS_ADR11, + PWRAP_DVFS_WDATA11, + PWRAP_DVFS_ADR12, + PWRAP_DVFS_WDATA12, + PWRAP_DVFS_ADR13, + PWRAP_DVFS_WDATA13, + PWRAP_DVFS_ADR14, + PWRAP_DVFS_WDATA14, + PWRAP_DVFS_ADR15, + PWRAP_DVFS_WDATA15, + PWRAP_EXT_CK, + PWRAP_ADC_RDATA_ADDR, + PWRAP_GPS_STA, + PWRAP_SW_RST, + PWRAP_DVFS_STEP_CTRL0, + PWRAP_DVFS_STEP_CTRL1, + PWRAP_DVFS_STEP_CTRL2, + PWRAP_SPI2_CTRL, + + /* MT8135 only regs */ + PWRAP_CSHEXT, + PWRAP_EVENT_IN_EN, + PWRAP_EVENT_DST_EN, + PWRAP_RRARB_INIT, + PWRAP_RRARB_EN, + PWRAP_RRARB_STA0, + PWRAP_RRARB_STA1, + PWRAP_EVENT_STA, + PWRAP_EVENT_STACLR, + PWRAP_CIPHER_LOAD, + PWRAP_CIPHER_START, + + /* MT8173 only regs */ + PWRAP_RDDMY, + PWRAP_SI_CK_CON, + PWRAP_DVFS_ADR0, + PWRAP_DVFS_WDATA0, + PWRAP_DVFS_ADR1, + PWRAP_DVFS_WDATA1, + PWRAP_DVFS_ADR2, + PWRAP_DVFS_WDATA2, + PWRAP_DVFS_ADR3, + PWRAP_DVFS_WDATA3, + PWRAP_DVFS_ADR4, + PWRAP_DVFS_WDATA4, + PWRAP_DVFS_ADR5, + PWRAP_DVFS_WDATA5, + PWRAP_DVFS_ADR6, + PWRAP_DVFS_WDATA6, + PWRAP_DVFS_ADR7, + PWRAP_DVFS_WDATA7, + PWRAP_SPMINF_STA, + PWRAP_CIPHER_EN, + + /* MT8183 only regs */ + PWRAP_SI_SAMPLE_CTRL, + PWRAP_CSLEXT_WRITE, + PWRAP_CSLEXT_READ, + PWRAP_EXT_CK_WRITE, + PWRAP_STAUPD_CTRL, + PWRAP_WACS_P2P_EN, + PWRAP_INIT_DONE_P2P, + PWRAP_WACS_MD32_EN, + PWRAP_INIT_DONE_MD32, + PWRAP_INT1_EN, + PWRAP_INT1_FLG, + PWRAP_INT1_CLR, + PWRAP_WDT_SRC_EN_1, + PWRAP_INT_GPS_AUXADC_CMD_ADDR, + PWRAP_INT_GPS_AUXADC_CMD, + PWRAP_INT_GPS_AUXADC_RDATA_ADDR, + PWRAP_EXT_GPS_AUXADC_RDATA_ADDR, + PWRAP_GPSINF_0_STA, + PWRAP_GPSINF_1_STA, + + /* MT8516 only regs */ + PWRAP_OP_TYPE, + PWRAP_MSB_FIRST, +}; + +static int mt2701_regs[] = { + [PWRAP_MUX_SEL] = 0x0, + [PWRAP_WRAP_EN] = 0x4, + [PWRAP_DIO_EN] = 0x8, + [PWRAP_SIDLY] = 0xc, + [PWRAP_RDDMY] = 0x18, + [PWRAP_SI_CK_CON] = 0x1c, + [PWRAP_CSHEXT_WRITE] = 0x20, + [PWRAP_CSHEXT_READ] = 0x24, + [PWRAP_CSLEXT_START] = 0x28, + [PWRAP_CSLEXT_END] = 0x2c, + [PWRAP_STAUPD_PRD] = 0x30, + [PWRAP_STAUPD_GRPEN] = 0x34, + [PWRAP_STAUPD_MAN_TRIG] = 0x38, + [PWRAP_STAUPD_STA] = 0x3c, + [PWRAP_WRAP_STA] = 0x44, + [PWRAP_HARB_INIT] = 0x48, + [PWRAP_HARB_HPRIO] = 0x4c, + [PWRAP_HIPRIO_ARB_EN] = 0x50, + [PWRAP_HARB_STA0] = 0x54, + [PWRAP_HARB_STA1] = 0x58, + [PWRAP_MAN_EN] = 0x5c, + [PWRAP_MAN_CMD] = 0x60, + [PWRAP_MAN_RDATA] = 0x64, + [PWRAP_MAN_VLDCLR] = 0x68, + [PWRAP_WACS0_EN] = 0x6c, + [PWRAP_INIT_DONE0] = 0x70, + [PWRAP_WACS0_CMD] = 0x74, + [PWRAP_WACS0_RDATA] = 0x78, + [PWRAP_WACS0_VLDCLR] = 0x7c, + [PWRAP_WACS1_EN] = 0x80, + [PWRAP_INIT_DONE1] = 0x84, + [PWRAP_WACS1_CMD] = 0x88, + [PWRAP_WACS1_RDATA] = 0x8c, + [PWRAP_WACS1_VLDCLR] = 0x90, + [PWRAP_WACS2_EN] = 0x94, + [PWRAP_INIT_DONE2] = 0x98, + [PWRAP_WACS2_CMD] = 0x9c, + [PWRAP_WACS2_RDATA] = 0xa0, + [PWRAP_WACS2_VLDCLR] = 0xa4, + [PWRAP_INT_EN] = 0xa8, + [PWRAP_INT_FLG_RAW] = 0xac, + [PWRAP_INT_FLG] = 0xb0, + [PWRAP_INT_CLR] = 0xb4, + [PWRAP_SIG_ADR] = 0xb8, + [PWRAP_SIG_MODE] = 0xbc, + [PWRAP_SIG_VALUE] = 0xc0, + [PWRAP_SIG_ERRVAL] = 0xc4, + [PWRAP_CRC_EN] = 0xc8, + [PWRAP_TIMER_EN] = 0xcc, + [PWRAP_TIMER_STA] = 0xd0, + [PWRAP_WDT_UNIT] = 0xd4, + [PWRAP_WDT_SRC_EN] = 0xd8, + [PWRAP_WDT_FLG] = 0xdc, + [PWRAP_DEBUG_INT_SEL] = 0xe0, + [PWRAP_DVFS_ADR0] = 0xe4, + [PWRAP_DVFS_WDATA0] = 0xe8, + [PWRAP_DVFS_ADR1] = 0xec, + [PWRAP_DVFS_WDATA1] = 0xf0, + [PWRAP_DVFS_ADR2] = 0xf4, + [PWRAP_DVFS_WDATA2] = 0xf8, + [PWRAP_DVFS_ADR3] = 0xfc, + [PWRAP_DVFS_WDATA3] = 0x100, + [PWRAP_DVFS_ADR4] = 0x104, + [PWRAP_DVFS_WDATA4] = 0x108, + [PWRAP_DVFS_ADR5] = 0x10c, + [PWRAP_DVFS_WDATA5] = 0x110, + [PWRAP_DVFS_ADR6] = 0x114, + [PWRAP_DVFS_WDATA6] = 0x118, + [PWRAP_DVFS_ADR7] = 0x11c, + [PWRAP_DVFS_WDATA7] = 0x120, + [PWRAP_CIPHER_KEY_SEL] = 0x124, + [PWRAP_CIPHER_IV_SEL] = 0x128, + [PWRAP_CIPHER_EN] = 0x12c, + [PWRAP_CIPHER_RDY] = 0x130, + [PWRAP_CIPHER_MODE] = 0x134, + [PWRAP_CIPHER_SWRST] = 0x138, + [PWRAP_DCM_EN] = 0x13c, + [PWRAP_DCM_DBC_PRD] = 0x140, + [PWRAP_ADC_CMD_ADDR] = 0x144, + [PWRAP_PWRAP_ADC_CMD] = 0x148, + [PWRAP_ADC_RDY_ADDR] = 0x14c, + [PWRAP_ADC_RDATA_ADDR1] = 0x150, + [PWRAP_ADC_RDATA_ADDR2] = 0x154, +}; + +static int mt6765_regs[] = { + [PWRAP_MUX_SEL] = 0x0, + [PWRAP_WRAP_EN] = 0x4, + [PWRAP_DIO_EN] = 0x8, + [PWRAP_RDDMY] = 0x20, + [PWRAP_CSHEXT_WRITE] = 0x24, + [PWRAP_CSHEXT_READ] = 0x28, + [PWRAP_CSLEXT_START] = 0x2C, + [PWRAP_CSLEXT_END] = 0x30, + [PWRAP_STAUPD_PRD] = 0x3C, + [PWRAP_HARB_HPRIO] = 0x68, + [PWRAP_HIPRIO_ARB_EN] = 0x6C, + [PWRAP_MAN_EN] = 0x7C, + [PWRAP_MAN_CMD] = 0x80, + [PWRAP_WACS0_EN] = 0x8C, + [PWRAP_WACS1_EN] = 0x94, + [PWRAP_WACS2_EN] = 0x9C, + [PWRAP_INIT_DONE2] = 0xA0, + [PWRAP_WACS2_CMD] = 0xC20, + [PWRAP_WACS2_RDATA] = 0xC24, + [PWRAP_WACS2_VLDCLR] = 0xC28, + [PWRAP_INT_EN] = 0xB4, + [PWRAP_INT_FLG_RAW] = 0xB8, + [PWRAP_INT_FLG] = 0xBC, + [PWRAP_INT_CLR] = 0xC0, + [PWRAP_TIMER_EN] = 0xE8, + [PWRAP_WDT_UNIT] = 0xF0, + [PWRAP_WDT_SRC_EN] = 0xF4, + [PWRAP_DCM_EN] = 0x1DC, + [PWRAP_DCM_DBC_PRD] = 0x1E0, +}; + +static int mt6779_regs[] = { + [PWRAP_MUX_SEL] = 0x0, + [PWRAP_WRAP_EN] = 0x4, + [PWRAP_DIO_EN] = 0x8, + [PWRAP_RDDMY] = 0x20, + [PWRAP_CSHEXT_WRITE] = 0x24, + [PWRAP_CSHEXT_READ] = 0x28, + [PWRAP_CSLEXT_WRITE] = 0x2C, + [PWRAP_CSLEXT_READ] = 0x30, + [PWRAP_EXT_CK_WRITE] = 0x34, + [PWRAP_STAUPD_CTRL] = 0x3C, + [PWRAP_STAUPD_GRPEN] = 0x40, + [PWRAP_EINT_STA0_ADR] = 0x44, + [PWRAP_HARB_HPRIO] = 0x68, + [PWRAP_HIPRIO_ARB_EN] = 0x6C, + [PWRAP_MAN_EN] = 0x7C, + [PWRAP_MAN_CMD] = 0x80, + [PWRAP_WACS0_EN] = 0x8C, + [PWRAP_INIT_DONE0] = 0x90, + [PWRAP_WACS1_EN] = 0x94, + [PWRAP_WACS2_EN] = 0x9C, + [PWRAP_INIT_DONE1] = 0x98, + [PWRAP_INIT_DONE2] = 0xA0, + [PWRAP_INT_EN] = 0xBC, + [PWRAP_INT_FLG_RAW] = 0xC0, + [PWRAP_INT_FLG] = 0xC4, + [PWRAP_INT_CLR] = 0xC8, + [PWRAP_INT1_EN] = 0xCC, + [PWRAP_INT1_FLG] = 0xD4, + [PWRAP_INT1_CLR] = 0xD8, + [PWRAP_TIMER_EN] = 0xF0, + [PWRAP_WDT_UNIT] = 0xF8, + [PWRAP_WDT_SRC_EN] = 0xFC, + [PWRAP_WDT_SRC_EN_1] = 0x100, + [PWRAP_WACS2_CMD] = 0xC20, + [PWRAP_WACS2_RDATA] = 0xC24, + [PWRAP_WACS2_VLDCLR] = 0xC28, +}; + +static int mt6797_regs[] = { + [PWRAP_MUX_SEL] = 0x0, + [PWRAP_WRAP_EN] = 0x4, + [PWRAP_DIO_EN] = 0x8, + [PWRAP_SIDLY] = 0xC, + [PWRAP_RDDMY] = 0x10, + [PWRAP_CSHEXT_WRITE] = 0x18, + [PWRAP_CSHEXT_READ] = 0x1C, + [PWRAP_CSLEXT_START] = 0x20, + [PWRAP_CSLEXT_END] = 0x24, + [PWRAP_STAUPD_PRD] = 0x28, + [PWRAP_HARB_HPRIO] = 0x50, + [PWRAP_HIPRIO_ARB_EN] = 0x54, + [PWRAP_MAN_EN] = 0x60, + [PWRAP_MAN_CMD] = 0x64, + [PWRAP_WACS0_EN] = 0x70, + [PWRAP_WACS1_EN] = 0x84, + [PWRAP_WACS2_EN] = 0x98, + [PWRAP_INIT_DONE2] = 0x9C, + [PWRAP_WACS2_CMD] = 0xA0, + [PWRAP_WACS2_RDATA] = 0xA4, + [PWRAP_WACS2_VLDCLR] = 0xA8, + [PWRAP_INT_EN] = 0xC0, + [PWRAP_INT_FLG_RAW] = 0xC4, + [PWRAP_INT_FLG] = 0xC8, + [PWRAP_INT_CLR] = 0xCC, + [PWRAP_TIMER_EN] = 0xF4, + [PWRAP_WDT_UNIT] = 0xFC, + [PWRAP_WDT_SRC_EN] = 0x100, + [PWRAP_DCM_EN] = 0x1CC, + [PWRAP_DCM_DBC_PRD] = 0x1D4, +}; + +static int mt7622_regs[] = { + [PWRAP_MUX_SEL] = 0x0, + [PWRAP_WRAP_EN] = 0x4, + [PWRAP_DIO_EN] = 0x8, + [PWRAP_SIDLY] = 0xC, + [PWRAP_RDDMY] = 0x10, + [PWRAP_SI_CK_CON] = 0x14, + [PWRAP_CSHEXT_WRITE] = 0x18, + [PWRAP_CSHEXT_READ] = 0x1C, + [PWRAP_CSLEXT_START] = 0x20, + [PWRAP_CSLEXT_END] = 0x24, + [PWRAP_STAUPD_PRD] = 0x28, + [PWRAP_STAUPD_GRPEN] = 0x2C, + [PWRAP_EINT_STA0_ADR] = 0x30, + [PWRAP_EINT_STA1_ADR] = 0x34, + [PWRAP_STA] = 0x38, + [PWRAP_CLR] = 0x3C, + [PWRAP_STAUPD_MAN_TRIG] = 0x40, + [PWRAP_STAUPD_STA] = 0x44, + [PWRAP_WRAP_STA] = 0x48, + [PWRAP_HARB_INIT] = 0x4C, + [PWRAP_HARB_HPRIO] = 0x50, + [PWRAP_HIPRIO_ARB_EN] = 0x54, + [PWRAP_HARB_STA0] = 0x58, + [PWRAP_HARB_STA1] = 0x5C, + [PWRAP_MAN_EN] = 0x60, + [PWRAP_MAN_CMD] = 0x64, + [PWRAP_MAN_RDATA] = 0x68, + [PWRAP_MAN_VLDCLR] = 0x6C, + [PWRAP_WACS0_EN] = 0x70, + [PWRAP_INIT_DONE0] = 0x74, + [PWRAP_WACS0_CMD] = 0x78, + [PWRAP_WACS0_RDATA] = 0x7C, + [PWRAP_WACS0_VLDCLR] = 0x80, + [PWRAP_WACS1_EN] = 0x84, + [PWRAP_INIT_DONE1] = 0x88, + [PWRAP_WACS1_CMD] = 0x8C, + [PWRAP_WACS1_RDATA] = 0x90, + [PWRAP_WACS1_VLDCLR] = 0x94, + [PWRAP_WACS2_EN] = 0x98, + [PWRAP_INIT_DONE2] = 0x9C, + [PWRAP_WACS2_CMD] = 0xA0, + [PWRAP_WACS2_RDATA] = 0xA4, + [PWRAP_WACS2_VLDCLR] = 0xA8, + [PWRAP_INT_EN] = 0xAC, + [PWRAP_INT_FLG_RAW] = 0xB0, + [PWRAP_INT_FLG] = 0xB4, + [PWRAP_INT_CLR] = 0xB8, + [PWRAP_SIG_ADR] = 0xBC, + [PWRAP_SIG_MODE] = 0xC0, + [PWRAP_SIG_VALUE] = 0xC4, + [PWRAP_SIG_ERRVAL] = 0xC8, + [PWRAP_CRC_EN] = 0xCC, + [PWRAP_TIMER_EN] = 0xD0, + [PWRAP_TIMER_STA] = 0xD4, + [PWRAP_WDT_UNIT] = 0xD8, + [PWRAP_WDT_SRC_EN] = 0xDC, + [PWRAP_WDT_FLG] = 0xE0, + [PWRAP_DEBUG_INT_SEL] = 0xE4, + [PWRAP_DVFS_ADR0] = 0xE8, + [PWRAP_DVFS_WDATA0] = 0xEC, + [PWRAP_DVFS_ADR1] = 0xF0, + [PWRAP_DVFS_WDATA1] = 0xF4, + [PWRAP_DVFS_ADR2] = 0xF8, + [PWRAP_DVFS_WDATA2] = 0xFC, + [PWRAP_DVFS_ADR3] = 0x100, + [PWRAP_DVFS_WDATA3] = 0x104, + [PWRAP_DVFS_ADR4] = 0x108, + [PWRAP_DVFS_WDATA4] = 0x10C, + [PWRAP_DVFS_ADR5] = 0x110, + [PWRAP_DVFS_WDATA5] = 0x114, + [PWRAP_DVFS_ADR6] = 0x118, + [PWRAP_DVFS_WDATA6] = 0x11C, + [PWRAP_DVFS_ADR7] = 0x120, + [PWRAP_DVFS_WDATA7] = 0x124, + [PWRAP_DVFS_ADR8] = 0x128, + [PWRAP_DVFS_WDATA8] = 0x12C, + [PWRAP_DVFS_ADR9] = 0x130, + [PWRAP_DVFS_WDATA9] = 0x134, + [PWRAP_DVFS_ADR10] = 0x138, + [PWRAP_DVFS_WDATA10] = 0x13C, + [PWRAP_DVFS_ADR11] = 0x140, + [PWRAP_DVFS_WDATA11] = 0x144, + [PWRAP_DVFS_ADR12] = 0x148, + [PWRAP_DVFS_WDATA12] = 0x14C, + [PWRAP_DVFS_ADR13] = 0x150, + [PWRAP_DVFS_WDATA13] = 0x154, + [PWRAP_DVFS_ADR14] = 0x158, + [PWRAP_DVFS_WDATA14] = 0x15C, + [PWRAP_DVFS_ADR15] = 0x160, + [PWRAP_DVFS_WDATA15] = 0x164, + [PWRAP_SPMINF_STA] = 0x168, + [PWRAP_CIPHER_KEY_SEL] = 0x16C, + [PWRAP_CIPHER_IV_SEL] = 0x170, + [PWRAP_CIPHER_EN] = 0x174, + [PWRAP_CIPHER_RDY] = 0x178, + [PWRAP_CIPHER_MODE] = 0x17C, + [PWRAP_CIPHER_SWRST] = 0x180, + [PWRAP_DCM_EN] = 0x184, + [PWRAP_DCM_DBC_PRD] = 0x188, + [PWRAP_EXT_CK] = 0x18C, + [PWRAP_ADC_CMD_ADDR] = 0x190, + [PWRAP_PWRAP_ADC_CMD] = 0x194, + [PWRAP_ADC_RDATA_ADDR] = 0x198, + [PWRAP_GPS_STA] = 0x19C, + [PWRAP_SW_RST] = 0x1A0, + [PWRAP_DVFS_STEP_CTRL0] = 0x238, + [PWRAP_DVFS_STEP_CTRL1] = 0x23C, + [PWRAP_DVFS_STEP_CTRL2] = 0x240, + [PWRAP_SPI2_CTRL] = 0x244, +}; + +static int mt8135_regs[] = { + [PWRAP_MUX_SEL] = 0x0, + [PWRAP_WRAP_EN] = 0x4, + [PWRAP_DIO_EN] = 0x8, + [PWRAP_SIDLY] = 0xc, + [PWRAP_CSHEXT] = 0x10, + [PWRAP_CSHEXT_WRITE] = 0x14, + [PWRAP_CSHEXT_READ] = 0x18, + [PWRAP_CSLEXT_START] = 0x1c, + [PWRAP_CSLEXT_END] = 0x20, + [PWRAP_STAUPD_PRD] = 0x24, + [PWRAP_STAUPD_GRPEN] = 0x28, + [PWRAP_STAUPD_MAN_TRIG] = 0x2c, + [PWRAP_STAUPD_STA] = 0x30, + [PWRAP_EVENT_IN_EN] = 0x34, + [PWRAP_EVENT_DST_EN] = 0x38, + [PWRAP_WRAP_STA] = 0x3c, + [PWRAP_RRARB_INIT] = 0x40, + [PWRAP_RRARB_EN] = 0x44, + [PWRAP_RRARB_STA0] = 0x48, + [PWRAP_RRARB_STA1] = 0x4c, + [PWRAP_HARB_INIT] = 0x50, + [PWRAP_HARB_HPRIO] = 0x54, + [PWRAP_HIPRIO_ARB_EN] = 0x58, + [PWRAP_HARB_STA0] = 0x5c, + [PWRAP_HARB_STA1] = 0x60, + [PWRAP_MAN_EN] = 0x64, + [PWRAP_MAN_CMD] = 0x68, + [PWRAP_MAN_RDATA] = 0x6c, + [PWRAP_MAN_VLDCLR] = 0x70, + [PWRAP_WACS0_EN] = 0x74, + [PWRAP_INIT_DONE0] = 0x78, + [PWRAP_WACS0_CMD] = 0x7c, + [PWRAP_WACS0_RDATA] = 0x80, + [PWRAP_WACS0_VLDCLR] = 0x84, + [PWRAP_WACS1_EN] = 0x88, + [PWRAP_INIT_DONE1] = 0x8c, + [PWRAP_WACS1_CMD] = 0x90, + [PWRAP_WACS1_RDATA] = 0x94, + [PWRAP_WACS1_VLDCLR] = 0x98, + [PWRAP_WACS2_EN] = 0x9c, + [PWRAP_INIT_DONE2] = 0xa0, + [PWRAP_WACS2_CMD] = 0xa4, + [PWRAP_WACS2_RDATA] = 0xa8, + [PWRAP_WACS2_VLDCLR] = 0xac, + [PWRAP_INT_EN] = 0xb0, + [PWRAP_INT_FLG_RAW] = 0xb4, + [PWRAP_INT_FLG] = 0xb8, + [PWRAP_INT_CLR] = 0xbc, + [PWRAP_SIG_ADR] = 0xc0, + [PWRAP_SIG_MODE] = 0xc4, + [PWRAP_SIG_VALUE] = 0xc8, + [PWRAP_SIG_ERRVAL] = 0xcc, + [PWRAP_CRC_EN] = 0xd0, + [PWRAP_EVENT_STA] = 0xd4, + [PWRAP_EVENT_STACLR] = 0xd8, + [PWRAP_TIMER_EN] = 0xdc, + [PWRAP_TIMER_STA] = 0xe0, + [PWRAP_WDT_UNIT] = 0xe4, + [PWRAP_WDT_SRC_EN] = 0xe8, + [PWRAP_WDT_FLG] = 0xec, + [PWRAP_DEBUG_INT_SEL] = 0xf0, + [PWRAP_CIPHER_KEY_SEL] = 0x134, + [PWRAP_CIPHER_IV_SEL] = 0x138, + [PWRAP_CIPHER_LOAD] = 0x13c, + [PWRAP_CIPHER_START] = 0x140, + [PWRAP_CIPHER_RDY] = 0x144, + [PWRAP_CIPHER_MODE] = 0x148, + [PWRAP_CIPHER_SWRST] = 0x14c, + [PWRAP_DCM_EN] = 0x15c, + [PWRAP_DCM_DBC_PRD] = 0x160, +}; + +static int mt8173_regs[] = { + [PWRAP_MUX_SEL] = 0x0, + [PWRAP_WRAP_EN] = 0x4, + [PWRAP_DIO_EN] = 0x8, + [PWRAP_SIDLY] = 0xc, + [PWRAP_RDDMY] = 0x10, + [PWRAP_SI_CK_CON] = 0x14, + [PWRAP_CSHEXT_WRITE] = 0x18, + [PWRAP_CSHEXT_READ] = 0x1c, + [PWRAP_CSLEXT_START] = 0x20, + [PWRAP_CSLEXT_END] = 0x24, + [PWRAP_STAUPD_PRD] = 0x28, + [PWRAP_STAUPD_GRPEN] = 0x2c, + [PWRAP_STAUPD_MAN_TRIG] = 0x40, + [PWRAP_STAUPD_STA] = 0x44, + [PWRAP_WRAP_STA] = 0x48, + [PWRAP_HARB_INIT] = 0x4c, + [PWRAP_HARB_HPRIO] = 0x50, + [PWRAP_HIPRIO_ARB_EN] = 0x54, + [PWRAP_HARB_STA0] = 0x58, + [PWRAP_HARB_STA1] = 0x5c, + [PWRAP_MAN_EN] = 0x60, + [PWRAP_MAN_CMD] = 0x64, + [PWRAP_MAN_RDATA] = 0x68, + [PWRAP_MAN_VLDCLR] = 0x6c, + [PWRAP_WACS0_EN] = 0x70, + [PWRAP_INIT_DONE0] = 0x74, + [PWRAP_WACS0_CMD] = 0x78, + [PWRAP_WACS0_RDATA] = 0x7c, + [PWRAP_WACS0_VLDCLR] = 0x80, + [PWRAP_WACS1_EN] = 0x84, + [PWRAP_INIT_DONE1] = 0x88, + [PWRAP_WACS1_CMD] = 0x8c, + [PWRAP_WACS1_RDATA] = 0x90, + [PWRAP_WACS1_VLDCLR] = 0x94, + [PWRAP_WACS2_EN] = 0x98, + [PWRAP_INIT_DONE2] = 0x9c, + [PWRAP_WACS2_CMD] = 0xa0, + [PWRAP_WACS2_RDATA] = 0xa4, + [PWRAP_WACS2_VLDCLR] = 0xa8, + [PWRAP_INT_EN] = 0xac, + [PWRAP_INT_FLG_RAW] = 0xb0, + [PWRAP_INT_FLG] = 0xb4, + [PWRAP_INT_CLR] = 0xb8, + [PWRAP_SIG_ADR] = 0xbc, + [PWRAP_SIG_MODE] = 0xc0, + [PWRAP_SIG_VALUE] = 0xc4, + [PWRAP_SIG_ERRVAL] = 0xc8, + [PWRAP_CRC_EN] = 0xcc, + [PWRAP_TIMER_EN] = 0xd0, + [PWRAP_TIMER_STA] = 0xd4, + [PWRAP_WDT_UNIT] = 0xd8, + [PWRAP_WDT_SRC_EN] = 0xdc, + [PWRAP_WDT_FLG] = 0xe0, + [PWRAP_DEBUG_INT_SEL] = 0xe4, + [PWRAP_DVFS_ADR0] = 0xe8, + [PWRAP_DVFS_WDATA0] = 0xec, + [PWRAP_DVFS_ADR1] = 0xf0, + [PWRAP_DVFS_WDATA1] = 0xf4, + [PWRAP_DVFS_ADR2] = 0xf8, + [PWRAP_DVFS_WDATA2] = 0xfc, + [PWRAP_DVFS_ADR3] = 0x100, + [PWRAP_DVFS_WDATA3] = 0x104, + [PWRAP_DVFS_ADR4] = 0x108, + [PWRAP_DVFS_WDATA4] = 0x10c, + [PWRAP_DVFS_ADR5] = 0x110, + [PWRAP_DVFS_WDATA5] = 0x114, + [PWRAP_DVFS_ADR6] = 0x118, + [PWRAP_DVFS_WDATA6] = 0x11c, + [PWRAP_DVFS_ADR7] = 0x120, + [PWRAP_DVFS_WDATA7] = 0x124, + [PWRAP_SPMINF_STA] = 0x128, + [PWRAP_CIPHER_KEY_SEL] = 0x12c, + [PWRAP_CIPHER_IV_SEL] = 0x130, + [PWRAP_CIPHER_EN] = 0x134, + [PWRAP_CIPHER_RDY] = 0x138, + [PWRAP_CIPHER_MODE] = 0x13c, + [PWRAP_CIPHER_SWRST] = 0x140, + [PWRAP_DCM_EN] = 0x144, + [PWRAP_DCM_DBC_PRD] = 0x148, +}; + +static int mt8183_regs[] = { + [PWRAP_MUX_SEL] = 0x0, + [PWRAP_WRAP_EN] = 0x4, + [PWRAP_DIO_EN] = 0x8, + [PWRAP_SI_SAMPLE_CTRL] = 0xC, + [PWRAP_RDDMY] = 0x14, + [PWRAP_CSHEXT_WRITE] = 0x18, + [PWRAP_CSHEXT_READ] = 0x1C, + [PWRAP_CSLEXT_WRITE] = 0x20, + [PWRAP_CSLEXT_READ] = 0x24, + [PWRAP_EXT_CK_WRITE] = 0x28, + [PWRAP_STAUPD_CTRL] = 0x30, + [PWRAP_STAUPD_GRPEN] = 0x34, + [PWRAP_EINT_STA0_ADR] = 0x38, + [PWRAP_HARB_HPRIO] = 0x5C, + [PWRAP_HIPRIO_ARB_EN] = 0x60, + [PWRAP_MAN_EN] = 0x70, + [PWRAP_MAN_CMD] = 0x74, + [PWRAP_WACS0_EN] = 0x80, + [PWRAP_INIT_DONE0] = 0x84, + [PWRAP_WACS1_EN] = 0x88, + [PWRAP_INIT_DONE1] = 0x8C, + [PWRAP_WACS2_EN] = 0x90, + [PWRAP_INIT_DONE2] = 0x94, + [PWRAP_WACS_P2P_EN] = 0xA0, + [PWRAP_INIT_DONE_P2P] = 0xA4, + [PWRAP_WACS_MD32_EN] = 0xA8, + [PWRAP_INIT_DONE_MD32] = 0xAC, + [PWRAP_INT_EN] = 0xB0, + [PWRAP_INT_FLG] = 0xB8, + [PWRAP_INT_CLR] = 0xBC, + [PWRAP_INT1_EN] = 0xC0, + [PWRAP_INT1_FLG] = 0xC8, + [PWRAP_INT1_CLR] = 0xCC, + [PWRAP_SIG_ADR] = 0xD0, + [PWRAP_CRC_EN] = 0xE0, + [PWRAP_TIMER_EN] = 0xE4, + [PWRAP_WDT_UNIT] = 0xEC, + [PWRAP_WDT_SRC_EN] = 0xF0, + [PWRAP_WDT_SRC_EN_1] = 0xF4, + [PWRAP_INT_GPS_AUXADC_CMD_ADDR] = 0x1DC, + [PWRAP_INT_GPS_AUXADC_CMD] = 0x1E0, + [PWRAP_INT_GPS_AUXADC_RDATA_ADDR] = 0x1E4, + [PWRAP_EXT_GPS_AUXADC_RDATA_ADDR] = 0x1E8, + [PWRAP_GPSINF_0_STA] = 0x1EC, + [PWRAP_GPSINF_1_STA] = 0x1F0, + [PWRAP_WACS2_CMD] = 0xC20, + [PWRAP_WACS2_RDATA] = 0xC24, + [PWRAP_WACS2_VLDCLR] = 0xC28, +}; + +static int mt8516_regs[] = { + [PWRAP_MUX_SEL] = 0x0, + [PWRAP_WRAP_EN] = 0x4, + [PWRAP_DIO_EN] = 0x8, + [PWRAP_SIDLY] = 0xc, + [PWRAP_RDDMY] = 0x10, + [PWRAP_SI_CK_CON] = 0x14, + [PWRAP_CSHEXT_WRITE] = 0x18, + [PWRAP_CSHEXT_READ] = 0x1c, + [PWRAP_CSLEXT_START] = 0x20, + [PWRAP_CSLEXT_END] = 0x24, + [PWRAP_STAUPD_PRD] = 0x28, + [PWRAP_STAUPD_GRPEN] = 0x2c, + [PWRAP_STAUPD_MAN_TRIG] = 0x40, + [PWRAP_STAUPD_STA] = 0x44, + [PWRAP_WRAP_STA] = 0x48, + [PWRAP_HARB_INIT] = 0x4c, + [PWRAP_HARB_HPRIO] = 0x50, + [PWRAP_HIPRIO_ARB_EN] = 0x54, + [PWRAP_HARB_STA0] = 0x58, + [PWRAP_HARB_STA1] = 0x5c, + [PWRAP_MAN_EN] = 0x60, + [PWRAP_MAN_CMD] = 0x64, + [PWRAP_MAN_RDATA] = 0x68, + [PWRAP_MAN_VLDCLR] = 0x6c, + [PWRAP_WACS0_EN] = 0x70, + [PWRAP_INIT_DONE0] = 0x74, + [PWRAP_WACS0_CMD] = 0x78, + [PWRAP_WACS0_RDATA] = 0x7c, + [PWRAP_WACS0_VLDCLR] = 0x80, + [PWRAP_WACS1_EN] = 0x84, + [PWRAP_INIT_DONE1] = 0x88, + [PWRAP_WACS1_CMD] = 0x8c, + [PWRAP_WACS1_RDATA] = 0x90, + [PWRAP_WACS1_VLDCLR] = 0x94, + [PWRAP_WACS2_EN] = 0x98, + [PWRAP_INIT_DONE2] = 0x9c, + [PWRAP_WACS2_CMD] = 0xa0, + [PWRAP_WACS2_RDATA] = 0xa4, + [PWRAP_WACS2_VLDCLR] = 0xa8, + [PWRAP_INT_EN] = 0xac, + [PWRAP_INT_FLG_RAW] = 0xb0, + [PWRAP_INT_FLG] = 0xb4, + [PWRAP_INT_CLR] = 0xb8, + [PWRAP_SIG_ADR] = 0xbc, + [PWRAP_SIG_MODE] = 0xc0, + [PWRAP_SIG_VALUE] = 0xc4, + [PWRAP_SIG_ERRVAL] = 0xc8, + [PWRAP_CRC_EN] = 0xcc, + [PWRAP_TIMER_EN] = 0xd0, + [PWRAP_TIMER_STA] = 0xd4, + [PWRAP_WDT_UNIT] = 0xd8, + [PWRAP_WDT_SRC_EN] = 0xdc, + [PWRAP_WDT_FLG] = 0xe0, + [PWRAP_DEBUG_INT_SEL] = 0xe4, + [PWRAP_DVFS_ADR0] = 0xe8, + [PWRAP_DVFS_WDATA0] = 0xec, + [PWRAP_DVFS_ADR1] = 0xf0, + [PWRAP_DVFS_WDATA1] = 0xf4, + [PWRAP_DVFS_ADR2] = 0xf8, + [PWRAP_DVFS_WDATA2] = 0xfc, + [PWRAP_DVFS_ADR3] = 0x100, + [PWRAP_DVFS_WDATA3] = 0x104, + [PWRAP_DVFS_ADR4] = 0x108, + [PWRAP_DVFS_WDATA4] = 0x10c, + [PWRAP_DVFS_ADR5] = 0x110, + [PWRAP_DVFS_WDATA5] = 0x114, + [PWRAP_DVFS_ADR6] = 0x118, + [PWRAP_DVFS_WDATA6] = 0x11c, + [PWRAP_DVFS_ADR7] = 0x120, + [PWRAP_DVFS_WDATA7] = 0x124, + [PWRAP_SPMINF_STA] = 0x128, + [PWRAP_CIPHER_KEY_SEL] = 0x12c, + [PWRAP_CIPHER_IV_SEL] = 0x130, + [PWRAP_CIPHER_EN] = 0x134, + [PWRAP_CIPHER_RDY] = 0x138, + [PWRAP_CIPHER_MODE] = 0x13c, + [PWRAP_CIPHER_SWRST] = 0x140, + [PWRAP_DCM_EN] = 0x144, + [PWRAP_DCM_DBC_PRD] = 0x148, + [PWRAP_SW_RST] = 0x168, + [PWRAP_OP_TYPE] = 0x16c, + [PWRAP_MSB_FIRST] = 0x170, +}; + +enum pmic_type { + PMIC_MT6323, + PMIC_MT6351, + PMIC_MT6357, + PMIC_MT6358, + PMIC_MT6359, + PMIC_MT6380, + PMIC_MT6397, +}; + +enum pwrap_type { + PWRAP_MT2701, + PWRAP_MT6765, + PWRAP_MT6779, + PWRAP_MT6797, + PWRAP_MT7622, + PWRAP_MT8135, + PWRAP_MT8173, + PWRAP_MT8183, + PWRAP_MT8516, +}; + +struct pmic_wrapper; +struct pwrap_slv_type { + const u32 *dew_regs; + enum pmic_type type; + const struct regmap_config *regmap; + /* Flags indicating the capability for the target slave */ + u32 caps; + /* + * pwrap operations are highly associated with the PMIC types, + * so the pointers added increases flexibility allowing determination + * which type is used by the detection through device tree. + */ + int (*pwrap_read)(struct pmic_wrapper *wrp, u32 adr, u32 *rdata); + int (*pwrap_write)(struct pmic_wrapper *wrp, u32 adr, u32 wdata); +}; + +struct pmic_wrapper { + struct device *dev; + void __iomem *base; + struct regmap *regmap; + const struct pmic_wrapper_type *master; + const struct pwrap_slv_type *slave; + struct clk *clk_spi; + struct clk *clk_wrap; + struct reset_control *rstc; + + struct reset_control *rstc_bridge; + void __iomem *bridge_base; +}; + +struct pmic_wrapper_type { + int *regs; + enum pwrap_type type; + u32 arb_en_all; + u32 int_en_all; + u32 int1_en_all; + u32 spi_w; + u32 wdt_src; + /* Flags indicating the capability for the target pwrap */ + u32 caps; + int (*init_reg_clock)(struct pmic_wrapper *wrp); + int (*init_soc_specific)(struct pmic_wrapper *wrp); +}; + +static u32 pwrap_readl(struct pmic_wrapper *wrp, enum pwrap_regs reg) +{ + return readl(wrp->base + wrp->master->regs[reg]); +} + +static void pwrap_writel(struct pmic_wrapper *wrp, u32 val, enum pwrap_regs reg) +{ + writel(val, wrp->base + wrp->master->regs[reg]); +} + +static bool pwrap_is_fsm_idle(struct pmic_wrapper *wrp) +{ + u32 val = pwrap_readl(wrp, PWRAP_WACS2_RDATA); + + return PWRAP_GET_WACS_FSM(val) == PWRAP_WACS_FSM_IDLE; +} + +static bool pwrap_is_fsm_vldclr(struct pmic_wrapper *wrp) +{ + u32 val = pwrap_readl(wrp, PWRAP_WACS2_RDATA); + + return PWRAP_GET_WACS_FSM(val) == PWRAP_WACS_FSM_WFVLDCLR; +} + +/* + * Timeout issue sometimes caused by the last read command + * failed because pmic wrap could not got the FSM_VLDCLR + * in time after finishing WACS2_CMD. It made state machine + * still on FSM_VLDCLR and timeout next time. + * Check the status of FSM and clear the vldclr to recovery the + * error. + */ +static inline void pwrap_leave_fsm_vldclr(struct pmic_wrapper *wrp) +{ + if (pwrap_is_fsm_vldclr(wrp)) + pwrap_writel(wrp, 1, PWRAP_WACS2_VLDCLR); +} + +static bool pwrap_is_sync_idle(struct pmic_wrapper *wrp) +{ + return pwrap_readl(wrp, PWRAP_WACS2_RDATA) & PWRAP_STATE_SYNC_IDLE0; +} + +static bool pwrap_is_fsm_idle_and_sync_idle(struct pmic_wrapper *wrp) +{ + u32 val = pwrap_readl(wrp, PWRAP_WACS2_RDATA); + + return (PWRAP_GET_WACS_FSM(val) == PWRAP_WACS_FSM_IDLE) && + (val & PWRAP_STATE_SYNC_IDLE0); +} + +static int pwrap_wait_for_state(struct pmic_wrapper *wrp, + bool (*fp)(struct pmic_wrapper *)) +{ + unsigned long timeout; + + timeout = jiffies + usecs_to_jiffies(10000); + + do { + if (time_after(jiffies, timeout)) + return fp(wrp) ? 0 : -ETIMEDOUT; + if (fp(wrp)) + return 0; + } while (1); +} + +static int pwrap_read16(struct pmic_wrapper *wrp, u32 adr, u32 *rdata) +{ + int ret; + + ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle); + if (ret) { + pwrap_leave_fsm_vldclr(wrp); + return ret; + } + + pwrap_writel(wrp, (adr >> 1) << 16, PWRAP_WACS2_CMD); + + ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_vldclr); + if (ret) + return ret; + + *rdata = PWRAP_GET_WACS_RDATA(pwrap_readl(wrp, PWRAP_WACS2_RDATA)); + + pwrap_writel(wrp, 1, PWRAP_WACS2_VLDCLR); + + return 0; +} + +static int pwrap_read32(struct pmic_wrapper *wrp, u32 adr, u32 *rdata) +{ + int ret, msb; + + *rdata = 0; + for (msb = 0; msb < 2; msb++) { + ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle); + if (ret) { + pwrap_leave_fsm_vldclr(wrp); + return ret; + } + + pwrap_writel(wrp, ((msb << 30) | (adr << 16)), + PWRAP_WACS2_CMD); + + ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_vldclr); + if (ret) + return ret; + + *rdata += (PWRAP_GET_WACS_RDATA(pwrap_readl(wrp, + PWRAP_WACS2_RDATA)) << (16 * msb)); + + pwrap_writel(wrp, 1, PWRAP_WACS2_VLDCLR); + } + + return 0; +} + +static int pwrap_read(struct pmic_wrapper *wrp, u32 adr, u32 *rdata) +{ + return wrp->slave->pwrap_read(wrp, adr, rdata); +} + +static int pwrap_write16(struct pmic_wrapper *wrp, u32 adr, u32 wdata) +{ + int ret; + + ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle); + if (ret) { + pwrap_leave_fsm_vldclr(wrp); + return ret; + } + + pwrap_writel(wrp, (1 << 31) | ((adr >> 1) << 16) | wdata, + PWRAP_WACS2_CMD); + + return 0; +} + +static int pwrap_write32(struct pmic_wrapper *wrp, u32 adr, u32 wdata) +{ + int ret, msb, rdata; + + for (msb = 0; msb < 2; msb++) { + ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle); + if (ret) { + pwrap_leave_fsm_vldclr(wrp); + return ret; + } + + pwrap_writel(wrp, (1 << 31) | (msb << 30) | (adr << 16) | + ((wdata >> (msb * 16)) & 0xffff), + PWRAP_WACS2_CMD); + + /* + * The pwrap_read operation is the requirement of hardware used + * for the synchronization between two successive 16-bit + * pwrap_writel operations composing one 32-bit bus writing. + * Otherwise, we'll find the result fails on the lower 16-bit + * pwrap writing. + */ + if (!msb) + pwrap_read(wrp, adr, &rdata); + } + + return 0; +} + +static int pwrap_write(struct pmic_wrapper *wrp, u32 adr, u32 wdata) +{ + return wrp->slave->pwrap_write(wrp, adr, wdata); +} + +static int pwrap_regmap_read(void *context, u32 adr, u32 *rdata) +{ + return pwrap_read(context, adr, rdata); +} + +static int pwrap_regmap_write(void *context, u32 adr, u32 wdata) +{ + return pwrap_write(context, adr, wdata); +} + +static int pwrap_reset_spislave(struct pmic_wrapper *wrp) +{ + int ret, i; + + pwrap_writel(wrp, 0, PWRAP_HIPRIO_ARB_EN); + pwrap_writel(wrp, 0, PWRAP_WRAP_EN); + pwrap_writel(wrp, 1, PWRAP_MUX_SEL); + pwrap_writel(wrp, 1, PWRAP_MAN_EN); + pwrap_writel(wrp, 0, PWRAP_DIO_EN); + + pwrap_writel(wrp, wrp->master->spi_w | PWRAP_MAN_CMD_OP_CSL, + PWRAP_MAN_CMD); + pwrap_writel(wrp, wrp->master->spi_w | PWRAP_MAN_CMD_OP_OUTS, + PWRAP_MAN_CMD); + pwrap_writel(wrp, wrp->master->spi_w | PWRAP_MAN_CMD_OP_CSH, + PWRAP_MAN_CMD); + + for (i = 0; i < 4; i++) + pwrap_writel(wrp, wrp->master->spi_w | PWRAP_MAN_CMD_OP_OUTS, + PWRAP_MAN_CMD); + + ret = pwrap_wait_for_state(wrp, pwrap_is_sync_idle); + if (ret) { + dev_err(wrp->dev, "%s fail, ret=%d\n", __func__, ret); + return ret; + } + + pwrap_writel(wrp, 0, PWRAP_MAN_EN); + pwrap_writel(wrp, 0, PWRAP_MUX_SEL); + + return 0; +} + +/* + * pwrap_init_sidly - configure serial input delay + * + * This configures the serial input delay. We can configure 0, 2, 4 or 6ns + * delay. Do a read test with all possible values and chose the best delay. + */ +static int pwrap_init_sidly(struct pmic_wrapper *wrp) +{ + u32 rdata; + u32 i; + u32 pass = 0; + signed char dly[16] = { + -1, 0, 1, 0, 2, -1, 1, 1, 3, -1, -1, -1, 3, -1, 2, 1 + }; + + for (i = 0; i < 4; i++) { + pwrap_writel(wrp, i, PWRAP_SIDLY); + pwrap_read(wrp, wrp->slave->dew_regs[PWRAP_DEW_READ_TEST], + &rdata); + if (rdata == PWRAP_DEW_READ_TEST_VAL) { + dev_dbg(wrp->dev, "[Read Test] pass, SIDLY=%x\n", i); + pass |= 1 << i; + } + } + + if (dly[pass] < 0) { + dev_err(wrp->dev, "sidly pass range 0x%x not continuous\n", + pass); + return -EIO; + } + + pwrap_writel(wrp, dly[pass], PWRAP_SIDLY); + + return 0; +} + +static int pwrap_init_dual_io(struct pmic_wrapper *wrp) +{ + int ret; + u32 rdata; + + /* Enable dual IO mode */ + pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_DIO_EN], 1); + + /* Check IDLE & INIT_DONE in advance */ + ret = pwrap_wait_for_state(wrp, + pwrap_is_fsm_idle_and_sync_idle); + if (ret) { + dev_err(wrp->dev, "%s fail, ret=%d\n", __func__, ret); + return ret; + } + + pwrap_writel(wrp, 1, PWRAP_DIO_EN); + + /* Read Test */ + pwrap_read(wrp, + wrp->slave->dew_regs[PWRAP_DEW_READ_TEST], &rdata); + if (rdata != PWRAP_DEW_READ_TEST_VAL) { + dev_err(wrp->dev, + "Read failed on DIO mode: 0x%04x!=0x%04x\n", + PWRAP_DEW_READ_TEST_VAL, rdata); + return -EFAULT; + } + + return 0; +} + +/* + * pwrap_init_chip_select_ext is used to configure CS extension time for each + * phase during data transactions on the pwrap bus. + */ +static void pwrap_init_chip_select_ext(struct pmic_wrapper *wrp, u8 hext_write, + u8 hext_read, u8 lext_start, + u8 lext_end) +{ + /* + * After finishing a write and read transaction, extends CS high time + * to be at least xT of BUS CLK as hext_write and hext_read specifies + * respectively. + */ + pwrap_writel(wrp, hext_write, PWRAP_CSHEXT_WRITE); + pwrap_writel(wrp, hext_read, PWRAP_CSHEXT_READ); + + /* + * Extends CS low time after CSL and before CSH command to be at + * least xT of BUS CLK as lext_start and lext_end specifies + * respectively. + */ + pwrap_writel(wrp, lext_start, PWRAP_CSLEXT_START); + pwrap_writel(wrp, lext_end, PWRAP_CSLEXT_END); +} + +static int pwrap_common_init_reg_clock(struct pmic_wrapper *wrp) +{ + switch (wrp->master->type) { + case PWRAP_MT8173: + pwrap_init_chip_select_ext(wrp, 0, 4, 2, 2); + break; + case PWRAP_MT8135: + pwrap_writel(wrp, 0x4, PWRAP_CSHEXT); + pwrap_init_chip_select_ext(wrp, 0, 4, 0, 0); + break; + default: + break; + } + + return 0; +} + +static int pwrap_mt2701_init_reg_clock(struct pmic_wrapper *wrp) +{ + switch (wrp->slave->type) { + case PMIC_MT6397: + pwrap_writel(wrp, 0xc, PWRAP_RDDMY); + pwrap_init_chip_select_ext(wrp, 4, 0, 2, 2); + break; + + case PMIC_MT6323: + pwrap_writel(wrp, 0x8, PWRAP_RDDMY); + pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_RDDMY_NO], + 0x8); + pwrap_init_chip_select_ext(wrp, 5, 0, 2, 2); + break; + default: + break; + } + + return 0; +} + +static bool pwrap_is_cipher_ready(struct pmic_wrapper *wrp) +{ + return pwrap_readl(wrp, PWRAP_CIPHER_RDY) & 1; +} + +static bool pwrap_is_pmic_cipher_ready(struct pmic_wrapper *wrp) +{ + u32 rdata; + int ret; + + ret = pwrap_read(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_RDY], + &rdata); + if (ret) + return false; + + return rdata == 1; +} + +static int pwrap_init_cipher(struct pmic_wrapper *wrp) +{ + int ret; + u32 rdata = 0; + + pwrap_writel(wrp, 0x1, PWRAP_CIPHER_SWRST); + pwrap_writel(wrp, 0x0, PWRAP_CIPHER_SWRST); + pwrap_writel(wrp, 0x1, PWRAP_CIPHER_KEY_SEL); + pwrap_writel(wrp, 0x2, PWRAP_CIPHER_IV_SEL); + + switch (wrp->master->type) { + case PWRAP_MT8135: + pwrap_writel(wrp, 1, PWRAP_CIPHER_LOAD); + pwrap_writel(wrp, 1, PWRAP_CIPHER_START); + break; + case PWRAP_MT2701: + case PWRAP_MT6765: + case PWRAP_MT6779: + case PWRAP_MT6797: + case PWRAP_MT8173: + case PWRAP_MT8516: + pwrap_writel(wrp, 1, PWRAP_CIPHER_EN); + break; + case PWRAP_MT7622: + pwrap_writel(wrp, 0, PWRAP_CIPHER_EN); + break; + case PWRAP_MT8183: + break; + } + + /* Config cipher mode @PMIC */ + pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_SWRST], 0x1); + pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_SWRST], 0x0); + pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_KEY_SEL], 0x1); + pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_IV_SEL], 0x2); + + switch (wrp->slave->type) { + case PMIC_MT6397: + pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_LOAD], + 0x1); + pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_START], + 0x1); + break; + case PMIC_MT6323: + case PMIC_MT6351: + case PMIC_MT6357: + pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_EN], + 0x1); + break; + default: + break; + } + + /* wait for cipher data ready@AP */ + ret = pwrap_wait_for_state(wrp, pwrap_is_cipher_ready); + if (ret) { + dev_err(wrp->dev, "cipher data ready@AP fail, ret=%d\n", ret); + return ret; + } + + /* wait for cipher data ready@PMIC */ + ret = pwrap_wait_for_state(wrp, pwrap_is_pmic_cipher_ready); + if (ret) { + dev_err(wrp->dev, + "timeout waiting for cipher data ready@PMIC\n"); + return ret; + } + + /* wait for cipher mode idle */ + pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_MODE], 0x1); + ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle_and_sync_idle); + if (ret) { + dev_err(wrp->dev, "cipher mode idle fail, ret=%d\n", ret); + return ret; + } + + pwrap_writel(wrp, 1, PWRAP_CIPHER_MODE); + + /* Write Test */ + if (pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_WRITE_TEST], + PWRAP_DEW_WRITE_TEST_VAL) || + pwrap_read(wrp, wrp->slave->dew_regs[PWRAP_DEW_WRITE_TEST], + &rdata) || + (rdata != PWRAP_DEW_WRITE_TEST_VAL)) { + dev_err(wrp->dev, "rdata=0x%04X\n", rdata); + return -EFAULT; + } + + return 0; +} + +static int pwrap_init_security(struct pmic_wrapper *wrp) +{ + int ret; + + /* Enable encryption */ + ret = pwrap_init_cipher(wrp); + if (ret) + return ret; + + /* Signature checking - using CRC */ + if (pwrap_write(wrp, + wrp->slave->dew_regs[PWRAP_DEW_CRC_EN], 0x1)) + return -EFAULT; + + pwrap_writel(wrp, 0x1, PWRAP_CRC_EN); + pwrap_writel(wrp, 0x0, PWRAP_SIG_MODE); + pwrap_writel(wrp, wrp->slave->dew_regs[PWRAP_DEW_CRC_VAL], + PWRAP_SIG_ADR); + pwrap_writel(wrp, + wrp->master->arb_en_all, PWRAP_HIPRIO_ARB_EN); + + return 0; +} + +static int pwrap_mt8135_init_soc_specific(struct pmic_wrapper *wrp) +{ + /* enable pwrap events and pwrap bridge in AP side */ + pwrap_writel(wrp, 0x1, PWRAP_EVENT_IN_EN); + pwrap_writel(wrp, 0xffff, PWRAP_EVENT_DST_EN); + writel(0x7f, wrp->bridge_base + PWRAP_MT8135_BRIDGE_IORD_ARB_EN); + writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WACS3_EN); + writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WACS4_EN); + writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WDT_UNIT); + writel(0xffff, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WDT_SRC_EN); + writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_TIMER_EN); + writel(0x7ff, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INT_EN); + + /* enable PMIC event out and sources */ + if (pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_EVENT_OUT_EN], + 0x1) || + pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_EVENT_SRC_EN], + 0xffff)) { + dev_err(wrp->dev, "enable dewrap fail\n"); + return -EFAULT; + } + + return 0; +} + +static int pwrap_mt8173_init_soc_specific(struct pmic_wrapper *wrp) +{ + /* PMIC_DEWRAP enables */ + if (pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_EVENT_OUT_EN], + 0x1) || + pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_EVENT_SRC_EN], + 0xffff)) { + dev_err(wrp->dev, "enable dewrap fail\n"); + return -EFAULT; + } + + return 0; +} + +static int pwrap_mt2701_init_soc_specific(struct pmic_wrapper *wrp) +{ + /* GPS_INTF initialization */ + switch (wrp->slave->type) { + case PMIC_MT6323: + pwrap_writel(wrp, 0x076c, PWRAP_ADC_CMD_ADDR); + pwrap_writel(wrp, 0x8000, PWRAP_PWRAP_ADC_CMD); + pwrap_writel(wrp, 0x072c, PWRAP_ADC_RDY_ADDR); + pwrap_writel(wrp, 0x072e, PWRAP_ADC_RDATA_ADDR1); + pwrap_writel(wrp, 0x0730, PWRAP_ADC_RDATA_ADDR2); + break; + default: + break; + } + + return 0; +} + +static int pwrap_mt7622_init_soc_specific(struct pmic_wrapper *wrp) +{ + pwrap_writel(wrp, 0, PWRAP_STAUPD_PRD); + /* enable 2wire SPI master */ + pwrap_writel(wrp, 0x8000000, PWRAP_SPI2_CTRL); + + return 0; +} + +static int pwrap_mt8183_init_soc_specific(struct pmic_wrapper *wrp) +{ + pwrap_writel(wrp, 0xf5, PWRAP_STAUPD_GRPEN); + + pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CRC_EN], 0x1); + pwrap_writel(wrp, 1, PWRAP_CRC_EN); + pwrap_writel(wrp, 0x416, PWRAP_SIG_ADR); + pwrap_writel(wrp, 0x42e, PWRAP_EINT_STA0_ADR); + + pwrap_writel(wrp, 1, PWRAP_WACS_P2P_EN); + pwrap_writel(wrp, 1, PWRAP_WACS_MD32_EN); + pwrap_writel(wrp, 1, PWRAP_INIT_DONE_P2P); + pwrap_writel(wrp, 1, PWRAP_INIT_DONE_MD32); + + return 0; +} + +static int pwrap_init(struct pmic_wrapper *wrp) +{ + int ret; + + if (wrp->rstc) + reset_control_reset(wrp->rstc); + if (wrp->rstc_bridge) + reset_control_reset(wrp->rstc_bridge); + + if (wrp->master->type == PWRAP_MT8173) { + /* Enable DCM */ + pwrap_writel(wrp, 3, PWRAP_DCM_EN); + pwrap_writel(wrp, 0, PWRAP_DCM_DBC_PRD); + } + + if (HAS_CAP(wrp->slave->caps, PWRAP_SLV_CAP_SPI)) { + /* Reset SPI slave */ + ret = pwrap_reset_spislave(wrp); + if (ret) + return ret; + } + + pwrap_writel(wrp, 1, PWRAP_WRAP_EN); + + pwrap_writel(wrp, wrp->master->arb_en_all, PWRAP_HIPRIO_ARB_EN); + + pwrap_writel(wrp, 1, PWRAP_WACS2_EN); + + ret = wrp->master->init_reg_clock(wrp); + if (ret) + return ret; + + if (HAS_CAP(wrp->slave->caps, PWRAP_SLV_CAP_SPI)) { + /* Setup serial input delay */ + ret = pwrap_init_sidly(wrp); + if (ret) + return ret; + } + + if (HAS_CAP(wrp->slave->caps, PWRAP_SLV_CAP_DUALIO)) { + /* Enable dual I/O mode */ + ret = pwrap_init_dual_io(wrp); + if (ret) + return ret; + } + + if (HAS_CAP(wrp->slave->caps, PWRAP_SLV_CAP_SECURITY)) { + /* Enable security on bus */ + ret = pwrap_init_security(wrp); + if (ret) + return ret; + } + + if (wrp->master->type == PWRAP_MT8135) + pwrap_writel(wrp, 0x7, PWRAP_RRARB_EN); + + pwrap_writel(wrp, 0x1, PWRAP_WACS0_EN); + pwrap_writel(wrp, 0x1, PWRAP_WACS1_EN); + pwrap_writel(wrp, 0x1, PWRAP_WACS2_EN); + pwrap_writel(wrp, 0x5, PWRAP_STAUPD_PRD); + pwrap_writel(wrp, 0xff, PWRAP_STAUPD_GRPEN); + + if (wrp->master->init_soc_specific) { + ret = wrp->master->init_soc_specific(wrp); + if (ret) + return ret; + } + + /* Setup the init done registers */ + pwrap_writel(wrp, 1, PWRAP_INIT_DONE2); + pwrap_writel(wrp, 1, PWRAP_INIT_DONE0); + pwrap_writel(wrp, 1, PWRAP_INIT_DONE1); + + if (HAS_CAP(wrp->master->caps, PWRAP_CAP_BRIDGE)) { + writel(1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INIT_DONE3); + writel(1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INIT_DONE4); + } + + return 0; +} + +static irqreturn_t pwrap_interrupt(int irqno, void *dev_id) +{ + u32 rdata; + struct pmic_wrapper *wrp = dev_id; + + rdata = pwrap_readl(wrp, PWRAP_INT_FLG); + dev_err(wrp->dev, "unexpected interrupt int=0x%x\n", rdata); + pwrap_writel(wrp, 0xffffffff, PWRAP_INT_CLR); + + if (HAS_CAP(wrp->master->caps, PWRAP_CAP_INT1_EN)) { + rdata = pwrap_readl(wrp, PWRAP_INT1_FLG); + dev_err(wrp->dev, "unexpected interrupt int1=0x%x\n", rdata); + pwrap_writel(wrp, 0xffffffff, PWRAP_INT1_CLR); + } + + return IRQ_HANDLED; +} + +static const struct regmap_config pwrap_regmap_config16 = { + .reg_bits = 16, + .val_bits = 16, + .reg_stride = 2, + .reg_read = pwrap_regmap_read, + .reg_write = pwrap_regmap_write, + .max_register = 0xffff, +}; + +static const struct regmap_config pwrap_regmap_config32 = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .reg_read = pwrap_regmap_read, + .reg_write = pwrap_regmap_write, + .max_register = 0xffff, +}; + +static const struct pwrap_slv_type pmic_mt6323 = { + .dew_regs = mt6323_regs, + .type = PMIC_MT6323, + .regmap = &pwrap_regmap_config16, + .caps = PWRAP_SLV_CAP_SPI | PWRAP_SLV_CAP_DUALIO | + PWRAP_SLV_CAP_SECURITY, + .pwrap_read = pwrap_read16, + .pwrap_write = pwrap_write16, +}; + +static const struct pwrap_slv_type pmic_mt6351 = { + .dew_regs = mt6351_regs, + .type = PMIC_MT6351, + .regmap = &pwrap_regmap_config16, + .caps = 0, + .pwrap_read = pwrap_read16, + .pwrap_write = pwrap_write16, +}; + +static const struct pwrap_slv_type pmic_mt6357 = { + .dew_regs = mt6357_regs, + .type = PMIC_MT6357, + .regmap = &pwrap_regmap_config16, + .caps = 0, + .pwrap_read = pwrap_read16, + .pwrap_write = pwrap_write16, +}; + +static const struct pwrap_slv_type pmic_mt6358 = { + .dew_regs = mt6358_regs, + .type = PMIC_MT6358, + .regmap = &pwrap_regmap_config16, + .caps = PWRAP_SLV_CAP_SPI | PWRAP_SLV_CAP_DUALIO, + .pwrap_read = pwrap_read16, + .pwrap_write = pwrap_write16, +}; + +static const struct pwrap_slv_type pmic_mt6359 = { + .dew_regs = mt6359_regs, + .type = PMIC_MT6359, + .regmap = &pwrap_regmap_config16, + .caps = PWRAP_SLV_CAP_DUALIO, + .pwrap_read = pwrap_read16, + .pwrap_write = pwrap_write16, +}; + +static const struct pwrap_slv_type pmic_mt6380 = { + .dew_regs = NULL, + .type = PMIC_MT6380, + .regmap = &pwrap_regmap_config32, + .caps = 0, + .pwrap_read = pwrap_read32, + .pwrap_write = pwrap_write32, +}; + +static const struct pwrap_slv_type pmic_mt6397 = { + .dew_regs = mt6397_regs, + .type = PMIC_MT6397, + .regmap = &pwrap_regmap_config16, + .caps = PWRAP_SLV_CAP_SPI | PWRAP_SLV_CAP_DUALIO | + PWRAP_SLV_CAP_SECURITY, + .pwrap_read = pwrap_read16, + .pwrap_write = pwrap_write16, +}; + +static const struct of_device_id of_slave_match_tbl[] = { + { + .compatible = "mediatek,mt6323", + .data = &pmic_mt6323, + }, { + .compatible = "mediatek,mt6351", + .data = &pmic_mt6351, + }, { + .compatible = "mediatek,mt6357", + .data = &pmic_mt6357, + }, { + .compatible = "mediatek,mt6358", + .data = &pmic_mt6358, + }, { + .compatible = "mediatek,mt6359", + .data = &pmic_mt6359, + }, { + /* The MT6380 PMIC only implements a regulator, so we bind it + * directly instead of using a MFD. + */ + .compatible = "mediatek,mt6380-regulator", + .data = &pmic_mt6380, + }, { + .compatible = "mediatek,mt6397", + .data = &pmic_mt6397, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, of_slave_match_tbl); + +static const struct pmic_wrapper_type pwrap_mt2701 = { + .regs = mt2701_regs, + .type = PWRAP_MT2701, + .arb_en_all = 0x3f, + .int_en_all = ~(u32)(BIT(31) | BIT(2)), + .int1_en_all = 0, + .spi_w = PWRAP_MAN_CMD_SPI_WRITE_NEW, + .wdt_src = PWRAP_WDT_SRC_MASK_ALL, + .caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM, + .init_reg_clock = pwrap_mt2701_init_reg_clock, + .init_soc_specific = pwrap_mt2701_init_soc_specific, +}; + +static const struct pmic_wrapper_type pwrap_mt6765 = { + .regs = mt6765_regs, + .type = PWRAP_MT6765, + .arb_en_all = 0x3fd35, + .int_en_all = 0xffffffff, + .spi_w = PWRAP_MAN_CMD_SPI_WRITE, + .wdt_src = PWRAP_WDT_SRC_MASK_ALL, + .caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM, + .init_reg_clock = pwrap_common_init_reg_clock, + .init_soc_specific = NULL, +}; + +static const struct pmic_wrapper_type pwrap_mt6779 = { + .regs = mt6779_regs, + .type = PWRAP_MT6779, + .arb_en_all = 0xfbb7f, + .int_en_all = 0xfffffffe, + .int1_en_all = 0, + .spi_w = PWRAP_MAN_CMD_SPI_WRITE, + .wdt_src = PWRAP_WDT_SRC_MASK_ALL, + .caps = 0, + .init_reg_clock = pwrap_common_init_reg_clock, + .init_soc_specific = NULL, +}; + +static const struct pmic_wrapper_type pwrap_mt6797 = { + .regs = mt6797_regs, + .type = PWRAP_MT6797, + .arb_en_all = 0x01fff, + .int_en_all = 0xffffffc6, + .int1_en_all = 0, + .spi_w = PWRAP_MAN_CMD_SPI_WRITE, + .wdt_src = PWRAP_WDT_SRC_MASK_ALL, + .caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM, + .init_reg_clock = pwrap_common_init_reg_clock, + .init_soc_specific = NULL, +}; + +static const struct pmic_wrapper_type pwrap_mt7622 = { + .regs = mt7622_regs, + .type = PWRAP_MT7622, + .arb_en_all = 0xff, + .int_en_all = ~(u32)BIT(31), + .int1_en_all = 0, + .spi_w = PWRAP_MAN_CMD_SPI_WRITE, + .wdt_src = PWRAP_WDT_SRC_MASK_ALL, + .caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM, + .init_reg_clock = pwrap_common_init_reg_clock, + .init_soc_specific = pwrap_mt7622_init_soc_specific, +}; + +static const struct pmic_wrapper_type pwrap_mt8135 = { + .regs = mt8135_regs, + .type = PWRAP_MT8135, + .arb_en_all = 0x1ff, + .int_en_all = ~(u32)(BIT(31) | BIT(1)), + .int1_en_all = 0, + .spi_w = PWRAP_MAN_CMD_SPI_WRITE, + .wdt_src = PWRAP_WDT_SRC_MASK_ALL, + .caps = PWRAP_CAP_BRIDGE | PWRAP_CAP_RESET | PWRAP_CAP_DCM, + .init_reg_clock = pwrap_common_init_reg_clock, + .init_soc_specific = pwrap_mt8135_init_soc_specific, +}; + +static const struct pmic_wrapper_type pwrap_mt8173 = { + .regs = mt8173_regs, + .type = PWRAP_MT8173, + .arb_en_all = 0x3f, + .int_en_all = ~(u32)(BIT(31) | BIT(1)), + .int1_en_all = 0, + .spi_w = PWRAP_MAN_CMD_SPI_WRITE, + .wdt_src = PWRAP_WDT_SRC_MASK_NO_STAUPD, + .caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM, + .init_reg_clock = pwrap_common_init_reg_clock, + .init_soc_specific = pwrap_mt8173_init_soc_specific, +}; + +static const struct pmic_wrapper_type pwrap_mt8183 = { + .regs = mt8183_regs, + .type = PWRAP_MT8183, + .arb_en_all = 0x3fa75, + .int_en_all = 0xffffffff, + .int1_en_all = 0xeef7ffff, + .spi_w = PWRAP_MAN_CMD_SPI_WRITE, + .wdt_src = PWRAP_WDT_SRC_MASK_ALL, + .caps = PWRAP_CAP_INT1_EN | PWRAP_CAP_WDT_SRC1, + .init_reg_clock = pwrap_common_init_reg_clock, + .init_soc_specific = pwrap_mt8183_init_soc_specific, +}; + +static struct pmic_wrapper_type pwrap_mt8516 = { + .regs = mt8516_regs, + .type = PWRAP_MT8516, + .arb_en_all = 0xff, + .int_en_all = ~(u32)(BIT(31) | BIT(2)), + .spi_w = PWRAP_MAN_CMD_SPI_WRITE, + .wdt_src = PWRAP_WDT_SRC_MASK_ALL, + .caps = PWRAP_CAP_DCM, + .init_reg_clock = pwrap_mt2701_init_reg_clock, + .init_soc_specific = NULL, +}; + +static const struct of_device_id of_pwrap_match_tbl[] = { + { + .compatible = "mediatek,mt2701-pwrap", + .data = &pwrap_mt2701, + }, { + .compatible = "mediatek,mt6765-pwrap", + .data = &pwrap_mt6765, + }, { + .compatible = "mediatek,mt6779-pwrap", + .data = &pwrap_mt6779, + }, { + .compatible = "mediatek,mt6797-pwrap", + .data = &pwrap_mt6797, + }, { + .compatible = "mediatek,mt7622-pwrap", + .data = &pwrap_mt7622, + }, { + .compatible = "mediatek,mt8135-pwrap", + .data = &pwrap_mt8135, + }, { + .compatible = "mediatek,mt8173-pwrap", + .data = &pwrap_mt8173, + }, { + .compatible = "mediatek,mt8183-pwrap", + .data = &pwrap_mt8183, + }, { + .compatible = "mediatek,mt8516-pwrap", + .data = &pwrap_mt8516, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, of_pwrap_match_tbl); + +static int pwrap_probe(struct platform_device *pdev) +{ + int ret, irq; + struct pmic_wrapper *wrp; + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_slave_id = NULL; + struct resource *res; + + if (np->child) + of_slave_id = of_match_node(of_slave_match_tbl, np->child); + + if (!of_slave_id) { + dev_dbg(&pdev->dev, "slave pmic should be defined in dts\n"); + return -EINVAL; + } + + wrp = devm_kzalloc(&pdev->dev, sizeof(*wrp), GFP_KERNEL); + if (!wrp) + return -ENOMEM; + + platform_set_drvdata(pdev, wrp); + + wrp->master = of_device_get_match_data(&pdev->dev); + wrp->slave = of_slave_id->data; + wrp->dev = &pdev->dev; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwrap"); + wrp->base = devm_ioremap_resource(wrp->dev, res); + if (IS_ERR(wrp->base)) + return PTR_ERR(wrp->base); + + if (HAS_CAP(wrp->master->caps, PWRAP_CAP_RESET)) { + wrp->rstc = devm_reset_control_get(wrp->dev, "pwrap"); + if (IS_ERR(wrp->rstc)) { + ret = PTR_ERR(wrp->rstc); + dev_dbg(wrp->dev, "cannot get pwrap reset: %d\n", ret); + return ret; + } + } + + if (HAS_CAP(wrp->master->caps, PWRAP_CAP_BRIDGE)) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "pwrap-bridge"); + wrp->bridge_base = devm_ioremap_resource(wrp->dev, res); + if (IS_ERR(wrp->bridge_base)) + return PTR_ERR(wrp->bridge_base); + + wrp->rstc_bridge = devm_reset_control_get(wrp->dev, + "pwrap-bridge"); + if (IS_ERR(wrp->rstc_bridge)) { + ret = PTR_ERR(wrp->rstc_bridge); + dev_dbg(wrp->dev, + "cannot get pwrap-bridge reset: %d\n", ret); + return ret; + } + } + + wrp->clk_spi = devm_clk_get(wrp->dev, "spi"); + if (IS_ERR(wrp->clk_spi)) { + dev_dbg(wrp->dev, "failed to get clock: %ld\n", + PTR_ERR(wrp->clk_spi)); + return PTR_ERR(wrp->clk_spi); + } + + wrp->clk_wrap = devm_clk_get(wrp->dev, "wrap"); + if (IS_ERR(wrp->clk_wrap)) { + dev_dbg(wrp->dev, "failed to get clock: %ld\n", + PTR_ERR(wrp->clk_wrap)); + return PTR_ERR(wrp->clk_wrap); + } + + ret = clk_prepare_enable(wrp->clk_spi); + if (ret) + return ret; + + ret = clk_prepare_enable(wrp->clk_wrap); + if (ret) + goto err_out1; + + /* Enable internal dynamic clock */ + if (HAS_CAP(wrp->master->caps, PWRAP_CAP_DCM)) { + pwrap_writel(wrp, 1, PWRAP_DCM_EN); + pwrap_writel(wrp, 0, PWRAP_DCM_DBC_PRD); + } + + /* + * The PMIC could already be initialized by the bootloader. + * Skip initialization here in this case. + */ + if (!pwrap_readl(wrp, PWRAP_INIT_DONE2)) { + ret = pwrap_init(wrp); + if (ret) { + dev_dbg(wrp->dev, "init failed with %d\n", ret); + goto err_out2; + } + } + + if (!(pwrap_readl(wrp, PWRAP_WACS2_RDATA) & PWRAP_STATE_INIT_DONE0)) { + dev_dbg(wrp->dev, "initialization isn't finished\n"); + ret = -ENODEV; + goto err_out2; + } + + /* Initialize watchdog, may not be done by the bootloader */ + pwrap_writel(wrp, 0xf, PWRAP_WDT_UNIT); + /* + * Since STAUPD was not used on mt8173 platform, + * so STAUPD of WDT_SRC which should be turned off + */ + pwrap_writel(wrp, wrp->master->wdt_src, PWRAP_WDT_SRC_EN); + if (HAS_CAP(wrp->master->caps, PWRAP_CAP_WDT_SRC1)) + pwrap_writel(wrp, wrp->master->wdt_src, PWRAP_WDT_SRC_EN_1); + + pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN); + pwrap_writel(wrp, wrp->master->int_en_all, PWRAP_INT_EN); + /* + * We add INT1 interrupt to handle starvation and request exception + * If we support it, we should enable it here. + */ + if (HAS_CAP(wrp->master->caps, PWRAP_CAP_INT1_EN)) + pwrap_writel(wrp, wrp->master->int1_en_all, PWRAP_INT1_EN); + + irq = platform_get_irq(pdev, 0); + ret = devm_request_irq(wrp->dev, irq, pwrap_interrupt, + IRQF_TRIGGER_HIGH, + "mt-pmic-pwrap", wrp); + if (ret) + goto err_out2; + + wrp->regmap = devm_regmap_init(wrp->dev, NULL, wrp, wrp->slave->regmap); + if (IS_ERR(wrp->regmap)) { + ret = PTR_ERR(wrp->regmap); + goto err_out2; + } + + ret = of_platform_populate(np, NULL, NULL, wrp->dev); + if (ret) { + dev_dbg(wrp->dev, "failed to create child devices at %pOF\n", + np); + goto err_out2; + } + + return 0; + +err_out2: + clk_disable_unprepare(wrp->clk_wrap); +err_out1: + clk_disable_unprepare(wrp->clk_spi); + + return ret; +} + +static struct platform_driver pwrap_drv = { + .driver = { + .name = "mt-pmic-pwrap", + .of_match_table = of_match_ptr(of_pwrap_match_tbl), + }, + .probe = pwrap_probe, +}; + +module_platform_driver(pwrap_drv); + +MODULE_AUTHOR("Flora Fu, MediaTek"); +MODULE_DESCRIPTION("MediaTek MT8135 PMIC Wrapper Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c new file mode 100644 index 000000000..ca75b1493 --- /dev/null +++ b/drivers/soc/mediatek/mtk-scpsys.c @@ -0,0 +1,1147 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015 Pengutronix, Sascha Hauer <kernel@pengutronix.de> + */ +#include <linux/clk.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/mfd/syscon.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm_domain.h> +#include <linux/regulator/consumer.h> +#include <linux/soc/mediatek/infracfg.h> + +#include <dt-bindings/power/mt2701-power.h> +#include <dt-bindings/power/mt2712-power.h> +#include <dt-bindings/power/mt6797-power.h> +#include <dt-bindings/power/mt7622-power.h> +#include <dt-bindings/power/mt7623a-power.h> +#include <dt-bindings/power/mt8173-power.h> + +#define MTK_POLL_DELAY_US 10 +#define MTK_POLL_TIMEOUT USEC_PER_SEC + +#define MTK_SCPD_ACTIVE_WAKEUP BIT(0) +#define MTK_SCPD_FWAIT_SRAM BIT(1) +#define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data->caps & (_x)) + +#define SPM_VDE_PWR_CON 0x0210 +#define SPM_MFG_PWR_CON 0x0214 +#define SPM_VEN_PWR_CON 0x0230 +#define SPM_ISP_PWR_CON 0x0238 +#define SPM_DIS_PWR_CON 0x023c +#define SPM_CONN_PWR_CON 0x0280 +#define SPM_VEN2_PWR_CON 0x0298 +#define SPM_AUDIO_PWR_CON 0x029c /* MT8173, MT2712 */ +#define SPM_BDP_PWR_CON 0x029c /* MT2701 */ +#define SPM_ETH_PWR_CON 0x02a0 +#define SPM_HIF_PWR_CON 0x02a4 +#define SPM_IFR_MSC_PWR_CON 0x02a8 +#define SPM_MFG_2D_PWR_CON 0x02c0 +#define SPM_MFG_ASYNC_PWR_CON 0x02c4 +#define SPM_USB_PWR_CON 0x02cc +#define SPM_USB2_PWR_CON 0x02d4 /* MT2712 */ +#define SPM_ETHSYS_PWR_CON 0x02e0 /* MT7622 */ +#define SPM_HIF0_PWR_CON 0x02e4 /* MT7622 */ +#define SPM_HIF1_PWR_CON 0x02e8 /* MT7622 */ +#define SPM_WB_PWR_CON 0x02ec /* MT7622 */ + +#define SPM_PWR_STATUS 0x060c +#define SPM_PWR_STATUS_2ND 0x0610 + +#define PWR_RST_B_BIT BIT(0) +#define PWR_ISO_BIT BIT(1) +#define PWR_ON_BIT BIT(2) +#define PWR_ON_2ND_BIT BIT(3) +#define PWR_CLK_DIS_BIT BIT(4) + +#define PWR_STATUS_CONN BIT(1) +#define PWR_STATUS_DISP BIT(3) +#define PWR_STATUS_MFG BIT(4) +#define PWR_STATUS_ISP BIT(5) +#define PWR_STATUS_VDEC BIT(7) +#define PWR_STATUS_BDP BIT(14) +#define PWR_STATUS_ETH BIT(15) +#define PWR_STATUS_HIF BIT(16) +#define PWR_STATUS_IFR_MSC BIT(17) +#define PWR_STATUS_USB2 BIT(19) /* MT2712 */ +#define PWR_STATUS_VENC_LT BIT(20) +#define PWR_STATUS_VENC BIT(21) +#define PWR_STATUS_MFG_2D BIT(22) /* MT8173 */ +#define PWR_STATUS_MFG_ASYNC BIT(23) /* MT8173 */ +#define PWR_STATUS_AUDIO BIT(24) /* MT8173, MT2712 */ +#define PWR_STATUS_USB BIT(25) /* MT8173, MT2712 */ +#define PWR_STATUS_ETHSYS BIT(24) /* MT7622 */ +#define PWR_STATUS_HIF0 BIT(25) /* MT7622 */ +#define PWR_STATUS_HIF1 BIT(26) /* MT7622 */ +#define PWR_STATUS_WB BIT(27) /* MT7622 */ + +enum clk_id { + CLK_NONE, + CLK_MM, + CLK_MFG, + CLK_VENC, + CLK_VENC_LT, + CLK_ETHIF, + CLK_VDEC, + CLK_HIFSEL, + CLK_JPGDEC, + CLK_AUDIO, + CLK_MAX, +}; + +static const char * const clk_names[] = { + NULL, + "mm", + "mfg", + "venc", + "venc_lt", + "ethif", + "vdec", + "hif_sel", + "jpgdec", + "audio", + NULL, +}; + +#define MAX_CLKS 3 + +/** + * struct scp_domain_data - scp domain data for power on/off flow + * @name: The domain name. + * @sta_mask: The mask for power on/off status bit. + * @ctl_offs: The offset for main power control register. + * @sram_pdn_bits: The mask for sram power control bits. + * @sram_pdn_ack_bits: The mask for sram power control acked bits. + * @bus_prot_mask: The mask for single step bus protection. + * @clk_id: The basic clocks required by this power domain. + * @caps: The flag for active wake-up action. + */ +struct scp_domain_data { + const char *name; + u32 sta_mask; + int ctl_offs; + u32 sram_pdn_bits; + u32 sram_pdn_ack_bits; + u32 bus_prot_mask; + enum clk_id clk_id[MAX_CLKS]; + u8 caps; +}; + +struct scp; + +struct scp_domain { + struct generic_pm_domain genpd; + struct scp *scp; + struct clk *clk[MAX_CLKS]; + const struct scp_domain_data *data; + struct regulator *supply; +}; + +struct scp_ctrl_reg { + int pwr_sta_offs; + int pwr_sta2nd_offs; +}; + +struct scp { + struct scp_domain *domains; + struct genpd_onecell_data pd_data; + struct device *dev; + void __iomem *base; + struct regmap *infracfg; + struct scp_ctrl_reg ctrl_reg; + bool bus_prot_reg_update; +}; + +struct scp_subdomain { + int origin; + int subdomain; +}; + +struct scp_soc_data { + const struct scp_domain_data *domains; + int num_domains; + const struct scp_subdomain *subdomains; + int num_subdomains; + const struct scp_ctrl_reg regs; + bool bus_prot_reg_update; +}; + +static int scpsys_domain_is_on(struct scp_domain *scpd) +{ + struct scp *scp = scpd->scp; + + u32 status = readl(scp->base + scp->ctrl_reg.pwr_sta_offs) & + scpd->data->sta_mask; + u32 status2 = readl(scp->base + scp->ctrl_reg.pwr_sta2nd_offs) & + scpd->data->sta_mask; + + /* + * A domain is on when both status bits are set. If only one is set + * return an error. This happens while powering up a domain + */ + + if (status && status2) + return true; + if (!status && !status2) + return false; + + return -EINVAL; +} + +static int scpsys_regulator_enable(struct scp_domain *scpd) +{ + if (!scpd->supply) + return 0; + + return regulator_enable(scpd->supply); +} + +static int scpsys_regulator_disable(struct scp_domain *scpd) +{ + if (!scpd->supply) + return 0; + + return regulator_disable(scpd->supply); +} + +static void scpsys_clk_disable(struct clk *clk[], int max_num) +{ + int i; + + for (i = max_num - 1; i >= 0; i--) + clk_disable_unprepare(clk[i]); +} + +static int scpsys_clk_enable(struct clk *clk[], int max_num) +{ + int i, ret = 0; + + for (i = 0; i < max_num && clk[i]; i++) { + ret = clk_prepare_enable(clk[i]); + if (ret) { + scpsys_clk_disable(clk, i); + break; + } + } + + return ret; +} + +static int scpsys_sram_enable(struct scp_domain *scpd, void __iomem *ctl_addr) +{ + u32 val; + u32 pdn_ack = scpd->data->sram_pdn_ack_bits; + int tmp; + + val = readl(ctl_addr); + val &= ~scpd->data->sram_pdn_bits; + writel(val, ctl_addr); + + /* Either wait until SRAM_PDN_ACK all 0 or have a force wait */ + if (MTK_SCPD_CAPS(scpd, MTK_SCPD_FWAIT_SRAM)) { + /* + * Currently, MTK_SCPD_FWAIT_SRAM is necessary only for + * MT7622_POWER_DOMAIN_WB and thus just a trivial setup + * is applied here. + */ + usleep_range(12000, 12100); + } else { + /* Either wait until SRAM_PDN_ACK all 1 or 0 */ + int ret = readl_poll_timeout(ctl_addr, tmp, + (tmp & pdn_ack) == 0, + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); + if (ret < 0) + return ret; + } + + return 0; +} + +static int scpsys_sram_disable(struct scp_domain *scpd, void __iomem *ctl_addr) +{ + u32 val; + u32 pdn_ack = scpd->data->sram_pdn_ack_bits; + int tmp; + + val = readl(ctl_addr); + val |= scpd->data->sram_pdn_bits; + writel(val, ctl_addr); + + /* Either wait until SRAM_PDN_ACK all 1 or 0 */ + return readl_poll_timeout(ctl_addr, tmp, + (tmp & pdn_ack) == pdn_ack, + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); +} + +static int scpsys_bus_protect_enable(struct scp_domain *scpd) +{ + struct scp *scp = scpd->scp; + + if (!scpd->data->bus_prot_mask) + return 0; + + return mtk_infracfg_set_bus_protection(scp->infracfg, + scpd->data->bus_prot_mask, + scp->bus_prot_reg_update); +} + +static int scpsys_bus_protect_disable(struct scp_domain *scpd) +{ + struct scp *scp = scpd->scp; + + if (!scpd->data->bus_prot_mask) + return 0; + + return mtk_infracfg_clear_bus_protection(scp->infracfg, + scpd->data->bus_prot_mask, + scp->bus_prot_reg_update); +} + +static int scpsys_power_on(struct generic_pm_domain *genpd) +{ + struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd); + struct scp *scp = scpd->scp; + void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs; + u32 val; + int ret, tmp; + + ret = scpsys_regulator_enable(scpd); + if (ret < 0) + return ret; + + ret = scpsys_clk_enable(scpd->clk, MAX_CLKS); + if (ret) + goto err_clk; + + /* subsys power on */ + val = readl(ctl_addr); + val |= PWR_ON_BIT; + writel(val, ctl_addr); + val |= PWR_ON_2ND_BIT; + writel(val, ctl_addr); + + /* wait until PWR_ACK = 1 */ + ret = readx_poll_timeout(scpsys_domain_is_on, scpd, tmp, tmp > 0, + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); + if (ret < 0) + goto err_pwr_ack; + + val &= ~PWR_CLK_DIS_BIT; + writel(val, ctl_addr); + + val &= ~PWR_ISO_BIT; + writel(val, ctl_addr); + + val |= PWR_RST_B_BIT; + writel(val, ctl_addr); + + ret = scpsys_sram_enable(scpd, ctl_addr); + if (ret < 0) + goto err_pwr_ack; + + ret = scpsys_bus_protect_disable(scpd); + if (ret < 0) + goto err_pwr_ack; + + return 0; + +err_pwr_ack: + scpsys_clk_disable(scpd->clk, MAX_CLKS); +err_clk: + scpsys_regulator_disable(scpd); + + dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name); + + return ret; +} + +static int scpsys_power_off(struct generic_pm_domain *genpd) +{ + struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd); + struct scp *scp = scpd->scp; + void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs; + u32 val; + int ret, tmp; + + ret = scpsys_bus_protect_enable(scpd); + if (ret < 0) + goto out; + + ret = scpsys_sram_disable(scpd, ctl_addr); + if (ret < 0) + goto out; + + /* subsys power off */ + val = readl(ctl_addr); + val |= PWR_ISO_BIT; + writel(val, ctl_addr); + + val &= ~PWR_RST_B_BIT; + writel(val, ctl_addr); + + val |= PWR_CLK_DIS_BIT; + writel(val, ctl_addr); + + val &= ~PWR_ON_BIT; + writel(val, ctl_addr); + + val &= ~PWR_ON_2ND_BIT; + writel(val, ctl_addr); + + /* wait until PWR_ACK = 0 */ + ret = readx_poll_timeout(scpsys_domain_is_on, scpd, tmp, tmp == 0, + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); + if (ret < 0) + goto out; + + scpsys_clk_disable(scpd->clk, MAX_CLKS); + + ret = scpsys_regulator_disable(scpd); + if (ret < 0) + goto out; + + return 0; + +out: + dev_err(scp->dev, "Failed to power off domain %s\n", genpd->name); + + return ret; +} + +static void init_clks(struct platform_device *pdev, struct clk **clk) +{ + int i; + + for (i = CLK_NONE + 1; i < CLK_MAX; i++) + clk[i] = devm_clk_get(&pdev->dev, clk_names[i]); +} + +static struct scp *init_scp(struct platform_device *pdev, + const struct scp_domain_data *scp_domain_data, int num, + const struct scp_ctrl_reg *scp_ctrl_reg, + bool bus_prot_reg_update) +{ + struct genpd_onecell_data *pd_data; + struct resource *res; + int i, j; + struct scp *scp; + struct clk *clk[CLK_MAX]; + + scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL); + if (!scp) + return ERR_PTR(-ENOMEM); + + scp->ctrl_reg.pwr_sta_offs = scp_ctrl_reg->pwr_sta_offs; + scp->ctrl_reg.pwr_sta2nd_offs = scp_ctrl_reg->pwr_sta2nd_offs; + + scp->bus_prot_reg_update = bus_prot_reg_update; + + scp->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + scp->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(scp->base)) + return ERR_CAST(scp->base); + + scp->domains = devm_kcalloc(&pdev->dev, + num, sizeof(*scp->domains), GFP_KERNEL); + if (!scp->domains) + return ERR_PTR(-ENOMEM); + + pd_data = &scp->pd_data; + + pd_data->domains = devm_kcalloc(&pdev->dev, + num, sizeof(*pd_data->domains), GFP_KERNEL); + if (!pd_data->domains) + return ERR_PTR(-ENOMEM); + + scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "infracfg"); + if (IS_ERR(scp->infracfg)) { + dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n", + PTR_ERR(scp->infracfg)); + return ERR_CAST(scp->infracfg); + } + + for (i = 0; i < num; i++) { + struct scp_domain *scpd = &scp->domains[i]; + const struct scp_domain_data *data = &scp_domain_data[i]; + + scpd->supply = devm_regulator_get_optional(&pdev->dev, data->name); + if (IS_ERR(scpd->supply)) { + if (PTR_ERR(scpd->supply) == -ENODEV) + scpd->supply = NULL; + else + return ERR_CAST(scpd->supply); + } + } + + pd_data->num_domains = num; + + init_clks(pdev, clk); + + for (i = 0; i < num; i++) { + struct scp_domain *scpd = &scp->domains[i]; + struct generic_pm_domain *genpd = &scpd->genpd; + const struct scp_domain_data *data = &scp_domain_data[i]; + + pd_data->domains[i] = genpd; + scpd->scp = scp; + + scpd->data = data; + + for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) { + struct clk *c = clk[data->clk_id[j]]; + + if (IS_ERR(c)) { + dev_err(&pdev->dev, "%s: clk unavailable\n", + data->name); + return ERR_CAST(c); + } + + scpd->clk[j] = c; + } + + genpd->name = data->name; + genpd->power_off = scpsys_power_off; + genpd->power_on = scpsys_power_on; + if (MTK_SCPD_CAPS(scpd, MTK_SCPD_ACTIVE_WAKEUP)) + genpd->flags |= GENPD_FLAG_ACTIVE_WAKEUP; + } + + return scp; +} + +static void mtk_register_power_domains(struct platform_device *pdev, + struct scp *scp, int num) +{ + struct genpd_onecell_data *pd_data; + int i, ret; + + for (i = 0; i < num; i++) { + struct scp_domain *scpd = &scp->domains[i]; + struct generic_pm_domain *genpd = &scpd->genpd; + bool on; + + /* + * Initially turn on all domains to make the domains usable + * with !CONFIG_PM and to get the hardware in sync with the + * software. The unused domains will be switched off during + * late_init time. + */ + on = !WARN_ON(genpd->power_on(genpd) < 0); + + pm_genpd_init(genpd, NULL, !on); + } + + /* + * We are not allowed to fail here since there is no way to unregister + * a power domain. Once registered above we have to keep the domains + * valid. + */ + + pd_data = &scp->pd_data; + + ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data); + if (ret) + dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret); +} + +/* + * MT2701 power domain support + */ + +static const struct scp_domain_data scp_domain_data_mt2701[] = { + [MT2701_POWER_DOMAIN_CONN] = { + .name = "conn", + .sta_mask = PWR_STATUS_CONN, + .ctl_offs = SPM_CONN_PWR_CON, + .bus_prot_mask = MT2701_TOP_AXI_PROT_EN_CONN_M | + MT2701_TOP_AXI_PROT_EN_CONN_S, + .clk_id = {CLK_NONE}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT2701_POWER_DOMAIN_DISP] = { + .name = "disp", + .sta_mask = PWR_STATUS_DISP, + .ctl_offs = SPM_DIS_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .clk_id = {CLK_MM}, + .bus_prot_mask = MT2701_TOP_AXI_PROT_EN_MM_M0, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT2701_POWER_DOMAIN_MFG] = { + .name = "mfg", + .sta_mask = PWR_STATUS_MFG, + .ctl_offs = SPM_MFG_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .clk_id = {CLK_MFG}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT2701_POWER_DOMAIN_VDEC] = { + .name = "vdec", + .sta_mask = PWR_STATUS_VDEC, + .ctl_offs = SPM_VDE_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .clk_id = {CLK_MM}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT2701_POWER_DOMAIN_ISP] = { + .name = "isp", + .sta_mask = PWR_STATUS_ISP, + .ctl_offs = SPM_ISP_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + .clk_id = {CLK_MM}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT2701_POWER_DOMAIN_BDP] = { + .name = "bdp", + .sta_mask = PWR_STATUS_BDP, + .ctl_offs = SPM_BDP_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .clk_id = {CLK_NONE}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT2701_POWER_DOMAIN_ETH] = { + .name = "eth", + .sta_mask = PWR_STATUS_ETH, + .ctl_offs = SPM_ETH_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_ETHIF}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT2701_POWER_DOMAIN_HIF] = { + .name = "hif", + .sta_mask = PWR_STATUS_HIF, + .ctl_offs = SPM_HIF_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_ETHIF}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT2701_POWER_DOMAIN_IFR_MSC] = { + .name = "ifr_msc", + .sta_mask = PWR_STATUS_IFR_MSC, + .ctl_offs = SPM_IFR_MSC_PWR_CON, + .clk_id = {CLK_NONE}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, +}; + +/* + * MT2712 power domain support + */ +static const struct scp_domain_data scp_domain_data_mt2712[] = { + [MT2712_POWER_DOMAIN_MM] = { + .name = "mm", + .sta_mask = PWR_STATUS_DISP, + .ctl_offs = SPM_DIS_PWR_CON, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .clk_id = {CLK_MM}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT2712_POWER_DOMAIN_VDEC] = { + .name = "vdec", + .sta_mask = PWR_STATUS_VDEC, + .ctl_offs = SPM_VDE_PWR_CON, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .clk_id = {CLK_MM, CLK_VDEC}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT2712_POWER_DOMAIN_VENC] = { + .name = "venc", + .sta_mask = PWR_STATUS_VENC, + .ctl_offs = SPM_VEN_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_MM, CLK_VENC, CLK_JPGDEC}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT2712_POWER_DOMAIN_ISP] = { + .name = "isp", + .sta_mask = PWR_STATUS_ISP, + .ctl_offs = SPM_ISP_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + .clk_id = {CLK_MM}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT2712_POWER_DOMAIN_AUDIO] = { + .name = "audio", + .sta_mask = PWR_STATUS_AUDIO, + .ctl_offs = SPM_AUDIO_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_AUDIO}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT2712_POWER_DOMAIN_USB] = { + .name = "usb", + .sta_mask = PWR_STATUS_USB, + .ctl_offs = SPM_USB_PWR_CON, + .sram_pdn_bits = GENMASK(10, 8), + .sram_pdn_ack_bits = GENMASK(14, 12), + .clk_id = {CLK_NONE}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT2712_POWER_DOMAIN_USB2] = { + .name = "usb2", + .sta_mask = PWR_STATUS_USB2, + .ctl_offs = SPM_USB2_PWR_CON, + .sram_pdn_bits = GENMASK(10, 8), + .sram_pdn_ack_bits = GENMASK(14, 12), + .clk_id = {CLK_NONE}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT2712_POWER_DOMAIN_MFG] = { + .name = "mfg", + .sta_mask = PWR_STATUS_MFG, + .ctl_offs = SPM_MFG_PWR_CON, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(16, 16), + .clk_id = {CLK_MFG}, + .bus_prot_mask = BIT(14) | BIT(21) | BIT(23), + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT2712_POWER_DOMAIN_MFG_SC1] = { + .name = "mfg_sc1", + .sta_mask = BIT(22), + .ctl_offs = 0x02c0, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(16, 16), + .clk_id = {CLK_NONE}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT2712_POWER_DOMAIN_MFG_SC2] = { + .name = "mfg_sc2", + .sta_mask = BIT(23), + .ctl_offs = 0x02c4, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(16, 16), + .clk_id = {CLK_NONE}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT2712_POWER_DOMAIN_MFG_SC3] = { + .name = "mfg_sc3", + .sta_mask = BIT(30), + .ctl_offs = 0x01f8, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(16, 16), + .clk_id = {CLK_NONE}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, +}; + +static const struct scp_subdomain scp_subdomain_mt2712[] = { + {MT2712_POWER_DOMAIN_MM, MT2712_POWER_DOMAIN_VDEC}, + {MT2712_POWER_DOMAIN_MM, MT2712_POWER_DOMAIN_VENC}, + {MT2712_POWER_DOMAIN_MM, MT2712_POWER_DOMAIN_ISP}, + {MT2712_POWER_DOMAIN_MFG, MT2712_POWER_DOMAIN_MFG_SC1}, + {MT2712_POWER_DOMAIN_MFG_SC1, MT2712_POWER_DOMAIN_MFG_SC2}, + {MT2712_POWER_DOMAIN_MFG_SC2, MT2712_POWER_DOMAIN_MFG_SC3}, +}; + +/* + * MT6797 power domain support + */ + +static const struct scp_domain_data scp_domain_data_mt6797[] = { + [MT6797_POWER_DOMAIN_VDEC] = { + .name = "vdec", + .sta_mask = BIT(7), + .ctl_offs = 0x300, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .clk_id = {CLK_VDEC}, + }, + [MT6797_POWER_DOMAIN_VENC] = { + .name = "venc", + .sta_mask = BIT(21), + .ctl_offs = 0x304, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_NONE}, + }, + [MT6797_POWER_DOMAIN_ISP] = { + .name = "isp", + .sta_mask = BIT(5), + .ctl_offs = 0x308, + .sram_pdn_bits = GENMASK(9, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + .clk_id = {CLK_NONE}, + }, + [MT6797_POWER_DOMAIN_MM] = { + .name = "mm", + .sta_mask = BIT(3), + .ctl_offs = 0x30C, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .clk_id = {CLK_MM}, + .bus_prot_mask = (BIT(1) | BIT(2)), + }, + [MT6797_POWER_DOMAIN_AUDIO] = { + .name = "audio", + .sta_mask = BIT(24), + .ctl_offs = 0x314, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_NONE}, + }, + [MT6797_POWER_DOMAIN_MFG_ASYNC] = { + .name = "mfg_async", + .sta_mask = BIT(13), + .ctl_offs = 0x334, + .sram_pdn_bits = 0, + .sram_pdn_ack_bits = 0, + .clk_id = {CLK_MFG}, + }, + [MT6797_POWER_DOMAIN_MJC] = { + .name = "mjc", + .sta_mask = BIT(20), + .ctl_offs = 0x310, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .clk_id = {CLK_NONE}, + }, +}; + +#define SPM_PWR_STATUS_MT6797 0x0180 +#define SPM_PWR_STATUS_2ND_MT6797 0x0184 + +static const struct scp_subdomain scp_subdomain_mt6797[] = { + {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_VDEC}, + {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_ISP}, + {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_VENC}, + {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_MJC}, +}; + +/* + * MT7622 power domain support + */ + +static const struct scp_domain_data scp_domain_data_mt7622[] = { + [MT7622_POWER_DOMAIN_ETHSYS] = { + .name = "ethsys", + .sta_mask = PWR_STATUS_ETHSYS, + .ctl_offs = SPM_ETHSYS_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_NONE}, + .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_ETHSYS, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT7622_POWER_DOMAIN_HIF0] = { + .name = "hif0", + .sta_mask = PWR_STATUS_HIF0, + .ctl_offs = SPM_HIF0_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_HIFSEL}, + .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_HIF0, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT7622_POWER_DOMAIN_HIF1] = { + .name = "hif1", + .sta_mask = PWR_STATUS_HIF1, + .ctl_offs = SPM_HIF1_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_HIFSEL}, + .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_HIF1, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT7622_POWER_DOMAIN_WB] = { + .name = "wb", + .sta_mask = PWR_STATUS_WB, + .ctl_offs = SPM_WB_PWR_CON, + .sram_pdn_bits = 0, + .sram_pdn_ack_bits = 0, + .clk_id = {CLK_NONE}, + .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_WB, + .caps = MTK_SCPD_ACTIVE_WAKEUP | MTK_SCPD_FWAIT_SRAM, + }, +}; + +/* + * MT7623A power domain support + */ + +static const struct scp_domain_data scp_domain_data_mt7623a[] = { + [MT7623A_POWER_DOMAIN_CONN] = { + .name = "conn", + .sta_mask = PWR_STATUS_CONN, + .ctl_offs = SPM_CONN_PWR_CON, + .bus_prot_mask = MT2701_TOP_AXI_PROT_EN_CONN_M | + MT2701_TOP_AXI_PROT_EN_CONN_S, + .clk_id = {CLK_NONE}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT7623A_POWER_DOMAIN_ETH] = { + .name = "eth", + .sta_mask = PWR_STATUS_ETH, + .ctl_offs = SPM_ETH_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_ETHIF}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT7623A_POWER_DOMAIN_HIF] = { + .name = "hif", + .sta_mask = PWR_STATUS_HIF, + .ctl_offs = SPM_HIF_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_ETHIF}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT7623A_POWER_DOMAIN_IFR_MSC] = { + .name = "ifr_msc", + .sta_mask = PWR_STATUS_IFR_MSC, + .ctl_offs = SPM_IFR_MSC_PWR_CON, + .clk_id = {CLK_NONE}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, +}; + +/* + * MT8173 power domain support + */ + +static const struct scp_domain_data scp_domain_data_mt8173[] = { + [MT8173_POWER_DOMAIN_VDEC] = { + .name = "vdec", + .sta_mask = PWR_STATUS_VDEC, + .ctl_offs = SPM_VDE_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .clk_id = {CLK_MM}, + }, + [MT8173_POWER_DOMAIN_VENC] = { + .name = "venc", + .sta_mask = PWR_STATUS_VENC, + .ctl_offs = SPM_VEN_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_MM, CLK_VENC}, + }, + [MT8173_POWER_DOMAIN_ISP] = { + .name = "isp", + .sta_mask = PWR_STATUS_ISP, + .ctl_offs = SPM_ISP_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + .clk_id = {CLK_MM}, + }, + [MT8173_POWER_DOMAIN_MM] = { + .name = "mm", + .sta_mask = PWR_STATUS_DISP, + .ctl_offs = SPM_DIS_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .clk_id = {CLK_MM}, + .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | + MT8173_TOP_AXI_PROT_EN_MM_M1, + }, + [MT8173_POWER_DOMAIN_VENC_LT] = { + .name = "venc_lt", + .sta_mask = PWR_STATUS_VENC_LT, + .ctl_offs = SPM_VEN2_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_MM, CLK_VENC_LT}, + }, + [MT8173_POWER_DOMAIN_AUDIO] = { + .name = "audio", + .sta_mask = PWR_STATUS_AUDIO, + .ctl_offs = SPM_AUDIO_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_NONE}, + }, + [MT8173_POWER_DOMAIN_USB] = { + .name = "usb", + .sta_mask = PWR_STATUS_USB, + .ctl_offs = SPM_USB_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_NONE}, + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT8173_POWER_DOMAIN_MFG_ASYNC] = { + .name = "mfg_async", + .sta_mask = PWR_STATUS_MFG_ASYNC, + .ctl_offs = SPM_MFG_ASYNC_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = 0, + .clk_id = {CLK_MFG}, + }, + [MT8173_POWER_DOMAIN_MFG_2D] = { + .name = "mfg_2d", + .sta_mask = PWR_STATUS_MFG_2D, + .ctl_offs = SPM_MFG_2D_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + .clk_id = {CLK_NONE}, + }, + [MT8173_POWER_DOMAIN_MFG] = { + .name = "mfg", + .sta_mask = PWR_STATUS_MFG, + .ctl_offs = SPM_MFG_PWR_CON, + .sram_pdn_bits = GENMASK(13, 8), + .sram_pdn_ack_bits = GENMASK(21, 16), + .clk_id = {CLK_NONE}, + .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | + MT8173_TOP_AXI_PROT_EN_MFG_M0 | + MT8173_TOP_AXI_PROT_EN_MFG_M1 | + MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT, + }, +}; + +static const struct scp_subdomain scp_subdomain_mt8173[] = { + {MT8173_POWER_DOMAIN_MFG_ASYNC, MT8173_POWER_DOMAIN_MFG_2D}, + {MT8173_POWER_DOMAIN_MFG_2D, MT8173_POWER_DOMAIN_MFG}, +}; + +static const struct scp_soc_data mt2701_data = { + .domains = scp_domain_data_mt2701, + .num_domains = ARRAY_SIZE(scp_domain_data_mt2701), + .regs = { + .pwr_sta_offs = SPM_PWR_STATUS, + .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND + }, + .bus_prot_reg_update = true, +}; + +static const struct scp_soc_data mt2712_data = { + .domains = scp_domain_data_mt2712, + .num_domains = ARRAY_SIZE(scp_domain_data_mt2712), + .subdomains = scp_subdomain_mt2712, + .num_subdomains = ARRAY_SIZE(scp_subdomain_mt2712), + .regs = { + .pwr_sta_offs = SPM_PWR_STATUS, + .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND + }, + .bus_prot_reg_update = false, +}; + +static const struct scp_soc_data mt6797_data = { + .domains = scp_domain_data_mt6797, + .num_domains = ARRAY_SIZE(scp_domain_data_mt6797), + .subdomains = scp_subdomain_mt6797, + .num_subdomains = ARRAY_SIZE(scp_subdomain_mt6797), + .regs = { + .pwr_sta_offs = SPM_PWR_STATUS_MT6797, + .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND_MT6797 + }, + .bus_prot_reg_update = true, +}; + +static const struct scp_soc_data mt7622_data = { + .domains = scp_domain_data_mt7622, + .num_domains = ARRAY_SIZE(scp_domain_data_mt7622), + .regs = { + .pwr_sta_offs = SPM_PWR_STATUS, + .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND + }, + .bus_prot_reg_update = true, +}; + +static const struct scp_soc_data mt7623a_data = { + .domains = scp_domain_data_mt7623a, + .num_domains = ARRAY_SIZE(scp_domain_data_mt7623a), + .regs = { + .pwr_sta_offs = SPM_PWR_STATUS, + .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND + }, + .bus_prot_reg_update = true, +}; + +static const struct scp_soc_data mt8173_data = { + .domains = scp_domain_data_mt8173, + .num_domains = ARRAY_SIZE(scp_domain_data_mt8173), + .subdomains = scp_subdomain_mt8173, + .num_subdomains = ARRAY_SIZE(scp_subdomain_mt8173), + .regs = { + .pwr_sta_offs = SPM_PWR_STATUS, + .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND + }, + .bus_prot_reg_update = true, +}; + +/* + * scpsys driver init + */ + +static const struct of_device_id of_scpsys_match_tbl[] = { + { + .compatible = "mediatek,mt2701-scpsys", + .data = &mt2701_data, + }, { + .compatible = "mediatek,mt2712-scpsys", + .data = &mt2712_data, + }, { + .compatible = "mediatek,mt6797-scpsys", + .data = &mt6797_data, + }, { + .compatible = "mediatek,mt7622-scpsys", + .data = &mt7622_data, + }, { + .compatible = "mediatek,mt7623a-scpsys", + .data = &mt7623a_data, + }, { + .compatible = "mediatek,mt8173-scpsys", + .data = &mt8173_data, + }, { + /* sentinel */ + } +}; + +static int scpsys_probe(struct platform_device *pdev) +{ + const struct scp_subdomain *sd; + const struct scp_soc_data *soc; + struct scp *scp; + struct genpd_onecell_data *pd_data; + int i, ret; + + soc = of_device_get_match_data(&pdev->dev); + + scp = init_scp(pdev, soc->domains, soc->num_domains, &soc->regs, + soc->bus_prot_reg_update); + if (IS_ERR(scp)) + return PTR_ERR(scp); + + mtk_register_power_domains(pdev, scp, soc->num_domains); + + pd_data = &scp->pd_data; + + for (i = 0, sd = soc->subdomains; i < soc->num_subdomains; i++, sd++) { + ret = pm_genpd_add_subdomain(pd_data->domains[sd->origin], + pd_data->domains[sd->subdomain]); + if (ret && IS_ENABLED(CONFIG_PM)) + dev_err(&pdev->dev, "Failed to add subdomain: %d\n", + ret); + } + + return 0; +} + +static struct platform_driver scpsys_drv = { + .probe = scpsys_probe, + .driver = { + .name = "mtk-scpsys", + .suppress_bind_attrs = true, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(of_scpsys_match_tbl), + }, +}; +builtin_platform_driver(scpsys_drv); |