Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
+92
View File
@@ -0,0 +1,92 @@
# 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_DEVAPC
tristate "Mediatek Device APC Support"
help
Say yes here to enable support for Mediatek Device APC driver.
This driver is mainly used to handle the violation which catches
unexpected transaction.
The violation information is logged for further analysis or
countermeasures.
config MTK_DVFSRC
tristate "MediaTek DVFSRC Support"
depends on ARCH_MEDIATEK
help
Say yes here to add support for the MediaTek Dynamic Voltage
and Frequency Scaling Resource Collector (DVFSRC): a HW
IP found on many MediaTek SoCs, which is responsible for
collecting DVFS requests from various SoC IPs, other than
software, and performing bandwidth scaling to provide the
best achievable performance-per-watt.
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
depends on OF
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_REGULATOR_COUPLER
bool "MediaTek SoC Regulator Coupler" if COMPILE_TEST
default ARCH_MEDIATEK
depends on REGULATOR
config MTK_MMSYS
tristate "MediaTek MMSYS Support"
default ARCH_MEDIATEK
depends on HAS_IOMEM
depends on MTK_CMDQ || MTK_CMDQ=n
help
Say yes here to add support for the MediaTek Multimedia
Subsystem (MMSYS).
config MTK_SVS
tristate "MediaTek Smart Voltage Scaling(SVS)"
depends on NVMEM_MTK_EFUSE && NVMEM
help
The Smart Voltage Scaling(SVS) engine is a piece of hardware
which has several controllers(banks) for calculating suitable
voltage to different power domains(CPU/GPU/CCI) according to
chip process corner, temperatures and other factors. Then DVFS
driver could apply SVS bank voltage to PMIC/Buck.
config MTK_SOCINFO
tristate "MediaTek SoC Information"
default y
depends on NVMEM_MTK_EFUSE
select SOC_BUS
help
The MediaTek SoC Information (mtk-socinfo) driver provides
information about the SoC to the userspace including the
manufacturer name, marketing name and soc name.
endmenu
+11
View File
@@ -0,0 +1,11 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq-helper.o
obj-$(CONFIG_MTK_DEVAPC) += mtk-devapc.o
obj-$(CONFIG_MTK_DVFSRC) += mtk-dvfsrc.o
obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o
obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
obj-$(CONFIG_MTK_REGULATOR_COUPLER) += mtk-regulator-coupler.o
obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o
obj-$(CONFIG_MTK_MMSYS) += mtk-mutex.o
obj-$(CONFIG_MTK_SVS) += mtk-svs.o
obj-$(CONFIG_MTK_SOCINFO) += mtk-socinfo.o
@@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __SOC_MEDIATEK_MT8167_MMSYS_H
#define __SOC_MEDIATEK_MT8167_MMSYS_H
#define MT8167_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN 0x030
#define MT8167_DISP_REG_CONFIG_DISP_DITHER_MOUT_EN 0x038
#define MT8167_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0x058
#define MT8167_DISP_REG_CONFIG_DISP_DSI0_SEL_IN 0x064
#define MT8167_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN 0x06c
#define MT8167_DITHER_MOUT_EN_RDMA0 0x1
#define MT8167_DITHER_MOUT_EN_MASK 0x7
#define MT8167_RDMA0_SOUT_DSI0 0x2
#define MT8167_RDMA0_SOUT_MASK 0x3
#define MT8167_DSI0_SEL_IN_RDMA0 0x1
#define MT8167_DSI0_SEL_IN_MASK 0x3
static const struct mtk_mmsys_routes mt8167_mmsys_routing_table[] = {
MMSYS_ROUTE(OVL0, COLOR0,
MT8167_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN, OVL0_MOUT_EN_COLOR0,
OVL0_MOUT_EN_COLOR0),
MMSYS_ROUTE(DITHER0, RDMA0,
MT8167_DISP_REG_CONFIG_DISP_DITHER_MOUT_EN, MT8167_DITHER_MOUT_EN_MASK,
MT8167_DITHER_MOUT_EN_RDMA0),
MMSYS_ROUTE(OVL0, COLOR0,
MT8167_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN, COLOR0_SEL_IN_OVL0,
COLOR0_SEL_IN_OVL0),
MMSYS_ROUTE(RDMA0, DSI0,
MT8167_DISP_REG_CONFIG_DISP_DSI0_SEL_IN, MT8167_DSI0_SEL_IN_MASK,
MT8167_DSI0_SEL_IN_RDMA0),
MMSYS_ROUTE(RDMA0, DSI0,
MT8167_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN, MT8167_RDMA0_SOUT_MASK,
MT8167_RDMA0_SOUT_DSI0),
};
#endif /* __SOC_MEDIATEK_MT8167_MMSYS_H */
@@ -0,0 +1,80 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __SOC_MEDIATEK_MT8173_MMSYS_H
#define __SOC_MEDIATEK_MT8173_MMSYS_H
#define MT8173_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN 0x040
#define MT8173_DISP_REG_CONFIG_DISP_OVL1_MOUT_EN 0x044
#define MT8173_DISP_REG_CONFIG_DISP_OD_MOUT_EN 0x048
#define MT8173_DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN 0x04c
#define MT8173_DISP_REG_CONFIG_DISP_UFOE_MOUT_EN 0x050
#define MT8173_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0x084
#define MT8173_DISP_REG_CONFIG_DISP_COLOR1_SEL_IN 0x088
#define MT8173_DISP_REG_CONFIG_DISP_AAL_SEL_IN 0x08c
#define MT8173_DISP_REG_CONFIG_DISP_UFOE_SEL_IN 0x0a0
#define MT8173_DISP_REG_CONFIG_DSI0_SEL_IN 0x0a4
#define MT8173_DISP_REG_CONFIG_DPI_SEL_IN 0x0ac
#define MT8173_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN 0x0b0
#define MT8173_DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN 0x0c8
#define MT8173_DISP_REG_CONFIG_DISP_COLOR0_SOUT_SEL_IN 0x0bc
#define MT8173_AAL_SEL_IN_MERGE BIT(0)
#define MT8173_COLOR0_SEL_IN_OVL0 BIT(0)
#define MT8173_COLOR0_SOUT_MERGE BIT(0)
#define MT8173_DPI0_SEL_IN_MASK GENMASK(1, 0)
#define MT8173_DPI0_SEL_IN_RDMA1 BIT(0)
#define MT8173_DSI0_SEL_IN_UFOE BIT(0)
#define MT8173_GAMMA_MOUT_EN_RDMA1 BIT(0)
#define MT8173_OD0_MOUT_EN_RDMA0 BIT(0)
#define MT8173_OVL0_MOUT_EN_COLOR0 BIT(0)
#define MT8173_OVL1_MOUT_EN_COLOR1 BIT(0)
#define MT8173_UFOE_MOUT_EN_DSI0 BIT(0)
#define MT8173_UFOE_SEL_IN_RDMA0 BIT(0)
#define MT8173_RDMA0_SOUT_COLOR0 BIT(0)
static const struct mtk_mmsys_routes mt8173_mmsys_routing_table[] = {
MMSYS_ROUTE(OVL0, COLOR0,
MT8173_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN, MT8173_OVL0_MOUT_EN_COLOR0,
MT8173_OVL0_MOUT_EN_COLOR0),
MMSYS_ROUTE(OD0, RDMA0,
MT8173_DISP_REG_CONFIG_DISP_OD_MOUT_EN, MT8173_OD0_MOUT_EN_RDMA0,
MT8173_OD0_MOUT_EN_RDMA0),
MMSYS_ROUTE(UFOE, DSI0,
MT8173_DISP_REG_CONFIG_DISP_UFOE_MOUT_EN, MT8173_UFOE_MOUT_EN_DSI0,
MT8173_UFOE_MOUT_EN_DSI0),
MMSYS_ROUTE(COLOR0, AAL0,
MT8173_DISP_REG_CONFIG_DISP_COLOR0_SOUT_SEL_IN, MT8173_COLOR0_SOUT_MERGE,
0 /* SOUT to AAL */),
MMSYS_ROUTE(RDMA0, UFOE,
MT8173_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN, MT8173_RDMA0_SOUT_COLOR0,
0 /* SOUT to UFOE */),
MMSYS_ROUTE(OVL0, COLOR0,
MT8173_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN, MT8173_COLOR0_SEL_IN_OVL0,
MT8173_COLOR0_SEL_IN_OVL0),
MMSYS_ROUTE(AAL0, COLOR0,
MT8173_DISP_REG_CONFIG_DISP_AAL_SEL_IN, MT8173_AAL_SEL_IN_MERGE,
0 /* SEL_IN from COLOR0 */),
MMSYS_ROUTE(RDMA0, UFOE,
MT8173_DISP_REG_CONFIG_DISP_UFOE_SEL_IN, MT8173_UFOE_SEL_IN_RDMA0,
0 /* SEL_IN from RDMA0 */),
MMSYS_ROUTE(UFOE, DSI0,
MT8173_DISP_REG_CONFIG_DSI0_SEL_IN, MT8173_DSI0_SEL_IN_UFOE,
0 /* SEL_IN from UFOE */),
MMSYS_ROUTE(OVL1, COLOR1,
MT8173_DISP_REG_CONFIG_DISP_OVL1_MOUT_EN, MT8173_OVL1_MOUT_EN_COLOR1,
MT8173_OVL1_MOUT_EN_COLOR1),
MMSYS_ROUTE(GAMMA, RDMA1,
MT8173_DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN, MT8173_GAMMA_MOUT_EN_RDMA1,
MT8173_GAMMA_MOUT_EN_RDMA1),
MMSYS_ROUTE(RDMA1, DPI0,
MT8173_DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK,
RDMA1_SOUT_DPI0),
MMSYS_ROUTE(OVL1, COLOR1,
MT8173_DISP_REG_CONFIG_DISP_COLOR1_SEL_IN, COLOR1_SEL_IN_OVL1,
COLOR1_SEL_IN_OVL1),
MMSYS_ROUTE(RDMA1, DPI0,
MT8173_DISP_REG_CONFIG_DPI_SEL_IN, MT8173_DPI0_SEL_IN_MASK,
MT8173_DPI0_SEL_IN_RDMA1),
};
#endif /* __SOC_MEDIATEK_MT8173_MMSYS_H */
@@ -0,0 +1,55 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __SOC_MEDIATEK_MT8183_MMSYS_H
#define __SOC_MEDIATEK_MT8183_MMSYS_H
#define MT8183_DISP_OVL0_MOUT_EN 0xf00
#define MT8183_DISP_OVL0_2L_MOUT_EN 0xf04
#define MT8183_DISP_OVL1_2L_MOUT_EN 0xf08
#define MT8183_DISP_DITHER0_MOUT_EN 0xf0c
#define MT8183_DISP_PATH0_SEL_IN 0xf24
#define MT8183_DISP_DSI0_SEL_IN 0xf2c
#define MT8183_DISP_DPI0_SEL_IN 0xf30
#define MT8183_DISP_RDMA0_SOUT_SEL_IN 0xf50
#define MT8183_DISP_RDMA1_SOUT_SEL_IN 0xf54
#define MT8183_OVL0_MOUT_EN_OVL0_2L BIT(4)
#define MT8183_OVL0_2L_MOUT_EN_DISP_PATH0 BIT(0)
#define MT8183_OVL1_2L_MOUT_EN_RDMA1 BIT(4)
#define MT8183_DITHER0_MOUT_IN_DSI0 BIT(0)
#define MT8183_DISP_PATH0_SEL_IN_OVL0_2L 0x1
#define MT8183_DSI0_SEL_IN_RDMA0 0x1
#define MT8183_DSI0_SEL_IN_RDMA1 0x3
#define MT8183_DPI0_SEL_IN_RDMA0 0x1
#define MT8183_DPI0_SEL_IN_RDMA1 0x2
#define MT8183_RDMA0_SOUT_COLOR0 0x1
#define MT8183_RDMA1_SOUT_DSI0 0x1
#define MT8183_MMSYS_SW0_RST_B 0x140
static const struct mtk_mmsys_routes mmsys_mt8183_routing_table[] = {
MMSYS_ROUTE(OVL0, OVL_2L0,
MT8183_DISP_OVL0_MOUT_EN, MT8183_OVL0_MOUT_EN_OVL0_2L,
MT8183_OVL0_MOUT_EN_OVL0_2L),
MMSYS_ROUTE(OVL_2L0, RDMA0,
MT8183_DISP_OVL0_2L_MOUT_EN, MT8183_OVL0_2L_MOUT_EN_DISP_PATH0,
MT8183_OVL0_2L_MOUT_EN_DISP_PATH0),
MMSYS_ROUTE(OVL_2L1, RDMA1,
MT8183_DISP_OVL1_2L_MOUT_EN, MT8183_OVL1_2L_MOUT_EN_RDMA1,
MT8183_OVL1_2L_MOUT_EN_RDMA1),
MMSYS_ROUTE(DITHER0, DSI0,
MT8183_DISP_DITHER0_MOUT_EN, MT8183_DITHER0_MOUT_IN_DSI0,
MT8183_DITHER0_MOUT_IN_DSI0),
MMSYS_ROUTE(OVL_2L0, RDMA0,
MT8183_DISP_PATH0_SEL_IN, MT8183_DISP_PATH0_SEL_IN_OVL0_2L,
MT8183_DISP_PATH0_SEL_IN_OVL0_2L),
MMSYS_ROUTE(RDMA1, DPI0,
MT8183_DISP_DPI0_SEL_IN, MT8183_DPI0_SEL_IN_RDMA1,
MT8183_DPI0_SEL_IN_RDMA1),
MMSYS_ROUTE(RDMA0, COLOR0,
MT8183_DISP_RDMA0_SOUT_SEL_IN, MT8183_RDMA0_SOUT_COLOR0,
MT8183_RDMA0_SOUT_COLOR0),
};
#endif /* __SOC_MEDIATEK_MT8183_MMSYS_H */
@@ -0,0 +1,101 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __SOC_MEDIATEK_MT8186_MMSYS_H
#define __SOC_MEDIATEK_MT8186_MMSYS_H
/* Values for DPI configuration in MMSYS address space */
#define MT8186_MMSYS_DPI_OUTPUT_FORMAT 0x400
#define MT8186_DPI_FORMAT_MASK GENMASK(1, 0)
#define MT8186_DPI_RGB888_SDR_CON 0
#define MT8186_DPI_RGB888_DDR_CON 1
#define MT8186_DPI_RGB565_SDR_CON 2
#define MT8186_DPI_RGB565_DDR_CON 3
#define MT8186_MMSYS_OVL_CON 0xF04
#define MT8186_MMSYS_OVL0_CON_MASK 0x3
#define MT8186_MMSYS_OVL0_2L_CON_MASK 0xC
#define MT8186_OVL0_GO_BLEND BIT(0)
#define MT8186_OVL0_GO_BG BIT(1)
#define MT8186_OVL0_2L_GO_BLEND BIT(2)
#define MT8186_OVL0_2L_GO_BG BIT(3)
#define MT8186_DISP_RDMA0_SOUT_SEL 0xF0C
#define MT8186_RDMA0_SOUT_SEL_MASK 0xF
#define MT8186_RDMA0_SOUT_TO_DSI0 (0)
#define MT8186_RDMA0_SOUT_TO_COLOR0 (1)
#define MT8186_RDMA0_SOUT_TO_DPI0 (2)
#define MT8186_DISP_OVL0_2L_MOUT_EN 0xF14
#define MT8186_OVL0_2L_MOUT_EN_MASK 0xF
#define MT8186_OVL0_2L_MOUT_TO_RDMA0 BIT(0)
#define MT8186_OVL0_2L_MOUT_TO_RDMA1 BIT(3)
#define MT8186_DISP_OVL0_MOUT_EN 0xF18
#define MT8186_OVL0_MOUT_EN_MASK 0xF
#define MT8186_OVL0_MOUT_TO_RDMA0 BIT(0)
#define MT8186_OVL0_MOUT_TO_RDMA1 BIT(3)
#define MT8186_DISP_DITHER0_MOUT_EN 0xF20
#define MT8186_DITHER0_MOUT_EN_MASK 0xF
#define MT8186_DITHER0_MOUT_TO_DSI0 BIT(0)
#define MT8186_DITHER0_MOUT_TO_RDMA1 BIT(2)
#define MT8186_DITHER0_MOUT_TO_DPI0 BIT(3)
#define MT8186_DISP_RDMA0_SEL_IN 0xF28
#define MT8186_RDMA0_SEL_IN_MASK 0xF
#define MT8186_RDMA0_FROM_OVL0 0
#define MT8186_RDMA0_FROM_OVL0_2L 2
#define MT8186_DISP_DSI0_SEL_IN 0xF30
#define MT8186_DSI0_SEL_IN_MASK 0xF
#define MT8186_DSI0_FROM_RDMA0 0
#define MT8186_DSI0_FROM_DITHER0 1
#define MT8186_DSI0_FROM_RDMA1 2
#define MT8186_DISP_RDMA1_MOUT_EN 0xF3C
#define MT8186_RDMA1_MOUT_EN_MASK 0xF
#define MT8186_RDMA1_MOUT_TO_DPI0_SEL BIT(0)
#define MT8186_RDMA1_MOUT_TO_DSI0_SEL BIT(2)
#define MT8186_DISP_RDMA1_SEL_IN 0xF40
#define MT8186_RDMA1_SEL_IN_MASK 0xF
#define MT8186_RDMA1_FROM_OVL0 0
#define MT8186_RDMA1_FROM_OVL0_2L 2
#define MT8186_RDMA1_FROM_DITHER0 3
#define MT8186_DISP_DPI0_SEL_IN 0xF44
#define MT8186_DPI0_SEL_IN_MASK 0xF
#define MT8186_DPI0_FROM_RDMA1 0
#define MT8186_DPI0_FROM_DITHER0 1
#define MT8186_DPI0_FROM_RDMA0 2
#define MT8186_MMSYS_SW0_RST_B 0x160
static const struct mtk_mmsys_routes mmsys_mt8186_routing_table[] = {
MMSYS_ROUTE(OVL0, RDMA0,
MT8186_DISP_OVL0_MOUT_EN, MT8186_OVL0_MOUT_EN_MASK,
MT8186_OVL0_MOUT_TO_RDMA0),
MMSYS_ROUTE(OVL0, RDMA0,
MT8186_DISP_RDMA0_SEL_IN, MT8186_RDMA0_SEL_IN_MASK,
MT8186_RDMA0_FROM_OVL0),
MMSYS_ROUTE(OVL0, RDMA0,
MT8186_MMSYS_OVL_CON, MT8186_MMSYS_OVL0_CON_MASK,
MT8186_OVL0_GO_BLEND),
MMSYS_ROUTE(RDMA0, COLOR0,
MT8186_DISP_RDMA0_SOUT_SEL, MT8186_RDMA0_SOUT_SEL_MASK,
MT8186_RDMA0_SOUT_TO_COLOR0),
MMSYS_ROUTE(DITHER0, DSI0,
MT8186_DISP_DITHER0_MOUT_EN, MT8186_DITHER0_MOUT_EN_MASK,
MT8186_DITHER0_MOUT_TO_DSI0),
MMSYS_ROUTE(DITHER0, DSI0,
MT8186_DISP_DSI0_SEL_IN, MT8186_DSI0_SEL_IN_MASK,
MT8186_DSI0_FROM_DITHER0),
MMSYS_ROUTE(OVL_2L0, RDMA1,
MT8186_DISP_OVL0_2L_MOUT_EN, MT8186_OVL0_2L_MOUT_EN_MASK,
MT8186_OVL0_2L_MOUT_TO_RDMA1),
MMSYS_ROUTE(OVL_2L0, RDMA1,
MT8186_DISP_RDMA1_SEL_IN, MT8186_RDMA1_SEL_IN_MASK,
MT8186_RDMA1_FROM_OVL0_2L),
MMSYS_ROUTE(OVL_2L0, RDMA1,
MT8186_MMSYS_OVL_CON, MT8186_MMSYS_OVL0_2L_CON_MASK,
MT8186_OVL0_2L_GO_BLEND),
MMSYS_ROUTE(RDMA1, DPI0,
MT8186_DISP_RDMA1_MOUT_EN, MT8186_RDMA1_MOUT_EN_MASK,
MT8186_RDMA1_MOUT_TO_DPI0_SEL),
MMSYS_ROUTE(RDMA1, DPI0,
MT8186_DISP_DPI0_SEL_IN, MT8186_DPI0_SEL_IN_MASK,
MT8186_DPI0_FROM_RDMA1),
};
#endif /* __SOC_MEDIATEK_MT8186_MMSYS_H */
@@ -0,0 +1,327 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __SOC_MEDIATEK_MT8188_MMSYS_H
#define __SOC_MEDIATEK_MT8188_MMSYS_H
#include <linux/soc/mediatek/mtk-mmsys.h>
#include <dt-bindings/reset/mt8188-resets.h>
#define MT8188_VDO0_SW0_RST_B 0x190
#define MT8188_VDO0_OVL_MOUT_EN 0xf14
#define MT8188_MOUT_DISP_OVL0_TO_DISP_RDMA0 BIT(0)
#define MT8188_MOUT_DISP_OVL0_TO_DISP_WDMA0 BIT(1)
#define MT8188_MOUT_DISP_OVL0_TO_DISP_OVL1 BIT(2)
#define MT8188_MOUT_DISP_OVL1_TO_DISP_RDMA1 BIT(4)
#define MT8188_MOUT_DISP_OVL1_TO_DISP_WDMA1 BIT(5)
#define MT8188_MOUT_DISP_OVL1_TO_DISP_OVL0 BIT(6)
#define MT8188_VDO0_SEL_IN 0xf34
#define MT8188_VDO0_SEL_OUT 0xf38
#define MT8188_VDO0_DISP_RDMA_SEL 0xf40
#define MT8188_SOUT_DISP_RDMA0_TO_MASK GENMASK(2, 0)
#define MT8188_SOUT_DISP_RDMA0_TO_DISP_COLOR0 (0 << 0)
#define MT8188_SOUT_DISP_RDMA0_TO_DISP_DSI0 (1 << 0)
#define MT8188_SOUT_DISP_RDMA0_TO_DISP_DP_INTF0 (5 << 0)
#define MT8188_SEL_IN_DISP_RDMA0_FROM_MASK GENMASK(8, 8)
#define MT8188_SEL_IN_DISP_RDMA0_FROM_DISP_OVL0 (0 << 8)
#define MT8188_SEL_IN_DISP_RDMA0_FROM_DISP_RSZ0 (1 << 8)
#define MT8188_VDO0_DSI0_SEL_IN 0xf44
#define MT8188_SEL_IN_DSI0_FROM_MASK BIT(0)
#define MT8188_SEL_IN_DSI0_FROM_DSC_WRAP0_OUT (0 << 0)
#define MT8188_SEL_IN_DSI0_FROM_DISP_DITHER0 (1 << 0)
#define MT8188_VDO0_DP_INTF0_SEL_IN 0xf4C
#define MT8188_SEL_IN_DP_INTF0_FROM_MASK GENMASK(2, 0)
#define MT8188_SEL_IN_DP_INTF0_FROM_DSC_WRAP0C1_OUT (0 << 0)
#define MT8188_SEL_IN_DP_INTF0_FROM_VPP_MERGE (1 << 0)
#define MT8188_SEL_IN_DP_INTF0_FROM_DISP_DITHER0 (3 << 0)
#define MT8188_VDO0_DISP_DITHER0_SEL_OUT 0xf58
#define MT8188_SOUT_DISP_DITHER0_TO_MASK GENMASK(2, 0)
#define MT8188_SOUT_DISP_DITHER0_TO_DSC_WRAP0_IN (0 << 0)
#define MT8188_SOUT_DISP_DITHER0_TO_DSI0 (1 << 0)
#define MT8188_SOUT_DISP_DITHER0_TO_VPP_MERGE0 (6 << 0)
#define MT8188_SOUT_DISP_DITHER0_TO_DP_INTF0 (7 << 0)
#define MT8188_VDO0_VPP_MERGE_SEL 0xf60
#define MT8188_SEL_IN_VPP_MERGE_FROM_MASK GENMASK(1, 0)
#define MT8188_SEL_IN_VPP_MERGE_FROM_DSC_WRAP0_OUT (0 << 0)
#define MT8188_SEL_IN_VPP_MERGE_FROM_DITHER0_OUT (3 << 0)
#define MT8188_SOUT_VPP_MERGE_TO_MASK GENMASK(6, 4)
#define MT8188_SOUT_VPP_MERGE_TO_DSI1 (0 << 4)
#define MT8188_SOUT_VPP_MERGE_TO_DP_INTF0 (1 << 4)
#define MT8188_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0 (2 << 4)
#define MT8188_SOUT_VPP_MERGE_TO_DISP_WDMA1 (3 << 4)
#define MT8188_SOUT_VPP_MERGE_TO_DSC_WRAP0_IN (4 << 4)
#define MT8188_SOUT_VPP_MERGE_TO_DISP_WDMA0 (5 << 4)
#define MT8188_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN_MASK GENMASK(11, 11)
#define MT8188_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN (0 << 11)
#define MT8188_VDO0_DSC_WARP_SEL 0xf64
#define MT8188_SEL_IN_DSC_WRAP0C0_IN_FROM_MASK GENMASK(0, 0)
#define MT8188_SEL_IN_DSC_WRAP0C0_IN_FROM_DISP_DITHER0 (0 << 0)
#define MT8188_SEL_IN_DSC_WRAP0C0_IN_FROM_VPP_MERGE (1 << 0)
#define MT8188_SOUT_DSC_WRAP0_OUT_TO_MASK GENMASK(19, 16)
#define MT8188_SOUT_DSC_WRAP0_OUT_TO_DSI0 BIT(16)
#define MT8188_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0 BIT(17)
#define MT8188_SOUT_DSC_WRAP0_OUT_TO_VPP_MERGE BIT(18)
#define MT8188_SOUT_DSC_WRAP0_OUT_TO_DISP_WDMA0 BIT(19)
#define MT8188_VDO1_SW0_RST_B 0x1d0
#define MT8188_VDO1_HDR_TOP_CFG 0xd00
#define MT8188_VDO1_MIXER_IN1_ALPHA 0xd30
#define MT8188_VDO1_MIXER_IN1_PAD 0xd40
#define MT8188_VDO1_MIXER_VSYNC_LEN 0xd5c
#define MT8188_VDO1_MERGE0_ASYNC_CFG_WD 0xe30
#define MT8188_VDO1_HDRBE_ASYNC_CFG_WD 0xe70
#define MT8188_VDO1_VPP_MERGE0_P0_SEL_IN 0xf04
#define MT8188_VPP_MERGE0_P0_SEL_IN_FROM_MDP_RDMA0 1
#define MT8188_VDO1_VPP_MERGE0_P1_SEL_IN 0xf08
#define MT8188_VPP_MERGE0_P1_SEL_IN_FROM_MDP_RDMA1 1
#define MT8188_VDO1_DISP_DPI1_SEL_IN 0xf10
#define MT8188_DISP_DPI1_SEL_IN_FROM_VPP_MERGE4_MOUT 0
#define MT8188_VDO1_DISP_DP_INTF0_SEL_IN 0xf14
#define MT8188_DISP_DP_INTF0_SEL_IN_FROM_VPP_MERGE4_MOUT 0
#define MT8188_VDO1_MERGE4_SOUT_SEL 0xf18
#define MT8188_MERGE4_SOUT_TO_DPI1_SEL BIT(2)
#define MT8188_MERGE4_SOUT_TO_DP_INTF0_SEL BIT(3)
#define MT8188_VDO1_MIXER_IN1_SEL_IN 0xf24
#define MT8188_MIXER_IN1_SEL_IN_FROM_MERGE0_ASYNC_SOUT 1
#define MT8188_VDO1_MIXER_IN2_SEL_IN 0xf28
#define MT8188_MIXER_IN2_SEL_IN_FROM_MERGE1_ASYNC_SOUT 1
#define MT8188_VDO1_MIXER_IN3_SEL_IN 0xf2c
#define MT8188_MIXER_IN3_SEL_IN_FROM_MERGE2_ASYNC_SOUT 1
#define MT8188_VDO1_MIXER_IN4_SEL_IN 0xf30
#define MT8188_MIXER_IN4_SEL_IN_FROM_MERGE3_ASYNC_SOUT 1
#define MT8188_VDO1_MIXER_OUT_SOUT_SEL 0xf34
#define MT8188_MIXER_SOUT_TO_MERGE4_ASYNC_SEL 1
#define MT8188_VDO1_VPP_MERGE1_P0_SEL_IN 0xf3c
#define MT8188_VPP_MERGE1_P0_SEL_IN_FROM_MDP_RDMA2 1
#define MT8188_VDO1_MERGE0_ASYNC_SOUT_SEL 0xf40
#define MT8188_SOUT_TO_MIXER_IN1_SEL 1
#define MT8188_VDO1_MERGE1_ASYNC_SOUT_SEL 0xf44
#define MT8188_SOUT_TO_MIXER_IN2_SEL 1
#define MT8188_VDO1_MERGE2_ASYNC_SOUT_SEL 0xf48
#define MT8188_SOUT_TO_MIXER_IN3_SEL 1
#define MT8188_VDO1_MERGE3_ASYNC_SOUT_SEL 0xf4c
#define MT8188_SOUT_TO_MIXER_IN4_SEL 1
#define MT8188_VDO1_MERGE4_ASYNC_SEL_IN 0xf50
#define MT8188_MERGE4_ASYNC_SEL_IN_FROM_MIXER_OUT_SOUT 1
#define MT8188_VDO1_MIXER_IN1_SOUT_SEL 0xf58
#define MT8188_MIXER_IN1_SOUT_TO_DISP_MIXER 0
#define MT8188_VDO1_MIXER_IN2_SOUT_SEL 0xf5c
#define MT8188_MIXER_IN2_SOUT_TO_DISP_MIXER 0
#define MT8188_VDO1_MIXER_IN3_SOUT_SEL 0xf60
#define MT8188_MIXER_IN3_SOUT_TO_DISP_MIXER 0
#define MT8188_VDO1_MIXER_IN4_SOUT_SEL 0xf64
#define MT8188_MIXER_IN4_SOUT_TO_DISP_MIXER 0
#define MT8188_VDO1_MIXER_SOUT_SEL_IN 0xf68
#define MT8188_MIXER_SOUT_SEL_IN_FROM_DISP_MIXER 0
static const u8 mmsys_mt8188_vdo0_rst_tb[] = {
[MT8188_VDO0_RST_DISP_OVL0] = MMSYS_RST_NR(0, 0),
[MT8188_VDO0_RST_FAKE_ENG0] = MMSYS_RST_NR(0, 2),
[MT8188_VDO0_RST_DISP_CCORR0] = MMSYS_RST_NR(0, 4),
[MT8188_VDO0_RST_DISP_MUTEX0] = MMSYS_RST_NR(0, 6),
[MT8188_VDO0_RST_DISP_GAMMA0] = MMSYS_RST_NR(0, 8),
[MT8188_VDO0_RST_DISP_DITHER0] = MMSYS_RST_NR(0, 10),
[MT8188_VDO0_RST_DISP_WDMA0] = MMSYS_RST_NR(0, 17),
[MT8188_VDO0_RST_DISP_RDMA0] = MMSYS_RST_NR(0, 19),
[MT8188_VDO0_RST_DSI0] = MMSYS_RST_NR(0, 21),
[MT8188_VDO0_RST_DSI1] = MMSYS_RST_NR(0, 22),
[MT8188_VDO0_RST_DSC_WRAP0] = MMSYS_RST_NR(0, 23),
[MT8188_VDO0_RST_VPP_MERGE0] = MMSYS_RST_NR(0, 24),
[MT8188_VDO0_RST_DP_INTF0] = MMSYS_RST_NR(0, 25),
[MT8188_VDO0_RST_DISP_AAL0] = MMSYS_RST_NR(0, 26),
[MT8188_VDO0_RST_INLINEROT0] = MMSYS_RST_NR(0, 27),
[MT8188_VDO0_RST_APB_BUS] = MMSYS_RST_NR(0, 28),
[MT8188_VDO0_RST_DISP_COLOR0] = MMSYS_RST_NR(0, 29),
[MT8188_VDO0_RST_MDP_WROT0] = MMSYS_RST_NR(0, 30),
[MT8188_VDO0_RST_DISP_RSZ0] = MMSYS_RST_NR(0, 31),
};
static const u8 mmsys_mt8188_vdo1_rst_tb[] = {
[MT8188_VDO1_RST_SMI_LARB2] = MMSYS_RST_NR(0, 0),
[MT8188_VDO1_RST_SMI_LARB3] = MMSYS_RST_NR(0, 1),
[MT8188_VDO1_RST_GALS] = MMSYS_RST_NR(0, 2),
[MT8188_VDO1_RST_FAKE_ENG0] = MMSYS_RST_NR(0, 3),
[MT8188_VDO1_RST_FAKE_ENG1] = MMSYS_RST_NR(0, 4),
[MT8188_VDO1_RST_MDP_RDMA0] = MMSYS_RST_NR(0, 5),
[MT8188_VDO1_RST_MDP_RDMA1] = MMSYS_RST_NR(0, 6),
[MT8188_VDO1_RST_MDP_RDMA2] = MMSYS_RST_NR(0, 7),
[MT8188_VDO1_RST_MDP_RDMA3] = MMSYS_RST_NR(0, 8),
[MT8188_VDO1_RST_VPP_MERGE0] = MMSYS_RST_NR(0, 9),
[MT8188_VDO1_RST_VPP_MERGE1] = MMSYS_RST_NR(0, 10),
[MT8188_VDO1_RST_VPP_MERGE2] = MMSYS_RST_NR(0, 11),
[MT8188_VDO1_RST_VPP_MERGE3] = MMSYS_RST_NR(1, 0),
[MT8188_VDO1_RST_VPP_MERGE4] = MMSYS_RST_NR(1, 1),
[MT8188_VDO1_RST_VPP2_TO_VDO1_DL_ASYNC] = MMSYS_RST_NR(1, 2),
[MT8188_VDO1_RST_VPP3_TO_VDO1_DL_ASYNC] = MMSYS_RST_NR(1, 3),
[MT8188_VDO1_RST_DISP_MUTEX] = MMSYS_RST_NR(1, 4),
[MT8188_VDO1_RST_MDP_RDMA4] = MMSYS_RST_NR(1, 5),
[MT8188_VDO1_RST_MDP_RDMA5] = MMSYS_RST_NR(1, 6),
[MT8188_VDO1_RST_MDP_RDMA6] = MMSYS_RST_NR(1, 7),
[MT8188_VDO1_RST_MDP_RDMA7] = MMSYS_RST_NR(1, 8),
[MT8188_VDO1_RST_DP_INTF1_MMCK] = MMSYS_RST_NR(1, 9),
[MT8188_VDO1_RST_DPI0_MM_CK] = MMSYS_RST_NR(1, 10),
[MT8188_VDO1_RST_DPI1_MM_CK] = MMSYS_RST_NR(1, 11),
[MT8188_VDO1_RST_MERGE0_DL_ASYNC] = MMSYS_RST_NR(1, 13),
[MT8188_VDO1_RST_MERGE1_DL_ASYNC] = MMSYS_RST_NR(1, 14),
[MT8188_VDO1_RST_MERGE2_DL_ASYNC] = MMSYS_RST_NR(1, 15),
[MT8188_VDO1_RST_MERGE3_DL_ASYNC] = MMSYS_RST_NR(1, 16),
[MT8188_VDO1_RST_MERGE4_DL_ASYNC] = MMSYS_RST_NR(1, 17),
[MT8188_VDO1_RST_VDO0_DSC_TO_VDO1_DL_ASYNC] = MMSYS_RST_NR(1, 18),
[MT8188_VDO1_RST_VDO0_MERGE_TO_VDO1_DL_ASYNC] = MMSYS_RST_NR(1, 19),
[MT8188_VDO1_RST_PADDING0] = MMSYS_RST_NR(1, 20),
[MT8188_VDO1_RST_PADDING1] = MMSYS_RST_NR(1, 21),
[MT8188_VDO1_RST_PADDING2] = MMSYS_RST_NR(1, 22),
[MT8188_VDO1_RST_PADDING3] = MMSYS_RST_NR(1, 23),
[MT8188_VDO1_RST_PADDING4] = MMSYS_RST_NR(1, 24),
[MT8188_VDO1_RST_PADDING5] = MMSYS_RST_NR(1, 25),
[MT8188_VDO1_RST_PADDING6] = MMSYS_RST_NR(1, 26),
[MT8188_VDO1_RST_PADDING7] = MMSYS_RST_NR(1, 27),
[MT8188_VDO1_RST_DISP_RSZ0] = MMSYS_RST_NR(1, 28),
[MT8188_VDO1_RST_DISP_RSZ1] = MMSYS_RST_NR(1, 29),
[MT8188_VDO1_RST_DISP_RSZ2] = MMSYS_RST_NR(1, 30),
[MT8188_VDO1_RST_DISP_RSZ3] = MMSYS_RST_NR(1, 31),
[MT8188_VDO1_RST_HDR_VDO_FE0] = MMSYS_RST_NR(2, 0),
[MT8188_VDO1_RST_HDR_GFX_FE0] = MMSYS_RST_NR(2, 1),
[MT8188_VDO1_RST_HDR_VDO_BE] = MMSYS_RST_NR(2, 2),
[MT8188_VDO1_RST_HDR_VDO_FE1] = MMSYS_RST_NR(2, 16),
[MT8188_VDO1_RST_HDR_GFX_FE1] = MMSYS_RST_NR(2, 17),
[MT8188_VDO1_RST_DISP_MIXER] = MMSYS_RST_NR(2, 18),
[MT8188_VDO1_RST_HDR_VDO_FE0_DL_ASYNC] = MMSYS_RST_NR(2, 19),
[MT8188_VDO1_RST_HDR_VDO_FE1_DL_ASYNC] = MMSYS_RST_NR(2, 20),
[MT8188_VDO1_RST_HDR_GFX_FE0_DL_ASYNC] = MMSYS_RST_NR(2, 21),
[MT8188_VDO1_RST_HDR_GFX_FE1_DL_ASYNC] = MMSYS_RST_NR(2, 22),
[MT8188_VDO1_RST_HDR_VDO_BE_DL_ASYNC] = MMSYS_RST_NR(2, 23),
};
static const struct mtk_mmsys_routes mmsys_mt8188_routing_table[] = {
MMSYS_ROUTE(OVL0, RDMA0,
MT8188_VDO0_OVL_MOUT_EN, MT8188_MOUT_DISP_OVL0_TO_DISP_RDMA0,
MT8188_MOUT_DISP_OVL0_TO_DISP_RDMA0),
MMSYS_ROUTE(OVL0, WDMA0,
MT8188_VDO0_OVL_MOUT_EN, MT8188_MOUT_DISP_OVL0_TO_DISP_WDMA0,
MT8188_MOUT_DISP_OVL0_TO_DISP_WDMA0),
MMSYS_ROUTE(OVL0, RDMA0,
MT8188_VDO0_DISP_RDMA_SEL, MT8188_SEL_IN_DISP_RDMA0_FROM_MASK,
MT8188_SEL_IN_DISP_RDMA0_FROM_DISP_OVL0),
MMSYS_ROUTE(DITHER0, DSI0,
MT8188_VDO0_DSI0_SEL_IN, MT8188_SEL_IN_DSI0_FROM_MASK,
MT8188_SEL_IN_DSI0_FROM_DISP_DITHER0),
MMSYS_ROUTE(DITHER0, MERGE0,
MT8188_VDO0_VPP_MERGE_SEL, MT8188_SEL_IN_VPP_MERGE_FROM_MASK,
MT8188_SEL_IN_DP_INTF0_FROM_DISP_DITHER0),
MMSYS_ROUTE(DITHER0, DSC0,
MT8188_VDO0_DSC_WARP_SEL, MT8188_SEL_IN_DSC_WRAP0C0_IN_FROM_MASK,
MT8188_SEL_IN_DSC_WRAP0C0_IN_FROM_DISP_DITHER0),
MMSYS_ROUTE(DITHER0, DP_INTF0,
MT8188_VDO0_DP_INTF0_SEL_IN, MT8188_SEL_IN_DP_INTF0_FROM_MASK,
MT8188_SEL_IN_DP_INTF0_FROM_DISP_DITHER0),
MMSYS_ROUTE(DSC0, MERGE0,
MT8188_VDO0_VPP_MERGE_SEL, MT8188_SEL_IN_VPP_MERGE_FROM_MASK,
MT8188_SEL_IN_VPP_MERGE_FROM_DSC_WRAP0_OUT),
MMSYS_ROUTE(MERGE0, DP_INTF0,
MT8188_VDO0_DP_INTF0_SEL_IN, MT8188_SEL_IN_DP_INTF0_FROM_MASK,
MT8188_SEL_IN_DP_INTF0_FROM_VPP_MERGE),
MMSYS_ROUTE(DSC0, DSI0,
MT8188_VDO0_DSI0_SEL_IN, MT8188_SEL_IN_DSI0_FROM_MASK,
MT8188_SEL_IN_DSI0_FROM_DSC_WRAP0_OUT),
MMSYS_ROUTE(RDMA0, COLOR0,
MT8188_VDO0_DISP_RDMA_SEL, GENMASK(1, 0),
MT8188_SOUT_DISP_RDMA0_TO_DISP_COLOR0),
MMSYS_ROUTE(DITHER0, DSC0,
MT8188_VDO0_DISP_DITHER0_SEL_OUT, MT8188_SOUT_DISP_DITHER0_TO_MASK,
MT8188_SOUT_DISP_DITHER0_TO_DSC_WRAP0_IN),
MMSYS_ROUTE(DITHER0, DSI0,
MT8188_VDO0_DISP_DITHER0_SEL_OUT, MT8188_SOUT_DISP_DITHER0_TO_MASK,
MT8188_SOUT_DISP_DITHER0_TO_DSI0),
MMSYS_ROUTE(DITHER0, MERGE0,
MT8188_VDO0_DISP_DITHER0_SEL_OUT, MT8188_SOUT_DISP_DITHER0_TO_MASK,
MT8188_SOUT_DISP_DITHER0_TO_VPP_MERGE0),
MMSYS_ROUTE(DITHER0, DP_INTF0,
MT8188_VDO0_DISP_DITHER0_SEL_OUT, MT8188_SOUT_DISP_DITHER0_TO_MASK,
MT8188_SOUT_DISP_DITHER0_TO_DP_INTF0),
MMSYS_ROUTE(MERGE0, DP_INTF0,
MT8188_VDO0_VPP_MERGE_SEL, MT8188_SOUT_VPP_MERGE_TO_MASK,
MT8188_SOUT_VPP_MERGE_TO_DP_INTF0),
MMSYS_ROUTE(MERGE0, DPI0,
MT8188_VDO0_VPP_MERGE_SEL, MT8188_SOUT_VPP_MERGE_TO_MASK,
MT8188_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0),
MMSYS_ROUTE(MERGE0, WDMA0,
MT8188_VDO0_VPP_MERGE_SEL, MT8188_SOUT_VPP_MERGE_TO_MASK,
MT8188_SOUT_VPP_MERGE_TO_DISP_WDMA0),
MMSYS_ROUTE(MERGE0, DSC0,
MT8188_VDO0_VPP_MERGE_SEL, MT8188_SOUT_VPP_MERGE_TO_MASK,
MT8188_SOUT_VPP_MERGE_TO_DSC_WRAP0_IN),
MMSYS_ROUTE(DSC0, DSI0,
MT8188_VDO0_DSC_WARP_SEL, MT8188_SOUT_DSC_WRAP0_OUT_TO_MASK,
MT8188_SOUT_DSC_WRAP0_OUT_TO_DSI0),
MMSYS_ROUTE(DSC0, MERGE0,
MT8188_VDO0_DSC_WARP_SEL, MT8188_SOUT_DSC_WRAP0_OUT_TO_MASK,
MT8188_SOUT_DSC_WRAP0_OUT_TO_VPP_MERGE),
};
static const struct mtk_mmsys_routes mmsys_mt8188_vdo1_routing_table[] = {
MMSYS_ROUTE(MDP_RDMA0, MERGE1,
MT8188_VDO1_VPP_MERGE0_P0_SEL_IN, GENMASK(0, 0),
MT8188_VPP_MERGE0_P0_SEL_IN_FROM_MDP_RDMA0),
MMSYS_ROUTE(MDP_RDMA1, MERGE1,
MT8188_VDO1_VPP_MERGE0_P1_SEL_IN, GENMASK(0, 0),
MT8188_VPP_MERGE0_P1_SEL_IN_FROM_MDP_RDMA1),
MMSYS_ROUTE(MDP_RDMA2, MERGE2,
MT8188_VDO1_VPP_MERGE1_P0_SEL_IN, GENMASK(0, 0),
MT8188_VPP_MERGE1_P0_SEL_IN_FROM_MDP_RDMA2),
MMSYS_ROUTE(MERGE1, ETHDR_MIXER,
MT8188_VDO1_MERGE0_ASYNC_SOUT_SEL, GENMASK(1, 0),
MT8188_SOUT_TO_MIXER_IN1_SEL),
MMSYS_ROUTE(MERGE2, ETHDR_MIXER,
MT8188_VDO1_MERGE1_ASYNC_SOUT_SEL, GENMASK(1, 0),
MT8188_SOUT_TO_MIXER_IN2_SEL),
MMSYS_ROUTE(MERGE3, ETHDR_MIXER,
MT8188_VDO1_MERGE2_ASYNC_SOUT_SEL, GENMASK(1, 0),
MT8188_SOUT_TO_MIXER_IN3_SEL),
MMSYS_ROUTE(MERGE4, ETHDR_MIXER,
MT8188_VDO1_MERGE3_ASYNC_SOUT_SEL, GENMASK(1, 0),
MT8188_SOUT_TO_MIXER_IN4_SEL),
MMSYS_ROUTE(ETHDR_MIXER, MERGE5,
MT8188_VDO1_MIXER_OUT_SOUT_SEL, GENMASK(0, 0),
MT8188_MIXER_SOUT_TO_MERGE4_ASYNC_SEL),
MMSYS_ROUTE(MERGE1, ETHDR_MIXER,
MT8188_VDO1_MIXER_IN1_SEL_IN, GENMASK(0, 0),
MT8188_MIXER_IN1_SEL_IN_FROM_MERGE0_ASYNC_SOUT),
MMSYS_ROUTE(MERGE2, ETHDR_MIXER,
MT8188_VDO1_MIXER_IN2_SEL_IN, GENMASK(0, 0),
MT8188_MIXER_IN2_SEL_IN_FROM_MERGE1_ASYNC_SOUT),
MMSYS_ROUTE(MERGE3, ETHDR_MIXER,
MT8188_VDO1_MIXER_IN3_SEL_IN, GENMASK(0, 0),
MT8188_MIXER_IN3_SEL_IN_FROM_MERGE2_ASYNC_SOUT),
MMSYS_ROUTE(MERGE4, ETHDR_MIXER,
MT8188_VDO1_MIXER_IN4_SEL_IN, GENMASK(0, 0),
MT8188_MIXER_IN4_SEL_IN_FROM_MERGE3_ASYNC_SOUT),
MMSYS_ROUTE(ETHDR_MIXER, MERGE5,
MT8188_VDO1_MIXER_SOUT_SEL_IN, GENMASK(2, 0),
MT8188_MIXER_SOUT_SEL_IN_FROM_DISP_MIXER),
MMSYS_ROUTE(ETHDR_MIXER, MERGE5,
MT8188_VDO1_MERGE4_ASYNC_SEL_IN, GENMASK(2, 0),
MT8188_MERGE4_ASYNC_SEL_IN_FROM_MIXER_OUT_SOUT),
MMSYS_ROUTE(MERGE5, DPI1,
MT8188_VDO1_DISP_DPI1_SEL_IN, GENMASK(1, 0),
MT8188_DISP_DPI1_SEL_IN_FROM_VPP_MERGE4_MOUT),
MMSYS_ROUTE(MERGE5, DPI1,
MT8188_VDO1_MERGE4_SOUT_SEL, GENMASK(3, 0),
MT8188_MERGE4_SOUT_TO_DPI1_SEL),
MMSYS_ROUTE(MERGE5, DP_INTF1,
MT8188_VDO1_DISP_DP_INTF0_SEL_IN, GENMASK(1, 0),
MT8188_DISP_DP_INTF0_SEL_IN_FROM_VPP_MERGE4_MOUT),
MMSYS_ROUTE(MERGE5, DP_INTF1,
MT8188_VDO1_MERGE4_SOUT_SEL, GENMASK(3, 0),
MT8188_MERGE4_SOUT_TO_DP_INTF0_SEL),
};
#endif /* __SOC_MEDIATEK_MT8188_MMSYS_H */
@@ -0,0 +1,66 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __SOC_MEDIATEK_MT8192_MMSYS_H
#define __SOC_MEDIATEK_MT8192_MMSYS_H
#define MT8192_MMSYS_OVL_MOUT_EN 0xf04
#define MT8192_DISP_OVL1_2L_MOUT_EN 0xf08
#define MT8192_DISP_OVL0_2L_MOUT_EN 0xf18
#define MT8192_DISP_OVL0_MOUT_EN 0xf1c
#define MT8192_DISP_RDMA0_SEL_IN 0xf2c
#define MT8192_DISP_RDMA0_SOUT_SEL 0xf30
#define MT8192_DISP_CCORR0_SOUT_SEL 0xf34
#define MT8192_DISP_AAL0_SEL_IN 0xf38
#define MT8192_DISP_DITHER0_MOUT_EN 0xf3c
#define MT8192_DISP_DSI0_SEL_IN 0xf40
#define MT8192_DISP_OVL2_2L_MOUT_EN 0xf4c
#define MT8192_DISP_OVL0_GO_BLEND BIT(0)
#define MT8192_DITHER0_MOUT_IN_DSI0 BIT(0)
#define MT8192_OVL0_MOUT_EN_DISP_RDMA0 BIT(0)
#define MT8192_OVL2_2L_MOUT_EN_RDMA4 BIT(0)
#define MT8192_DISP_OVL0_GO_BG BIT(1)
#define MT8192_DISP_OVL0_2L_GO_BLEND BIT(2)
#define MT8192_DISP_OVL0_2L_GO_BG BIT(3)
#define MT8192_OVL1_2L_MOUT_EN_RDMA1 BIT(4)
#define MT8192_OVL0_MOUT_EN_OVL0_2L BIT(4)
#define MT8192_RDMA0_SEL_IN_OVL0_2L 0x3
#define MT8192_RDMA0_SOUT_COLOR0 0x1
#define MT8192_CCORR0_SOUT_AAL0 0x1
#define MT8192_AAL0_SEL_IN_CCORR0 0x1
#define MT8192_DSI0_SEL_IN_DITHER0 0x1
static const struct mtk_mmsys_routes mmsys_mt8192_routing_table[] = {
MMSYS_ROUTE(OVL_2L0, RDMA0,
MT8192_DISP_OVL0_2L_MOUT_EN, MT8192_OVL0_MOUT_EN_DISP_RDMA0,
MT8192_OVL0_MOUT_EN_DISP_RDMA0),
MMSYS_ROUTE(OVL_2L2, RDMA4,
MT8192_DISP_OVL2_2L_MOUT_EN, MT8192_OVL2_2L_MOUT_EN_RDMA4,
MT8192_OVL2_2L_MOUT_EN_RDMA4),
MMSYS_ROUTE(DITHER0, DSI0,
MT8192_DISP_DITHER0_MOUT_EN, MT8192_DITHER0_MOUT_IN_DSI0,
MT8192_DITHER0_MOUT_IN_DSI0),
MMSYS_ROUTE(OVL_2L0, RDMA0,
MT8192_DISP_RDMA0_SEL_IN, MT8192_RDMA0_SEL_IN_OVL0_2L,
MT8192_RDMA0_SEL_IN_OVL0_2L),
MMSYS_ROUTE(CCORR, AAL0,
MT8192_DISP_AAL0_SEL_IN, MT8192_AAL0_SEL_IN_CCORR0,
MT8192_AAL0_SEL_IN_CCORR0),
MMSYS_ROUTE(DITHER0, DSI0,
MT8192_DISP_DSI0_SEL_IN, MT8192_DSI0_SEL_IN_DITHER0,
MT8192_DSI0_SEL_IN_DITHER0),
MMSYS_ROUTE(RDMA0, COLOR0,
MT8192_DISP_RDMA0_SOUT_SEL, MT8192_RDMA0_SOUT_COLOR0,
MT8192_RDMA0_SOUT_COLOR0),
MMSYS_ROUTE(CCORR, AAL0,
MT8192_DISP_CCORR0_SOUT_SEL, MT8192_CCORR0_SOUT_AAL0,
MT8192_CCORR0_SOUT_AAL0),
MMSYS_ROUTE(OVL0, OVL_2L0,
MT8192_MMSYS_OVL_MOUT_EN, MT8192_DISP_OVL0_GO_BG,
MT8192_DISP_OVL0_GO_BG),
MMSYS_ROUTE(OVL_2L0, RDMA0,
MT8192_MMSYS_OVL_MOUT_EN, MT8192_DISP_OVL0_2L_GO_BLEND,
MT8192_DISP_OVL0_2L_GO_BLEND),
};
#endif /* __SOC_MEDIATEK_MT8192_MMSYS_H */
@@ -0,0 +1,437 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __SOC_MEDIATEK_MT8195_MMSYS_H
#define __SOC_MEDIATEK_MT8195_MMSYS_H
#define MT8195_VDO0_OVL_MOUT_EN 0xf14
#define MT8195_MOUT_DISP_OVL0_TO_DISP_RDMA0 BIT(0)
#define MT8195_MOUT_DISP_OVL0_TO_DISP_WDMA0 BIT(1)
#define MT8195_MOUT_DISP_OVL0_TO_DISP_OVL1 BIT(2)
#define MT8195_MOUT_DISP_OVL1_TO_DISP_RDMA1 BIT(4)
#define MT8195_MOUT_DISP_OVL1_TO_DISP_WDMA1 BIT(5)
#define MT8195_MOUT_DISP_OVL1_TO_DISP_OVL0 BIT(6)
#define MT8195_VDO0_SEL_IN 0xf34
#define MT8195_SEL_IN_VPP_MERGE_FROM_MASK GENMASK(1, 0)
#define MT8195_SEL_IN_VPP_MERGE_FROM_DSC_WRAP0_OUT (0 << 0)
#define MT8195_SEL_IN_VPP_MERGE_FROM_DISP_DITHER1 (1 << 0)
#define MT8195_SEL_IN_VPP_MERGE_FROM_VDO1_VIRTUAL0 (2 << 0)
#define MT8195_SEL_IN_DSC_WRAP0_IN_FROM_MASK GENMASK(4, 4)
#define MT8195_SEL_IN_DSC_WRAP0_IN_FROM_DISP_DITHER0 (0 << 4)
#define MT8195_SEL_IN_DSC_WRAP0_IN_FROM_VPP_MERGE (1 << 4)
#define MT8195_SEL_IN_DSC_WRAP1_IN_FROM_MASK GENMASK(5, 5)
#define MT8195_SEL_IN_DSC_WRAP1_IN_FROM_DISP_DITHER1 (0 << 5)
#define MT8195_SEL_IN_DSC_WRAP1_IN_FROM_VPP_MERGE (1 << 5)
#define MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK GENMASK(8, 8)
#define MT8195_SEL_IN_SINA_VIRTUAL0_FROM_VPP_MERGE (0 << 8)
#define MT8195_SEL_IN_SINA_VIRTUAL0_FROM_DSC_WRAP1_OUT (1 << 8)
#define MT8195_SEL_IN_SINB_VIRTUAL0_FROM_MASK GENMASK(9, 9)
#define MT8195_SEL_IN_SINB_VIRTUAL0_FROM_DSC_WRAP0_OUT (0 << 9)
#define MT8195_SEL_IN_DP_INTF0_FROM_MASK GENMASK(13, 12)
#define MT8195_SEL_IN_DP_INTF0_FROM_DSC_WRAP1_OUT (0 << 0)
#define MT8195_SEL_IN_DP_INTF0_FROM_VPP_MERGE (1 << 12)
#define MT8195_SEL_IN_DP_INTF0_FROM_VDO1_VIRTUAL0 (2 << 12)
#define MT8195_SEL_IN_DSI0_FROM_MASK GENMASK(16, 16)
#define MT8195_SEL_IN_DSI0_FROM_DSC_WRAP0_OUT (0 << 16)
#define MT8195_SEL_IN_DSI0_FROM_DISP_DITHER0 (1 << 16)
#define MT8195_SEL_IN_DSI1_FROM_MASK GENMASK(17, 17)
#define MT8195_SEL_IN_DSI1_FROM_DSC_WRAP1_OUT (0 << 17)
#define MT8195_SEL_IN_DSI1_FROM_VPP_MERGE (1 << 17)
#define MT8195_SEL_IN_DISP_WDMA1_FROM_MASK GENMASK(20, 20)
#define MT8195_SEL_IN_DISP_WDMA1_FROM_DISP_OVL1 (0 << 20)
#define MT8195_SEL_IN_DISP_WDMA1_FROM_VPP_MERGE (1 << 20)
#define MT8195_SEL_IN_DSC_WRAP1_FROM_MASK GENMASK(21, 21)
#define MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN (0 << 21)
#define MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1 (1 << 21)
#define MT8195_SEL_IN_DISP_WDMA0_FROM_MASK GENMASK(22, 22)
#define MT8195_SEL_IN_DISP_WDMA0_FROM_DISP_OVL0 (0 << 22)
#define MT8195_VDO0_SEL_OUT 0xf38
#define MT8195_SOUT_DISP_DITHER0_TO_MASK BIT(0)
#define MT8195_SOUT_DISP_DITHER0_TO_DSC_WRAP0_IN (0 << 0)
#define MT8195_SOUT_DISP_DITHER0_TO_DSI0 (1 << 0)
#define MT8195_SOUT_DISP_DITHER1_TO_MASK GENMASK(2, 1)
#define MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_IN (0 << 1)
#define MT8195_SOUT_DISP_DITHER1_TO_VPP_MERGE (1 << 1)
#define MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT (2 << 1)
#define MT8195_SOUT_VDO1_VIRTUAL0_TO_MASK GENMASK(4, 4)
#define MT8195_SOUT_VDO1_VIRTUAL0_TO_VPP_MERGE (0 << 4)
#define MT8195_SOUT_VDO1_VIRTUAL0_TO_DP_INTF0 (1 << 4)
#define MT8195_SOUT_VPP_MERGE_TO_MASK GENMASK(10, 8)
#define MT8195_SOUT_VPP_MERGE_TO_DSI1 (0 << 8)
#define MT8195_SOUT_VPP_MERGE_TO_DP_INTF0 (1 << 8)
#define MT8195_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0 (2 << 8)
#define MT8195_SOUT_VPP_MERGE_TO_DISP_WDMA1 (3 << 8)
#define MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP0_IN (4 << 8)
#define MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN_MASK GENMASK(11, 11)
#define MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN (0 << 11)
#define MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK GENMASK(13, 12)
#define MT8195_SOUT_DSC_WRAP0_OUT_TO_DSI0 (0 << 12)
#define MT8195_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0 (1 << 12)
#define MT8195_SOUT_DSC_WRAP0_OUT_TO_VPP_MERGE (2 << 12)
#define MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK GENMASK(17, 16)
#define MT8195_SOUT_DSC_WRAP1_OUT_TO_DSI1 (0 << 16)
#define MT8195_SOUT_DSC_WRAP1_OUT_TO_DP_INTF0 (1 << 16)
#define MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0 (2 << 16)
#define MT8195_SOUT_DSC_WRAP1_OUT_TO_VPP_MERGE (3 << 16)
#define MT8195_VDO1_SW0_RST_B 0x1d0
#define MT8195_VDO1_MERGE0_ASYNC_CFG_WD 0xe30
#define MT8195_VDO1_HDRBE_ASYNC_CFG_WD 0xe70
#define MT8195_VDO1_HDR_TOP_CFG 0xd00
#define MT8195_VDO1_MIXER_IN1_ALPHA 0xd30
#define MT8195_VDO1_MIXER_IN1_PAD 0xd40
#define MT8195_VDO1_VPP_MERGE0_P0_SEL_IN 0xf04
#define MT8195_VPP_MERGE0_P0_SEL_IN_FROM_MDP_RDMA0 1
#define MT8195_VDO1_VPP_MERGE0_P1_SEL_IN 0xf08
#define MT8195_VPP_MERGE0_P1_SEL_IN_FROM_MDP_RDMA1 1
#define MT8195_VDO1_DISP_DPI1_SEL_IN 0xf10
#define MT8195_DISP_DPI1_SEL_IN_FROM_VPP_MERGE4_MOUT 0
#define MT8195_VDO1_DISP_DP_INTF0_SEL_IN 0xf14
#define MT8195_DISP_DP_INTF0_SEL_IN_FROM_VPP_MERGE4_MOUT 0
#define MT8195_VDO1_MERGE4_SOUT_SEL 0xf18
#define MT8195_MERGE4_SOUT_TO_DPI1_SEL 2
#define MT8195_MERGE4_SOUT_TO_DP_INTF0_SEL 3
#define MT8195_VDO1_MIXER_IN1_SEL_IN 0xf24
#define MT8195_MIXER_IN1_SEL_IN_FROM_MERGE0_ASYNC_SOUT 1
#define MT8195_VDO1_MIXER_IN2_SEL_IN 0xf28
#define MT8195_MIXER_IN2_SEL_IN_FROM_MERGE1_ASYNC_SOUT 1
#define MT8195_VDO1_MIXER_IN3_SEL_IN 0xf2c
#define MT8195_MIXER_IN3_SEL_IN_FROM_MERGE2_ASYNC_SOUT 1
#define MT8195_VDO1_MIXER_IN4_SEL_IN 0xf30
#define MT8195_MIXER_IN4_SEL_IN_FROM_MERGE3_ASYNC_SOUT 1
#define MT8195_VDO1_MIXER_OUT_SOUT_SEL 0xf34
#define MT8195_MIXER_SOUT_TO_MERGE4_ASYNC_SEL 1
#define MT8195_VDO1_VPP_MERGE1_P0_SEL_IN 0xf3c
#define MT8195_VPP_MERGE1_P0_SEL_IN_FROM_MDP_RDMA2 1
#define MT8195_VDO1_MERGE0_ASYNC_SOUT_SEL 0xf40
#define MT8195_SOUT_TO_MIXER_IN1_SEL 1
#define MT8195_VDO1_MERGE1_ASYNC_SOUT_SEL 0xf44
#define MT8195_SOUT_TO_MIXER_IN2_SEL 1
#define MT8195_VDO1_MERGE2_ASYNC_SOUT_SEL 0xf48
#define MT8195_SOUT_TO_MIXER_IN3_SEL 1
#define MT8195_VDO1_MERGE3_ASYNC_SOUT_SEL 0xf4c
#define MT8195_SOUT_TO_MIXER_IN4_SEL 1
#define MT8195_VDO1_MERGE4_ASYNC_SEL_IN 0xf50
#define MT8195_MERGE4_ASYNC_SEL_IN_FROM_MIXER_OUT_SOUT 1
#define MT8195_VDO1_MIXER_IN1_SOUT_SEL 0xf58
#define MT8195_MIXER_IN1_SOUT_TO_DISP_MIXER 0
#define MT8195_VDO1_MIXER_IN2_SOUT_SEL 0xf5c
#define MT8195_MIXER_IN2_SOUT_TO_DISP_MIXER 0
#define MT8195_VDO1_MIXER_IN3_SOUT_SEL 0xf60
#define MT8195_MIXER_IN3_SOUT_TO_DISP_MIXER 0
#define MT8195_VDO1_MIXER_IN4_SOUT_SEL 0xf64
#define MT8195_MIXER_IN4_SOUT_TO_DISP_MIXER 0
#define MT8195_VDO1_MIXER_SOUT_SEL_IN 0xf68
#define MT8195_MIXER_SOUT_SEL_IN_FROM_DISP_MIXER 0
/* VPPSYS1 */
#define MT8195_VPP1_HW_DCM_1ST_DIS0 0x150
#define MT8195_VPP1_HW_DCM_1ST_DIS1 0x160
#define MT8195_VPP1_HW_DCM_2ND_DIS0 0x1a0
#define MT8195_VPP1_HW_DCM_2ND_DIS1 0x1b0
#define MT8195_SVPP2_BUF_BF_RSZ_SWITCH 0xf48
#define MT8195_SVPP3_BUF_BF_RSZ_SWITCH 0xf74
/* VPPSYS1 HW DCM client*/
#define MT8195_SVPP1_MDP_RSZ BIT(25)
#define MT8195_SVPP2_MDP_RSZ BIT(4)
#define MT8195_SVPP3_MDP_RSZ BIT(5)
static const struct mtk_mmsys_routes mmsys_mt8195_routing_table[] = {
MMSYS_ROUTE(OVL0, RDMA0,
MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL0_TO_DISP_RDMA0,
MT8195_MOUT_DISP_OVL0_TO_DISP_RDMA0),
MMSYS_ROUTE(OVL0, WDMA0,
MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL0_TO_DISP_WDMA0,
MT8195_MOUT_DISP_OVL0_TO_DISP_WDMA0),
MMSYS_ROUTE(OVL0, OVL1,
MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL0_TO_DISP_OVL1,
MT8195_MOUT_DISP_OVL0_TO_DISP_OVL1),
MMSYS_ROUTE(OVL1, RDMA1,
MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL1_TO_DISP_RDMA1,
MT8195_MOUT_DISP_OVL1_TO_DISP_RDMA1),
MMSYS_ROUTE(OVL1, WDMA1,
MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL1_TO_DISP_WDMA1,
MT8195_MOUT_DISP_OVL1_TO_DISP_WDMA1),
MMSYS_ROUTE(OVL1, OVL0,
MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL1_TO_DISP_OVL0,
MT8195_MOUT_DISP_OVL1_TO_DISP_OVL0),
MMSYS_ROUTE(DSC0, MERGE0,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_VPP_MERGE_FROM_MASK,
MT8195_SEL_IN_VPP_MERGE_FROM_DSC_WRAP0_OUT),
MMSYS_ROUTE(DITHER1, MERGE0,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_VPP_MERGE_FROM_MASK,
MT8195_SEL_IN_VPP_MERGE_FROM_DISP_DITHER1),
MMSYS_ROUTE(MERGE5, MERGE0,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_VPP_MERGE_FROM_MASK,
MT8195_SEL_IN_VPP_MERGE_FROM_VDO1_VIRTUAL0),
MMSYS_ROUTE(DITHER0, DSC0,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP0_IN_FROM_MASK,
MT8195_SEL_IN_DSC_WRAP0_IN_FROM_DISP_DITHER0),
MMSYS_ROUTE(MERGE0, DSC0,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP0_IN_FROM_MASK,
MT8195_SEL_IN_DSC_WRAP0_IN_FROM_VPP_MERGE),
MMSYS_ROUTE(DITHER1, DSC1,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_IN_FROM_MASK,
MT8195_SEL_IN_DSC_WRAP1_IN_FROM_DISP_DITHER1),
MMSYS_ROUTE(MERGE0, DSC1,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_IN_FROM_MASK,
MT8195_SEL_IN_DSC_WRAP1_IN_FROM_VPP_MERGE),
MMSYS_ROUTE(MERGE0, DP_INTF1,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
MT8195_SEL_IN_SINA_VIRTUAL0_FROM_VPP_MERGE),
MMSYS_ROUTE(MERGE0, DPI0,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
MT8195_SEL_IN_SINA_VIRTUAL0_FROM_VPP_MERGE),
MMSYS_ROUTE(MERGE0, DPI1,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
MT8195_SEL_IN_SINA_VIRTUAL0_FROM_VPP_MERGE),
MMSYS_ROUTE(DSC1, DP_INTF1,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
MT8195_SEL_IN_SINA_VIRTUAL0_FROM_DSC_WRAP1_OUT),
MMSYS_ROUTE(DSC1, DPI0,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
MT8195_SEL_IN_SINA_VIRTUAL0_FROM_DSC_WRAP1_OUT),
MMSYS_ROUTE(DSC1, DPI1,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
MT8195_SEL_IN_SINA_VIRTUAL0_FROM_DSC_WRAP1_OUT),
MMSYS_ROUTE(DSC0, DP_INTF1,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINB_VIRTUAL0_FROM_MASK,
MT8195_SEL_IN_SINB_VIRTUAL0_FROM_DSC_WRAP0_OUT),
MMSYS_ROUTE(DSC0, DPI0,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINB_VIRTUAL0_FROM_MASK,
MT8195_SEL_IN_SINB_VIRTUAL0_FROM_DSC_WRAP0_OUT),
MMSYS_ROUTE(DSC0, DPI1,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINB_VIRTUAL0_FROM_MASK,
MT8195_SEL_IN_SINB_VIRTUAL0_FROM_DSC_WRAP0_OUT),
MMSYS_ROUTE(DSC1, DP_INTF0,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DP_INTF0_FROM_MASK,
MT8195_SEL_IN_DP_INTF0_FROM_DSC_WRAP1_OUT),
MMSYS_ROUTE(MERGE0, DP_INTF0,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DP_INTF0_FROM_MASK,
MT8195_SEL_IN_DP_INTF0_FROM_VPP_MERGE),
MMSYS_ROUTE(MERGE5, DP_INTF0,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DP_INTF0_FROM_MASK,
MT8195_SEL_IN_DP_INTF0_FROM_VDO1_VIRTUAL0),
MMSYS_ROUTE(DSC0, DSI0,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI0_FROM_MASK,
MT8195_SEL_IN_DSI0_FROM_DSC_WRAP0_OUT),
MMSYS_ROUTE(DITHER0, DSI0,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI0_FROM_MASK,
MT8195_SEL_IN_DSI0_FROM_DISP_DITHER0),
MMSYS_ROUTE(DSC1, DSI1,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI1_FROM_MASK,
MT8195_SEL_IN_DSI1_FROM_DSC_WRAP1_OUT),
MMSYS_ROUTE(MERGE0, DSI1,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI1_FROM_MASK,
MT8195_SEL_IN_DSI1_FROM_VPP_MERGE),
MMSYS_ROUTE(OVL1, WDMA1,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DISP_WDMA1_FROM_MASK,
MT8195_SEL_IN_DISP_WDMA1_FROM_DISP_OVL1),
MMSYS_ROUTE(MERGE0, WDMA1,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DISP_WDMA1_FROM_MASK,
MT8195_SEL_IN_DISP_WDMA1_FROM_VPP_MERGE),
MMSYS_ROUTE(DSC1, DSI1,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN),
MMSYS_ROUTE(DSC1, DP_INTF0,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN),
MMSYS_ROUTE(DSC1, DP_INTF1,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN),
MMSYS_ROUTE(DSC1, DPI0,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN),
MMSYS_ROUTE(DSC1, DPI1,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN),
MMSYS_ROUTE(DSC1, MERGE0,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN),
MMSYS_ROUTE(DITHER1, DSI1,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1),
MMSYS_ROUTE(DITHER1, DP_INTF0,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1),
MMSYS_ROUTE(DITHER1, DPI0,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1),
MMSYS_ROUTE(DITHER1, DPI1,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1),
MMSYS_ROUTE(OVL0, WDMA0,
MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DISP_WDMA0_FROM_MASK,
MT8195_SEL_IN_DISP_WDMA0_FROM_DISP_OVL0),
MMSYS_ROUTE(DITHER0, DSC0,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER0_TO_MASK,
MT8195_SOUT_DISP_DITHER0_TO_DSC_WRAP0_IN),
MMSYS_ROUTE(DITHER0, DSI0,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER0_TO_MASK,
MT8195_SOUT_DISP_DITHER0_TO_DSI0),
MMSYS_ROUTE(DITHER1, DSC1,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_IN),
MMSYS_ROUTE(DITHER1, MERGE0,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
MT8195_SOUT_DISP_DITHER1_TO_VPP_MERGE),
MMSYS_ROUTE(DITHER1, DSI1,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT),
MMSYS_ROUTE(DITHER1, DP_INTF0,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT),
MMSYS_ROUTE(DITHER1, DP_INTF1,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT),
MMSYS_ROUTE(DITHER1, DPI0,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT),
MMSYS_ROUTE(DITHER1, DPI1,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT),
MMSYS_ROUTE(MERGE5, MERGE0,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_VDO1_VIRTUAL0_TO_MASK,
MT8195_SOUT_VDO1_VIRTUAL0_TO_VPP_MERGE),
MMSYS_ROUTE(MERGE5, DP_INTF0,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_VDO1_VIRTUAL0_TO_MASK,
MT8195_SOUT_VDO1_VIRTUAL0_TO_DP_INTF0),
MMSYS_ROUTE(MERGE0, DSI1,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
MT8195_SOUT_VPP_MERGE_TO_DSI1),
MMSYS_ROUTE(MERGE0, DP_INTF0,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
MT8195_SOUT_VPP_MERGE_TO_DP_INTF0),
MMSYS_ROUTE(MERGE0, DP_INTF1,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
MT8195_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0),
MMSYS_ROUTE(MERGE0, DPI0,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
MT8195_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0),
MMSYS_ROUTE(MERGE0, DPI1,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
MT8195_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0),
MMSYS_ROUTE(MERGE0, WDMA1,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
MT8195_SOUT_VPP_MERGE_TO_DISP_WDMA1),
MMSYS_ROUTE(MERGE0, DSC0,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP0_IN),
MMSYS_ROUTE(MERGE0, DSC1,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN_MASK,
MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN),
MMSYS_ROUTE(DSC0, DSI0,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
MT8195_SOUT_DSC_WRAP0_OUT_TO_DSI0),
MMSYS_ROUTE(DSC0, DP_INTF1,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
MT8195_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0),
MMSYS_ROUTE(DSC0, DPI0,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
MT8195_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0),
MMSYS_ROUTE(DSC0, DPI1,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
MT8195_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0),
MMSYS_ROUTE(DSC0, MERGE0,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
MT8195_SOUT_DSC_WRAP0_OUT_TO_VPP_MERGE),
MMSYS_ROUTE(DSC1, DSI1,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
MT8195_SOUT_DSC_WRAP1_OUT_TO_DSI1),
MMSYS_ROUTE(DSC1, DP_INTF0,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
MT8195_SOUT_DSC_WRAP1_OUT_TO_DP_INTF0),
MMSYS_ROUTE(DSC1, DP_INTF1,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0),
MMSYS_ROUTE(DSC1, DPI0,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0),
MMSYS_ROUTE(DSC1, DPI1,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0),
MMSYS_ROUTE(DSC1, MERGE0,
MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
MT8195_SOUT_DSC_WRAP1_OUT_TO_VPP_MERGE),
};
static const struct mtk_mmsys_routes mmsys_mt8195_vdo1_routing_table[] = {
MMSYS_ROUTE(MDP_RDMA0, MERGE1,
MT8195_VDO1_VPP_MERGE0_P0_SEL_IN, GENMASK(0, 0),
MT8195_VPP_MERGE0_P0_SEL_IN_FROM_MDP_RDMA0),
MMSYS_ROUTE(MDP_RDMA1, MERGE1,
MT8195_VDO1_VPP_MERGE0_P1_SEL_IN, GENMASK(0, 0),
MT8195_VPP_MERGE0_P1_SEL_IN_FROM_MDP_RDMA1),
MMSYS_ROUTE(MDP_RDMA2, MERGE2,
MT8195_VDO1_VPP_MERGE1_P0_SEL_IN, GENMASK(0, 0),
MT8195_VPP_MERGE1_P0_SEL_IN_FROM_MDP_RDMA2),
MMSYS_ROUTE(MERGE1, ETHDR_MIXER,
MT8195_VDO1_MERGE0_ASYNC_SOUT_SEL, GENMASK(1, 0),
MT8195_SOUT_TO_MIXER_IN1_SEL),
MMSYS_ROUTE(MERGE2, ETHDR_MIXER,
MT8195_VDO1_MERGE1_ASYNC_SOUT_SEL, GENMASK(1, 0),
MT8195_SOUT_TO_MIXER_IN2_SEL),
MMSYS_ROUTE(MERGE3, ETHDR_MIXER,
MT8195_VDO1_MERGE2_ASYNC_SOUT_SEL, GENMASK(1, 0),
MT8195_SOUT_TO_MIXER_IN3_SEL),
MMSYS_ROUTE(MERGE4, ETHDR_MIXER,
MT8195_VDO1_MERGE3_ASYNC_SOUT_SEL, GENMASK(1, 0),
MT8195_SOUT_TO_MIXER_IN4_SEL),
MMSYS_ROUTE(ETHDR_MIXER, MERGE5,
MT8195_VDO1_MIXER_OUT_SOUT_SEL, GENMASK(0, 0),
MT8195_MIXER_SOUT_TO_MERGE4_ASYNC_SEL),
MMSYS_ROUTE(MERGE1, ETHDR_MIXER,
MT8195_VDO1_MIXER_IN1_SEL_IN, GENMASK(0, 0),
MT8195_MIXER_IN1_SEL_IN_FROM_MERGE0_ASYNC_SOUT),
MMSYS_ROUTE(MERGE2, ETHDR_MIXER,
MT8195_VDO1_MIXER_IN2_SEL_IN, GENMASK(0, 0),
MT8195_MIXER_IN2_SEL_IN_FROM_MERGE1_ASYNC_SOUT),
MMSYS_ROUTE(MERGE3, ETHDR_MIXER,
MT8195_VDO1_MIXER_IN3_SEL_IN, GENMASK(0, 0),
MT8195_MIXER_IN3_SEL_IN_FROM_MERGE2_ASYNC_SOUT),
MMSYS_ROUTE(MERGE4, ETHDR_MIXER,
MT8195_VDO1_MIXER_IN4_SEL_IN, GENMASK(0, 0),
MT8195_MIXER_IN4_SEL_IN_FROM_MERGE3_ASYNC_SOUT),
MMSYS_ROUTE(ETHDR_MIXER, MERGE5,
MT8195_VDO1_MIXER_SOUT_SEL_IN, GENMASK(2, 0),
MT8195_MIXER_SOUT_SEL_IN_FROM_DISP_MIXER),
MMSYS_ROUTE(ETHDR_MIXER, MERGE5,
MT8195_VDO1_MERGE4_ASYNC_SEL_IN, GENMASK(2, 0),
MT8195_MERGE4_ASYNC_SEL_IN_FROM_MIXER_OUT_SOUT),
MMSYS_ROUTE(MERGE5, DPI1,
MT8195_VDO1_DISP_DPI1_SEL_IN, GENMASK(1, 0),
MT8195_DISP_DPI1_SEL_IN_FROM_VPP_MERGE4_MOUT),
MMSYS_ROUTE(MERGE5, DPI1,
MT8195_VDO1_MERGE4_SOUT_SEL, GENMASK(1, 0),
MT8195_MERGE4_SOUT_TO_DPI1_SEL),
MMSYS_ROUTE(MERGE5, DP_INTF1,
MT8195_VDO1_DISP_DP_INTF0_SEL_IN, GENMASK(1, 0),
MT8195_DISP_DP_INTF0_SEL_IN_FROM_VPP_MERGE4_MOUT),
MMSYS_ROUTE(MERGE5, DP_INTF1,
MT8195_VDO1_MERGE4_SOUT_SEL, GENMASK(1, 0),
MT8195_MERGE4_SOUT_TO_DP_INTF0_SEL),
};
#endif /* __SOC_MEDIATEK_MT8195_MMSYS_H */
@@ -0,0 +1,64 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __SOC_MEDIATEK_MT8365_MMSYS_H
#define __SOC_MEDIATEK_MT8365_MMSYS_H
#define MT8365_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN 0xf3c
#define MT8365_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL 0xf4c
#define MT8365_DISP_REG_CONFIG_DISP_DITHER0_MOUT_EN 0xf50
#define MT8365_DISP_REG_CONFIG_DISP_RDMA0_SEL_IN 0xf54
#define MT8365_DISP_REG_CONFIG_DISP_RDMA0_RSZ0_SEL_IN 0xf60
#define MT8365_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0xf64
#define MT8365_DISP_REG_CONFIG_DISP_DSI0_SEL_IN 0xf68
#define MT8365_DISP_REG_CONFIG_DISP_RDMA1_SOUT_SEL 0xfd0
#define MT8365_DISP_REG_CONFIG_DISP_DPI0_SEL_IN 0xfd8
#define MT8365_DISP_REG_CONFIG_DISP_LVDS_SYS_CFG_00 0xfdc
#define MT8365_DISP_MS_IN_OUT_MASK GENMASK(3, 0)
#define MT8365_RDMA0_SOUT_COLOR0 0x1
#define MT8365_DITHER_MOUT_EN_DSI0 BIT(0)
#define MT8365_DSI0_SEL_IN_DITHER 0x1
#define MT8365_RDMA0_SEL_IN_OVL0 0x0
#define MT8365_RDMA0_RSZ0_SEL_IN_RDMA0 0x0
#define MT8365_DISP_COLOR_SEL_IN_COLOR0 0x0
#define MT8365_OVL0_MOUT_PATH0_SEL BIT(0)
#define MT8365_RDMA1_SOUT_DPI0 0x1
#define MT8365_DPI0_SEL_IN_RDMA1 0x0
#define MT8365_LVDS_SYS_CFG_00_SEL_LVDS_PXL_CLK 0x1
#define MT8365_DPI0_SEL_IN_RDMA1 0x0
static const struct mtk_mmsys_routes mt8365_mmsys_routing_table[] = {
MMSYS_ROUTE(OVL0, RDMA0,
MT8365_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN,
MT8365_DISP_MS_IN_OUT_MASK, MT8365_OVL0_MOUT_PATH0_SEL),
MMSYS_ROUTE(OVL0, RDMA0,
MT8365_DISP_REG_CONFIG_DISP_RDMA0_SEL_IN,
MT8365_DISP_MS_IN_OUT_MASK, MT8365_RDMA0_SEL_IN_OVL0),
MMSYS_ROUTE(RDMA0, COLOR0,
MT8365_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL,
MT8365_DISP_MS_IN_OUT_MASK, MT8365_RDMA0_SOUT_COLOR0),
MMSYS_ROUTE(COLOR0, CCORR,
MT8365_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN,
MT8365_DISP_MS_IN_OUT_MASK, MT8365_DISP_COLOR_SEL_IN_COLOR0),
MMSYS_ROUTE(DITHER0, DSI0,
MT8365_DISP_REG_CONFIG_DISP_DITHER0_MOUT_EN,
MT8365_DISP_MS_IN_OUT_MASK, MT8365_DITHER_MOUT_EN_DSI0),
MMSYS_ROUTE(DITHER0, DSI0,
MT8365_DISP_REG_CONFIG_DISP_DSI0_SEL_IN,
MT8365_DISP_MS_IN_OUT_MASK, MT8365_DSI0_SEL_IN_DITHER),
MMSYS_ROUTE(RDMA0, COLOR0,
MT8365_DISP_REG_CONFIG_DISP_RDMA0_RSZ0_SEL_IN,
MT8365_DISP_MS_IN_OUT_MASK, MT8365_RDMA0_RSZ0_SEL_IN_RDMA0),
MMSYS_ROUTE(RDMA1, DPI0,
MT8365_DISP_REG_CONFIG_DISP_LVDS_SYS_CFG_00,
MT8365_LVDS_SYS_CFG_00_SEL_LVDS_PXL_CLK,
MT8365_LVDS_SYS_CFG_00_SEL_LVDS_PXL_CLK),
MMSYS_ROUTE(RDMA1, DPI0,
MT8365_DISP_REG_CONFIG_DISP_DPI0_SEL_IN,
MT8365_DISP_MS_IN_OUT_MASK, MT8365_DPI0_SEL_IN_RDMA1),
MMSYS_ROUTE(RDMA1, DPI0,
MT8365_DISP_REG_CONFIG_DISP_RDMA1_SOUT_SEL,
MT8365_DISP_MS_IN_OUT_MASK, MT8365_RDMA1_SOUT_DPI0),
};
#endif /* __SOC_MEDIATEK_MT8365_MMSYS_H */
@@ -0,0 +1,597 @@
// 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/of.h>
#include <linux/of_address.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
#define CMDQ_WRITE_ENABLE_MASK BIT(0)
#define CMDQ_POLL_ENABLE_MASK BIT(0)
/* dedicate the last GPR_R15 to assign the register address to be poll */
#define CMDQ_POLL_ADDR_GPR (15)
#define CMDQ_EOC_IRQ_EN BIT(0)
#define CMDQ_IMMEDIATE_VALUE 0
#define CMDQ_REG_TYPE 1
#define CMDQ_JUMP_RELATIVE 0
#define CMDQ_JUMP_ABSOLUTE 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;
};
static inline u8 cmdq_operand_get_type(struct cmdq_operand *op)
{
return op->reg ? CMDQ_REG_TYPE : CMDQ_IMMEDIATE_VALUE;
}
static inline u16 cmdq_operand_get_idx_value(struct cmdq_operand *op)
{
return op->reg ? op->idx : op->value;
}
int cmdq_dev_get_client_reg(struct device *dev,
struct cmdq_client_reg *client_reg, int idx)
{
struct of_phandle_args spec;
struct resource res;
int err;
if (!client_reg)
return -ENOENT;
err = of_address_to_resource(dev->of_node, 0, &res);
if (err) {
dev_err(dev, "Missing reg in %s node\n", dev->of_node->full_name);
return -EINVAL;
}
client_reg->pa_base = res.start;
err = of_parse_phandle_with_fixed_args(dev->of_node,
"mediatek,gce-client-reg",
3, idx, &spec);
if (err < 0) {
dev_dbg(dev,
"error %d can't parse gce-client-reg property (%d)",
err, idx);
/* make subsys invalid */
client_reg->subsys = CMDQ_SUBSYS_INVALID;
/*
* All GCEs support writing register PA with mask without subsys,
* but this requires extra GCE instructions to convert the PA into
* a format that GCE can handle, which is less performance than
* directly using subsys. Therefore, when subsys is available,
* we prefer to use subsys for writing register PA.
*/
client_reg->pkt_write = cmdq_pkt_write_pa;
client_reg->pkt_write_mask = cmdq_pkt_write_mask_pa;
return 0;
}
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);
client_reg->pkt_write = cmdq_pkt_write_subsys;
client_reg->pkt_write_mask = cmdq_pkt_write_mask_subsys;
return 0;
}
EXPORT_SYMBOL(cmdq_dev_get_client_reg);
struct cmdq_client *cmdq_mbox_create(struct device *dev, int index)
{
struct cmdq_client *client;
client = kzalloc_obj(*client);
if (!client)
return (struct cmdq_client *)-ENOMEM;
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)
{
mbox_free_channel(client->chan);
kfree(client);
}
EXPORT_SYMBOL(cmdq_mbox_destroy);
int cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt, size_t size)
{
struct device *dev;
dma_addr_t dma_addr;
pkt->va_base = kzalloc(size, GFP_KERNEL);
if (!pkt->va_base)
return -ENOMEM;
pkt->buf_size = size;
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);
return -ENOMEM;
}
pkt->pa_base = dma_addr;
cmdq_get_mbox_priv(client->chan, &pkt->priv);
return 0;
}
EXPORT_SYMBOL(cmdq_pkt_create);
void cmdq_pkt_destroy(struct cmdq_client *client, struct cmdq_pkt *pkt)
{
dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size,
DMA_TO_DEVICE);
kfree(pkt->va_base);
}
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;
}
static int cmdq_pkt_mask(struct cmdq_pkt *pkt, u32 mask)
{
struct cmdq_instruction inst = {
.op = CMDQ_CODE_MASK,
.mask = ~mask
};
return cmdq_pkt_append_command(pkt, inst);
}
int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value)
{
struct cmdq_instruction inst = {
.op = CMDQ_CODE_WRITE,
.value = value,
.offset = offset,
.subsys = subsys
};
return cmdq_pkt_append_command(pkt, inst);
}
EXPORT_SYMBOL(cmdq_pkt_write);
int cmdq_pkt_write_pa(struct cmdq_pkt *pkt, u8 subsys /*unused*/, u32 pa_base,
u16 offset, u32 value)
{
int err;
err = cmdq_pkt_assign(pkt, CMDQ_THR_SPR_IDX0, CMDQ_ADDR_HIGH(pa_base));
if (err < 0)
return err;
return cmdq_pkt_write_s_value(pkt, CMDQ_THR_SPR_IDX0, CMDQ_ADDR_LOW(offset), value);
}
EXPORT_SYMBOL(cmdq_pkt_write_pa);
int cmdq_pkt_write_subsys(struct cmdq_pkt *pkt, u8 subsys, u32 pa_base /*unused*/,
u16 offset, u32 value)
{
return cmdq_pkt_write(pkt, subsys, offset, value);
}
EXPORT_SYMBOL(cmdq_pkt_write_subsys);
int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
u16 offset, u32 value, u32 mask)
{
u16 offset_mask = offset;
int err;
if (mask != GENMASK(31, 0)) {
err = cmdq_pkt_mask(pkt, mask);
if (err < 0)
return err;
offset_mask |= CMDQ_WRITE_ENABLE_MASK;
}
return cmdq_pkt_write(pkt, subsys, offset_mask, value);
}
EXPORT_SYMBOL(cmdq_pkt_write_mask);
int cmdq_pkt_write_mask_pa(struct cmdq_pkt *pkt, u8 subsys /*unused*/, u32 pa_base,
u16 offset, u32 value, u32 mask)
{
int err;
err = cmdq_pkt_assign(pkt, CMDQ_THR_SPR_IDX0, CMDQ_ADDR_HIGH(pa_base));
if (err < 0)
return err;
return cmdq_pkt_write_s_mask_value(pkt, CMDQ_THR_SPR_IDX0,
CMDQ_ADDR_LOW(offset), value, mask);
}
EXPORT_SYMBOL(cmdq_pkt_write_mask_pa);
int cmdq_pkt_write_mask_subsys(struct cmdq_pkt *pkt, u8 subsys, u32 pa_base /*unused*/,
u16 offset, u32 value, u32 mask)
{
return cmdq_pkt_write_mask(pkt, subsys, offset, value, mask);
}
EXPORT_SYMBOL(cmdq_pkt_write_mask_subsys);
int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, u16 addr_low,
u16 reg_idx)
{
struct cmdq_instruction inst = {
.op = CMDQ_CODE_READ_S,
.dst_t = CMDQ_REG_TYPE,
.sop = high_addr_reg_idx,
.reg_dst = reg_idx,
.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 = {
.op = CMDQ_CODE_WRITE_S,
.src_t = CMDQ_REG_TYPE,
.sop = high_addr_reg_idx,
.offset = addr_low,
.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 = {
.op = CMDQ_CODE_WRITE_S_MASK,
.src_t = CMDQ_REG_TYPE,
.sop = high_addr_reg_idx,
.offset = addr_low,
.src_reg = src_reg_idx,
};
int err;
err = cmdq_pkt_mask(pkt, mask);
if (err < 0)
return err;
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 = {
.op = CMDQ_CODE_WRITE_S,
.sop = high_addr_reg_idx,
.offset = addr_low,
.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 = {
.op = CMDQ_CODE_WRITE_S_MASK,
.sop = high_addr_reg_idx,
.offset = addr_low,
.value = value
};
int err;
err = cmdq_pkt_mask(pkt, mask);
if (err < 0)
return err;
return cmdq_pkt_append_command(pkt, inst);
}
EXPORT_SYMBOL(cmdq_pkt_write_s_mask_value);
int cmdq_pkt_mem_move(struct cmdq_pkt *pkt, dma_addr_t src_addr, dma_addr_t dst_addr)
{
const u16 high_addr_reg_idx = CMDQ_THR_SPR_IDX0;
const u16 value_reg_idx = CMDQ_THR_SPR_IDX1;
int ret;
/* read the value of src_addr into high_addr_reg_idx */
src_addr += pkt->priv.mminfra_offset;
ret = cmdq_pkt_assign(pkt, high_addr_reg_idx, CMDQ_ADDR_HIGH(src_addr));
if (ret < 0)
return ret;
ret = cmdq_pkt_read_s(pkt, high_addr_reg_idx, CMDQ_ADDR_LOW(src_addr), value_reg_idx);
if (ret < 0)
return ret;
/* write the value of value_reg_idx into dst_addr */
dst_addr += pkt->priv.mminfra_offset;
ret = cmdq_pkt_assign(pkt, high_addr_reg_idx, CMDQ_ADDR_HIGH(dst_addr));
if (ret < 0)
return ret;
ret = cmdq_pkt_write_s(pkt, high_addr_reg_idx, CMDQ_ADDR_LOW(dst_addr), value_reg_idx);
if (ret < 0)
return ret;
return 0;
}
EXPORT_SYMBOL(cmdq_pkt_mem_move);
int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event, bool clear)
{
u32 clear_option = clear ? CMDQ_WFE_UPDATE : 0;
struct cmdq_instruction inst = {
.op = CMDQ_CODE_WFE,
.value = CMDQ_WFE_OPTION | clear_option,
.event = event
};
if (event >= CMDQ_MAX_EVENT)
return -EINVAL;
return cmdq_pkt_append_command(pkt, inst);
}
EXPORT_SYMBOL(cmdq_pkt_wfe);
int cmdq_pkt_acquire_event(struct cmdq_pkt *pkt, u16 event)
{
struct cmdq_instruction inst = {
.op = CMDQ_CODE_WFE,
.value = CMDQ_WFE_UPDATE | CMDQ_WFE_UPDATE_VALUE | CMDQ_WFE_WAIT,
.event = event
};
if (event >= CMDQ_MAX_EVENT)
return -EINVAL;
return cmdq_pkt_append_command(pkt, inst);
}
EXPORT_SYMBOL(cmdq_pkt_acquire_event);
int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event)
{
struct cmdq_instruction inst = {
.op = CMDQ_CODE_WFE,
.value = CMDQ_WFE_UPDATE,
.event = event
};
if (event >= CMDQ_MAX_EVENT)
return -EINVAL;
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 = {
.op = CMDQ_CODE_WFE,
.value = CMDQ_WFE_UPDATE | CMDQ_WFE_UPDATE_VALUE,
.event = event
};
if (event >= CMDQ_MAX_EVENT)
return -EINVAL;
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 = {
.op = CMDQ_CODE_POLL,
.value = value,
.offset = offset,
.subsys = subsys
};
return cmdq_pkt_append_command(pkt, inst);
}
EXPORT_SYMBOL(cmdq_pkt_poll);
int cmdq_pkt_poll_mask(struct cmdq_pkt *pkt, u8 subsys,
u16 offset, u32 value, u32 mask)
{
int err;
err = cmdq_pkt_mask(pkt, mask);
if (err < 0)
return err;
offset = offset | CMDQ_POLL_ENABLE_MASK;
return cmdq_pkt_poll(pkt, subsys, offset, value);
}
EXPORT_SYMBOL(cmdq_pkt_poll_mask);
int cmdq_pkt_poll_addr(struct cmdq_pkt *pkt, dma_addr_t addr, u32 value, u32 mask)
{
struct cmdq_instruction inst = { {0} };
u8 use_mask = 0;
int ret;
/*
* Append an MASK instruction to set the mask for following POLL instruction
* which enables use_mask bit.
*/
if (mask != GENMASK(31, 0)) {
ret = cmdq_pkt_mask(pkt, mask);
if (ret < 0)
return ret;
use_mask = CMDQ_POLL_ENABLE_MASK;
}
/*
* POLL is an legacy operation in GCE and it does not support SPR and CMDQ_CODE_LOGIC,
* so it can not use cmdq_pkt_assign to keep polling register address to SPR.
* If user wants to poll a register address which doesn't have a subsys id,
* user needs to use GPR and CMDQ_CODE_MASK to move polling register address to GPR.
*/
inst.op = CMDQ_CODE_MASK;
inst.dst_t = CMDQ_REG_TYPE;
inst.sop = CMDQ_POLL_ADDR_GPR;
inst.value = addr + pkt->priv.mminfra_offset;
ret = cmdq_pkt_append_command(pkt, inst);
if (ret < 0)
return ret;
/* Append POLL instruction to poll the register address assign to GPR previously. */
inst.op = CMDQ_CODE_POLL;
inst.dst_t = CMDQ_REG_TYPE;
inst.sop = CMDQ_POLL_ADDR_GPR;
inst.offset = use_mask;
inst.value = value;
ret = cmdq_pkt_append_command(pkt, inst);
if (ret < 0)
return ret;
return 0;
}
EXPORT_SYMBOL(cmdq_pkt_poll_addr);
int cmdq_pkt_logic_command(struct cmdq_pkt *pkt, u16 result_reg_idx,
struct cmdq_operand *left_operand,
enum cmdq_logic_op s_op,
struct cmdq_operand *right_operand)
{
struct cmdq_instruction inst;
if (!left_operand || !right_operand || s_op >= CMDQ_LOGIC_MAX)
return -EINVAL;
inst.value = 0;
inst.op = CMDQ_CODE_LOGIC;
inst.dst_t = CMDQ_REG_TYPE;
inst.src_t = cmdq_operand_get_type(left_operand);
inst.arg_c_t = cmdq_operand_get_type(right_operand);
inst.sop = s_op;
inst.reg_dst = result_reg_idx;
inst.src_reg = cmdq_operand_get_idx_value(left_operand);
inst.arg_c = cmdq_operand_get_idx_value(right_operand);
return cmdq_pkt_append_command(pkt, inst);
}
EXPORT_SYMBOL(cmdq_pkt_logic_command);
int cmdq_pkt_assign(struct cmdq_pkt *pkt, u16 reg_idx, u32 value)
{
struct cmdq_instruction inst = {
.op = CMDQ_CODE_LOGIC,
.dst_t = CMDQ_REG_TYPE,
.reg_dst = reg_idx,
.value = value
};
return cmdq_pkt_append_command(pkt, inst);
}
EXPORT_SYMBOL(cmdq_pkt_assign);
int cmdq_pkt_jump_abs(struct cmdq_pkt *pkt, dma_addr_t addr, u8 shift_pa)
{
struct cmdq_instruction inst = {
.op = CMDQ_CODE_JUMP,
.offset = CMDQ_JUMP_ABSOLUTE,
.value = (addr + pkt->priv.mminfra_offset) >> pkt->priv.shift_pa
};
return cmdq_pkt_append_command(pkt, inst);
}
EXPORT_SYMBOL(cmdq_pkt_jump_abs);
int cmdq_pkt_jump_rel(struct cmdq_pkt *pkt, s32 offset, u8 shift_pa)
{
struct cmdq_instruction inst = {
.op = CMDQ_CODE_JUMP,
.value = (u32)offset >> shift_pa
};
return cmdq_pkt_append_command(pkt, inst);
}
EXPORT_SYMBOL(cmdq_pkt_jump_rel);
int cmdq_pkt_eoc(struct cmdq_pkt *pkt)
{
struct cmdq_instruction inst = {
.op = CMDQ_CODE_EOC,
.value = CMDQ_EOC_IRQ_EN
};
return cmdq_pkt_append_command(pkt, inst);
}
EXPORT_SYMBOL(cmdq_pkt_eoc);
MODULE_DESCRIPTION("MediaTek Command Queue (CMDQ) driver");
MODULE_LICENSE("GPL v2");
@@ -0,0 +1,324 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020 MediaTek Inc.
*/
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#define VIO_MOD_TO_REG_IND(m) ((m) / 32)
#define VIO_MOD_TO_REG_OFF(m) ((m) % 32)
struct mtk_devapc_vio_dbgs {
union {
u32 vio_dbg0;
struct {
u32 mstid:16;
u32 dmnid:6;
u32 vio_w:1;
u32 vio_r:1;
u32 addr_h:4;
u32 resv:4;
} dbg0_bits;
};
u32 vio_dbg1;
};
struct mtk_devapc_regs_ofs {
/* reg offset */
u32 vio_mask_offset;
u32 vio_sta_offset;
u32 vio_dbg0_offset;
u32 vio_dbg1_offset;
u32 apc_con_offset;
u32 vio_shift_sta_offset;
u32 vio_shift_sel_offset;
u32 vio_shift_con_offset;
};
struct mtk_devapc_data {
/* numbers of violation index */
u32 vio_idx_num;
const struct mtk_devapc_regs_ofs *regs_ofs;
};
struct mtk_devapc_context {
struct device *dev;
void __iomem *infra_base;
struct clk *infra_clk;
const struct mtk_devapc_data *data;
};
static void clear_vio_status(struct mtk_devapc_context *ctx)
{
void __iomem *reg;
int i;
reg = ctx->infra_base + ctx->data->regs_ofs->vio_sta_offset;
for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->data->vio_idx_num) - 1; i++)
writel(GENMASK(31, 0), reg + 4 * i);
writel(GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1, 0),
reg + 4 * i);
}
static void mask_module_irq(struct mtk_devapc_context *ctx, bool mask)
{
void __iomem *reg;
u32 val;
int i;
reg = ctx->infra_base + ctx->data->regs_ofs->vio_mask_offset;
if (mask)
val = GENMASK(31, 0);
else
val = 0;
for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->data->vio_idx_num) - 1; i++)
writel(val, reg + 4 * i);
val = readl(reg + 4 * i);
if (mask)
val |= GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1,
0);
else
val &= ~GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1,
0);
writel(val, reg + 4 * i);
}
#define PHY_DEVAPC_TIMEOUT 0x10000
/*
* devapc_sync_vio_dbg - do "shift" mechansim" to get full violation information.
* shift mechanism is depends on devapc hardware design.
* Mediatek devapc set multiple slaves as a group.
* When violation is triggered, violation info is kept
* inside devapc hardware.
* Driver should do shift mechansim to sync full violation
* info to VIO_DBGs registers.
*
*/
static int devapc_sync_vio_dbg(struct mtk_devapc_context *ctx)
{
void __iomem *pd_vio_shift_sta_reg;
void __iomem *pd_vio_shift_sel_reg;
void __iomem *pd_vio_shift_con_reg;
int min_shift_group;
int ret;
u32 val;
pd_vio_shift_sta_reg = ctx->infra_base +
ctx->data->regs_ofs->vio_shift_sta_offset;
pd_vio_shift_sel_reg = ctx->infra_base +
ctx->data->regs_ofs->vio_shift_sel_offset;
pd_vio_shift_con_reg = ctx->infra_base +
ctx->data->regs_ofs->vio_shift_con_offset;
/* Find the minimum shift group which has violation */
val = readl(pd_vio_shift_sta_reg);
if (!val)
return false;
min_shift_group = __ffs(val);
/* Assign the group to sync */
writel(0x1 << min_shift_group, pd_vio_shift_sel_reg);
/* Start syncing */
writel(0x1, pd_vio_shift_con_reg);
ret = readl_poll_timeout(pd_vio_shift_con_reg, val, val == 0x3, 0,
PHY_DEVAPC_TIMEOUT);
if (ret) {
dev_err(ctx->dev, "%s: Shift violation info failed\n", __func__);
return false;
}
/* Stop syncing */
writel(0x0, pd_vio_shift_con_reg);
/* Write clear */
writel(0x1 << min_shift_group, pd_vio_shift_sta_reg);
return true;
}
/*
* devapc_extract_vio_dbg - extract full violation information after doing
* shift mechanism.
*/
static void devapc_extract_vio_dbg(struct mtk_devapc_context *ctx)
{
struct mtk_devapc_vio_dbgs vio_dbgs;
void __iomem *vio_dbg0_reg;
void __iomem *vio_dbg1_reg;
vio_dbg0_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg0_offset;
vio_dbg1_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg1_offset;
vio_dbgs.vio_dbg0 = readl(vio_dbg0_reg);
vio_dbgs.vio_dbg1 = readl(vio_dbg1_reg);
/* Print violation information */
if (vio_dbgs.dbg0_bits.vio_w)
dev_info(ctx->dev, "Write Violation\n");
else if (vio_dbgs.dbg0_bits.vio_r)
dev_info(ctx->dev, "Read Violation\n");
dev_info(ctx->dev, "Bus ID:0x%x, Dom ID:0x%x, Vio Addr:0x%x\n",
vio_dbgs.dbg0_bits.mstid, vio_dbgs.dbg0_bits.dmnid,
vio_dbgs.vio_dbg1);
}
/*
* devapc_violation_irq - the devapc Interrupt Service Routine (ISR) will dump
* violation information including which master violates
* access slave.
*/
static irqreturn_t devapc_violation_irq(int irq_number, void *data)
{
struct mtk_devapc_context *ctx = data;
while (devapc_sync_vio_dbg(ctx))
devapc_extract_vio_dbg(ctx);
clear_vio_status(ctx);
return IRQ_HANDLED;
}
/*
* start_devapc - unmask slave's irq to start receiving devapc violation.
*/
static void start_devapc(struct mtk_devapc_context *ctx)
{
writel(BIT(31), ctx->infra_base + ctx->data->regs_ofs->apc_con_offset);
mask_module_irq(ctx, false);
}
/*
* stop_devapc - mask slave's irq to stop service.
*/
static void stop_devapc(struct mtk_devapc_context *ctx)
{
mask_module_irq(ctx, true);
writel(BIT(2), ctx->infra_base + ctx->data->regs_ofs->apc_con_offset);
}
static const struct mtk_devapc_regs_ofs devapc_regs_ofs_mt6779 = {
.vio_mask_offset = 0x0,
.vio_sta_offset = 0x400,
.vio_dbg0_offset = 0x900,
.vio_dbg1_offset = 0x904,
.apc_con_offset = 0xF00,
.vio_shift_sta_offset = 0xF10,
.vio_shift_sel_offset = 0xF14,
.vio_shift_con_offset = 0xF20,
};
static const struct mtk_devapc_data devapc_mt6779 = {
.vio_idx_num = 511,
.regs_ofs = &devapc_regs_ofs_mt6779,
};
static const struct mtk_devapc_data devapc_mt8186 = {
.vio_idx_num = 519,
.regs_ofs = &devapc_regs_ofs_mt6779,
};
static const struct of_device_id mtk_devapc_dt_match[] = {
{
.compatible = "mediatek,mt6779-devapc",
.data = &devapc_mt6779,
}, {
.compatible = "mediatek,mt8186-devapc",
.data = &devapc_mt8186,
}, {
},
};
MODULE_DEVICE_TABLE(of, mtk_devapc_dt_match);
static int mtk_devapc_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct mtk_devapc_context *ctx;
u32 devapc_irq;
int ret;
if (IS_ERR(node))
return -ENODEV;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->data = of_device_get_match_data(&pdev->dev);
ctx->dev = &pdev->dev;
ctx->infra_base = of_iomap(node, 0);
if (!ctx->infra_base)
return -EINVAL;
devapc_irq = irq_of_parse_and_map(node, 0);
if (!devapc_irq) {
ret = -EINVAL;
goto err;
}
ctx->infra_clk = devm_clk_get_enabled(&pdev->dev, "devapc-infra-clock");
if (IS_ERR(ctx->infra_clk)) {
ret = -EINVAL;
goto err;
}
ret = devm_request_irq(&pdev->dev, devapc_irq, devapc_violation_irq,
IRQF_TRIGGER_NONE, "devapc", ctx);
if (ret)
goto err;
platform_set_drvdata(pdev, ctx);
start_devapc(ctx);
return 0;
err:
iounmap(ctx->infra_base);
return ret;
}
static void mtk_devapc_remove(struct platform_device *pdev)
{
struct mtk_devapc_context *ctx = platform_get_drvdata(pdev);
stop_devapc(ctx);
iounmap(ctx->infra_base);
}
static struct platform_driver mtk_devapc_driver = {
.probe = mtk_devapc_probe,
.remove = mtk_devapc_remove,
.driver = {
.name = "mtk-devapc",
.of_match_table = mtk_devapc_dt_match,
},
};
module_platform_driver(mtk_devapc_driver);
MODULE_DESCRIPTION("Mediatek Device APC Driver");
MODULE_AUTHOR("Neal Liu <neal.liu@mediatek.com>");
MODULE_LICENSE("GPL");
@@ -0,0 +1,878 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2021 MediaTek Inc.
* Copyright (c) 2024 Collabora Ltd.
* AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
*/
#include <linux/arm-smccc.h>
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/soc/mediatek/dvfsrc.h>
#include <linux/soc/mediatek/mtk_sip_svc.h>
/* DVFSRC_BASIC_CONTROL */
#define DVFSRC_V4_BASIC_CTRL_OPP_COUNT GENMASK(26, 20)
/* DVFSRC_LEVEL */
#define DVFSRC_V1_LEVEL_TARGET_LEVEL GENMASK(15, 0)
#define DVFSRC_TGT_LEVEL_IDLE 0x00
#define DVFSRC_V1_LEVEL_CURRENT_LEVEL GENMASK(31, 16)
#define DVFSRC_V4_LEVEL_TARGET_LEVEL GENMASK(15, 8)
#define DVFSRC_V4_LEVEL_TARGET_PRESENT BIT(16)
/* DVFSRC_SW_REQ, DVFSRC_SW_REQ2 */
#define DVFSRC_V1_SW_REQ2_DRAM_LEVEL GENMASK(1, 0)
#define DVFSRC_V1_SW_REQ2_VCORE_LEVEL GENMASK(3, 2)
#define DVFSRC_V2_SW_REQ_DRAM_LEVEL GENMASK(3, 0)
#define DVFSRC_V2_SW_REQ_VCORE_LEVEL GENMASK(6, 4)
#define DVFSRC_V4_SW_REQ_EMI_LEVEL GENMASK(3, 0)
#define DVFSRC_V4_SW_REQ_DRAM_LEVEL GENMASK(15, 12)
/* DVFSRC_VCORE */
#define DVFSRC_V2_VCORE_REQ_VSCP_LEVEL GENMASK(14, 12)
/* DVFSRC_TARGET_GEAR */
#define DVFSRC_V4_GEAR_TARGET_DRAM GENMASK(7, 0)
#define DVFSRC_V4_GEAR_TARGET_VCORE GENMASK(15, 8)
/* DVFSRC_GEAR_INFO */
#define DVFSRC_V4_GEAR_INFO_REG_WIDTH 0x4
#define DVFSRC_V4_GEAR_INFO_REG_LEVELS 64
#define DVFSRC_V4_GEAR_INFO_VCORE GENMASK(3, 0)
#define DVFSRC_V4_GEAR_INFO_EMI GENMASK(7, 4)
#define DVFSRC_V4_GEAR_INFO_DRAM GENMASK(15, 12)
#define DVFSRC_POLL_TIMEOUT_US 1000
#define STARTUP_TIME_US 1
#define MTK_SIP_DVFSRC_INIT 0x0
#define MTK_SIP_DVFSRC_START 0x1
enum mtk_dvfsrc_bw_type {
DVFSRC_BW_AVG,
DVFSRC_BW_PEAK,
DVFSRC_BW_HRT,
DVFSRC_BW_MAX,
};
struct dvfsrc_opp {
u32 vcore_opp;
u32 dram_opp;
u32 emi_opp;
};
struct dvfsrc_opp_desc {
const struct dvfsrc_opp *opps;
u32 num_opp;
};
struct dvfsrc_soc_data;
struct mtk_dvfsrc {
struct device *dev;
struct clk *clk;
struct platform_device *icc;
struct platform_device *regulator;
const struct dvfsrc_soc_data *dvd;
const struct dvfsrc_opp_desc *curr_opps;
void __iomem *regs;
int dram_type;
};
struct dvfsrc_soc_data {
const int *regs;
const u8 *bw_units;
const bool has_emi_ddr;
const struct dvfsrc_opp_desc *opps_desc;
u32 (*calc_dram_bw)(struct mtk_dvfsrc *dvfsrc, enum mtk_dvfsrc_bw_type type, u64 bw);
u32 (*get_target_level)(struct mtk_dvfsrc *dvfsrc);
u32 (*get_current_level)(struct mtk_dvfsrc *dvfsrc);
u32 (*get_vcore_level)(struct mtk_dvfsrc *dvfsrc);
u32 (*get_vscp_level)(struct mtk_dvfsrc *dvfsrc);
u32 (*get_opp_count)(struct mtk_dvfsrc *dvfsrc);
int (*get_hw_opps)(struct mtk_dvfsrc *dvfsrc);
void (*set_dram_bw)(struct mtk_dvfsrc *dvfsrc, u64 bw);
void (*set_dram_peak_bw)(struct mtk_dvfsrc *dvfsrc, u64 bw);
void (*set_dram_hrt_bw)(struct mtk_dvfsrc *dvfsrc, u64 bw);
void (*set_opp_level)(struct mtk_dvfsrc *dvfsrc, u32 level);
void (*set_vcore_level)(struct mtk_dvfsrc *dvfsrc, u32 level);
void (*set_vscp_level)(struct mtk_dvfsrc *dvfsrc, u32 level);
int (*wait_for_opp_level)(struct mtk_dvfsrc *dvfsrc, u32 level);
int (*wait_for_vcore_level)(struct mtk_dvfsrc *dvfsrc, u32 level);
/**
* @bw_max_constraints - array of maximum bandwidth for this hardware
*
* indexed by &enum mtk_dvfsrc_bw_type, storing the maximum permissible
* hardware value for each bandwidth type.
*/
const u32 *const bw_max_constraints;
/**
* @bw_min_constraints - array of minimum bandwidth for this hardware
*
* indexed by &enum mtk_dvfsrc_bw_type, storing the minimum permissible
* hardware value for each bandwidth type.
*/
const u32 *const bw_min_constraints;
};
static u32 dvfsrc_readl(struct mtk_dvfsrc *dvfs, u32 offset)
{
return readl(dvfs->regs + dvfs->dvd->regs[offset]);
}
static void dvfsrc_writel(struct mtk_dvfsrc *dvfs, u32 offset, u32 val)
{
writel(val, dvfs->regs + dvfs->dvd->regs[offset]);
}
enum dvfsrc_regs {
DVFSRC_BASIC_CONTROL,
DVFSRC_SW_REQ,
DVFSRC_SW_REQ2,
DVFSRC_LEVEL,
DVFSRC_TARGET_LEVEL,
DVFSRC_SW_BW,
DVFSRC_SW_PEAK_BW,
DVFSRC_SW_HRT_BW,
DVFSRC_SW_EMI_BW,
DVFSRC_VCORE,
DVFSRC_TARGET_GEAR,
DVFSRC_GEAR_INFO_L,
DVFSRC_GEAR_INFO_H,
DVFSRC_REGS_MAX,
};
static const int dvfsrc_mt8183_regs[] = {
[DVFSRC_SW_REQ] = 0x4,
[DVFSRC_SW_REQ2] = 0x8,
[DVFSRC_LEVEL] = 0xDC,
[DVFSRC_SW_BW] = 0x160,
};
static const int dvfsrc_mt8195_regs[] = {
[DVFSRC_SW_REQ] = 0xc,
[DVFSRC_VCORE] = 0x6c,
[DVFSRC_SW_PEAK_BW] = 0x278,
[DVFSRC_SW_BW] = 0x26c,
[DVFSRC_SW_HRT_BW] = 0x290,
[DVFSRC_LEVEL] = 0xd44,
[DVFSRC_TARGET_LEVEL] = 0xd48,
};
static const int dvfsrc_mt8196_regs[] = {
[DVFSRC_BASIC_CONTROL] = 0x0,
[DVFSRC_SW_REQ] = 0x18,
[DVFSRC_VCORE] = 0x80,
[DVFSRC_GEAR_INFO_L] = 0xfc,
[DVFSRC_SW_BW] = 0x1e8,
[DVFSRC_SW_PEAK_BW] = 0x1f4,
[DVFSRC_SW_HRT_BW] = 0x20c,
[DVFSRC_LEVEL] = 0x5f0,
[DVFSRC_TARGET_LEVEL] = 0x5f0,
[DVFSRC_SW_REQ2] = 0x604,
[DVFSRC_SW_EMI_BW] = 0x60c,
[DVFSRC_TARGET_GEAR] = 0x6ac,
[DVFSRC_GEAR_INFO_H] = 0x6b0,
};
static const struct dvfsrc_opp *dvfsrc_get_current_opp(struct mtk_dvfsrc *dvfsrc)
{
u32 level = dvfsrc->dvd->get_current_level(dvfsrc);
return &dvfsrc->curr_opps->opps[level];
}
static u32 dvfsrc_get_current_target_vcore_gear(struct mtk_dvfsrc *dvfsrc)
{
u32 val = dvfsrc_readl(dvfsrc, DVFSRC_TARGET_GEAR);
return FIELD_GET(DVFSRC_V4_GEAR_TARGET_VCORE, val);
}
static u32 dvfsrc_get_current_target_dram_gear(struct mtk_dvfsrc *dvfsrc)
{
u32 val = dvfsrc_readl(dvfsrc, DVFSRC_TARGET_GEAR);
return FIELD_GET(DVFSRC_V4_GEAR_TARGET_DRAM, val);
}
static bool dvfsrc_is_idle(struct mtk_dvfsrc *dvfsrc)
{
if (!dvfsrc->dvd->get_target_level)
return true;
return dvfsrc->dvd->get_target_level(dvfsrc) == DVFSRC_TGT_LEVEL_IDLE;
}
static int dvfsrc_wait_for_vcore_level_v1(struct mtk_dvfsrc *dvfsrc, u32 level)
{
const struct dvfsrc_opp *curr;
return readx_poll_timeout_atomic(dvfsrc_get_current_opp, dvfsrc, curr,
curr->vcore_opp >= level, STARTUP_TIME_US,
DVFSRC_POLL_TIMEOUT_US);
}
static int dvfsrc_wait_for_opp_level_v1(struct mtk_dvfsrc *dvfsrc, u32 level)
{
const struct dvfsrc_opp *target, *curr;
int ret;
target = &dvfsrc->curr_opps->opps[level];
ret = readx_poll_timeout_atomic(dvfsrc_get_current_opp, dvfsrc, curr,
curr->dram_opp >= target->dram_opp &&
curr->vcore_opp >= target->vcore_opp,
STARTUP_TIME_US, DVFSRC_POLL_TIMEOUT_US);
if (ret < 0) {
dev_warn(dvfsrc->dev,
"timeout! target OPP: %u, dram: %d, vcore: %d\n", level,
curr->dram_opp, curr->vcore_opp);
return ret;
}
return 0;
}
static int dvfsrc_wait_for_opp_level_v2(struct mtk_dvfsrc *dvfsrc, u32 level)
{
const struct dvfsrc_opp *target, *curr;
int ret;
target = &dvfsrc->curr_opps->opps[level];
ret = readx_poll_timeout_atomic(dvfsrc_get_current_opp, dvfsrc, curr,
curr->dram_opp >= target->dram_opp &&
curr->vcore_opp >= target->vcore_opp,
STARTUP_TIME_US, DVFSRC_POLL_TIMEOUT_US);
if (ret < 0) {
dev_warn(dvfsrc->dev,
"timeout! target OPP: %u, dram: %d\n", level, curr->dram_opp);
return ret;
}
return 0;
}
static int dvfsrc_wait_for_vcore_level_v4(struct mtk_dvfsrc *dvfsrc, u32 level)
{
u32 val;
return readx_poll_timeout_atomic(dvfsrc_get_current_target_vcore_gear,
dvfsrc, val, val >= level,
STARTUP_TIME_US, DVFSRC_POLL_TIMEOUT_US);
}
static int dvfsrc_wait_for_opp_level_v4(struct mtk_dvfsrc *dvfsrc, u32 level)
{
u32 val;
return readx_poll_timeout_atomic(dvfsrc_get_current_target_dram_gear,
dvfsrc, val, val >= level,
STARTUP_TIME_US, DVFSRC_POLL_TIMEOUT_US);
}
static u32 dvfsrc_get_target_level_v1(struct mtk_dvfsrc *dvfsrc)
{
u32 val = dvfsrc_readl(dvfsrc, DVFSRC_LEVEL);
return FIELD_GET(DVFSRC_V1_LEVEL_TARGET_LEVEL, val);
}
static u32 dvfsrc_get_current_level_v1(struct mtk_dvfsrc *dvfsrc)
{
u32 val = dvfsrc_readl(dvfsrc, DVFSRC_LEVEL);
u32 current_level = FIELD_GET(DVFSRC_V1_LEVEL_CURRENT_LEVEL, val);
return ffs(current_level) - 1;
}
static u32 dvfsrc_get_target_level_v2(struct mtk_dvfsrc *dvfsrc)
{
return dvfsrc_readl(dvfsrc, DVFSRC_TARGET_LEVEL);
}
static u32 dvfsrc_get_current_level_v2(struct mtk_dvfsrc *dvfsrc)
{
u32 val = dvfsrc_readl(dvfsrc, DVFSRC_LEVEL);
u32 level = ffs(val);
/* Valid levels */
if (level < dvfsrc->curr_opps->num_opp)
return dvfsrc->curr_opps->num_opp - level;
/* Zero for level 0 or invalid level */
return 0;
}
static u32 dvfsrc_get_target_level_v4(struct mtk_dvfsrc *dvfsrc)
{
u32 val = dvfsrc_readl(dvfsrc, DVFSRC_TARGET_LEVEL);
if (val & DVFSRC_V4_LEVEL_TARGET_PRESENT)
return FIELD_GET(DVFSRC_V4_LEVEL_TARGET_LEVEL, val) + 1;
return 0;
}
static u32 dvfsrc_get_current_level_v4(struct mtk_dvfsrc *dvfsrc)
{
u32 level = dvfsrc_readl(dvfsrc, DVFSRC_LEVEL) + 1;
/* Valid levels */
if (level < dvfsrc->curr_opps->num_opp)
return dvfsrc->curr_opps->num_opp - level;
/* Zero for level 0 or invalid level */
return 0;
}
static u32 dvfsrc_get_vcore_level_v1(struct mtk_dvfsrc *dvfsrc)
{
u32 val = dvfsrc_readl(dvfsrc, DVFSRC_SW_REQ2);
return FIELD_GET(DVFSRC_V1_SW_REQ2_VCORE_LEVEL, val);
}
static void dvfsrc_set_vcore_level_v1(struct mtk_dvfsrc *dvfsrc, u32 level)
{
u32 val = dvfsrc_readl(dvfsrc, DVFSRC_SW_REQ2);
val &= ~DVFSRC_V1_SW_REQ2_VCORE_LEVEL;
val |= FIELD_PREP(DVFSRC_V1_SW_REQ2_VCORE_LEVEL, level);
dvfsrc_writel(dvfsrc, DVFSRC_SW_REQ2, val);
}
static u32 dvfsrc_get_vcore_level_v2(struct mtk_dvfsrc *dvfsrc)
{
u32 val = dvfsrc_readl(dvfsrc, DVFSRC_SW_REQ);
return FIELD_GET(DVFSRC_V2_SW_REQ_VCORE_LEVEL, val);
}
static void dvfsrc_set_vcore_level_v2(struct mtk_dvfsrc *dvfsrc, u32 level)
{
u32 val = dvfsrc_readl(dvfsrc, DVFSRC_SW_REQ);
val &= ~DVFSRC_V2_SW_REQ_VCORE_LEVEL;
val |= FIELD_PREP(DVFSRC_V2_SW_REQ_VCORE_LEVEL, level);
dvfsrc_writel(dvfsrc, DVFSRC_SW_REQ, val);
}
static u32 dvfsrc_get_vscp_level_v2(struct mtk_dvfsrc *dvfsrc)
{
u32 val = dvfsrc_readl(dvfsrc, DVFSRC_VCORE);
return FIELD_GET(DVFSRC_V2_VCORE_REQ_VSCP_LEVEL, val);
}
static void dvfsrc_set_vscp_level_v2(struct mtk_dvfsrc *dvfsrc, u32 level)
{
u32 val = dvfsrc_readl(dvfsrc, DVFSRC_VCORE);
val &= ~DVFSRC_V2_VCORE_REQ_VSCP_LEVEL;
val |= FIELD_PREP(DVFSRC_V2_VCORE_REQ_VSCP_LEVEL, level);
dvfsrc_writel(dvfsrc, DVFSRC_VCORE, val);
}
static u32 dvfsrc_get_opp_count_v4(struct mtk_dvfsrc *dvfsrc)
{
u32 val = dvfsrc_readl(dvfsrc, DVFSRC_BASIC_CONTROL);
return FIELD_GET(DVFSRC_V4_BASIC_CTRL_OPP_COUNT, val) + 1;
}
static u32
dvfsrc_calc_dram_bw_v1(struct mtk_dvfsrc *dvfsrc, enum mtk_dvfsrc_bw_type type, u64 bw)
{
return clamp_val(div_u64(bw, 100 * 1000), dvfsrc->dvd->bw_min_constraints[type],
dvfsrc->dvd->bw_max_constraints[type]);
}
/**
* dvfsrc_calc_dram_bw_v4 - convert kbps to hardware register bandwidth value
* @dvfsrc: pointer to the &struct mtk_dvfsrc of this driver instance
* @type: one of %DVFSRC_BW_AVG, %DVFSRC_BW_PEAK, or %DVFSRC_BW_HRT
* @bw: the bandwidth in kilobits per second
*
* Returns the hardware register value appropriate for expressing @bw, clamped
* to hardware limits.
*/
static u32
dvfsrc_calc_dram_bw_v4(struct mtk_dvfsrc *dvfsrc, enum mtk_dvfsrc_bw_type type, u64 bw)
{
u8 bw_unit = dvfsrc->dvd->bw_units[type];
u64 bw_mbps;
u32 bw_hw;
if (type < DVFSRC_BW_AVG || type >= DVFSRC_BW_MAX)
return 0;
bw_mbps = div_u64(bw, 1000);
bw_hw = div_u64((bw_mbps + bw_unit - 1), bw_unit);
return clamp_val(bw_hw, dvfsrc->dvd->bw_min_constraints[type],
dvfsrc->dvd->bw_max_constraints[type]);
}
static void __dvfsrc_set_dram_bw_v1(struct mtk_dvfsrc *dvfsrc, u32 reg,
enum mtk_dvfsrc_bw_type type, u64 bw)
{
u32 bw_hw = dvfsrc->dvd->calc_dram_bw(dvfsrc, type, bw);
dvfsrc_writel(dvfsrc, reg, bw_hw);
if (type == DVFSRC_BW_AVG && dvfsrc->dvd->has_emi_ddr)
dvfsrc_writel(dvfsrc, DVFSRC_SW_EMI_BW, bw_hw);
}
static void dvfsrc_set_dram_bw_v1(struct mtk_dvfsrc *dvfsrc, u64 bw)
{
__dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_BW, DVFSRC_BW_AVG, bw);
};
static void dvfsrc_set_dram_peak_bw_v1(struct mtk_dvfsrc *dvfsrc, u64 bw)
{
__dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_PEAK_BW, DVFSRC_BW_PEAK, bw);
}
static void dvfsrc_set_dram_hrt_bw_v1(struct mtk_dvfsrc *dvfsrc, u64 bw)
{
__dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_HRT_BW, DVFSRC_BW_HRT, bw);
}
static void dvfsrc_set_opp_level_v1(struct mtk_dvfsrc *dvfsrc, u32 level)
{
const struct dvfsrc_opp *opp = &dvfsrc->curr_opps->opps[level];
u32 val;
/* Translate Pstate to DVFSRC level and set it to DVFSRC HW */
val = FIELD_PREP(DVFSRC_V1_SW_REQ2_DRAM_LEVEL, opp->dram_opp);
val |= FIELD_PREP(DVFSRC_V1_SW_REQ2_VCORE_LEVEL, opp->vcore_opp);
dev_dbg(dvfsrc->dev, "vcore_opp: %d, dram_opp: %d\n", opp->vcore_opp, opp->dram_opp);
dvfsrc_writel(dvfsrc, DVFSRC_SW_REQ, val);
}
static u32 dvfsrc_get_opp_gear(struct mtk_dvfsrc *dvfsrc, u8 level)
{
u32 reg_ofst, val;
u8 idx;
/* Calculate register offset and index for requested gear */
if (level < DVFSRC_V4_GEAR_INFO_REG_LEVELS) {
reg_ofst = dvfsrc->dvd->regs[DVFSRC_GEAR_INFO_L];
idx = level;
} else {
reg_ofst = dvfsrc->dvd->regs[DVFSRC_GEAR_INFO_H];
idx = level - DVFSRC_V4_GEAR_INFO_REG_LEVELS;
}
reg_ofst += DVFSRC_V4_GEAR_INFO_REG_WIDTH * (level / 2);
/* Read the corresponding gear register */
val = readl(dvfsrc->regs + reg_ofst);
/* Each register contains two sets of data, 16 bits per gear */
val >>= 16 * (idx % 2);
return val;
}
static int dvfsrc_get_hw_opps_v4(struct mtk_dvfsrc *dvfsrc)
{
struct dvfsrc_opp *dvfsrc_opps;
struct dvfsrc_opp_desc *desc;
u32 num_opps, gear_info;
u8 num_vcore, num_dram;
u8 num_emi;
int i;
num_opps = dvfsrc_get_opp_count_v4(dvfsrc);
if (num_opps == 0) {
dev_err(dvfsrc->dev, "No OPPs programmed in DVFSRC MCU.\n");
return -EINVAL;
}
/*
* The first 16 bits set in the gear info table says how many OPPs
* and how many vcore, dram and emi table entries are available.
*/
gear_info = dvfsrc_readl(dvfsrc, DVFSRC_GEAR_INFO_L);
if (gear_info == 0) {
dev_err(dvfsrc->dev, "No gear info in DVFSRC MCU.\n");
return -EINVAL;
}
num_vcore = FIELD_GET(DVFSRC_V4_GEAR_INFO_VCORE, gear_info) + 1;
num_dram = FIELD_GET(DVFSRC_V4_GEAR_INFO_DRAM, gear_info) + 1;
num_emi = FIELD_GET(DVFSRC_V4_GEAR_INFO_EMI, gear_info) + 1;
dev_info(dvfsrc->dev,
"Discovered %u gears and %u vcore, %u dram, %u emi table entries.\n",
num_opps, num_vcore, num_dram, num_emi);
/* Allocate everything now as anything else after that cannot fail */
desc = devm_kzalloc(dvfsrc->dev, sizeof(*desc), GFP_KERNEL);
if (!desc)
return -ENOMEM;
dvfsrc_opps = devm_kcalloc(dvfsrc->dev, num_opps + 1,
sizeof(*dvfsrc_opps), GFP_KERNEL);
if (!dvfsrc_opps)
return -ENOMEM;
/* Read the OPP table gear indices */
for (i = 0; i <= num_opps; i++) {
gear_info = dvfsrc_get_opp_gear(dvfsrc, num_opps - i);
dvfsrc_opps[i].vcore_opp = FIELD_GET(DVFSRC_V4_GEAR_INFO_VCORE, gear_info);
dvfsrc_opps[i].dram_opp = FIELD_GET(DVFSRC_V4_GEAR_INFO_DRAM, gear_info);
dvfsrc_opps[i].emi_opp = FIELD_GET(DVFSRC_V4_GEAR_INFO_EMI, gear_info);
};
desc->num_opp = num_opps + 1;
desc->opps = dvfsrc_opps;
/* Assign to main structure now that everything is done! */
dvfsrc->curr_opps = desc;
return 0;
}
static void dvfsrc_set_dram_level_v4(struct mtk_dvfsrc *dvfsrc, u32 level)
{
u32 val = dvfsrc_readl(dvfsrc, DVFSRC_SW_REQ);
val &= ~DVFSRC_V4_SW_REQ_DRAM_LEVEL;
val |= FIELD_PREP(DVFSRC_V4_SW_REQ_DRAM_LEVEL, level);
dev_dbg(dvfsrc->dev, "%s level=%u\n", __func__, level);
dvfsrc_writel(dvfsrc, DVFSRC_SW_REQ, val);
}
int mtk_dvfsrc_send_request(const struct device *dev, u32 cmd, u64 data)
{
struct mtk_dvfsrc *dvfsrc = dev_get_drvdata(dev);
bool state;
int ret;
dev_dbg(dvfsrc->dev, "cmd: %d, data: %llu\n", cmd, data);
switch (cmd) {
case MTK_DVFSRC_CMD_BW:
dvfsrc->dvd->set_dram_bw(dvfsrc, data);
return 0;
case MTK_DVFSRC_CMD_HRT_BW:
if (dvfsrc->dvd->set_dram_hrt_bw)
dvfsrc->dvd->set_dram_hrt_bw(dvfsrc, data);
return 0;
case MTK_DVFSRC_CMD_PEAK_BW:
if (dvfsrc->dvd->set_dram_peak_bw)
dvfsrc->dvd->set_dram_peak_bw(dvfsrc, data);
return 0;
case MTK_DVFSRC_CMD_OPP:
if (!dvfsrc->dvd->set_opp_level)
return 0;
dvfsrc->dvd->set_opp_level(dvfsrc, data);
break;
case MTK_DVFSRC_CMD_VCORE_LEVEL:
dvfsrc->dvd->set_vcore_level(dvfsrc, data);
break;
case MTK_DVFSRC_CMD_VSCP_LEVEL:
if (!dvfsrc->dvd->set_vscp_level)
return 0;
dvfsrc->dvd->set_vscp_level(dvfsrc, data);
break;
default:
dev_err(dvfsrc->dev, "unknown command: %d\n", cmd);
return -EOPNOTSUPP;
}
/* DVFSRC needs at least 2T(~196ns) to handle a request */
udelay(STARTUP_TIME_US);
ret = readx_poll_timeout_atomic(dvfsrc_is_idle, dvfsrc, state, state,
STARTUP_TIME_US, DVFSRC_POLL_TIMEOUT_US);
if (ret < 0) {
dev_warn(dvfsrc->dev,
"%d: idle timeout, data: %llu, last: %d -> %d\n", cmd, data,
dvfsrc->dvd->get_current_level(dvfsrc),
dvfsrc->dvd->get_target_level(dvfsrc));
return ret;
}
if (cmd == MTK_DVFSRC_CMD_OPP)
ret = dvfsrc->dvd->wait_for_opp_level(dvfsrc, data);
else
ret = dvfsrc->dvd->wait_for_vcore_level(dvfsrc, data);
if (ret < 0) {
dev_warn(dvfsrc->dev,
"%d: wait timeout, data: %llu, last: %d -> %d\n",
cmd, data,
dvfsrc->dvd->get_current_level(dvfsrc),
dvfsrc->dvd->get_target_level(dvfsrc));
return ret;
}
return 0;
}
EXPORT_SYMBOL(mtk_dvfsrc_send_request);
int mtk_dvfsrc_query_info(const struct device *dev, u32 cmd, int *data)
{
struct mtk_dvfsrc *dvfsrc = dev_get_drvdata(dev);
switch (cmd) {
case MTK_DVFSRC_CMD_VCORE_LEVEL:
*data = dvfsrc->dvd->get_vcore_level(dvfsrc);
break;
case MTK_DVFSRC_CMD_VSCP_LEVEL:
*data = dvfsrc->dvd->get_vscp_level(dvfsrc);
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
EXPORT_SYMBOL(mtk_dvfsrc_query_info);
static int mtk_dvfsrc_probe(struct platform_device *pdev)
{
struct arm_smccc_res ares;
struct mtk_dvfsrc *dvfsrc;
int ret;
dvfsrc = devm_kzalloc(&pdev->dev, sizeof(*dvfsrc), GFP_KERNEL);
if (!dvfsrc)
return -ENOMEM;
dvfsrc->dvd = of_device_get_match_data(&pdev->dev);
dvfsrc->dev = &pdev->dev;
dvfsrc->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(dvfsrc->regs))
return PTR_ERR(dvfsrc->regs);
dvfsrc->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(dvfsrc->clk))
return dev_err_probe(&pdev->dev, PTR_ERR(dvfsrc->clk),
"Couldn't get and enable DVFSRC clock\n");
arm_smccc_smc(MTK_SIP_DVFSRC_VCOREFS_CONTROL, MTK_SIP_DVFSRC_INIT,
0, 0, 0, 0, 0, 0, &ares);
if (ares.a0)
return dev_err_probe(&pdev->dev, -EINVAL, "DVFSRC init failed: %lu\n", ares.a0);
dvfsrc->dram_type = ares.a1;
dev_dbg(&pdev->dev, "DRAM Type: %d\n", dvfsrc->dram_type);
/* Newer versions of the DVFSRC MCU have pre-programmed gear tables */
if (dvfsrc->dvd->get_hw_opps) {
ret = dvfsrc->dvd->get_hw_opps(dvfsrc);
if (ret)
return ret;
} else {
dvfsrc->curr_opps = &dvfsrc->dvd->opps_desc[dvfsrc->dram_type];
}
platform_set_drvdata(pdev, dvfsrc);
ret = devm_of_platform_populate(&pdev->dev);
if (ret)
return dev_err_probe(&pdev->dev, ret, "Failed to populate child devices\n");
/* Everything is set up - make it run! */
arm_smccc_smc(MTK_SIP_DVFSRC_VCOREFS_CONTROL, MTK_SIP_DVFSRC_START,
0, 0, 0, 0, 0, 0, &ares);
if (ares.a0 & BIT(0))
return dev_err_probe(&pdev->dev, -EINVAL, "Cannot start DVFSRC: %lu\n", ares.a0);
return 0;
}
static const u32 dvfsrc_bw_min_constr_none[DVFSRC_BW_MAX] = {
[DVFSRC_BW_AVG] = 0,
[DVFSRC_BW_PEAK] = 0,
[DVFSRC_BW_HRT] = 0,
};
static const u32 dvfsrc_bw_max_constr_v1[DVFSRC_BW_MAX] = {
[DVFSRC_BW_AVG] = U32_MAX,
[DVFSRC_BW_PEAK] = U32_MAX,
[DVFSRC_BW_HRT] = U32_MAX,
};
static const u32 dvfsrc_bw_max_constr_v2[DVFSRC_BW_MAX] = {
[DVFSRC_BW_AVG] = 65535,
[DVFSRC_BW_PEAK] = 65535,
[DVFSRC_BW_HRT] = 1023,
};
static const struct dvfsrc_opp dvfsrc_opp_mt6893_lp4[] = {
{ 0, 0 }, { 1, 0 }, { 2, 0 }, { 3, 0 },
{ 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 },
{ 0, 2 }, { 1, 2 }, { 2, 2 }, { 3, 2 },
{ 0, 3 }, { 1, 3 }, { 2, 3 }, { 3, 3 },
{ 1, 4 }, { 2, 4 }, { 3, 4 }, { 2, 5 },
{ 3, 5 }, { 3, 6 }, { 4, 6 }, { 4, 7 },
};
static const struct dvfsrc_opp_desc dvfsrc_opp_mt6893_desc[] = {
[0] = {
.opps = dvfsrc_opp_mt6893_lp4,
.num_opp = ARRAY_SIZE(dvfsrc_opp_mt6893_lp4),
}
};
static const struct dvfsrc_soc_data mt6893_data = {
.opps_desc = dvfsrc_opp_mt6893_desc,
.regs = dvfsrc_mt8195_regs,
.get_target_level = dvfsrc_get_target_level_v2,
.get_current_level = dvfsrc_get_current_level_v2,
.get_vcore_level = dvfsrc_get_vcore_level_v2,
.get_vscp_level = dvfsrc_get_vscp_level_v2,
.set_dram_bw = dvfsrc_set_dram_bw_v1,
.set_dram_peak_bw = dvfsrc_set_dram_peak_bw_v1,
.set_dram_hrt_bw = dvfsrc_set_dram_hrt_bw_v1,
.set_vcore_level = dvfsrc_set_vcore_level_v2,
.set_vscp_level = dvfsrc_set_vscp_level_v2,
.wait_for_opp_level = dvfsrc_wait_for_opp_level_v2,
.wait_for_vcore_level = dvfsrc_wait_for_vcore_level_v1,
.bw_max_constraints = dvfsrc_bw_max_constr_v2,
.bw_min_constraints = dvfsrc_bw_min_constr_none,
};
static const struct dvfsrc_opp dvfsrc_opp_mt8183_lp4[] = {
{ 0, 0 }, { 0, 1 }, { 0, 2 }, { 1, 2 },
};
static const struct dvfsrc_opp dvfsrc_opp_mt8183_lp3[] = {
{ 0, 0 }, { 0, 1 }, { 1, 1 }, { 1, 2 },
};
static const struct dvfsrc_opp_desc dvfsrc_opp_mt8183_desc[] = {
[0] = {
.opps = dvfsrc_opp_mt8183_lp4,
.num_opp = ARRAY_SIZE(dvfsrc_opp_mt8183_lp4),
},
[1] = {
.opps = dvfsrc_opp_mt8183_lp3,
.num_opp = ARRAY_SIZE(dvfsrc_opp_mt8183_lp3),
},
[2] = {
.opps = dvfsrc_opp_mt8183_lp3,
.num_opp = ARRAY_SIZE(dvfsrc_opp_mt8183_lp3),
}
};
static const struct dvfsrc_soc_data mt8183_data = {
.opps_desc = dvfsrc_opp_mt8183_desc,
.regs = dvfsrc_mt8183_regs,
.calc_dram_bw = dvfsrc_calc_dram_bw_v1,
.get_target_level = dvfsrc_get_target_level_v1,
.get_current_level = dvfsrc_get_current_level_v1,
.get_vcore_level = dvfsrc_get_vcore_level_v1,
.set_dram_bw = dvfsrc_set_dram_bw_v1,
.set_opp_level = dvfsrc_set_opp_level_v1,
.set_vcore_level = dvfsrc_set_vcore_level_v1,
.wait_for_opp_level = dvfsrc_wait_for_opp_level_v1,
.wait_for_vcore_level = dvfsrc_wait_for_vcore_level_v1,
.bw_max_constraints = dvfsrc_bw_max_constr_v1,
.bw_min_constraints = dvfsrc_bw_min_constr_none,
};
static const struct dvfsrc_opp dvfsrc_opp_mt8195_lp4[] = {
{ 0, 0 }, { 1, 0 }, { 2, 0 }, { 3, 0 },
{ 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 },
{ 0, 2 }, { 1, 2 }, { 2, 2 }, { 3, 2 },
{ 1, 3 }, { 2, 3 }, { 3, 3 }, { 1, 4 },
{ 2, 4 }, { 3, 4 }, { 2, 5 }, { 3, 5 },
{ 3, 6 },
};
static const struct dvfsrc_opp_desc dvfsrc_opp_mt8195_desc[] = {
[0] = {
.opps = dvfsrc_opp_mt8195_lp4,
.num_opp = ARRAY_SIZE(dvfsrc_opp_mt8195_lp4),
}
};
static const struct dvfsrc_soc_data mt8195_data = {
.opps_desc = dvfsrc_opp_mt8195_desc,
.regs = dvfsrc_mt8195_regs,
.calc_dram_bw = dvfsrc_calc_dram_bw_v1,
.get_target_level = dvfsrc_get_target_level_v2,
.get_current_level = dvfsrc_get_current_level_v2,
.get_vcore_level = dvfsrc_get_vcore_level_v2,
.get_vscp_level = dvfsrc_get_vscp_level_v2,
.set_dram_bw = dvfsrc_set_dram_bw_v1,
.set_dram_peak_bw = dvfsrc_set_dram_peak_bw_v1,
.set_dram_hrt_bw = dvfsrc_set_dram_hrt_bw_v1,
.set_vcore_level = dvfsrc_set_vcore_level_v2,
.set_vscp_level = dvfsrc_set_vscp_level_v2,
.wait_for_opp_level = dvfsrc_wait_for_opp_level_v2,
.wait_for_vcore_level = dvfsrc_wait_for_vcore_level_v1,
.bw_max_constraints = dvfsrc_bw_max_constr_v2,
.bw_min_constraints = dvfsrc_bw_min_constr_none,
};
static const u8 mt8196_bw_units[] = {
[DVFSRC_BW_AVG] = 64,
[DVFSRC_BW_PEAK] = 64,
[DVFSRC_BW_HRT] = 30,
};
static const struct dvfsrc_soc_data mt8196_data = {
.regs = dvfsrc_mt8196_regs,
.bw_units = mt8196_bw_units,
.has_emi_ddr = true,
.get_target_level = dvfsrc_get_target_level_v4,
.get_current_level = dvfsrc_get_current_level_v4,
.get_vcore_level = dvfsrc_get_vcore_level_v2,
.get_vscp_level = dvfsrc_get_vscp_level_v2,
.get_opp_count = dvfsrc_get_opp_count_v4,
.get_hw_opps = dvfsrc_get_hw_opps_v4,
.calc_dram_bw = dvfsrc_calc_dram_bw_v4,
.set_dram_bw = dvfsrc_set_dram_bw_v1,
.set_dram_peak_bw = dvfsrc_set_dram_peak_bw_v1,
.set_dram_hrt_bw = dvfsrc_set_dram_hrt_bw_v1,
.set_opp_level = dvfsrc_set_dram_level_v4,
.set_vcore_level = dvfsrc_set_vcore_level_v2,
.set_vscp_level = dvfsrc_set_vscp_level_v2,
.wait_for_opp_level = dvfsrc_wait_for_opp_level_v4,
.wait_for_vcore_level = dvfsrc_wait_for_vcore_level_v4,
.bw_max_constraints = dvfsrc_bw_max_constr_v2,
.bw_min_constraints = dvfsrc_bw_min_constr_none,
};
static const struct of_device_id mtk_dvfsrc_of_match[] = {
{ .compatible = "mediatek,mt6893-dvfsrc", .data = &mt6893_data },
{ .compatible = "mediatek,mt8183-dvfsrc", .data = &mt8183_data },
{ .compatible = "mediatek,mt8195-dvfsrc", .data = &mt8195_data },
{ .compatible = "mediatek,mt8196-dvfsrc", .data = &mt8196_data },
{ /* sentinel */ }
};
static struct platform_driver mtk_dvfsrc_driver = {
.probe = mtk_dvfsrc_probe,
.driver = {
.name = "mtk-dvfsrc",
.of_match_table = mtk_dvfsrc_of_match,
},
};
module_platform_driver(mtk_dvfsrc_driver);
MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
MODULE_AUTHOR("Dawei Chien <dawei.chien@mediatek.com>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("MediaTek DVFSRC driver");
@@ -0,0 +1,93 @@
// 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/mfd/syscon.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))
/**
* 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;
}
static int __init mtk_infracfg_init(void)
{
struct regmap *infracfg;
/*
* MT8192 has an experimental path to route GPU traffic to the DSU's
* Accelerator Coherency Port, which is inadvertently enabled by
* default. It turns out not to work, so disable it to prevent spurious
* GPU faults.
*/
infracfg = syscon_regmap_lookup_by_compatible("mediatek,mt8192-infracfg");
if (!IS_ERR(infracfg))
regmap_set_bits(infracfg, MT8192_INFRA_CTRL,
MT8192_INFRA_CTRL_DISABLE_MFG2ACP);
return 0;
}
postcore_initcall(mtk_infracfg_init);
@@ -0,0 +1,498 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014 MediaTek Inc.
* Author: James Liao <jamesjj.liao@mediatek.com>
*/
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/soc/mediatek/mtk-mmsys.h>
#include "mtk-mmsys.h"
#include "mt8167-mmsys.h"
#include "mt8173-mmsys.h"
#include "mt8183-mmsys.h"
#include "mt8186-mmsys.h"
#include "mt8188-mmsys.h"
#include "mt8192-mmsys.h"
#include "mt8195-mmsys.h"
#include "mt8365-mmsys.h"
#define MMSYS_SW_RESET_PER_REG 32
static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = {
.clk_driver = "clk-mt2701-mm",
.routes = mmsys_default_routing_table,
.num_routes = ARRAY_SIZE(mmsys_default_routing_table),
};
static const struct mtk_mmsys_driver_data mt2712_mmsys_driver_data = {
.clk_driver = "clk-mt2712-mm",
.routes = mmsys_default_routing_table,
.num_routes = ARRAY_SIZE(mmsys_default_routing_table),
};
static const struct mtk_mmsys_driver_data mt6779_mmsys_driver_data = {
.clk_driver = "clk-mt6779-mm",
};
static const struct mtk_mmsys_driver_data mt6795_mmsys_driver_data = {
.clk_driver = "clk-mt6795-mm",
.routes = mt8173_mmsys_routing_table,
.num_routes = ARRAY_SIZE(mt8173_mmsys_routing_table),
.sw0_rst_offset = MT8183_MMSYS_SW0_RST_B,
.num_resets = 64,
};
static const struct mtk_mmsys_driver_data mt6797_mmsys_driver_data = {
.clk_driver = "clk-mt6797-mm",
};
static const struct mtk_mmsys_driver_data mt8167_mmsys_driver_data = {
.clk_driver = "clk-mt8167-mm",
.routes = mt8167_mmsys_routing_table,
.num_routes = ARRAY_SIZE(mt8167_mmsys_routing_table),
};
static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = {
.clk_driver = "clk-mt8173-mm",
.routes = mt8173_mmsys_routing_table,
.num_routes = ARRAY_SIZE(mt8173_mmsys_routing_table),
.sw0_rst_offset = MT8183_MMSYS_SW0_RST_B,
.num_resets = 64,
};
static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = {
.clk_driver = "clk-mt8183-mm",
.routes = mmsys_mt8183_routing_table,
.num_routes = ARRAY_SIZE(mmsys_mt8183_routing_table),
.sw0_rst_offset = MT8183_MMSYS_SW0_RST_B,
.num_resets = 32,
};
static const struct mtk_mmsys_driver_data mt8186_mmsys_driver_data = {
.clk_driver = "clk-mt8186-mm",
.routes = mmsys_mt8186_routing_table,
.num_routes = ARRAY_SIZE(mmsys_mt8186_routing_table),
.sw0_rst_offset = MT8186_MMSYS_SW0_RST_B,
.num_resets = 32,
};
static const struct mtk_mmsys_driver_data mt8188_vdosys0_driver_data = {
.clk_driver = "clk-mt8188-vdo0",
.routes = mmsys_mt8188_routing_table,
.num_routes = ARRAY_SIZE(mmsys_mt8188_routing_table),
.sw0_rst_offset = MT8188_VDO0_SW0_RST_B,
.rst_tb = mmsys_mt8188_vdo0_rst_tb,
.num_resets = ARRAY_SIZE(mmsys_mt8188_vdo0_rst_tb),
};
static const struct mtk_mmsys_driver_data mt8188_vdosys1_driver_data = {
.clk_driver = "clk-mt8188-vdo1",
.routes = mmsys_mt8188_vdo1_routing_table,
.num_routes = ARRAY_SIZE(mmsys_mt8188_vdo1_routing_table),
.sw0_rst_offset = MT8188_VDO1_SW0_RST_B,
.rst_tb = mmsys_mt8188_vdo1_rst_tb,
.num_resets = ARRAY_SIZE(mmsys_mt8188_vdo1_rst_tb),
.vsync_len = 1,
};
static const struct mtk_mmsys_driver_data mt8188_vppsys0_driver_data = {
.clk_driver = "clk-mt8188-vpp0",
.is_vppsys = true,
};
static const struct mtk_mmsys_driver_data mt8188_vppsys1_driver_data = {
.clk_driver = "clk-mt8188-vpp1",
.is_vppsys = true,
};
static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = {
.clk_driver = "clk-mt8192-mm",
.routes = mmsys_mt8192_routing_table,
.num_routes = ARRAY_SIZE(mmsys_mt8192_routing_table),
.sw0_rst_offset = MT8186_MMSYS_SW0_RST_B,
.num_resets = 32,
};
static const struct mtk_mmsys_driver_data mt8195_vdosys0_driver_data = {
.clk_driver = "clk-mt8195-vdo0",
.routes = mmsys_mt8195_routing_table,
.num_routes = ARRAY_SIZE(mmsys_mt8195_routing_table),
};
static const struct mtk_mmsys_driver_data mt8195_vdosys1_driver_data = {
.clk_driver = "clk-mt8195-vdo1",
.routes = mmsys_mt8195_vdo1_routing_table,
.num_routes = ARRAY_SIZE(mmsys_mt8195_vdo1_routing_table),
.sw0_rst_offset = MT8195_VDO1_SW0_RST_B,
.num_resets = 64,
};
static const struct mtk_mmsys_driver_data mt8195_vppsys0_driver_data = {
.clk_driver = "clk-mt8195-vpp0",
.is_vppsys = true,
};
static const struct mtk_mmsys_driver_data mt8195_vppsys1_driver_data = {
.clk_driver = "clk-mt8195-vpp1",
.is_vppsys = true,
};
static const struct mtk_mmsys_driver_data mt8365_mmsys_driver_data = {
.clk_driver = "clk-mt8365-mm",
.routes = mt8365_mmsys_routing_table,
.num_routes = ARRAY_SIZE(mt8365_mmsys_routing_table),
};
struct mtk_mmsys {
void __iomem *regs;
const struct mtk_mmsys_driver_data *data;
struct platform_device *clks_pdev;
struct platform_device *drm_pdev;
spinlock_t lock; /* protects mmsys_sw_rst_b reg */
struct reset_controller_dev rcdev;
struct cmdq_client_reg cmdq_base;
};
static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32 offset, u32 mask, u32 val,
struct cmdq_pkt *cmdq_pkt)
{
int ret;
u32 tmp;
if (mmsys->cmdq_base.size && cmdq_pkt) {
ret = mmsys->cmdq_base.pkt_write_mask(cmdq_pkt,
mmsys->cmdq_base.subsys,
mmsys->cmdq_base.pa_base,
mmsys->cmdq_base.offset + offset,
val, mask);
if (ret)
pr_debug("CMDQ unavailable: using CPU write\n");
else
return;
}
tmp = readl_relaxed(mmsys->regs + offset);
tmp = (tmp & ~mask) | (val & mask);
writel_relaxed(tmp, mmsys->regs + offset);
}
void mtk_mmsys_ddp_connect(struct device *dev,
enum mtk_ddp_comp_id cur,
enum mtk_ddp_comp_id next)
{
struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
const struct mtk_mmsys_routes *routes = mmsys->data->routes;
int i;
for (i = 0; i < mmsys->data->num_routes; i++)
if (cur == routes[i].from_comp && next == routes[i].to_comp)
mtk_mmsys_update_bits(mmsys, routes[i].addr, routes[i].mask,
routes[i].val, NULL);
if (mmsys->data->vsync_len)
mtk_mmsys_update_bits(mmsys, MT8188_VDO1_MIXER_VSYNC_LEN, GENMASK(31, 0),
mmsys->data->vsync_len, NULL);
}
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)
{
struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
const struct mtk_mmsys_routes *routes = mmsys->data->routes;
int i;
for (i = 0; i < mmsys->data->num_routes; i++)
if (cur == routes[i].from_comp && next == routes[i].to_comp)
mtk_mmsys_update_bits(mmsys, routes[i].addr, routes[i].mask, 0, NULL);
}
EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_disconnect);
void mtk_mmsys_merge_async_config(struct device *dev, int idx, int width, int height,
struct cmdq_pkt *cmdq_pkt)
{
mtk_mmsys_update_bits(dev_get_drvdata(dev), MT8195_VDO1_MERGE0_ASYNC_CFG_WD + 0x10 * idx,
~0, height << 16 | width, cmdq_pkt);
}
EXPORT_SYMBOL_GPL(mtk_mmsys_merge_async_config);
void mtk_mmsys_hdr_config(struct device *dev, int be_width, int be_height,
struct cmdq_pkt *cmdq_pkt)
{
mtk_mmsys_update_bits(dev_get_drvdata(dev), MT8195_VDO1_HDRBE_ASYNC_CFG_WD, ~0,
be_height << 16 | be_width, cmdq_pkt);
}
EXPORT_SYMBOL_GPL(mtk_mmsys_hdr_config);
void mtk_mmsys_mixer_in_config(struct device *dev, int idx, bool alpha_sel, u16 alpha,
u8 mode, u32 biwidth, struct cmdq_pkt *cmdq_pkt)
{
struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
mtk_mmsys_update_bits(mmsys, MT8195_VDO1_MIXER_IN1_ALPHA + (idx - 1) * 4, ~0,
alpha << 16 | alpha, cmdq_pkt);
mtk_mmsys_update_bits(mmsys, MT8195_VDO1_HDR_TOP_CFG, BIT(15 + idx), 0, cmdq_pkt);
mtk_mmsys_update_bits(mmsys, MT8195_VDO1_HDR_TOP_CFG, BIT(19 + idx),
alpha_sel << (19 + idx), cmdq_pkt);
mtk_mmsys_update_bits(mmsys, MT8195_VDO1_MIXER_IN1_PAD + (idx - 1) * 4,
GENMASK(31, 16) | GENMASK(1, 0), biwidth << 16 | mode, cmdq_pkt);
}
EXPORT_SYMBOL_GPL(mtk_mmsys_mixer_in_config);
void mtk_mmsys_mixer_in_channel_swap(struct device *dev, int idx, bool channel_swap,
struct cmdq_pkt *cmdq_pkt)
{
mtk_mmsys_update_bits(dev_get_drvdata(dev), MT8195_VDO1_MIXER_IN1_PAD + (idx - 1) * 4,
BIT(4), channel_swap << 4, cmdq_pkt);
}
EXPORT_SYMBOL_GPL(mtk_mmsys_mixer_in_channel_swap);
void mtk_mmsys_ddp_dpi_fmt_config(struct device *dev, u32 val)
{
struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
switch (val) {
case MTK_DPI_RGB888_SDR_CON:
mtk_mmsys_update_bits(mmsys, MT8186_MMSYS_DPI_OUTPUT_FORMAT,
MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB888_SDR_CON, NULL);
break;
case MTK_DPI_RGB565_SDR_CON:
mtk_mmsys_update_bits(mmsys, MT8186_MMSYS_DPI_OUTPUT_FORMAT,
MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB565_SDR_CON, NULL);
break;
case MTK_DPI_RGB565_DDR_CON:
mtk_mmsys_update_bits(mmsys, MT8186_MMSYS_DPI_OUTPUT_FORMAT,
MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB565_DDR_CON, NULL);
break;
case MTK_DPI_RGB888_DDR_CON:
default:
mtk_mmsys_update_bits(mmsys, MT8186_MMSYS_DPI_OUTPUT_FORMAT,
MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB888_DDR_CON, NULL);
break;
}
}
EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_dpi_fmt_config);
void mtk_mmsys_vpp_rsz_merge_config(struct device *dev, u32 id, bool enable,
struct cmdq_pkt *cmdq_pkt)
{
u32 reg;
switch (id) {
case 2:
reg = MT8195_SVPP2_BUF_BF_RSZ_SWITCH;
break;
case 3:
reg = MT8195_SVPP3_BUF_BF_RSZ_SWITCH;
break;
default:
dev_err(dev, "Invalid id %d\n", id);
return;
}
mtk_mmsys_update_bits(dev_get_drvdata(dev), reg, ~0, enable, cmdq_pkt);
}
EXPORT_SYMBOL_GPL(mtk_mmsys_vpp_rsz_merge_config);
void mtk_mmsys_vpp_rsz_dcm_config(struct device *dev, bool enable,
struct cmdq_pkt *cmdq_pkt)
{
u32 client;
client = MT8195_SVPP1_MDP_RSZ;
mtk_mmsys_update_bits(dev_get_drvdata(dev),
MT8195_VPP1_HW_DCM_1ST_DIS0, client,
((enable) ? client : 0), cmdq_pkt);
mtk_mmsys_update_bits(dev_get_drvdata(dev),
MT8195_VPP1_HW_DCM_2ND_DIS0, client,
((enable) ? client : 0), cmdq_pkt);
client = MT8195_SVPP2_MDP_RSZ | MT8195_SVPP3_MDP_RSZ;
mtk_mmsys_update_bits(dev_get_drvdata(dev),
MT8195_VPP1_HW_DCM_1ST_DIS1, client,
((enable) ? client : 0), cmdq_pkt);
mtk_mmsys_update_bits(dev_get_drvdata(dev),
MT8195_VPP1_HW_DCM_2ND_DIS1, client,
((enable) ? client : 0), cmdq_pkt);
}
EXPORT_SYMBOL_GPL(mtk_mmsys_vpp_rsz_dcm_config);
static int mtk_mmsys_reset_update(struct reset_controller_dev *rcdev, unsigned long id,
bool assert)
{
struct mtk_mmsys *mmsys = container_of(rcdev, struct mtk_mmsys, rcdev);
unsigned long flags;
u32 offset;
u32 reg;
if (mmsys->data->rst_tb) {
if (id >= mmsys->data->num_resets) {
dev_err(rcdev->dev, "Invalid reset ID: %lu (>=%u)\n",
id, mmsys->data->num_resets);
return -EINVAL;
}
id = mmsys->data->rst_tb[id];
}
offset = (id / MMSYS_SW_RESET_PER_REG) * sizeof(u32);
id = id % MMSYS_SW_RESET_PER_REG;
reg = mmsys->data->sw0_rst_offset + offset;
spin_lock_irqsave(&mmsys->lock, flags);
if (assert)
mtk_mmsys_update_bits(mmsys, reg, BIT(id), 0, NULL);
else
mtk_mmsys_update_bits(mmsys, reg, BIT(id), BIT(id), NULL);
spin_unlock_irqrestore(&mmsys->lock, flags);
return 0;
}
static int mtk_mmsys_reset_assert(struct reset_controller_dev *rcdev, unsigned long id)
{
return mtk_mmsys_reset_update(rcdev, id, true);
}
static int mtk_mmsys_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
{
return mtk_mmsys_reset_update(rcdev, id, false);
}
static int mtk_mmsys_reset(struct reset_controller_dev *rcdev, unsigned long id)
{
int ret;
ret = mtk_mmsys_reset_assert(rcdev, id);
if (ret)
return ret;
usleep_range(1000, 1100);
return mtk_mmsys_reset_deassert(rcdev, id);
}
static const struct reset_control_ops mtk_mmsys_reset_ops = {
.assert = mtk_mmsys_reset_assert,
.deassert = mtk_mmsys_reset_deassert,
.reset = mtk_mmsys_reset,
};
static int mtk_mmsys_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct platform_device *clks;
struct platform_device *drm;
struct mtk_mmsys *mmsys;
int ret;
mmsys = devm_kzalloc(dev, sizeof(*mmsys), GFP_KERNEL);
if (!mmsys)
return -ENOMEM;
mmsys->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(mmsys->regs)) {
ret = PTR_ERR(mmsys->regs);
dev_err(dev, "Failed to ioremap mmsys registers: %d\n", ret);
return ret;
}
mmsys->data = of_device_get_match_data(&pdev->dev);
if (mmsys->data->num_resets > 0) {
spin_lock_init(&mmsys->lock);
mmsys->rcdev.owner = THIS_MODULE;
mmsys->rcdev.nr_resets = mmsys->data->num_resets;
mmsys->rcdev.ops = &mtk_mmsys_reset_ops;
mmsys->rcdev.of_node = pdev->dev.of_node;
ret = devm_reset_controller_register(&pdev->dev, &mmsys->rcdev);
if (ret) {
dev_err(&pdev->dev, "Couldn't register mmsys reset controller: %d\n", ret);
return ret;
}
}
/* CMDQ is optional */
ret = cmdq_dev_get_client_reg(dev, &mmsys->cmdq_base, 0);
if (ret)
dev_dbg(dev, "No mediatek,gce-client-reg!\n");
platform_set_drvdata(pdev, mmsys);
clks = platform_device_register_data(&pdev->dev, mmsys->data->clk_driver,
PLATFORM_DEVID_AUTO, NULL, 0);
if (IS_ERR(clks))
return PTR_ERR(clks);
mmsys->clks_pdev = clks;
if (mmsys->data->is_vppsys)
goto out_probe_done;
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);
}
mmsys->drm_pdev = drm;
out_probe_done:
return 0;
}
static void mtk_mmsys_remove(struct platform_device *pdev)
{
struct mtk_mmsys *mmsys = platform_get_drvdata(pdev);
platform_device_unregister(mmsys->drm_pdev);
platform_device_unregister(mmsys->clks_pdev);
}
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,mt6795-mmsys", .data = &mt6795_mmsys_driver_data },
{ .compatible = "mediatek,mt6797-mmsys", .data = &mt6797_mmsys_driver_data },
{ .compatible = "mediatek,mt8167-mmsys", .data = &mt8167_mmsys_driver_data },
{ .compatible = "mediatek,mt8173-mmsys", .data = &mt8173_mmsys_driver_data },
{ .compatible = "mediatek,mt8183-mmsys", .data = &mt8183_mmsys_driver_data },
{ .compatible = "mediatek,mt8186-mmsys", .data = &mt8186_mmsys_driver_data },
{ .compatible = "mediatek,mt8188-vdosys0", .data = &mt8188_vdosys0_driver_data },
{ .compatible = "mediatek,mt8188-vdosys1", .data = &mt8188_vdosys1_driver_data },
{ .compatible = "mediatek,mt8188-vppsys0", .data = &mt8188_vppsys0_driver_data },
{ .compatible = "mediatek,mt8188-vppsys1", .data = &mt8188_vppsys1_driver_data },
{ .compatible = "mediatek,mt8192-mmsys", .data = &mt8192_mmsys_driver_data },
/* "mediatek,mt8195-mmsys" compatible is deprecated */
{ .compatible = "mediatek,mt8195-mmsys", .data = &mt8195_vdosys0_driver_data },
{ .compatible = "mediatek,mt8195-vdosys0", .data = &mt8195_vdosys0_driver_data },
{ .compatible = "mediatek,mt8195-vdosys1", .data = &mt8195_vdosys1_driver_data },
{ .compatible = "mediatek,mt8195-vppsys0", .data = &mt8195_vppsys0_driver_data },
{ .compatible = "mediatek,mt8195-vppsys1", .data = &mt8195_vppsys1_driver_data },
{ .compatible = "mediatek,mt8365-mmsys", .data = &mt8365_mmsys_driver_data },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_match_mtk_mmsys);
static struct platform_driver mtk_mmsys_drv = {
.driver = {
.name = "mtk-mmsys",
.of_match_table = of_match_mtk_mmsys,
},
.probe = mtk_mmsys_probe,
.remove = mtk_mmsys_remove,
};
module_platform_driver(mtk_mmsys_drv);
MODULE_AUTHOR("Yongqiang Niu <yongqiang.niu@mediatek.com>");
MODULE_DESCRIPTION("MediaTek SoC MMSYS driver");
MODULE_LICENSE("GPL");
@@ -0,0 +1,321 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __SOC_MEDIATEK_MTK_MMSYS_H
#define __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 RDMA0_SOUT_MASK 0x7
#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 RDMA1_SOUT_MASK 0x7
#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 RDMA2_SOUT_MASK 0x7
#define DPI0_SEL_IN_RDMA1 0x1
#define DPI0_SEL_IN_RDMA2 0x3
#define DPI0_SEL_IN_MASK 0x3
#define DPI1_SEL_IN_RDMA1 (0x1 << 8)
#define DPI1_SEL_IN_RDMA2 (0x3 << 8)
#define DPI1_SEL_IN_MASK (0x3 << 8)
#define DSI0_SEL_IN_RDMA1 0x1
#define DSI0_SEL_IN_RDMA2 0x4
#define DSI0_SEL_IN_MASK 0x7
#define DSI1_SEL_IN_RDMA1 0x1
#define DSI1_SEL_IN_RDMA2 0x4
#define DSI1_SEL_IN_MASK 0x7
#define DSI2_SEL_IN_RDMA1 (0x1 << 16)
#define DSI2_SEL_IN_RDMA2 (0x4 << 16)
#define DSI2_SEL_IN_MASK (0x7 << 16)
#define DSI3_SEL_IN_RDMA1 (0x1 << 16)
#define DSI3_SEL_IN_RDMA2 (0x4 << 16)
#define DSI3_SEL_IN_MASK (0x7 << 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 BLS_RDMA1_DSI_DPI_MASK 0xf
#define DSI_SEL_IN_BLS 0x0
#define DPI_SEL_IN_BLS 0x0
#define DPI_SEL_IN_MASK 0x1
#define DSI_SEL_IN_RDMA 0x1
#define DSI_SEL_IN_MASK 0x1
#define MMSYS_RST_NR(bank, bit) (((bank) * 32) + (bit))
/*
* This macro adds a compile time check to make sure that the in/out
* selection bit(s) fit in the register mask, similar to bitfield
* macros, but this does not transform the value.
*/
#define MMSYS_ROUTE(from, to, reg_addr, reg_mask, selection) \
{ DDP_COMPONENT_##from, DDP_COMPONENT_##to, reg_addr, reg_mask, \
(__BUILD_BUG_ON_ZERO_MSG((reg_mask) == 0, "Invalid mask") + \
__BUILD_BUG_ON_ZERO_MSG(~(reg_mask) & (selection), \
#selection " does not fit in " \
#reg_mask) + \
(selection)) \
}
struct mtk_mmsys_routes {
u32 from_comp;
u32 to_comp;
u32 addr;
u32 mask;
u32 val;
};
/**
* struct mtk_mmsys_driver_data - Settings of the mmsys
* @clk_driver: Clock driver name that the mmsys is using
* (defined in drivers/clk/mediatek/clk-*.c).
* @routes: Routing table of the mmsys.
* It provides mux settings from one module to another.
* @num_routes: Array size of the routes.
* @sw0_rst_offset: Register offset for the reset control.
* @num_resets: Number of reset bits that are defined
* @is_vppsys: Whether the mmsys is VPPSYS (Video Processing Pipe)
* or VDOSYS (Video). Only VDOSYS needs to be added to drm driver.
* @vsync_len: VSYNC length of the MIXER.
* VSYNC is usually triggered by the connector, so its length is a
* fixed value when the frame rate is decided, but ETHDR and
* MIXER generate their own VSYNC due to hardware design, therefore
* MIXER has to sync with ETHDR by adjusting VSYNC length.
* On MT8195, there is no such setting so we use the gap between
* falling edge and rising edge of SOF (Start of Frame) signal to
* do the job, but since MT8188, VSYNC_LEN setting is introduced to
* solve the problem and is given 0x40 (ticks) as the default value.
* Please notice that this value has to be set to 1 (minimum) if
* ETHDR is bypassed, otherwise MIXER could wait too long and causing
* underflow.
*
* Each MMSYS (multi-media system) may have different settings, they may use
* different clock sources, mux settings, reset control ...etc., and these
* differences are all stored here.
*/
struct mtk_mmsys_driver_data {
const char *clk_driver;
const struct mtk_mmsys_routes *routes;
const unsigned int num_routes;
const u16 sw0_rst_offset;
const u8 *rst_tb;
const u32 num_resets;
const bool is_vppsys;
const u8 vsync_len;
};
/*
* Routes in mt2701 and mt2712 are different. That means
* in the same register address, it controls different input/output
* selection for each SoC. But, right now, they use the same table as
* default routes meet their requirements. But we don't have the complete
* route information for these three SoC, so just keep them in the same
* table. After we've more information, we could separate mt2701, mt2712
* to an independent table.
*/
static const struct mtk_mmsys_routes mmsys_default_routing_table[] = {
{
DDP_COMPONENT_BLS, DDP_COMPONENT_DSI0,
DISP_REG_CONFIG_OUT_SEL, BLS_RDMA1_DSI_DPI_MASK,
BLS_TO_DSI_RDMA1_TO_DPI1
}, {
DDP_COMPONENT_BLS, DDP_COMPONENT_DSI0,
DISP_REG_CONFIG_DSI_SEL, DSI_SEL_IN_MASK,
DSI_SEL_IN_BLS
}, {
DDP_COMPONENT_BLS, DDP_COMPONENT_DPI0,
DISP_REG_CONFIG_OUT_SEL, BLS_RDMA1_DSI_DPI_MASK,
BLS_TO_DPI_RDMA1_TO_DSI
}, {
DDP_COMPONENT_BLS, DDP_COMPONENT_DPI0,
DISP_REG_CONFIG_DSI_SEL, DSI_SEL_IN_MASK,
DSI_SEL_IN_RDMA
}, {
DDP_COMPONENT_BLS, DDP_COMPONENT_DPI0,
DISP_REG_CONFIG_DPI_SEL, DPI_SEL_IN_MASK,
DPI_SEL_IN_BLS
}, {
DDP_COMPONENT_GAMMA, DDP_COMPONENT_RDMA1,
DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN, GAMMA_MOUT_EN_RDMA1,
GAMMA_MOUT_EN_RDMA1
}, {
DDP_COMPONENT_OD0, DDP_COMPONENT_RDMA0,
DISP_REG_CONFIG_DISP_OD_MOUT_EN, OD_MOUT_EN_RDMA0,
OD_MOUT_EN_RDMA0
}, {
DDP_COMPONENT_OD1, DDP_COMPONENT_RDMA1,
DISP_REG_CONFIG_DISP_OD_MOUT_EN, OD1_MOUT_EN_RDMA1,
OD1_MOUT_EN_RDMA1
}, {
DDP_COMPONENT_OVL0, DDP_COMPONENT_COLOR0,
DISP_REG_CONFIG_DISP_OVL0_MOUT_EN, OVL0_MOUT_EN_COLOR0,
OVL0_MOUT_EN_COLOR0
}, {
DDP_COMPONENT_OVL0, DDP_COMPONENT_COLOR0,
DISP_REG_CONFIG_DISP_COLOR0_SEL_IN, COLOR0_SEL_IN_OVL0,
COLOR0_SEL_IN_OVL0
}, {
DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0,
DISP_REG_CONFIG_DISP_OVL_MOUT_EN, OVL_MOUT_EN_RDMA,
OVL_MOUT_EN_RDMA
}, {
DDP_COMPONENT_OVL1, DDP_COMPONENT_COLOR1,
DISP_REG_CONFIG_DISP_OVL1_MOUT_EN, OVL1_MOUT_EN_COLOR1,
OVL1_MOUT_EN_COLOR1
}, {
DDP_COMPONENT_OVL1, DDP_COMPONENT_COLOR1,
DISP_REG_CONFIG_DISP_COLOR1_SEL_IN, COLOR1_SEL_IN_OVL1,
COLOR1_SEL_IN_OVL1
}, {
DDP_COMPONENT_RDMA0, DDP_COMPONENT_DPI0,
DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_MASK,
RDMA0_SOUT_DPI0
}, {
DDP_COMPONENT_RDMA0, DDP_COMPONENT_DPI1,
DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_MASK,
RDMA0_SOUT_DPI1
}, {
DDP_COMPONENT_RDMA0, DDP_COMPONENT_DSI1,
DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_MASK,
RDMA0_SOUT_DSI1
}, {
DDP_COMPONENT_RDMA0, DDP_COMPONENT_DSI2,
DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_MASK,
RDMA0_SOUT_DSI2
}, {
DDP_COMPONENT_RDMA0, DDP_COMPONENT_DSI3,
DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_MASK,
RDMA0_SOUT_DSI3
}, {
DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK,
RDMA1_SOUT_DPI0
}, {
DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
DISP_REG_CONFIG_DPI_SEL_IN, DPI0_SEL_IN_MASK,
DPI0_SEL_IN_RDMA1
}, {
DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI1,
DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK,
RDMA1_SOUT_DPI1
}, {
DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI1,
DISP_REG_CONFIG_DPI_SEL_IN, DPI1_SEL_IN_MASK,
DPI1_SEL_IN_RDMA1
}, {
DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI0,
DISP_REG_CONFIG_DSIE_SEL_IN, DSI0_SEL_IN_MASK,
DSI0_SEL_IN_RDMA1
}, {
DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI1,
DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK,
RDMA1_SOUT_DSI1
}, {
DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI1,
DISP_REG_CONFIG_DSIO_SEL_IN, DSI1_SEL_IN_MASK,
DSI1_SEL_IN_RDMA1
}, {
DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI2,
DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK,
RDMA1_SOUT_DSI2
}, {
DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI2,
DISP_REG_CONFIG_DSIE_SEL_IN, DSI2_SEL_IN_MASK,
DSI2_SEL_IN_RDMA1
}, {
DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI3,
DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK,
RDMA1_SOUT_DSI3
}, {
DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI3,
DISP_REG_CONFIG_DSIO_SEL_IN, DSI3_SEL_IN_MASK,
DSI3_SEL_IN_RDMA1
}, {
DDP_COMPONENT_RDMA2, DDP_COMPONENT_DPI0,
DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_MASK,
RDMA2_SOUT_DPI0
}, {
DDP_COMPONENT_RDMA2, DDP_COMPONENT_DPI0,
DISP_REG_CONFIG_DPI_SEL_IN, DPI0_SEL_IN_MASK,
DPI0_SEL_IN_RDMA2
}, {
DDP_COMPONENT_RDMA2, DDP_COMPONENT_DPI1,
DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_MASK,
RDMA2_SOUT_DPI1
}, {
DDP_COMPONENT_RDMA2, DDP_COMPONENT_DPI1,
DISP_REG_CONFIG_DPI_SEL_IN, DPI1_SEL_IN_MASK,
DPI1_SEL_IN_RDMA2
}, {
DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI0,
DISP_REG_CONFIG_DSIE_SEL_IN, DSI0_SEL_IN_MASK,
DSI0_SEL_IN_RDMA2
}, {
DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI1,
DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_MASK,
RDMA2_SOUT_DSI1
}, {
DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI1,
DISP_REG_CONFIG_DSIO_SEL_IN, DSI1_SEL_IN_MASK,
DSI1_SEL_IN_RDMA2
}, {
DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI2,
DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_MASK,
RDMA2_SOUT_DSI2
}, {
DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI2,
DISP_REG_CONFIG_DSIE_SEL_IN, DSI2_SEL_IN_MASK,
DSI2_SEL_IN_RDMA2
}, {
DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI3,
DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_MASK,
RDMA2_SOUT_DSI3
}, {
DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI3,
DISP_REG_CONFIG_DSIO_SEL_IN, DSI3_SEL_IN_MASK,
DSI3_SEL_IN_RDMA2
}, {
DDP_COMPONENT_UFOE, DDP_COMPONENT_DSI0,
DISP_REG_CONFIG_DISP_UFOE_MOUT_EN, UFOE_MOUT_EN_DSI0,
UFOE_MOUT_EN_DSI0
}
};
#endif /* __SOC_MEDIATEK_MTK_MMSYS_H */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,160 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Voltage regulators coupler for MediaTek SoCs
*
* Copyright (C) 2022 Collabora, Ltd.
* Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/regulator/coupler.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/suspend.h>
#define to_mediatek_coupler(x) container_of(x, struct mediatek_regulator_coupler, coupler)
struct mediatek_regulator_coupler {
struct regulator_coupler coupler;
struct regulator_dev *vsram_rdev;
};
/*
* We currently support only couples of not more than two vregs and
* modify the vsram voltage only when changing voltage of vgpu.
*
* This function is limited to the GPU<->SRAM voltages relationships.
*/
static int mediatek_regulator_balance_voltage(struct regulator_coupler *coupler,
struct regulator_dev *rdev,
suspend_state_t state)
{
struct mediatek_regulator_coupler *mrc = to_mediatek_coupler(coupler);
int max_spread = rdev->constraints->max_spread[0];
int vsram_min_uV = mrc->vsram_rdev->constraints->min_uV;
int vsram_max_uV = mrc->vsram_rdev->constraints->max_uV;
int vsram_target_min_uV, vsram_target_max_uV;
int min_uV = 0;
int max_uV = INT_MAX;
int ret;
/*
* If the target device is on, setting the SRAM voltage directly
* is not supported as it scales through its coupled supply voltage.
*
* An exception is made in case the use_count is zero: this means
* that this is the first time we power up the SRAM regulator, which
* implies that the target device has yet to perform initialization
* and setting a voltage at that time is harmless.
*/
if (rdev == mrc->vsram_rdev) {
if (rdev->use_count == 0)
return regulator_do_balance_voltage(rdev, state, true);
return -EPERM;
}
ret = regulator_check_consumers(rdev, &min_uV, &max_uV, state);
if (ret < 0)
return ret;
if (min_uV == 0) {
ret = regulator_get_voltage_rdev(rdev);
if (ret < 0)
return ret;
min_uV = ret;
}
ret = regulator_check_voltage(rdev, &min_uV, &max_uV);
if (ret < 0)
return ret;
/*
* If we're asked to set a voltage less than VSRAM min_uV, set
* the minimum allowed voltage on VSRAM, as in this case it is
* safe to ignore the max_spread parameter.
*/
vsram_target_min_uV = max(vsram_min_uV, min_uV + max_spread);
vsram_target_max_uV = min(vsram_max_uV, vsram_target_min_uV + max_spread);
/* Make sure we're not out of range */
vsram_target_min_uV = min(vsram_target_min_uV, vsram_max_uV);
pr_debug("Setting voltage %d-%duV on %s (minuV %d)\n",
vsram_target_min_uV, vsram_target_max_uV,
rdev_get_name(mrc->vsram_rdev), min_uV);
ret = regulator_set_voltage_rdev(mrc->vsram_rdev, vsram_target_min_uV,
vsram_target_max_uV, state);
if (ret)
return ret;
/* The sram voltage is now balanced: update the target vreg voltage */
return regulator_do_balance_voltage(rdev, state, true);
}
static int mediatek_regulator_attach(struct regulator_coupler *coupler,
struct regulator_dev *rdev)
{
struct mediatek_regulator_coupler *mrc = to_mediatek_coupler(coupler);
const char *rdev_name = rdev_get_name(rdev);
/*
* If we're getting a coupling of more than two regulators here and
* this means that this is surely not a GPU<->SRAM couple: in that
* case, we may want to use another coupler implementation, if any,
* or the generic one: the regulator core will keep walking through
* the list of couplers when any .attach_regulator() cb returns 1.
*/
if (rdev->coupling_desc.n_coupled > 2)
return 1;
if (strstr(rdev_name, "sram")) {
if (mrc->vsram_rdev)
return -EINVAL;
mrc->vsram_rdev = rdev;
} else if (!strstr(rdev_name, "vgpu") && !strstr(rdev_name, "Vgpu")) {
return 1;
}
return 0;
}
static int mediatek_regulator_detach(struct regulator_coupler *coupler,
struct regulator_dev *rdev)
{
struct mediatek_regulator_coupler *mrc = to_mediatek_coupler(coupler);
if (rdev == mrc->vsram_rdev)
mrc->vsram_rdev = NULL;
return 0;
}
static struct mediatek_regulator_coupler mediatek_coupler = {
.coupler = {
.attach_regulator = mediatek_regulator_attach,
.detach_regulator = mediatek_regulator_detach,
.balance_voltage = mediatek_regulator_balance_voltage,
},
};
static int mediatek_regulator_coupler_init(void)
{
if (!of_machine_is_compatible("mediatek,mt8183") &&
!of_machine_is_compatible("mediatek,mt8186") &&
!of_machine_is_compatible("mediatek,mt8188") &&
!of_machine_is_compatible("mediatek,mt8192"))
return 0;
return regulator_coupler_register(&mediatek_coupler.coupler);
}
arch_initcall(mediatek_regulator_coupler_init);
MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
MODULE_DESCRIPTION("MediaTek Regulator Coupler driver");
MODULE_LICENSE("GPL");
@@ -0,0 +1,213 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023 MediaTek Inc.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
#include <linux/nvmem-consumer.h>
#include <linux/device.h>
#include <linux/device/bus.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/string.h>
#include <linux/sys_soc.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#define MTK_SOCINFO_ENTRY(_soc_name, _segment_name, _marketing_name, _cell_data1, _cell_data2) {\
.soc_name = _soc_name, \
.segment_name = _segment_name, \
.marketing_name = _marketing_name, \
.cell_data = {_cell_data1, _cell_data2} \
}
#define CELL_NOT_USED (0xFFFFFFFF)
#define MAX_CELLS (2)
struct mtk_socinfo {
struct device *dev;
struct name_data *name_data;
struct socinfo_data *socinfo_data;
struct soc_device *soc_dev;
};
struct socinfo_data {
char *soc_name;
char *segment_name;
char *marketing_name;
u32 cell_data[MAX_CELLS];
};
static const char *cell_names[MAX_CELLS] = {"socinfo-data1", "socinfo-data2"};
static struct socinfo_data socinfo_data_table[] = {
MTK_SOCINFO_ENTRY("MT8173", "MT8173V/AC", "MT8173", 0x6CA20004, 0x10000000),
MTK_SOCINFO_ENTRY("MT8183", "MT8183V/AZA", "Kompanio 500", 0x00010043, 0x00000840),
MTK_SOCINFO_ENTRY("MT8183", "MT8183V/AZA", "Kompanio 500", 0x00010043, 0x00000940),
MTK_SOCINFO_ENTRY("MT8186", "MT8186GV/AZA", "Kompanio 520", 0x81861001, CELL_NOT_USED),
MTK_SOCINFO_ENTRY("MT8186T", "MT8186TV/AZA", "Kompanio 528", 0x81862001, CELL_NOT_USED),
MTK_SOCINFO_ENTRY("MT8188", "MT8188GV/AZA", "Kompanio 838", 0x81880000, 0x00000010),
MTK_SOCINFO_ENTRY("MT8188", "MT8188GV/HZA", "Kompanio 838", 0x81880000, 0x00000011),
MTK_SOCINFO_ENTRY("MT8189", "MT8189GV/AZA", "Kompanio 540", 0x81890000, 0x00000020),
MTK_SOCINFO_ENTRY("MT8189", "MT8189HV/AZA", "Kompanio 540", 0x81890000, 0x00000021),
MTK_SOCINFO_ENTRY("MT8192", "MT8192V/AZA", "Kompanio 820", 0x00001100, 0x00040080),
MTK_SOCINFO_ENTRY("MT8192T", "MT8192V/ATZA", "Kompanio 828", 0x00000100, 0x000400C0),
MTK_SOCINFO_ENTRY("MT8195", "MT8195GV/EZA", "Kompanio 1200", 0x81950300, CELL_NOT_USED),
MTK_SOCINFO_ENTRY("MT8195", "MT8195GV/EHZA", "Kompanio 1200", 0x81950304, CELL_NOT_USED),
MTK_SOCINFO_ENTRY("MT8195", "MT8195TV/EZA", "Kompanio 1380", 0x81950400, CELL_NOT_USED),
MTK_SOCINFO_ENTRY("MT8195", "MT8195TV/EHZA", "Kompanio 1380", 0x81950404, CELL_NOT_USED),
MTK_SOCINFO_ENTRY("MT8370", "MT8370AV/AZA", "Genio 510", 0x83700000, 0x00000081),
MTK_SOCINFO_ENTRY("MT8371", "MT8371AV/AZA", "Genio 520", 0x83710000, 0x00000081),
MTK_SOCINFO_ENTRY("MT8390", "MT8390AV/AZA", "Genio 700", 0x83900000, 0x00000080),
MTK_SOCINFO_ENTRY("MT8391", "MT8391AV/AZA", "Genio 720", 0x83910000, 0x00000080),
MTK_SOCINFO_ENTRY("MT8395", "MT8395AV/ZA", "Genio 1200", 0x83950100, CELL_NOT_USED),
MTK_SOCINFO_ENTRY("MT8395", "MT8395AV/ZA", "Genio 1200", 0x83950800, CELL_NOT_USED),
};
static int mtk_socinfo_create_socinfo_node(struct mtk_socinfo *mtk_socinfop)
{
struct soc_device_attribute *attrs;
struct socinfo_data *data = mtk_socinfop->socinfo_data;
static const char *soc_manufacturer = "MediaTek";
attrs = devm_kzalloc(mtk_socinfop->dev, sizeof(*attrs), GFP_KERNEL);
if (!attrs)
return -ENOMEM;
if (data->marketing_name != NULL && data->marketing_name[0] != '\0')
attrs->family = devm_kasprintf(mtk_socinfop->dev, GFP_KERNEL, "MediaTek %s",
data->marketing_name);
else
attrs->family = soc_manufacturer;
attrs->soc_id = data->soc_name;
/*
* The "machine" field will be populated automatically with the model
* name from board DTS (if available).
**/
mtk_socinfop->soc_dev = soc_device_register(attrs);
if (IS_ERR(mtk_socinfop->soc_dev))
return PTR_ERR(mtk_socinfop->soc_dev);
dev_info(mtk_socinfop->dev, "%s (%s) SoC detected.\n", attrs->family, attrs->soc_id);
return 0;
}
static u32 mtk_socinfo_read_cell(struct device *dev, const char *name)
{
struct nvmem_device *nvmemp;
struct device_node *np, *nvmem_node = dev->parent->of_node;
u32 offset;
u32 cell_val = CELL_NOT_USED;
/* should never fail since the nvmem driver registers this child */
nvmemp = nvmem_device_find(nvmem_node, device_match_of_node);
if (IS_ERR(nvmemp))
goto out;
np = of_get_child_by_name(nvmem_node, name);
if (!np)
goto put_device;
if (of_property_read_u32_index(np, "reg", 0, &offset))
goto put_node;
nvmem_device_read(nvmemp, offset, sizeof(cell_val), &cell_val);
put_node:
of_node_put(np);
put_device:
nvmem_device_put(nvmemp);
out:
return cell_val;
}
static int mtk_socinfo_get_socinfo_data(struct mtk_socinfo *mtk_socinfop)
{
unsigned int i, j;
unsigned int num_cell_data = 0;
u32 cell_data[MAX_CELLS] = {0};
bool match_socinfo;
int match_socinfo_index = -1;
for (i = 0; i < MAX_CELLS; i++) {
cell_data[i] = mtk_socinfo_read_cell(mtk_socinfop->dev, cell_names[i]);
if (cell_data[i] != CELL_NOT_USED)
num_cell_data++;
else
break;
}
if (!num_cell_data)
return -ENOENT;
for (i = 0; i < ARRAY_SIZE(socinfo_data_table); i++) {
match_socinfo = true;
for (j = 0; j < num_cell_data; j++) {
if (cell_data[j] != socinfo_data_table[i].cell_data[j]) {
match_socinfo = false;
break;
}
}
if (match_socinfo) {
mtk_socinfop->socinfo_data = &(socinfo_data_table[i]);
match_socinfo_index = i;
break;
}
}
if (match_socinfo_index < 0) {
dev_warn(mtk_socinfop->dev,
"Unknown MediaTek SoC with ID 0x%08x 0x%08x\n",
cell_data[0], cell_data[1]);
return -ENOENT;
}
return match_socinfo_index;
}
static int mtk_socinfo_probe(struct platform_device *pdev)
{
struct mtk_socinfo *mtk_socinfop;
int ret;
mtk_socinfop = devm_kzalloc(&pdev->dev, sizeof(*mtk_socinfop), GFP_KERNEL);
if (!mtk_socinfop)
return -ENOMEM;
mtk_socinfop->dev = &pdev->dev;
ret = mtk_socinfo_get_socinfo_data(mtk_socinfop);
if (ret < 0)
return dev_err_probe(mtk_socinfop->dev, ret, "Failed to get socinfo data\n");
ret = mtk_socinfo_create_socinfo_node(mtk_socinfop);
if (ret)
return dev_err_probe(mtk_socinfop->dev, ret, "Cannot create node\n");
platform_set_drvdata(pdev, mtk_socinfop);
return 0;
}
static void mtk_socinfo_remove(struct platform_device *pdev)
{
struct mtk_socinfo *mtk_socinfop = platform_get_drvdata(pdev);
soc_device_unregister(mtk_socinfop->soc_dev);
}
static struct platform_driver mtk_socinfo = {
.probe = mtk_socinfo_probe,
.remove = mtk_socinfo_remove,
.driver = {
.name = "mtk-socinfo",
},
};
module_platform_driver(mtk_socinfo);
MODULE_AUTHOR("William-TW LIN <william-tw.lin@mediatek.com>");
MODULE_DESCRIPTION("MediaTek socinfo driver");
MODULE_LICENSE("GPL");
File diff suppressed because it is too large Load Diff