summaryrefslogtreecommitdiff
path: root/drivers/soc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/soc')
-rw-r--r--drivers/soc/Kconfig1
-rw-r--r--drivers/soc/Makefile5
-rw-r--r--drivers/soc/amlogic/meson-clk-measure.c1
-rw-r--r--drivers/soc/amlogic/meson-gx-socinfo.c12
-rw-r--r--drivers/soc/aspeed/aspeed-lpc-ctrl.c2
-rw-r--r--drivers/soc/aspeed/aspeed-lpc-snoop.c2
-rw-r--r--drivers/soc/aspeed/aspeed-p2a-ctrl.c2
-rw-r--r--drivers/soc/aspeed/aspeed-uart-routing.c2
-rw-r--r--drivers/soc/atmel/soc.c25
-rw-r--r--drivers/soc/atmel/soc.h9
-rw-r--r--drivers/soc/canaan/Kconfig4
-rw-r--r--drivers/soc/cirrus/Kconfig17
-rw-r--r--drivers/soc/cirrus/Makefile2
-rw-r--r--drivers/soc/cirrus/soc-ep93xx.c252
-rw-r--r--drivers/soc/fsl/Kconfig2
-rw-r--r--drivers/soc/fsl/dpaa2-console.c2
-rw-r--r--drivers/soc/fsl/dpio/dpio-service.c4
-rw-r--r--drivers/soc/fsl/qbman/Kconfig2
-rw-r--r--drivers/soc/fsl/qbman/bman_ccsr.c27
-rw-r--r--drivers/soc/fsl/qbman/dpaa_sys.c12
-rw-r--r--drivers/soc/fsl/qbman/dpaa_sys.h4
-rw-r--r--drivers/soc/fsl/qbman/qman.c30
-rw-r--r--drivers/soc/fsl/qbman/qman_ccsr.c73
-rw-r--r--drivers/soc/fsl/qbman/qman_portal.c5
-rw-r--r--drivers/soc/fsl/qbman/qman_test_stash.c6
-rw-r--r--drivers/soc/fsl/qe/Kconfig17
-rw-r--r--drivers/soc/fsl/qe/qe_common.c80
-rw-r--r--drivers/soc/fsl/qe/qmc.c704
-rw-r--r--drivers/soc/fsl/qe/tsa.c689
-rw-r--r--drivers/soc/fsl/qe/tsa.h3
-rw-r--r--drivers/soc/fsl/qe/ucc.c1
-rw-r--r--drivers/soc/fsl/rcpm.c1
-rw-r--r--drivers/soc/fujitsu/a64fx-diag.c2
-rw-r--r--drivers/soc/hisilicon/Kconfig9
-rw-r--r--drivers/soc/hisilicon/kunpeng_hccs.c522
-rw-r--r--drivers/soc/hisilicon/kunpeng_hccs.h33
-rw-r--r--drivers/soc/imx/Makefile2
-rw-r--r--drivers/soc/imx/soc-imx8m.c201
-rw-r--r--drivers/soc/imx/soc-imx9.c128
-rw-r--r--drivers/soc/ixp4xx/ixp4xx-npe.c3
-rw-r--r--drivers/soc/ixp4xx/ixp4xx-qmgr.c3
-rw-r--r--drivers/soc/litex/Kconfig2
-rw-r--r--drivers/soc/litex/litex_soc_ctrl.c27
-rw-r--r--drivers/soc/loongson/loongson2_guts.c7
-rw-r--r--drivers/soc/mediatek/Kconfig21
-rw-r--r--drivers/soc/mediatek/Makefile2
-rw-r--r--drivers/soc/mediatek/mtk-cmdq-helper.c386
-rw-r--r--drivers/soc/mediatek/mtk-devapc.c21
-rw-r--r--drivers/soc/mediatek/mtk-dvfsrc.c545
-rw-r--r--drivers/soc/mediatek/mtk-mmsys.c3
-rw-r--r--drivers/soc/mediatek/mtk-mutex.c92
-rw-r--r--drivers/soc/mediatek/mtk-pmic-wrap.c120
-rw-r--r--drivers/soc/mediatek/mtk-regulator-coupler.c1
-rw-r--r--drivers/soc/mediatek/mtk-socinfo.c199
-rw-r--r--drivers/soc/mediatek/mtk-svs.c11
-rw-r--r--drivers/soc/microchip/mpfs-sys-controller.c2
-rw-r--r--drivers/soc/pxa/ssp.c4
-rw-r--r--drivers/soc/qcom/Kconfig29
-rw-r--r--drivers/soc/qcom/Makefile5
-rw-r--r--drivers/soc/qcom/apr.c11
-rw-r--r--drivers/soc/qcom/cmd-db.c43
-rw-r--r--drivers/soc/qcom/icc-bwmon.c32
-rw-r--r--drivers/soc/qcom/ice.c20
-rw-r--r--drivers/soc/qcom/llcc-qcom.c3353
-rw-r--r--drivers/soc/qcom/mdt_loader.c6
-rw-r--r--drivers/soc/qcom/ocmem.c19
-rw-r--r--drivers/soc/qcom/pdr_interface.c54
-rw-r--r--drivers/soc/qcom/pdr_internal.h318
-rw-r--r--drivers/soc/qcom/pmic_glink.c135
-rw-r--r--drivers/soc/qcom/pmic_glink_altmode.c30
-rw-r--r--drivers/soc/qcom/pmic_pdcharger_ulog.c4
-rw-r--r--drivers/soc/qcom/pmic_pdcharger_ulog.h2
-rw-r--r--drivers/soc/qcom/qcom-geni-se.c4
-rw-r--r--drivers/soc/qcom/qcom-pbs.c226
-rw-r--r--drivers/soc/qcom/qcom_aoss.c115
-rw-r--r--drivers/soc/qcom/qcom_gsbi.c2
-rw-r--r--drivers/soc/qcom/qcom_pd_mapper.c697
-rw-r--r--drivers/soc/qcom/qcom_pdr_msg.c353
-rw-r--r--drivers/soc/qcom/qcom_stats.c6
-rw-r--r--drivers/soc/qcom/qmi_interface.c2
-rw-r--r--drivers/soc/qcom/ramp_controller.c4
-rw-r--r--drivers/soc/qcom/rmtfs_mem.c4
-rw-r--r--drivers/soc/qcom/rpm-proc.c2
-rw-r--r--drivers/soc/qcom/rpm_master_stats.c6
-rw-r--r--drivers/soc/qcom/rpmh-rsc.c21
-rw-r--r--drivers/soc/qcom/rpmh.c1
-rw-r--r--drivers/soc/qcom/smd-rpm.c41
-rw-r--r--drivers/soc/qcom/smem.c88
-rw-r--r--drivers/soc/qcom/smem_state.c15
-rw-r--r--drivers/soc/qcom/smp2p.c53
-rw-r--r--drivers/soc/qcom/smsm.c57
-rw-r--r--drivers/soc/qcom/socinfo.c45
-rw-r--r--drivers/soc/qcom/spm.c249
-rw-r--r--drivers/soc/qcom/trace-aoss.h48
-rw-r--r--drivers/soc/qcom/trace-rpmh.h4
-rw-r--r--drivers/soc/qcom/trace-smp2p.h98
-rw-r--r--drivers/soc/qcom/trace_icc-bwmon.h48
-rw-r--r--drivers/soc/qcom/wcnss_ctrl.c11
-rw-r--r--drivers/soc/renesas/Kconfig29
-rw-r--r--drivers/soc/renesas/rcar-rst.c1
-rw-r--r--drivers/soc/renesas/renesas-soc.c28
-rw-r--r--drivers/soc/rockchip/grf.c32
-rw-r--r--drivers/soc/rockchip/io-domain.c48
-rw-r--r--drivers/soc/samsung/Kconfig1
-rw-r--r--drivers/soc/samsung/exynos-asv.c10
-rw-r--r--drivers/soc/samsung/exynos-chipid.c7
-rw-r--r--drivers/soc/samsung/exynos-pmu.c241
-rw-r--r--drivers/soc/samsung/exynos-pmu.h1
-rw-r--r--drivers/soc/sunxi/sunxi_sram.c26
-rw-r--r--drivers/soc/tegra/Kconfig5
-rw-r--r--drivers/soc/tegra/cbb/tegra-cbb.c20
-rw-r--r--drivers/soc/tegra/cbb/tegra194-cbb.c2
-rw-r--r--drivers/soc/tegra/cbb/tegra234-cbb.c2
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra.c118
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra30.c40
-rw-r--r--drivers/soc/tegra/fuse/fuse.h8
-rw-r--r--drivers/soc/tegra/fuse/tegra-apbmisc.c108
-rw-r--r--drivers/soc/tegra/pmc.c101
-rw-r--r--drivers/soc/ti/k3-ringacc.c14
-rw-r--r--drivers/soc/ti/k3-socinfo.c2
-rw-r--r--drivers/soc/ti/knav_dma.c26
-rw-r--r--drivers/soc/ti/knav_qmss.h2
-rw-r--r--drivers/soc/ti/knav_qmss_acc.c2
-rw-r--r--drivers/soc/ti/knav_qmss_queue.c115
-rw-r--r--drivers/soc/ti/pm33xx.c58
-rw-r--r--drivers/soc/ti/pruss.c180
-rw-r--r--drivers/soc/ti/smartreflex.c6
-rw-r--r--drivers/soc/ti/wkup_m3_ipc.c9
-rw-r--r--drivers/soc/versatile/Kconfig4
-rw-r--r--drivers/soc/versatile/soc-integrator.c1
-rw-r--r--drivers/soc/versatile/soc-realview.c20
-rw-r--r--drivers/soc/xilinx/xlnx_event_manager.c22
-rw-r--r--drivers/soc/xilinx/zynqmp_power.c157
133 files changed, 9904 insertions, 2147 deletions
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index 5d924e946507..6a8daeb8c4b9 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -7,6 +7,7 @@ source "drivers/soc/aspeed/Kconfig"
source "drivers/soc/atmel/Kconfig"
source "drivers/soc/bcm/Kconfig"
source "drivers/soc/canaan/Kconfig"
+source "drivers/soc/cirrus/Kconfig"
source "drivers/soc/fsl/Kconfig"
source "drivers/soc/fujitsu/Kconfig"
source "drivers/soc/hisilicon/Kconfig"
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index ba8f5b5460e1..2037a8695cb2 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -7,7 +7,8 @@ obj-y += apple/
obj-y += aspeed/
obj-$(CONFIG_ARCH_AT91) += atmel/
obj-y += bcm/
-obj-$(CONFIG_SOC_CANAAN) += canaan/
+obj-$(CONFIG_ARCH_CANAAN) += canaan/
+obj-$(CONFIG_EP93XX_SOC) += cirrus/
obj-$(CONFIG_ARCH_DOVE) += dove/
obj-$(CONFIG_MACH_DOVE) += dove/
obj-y += fsl/
@@ -32,5 +33,5 @@ obj-y += sunxi/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-y += ti/
obj-$(CONFIG_ARCH_U8500) += ux500/
-obj-$(CONFIG_PLAT_VERSATILE) += versatile/
+obj-y += versatile/
obj-y += xilinx/
diff --git a/drivers/soc/amlogic/meson-clk-measure.c b/drivers/soc/amlogic/meson-clk-measure.c
index 3f3039600357..a6453ffeb753 100644
--- a/drivers/soc/amlogic/meson-clk-measure.c
+++ b/drivers/soc/amlogic/meson-clk-measure.c
@@ -688,4 +688,5 @@ static struct platform_driver meson_msr_driver = {
},
};
module_platform_driver(meson_msr_driver);
+MODULE_DESCRIPTION("Amlogic Meson SoC Clock Measure driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/amlogic/meson-gx-socinfo.c b/drivers/soc/amlogic/meson-gx-socinfo.c
index 6abb730344ab..7549f1644e5e 100644
--- a/drivers/soc/amlogic/meson-gx-socinfo.c
+++ b/drivers/soc/amlogic/meson-gx-socinfo.c
@@ -41,6 +41,11 @@ static const struct meson_gx_soc_id {
{ "G12B", 0x29 },
{ "SM1", 0x2b },
{ "A1", 0x2c },
+ { "T7", 0x36 },
+ { "S4", 0x37 },
+ { "A5", 0x3c },
+ { "C3", 0x3d },
+ { "A4", 0x40 },
};
static const struct meson_gx_package_id {
@@ -63,7 +68,9 @@ static const struct meson_gx_package_id {
{ "962X", 0x24, 0x10, 0xf0 },
{ "962E", 0x24, 0x20, 0xf0 },
{ "A113X", 0x25, 0x37, 0xff },
+ { "A113X", 0x25, 0x43, 0xff },
{ "A113D", 0x25, 0x22, 0xff },
+ { "S905L", 0x26, 0, 0x0 },
{ "S905D2", 0x28, 0x10, 0xf0 },
{ "S905Y2", 0x28, 0x30, 0xf0 },
{ "S905X2", 0x28, 0x40, 0xf0 },
@@ -74,6 +81,11 @@ static const struct meson_gx_package_id {
{ "S905X3", 0x2b, 0x10, 0x3f },
{ "S905D3", 0x2b, 0x30, 0x3f },
{ "A113L", 0x2c, 0x0, 0xf8 },
+ { "S805X2", 0x37, 0x2, 0xf },
+ { "C308L", 0x3d, 0x1, 0xf },
+ { "A311D2", 0x36, 0x1, 0xf },
+ { "A113X2", 0x3c, 0x1, 0xf },
+ { "A113L2", 0x40, 0x1, 0xf },
};
static inline unsigned int socinfo_to_major(u32 socinfo)
diff --git a/drivers/soc/aspeed/aspeed-lpc-ctrl.c b/drivers/soc/aspeed/aspeed-lpc-ctrl.c
index e87038009d1b..ee58151bd69e 100644
--- a/drivers/soc/aspeed/aspeed-lpc-ctrl.c
+++ b/drivers/soc/aspeed/aspeed-lpc-ctrl.c
@@ -353,7 +353,7 @@ static struct platform_driver aspeed_lpc_ctrl_driver = {
.of_match_table = aspeed_lpc_ctrl_match,
},
.probe = aspeed_lpc_ctrl_probe,
- .remove_new = aspeed_lpc_ctrl_remove,
+ .remove = aspeed_lpc_ctrl_remove,
};
module_platform_driver(aspeed_lpc_ctrl_driver);
diff --git a/drivers/soc/aspeed/aspeed-lpc-snoop.c b/drivers/soc/aspeed/aspeed-lpc-snoop.c
index 888b5840c015..9ab5ba9cf1d6 100644
--- a/drivers/soc/aspeed/aspeed-lpc-snoop.c
+++ b/drivers/soc/aspeed/aspeed-lpc-snoop.c
@@ -366,7 +366,7 @@ static struct platform_driver aspeed_lpc_snoop_driver = {
.of_match_table = aspeed_lpc_snoop_match,
},
.probe = aspeed_lpc_snoop_probe,
- .remove_new = aspeed_lpc_snoop_remove,
+ .remove = aspeed_lpc_snoop_remove,
};
module_platform_driver(aspeed_lpc_snoop_driver);
diff --git a/drivers/soc/aspeed/aspeed-p2a-ctrl.c b/drivers/soc/aspeed/aspeed-p2a-ctrl.c
index 8610ddacc7bc..6cc943744e12 100644
--- a/drivers/soc/aspeed/aspeed-p2a-ctrl.c
+++ b/drivers/soc/aspeed/aspeed-p2a-ctrl.c
@@ -431,7 +431,7 @@ static struct platform_driver aspeed_p2a_ctrl_driver = {
.of_match_table = aspeed_p2a_ctrl_match,
},
.probe = aspeed_p2a_ctrl_probe,
- .remove_new = aspeed_p2a_ctrl_remove,
+ .remove = aspeed_p2a_ctrl_remove,
};
module_platform_driver(aspeed_p2a_ctrl_driver);
diff --git a/drivers/soc/aspeed/aspeed-uart-routing.c b/drivers/soc/aspeed/aspeed-uart-routing.c
index a2195f062e01..0191e36e66e1 100644
--- a/drivers/soc/aspeed/aspeed-uart-routing.c
+++ b/drivers/soc/aspeed/aspeed-uart-routing.c
@@ -589,7 +589,7 @@ static struct platform_driver aspeed_uart_routing_driver = {
.of_match_table = aspeed_uart_routing_table,
},
.probe = aspeed_uart_routing_probe,
- .remove_new = aspeed_uart_routing_remove,
+ .remove = aspeed_uart_routing_remove,
};
module_platform_driver(aspeed_uart_routing_driver);
diff --git a/drivers/soc/atmel/soc.c b/drivers/soc/atmel/soc.c
index cc9a3e107479..298b542dd1c0 100644
--- a/drivers/soc/atmel/soc.c
+++ b/drivers/soc/atmel/soc.c
@@ -101,6 +101,29 @@ static const struct at91_soc socs[] __initconst = {
AT91_CIDR_VERSION_MASK, SAM9X60_D6K_EXID_MATCH,
"sam9x60 8MiB SDRAM SiP", "sam9x60"),
#endif
+#ifdef CONFIG_SOC_SAM9X7
+ AT91_SOC(SAM9X7_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
+ AT91_CIDR_VERSION_MASK, SAM9X70_EXID_MATCH,
+ "sam9x70", "sam9x7"),
+ AT91_SOC(SAM9X7_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
+ AT91_CIDR_VERSION_MASK, SAM9X72_EXID_MATCH,
+ "sam9x72", "sam9x7"),
+ AT91_SOC(SAM9X7_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
+ AT91_CIDR_VERSION_MASK, SAM9X75_EXID_MATCH,
+ "sam9x75", "sam9x7"),
+ AT91_SOC(SAM9X7_CIDR_MATCH, SAM9X75_D1M_EXID_MATCH,
+ AT91_CIDR_VERSION_MASK, SAM9X75_EXID_MATCH,
+ "sam9x75 16MB DDR2 SiP", "sam9x7"),
+ AT91_SOC(SAM9X7_CIDR_MATCH, SAM9X75_D5M_EXID_MATCH,
+ AT91_CIDR_VERSION_MASK, SAM9X75_EXID_MATCH,
+ "sam9x75 64MB DDR2 SiP", "sam9x7"),
+ AT91_SOC(SAM9X7_CIDR_MATCH, SAM9X75_D1G_EXID_MATCH,
+ AT91_CIDR_VERSION_MASK, SAM9X75_EXID_MATCH,
+ "sam9x75 125MB DDR3L SiP ", "sam9x7"),
+ AT91_SOC(SAM9X7_CIDR_MATCH, SAM9X75_D2G_EXID_MATCH,
+ AT91_CIDR_VERSION_MASK, SAM9X75_EXID_MATCH,
+ "sam9x75 250MB DDR3L SiP", "sam9x7"),
+#endif
#ifdef CONFIG_SOC_SAMA5
AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
AT91_CIDR_VERSION_MASK, SAMA5D21CU_EXID_MATCH,
@@ -376,7 +399,7 @@ static const struct of_device_id at91_soc_allowed_list[] __initconst = {
static int __init atmel_soc_device_init(void)
{
- struct device_node *np = of_find_node_by_path("/");
+ struct device_node *np __free(device_node) = of_find_node_by_path("/");
if (!of_match_node(at91_soc_allowed_list, np))
return 0;
diff --git a/drivers/soc/atmel/soc.h b/drivers/soc/atmel/soc.h
index 7a9f47ce85fb..2c78e54255f7 100644
--- a/drivers/soc/atmel/soc.h
+++ b/drivers/soc/atmel/soc.h
@@ -44,6 +44,7 @@ at91_soc_init(const struct at91_soc *socs);
#define AT91SAM9X5_CIDR_MATCH 0x019a05a0
#define AT91SAM9N12_CIDR_MATCH 0x019a07a0
#define SAM9X60_CIDR_MATCH 0x019b35a0
+#define SAM9X7_CIDR_MATCH 0x09750020
#define SAMA7G5_CIDR_MATCH 0x00162100
#define AT91SAM9M11_EXID_MATCH 0x00000001
@@ -66,6 +67,14 @@ at91_soc_init(const struct at91_soc *socs);
#define SAM9X60_D1G_EXID_MATCH 0x00000010
#define SAM9X60_D6K_EXID_MATCH 0x00000011
+#define SAM9X70_EXID_MATCH 0x00000005
+#define SAM9X72_EXID_MATCH 0x00000004
+#define SAM9X75_D1G_EXID_MATCH 0x00000018
+#define SAM9X75_D2G_EXID_MATCH 0x00000020
+#define SAM9X75_D1M_EXID_MATCH 0x00000003
+#define SAM9X75_D5M_EXID_MATCH 0x00000010
+#define SAM9X75_EXID_MATCH 0x00000000
+
#define SAMA7G51_EXID_MATCH 0x3
#define SAMA7G52_EXID_MATCH 0x2
#define SAMA7G53_EXID_MATCH 0x1
diff --git a/drivers/soc/canaan/Kconfig b/drivers/soc/canaan/Kconfig
index 43ced2bf8444..3121d351fea6 100644
--- a/drivers/soc/canaan/Kconfig
+++ b/drivers/soc/canaan/Kconfig
@@ -2,9 +2,9 @@
config SOC_K210_SYSCTL
bool "Canaan Kendryte K210 SoC system controller"
- depends on RISCV && SOC_CANAAN && OF
+ depends on RISCV && SOC_CANAAN_K210 && OF
depends on COMMON_CLK_K210
- default SOC_CANAAN
+ default SOC_CANAAN_K210
select PM
select MFD_SYSCON
help
diff --git a/drivers/soc/cirrus/Kconfig b/drivers/soc/cirrus/Kconfig
new file mode 100644
index 000000000000..d8b3b1e68998
--- /dev/null
+++ b/drivers/soc/cirrus/Kconfig
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+if ARCH_EP93XX
+
+config EP93XX_SOC
+ bool "Cirrus EP93xx chips SoC"
+ select SOC_BUS
+ select AUXILIARY_BUS
+ default y
+ help
+ Enable support SoC for Cirrus EP93xx chips.
+
+ Cirrus EP93xx chips have several swlocked registers,
+ this driver provides locked access for reset, pinctrl
+ and clk devices implemented as auxiliary devices.
+
+endif
diff --git a/drivers/soc/cirrus/Makefile b/drivers/soc/cirrus/Makefile
new file mode 100644
index 000000000000..9e6608b67f76
--- /dev/null
+++ b/drivers/soc/cirrus/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-y += soc-ep93xx.o
diff --git a/drivers/soc/cirrus/soc-ep93xx.c b/drivers/soc/cirrus/soc-ep93xx.c
new file mode 100644
index 000000000000..3e79b3b13aef
--- /dev/null
+++ b/drivers/soc/cirrus/soc-ep93xx.c
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * SoC driver for Cirrus EP93xx chips.
+ * Copyright (C) 2022 Nikita Shubin <nikita.shubin@maquefel.me>
+ *
+ * Based on a rewrite of arch/arm/mach-ep93xx/core.c
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
+ *
+ * Thanks go to Michael Burian and Ray Lehtiniemi for their key
+ * role in the ep93xx Linux community.
+ */
+
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/init.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/sys_soc.h>
+
+#include <linux/soc/cirrus/ep93xx.h>
+
+#define EP93XX_SYSCON_DEVCFG 0x80
+
+#define EP93XX_SWLOCK_MAGICK 0xaa
+#define EP93XX_SYSCON_SWLOCK 0xc0
+#define EP93XX_SYSCON_SYSCFG 0x9c
+#define EP93XX_SYSCON_SYSCFG_REV_MASK GENMASK(31, 28)
+#define EP93XX_SYSCON_SYSCFG_REV_SHIFT 28
+
+struct ep93xx_map_info {
+ spinlock_t lock;
+ void __iomem *base;
+ struct regmap *map;
+};
+
+/*
+ * EP93xx System Controller software locked register write
+ *
+ * Logic safeguards are included to condition the control signals for
+ * power connection to the matrix to prevent part damage. In addition, a
+ * software lock register is included that must be written with 0xAA
+ * before each register write to change the values of the four switch
+ * matrix control registers.
+ */
+static void ep93xx_regmap_write(struct regmap *map, spinlock_t *lock,
+ unsigned int reg, unsigned int val)
+{
+ guard(spinlock_irqsave)(lock);
+
+ regmap_write(map, EP93XX_SYSCON_SWLOCK, EP93XX_SWLOCK_MAGICK);
+ regmap_write(map, reg, val);
+}
+
+static void ep93xx_regmap_update_bits(struct regmap *map, spinlock_t *lock,
+ unsigned int reg, unsigned int mask,
+ unsigned int val)
+{
+ guard(spinlock_irqsave)(lock);
+
+ regmap_write(map, EP93XX_SYSCON_SWLOCK, EP93XX_SWLOCK_MAGICK);
+ /* force write is required to clear swlock if no changes are made */
+ regmap_update_bits_base(map, reg, mask, val, NULL, false, true);
+}
+
+static void ep93xx_unregister_adev(void *_adev)
+{
+ struct auxiliary_device *adev = _adev;
+
+ auxiliary_device_delete(adev);
+ auxiliary_device_uninit(adev);
+}
+
+static void ep93xx_adev_release(struct device *dev)
+{
+ struct auxiliary_device *adev = to_auxiliary_dev(dev);
+ struct ep93xx_regmap_adev *rdev = to_ep93xx_regmap_adev(adev);
+
+ kfree(rdev);
+}
+
+static struct auxiliary_device __init *ep93xx_adev_alloc(struct device *parent,
+ const char *name,
+ struct ep93xx_map_info *info)
+{
+ struct ep93xx_regmap_adev *rdev __free(kfree) = NULL;
+ struct auxiliary_device *adev;
+ int ret;
+
+ rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
+ if (!rdev)
+ return ERR_PTR(-ENOMEM);
+
+ rdev->map = info->map;
+ rdev->base = info->base;
+ rdev->lock = &info->lock;
+ rdev->write = ep93xx_regmap_write;
+ rdev->update_bits = ep93xx_regmap_update_bits;
+
+ adev = &rdev->adev;
+ adev->name = name;
+ adev->dev.parent = parent;
+ adev->dev.release = ep93xx_adev_release;
+
+ ret = auxiliary_device_init(adev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return &no_free_ptr(rdev)->adev;
+}
+
+static int __init ep93xx_controller_register(struct device *parent, const char *name,
+ struct ep93xx_map_info *info)
+{
+ struct auxiliary_device *adev;
+ int ret;
+
+ adev = ep93xx_adev_alloc(parent, name, info);
+ if (IS_ERR(adev))
+ return PTR_ERR(adev);
+
+ ret = auxiliary_device_add(adev);
+ if (ret) {
+ auxiliary_device_uninit(adev);
+ return ret;
+ }
+
+ return devm_add_action_or_reset(parent, ep93xx_unregister_adev, adev);
+}
+
+static unsigned int __init ep93xx_soc_revision(struct regmap *map)
+{
+ unsigned int val;
+
+ regmap_read(map, EP93XX_SYSCON_SYSCFG, &val);
+ val &= EP93XX_SYSCON_SYSCFG_REV_MASK;
+ val >>= EP93XX_SYSCON_SYSCFG_REV_SHIFT;
+ return val;
+}
+
+static const char __init *ep93xx_get_soc_rev(unsigned int rev)
+{
+ switch (rev) {
+ case EP93XX_CHIP_REV_D0:
+ return "D0";
+ case EP93XX_CHIP_REV_D1:
+ return "D1";
+ case EP93XX_CHIP_REV_E0:
+ return "E0";
+ case EP93XX_CHIP_REV_E1:
+ return "E1";
+ case EP93XX_CHIP_REV_E2:
+ return "E2";
+ default:
+ return "unknown";
+ }
+}
+
+static const char *pinctrl_names[] __initconst = {
+ "pinctrl-ep9301", /* EP93XX_9301_SOC */
+ "pinctrl-ep9307", /* EP93XX_9307_SOC */
+ "pinctrl-ep9312", /* EP93XX_9312_SOC */
+};
+
+static int __init ep93xx_syscon_probe(struct platform_device *pdev)
+{
+ enum ep93xx_soc_model model;
+ struct ep93xx_map_info *map_info;
+ struct soc_device_attribute *attrs;
+ struct soc_device *soc_dev;
+ struct device *dev = &pdev->dev;
+ struct regmap *map;
+ void __iomem *base;
+ unsigned int rev;
+ int ret;
+
+ model = (enum ep93xx_soc_model)(uintptr_t)device_get_match_data(dev);
+
+ map = device_node_to_regmap(dev->of_node);
+ if (IS_ERR(map))
+ return PTR_ERR(map);
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ attrs = devm_kzalloc(dev, sizeof(*attrs), GFP_KERNEL);
+ if (!attrs)
+ return -ENOMEM;
+
+ rev = ep93xx_soc_revision(map);
+
+ attrs->machine = of_flat_dt_get_machine_name();
+ attrs->family = "Cirrus Logic EP93xx";
+ attrs->revision = ep93xx_get_soc_rev(rev);
+
+ soc_dev = soc_device_register(attrs);
+ if (IS_ERR(soc_dev))
+ return PTR_ERR(soc_dev);
+
+ map_info = devm_kzalloc(dev, sizeof(*map_info), GFP_KERNEL);
+ if (!map_info)
+ return -ENOMEM;
+
+ spin_lock_init(&map_info->lock);
+ map_info->map = map;
+ map_info->base = base;
+
+ ret = ep93xx_controller_register(dev, pinctrl_names[model], map_info);
+ if (ret)
+ dev_err(dev, "registering pinctrl controller failed\n");
+
+ /*
+ * EP93xx SSP clock rate was doubled in version E2. For more information
+ * see section 6 "2x SSP (Synchronous Serial Port) Clock – Revision E2 only":
+ * http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
+ */
+ if (rev == EP93XX_CHIP_REV_E2)
+ ret = ep93xx_controller_register(dev, "clk-ep93xx.e2", map_info);
+ else
+ ret = ep93xx_controller_register(dev, "clk-ep93xx", map_info);
+ if (ret)
+ dev_err(dev, "registering clock controller failed\n");
+
+ ret = ep93xx_controller_register(dev, "reset-ep93xx", map_info);
+ if (ret)
+ dev_err(dev, "registering reset controller failed\n");
+
+ return 0;
+}
+
+static const struct of_device_id ep9301_syscon_of_device_ids[] = {
+ { .compatible = "cirrus,ep9301-syscon", .data = (void *)EP93XX_9301_SOC },
+ { .compatible = "cirrus,ep9302-syscon", .data = (void *)EP93XX_9301_SOC },
+ { .compatible = "cirrus,ep9307-syscon", .data = (void *)EP93XX_9307_SOC },
+ { .compatible = "cirrus,ep9312-syscon", .data = (void *)EP93XX_9312_SOC },
+ { .compatible = "cirrus,ep9315-syscon", .data = (void *)EP93XX_9312_SOC },
+ { /* sentinel */ }
+};
+
+static struct platform_driver ep9301_syscon_driver = {
+ .driver = {
+ .name = "ep9301-syscon",
+ .of_match_table = ep9301_syscon_of_device_ids,
+ },
+};
+builtin_platform_driver_probe(ep9301_syscon_driver, ep93xx_syscon_probe);
diff --git a/drivers/soc/fsl/Kconfig b/drivers/soc/fsl/Kconfig
index fcec6ed83d5e..a1e0bc8c1757 100644
--- a/drivers/soc/fsl/Kconfig
+++ b/drivers/soc/fsl/Kconfig
@@ -22,7 +22,7 @@ config FSL_GUTS
config FSL_MC_DPIO
tristate "QorIQ DPAA2 DPIO driver"
- depends on FSL_MC_BUS
+ depends on FSL_MC_BUS && NET
select SOC_BUS
select FSL_GUTS
select DIMLIB
diff --git a/drivers/soc/fsl/dpaa2-console.c b/drivers/soc/fsl/dpaa2-console.c
index 6dbc77db7718..6310f54e68a2 100644
--- a/drivers/soc/fsl/dpaa2-console.c
+++ b/drivers/soc/fsl/dpaa2-console.c
@@ -320,7 +320,7 @@ static struct platform_driver dpaa2_console_driver = {
.of_match_table = dpaa2_console_match_table,
},
.probe = dpaa2_console_probe,
- .remove_new = dpaa2_console_remove,
+ .remove = dpaa2_console_remove,
};
module_platform_driver(dpaa2_console_driver);
diff --git a/drivers/soc/fsl/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c
index 1d2b27e3ea63..0b60ed16297c 100644
--- a/drivers/soc/fsl/dpio/dpio-service.c
+++ b/drivers/soc/fsl/dpio/dpio-service.c
@@ -523,7 +523,7 @@ int dpaa2_io_service_enqueue_multiple_desc_fq(struct dpaa2_io *d,
struct qbman_eq_desc *ed;
int i, ret;
- ed = kcalloc(sizeof(struct qbman_eq_desc), 32, GFP_KERNEL);
+ ed = kcalloc(32, sizeof(struct qbman_eq_desc), GFP_KERNEL);
if (!ed)
return -ENOMEM;
@@ -891,7 +891,7 @@ void dpaa2_io_update_net_dim(struct dpaa2_io *d, __u64 frames, __u64 bytes)
d->frames += frames;
dim_update_sample(d->event_ctr, d->frames, d->bytes, &dim_sample);
- net_dim(&d->rx_dim, dim_sample);
+ net_dim(&d->rx_dim, &dim_sample);
spin_unlock(&d->dim_lock);
}
diff --git a/drivers/soc/fsl/qbman/Kconfig b/drivers/soc/fsl/qbman/Kconfig
index bdecb86bb656..27774ec6ff90 100644
--- a/drivers/soc/fsl/qbman/Kconfig
+++ b/drivers/soc/fsl/qbman/Kconfig
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
menuconfig FSL_DPAA
bool "QorIQ DPAA1 framework support"
- depends on ((FSL_SOC_BOOKE || ARCH_LAYERSCAPE) && ARCH_DMA_ADDR_T_64BIT)
+ depends on ((FSL_SOC_BOOKE || ARCH_LAYERSCAPE || COMPILE_TEST) && ARCH_DMA_ADDR_T_64BIT)
select GENERIC_ALLOCATOR
help
The Freescale Data Path Acceleration Architecture (DPAA) is a set of
diff --git a/drivers/soc/fsl/qbman/bman_ccsr.c b/drivers/soc/fsl/qbman/bman_ccsr.c
index cb24a08be084..b0f26f6f731e 100644
--- a/drivers/soc/fsl/qbman/bman_ccsr.c
+++ b/drivers/soc/fsl/qbman/bman_ccsr.c
@@ -144,17 +144,6 @@ static int bm_set_memory(u64 ba, u32 size)
static dma_addr_t fbpr_a;
static size_t fbpr_sz;
-static int bman_fbpr(struct reserved_mem *rmem)
-{
- fbpr_a = rmem->base;
- fbpr_sz = rmem->size;
-
- WARN_ON(!(fbpr_a && fbpr_sz));
-
- return 0;
-}
-RESERVEDMEM_OF_DECLARE(bman_fbpr, "fsl,bman-fbpr", bman_fbpr);
-
static irqreturn_t bman_isr(int irq, void *ptr)
{
u32 isr_val, ier_val, ecsr_val, isr_mask, i;
@@ -242,17 +231,11 @@ static int fsl_bman_probe(struct platform_device *pdev)
return -ENODEV;
}
- /*
- * If FBPR memory wasn't defined using the qbman compatible string
- * try using the of_reserved_mem_device method
- */
- if (!fbpr_a) {
- ret = qbman_init_private_mem(dev, 0, &fbpr_a, &fbpr_sz);
- if (ret) {
- dev_err(dev, "qbman_init_private_mem() failed 0x%x\n",
- ret);
- return -ENODEV;
- }
+ ret = qbman_init_private_mem(dev, 0, "fsl,bman-fbpr", &fbpr_a, &fbpr_sz);
+ if (ret) {
+ dev_err(dev, "qbman_init_private_mem() failed 0x%x\n",
+ ret);
+ return -ENODEV;
}
dev_dbg(dev, "Allocated FBPR 0x%llx 0x%zx\n", fbpr_a, fbpr_sz);
diff --git a/drivers/soc/fsl/qbman/dpaa_sys.c b/drivers/soc/fsl/qbman/dpaa_sys.c
index 33751450047e..e1d7b79cc450 100644
--- a/drivers/soc/fsl/qbman/dpaa_sys.c
+++ b/drivers/soc/fsl/qbman/dpaa_sys.c
@@ -34,8 +34,8 @@
/*
* Initialize a devices private memory region
*/
-int qbman_init_private_mem(struct device *dev, int idx, dma_addr_t *addr,
- size_t *size)
+int qbman_init_private_mem(struct device *dev, int idx, const char *compat,
+ dma_addr_t *addr, size_t *size)
{
struct device_node *mem_node;
struct reserved_mem *rmem;
@@ -44,8 +44,12 @@ int qbman_init_private_mem(struct device *dev, int idx, dma_addr_t *addr,
mem_node = of_parse_phandle(dev->of_node, "memory-region", idx);
if (!mem_node) {
- dev_err(dev, "No memory-region found for index %d\n", idx);
- return -ENODEV;
+ mem_node = of_find_compatible_node(NULL, NULL, compat);
+ if (!mem_node) {
+ dev_err(dev, "No memory-region found for index %d or compatible '%s'\n",
+ idx, compat);
+ return -ENODEV;
+ }
}
rmem = of_reserved_mem_lookup(mem_node);
diff --git a/drivers/soc/fsl/qbman/dpaa_sys.h b/drivers/soc/fsl/qbman/dpaa_sys.h
index ae8afa552b1e..16485bde9636 100644
--- a/drivers/soc/fsl/qbman/dpaa_sys.h
+++ b/drivers/soc/fsl/qbman/dpaa_sys.h
@@ -101,8 +101,8 @@ static inline u8 dpaa_cyc_diff(u8 ringsize, u8 first, u8 last)
#define DPAA_GENALLOC_OFF 0x80000000
/* Initialize the devices private memory region */
-int qbman_init_private_mem(struct device *dev, int idx, dma_addr_t *addr,
- size_t *size);
+int qbman_init_private_mem(struct device *dev, int idx, const char *compat,
+ dma_addr_t *addr, size_t *size);
/* memremap() attributes for different platforms */
#ifdef CONFIG_PPC
diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c
index 739e4eee6b75..4dc8aba33d9b 100644
--- a/drivers/soc/fsl/qbman/qman.c
+++ b/drivers/soc/fsl/qbman/qman.c
@@ -991,7 +991,7 @@ struct qman_portal {
/* linked-list of CSCN handlers. */
struct list_head cgr_cbs;
/* list lock */
- spinlock_t cgr_lock;
+ raw_spinlock_t cgr_lock;
struct work_struct congestion_work;
struct work_struct mr_work;
char irqname[MAX_IRQNAME];
@@ -1281,7 +1281,7 @@ static int qman_create_portal(struct qman_portal *portal,
/* if the given mask is NULL, assume all CGRs can be seen */
qman_cgrs_fill(&portal->cgrs[0]);
INIT_LIST_HEAD(&portal->cgr_cbs);
- spin_lock_init(&portal->cgr_lock);
+ raw_spin_lock_init(&portal->cgr_lock);
INIT_WORK(&portal->congestion_work, qm_congestion_task);
INIT_WORK(&portal->mr_work, qm_mr_process_task);
portal->bits = 0;
@@ -1456,11 +1456,14 @@ static void qm_congestion_task(struct work_struct *work)
union qm_mc_result *mcr;
struct qman_cgr *cgr;
- spin_lock(&p->cgr_lock);
+ /*
+ * FIXME: QM_MCR_TIMEOUT is 10ms, which is too long for a raw spinlock!
+ */
+ raw_spin_lock_irq(&p->cgr_lock);
qm_mc_start(&p->p);
qm_mc_commit(&p->p, QM_MCC_VERB_QUERYCONGESTION);
if (!qm_mc_result_timeout(&p->p, &mcr)) {
- spin_unlock(&p->cgr_lock);
+ raw_spin_unlock_irq(&p->cgr_lock);
dev_crit(p->config->dev, "QUERYCONGESTION timeout\n");
qman_p_irqsource_add(p, QM_PIRQ_CSCI);
return;
@@ -1476,7 +1479,7 @@ static void qm_congestion_task(struct work_struct *work)
list_for_each_entry(cgr, &p->cgr_cbs, node)
if (cgr->cb && qman_cgrs_get(&c, cgr->cgrid))
cgr->cb(p, cgr, qman_cgrs_get(&rr, cgr->cgrid));
- spin_unlock(&p->cgr_lock);
+ raw_spin_unlock_irq(&p->cgr_lock);
qman_p_irqsource_add(p, QM_PIRQ_CSCI);
}
@@ -2440,7 +2443,7 @@ int qman_create_cgr(struct qman_cgr *cgr, u32 flags,
preempt_enable();
cgr->chan = p->config->channel;
- spin_lock(&p->cgr_lock);
+ raw_spin_lock_irq(&p->cgr_lock);
if (opts) {
struct qm_mcc_initcgr local_opts = *opts;
@@ -2477,7 +2480,7 @@ int qman_create_cgr(struct qman_cgr *cgr, u32 flags,
qman_cgrs_get(&p->cgrs[1], cgr->cgrid))
cgr->cb(p, cgr, 1);
out:
- spin_unlock(&p->cgr_lock);
+ raw_spin_unlock_irq(&p->cgr_lock);
put_affine_portal();
return ret;
}
@@ -2512,7 +2515,7 @@ int qman_delete_cgr(struct qman_cgr *cgr)
return -EINVAL;
memset(&local_opts, 0, sizeof(struct qm_mcc_initcgr));
- spin_lock_irqsave(&p->cgr_lock, irqflags);
+ raw_spin_lock_irqsave(&p->cgr_lock, irqflags);
list_del(&cgr->node);
/*
* If there are no other CGR objects for this CGRID in the list,
@@ -2537,17 +2540,12 @@ int qman_delete_cgr(struct qman_cgr *cgr)
/* add back to the list */
list_add(&cgr->node, &p->cgr_cbs);
release_lock:
- spin_unlock_irqrestore(&p->cgr_lock, irqflags);
+ raw_spin_unlock_irqrestore(&p->cgr_lock, irqflags);
put_affine_portal();
return ret;
}
EXPORT_SYMBOL(qman_delete_cgr);
-struct cgr_comp {
- struct qman_cgr *cgr;
- struct completion completion;
-};
-
static void qman_delete_cgr_smp_call(void *p)
{
qman_delete_cgr((struct qman_cgr *)p);
@@ -2577,9 +2575,9 @@ static int qman_update_cgr(struct qman_cgr *cgr, struct qm_mcc_initcgr *opts)
if (!p)
return -EINVAL;
- spin_lock_irqsave(&p->cgr_lock, irqflags);
+ raw_spin_lock_irqsave(&p->cgr_lock, irqflags);
ret = qm_modify_cgr(cgr, 0, opts);
- spin_unlock_irqrestore(&p->cgr_lock, irqflags);
+ raw_spin_unlock_irqrestore(&p->cgr_lock, irqflags);
put_affine_portal();
return ret;
}
diff --git a/drivers/soc/fsl/qbman/qman_ccsr.c b/drivers/soc/fsl/qbman/qman_ccsr.c
index 157659fd033a..aa5348f4902f 100644
--- a/drivers/soc/fsl/qbman/qman_ccsr.c
+++ b/drivers/soc/fsl/qbman/qman_ccsr.c
@@ -468,28 +468,6 @@ static int zero_priv_mem(phys_addr_t addr, size_t sz)
return 0;
}
-
-static int qman_fqd(struct reserved_mem *rmem)
-{
- fqd_a = rmem->base;
- fqd_sz = rmem->size;
-
- WARN_ON(!(fqd_a && fqd_sz));
- return 0;
-}
-RESERVEDMEM_OF_DECLARE(qman_fqd, "fsl,qman-fqd", qman_fqd);
-
-static int qman_pfdr(struct reserved_mem *rmem)
-{
- pfdr_a = rmem->base;
- pfdr_sz = rmem->size;
-
- WARN_ON(!(pfdr_a && pfdr_sz));
-
- return 0;
-}
-RESERVEDMEM_OF_DECLARE(qman_pfdr, "fsl,qman-pfdr", qman_pfdr);
-
#endif
unsigned int qm_get_fqid_maxcnt(void)
@@ -796,39 +774,32 @@ static int fsl_qman_probe(struct platform_device *pdev)
qm_channel_caam = QMAN_CHANNEL_CAAM_REV3;
}
- if (fqd_a) {
+ /*
+ * Order of memory regions is assumed as FQD followed by PFDR
+ * in order to ensure allocations from the correct regions the
+ * driver initializes then allocates each piece in order
+ */
+ ret = qbman_init_private_mem(dev, 0, "fsl,qman-fqd", &fqd_a, &fqd_sz);
+ if (ret) {
+ dev_err(dev, "qbman_init_private_mem() for FQD failed 0x%x\n",
+ ret);
+ return -ENODEV;
+ }
#ifdef CONFIG_PPC
- /*
- * For PPC backward DT compatibility
- * FQD memory MUST be zero'd by software
- */
- zero_priv_mem(fqd_a, fqd_sz);
-#else
- WARN(1, "Unexpected architecture using non shared-dma-mem reservations");
+ /*
+ * For PPC backward DT compatibility
+ * FQD memory MUST be zero'd by software
+ */
+ zero_priv_mem(fqd_a, fqd_sz);
#endif
- } else {
- /*
- * Order of memory regions is assumed as FQD followed by PFDR
- * in order to ensure allocations from the correct regions the
- * driver initializes then allocates each piece in order
- */
- ret = qbman_init_private_mem(dev, 0, &fqd_a, &fqd_sz);
- if (ret) {
- dev_err(dev, "qbman_init_private_mem() for FQD failed 0x%x\n",
- ret);
- return -ENODEV;
- }
- }
dev_dbg(dev, "Allocated FQD 0x%llx 0x%zx\n", fqd_a, fqd_sz);
- if (!pfdr_a) {
- /* Setup PFDR memory */
- ret = qbman_init_private_mem(dev, 1, &pfdr_a, &pfdr_sz);
- if (ret) {
- dev_err(dev, "qbman_init_private_mem() for PFDR failed 0x%x\n",
- ret);
- return -ENODEV;
- }
+ /* Setup PFDR memory */
+ ret = qbman_init_private_mem(dev, 1, "fsl,qman-pfdr", &pfdr_a, &pfdr_sz);
+ if (ret) {
+ dev_err(dev, "qbman_init_private_mem() for PFDR failed 0x%x\n",
+ ret);
+ return -ENODEV;
}
dev_dbg(dev, "Allocated PFDR 0x%llx 0x%zx\n", pfdr_a, pfdr_sz);
diff --git a/drivers/soc/fsl/qbman/qman_portal.c b/drivers/soc/fsl/qbman/qman_portal.c
index e23b60618c1a..456ef5d5c199 100644
--- a/drivers/soc/fsl/qbman/qman_portal.c
+++ b/drivers/soc/fsl/qbman/qman_portal.c
@@ -48,9 +48,10 @@ static void portal_set_cpu(struct qm_portal_config *pcfg, int cpu)
struct device *dev = pcfg->dev;
int ret;
- pcfg->iommu_domain = iommu_domain_alloc(&platform_bus_type);
- if (!pcfg->iommu_domain) {
+ pcfg->iommu_domain = iommu_paging_domain_alloc(dev);
+ if (IS_ERR(pcfg->iommu_domain)) {
dev_err(dev, "%s(): iommu_domain_alloc() failed", __func__);
+ pcfg->iommu_domain = NULL;
goto no_iommu;
}
ret = fsl_pamu_configure_l1_stash(pcfg->iommu_domain, cpu);
diff --git a/drivers/soc/fsl/qbman/qman_test_stash.c b/drivers/soc/fsl/qbman/qman_test_stash.c
index b7e8e5ec884c..f4d3c2146f4f 100644
--- a/drivers/soc/fsl/qbman/qman_test_stash.c
+++ b/drivers/soc/fsl/qbman/qman_test_stash.c
@@ -108,14 +108,12 @@ static int on_all_cpus(int (*fn)(void))
.fn = fn,
.started = ATOMIC_INIT(0)
};
- struct task_struct *k = kthread_create(bstrap_fn, &bstrap,
- "hotpotato%d", cpu);
+ struct task_struct *k = kthread_run_on_cpu(bstrap_fn, &bstrap,
+ cpu, "hotpotato%d");
int ret;
if (IS_ERR(k))
return -ENOMEM;
- kthread_bind(k, cpu);
- wake_up_process(k);
/*
* If we call kthread_stop() before the "wake up" has had an
* effect, then the thread may exit with -EINTR without ever
diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig
index fa9ffbed0e92..eb03f42ab978 100644
--- a/drivers/soc/fsl/qe/Kconfig
+++ b/drivers/soc/fsl/qe/Kconfig
@@ -17,7 +17,7 @@ config QUICC_ENGINE
config UCC_SLOW
bool
- default y if SERIAL_QE
+ default y if SERIAL_QE || (CPM_QMC && QUICC_ENGINE)
help
This option provides qe_lib support to UCC slow
protocols: UART, BISYNC, QMC
@@ -31,26 +31,27 @@ config UCC_FAST
config UCC
bool
- default y if UCC_FAST || UCC_SLOW
+ default y if UCC_FAST || UCC_SLOW || (CPM_TSA && QUICC_ENGINE)
config CPM_TSA
- tristate "CPM TSA support"
+ tristate "CPM/QE TSA support"
depends on OF && HAS_IOMEM
- depends on CPM1 || (CPM && COMPILE_TEST)
+ depends on CPM1 || QUICC_ENGINE || \
+ ((CPM || QUICC_ENGINE) && COMPILE_TEST)
help
- Freescale CPM Time Slot Assigner (TSA)
+ Freescale CPM/QE Time Slot Assigner (TSA)
controller.
This option enables support for this
controller
config CPM_QMC
- tristate "CPM QMC support"
+ tristate "CPM/QE QMC support"
depends on OF && HAS_IOMEM
- depends on CPM1 || (FSL_SOC && CPM && COMPILE_TEST)
+ depends on FSL_SOC
depends on CPM_TSA
help
- Freescale CPM QUICC Multichannel Controller
+ Freescale CPM/QE QUICC Multichannel Controller
(QMC)
This option enables support for this
diff --git a/drivers/soc/fsl/qe/qe_common.c b/drivers/soc/fsl/qe/qe_common.c
index a877347d37d3..02c29f5f86d3 100644
--- a/drivers/soc/fsl/qe/qe_common.c
+++ b/drivers/soc/fsl/qe/qe_common.c
@@ -13,6 +13,7 @@
* 2006 (c) MontaVista Software, Inc.
* Vitaly Bordug <vbordug@ru.mvista.com>
*/
+#include <linux/device.h>
#include <linux/genalloc.h>
#include <linux/init.h>
#include <linux/list.h>
@@ -187,6 +188,49 @@ void cpm_muram_free(s32 offset)
}
EXPORT_SYMBOL(cpm_muram_free);
+static void devm_cpm_muram_release(struct device *dev, void *res)
+{
+ s32 *info = res;
+
+ cpm_muram_free(*info);
+}
+
+/**
+ * devm_cpm_muram_alloc - Resource-managed cpm_muram_alloc
+ * @dev: Device to allocate memory for
+ * @size: number of bytes to allocate
+ * @align: requested alignment, in bytes
+ *
+ * This function returns a non-negative offset into the muram area, or
+ * a negative errno on failure as cpm_muram_alloc() does.
+ * Use cpm_muram_addr() to get the virtual address of the area.
+ *
+ * Compare against cpm_muram_alloc(), the memory allocated by this
+ * resource-managed version is automatically freed on driver detach and so,
+ * cpm_muram_free() must not be called to release the allocated memory.
+ */
+s32 devm_cpm_muram_alloc(struct device *dev, unsigned long size,
+ unsigned long align)
+{
+ s32 info;
+ s32 *dr;
+
+ dr = devres_alloc(devm_cpm_muram_release, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ info = cpm_muram_alloc(size, align);
+ if (info >= 0) {
+ *dr = info;
+ devres_add(dev, dr);
+ } else {
+ devres_free(dr);
+ }
+
+ return info;
+}
+EXPORT_SYMBOL(devm_cpm_muram_alloc);
+
/*
* cpm_muram_alloc_fixed - reserve a specific region of multi-user ram
* @offset: offset of allocation start address
@@ -212,6 +256,42 @@ s32 cpm_muram_alloc_fixed(unsigned long offset, unsigned long size)
EXPORT_SYMBOL(cpm_muram_alloc_fixed);
/**
+ * devm_cpm_muram_alloc_fixed - Resource-managed cpm_muram_alloc_fixed
+ * @dev: Device to allocate memory for
+ * @offset: offset of allocation start address
+ * @size: number of bytes to allocate
+ *
+ * This function returns a non-negative offset into the muram area, or
+ * a negative errno on failure as cpm_muram_alloc_fixed() does.
+ * Use cpm_muram_addr() to get the virtual address of the area.
+ *
+ * Compare against cpm_muram_alloc_fixed(), the memory allocated by this
+ * resource-managed version is automatically freed on driver detach and so,
+ * cpm_muram_free() must not be called to release the allocated memory.
+ */
+s32 devm_cpm_muram_alloc_fixed(struct device *dev, unsigned long offset,
+ unsigned long size)
+{
+ s32 info;
+ s32 *dr;
+
+ dr = devres_alloc(devm_cpm_muram_release, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ info = cpm_muram_alloc_fixed(offset, size);
+ if (info >= 0) {
+ *dr = info;
+ devres_add(dev, dr);
+ } else {
+ devres_free(dr);
+ }
+
+ return info;
+}
+EXPORT_SYMBOL(devm_cpm_muram_alloc_fixed);
+
+/**
* cpm_muram_addr - turn a muram offset into a virtual address
* @offset: muram offset to convert
*/
diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c
index f498db9abe35..36c0ccc06151 100644
--- a/drivers/soc/fsl/qe/qmc.c
+++ b/drivers/soc/fsl/qe/qmc.c
@@ -8,7 +8,9 @@
*/
#include <soc/fsl/qe/qmc.h>
+#include <linux/bitfield.h>
#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
#include <linux/hdlc.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -18,31 +20,41 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <soc/fsl/cpm.h>
+#include <soc/fsl/qe/ucc_slow.h>
+#include <soc/fsl/qe/qe.h>
#include <sysdev/fsl_soc.h>
#include "tsa.h"
-/* SCC general mode register high (32 bits) */
+/* SCC general mode register low (32 bits) (GUMR_L in QE) */
#define SCC_GSMRL 0x00
-#define SCC_GSMRL_ENR (1 << 5)
-#define SCC_GSMRL_ENT (1 << 4)
-#define SCC_GSMRL_MODE_QMC (0x0A << 0)
+#define SCC_GSMRL_ENR BIT(5)
+#define SCC_GSMRL_ENT BIT(4)
+#define SCC_GSMRL_MODE_MASK GENMASK(3, 0)
+#define SCC_CPM1_GSMRL_MODE_QMC FIELD_PREP_CONST(SCC_GSMRL_MODE_MASK, 0x0A)
+#define SCC_QE_GSMRL_MODE_QMC FIELD_PREP_CONST(SCC_GSMRL_MODE_MASK, 0x02)
-/* SCC general mode register low (32 bits) */
+/* SCC general mode register high (32 bits) (identical to GUMR_H in QE) */
#define SCC_GSMRH 0x04
-#define SCC_GSMRH_CTSS (1 << 7)
-#define SCC_GSMRH_CDS (1 << 8)
-#define SCC_GSMRH_CTSP (1 << 9)
-#define SCC_GSMRH_CDP (1 << 10)
-
-/* SCC event register (16 bits) */
+#define SCC_GSMRH_CTSS BIT(7)
+#define SCC_GSMRH_CDS BIT(8)
+#define SCC_GSMRH_CTSP BIT(9)
+#define SCC_GSMRH_CDP BIT(10)
+#define SCC_GSMRH_TTX BIT(11)
+#define SCC_GSMRH_TRX BIT(12)
+
+/* SCC event register (16 bits) (identical to UCCE in QE) */
#define SCC_SCCE 0x10
-#define SCC_SCCE_IQOV (1 << 3)
-#define SCC_SCCE_GINT (1 << 2)
-#define SCC_SCCE_GUN (1 << 1)
-#define SCC_SCCE_GOV (1 << 0)
+#define SCC_SCCE_IQOV BIT(3)
+#define SCC_SCCE_GINT BIT(2)
+#define SCC_SCCE_GUN BIT(1)
+#define SCC_SCCE_GOV BIT(0)
/* SCC mask register (16 bits) */
#define SCC_SCCM 0x14
+
+/* UCC Extended Mode Register (8 bits, QE only) */
+#define SCC_QE_UCC_GUEMR 0x90
+
/* Multichannel base pointer (32 bits) */
#define QMC_GBL_MCBASE 0x00
/* Multichannel controller state (16 bits) */
@@ -73,27 +85,42 @@
#define QMC_GBL_TSATTX 0x60
/* CRC constant (16 bits) */
#define QMC_GBL_C_MASK16 0xA0
+/* Rx framer base pointer (16 bits, QE only) */
+#define QMC_QE_GBL_RX_FRM_BASE 0xAC
+/* Tx framer base pointer (16 bits, QE only) */
+#define QMC_QE_GBL_TX_FRM_BASE 0xAE
+/* A reserved area (0xB0 -> 0xC3) that must be initialized to 0 (QE only) */
+#define QMC_QE_GBL_RSV_B0_START 0xB0
+#define QMC_QE_GBL_RSV_B0_SIZE 0x14
+/* QMC Global Channel specific base (32 bits, QE only) */
+#define QMC_QE_GBL_GCSBASE 0xC4
/* TSA entry (16bit entry in TSATRX and TSATTX) */
-#define QMC_TSA_VALID (1 << 15)
-#define QMC_TSA_WRAP (1 << 14)
-#define QMC_TSA_MASK (0x303F)
-#define QMC_TSA_CHANNEL(x) ((x) << 6)
+#define QMC_TSA_VALID BIT(15)
+#define QMC_TSA_WRAP BIT(14)
+#define QMC_TSA_MASK_MASKH GENMASK(13, 12)
+#define QMC_TSA_MASK_MASKL GENMASK(5, 0)
+#define QMC_TSA_MASK_8BIT (FIELD_PREP_CONST(QMC_TSA_MASK_MASKH, 0x3) | \
+ FIELD_PREP_CONST(QMC_TSA_MASK_MASKL, 0x3F))
+#define QMC_TSA_CHANNEL_MASK GENMASK(11, 6)
+#define QMC_TSA_CHANNEL(x) FIELD_PREP(QMC_TSA_CHANNEL_MASK, x)
/* Tx buffer descriptor base address (16 bits, offset from MCBASE) */
#define QMC_SPE_TBASE 0x00
/* Channel mode register (16 bits) */
#define QMC_SPE_CHAMR 0x02
-#define QMC_SPE_CHAMR_MODE_HDLC (1 << 15)
-#define QMC_SPE_CHAMR_MODE_TRANSP ((0 << 15) | (1 << 13))
-#define QMC_SPE_CHAMR_ENT (1 << 12)
-#define QMC_SPE_CHAMR_POL (1 << 8)
-#define QMC_SPE_CHAMR_HDLC_IDLM (1 << 13)
-#define QMC_SPE_CHAMR_HDLC_CRC (1 << 7)
-#define QMC_SPE_CHAMR_HDLC_NOF (0x0f << 0)
-#define QMC_SPE_CHAMR_TRANSP_RD (1 << 14)
-#define QMC_SPE_CHAMR_TRANSP_SYNC (1 << 10)
+#define QMC_SPE_CHAMR_MODE_MASK GENMASK(15, 15)
+#define QMC_SPE_CHAMR_MODE_HDLC FIELD_PREP_CONST(QMC_SPE_CHAMR_MODE_MASK, 1)
+#define QMC_SPE_CHAMR_MODE_TRANSP (FIELD_PREP_CONST(QMC_SPE_CHAMR_MODE_MASK, 0) | BIT(13))
+#define QMC_SPE_CHAMR_ENT BIT(12)
+#define QMC_SPE_CHAMR_POL BIT(8)
+#define QMC_SPE_CHAMR_HDLC_IDLM BIT(13)
+#define QMC_SPE_CHAMR_HDLC_CRC BIT(7)
+#define QMC_SPE_CHAMR_HDLC_NOF_MASK GENMASK(3, 0)
+#define QMC_SPE_CHAMR_HDLC_NOF(x) FIELD_PREP(QMC_SPE_CHAMR_HDLC_NOF_MASK, x)
+#define QMC_SPE_CHAMR_TRANSP_RD BIT(14)
+#define QMC_SPE_CHAMR_TRANSP_SYNC BIT(10)
/* Tx internal state (32 bits) */
#define QMC_SPE_TSTATE 0x04
@@ -120,43 +147,47 @@
/* Transparent synchronization (16 bits) */
#define QMC_SPE_TRNSYNC 0x3C
-#define QMC_SPE_TRNSYNC_RX(x) ((x) << 8)
-#define QMC_SPE_TRNSYNC_TX(x) ((x) << 0)
+#define QMC_SPE_TRNSYNC_RX_MASK GENMASK(15, 8)
+#define QMC_SPE_TRNSYNC_RX(x) FIELD_PREP(QMC_SPE_TRNSYNC_RX_MASK, x)
+#define QMC_SPE_TRNSYNC_TX_MASK GENMASK(7, 0)
+#define QMC_SPE_TRNSYNC_TX(x) FIELD_PREP(QMC_SPE_TRNSYNC_TX_MASK, x)
/* Interrupt related registers bits */
-#define QMC_INT_V (1 << 15)
-#define QMC_INT_W (1 << 14)
-#define QMC_INT_NID (1 << 13)
-#define QMC_INT_IDL (1 << 12)
-#define QMC_INT_GET_CHANNEL(x) (((x) & 0x0FC0) >> 6)
-#define QMC_INT_MRF (1 << 5)
-#define QMC_INT_UN (1 << 4)
-#define QMC_INT_RXF (1 << 3)
-#define QMC_INT_BSY (1 << 2)
-#define QMC_INT_TXB (1 << 1)
-#define QMC_INT_RXB (1 << 0)
+#define QMC_INT_V BIT(15)
+#define QMC_INT_W BIT(14)
+#define QMC_INT_NID BIT(13)
+#define QMC_INT_IDL BIT(12)
+#define QMC_INT_CHANNEL_MASK GENMASK(11, 6)
+#define QMC_INT_GET_CHANNEL(x) FIELD_GET(QMC_INT_CHANNEL_MASK, x)
+#define QMC_INT_MRF BIT(5)
+#define QMC_INT_UN BIT(4)
+#define QMC_INT_RXF BIT(3)
+#define QMC_INT_BSY BIT(2)
+#define QMC_INT_TXB BIT(1)
+#define QMC_INT_RXB BIT(0)
/* BD related registers bits */
-#define QMC_BD_RX_E (1 << 15)
-#define QMC_BD_RX_W (1 << 13)
-#define QMC_BD_RX_I (1 << 12)
-#define QMC_BD_RX_L (1 << 11)
-#define QMC_BD_RX_F (1 << 10)
-#define QMC_BD_RX_CM (1 << 9)
-#define QMC_BD_RX_UB (1 << 7)
-#define QMC_BD_RX_LG (1 << 5)
-#define QMC_BD_RX_NO (1 << 4)
-#define QMC_BD_RX_AB (1 << 3)
-#define QMC_BD_RX_CR (1 << 2)
-
-#define QMC_BD_TX_R (1 << 15)
-#define QMC_BD_TX_W (1 << 13)
-#define QMC_BD_TX_I (1 << 12)
-#define QMC_BD_TX_L (1 << 11)
-#define QMC_BD_TX_TC (1 << 10)
-#define QMC_BD_TX_CM (1 << 9)
-#define QMC_BD_TX_UB (1 << 7)
-#define QMC_BD_TX_PAD (0x0f << 0)
+#define QMC_BD_RX_E BIT(15)
+#define QMC_BD_RX_W BIT(13)
+#define QMC_BD_RX_I BIT(12)
+#define QMC_BD_RX_L BIT(11)
+#define QMC_BD_RX_F BIT(10)
+#define QMC_BD_RX_CM BIT(9)
+#define QMC_BD_RX_UB BIT(7)
+#define QMC_BD_RX_LG BIT(5)
+#define QMC_BD_RX_NO BIT(4)
+#define QMC_BD_RX_AB BIT(3)
+#define QMC_BD_RX_CR BIT(2)
+
+#define QMC_BD_TX_R BIT(15)
+#define QMC_BD_TX_W BIT(13)
+#define QMC_BD_TX_I BIT(12)
+#define QMC_BD_TX_L BIT(11)
+#define QMC_BD_TX_TC BIT(10)
+#define QMC_BD_TX_CM BIT(9)
+#define QMC_BD_TX_UB BIT(7)
+#define QMC_BD_TX_PAD_MASK GENMASK(3, 0)
+#define QMC_BD_TX_PAD(x) FIELD_PREP(QMC_BD_TX_PAD_MASK, x)
/* Numbers of BDs and interrupt items */
#define QMC_NB_TXBDS 8
@@ -184,7 +215,7 @@ struct qmc_chan {
u64 rx_ts_mask;
bool is_reverse_data;
- spinlock_t tx_lock;
+ spinlock_t tx_lock; /* Protect Tx related data */
cbd_t __iomem *txbds;
cbd_t __iomem *txbd_free;
cbd_t __iomem *txbd_done;
@@ -192,7 +223,7 @@ struct qmc_chan {
u64 nb_tx_underrun;
bool is_tx_stopped;
- spinlock_t rx_lock;
+ spinlock_t rx_lock; /* Protect Rx related data */
cbd_t __iomem *rxbds;
cbd_t __iomem *rxbd_free;
cbd_t __iomem *rxbd_done;
@@ -203,13 +234,31 @@ struct qmc_chan {
bool is_rx_stopped;
};
+enum qmc_version {
+ QMC_CPM1,
+ QMC_QE,
+};
+
+struct qmc_data {
+ enum qmc_version version;
+ u32 tstate; /* Initial TSTATE value */
+ u32 rstate; /* Initial RSTATE value */
+ u32 zistate; /* Initial ZISTATE value */
+ u32 zdstate_hdlc; /* Initial ZDSTATE value (HDLC mode) */
+ u32 zdstate_transp; /* Initial ZDSTATE value (Transparent mode) */
+ u32 rpack; /* Initial RPACK value */
+};
+
struct qmc {
struct device *dev;
+ const struct qmc_data *data;
struct tsa_serial *tsa_serial;
void __iomem *scc_regs;
void __iomem *scc_pram;
void __iomem *dpram;
u16 scc_pram_offset;
+ u32 dpram_offset;
+ u32 qe_subblock;
cbd_t __iomem *bd_table;
dma_addr_t bd_dma_addr;
size_t bd_size;
@@ -222,6 +271,11 @@ struct qmc {
struct qmc_chan *chans[64];
};
+static void qmc_write8(void __iomem *addr, u8 val)
+{
+ iowrite8(val, addr);
+}
+
static void qmc_write16(void __iomem *addr, u16 val)
{
iowrite16be(val, addr);
@@ -262,6 +316,13 @@ static void qmc_setbits32(void __iomem *addr, u32 set)
qmc_write32(addr, qmc_read32(addr) | set);
}
+static bool qmc_is_qe(const struct qmc *qmc)
+{
+ if (IS_ENABLED(CONFIG_QUICC_ENGINE) && IS_ENABLED(CONFIG_CPM))
+ return qmc->data->version == QMC_QE;
+
+ return IS_ENABLED(CONFIG_QUICC_ENGINE);
+}
int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info)
{
@@ -348,8 +409,8 @@ int qmc_chan_set_param(struct qmc_chan *chan, const struct qmc_chan_param *param
switch (param->mode) {
case QMC_HDLC:
- if ((param->hdlc.max_rx_buf_size % 4) ||
- (param->hdlc.max_rx_buf_size < 8))
+ if (param->hdlc.max_rx_buf_size % 4 ||
+ param->hdlc.max_rx_buf_size < 8)
return -EINVAL;
qmc_write16(chan->qmc->scc_pram + QMC_GBL_MRBLR,
@@ -532,11 +593,12 @@ int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
/* Restart receiver if needed */
if (chan->is_rx_halted && !chan->is_rx_stopped) {
/* Restart receiver */
- if (chan->mode == QMC_TRANSPARENT)
- qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080);
- else
- qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080);
- qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000);
+ qmc_write32(chan->s_param + QMC_SPE_RPACK, chan->qmc->data->rpack);
+ qmc_write32(chan->s_param + QMC_SPE_ZDSTATE,
+ chan->mode == QMC_TRANSPARENT ?
+ chan->qmc->data->zdstate_transp :
+ chan->qmc->data->zdstate_hdlc);
+ qmc_write32(chan->s_param + QMC_SPE_RSTATE, chan->qmc->data->rstate);
chan->is_rx_halted = false;
}
chan->rx_pending++;
@@ -641,7 +703,7 @@ static int qmc_chan_setup_tsa_64rxtx(struct qmc_chan *chan, const struct tsa_ser
return -EINVAL;
}
- val = QMC_TSA_VALID | QMC_TSA_MASK | QMC_TSA_CHANNEL(chan->id);
+ val = QMC_TSA_VALID | QMC_TSA_MASK_8BIT | QMC_TSA_CHANNEL(chan->id);
/* Check entries based on Rx stuff*/
for (i = 0; i < info->nb_rx_ts; i++) {
@@ -662,7 +724,7 @@ static int qmc_chan_setup_tsa_64rxtx(struct qmc_chan *chan, const struct tsa_ser
continue;
qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2),
- ~QMC_TSA_WRAP, enable ? val : 0x0000);
+ (u16)~QMC_TSA_WRAP, enable ? val : 0x0000);
}
return 0;
@@ -677,7 +739,7 @@ static int qmc_chan_setup_tsa_32rx(struct qmc_chan *chan, const struct tsa_seria
/* Use a Rx 32 entries table */
- val = QMC_TSA_VALID | QMC_TSA_MASK | QMC_TSA_CHANNEL(chan->id);
+ val = QMC_TSA_VALID | QMC_TSA_MASK_8BIT | QMC_TSA_CHANNEL(chan->id);
/* Check entries based on Rx stuff */
for (i = 0; i < info->nb_rx_ts; i++) {
@@ -698,7 +760,7 @@ static int qmc_chan_setup_tsa_32rx(struct qmc_chan *chan, const struct tsa_seria
continue;
qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2),
- ~QMC_TSA_WRAP, enable ? val : 0x0000);
+ (u16)~QMC_TSA_WRAP, enable ? val : 0x0000);
}
return 0;
@@ -713,7 +775,7 @@ static int qmc_chan_setup_tsa_32tx(struct qmc_chan *chan, const struct tsa_seria
/* Use a Tx 32 entries table */
- val = QMC_TSA_VALID | QMC_TSA_MASK | QMC_TSA_CHANNEL(chan->id);
+ val = QMC_TSA_VALID | QMC_TSA_MASK_8BIT | QMC_TSA_CHANNEL(chan->id);
/* Check entries based on Tx stuff */
for (i = 0; i < info->nb_tx_ts; i++) {
@@ -734,7 +796,7 @@ static int qmc_chan_setup_tsa_32tx(struct qmc_chan *chan, const struct tsa_seria
continue;
qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATTX + (i * 2),
- ~QMC_TSA_WRAP, enable ? val : 0x0000);
+ (u16)~QMC_TSA_WRAP, enable ? val : 0x0000);
}
return 0;
@@ -774,11 +836,18 @@ static int qmc_chan_setup_tsa_rx(struct qmc_chan *chan, bool enable)
return qmc_chan_setup_tsa_32rx(chan, &info, enable);
}
-static int qmc_chan_command(struct qmc_chan *chan, u8 qmc_opcode)
+static int qmc_chan_cpm1_command(struct qmc_chan *chan, u8 qmc_opcode)
{
return cpm_command(chan->id << 2, (qmc_opcode << 4) | 0x0E);
}
+static int qmc_chan_qe_command(struct qmc_chan *chan, u32 cmd)
+{
+ if (!qe_issue_cmd(cmd, chan->qmc->qe_subblock, chan->id, 0))
+ return -EIO;
+ return 0;
+}
+
static int qmc_chan_stop_rx(struct qmc_chan *chan)
{
unsigned long flags;
@@ -793,7 +862,9 @@ static int qmc_chan_stop_rx(struct qmc_chan *chan)
}
/* Send STOP RECEIVE command */
- ret = qmc_chan_command(chan, 0x0);
+ ret = qmc_is_qe(chan->qmc) ?
+ qmc_chan_qe_command(chan, QE_QMC_STOP_RX) :
+ qmc_chan_cpm1_command(chan, 0x0);
if (ret) {
dev_err(chan->qmc->dev, "chan %u: Send STOP RECEIVE failed (%d)\n",
chan->id, ret);
@@ -830,7 +901,9 @@ static int qmc_chan_stop_tx(struct qmc_chan *chan)
}
/* Send STOP TRANSMIT command */
- ret = qmc_chan_command(chan, 0x1);
+ ret = qmc_is_qe(chan->qmc) ?
+ qmc_chan_qe_command(chan, QE_QMC_STOP_TX) :
+ qmc_chan_cpm1_command(chan, 0x1);
if (ret) {
dev_err(chan->qmc->dev, "chan %u: Send STOP TRANSMIT failed (%d)\n",
chan->id, ret);
@@ -889,6 +962,7 @@ EXPORT_SYMBOL(qmc_chan_stop);
static int qmc_setup_chan_trnsync(struct qmc *qmc, struct qmc_chan *chan)
{
struct tsa_serial_info info;
+ unsigned int w_rx, w_tx;
u16 first_rx, last_tx;
u16 trnsync;
int ret;
@@ -898,6 +972,14 @@ static int qmc_setup_chan_trnsync(struct qmc *qmc, struct qmc_chan *chan)
if (ret)
return ret;
+ w_rx = hweight64(chan->rx_ts_mask);
+ w_tx = hweight64(chan->tx_ts_mask);
+ if (w_rx <= 1 && w_tx <= 1) {
+ dev_dbg(qmc->dev, "only one or zero ts -> disable trnsync\n");
+ qmc_clrbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_TRANSP_SYNC);
+ return 0;
+ }
+
/* Find the first Rx TS allocated to the channel */
first_rx = chan->rx_ts_mask ? __ffs64(chan->rx_ts_mask) + 1 : 0;
@@ -911,6 +993,7 @@ static int qmc_setup_chan_trnsync(struct qmc *qmc, struct qmc_chan *chan)
trnsync |= QMC_SPE_TRNSYNC_TX((last_tx % info.nb_tx_ts) * 2);
qmc_write16(chan->s_param + QMC_SPE_TRNSYNC, trnsync);
+ qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_TRANSP_SYNC);
dev_dbg(qmc->dev, "chan %u: trnsync=0x%04x, rx %u/%u 0x%llx, tx %u/%u 0x%llx\n",
chan->id, trnsync,
@@ -940,19 +1023,22 @@ static int qmc_chan_start_rx(struct qmc_chan *chan)
goto end;
}
- ret = qmc_setup_chan_trnsync(chan->qmc, chan);
- if (ret) {
- dev_err(chan->qmc->dev, "chan %u: setup TRNSYNC failed (%d)\n",
- chan->id, ret);
- goto end;
+ if (chan->mode == QMC_TRANSPARENT) {
+ ret = qmc_setup_chan_trnsync(chan->qmc, chan);
+ if (ret) {
+ dev_err(chan->qmc->dev, "chan %u: setup TRNSYNC failed (%d)\n",
+ chan->id, ret);
+ goto end;
+ }
}
/* Restart the receiver */
- if (chan->mode == QMC_TRANSPARENT)
- qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080);
- else
- qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080);
- qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000);
+ qmc_write32(chan->s_param + QMC_SPE_RPACK, chan->qmc->data->rpack);
+ qmc_write32(chan->s_param + QMC_SPE_ZDSTATE,
+ chan->mode == QMC_TRANSPARENT ?
+ chan->qmc->data->zdstate_transp :
+ chan->qmc->data->zdstate_hdlc);
+ qmc_write32(chan->s_param + QMC_SPE_RSTATE, chan->qmc->data->rstate);
chan->is_rx_halted = false;
chan->is_rx_stopped = false;
@@ -982,11 +1068,13 @@ static int qmc_chan_start_tx(struct qmc_chan *chan)
goto end;
}
- ret = qmc_setup_chan_trnsync(chan->qmc, chan);
- if (ret) {
- dev_err(chan->qmc->dev, "chan %u: setup TRNSYNC failed (%d)\n",
- chan->id, ret);
- goto end;
+ if (chan->mode == QMC_TRANSPARENT) {
+ ret = qmc_setup_chan_trnsync(chan->qmc, chan);
+ if (ret) {
+ dev_err(chan->qmc->dev, "chan %u: setup TRNSYNC failed (%d)\n",
+ chan->id, ret);
+ goto end;
+ }
}
/*
@@ -1096,8 +1184,8 @@ static void qmc_chan_reset_tx(struct qmc_chan *chan)
qmc_read16(chan->s_param + QMC_SPE_TBASE));
/* Reset TSTATE and ZISTATE to their initial value */
- qmc_write32(chan->s_param + QMC_SPE_TSTATE, 0x30000000);
- qmc_write32(chan->s_param + QMC_SPE_ZISTATE, 0x00000100);
+ qmc_write32(chan->s_param + QMC_SPE_TSTATE, chan->qmc->data->tstate);
+ qmc_write32(chan->s_param + QMC_SPE_ZISTATE, chan->qmc->data->zistate);
spin_unlock_irqrestore(&chan->tx_lock, flags);
}
@@ -1127,7 +1215,7 @@ static int qmc_check_chans(struct qmc *qmc)
if (ret)
return ret;
- if ((info.nb_tx_ts > 64) || (info.nb_rx_ts > 64)) {
+ if (info.nb_tx_ts > 64 || info.nb_rx_ts > 64) {
dev_err(qmc->dev, "Number of TSA Tx/Rx TS assigned not supported\n");
return -EINVAL;
}
@@ -1136,7 +1224,7 @@ static int qmc_check_chans(struct qmc *qmc)
* If more than 32 TS are assigned to this serial, one common table is
* used for Tx and Rx and so masks must be equal for all channels.
*/
- if ((info.nb_tx_ts > 32) || (info.nb_rx_ts > 32)) {
+ if (info.nb_tx_ts > 32 || info.nb_rx_ts > 32) {
if (info.nb_tx_ts != info.nb_rx_ts) {
dev_err(qmc->dev, "Number of TSA Tx/Rx TS assigned are not equal\n");
return -EINVAL;
@@ -1368,13 +1456,14 @@ static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan)
val = ((chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS)) + QMC_NB_TXBDS) * sizeof(cbd_t);
qmc_write16(chan->s_param + QMC_SPE_RBASE, val);
qmc_write16(chan->s_param + QMC_SPE_RBPTR, val);
- qmc_write32(chan->s_param + QMC_SPE_TSTATE, 0x30000000);
- qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000);
- qmc_write32(chan->s_param + QMC_SPE_ZISTATE, 0x00000100);
+ qmc_write32(chan->s_param + QMC_SPE_TSTATE, chan->qmc->data->tstate);
+ qmc_write32(chan->s_param + QMC_SPE_RSTATE, chan->qmc->data->rstate);
+ qmc_write32(chan->s_param + QMC_SPE_ZISTATE, chan->qmc->data->zistate);
+ qmc_write32(chan->s_param + QMC_SPE_RPACK, chan->qmc->data->rpack);
if (chan->mode == QMC_TRANSPARENT) {
- qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080);
+ qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, chan->qmc->data->zdstate_transp);
qmc_write16(chan->s_param + QMC_SPE_TMRBLR, 60);
- val = QMC_SPE_CHAMR_MODE_TRANSP | QMC_SPE_CHAMR_TRANSP_SYNC;
+ val = QMC_SPE_CHAMR_MODE_TRANSP;
if (chan->is_reverse_data)
val |= QMC_SPE_CHAMR_TRANSP_RD;
qmc_write16(chan->s_param + QMC_SPE_CHAMR, val);
@@ -1382,10 +1471,10 @@ static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan)
if (ret)
return ret;
} else {
- qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080);
+ qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, chan->qmc->data->zdstate_hdlc);
qmc_write16(chan->s_param + QMC_SPE_MFLR, 60);
qmc_write16(chan->s_param + QMC_SPE_CHAMR,
- QMC_SPE_CHAMR_MODE_HDLC | QMC_SPE_CHAMR_HDLC_IDLM);
+ QMC_SPE_CHAMR_MODE_HDLC | QMC_SPE_CHAMR_HDLC_IDLM);
}
/* Do not enable interrupts now. They will be enabled later */
@@ -1510,11 +1599,14 @@ static void qmc_irq_gint(struct qmc *qmc)
/* Restart the receiver if needed */
spin_lock_irqsave(&chan->rx_lock, flags);
if (chan->rx_pending && !chan->is_rx_stopped) {
- if (chan->mode == QMC_TRANSPARENT)
- qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080);
- else
- qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080);
- qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000);
+ qmc_write32(chan->s_param + QMC_SPE_RPACK,
+ chan->qmc->data->rpack);
+ qmc_write32(chan->s_param + QMC_SPE_ZDSTATE,
+ chan->mode == QMC_TRANSPARENT ?
+ chan->qmc->data->zdstate_transp :
+ chan->qmc->data->zdstate_hdlc);
+ qmc_write32(chan->s_param + QMC_SPE_RSTATE,
+ chan->qmc->data->rstate);
chan->is_rx_halted = false;
} else {
chan->is_rx_halted = true;
@@ -1558,27 +1650,74 @@ static irqreturn_t qmc_irq_handler(int irq, void *priv)
return IRQ_HANDLED;
}
-static int qmc_probe(struct platform_device *pdev)
+static int qmc_qe_soft_qmc_init(struct qmc *qmc, struct device_node *np)
{
- struct device_node *np = pdev->dev.of_node;
- unsigned int nb_chans;
- struct resource *res;
- struct qmc *qmc;
- int irq;
+ struct qe_firmware_info *qe_fw_info;
+ const struct qe_firmware *qe_fw;
+ const struct firmware *fw;
+ const char *filename;
int ret;
- qmc = devm_kzalloc(&pdev->dev, sizeof(*qmc), GFP_KERNEL);
- if (!qmc)
- return -ENOMEM;
+ ret = of_property_read_string(np, "fsl,soft-qmc", &filename);
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ /* fsl,soft-qmc property not set -> Simply do nothing */
+ return 0;
+ default:
+ dev_err(qmc->dev, "%pOF: failed to read fsl,soft-qmc\n",
+ np);
+ return ret;
+ }
- qmc->dev = &pdev->dev;
- INIT_LIST_HEAD(&qmc->chan_head);
+ qe_fw_info = qe_get_firmware_info();
+ if (qe_fw_info) {
+ if (!strstr(qe_fw_info->id, "Soft-QMC")) {
+ dev_err(qmc->dev, "Another Firmware is already loaded\n");
+ return -EALREADY;
+ }
+ dev_info(qmc->dev, "Firmware already loaded\n");
+ return 0;
+ }
+
+ dev_info(qmc->dev, "Using firmware %s\n", filename);
+
+ ret = request_firmware(&fw, filename, qmc->dev);
+ if (ret) {
+ dev_err(qmc->dev, "Failed to request firmware %s\n", filename);
+ return ret;
+ }
+
+ qe_fw = (const struct qe_firmware *)fw->data;
+
+ if (fw->size < sizeof(qe_fw->header) ||
+ be32_to_cpu(qe_fw->header.length) != fw->size) {
+ dev_err(qmc->dev, "Invalid firmware %s\n", filename);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ ret = qe_upload_firmware(qe_fw);
+ if (ret) {
+ dev_err(qmc->dev, "Failed to load firmware %s\n", filename);
+ goto end;
+ }
+
+ ret = 0;
+end:
+ release_firmware(fw);
+ return ret;
+}
+
+static int qmc_cpm1_init_resources(struct qmc *qmc, struct platform_device *pdev)
+{
+ struct resource *res;
qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "scc_regs");
if (IS_ERR(qmc->scc_regs))
return PTR_ERR(qmc->scc_regs);
-
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scc_pram");
if (!res)
return -EINVAL;
@@ -1591,44 +1730,214 @@ static int qmc_probe(struct platform_device *pdev)
if (IS_ERR(qmc->dpram))
return PTR_ERR(qmc->dpram);
+ return 0;
+}
+
+static int qmc_qe_init_resources(struct qmc *qmc, struct platform_device *pdev)
+{
+ struct resource *res;
+ int ucc_num;
+ s32 info;
+
+ qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "ucc_regs");
+ if (IS_ERR(qmc->scc_regs))
+ return PTR_ERR(qmc->scc_regs);
+
+ ucc_num = tsa_serial_get_num(qmc->tsa_serial);
+ if (ucc_num < 0)
+ return dev_err_probe(qmc->dev, ucc_num, "Failed to get UCC num\n");
+
+ qmc->qe_subblock = ucc_slow_get_qe_cr_subblock(ucc_num);
+ if (qmc->qe_subblock == QE_CR_SUBBLOCK_INVALID) {
+ dev_err(qmc->dev, "Unsupported ucc num %u\n", ucc_num);
+ return -EINVAL;
+ }
+ /* Allocate the 'Global Multichannel Parameters' and the
+ * 'Framer parameters' areas. The 'Framer parameters' area
+ * is located right after the 'Global Multichannel Parameters'.
+ * The 'Framer parameters' need 1 byte per receive and transmit
+ * channel. The maximum number of receive or transmit channel
+ * is 64. So reserve 2 * 64 bytes for the 'Framer parameters'.
+ */
+ info = devm_qe_muram_alloc(qmc->dev, UCC_SLOW_PRAM_SIZE + 2 * 64,
+ ALIGNMENT_OF_UCC_SLOW_PRAM);
+ if (info < 0)
+ return info;
+
+ if (!qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, qmc->qe_subblock,
+ QE_CR_PROTOCOL_UNSPECIFIED, info)) {
+ dev_err(qmc->dev, "QE_ASSIGN_PAGE_TO_DEVICE cmd failed");
+ return -EIO;
+ }
+ qmc->scc_pram = qe_muram_addr(info);
+ qmc->scc_pram_offset = info;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dpram");
+ if (!res)
+ return -EINVAL;
+ qmc->dpram_offset = res->start - qe_muram_dma(qe_muram_addr(0));
+ qmc->dpram = devm_ioremap_resource(qmc->dev, res);
+ if (IS_ERR(qmc->scc_pram))
+ return PTR_ERR(qmc->scc_pram);
+
+ return 0;
+}
+
+static int qmc_init_resources(struct qmc *qmc, struct platform_device *pdev)
+{
+ return qmc_is_qe(qmc) ?
+ qmc_qe_init_resources(qmc, pdev) :
+ qmc_cpm1_init_resources(qmc, pdev);
+}
+
+static int qmc_cpm1_init_scc(struct qmc *qmc)
+{
+ u32 val;
+ int ret;
+
+ /* Connect the serial (SCC) to TSA */
+ ret = tsa_serial_connect(qmc->tsa_serial);
+ if (ret)
+ return dev_err_probe(qmc->dev, ret, "Failed to connect TSA serial\n");
+
+ /* Init GMSR_H and GMSR_L registers */
+ val = SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP;
+ qmc_write32(qmc->scc_regs + SCC_GSMRH, val);
+
+ /* enable QMC mode */
+ qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_CPM1_GSMRL_MODE_QMC);
+
+ /* Disable and clear interrupts */
+ qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000);
+ qmc_write16(qmc->scc_regs + SCC_SCCE, 0x000F);
+
+ return 0;
+}
+
+static int qmc_qe_init_ucc(struct qmc *qmc)
+{
+ u32 val;
+ int ret;
+
+ /* Set the UCC in slow mode */
+ qmc_write8(qmc->scc_regs + SCC_QE_UCC_GUEMR,
+ UCC_GUEMR_SET_RESERVED3 | UCC_GUEMR_MODE_SLOW_RX | UCC_GUEMR_MODE_SLOW_TX);
+
+ /* Connect the serial (UCC) to TSA */
+ ret = tsa_serial_connect(qmc->tsa_serial);
+ if (ret)
+ return dev_err_probe(qmc->dev, ret, "Failed to connect TSA serial\n");
+
+ /* Initialize the QMC tx startup addresses */
+ if (!qe_issue_cmd(QE_PUSHSCHED, qmc->qe_subblock,
+ QE_CR_PROTOCOL_UNSPECIFIED, 0x80)) {
+ dev_err(qmc->dev, "QE_CMD_PUSH_SCHED tx cmd failed");
+ ret = -EIO;
+ goto err_tsa_serial_disconnect;
+ }
+
+ /* Initialize the QMC rx startup addresses */
+ if (!qe_issue_cmd(QE_PUSHSCHED, qmc->qe_subblock | 0x00020000,
+ QE_CR_PROTOCOL_UNSPECIFIED, 0x82)) {
+ dev_err(qmc->dev, "QE_CMD_PUSH_SCHED rx cmd failed");
+ ret = -EIO;
+ goto err_tsa_serial_disconnect;
+ }
+
+ /* Re-init RXPTR and TXPTR with the content of RX_S_PTR and
+ * TX_S_PTR (RX_S_PTR and TX_S_PTR are initialized during
+ * qmc_setup_tsa() call
+ */
+ val = qmc_read16(qmc->scc_pram + QMC_GBL_RX_S_PTR);
+ qmc_write16(qmc->scc_pram + QMC_GBL_RXPTR, val);
+ val = qmc_read16(qmc->scc_pram + QMC_GBL_TX_S_PTR);
+ qmc_write16(qmc->scc_pram + QMC_GBL_TXPTR, val);
+
+ /* Init GUMR_H and GUMR_L registers (SCC GSMR_H and GSMR_L) */
+ val = SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP |
+ SCC_GSMRH_TRX | SCC_GSMRH_TTX;
+ qmc_write32(qmc->scc_regs + SCC_GSMRH, val);
+
+ /* enable QMC mode */
+ qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_QE_GSMRL_MODE_QMC);
+
+ /* Disable and clear interrupts */
+ qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000);
+ qmc_write16(qmc->scc_regs + SCC_SCCE, 0x000F);
+
+ return 0;
+
+err_tsa_serial_disconnect:
+ tsa_serial_disconnect(qmc->tsa_serial);
+ return ret;
+}
+
+static int qmc_init_xcc(struct qmc *qmc)
+{
+ return qmc_is_qe(qmc) ?
+ qmc_qe_init_ucc(qmc) :
+ qmc_cpm1_init_scc(qmc);
+}
+
+static void qmc_exit_xcc(struct qmc *qmc)
+{
+ /* Disconnect the serial from TSA */
+ tsa_serial_disconnect(qmc->tsa_serial);
+}
+
+static int qmc_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ unsigned int nb_chans;
+ struct qmc *qmc;
+ int irq;
+ int ret;
+
+ qmc = devm_kzalloc(&pdev->dev, sizeof(*qmc), GFP_KERNEL);
+ if (!qmc)
+ return -ENOMEM;
+
+ qmc->dev = &pdev->dev;
+ qmc->data = of_device_get_match_data(&pdev->dev);
+ if (!qmc->data) {
+ dev_err(qmc->dev, "Missing match data\n");
+ return -EINVAL;
+ }
+ INIT_LIST_HEAD(&qmc->chan_head);
+
qmc->tsa_serial = devm_tsa_serial_get_byphandle(qmc->dev, np, "fsl,tsa-serial");
if (IS_ERR(qmc->tsa_serial)) {
return dev_err_probe(qmc->dev, PTR_ERR(qmc->tsa_serial),
"Failed to get TSA serial\n");
}
- /* Connect the serial (SCC) to TSA */
- ret = tsa_serial_connect(qmc->tsa_serial);
- if (ret) {
- dev_err(qmc->dev, "Failed to connect TSA serial\n");
+ ret = qmc_init_resources(qmc, pdev);
+ if (ret)
return ret;
+
+ if (qmc_is_qe(qmc)) {
+ ret = qmc_qe_soft_qmc_init(qmc, np);
+ if (ret)
+ return ret;
}
/* Parse channels informationss */
ret = qmc_of_parse_chans(qmc, np);
if (ret)
- goto err_tsa_serial_disconnect;
+ return ret;
nb_chans = qmc_nb_chans(qmc);
- /* Init GMSR_H and GMSR_L registers */
- qmc_write32(qmc->scc_regs + SCC_GSMRH,
- SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP);
-
- /* enable QMC mode */
- qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC);
-
/*
* Allocate the buffer descriptor table
* 8 rx and 8 tx descriptors per channel
*/
qmc->bd_size = (nb_chans * (QMC_NB_TXBDS + QMC_NB_RXBDS)) * sizeof(cbd_t);
qmc->bd_table = dmam_alloc_coherent(qmc->dev, qmc->bd_size,
- &qmc->bd_dma_addr, GFP_KERNEL);
+ &qmc->bd_dma_addr, GFP_KERNEL);
if (!qmc->bd_table) {
dev_err(qmc->dev, "Failed to allocate bd table\n");
- ret = -ENOMEM;
- goto err_tsa_serial_disconnect;
+ return -ENOMEM;
}
memset(qmc->bd_table, 0, qmc->bd_size);
@@ -1637,11 +1946,10 @@ static int qmc_probe(struct platform_device *pdev)
/* Allocate the interrupt table */
qmc->int_size = QMC_NB_INTS * sizeof(u16);
qmc->int_table = dmam_alloc_coherent(qmc->dev, qmc->int_size,
- &qmc->int_dma_addr, GFP_KERNEL);
+ &qmc->int_dma_addr, GFP_KERNEL);
if (!qmc->int_table) {
dev_err(qmc->dev, "Failed to allocate interrupt table\n");
- ret = -ENOMEM;
- goto err_tsa_serial_disconnect;
+ return -ENOMEM;
}
memset(qmc->int_table, 0, qmc->int_size);
@@ -1658,40 +1966,61 @@ static int qmc_probe(struct platform_device *pdev)
qmc_write32(qmc->scc_pram + QMC_GBL_C_MASK32, 0xDEBB20E3);
qmc_write16(qmc->scc_pram + QMC_GBL_C_MASK16, 0xF0B8);
+ if (qmc_is_qe(qmc)) {
+ /* Zeroed the reserved area */
+ memset_io(qmc->scc_pram + QMC_QE_GBL_RSV_B0_START, 0,
+ QMC_QE_GBL_RSV_B0_SIZE);
+
+ qmc_write32(qmc->scc_pram + QMC_QE_GBL_GCSBASE, qmc->dpram_offset);
+
+ /* Init 'framer parameters' area and set the base addresses */
+ memset_io(qmc->scc_pram + UCC_SLOW_PRAM_SIZE, 0x01, 64);
+ memset_io(qmc->scc_pram + UCC_SLOW_PRAM_SIZE + 64, 0x01, 64);
+ qmc_write16(qmc->scc_pram + QMC_QE_GBL_RX_FRM_BASE,
+ qmc->scc_pram_offset + UCC_SLOW_PRAM_SIZE);
+ qmc_write16(qmc->scc_pram + QMC_QE_GBL_TX_FRM_BASE,
+ qmc->scc_pram_offset + UCC_SLOW_PRAM_SIZE + 64);
+ }
+
ret = qmc_init_tsa(qmc);
if (ret)
- goto err_tsa_serial_disconnect;
+ return ret;
qmc_write16(qmc->scc_pram + QMC_GBL_QMCSTATE, 0x8000);
ret = qmc_setup_chans(qmc);
if (ret)
- goto err_tsa_serial_disconnect;
+ return ret;
/* Init interrupts table */
ret = qmc_setup_ints(qmc);
if (ret)
- goto err_tsa_serial_disconnect;
+ return ret;
- /* Disable and clear interrupts, set the irq handler */
- qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000);
- qmc_write16(qmc->scc_regs + SCC_SCCE, 0x000F);
+ /* Init SCC (CPM1) or UCC (QE) */
+ ret = qmc_init_xcc(qmc);
+ if (ret)
+ return ret;
+
+ /* Set the irq handler */
irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- goto err_tsa_serial_disconnect;
+ if (irq < 0) {
+ ret = irq;
+ goto err_exit_xcc;
+ }
ret = devm_request_irq(qmc->dev, irq, qmc_irq_handler, 0, "qmc", qmc);
if (ret < 0)
- goto err_tsa_serial_disconnect;
+ goto err_exit_xcc;
/* Enable interrupts */
qmc_write16(qmc->scc_regs + SCC_SCCM,
- SCC_SCCE_IQOV | SCC_SCCE_GINT | SCC_SCCE_GUN | SCC_SCCE_GOV);
+ SCC_SCCE_IQOV | SCC_SCCE_GINT | SCC_SCCE_GUN | SCC_SCCE_GOV);
ret = qmc_finalize_chans(qmc);
if (ret < 0)
goto err_disable_intr;
- /* Enable transmiter and receiver */
+ /* Enable transmitter and receiver */
qmc_setbits32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
platform_set_drvdata(pdev, qmc);
@@ -1709,8 +2038,8 @@ err_disable_txrx:
err_disable_intr:
qmc_write16(qmc->scc_regs + SCC_SCCM, 0);
-err_tsa_serial_disconnect:
- tsa_serial_disconnect(qmc->tsa_serial);
+err_exit_xcc:
+ qmc_exit_xcc(qmc);
return ret;
}
@@ -1718,18 +2047,43 @@ static void qmc_remove(struct platform_device *pdev)
{
struct qmc *qmc = platform_get_drvdata(pdev);
- /* Disable transmiter and receiver */
+ /* Disable transmitter and receiver */
qmc_setbits32(qmc->scc_regs + SCC_GSMRL, 0);
/* Disable interrupts */
qmc_write16(qmc->scc_regs + SCC_SCCM, 0);
- /* Disconnect the serial from TSA */
- tsa_serial_disconnect(qmc->tsa_serial);
+ /* Exit SCC (CPM1) or UCC (QE) */
+ qmc_exit_xcc(qmc);
}
+static const struct qmc_data qmc_data_cpm1 __maybe_unused = {
+ .version = QMC_CPM1,
+ .tstate = 0x30000000,
+ .rstate = 0x31000000,
+ .zistate = 0x00000100,
+ .zdstate_hdlc = 0x00000080,
+ .zdstate_transp = 0x18000080,
+ .rpack = 0x00000000,
+};
+
+static const struct qmc_data qmc_data_qe __maybe_unused = {
+ .version = QMC_QE,
+ .tstate = 0x30000000,
+ .rstate = 0x30000000,
+ .zistate = 0x00000200,
+ .zdstate_hdlc = 0x80FFFFE0,
+ .zdstate_transp = 0x003FFFE2,
+ .rpack = 0x80000000,
+};
+
static const struct of_device_id qmc_id_table[] = {
- { .compatible = "fsl,cpm1-scc-qmc" },
+#if IS_ENABLED(CONFIG_CPM1)
+ { .compatible = "fsl,cpm1-scc-qmc", .data = &qmc_data_cpm1 },
+#endif
+#if IS_ENABLED(CONFIG_QUICC_ENGINE)
+ { .compatible = "fsl,qe-ucc-qmc", .data = &qmc_data_qe },
+#endif
{} /* sentinel */
};
MODULE_DEVICE_TABLE(of, qmc_id_table);
@@ -1740,7 +2094,7 @@ static struct platform_driver qmc_driver = {
.of_match_table = of_match_ptr(qmc_id_table),
},
.probe = qmc_probe,
- .remove_new = qmc_remove,
+ .remove = qmc_remove,
};
module_platform_driver(qmc_driver);
@@ -1777,13 +2131,28 @@ static struct qmc_chan *qmc_chan_get_from_qmc(struct device_node *qmc_np, unsign
return qmc_chan;
}
-struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phandle_name)
+int qmc_chan_count_phandles(struct device_node *np, const char *phandles_name)
+{
+ int count;
+
+ /* phandles are fixed args phandles with one arg */
+ count = of_count_phandle_with_args(np, phandles_name, NULL);
+ if (count < 0)
+ return count;
+
+ return count / 2;
+}
+EXPORT_SYMBOL(qmc_chan_count_phandles);
+
+struct qmc_chan *qmc_chan_get_byphandles_index(struct device_node *np,
+ const char *phandles_name,
+ int index)
{
struct of_phandle_args out_args;
struct qmc_chan *qmc_chan;
int ret;
- ret = of_parse_phandle_with_fixed_args(np, phandle_name, 1, 0,
+ ret = of_parse_phandle_with_fixed_args(np, phandles_name, 1, index,
&out_args);
if (ret < 0)
return ERR_PTR(ret);
@@ -1797,7 +2166,7 @@ struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phan
of_node_put(out_args.np);
return qmc_chan;
}
-EXPORT_SYMBOL(qmc_chan_get_byphandle);
+EXPORT_SYMBOL(qmc_chan_get_byphandles_index);
struct qmc_chan *qmc_chan_get_bychild(struct device_node *np)
{
@@ -1827,9 +2196,10 @@ static void devm_qmc_chan_release(struct device *dev, void *res)
qmc_chan_put(*qmc_chan);
}
-struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev,
- struct device_node *np,
- const char *phandle_name)
+struct qmc_chan *devm_qmc_chan_get_byphandles_index(struct device *dev,
+ struct device_node *np,
+ const char *phandles_name,
+ int index)
{
struct qmc_chan *qmc_chan;
struct qmc_chan **dr;
@@ -1838,7 +2208,7 @@ struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev,
if (!dr)
return ERR_PTR(-ENOMEM);
- qmc_chan = qmc_chan_get_byphandle(np, phandle_name);
+ qmc_chan = qmc_chan_get_byphandles_index(np, phandles_name, index);
if (!IS_ERR(qmc_chan)) {
*dr = qmc_chan;
devres_add(dev, dr);
@@ -1848,7 +2218,7 @@ struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev,
return qmc_chan;
}
-EXPORT_SYMBOL(devm_qmc_chan_get_byphandle);
+EXPORT_SYMBOL(devm_qmc_chan_get_byphandles_index);
struct qmc_chan *devm_qmc_chan_get_bychild(struct device *dev,
struct device_node *np)
@@ -1873,5 +2243,5 @@ struct qmc_chan *devm_qmc_chan_get_bychild(struct device *dev,
EXPORT_SYMBOL(devm_qmc_chan_get_bychild);
MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
-MODULE_DESCRIPTION("CPM QMC driver");
+MODULE_DESCRIPTION("CPM/QE QMC driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c
index 6c5741cf5e9d..4a88e54d25b9 100644
--- a/drivers/soc/fsl/qe/tsa.c
+++ b/drivers/soc/fsl/qe/tsa.c
@@ -9,6 +9,8 @@
#include "tsa.h"
#include <dt-bindings/soc/cpm1-fsl,tsa.h>
+#include <dt-bindings/soc/qe-fsl,tsa.h>
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -16,86 +18,116 @@
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <soc/fsl/qe/ucc.h>
+
+/* TSA SI RAM routing tables entry (CPM1) */
+#define TSA_CPM1_SIRAM_ENTRY_LAST BIT(16)
+#define TSA_CPM1_SIRAM_ENTRY_BYTE BIT(17)
+#define TSA_CPM1_SIRAM_ENTRY_CNT_MASK GENMASK(21, 18)
+#define TSA_CPM1_SIRAM_ENTRY_CNT(x) FIELD_PREP(TSA_CPM1_SIRAM_ENTRY_CNT_MASK, x)
+#define TSA_CPM1_SIRAM_ENTRY_CSEL_MASK GENMASK(24, 22)
+#define TSA_CPM1_SIRAM_ENTRY_CSEL_NU FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x0)
+#define TSA_CPM1_SIRAM_ENTRY_CSEL_SCC2 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x2)
+#define TSA_CPM1_SIRAM_ENTRY_CSEL_SCC3 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x3)
+#define TSA_CPM1_SIRAM_ENTRY_CSEL_SCC4 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x4)
+#define TSA_CPM1_SIRAM_ENTRY_CSEL_SMC1 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x5)
+#define TSA_CPM1_SIRAM_ENTRY_CSEL_SMC2 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x6)
+
+/* TSA SI RAM routing tables entry (QE) */
+#define TSA_QE_SIRAM_ENTRY_LAST BIT(0)
+#define TSA_QE_SIRAM_ENTRY_BYTE BIT(1)
+#define TSA_QE_SIRAM_ENTRY_CNT_MASK GENMASK(4, 2)
+#define TSA_QE_SIRAM_ENTRY_CNT(x) FIELD_PREP(TSA_QE_SIRAM_ENTRY_CNT_MASK, x)
+#define TSA_QE_SIRAM_ENTRY_CSEL_MASK GENMASK(8, 5)
+#define TSA_QE_SIRAM_ENTRY_CSEL_NU FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0x0)
+#define TSA_QE_SIRAM_ENTRY_CSEL_UCC5 FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0x1)
+#define TSA_QE_SIRAM_ENTRY_CSEL_UCC1 FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0x9)
+#define TSA_QE_SIRAM_ENTRY_CSEL_UCC2 FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0xa)
+#define TSA_QE_SIRAM_ENTRY_CSEL_UCC3 FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0xb)
+#define TSA_QE_SIRAM_ENTRY_CSEL_UCC4 FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0xc)
-
-/* TSA SI RAM routing tables entry */
-#define TSA_SIRAM_ENTRY_LAST (1 << 16)
-#define TSA_SIRAM_ENTRY_BYTE (1 << 17)
-#define TSA_SIRAM_ENTRY_CNT(x) (((x) & 0x0f) << 18)
-#define TSA_SIRAM_ENTRY_CSEL_MASK (0x7 << 22)
-#define TSA_SIRAM_ENTRY_CSEL_NU (0x0 << 22)
-#define TSA_SIRAM_ENTRY_CSEL_SCC2 (0x2 << 22)
-#define TSA_SIRAM_ENTRY_CSEL_SCC3 (0x3 << 22)
-#define TSA_SIRAM_ENTRY_CSEL_SCC4 (0x4 << 22)
-#define TSA_SIRAM_ENTRY_CSEL_SMC1 (0x5 << 22)
-#define TSA_SIRAM_ENTRY_CSEL_SMC2 (0x6 << 22)
-
-/* SI mode register (32 bits) */
-#define TSA_SIMODE 0x00
-#define TSA_SIMODE_SMC2 0x80000000
-#define TSA_SIMODE_SMC1 0x00008000
-#define TSA_SIMODE_TDMA(x) ((x) << 0)
-#define TSA_SIMODE_TDMB(x) ((x) << 16)
-#define TSA_SIMODE_TDM_MASK 0x0fff
-#define TSA_SIMODE_TDM_SDM_MASK 0x0c00
-#define TSA_SIMODE_TDM_SDM_NORM 0x0000
-#define TSA_SIMODE_TDM_SDM_ECHO 0x0400
-#define TSA_SIMODE_TDM_SDM_INTL_LOOP 0x0800
-#define TSA_SIMODE_TDM_SDM_LOOP_CTRL 0x0c00
-#define TSA_SIMODE_TDM_RFSD(x) ((x) << 8)
-#define TSA_SIMODE_TDM_DSC 0x0080
-#define TSA_SIMODE_TDM_CRT 0x0040
-#define TSA_SIMODE_TDM_STZ 0x0020
-#define TSA_SIMODE_TDM_CE 0x0010
-#define TSA_SIMODE_TDM_FE 0x0008
-#define TSA_SIMODE_TDM_GM 0x0004
-#define TSA_SIMODE_TDM_TFSD(x) ((x) << 0)
-
-/* SI global mode register (8 bits) */
-#define TSA_SIGMR 0x04
-#define TSA_SIGMR_ENB (1<<3)
-#define TSA_SIGMR_ENA (1<<2)
-#define TSA_SIGMR_RDM_MASK 0x03
-#define TSA_SIGMR_RDM_STATIC_TDMA 0x00
-#define TSA_SIGMR_RDM_DYN_TDMA 0x01
-#define TSA_SIGMR_RDM_STATIC_TDMAB 0x02
-#define TSA_SIGMR_RDM_DYN_TDMAB 0x03
-
-/* SI status register (8 bits) */
-#define TSA_SISTR 0x06
-
-/* SI command register (8 bits) */
-#define TSA_SICMR 0x07
+/*
+ * SI mode register :
+ * - CPM1: 32bit register split in 2*16bit (16bit TDM)
+ * - QE: 4x16bit registers, one per TDM
+ */
+#define TSA_CPM1_SIMODE 0x00
+#define TSA_QE_SIAMR 0x00
+#define TSA_QE_SIBMR 0x02
+#define TSA_QE_SICMR 0x04
+#define TSA_QE_SIDMR 0x06
+#define TSA_CPM1_SIMODE_SMC2 BIT(31)
+#define TSA_CPM1_SIMODE_SMC1 BIT(15)
+#define TSA_CPM1_SIMODE_TDMA_MASK GENMASK(11, 0)
+#define TSA_CPM1_SIMODE_TDMA(x) FIELD_PREP(TSA_CPM1_SIMODE_TDMA_MASK, x)
+#define TSA_CPM1_SIMODE_TDMB_MASK GENMASK(27, 16)
+#define TSA_CPM1_SIMODE_TDMB(x) FIELD_PREP(TSA_CPM1_SIMODE_TDMB_MASK, x)
+#define TSA_QE_SIMODE_TDM_SAD_MASK GENMASK(15, 12)
+#define TSA_QE_SIMODE_TDM_SAD(x) FIELD_PREP(TSA_QE_SIMODE_TDM_SAD_MASK, x)
+#define TSA_CPM1_SIMODE_TDM_MASK GENMASK(11, 0)
+#define TSA_SIMODE_TDM_SDM_MASK GENMASK(11, 10)
+#define TSA_SIMODE_TDM_SDM_NORM FIELD_PREP_CONST(TSA_SIMODE_TDM_SDM_MASK, 0x0)
+#define TSA_SIMODE_TDM_SDM_ECHO FIELD_PREP_CONST(TSA_SIMODE_TDM_SDM_MASK, 0x1)
+#define TSA_SIMODE_TDM_SDM_INTL_LOOP FIELD_PREP_CONST(TSA_SIMODE_TDM_SDM_MASK, 0x2)
+#define TSA_SIMODE_TDM_SDM_LOOP_CTRL FIELD_PREP_CONST(TSA_SIMODE_TDM_SDM_MASK, 0x3)
+#define TSA_SIMODE_TDM_RFSD_MASK GENMASK(9, 8)
+#define TSA_SIMODE_TDM_RFSD(x) FIELD_PREP(TSA_SIMODE_TDM_RFSD_MASK, x)
+#define TSA_SIMODE_TDM_DSC BIT(7)
+#define TSA_SIMODE_TDM_CRT BIT(6)
+#define TSA_CPM1_SIMODE_TDM_STZ BIT(5) /* bit 5: STZ in CPM1 */
+#define TSA_QE_SIMODE_TDM_SL BIT(5) /* bit 5: SL in QE */
+#define TSA_SIMODE_TDM_CE BIT(4)
+#define TSA_SIMODE_TDM_FE BIT(3)
+#define TSA_SIMODE_TDM_GM BIT(2)
+#define TSA_SIMODE_TDM_TFSD_MASK GENMASK(1, 0)
+#define TSA_SIMODE_TDM_TFSD(x) FIELD_PREP(TSA_SIMODE_TDM_TFSD_MASK, x)
+
+/* CPM SI global mode register (8 bits) */
+#define TSA_CPM1_SIGMR 0x04
+#define TSA_CPM1_SIGMR_ENB BIT(3)
+#define TSA_CPM1_SIGMR_ENA BIT(2)
+#define TSA_CPM1_SIGMR_RDM_MASK GENMASK(1, 0)
+#define TSA_CPM1_SIGMR_RDM_STATIC_TDMA FIELD_PREP_CONST(TSA_CPM1_SIGMR_RDM_MASK, 0x0)
+#define TSA_CPM1_SIGMR_RDM_DYN_TDMA FIELD_PREP_CONST(TSA_CPM1_SIGMR_RDM_MASK, 0x1)
+#define TSA_CPM1_SIGMR_RDM_STATIC_TDMAB FIELD_PREP_CONST(TSA_CPM1_SIGMR_RDM_MASK, 0x2)
+#define TSA_CPM1_SIGMR_RDM_DYN_TDMAB FIELD_PREP_CONST(TSA_CPM1_SIGMR_RDM_MASK, 0x3)
+
+/* QE SI global mode register high (8 bits) */
+#define TSA_QE_SIGLMRH 0x08
+#define TSA_QE_SIGLMRH_END BIT(3)
+#define TSA_QE_SIGLMRH_ENC BIT(2)
+#define TSA_QE_SIGLMRH_ENB BIT(1)
+#define TSA_QE_SIGLMRH_ENA BIT(0)
/* SI clock route register (32 bits) */
-#define TSA_SICR 0x0C
-#define TSA_SICR_SCC2(x) ((x) << 8)
-#define TSA_SICR_SCC3(x) ((x) << 16)
-#define TSA_SICR_SCC4(x) ((x) << 24)
-#define TSA_SICR_SCC_MASK 0x0ff
-#define TSA_SICR_SCC_GRX (1 << 7)
-#define TSA_SICR_SCC_SCX_TSA (1 << 6)
-#define TSA_SICR_SCC_RXCS_MASK (0x7 << 3)
-#define TSA_SICR_SCC_RXCS_BRG1 (0x0 << 3)
-#define TSA_SICR_SCC_RXCS_BRG2 (0x1 << 3)
-#define TSA_SICR_SCC_RXCS_BRG3 (0x2 << 3)
-#define TSA_SICR_SCC_RXCS_BRG4 (0x3 << 3)
-#define TSA_SICR_SCC_RXCS_CLK15 (0x4 << 3)
-#define TSA_SICR_SCC_RXCS_CLK26 (0x5 << 3)
-#define TSA_SICR_SCC_RXCS_CLK37 (0x6 << 3)
-#define TSA_SICR_SCC_RXCS_CLK48 (0x7 << 3)
-#define TSA_SICR_SCC_TXCS_MASK (0x7 << 0)
-#define TSA_SICR_SCC_TXCS_BRG1 (0x0 << 0)
-#define TSA_SICR_SCC_TXCS_BRG2 (0x1 << 0)
-#define TSA_SICR_SCC_TXCS_BRG3 (0x2 << 0)
-#define TSA_SICR_SCC_TXCS_BRG4 (0x3 << 0)
-#define TSA_SICR_SCC_TXCS_CLK15 (0x4 << 0)
-#define TSA_SICR_SCC_TXCS_CLK26 (0x5 << 0)
-#define TSA_SICR_SCC_TXCS_CLK37 (0x6 << 0)
-#define TSA_SICR_SCC_TXCS_CLK48 (0x7 << 0)
-
-/* Serial interface RAM pointer register (32 bits) */
-#define TSA_SIRP 0x10
+#define TSA_CPM1_SICR 0x0C
+#define TSA_CPM1_SICR_SCC2_MASK GENMASK(15, 8)
+#define TSA_CPM1_SICR_SCC2(x) FIELD_PREP(TSA_CPM1_SICR_SCC2_MASK, x)
+#define TSA_CPM1_SICR_SCC3_MASK GENMASK(23, 16)
+#define TSA_CPM1_SICR_SCC3(x) FIELD_PREP(TSA_CPM1_SICR_SCC3_MASK, x)
+#define TSA_CPM1_SICR_SCC4_MASK GENMASK(31, 24)
+#define TSA_CPM1_SICR_SCC4(x) FIELD_PREP(TSA_CPM1_SICR_SCC4_MASK, x)
+#define TSA_CPM1_SICR_SCC_MASK GENMASK(7, 0)
+#define TSA_CPM1_SICR_SCC_GRX BIT(7)
+#define TSA_CPM1_SICR_SCC_SCX_TSA BIT(6)
+#define TSA_CPM1_SICR_SCC_RXCS_MASK GENMASK(5, 3)
+#define TSA_CPM1_SICR_SCC_RXCS_BRG1 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x0)
+#define TSA_CPM1_SICR_SCC_RXCS_BRG2 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x1)
+#define TSA_CPM1_SICR_SCC_RXCS_BRG3 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x2)
+#define TSA_CPM1_SICR_SCC_RXCS_BRG4 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x3)
+#define TSA_CPM1_SICR_SCC_RXCS_CLK15 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x4)
+#define TSA_CPM1_SICR_SCC_RXCS_CLK26 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x5)
+#define TSA_CPM1_SICR_SCC_RXCS_CLK37 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x6)
+#define TSA_CPM1_SICR_SCC_RXCS_CLK48 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x7)
+#define TSA_CPM1_SICR_SCC_TXCS_MASK GENMASK(2, 0)
+#define TSA_CPM1_SICR_SCC_TXCS_BRG1 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x0)
+#define TSA_CPM1_SICR_SCC_TXCS_BRG2 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x1)
+#define TSA_CPM1_SICR_SCC_TXCS_BRG3 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x2)
+#define TSA_CPM1_SICR_SCC_TXCS_BRG4 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x3)
+#define TSA_CPM1_SICR_SCC_TXCS_CLK15 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x4)
+#define TSA_CPM1_SICR_SCC_TXCS_CLK26 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x5)
+#define TSA_CPM1_SICR_SCC_TXCS_CLK37 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x6)
+#define TSA_CPM1_SICR_SCC_TXCS_CLK48 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x7)
struct tsa_entries_area {
void __iomem *entries_start;
@@ -114,15 +146,31 @@ struct tsa_tdm {
#define TSA_TDMA 0
#define TSA_TDMB 1
+#define TSA_TDMC 2 /* QE implementation only */
+#define TSA_TDMD 3 /* QE implementation only */
+
+enum tsa_version {
+ TSA_CPM1 = 1, /* Avoid 0 value */
+ TSA_QE,
+};
struct tsa {
struct device *dev;
void __iomem *si_regs;
void __iomem *si_ram;
resource_size_t si_ram_sz;
- spinlock_t lock;
+ spinlock_t lock; /* Lock for read/modify/write sequence */
+ enum tsa_version version;
int tdms; /* TSA_TDMx ORed */
+#if IS_ENABLED(CONFIG_QUICC_ENGINE)
+ struct tsa_tdm tdm[4]; /* TDMa, TDMb, TDMc and TDMd */
+#else
struct tsa_tdm tdm[2]; /* TDMa and TDMb */
+#endif
+ /* Same number of serials for CPM1 and QE:
+ * CPM1: NU, 3 SCCs and 2 SMCs
+ * QE: NU and 5 UCCs
+ */
struct tsa_serial {
unsigned int id;
struct tsa_serial_info info;
@@ -140,7 +188,12 @@ static inline void tsa_write32(void __iomem *addr, u32 val)
iowrite32be(val, addr);
}
-static inline void tsa_write8(void __iomem *addr, u32 val)
+static inline void tsa_write16(void __iomem *addr, u16 val)
+{
+ iowrite16be(val, addr);
+}
+
+static inline void tsa_write8(void __iomem *addr, u8 val)
{
iowrite8(val, addr);
}
@@ -150,17 +203,68 @@ static inline u32 tsa_read32(void __iomem *addr)
return ioread32be(addr);
}
+static inline u16 tsa_read16(void __iomem *addr)
+{
+ return ioread16be(addr);
+}
+
static inline void tsa_clrbits32(void __iomem *addr, u32 clr)
{
tsa_write32(addr, tsa_read32(addr) & ~clr);
}
+static inline void tsa_clrbits16(void __iomem *addr, u16 clr)
+{
+ tsa_write16(addr, tsa_read16(addr) & ~clr);
+}
+
static inline void tsa_clrsetbits32(void __iomem *addr, u32 clr, u32 set)
{
tsa_write32(addr, (tsa_read32(addr) & ~clr) | set);
}
-int tsa_serial_connect(struct tsa_serial *tsa_serial)
+static bool tsa_is_qe(const struct tsa *tsa)
+{
+ if (IS_ENABLED(CONFIG_QUICC_ENGINE) && IS_ENABLED(CONFIG_CPM))
+ return tsa->version == TSA_QE;
+
+ return IS_ENABLED(CONFIG_QUICC_ENGINE);
+}
+
+static int tsa_qe_serial_get_num(struct tsa_serial *tsa_serial)
+{
+ struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);
+
+ switch (tsa_serial->id) {
+ case FSL_QE_TSA_UCC1: return 0;
+ case FSL_QE_TSA_UCC2: return 1;
+ case FSL_QE_TSA_UCC3: return 2;
+ case FSL_QE_TSA_UCC4: return 3;
+ case FSL_QE_TSA_UCC5: return 4;
+ default:
+ break;
+ }
+
+ dev_err(tsa->dev, "Unsupported serial id %u\n", tsa_serial->id);
+ return -EINVAL;
+}
+
+int tsa_serial_get_num(struct tsa_serial *tsa_serial)
+{
+ struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);
+
+ /*
+ * There is no need to get the serial num out of the TSA driver in the
+ * CPM case.
+ * Further more, in CPM, we can have 2 types of serial SCCs and FCCs.
+ * What kind of numbering to use that can be global to both SCCs and
+ * FCCs ?
+ */
+ return tsa_is_qe(tsa) ? tsa_qe_serial_get_num(tsa_serial) : -EOPNOTSUPP;
+}
+EXPORT_SYMBOL(tsa_serial_get_num);
+
+static int tsa_cpm1_serial_connect(struct tsa_serial *tsa_serial, bool connect)
{
struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);
unsigned long flags;
@@ -169,16 +273,16 @@ int tsa_serial_connect(struct tsa_serial *tsa_serial)
switch (tsa_serial->id) {
case FSL_CPM_TSA_SCC2:
- clear = TSA_SICR_SCC2(TSA_SICR_SCC_MASK);
- set = TSA_SICR_SCC2(TSA_SICR_SCC_SCX_TSA);
+ clear = TSA_CPM1_SICR_SCC2(TSA_CPM1_SICR_SCC_MASK);
+ set = TSA_CPM1_SICR_SCC2(TSA_CPM1_SICR_SCC_SCX_TSA);
break;
case FSL_CPM_TSA_SCC3:
- clear = TSA_SICR_SCC3(TSA_SICR_SCC_MASK);
- set = TSA_SICR_SCC3(TSA_SICR_SCC_SCX_TSA);
+ clear = TSA_CPM1_SICR_SCC3(TSA_CPM1_SICR_SCC_MASK);
+ set = TSA_CPM1_SICR_SCC3(TSA_CPM1_SICR_SCC_SCX_TSA);
break;
case FSL_CPM_TSA_SCC4:
- clear = TSA_SICR_SCC4(TSA_SICR_SCC_MASK);
- set = TSA_SICR_SCC4(TSA_SICR_SCC_SCX_TSA);
+ clear = TSA_CPM1_SICR_SCC4(TSA_CPM1_SICR_SCC_MASK);
+ set = TSA_CPM1_SICR_SCC4(TSA_CPM1_SICR_SCC_SCX_TSA);
break;
default:
dev_err(tsa->dev, "Unsupported serial id %u\n", tsa_serial->id);
@@ -186,40 +290,53 @@ int tsa_serial_connect(struct tsa_serial *tsa_serial)
}
spin_lock_irqsave(&tsa->lock, flags);
- tsa_clrsetbits32(tsa->si_regs + TSA_SICR, clear, set);
+ tsa_clrsetbits32(tsa->si_regs + TSA_CPM1_SICR, clear,
+ connect ? set : 0);
spin_unlock_irqrestore(&tsa->lock, flags);
return 0;
}
-EXPORT_SYMBOL(tsa_serial_connect);
-int tsa_serial_disconnect(struct tsa_serial *tsa_serial)
+static int tsa_qe_serial_connect(struct tsa_serial *tsa_serial, bool connect)
{
struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);
unsigned long flags;
- u32 clear;
+ int ucc_num;
+ int ret;
- switch (tsa_serial->id) {
- case FSL_CPM_TSA_SCC2:
- clear = TSA_SICR_SCC2(TSA_SICR_SCC_MASK);
- break;
- case FSL_CPM_TSA_SCC3:
- clear = TSA_SICR_SCC3(TSA_SICR_SCC_MASK);
- break;
- case FSL_CPM_TSA_SCC4:
- clear = TSA_SICR_SCC4(TSA_SICR_SCC_MASK);
- break;
- default:
- dev_err(tsa->dev, "Unsupported serial id %u\n", tsa_serial->id);
- return -EINVAL;
- }
+ ucc_num = tsa_qe_serial_get_num(tsa_serial);
+ if (ucc_num < 0)
+ return ucc_num;
spin_lock_irqsave(&tsa->lock, flags);
- tsa_clrsetbits32(tsa->si_regs + TSA_SICR, clear, 0);
+ ret = ucc_set_qe_mux_tsa(ucc_num, connect);
spin_unlock_irqrestore(&tsa->lock, flags);
-
+ if (ret) {
+ dev_err(tsa->dev, "Connect serial id %u to TSA failed (%d)\n",
+ tsa_serial->id, ret);
+ return ret;
+ }
return 0;
}
+
+int tsa_serial_connect(struct tsa_serial *tsa_serial)
+{
+ struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);
+
+ return tsa_is_qe(tsa) ?
+ tsa_qe_serial_connect(tsa_serial, true) :
+ tsa_cpm1_serial_connect(tsa_serial, true);
+}
+EXPORT_SYMBOL(tsa_serial_connect);
+
+int tsa_serial_disconnect(struct tsa_serial *tsa_serial)
+{
+ struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);
+
+ return tsa_is_qe(tsa) ?
+ tsa_qe_serial_connect(tsa_serial, false) :
+ tsa_cpm1_serial_connect(tsa_serial, false);
+}
EXPORT_SYMBOL(tsa_serial_disconnect);
int tsa_serial_get_info(struct tsa_serial *tsa_serial, struct tsa_serial_info *info)
@@ -229,14 +346,14 @@ int tsa_serial_get_info(struct tsa_serial *tsa_serial, struct tsa_serial_info *i
}
EXPORT_SYMBOL(tsa_serial_get_info);
-static void tsa_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area,
- u32 tdms, u32 tdm_id, bool is_rx)
+static void tsa_cpm1_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area,
+ u32 tdms, u32 tdm_id, bool is_rx)
{
resource_size_t quarter;
resource_size_t half;
- quarter = tsa->si_ram_sz/4;
- half = tsa->si_ram_sz/2;
+ quarter = tsa->si_ram_sz / 4;
+ half = tsa->si_ram_sz / 2;
if (tdms == BIT(TSA_TDMA)) {
/* Only TDMA */
@@ -281,7 +398,42 @@ static void tsa_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area
}
}
-static const char *tsa_serial_id2name(struct tsa *tsa, u32 serial_id)
+static void tsa_qe_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area,
+ u32 tdms, u32 tdm_id, bool is_rx)
+{
+ resource_size_t eighth;
+ resource_size_t half;
+
+ eighth = tsa->si_ram_sz / 8;
+ half = tsa->si_ram_sz / 2;
+
+ /*
+ * One half of the SI RAM used for Tx, the other one for Rx.
+ * In each half, 1/4 of the area is assigned to each TDM.
+ */
+ if (is_rx) {
+ /* Rx: Second half of si_ram */
+ area->entries_start = tsa->si_ram + half + (eighth * tdm_id);
+ area->entries_next = area->entries_start + eighth;
+ area->last_entry = NULL;
+ } else {
+ /* Tx: First half of si_ram */
+ area->entries_start = tsa->si_ram + (eighth * tdm_id);
+ area->entries_next = area->entries_start + eighth;
+ area->last_entry = NULL;
+ }
+}
+
+static void tsa_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area,
+ u32 tdms, u32 tdm_id, bool is_rx)
+{
+ if (tsa_is_qe(tsa))
+ tsa_qe_init_entries_area(tsa, area, tdms, tdm_id, is_rx);
+ else
+ tsa_cpm1_init_entries_area(tsa, area, tdms, tdm_id, is_rx);
+}
+
+static const char *tsa_cpm1_serial_id2name(struct tsa *tsa, u32 serial_id)
{
switch (serial_id) {
case FSL_CPM_TSA_NU: return "Not used";
@@ -296,22 +448,44 @@ static const char *tsa_serial_id2name(struct tsa *tsa, u32 serial_id)
return NULL;
}
-static u32 tsa_serial_id2csel(struct tsa *tsa, u32 serial_id)
+static const char *tsa_qe_serial_id2name(struct tsa *tsa, u32 serial_id)
{
switch (serial_id) {
- case FSL_CPM_TSA_SCC2: return TSA_SIRAM_ENTRY_CSEL_SCC2;
- case FSL_CPM_TSA_SCC3: return TSA_SIRAM_ENTRY_CSEL_SCC3;
- case FSL_CPM_TSA_SCC4: return TSA_SIRAM_ENTRY_CSEL_SCC4;
- case FSL_CPM_TSA_SMC1: return TSA_SIRAM_ENTRY_CSEL_SMC1;
- case FSL_CPM_TSA_SMC2: return TSA_SIRAM_ENTRY_CSEL_SMC2;
+ case FSL_QE_TSA_NU: return "Not used";
+ case FSL_QE_TSA_UCC1: return "UCC1";
+ case FSL_QE_TSA_UCC2: return "UCC2";
+ case FSL_QE_TSA_UCC3: return "UCC3";
+ case FSL_QE_TSA_UCC4: return "UCC4";
+ case FSL_QE_TSA_UCC5: return "UCC5";
default:
break;
}
- return TSA_SIRAM_ENTRY_CSEL_NU;
+ return NULL;
}
-static int tsa_add_entry(struct tsa *tsa, struct tsa_entries_area *area,
- u32 count, u32 serial_id)
+static const char *tsa_serial_id2name(struct tsa *tsa, u32 serial_id)
+{
+ return tsa_is_qe(tsa) ?
+ tsa_qe_serial_id2name(tsa, serial_id) :
+ tsa_cpm1_serial_id2name(tsa, serial_id);
+}
+
+static u32 tsa_cpm1_serial_id2csel(struct tsa *tsa, u32 serial_id)
+{
+ switch (serial_id) {
+ case FSL_CPM_TSA_SCC2: return TSA_CPM1_SIRAM_ENTRY_CSEL_SCC2;
+ case FSL_CPM_TSA_SCC3: return TSA_CPM1_SIRAM_ENTRY_CSEL_SCC3;
+ case FSL_CPM_TSA_SCC4: return TSA_CPM1_SIRAM_ENTRY_CSEL_SCC4;
+ case FSL_CPM_TSA_SMC1: return TSA_CPM1_SIRAM_ENTRY_CSEL_SMC1;
+ case FSL_CPM_TSA_SMC2: return TSA_CPM1_SIRAM_ENTRY_CSEL_SMC2;
+ default:
+ break;
+ }
+ return TSA_CPM1_SIRAM_ENTRY_CSEL_NU;
+}
+
+static int tsa_cpm1_add_entry(struct tsa *tsa, struct tsa_entries_area *area,
+ u32 count, u32 serial_id)
{
void __iomem *addr;
u32 left;
@@ -329,21 +503,21 @@ static int tsa_add_entry(struct tsa *tsa, struct tsa_entries_area *area,
if (area->last_entry) {
/* Clear last flag */
- tsa_clrbits32(area->last_entry, TSA_SIRAM_ENTRY_LAST);
+ tsa_clrbits32(area->last_entry, TSA_CPM1_SIRAM_ENTRY_LAST);
}
left = count;
while (left) {
- val = TSA_SIRAM_ENTRY_BYTE | tsa_serial_id2csel(tsa, serial_id);
+ val = TSA_CPM1_SIRAM_ENTRY_BYTE | tsa_cpm1_serial_id2csel(tsa, serial_id);
if (left > 16) {
cnt = 16;
} else {
cnt = left;
- val |= TSA_SIRAM_ENTRY_LAST;
+ val |= TSA_CPM1_SIRAM_ENTRY_LAST;
area->last_entry = addr;
}
- val |= TSA_SIRAM_ENTRY_CNT(cnt - 1);
+ val |= TSA_CPM1_SIRAM_ENTRY_CNT(cnt - 1);
tsa_write32(addr, val);
addr += 4;
@@ -353,6 +527,71 @@ static int tsa_add_entry(struct tsa *tsa, struct tsa_entries_area *area,
return 0;
}
+static u32 tsa_qe_serial_id2csel(struct tsa *tsa, u32 serial_id)
+{
+ switch (serial_id) {
+ case FSL_QE_TSA_UCC1: return TSA_QE_SIRAM_ENTRY_CSEL_UCC1;
+ case FSL_QE_TSA_UCC2: return TSA_QE_SIRAM_ENTRY_CSEL_UCC2;
+ case FSL_QE_TSA_UCC3: return TSA_QE_SIRAM_ENTRY_CSEL_UCC3;
+ case FSL_QE_TSA_UCC4: return TSA_QE_SIRAM_ENTRY_CSEL_UCC4;
+ case FSL_QE_TSA_UCC5: return TSA_QE_SIRAM_ENTRY_CSEL_UCC5;
+ default:
+ break;
+ }
+ return TSA_QE_SIRAM_ENTRY_CSEL_NU;
+}
+
+static int tsa_qe_add_entry(struct tsa *tsa, struct tsa_entries_area *area,
+ u32 count, u32 serial_id)
+{
+ void __iomem *addr;
+ u32 left;
+ u32 val;
+ u32 cnt;
+ u32 nb;
+
+ addr = area->last_entry ? area->last_entry + 2 : area->entries_start;
+
+ nb = DIV_ROUND_UP(count, 8);
+ if ((addr + (nb * 2)) > area->entries_next) {
+ dev_err(tsa->dev, "si ram area full\n");
+ return -ENOSPC;
+ }
+
+ if (area->last_entry) {
+ /* Clear last flag */
+ tsa_clrbits16(area->last_entry, TSA_QE_SIRAM_ENTRY_LAST);
+ }
+
+ left = count;
+ while (left) {
+ val = TSA_QE_SIRAM_ENTRY_BYTE | tsa_qe_serial_id2csel(tsa, serial_id);
+
+ if (left > 8) {
+ cnt = 8;
+ } else {
+ cnt = left;
+ val |= TSA_QE_SIRAM_ENTRY_LAST;
+ area->last_entry = addr;
+ }
+ val |= TSA_QE_SIRAM_ENTRY_CNT(cnt - 1);
+
+ tsa_write16(addr, val);
+ addr += 2;
+ left -= cnt;
+ }
+
+ return 0;
+}
+
+static int tsa_add_entry(struct tsa *tsa, struct tsa_entries_area *area,
+ u32 count, u32 serial_id)
+{
+ return tsa_is_qe(tsa) ?
+ tsa_qe_add_entry(tsa, area, count, serial_id) :
+ tsa_cpm1_add_entry(tsa, area, count, serial_id);
+}
+
static int tsa_of_parse_tdm_route(struct tsa *tsa, struct device_node *tdm_np,
u32 tdms, u32 tdm_id, bool is_rx)
{
@@ -399,7 +638,7 @@ static int tsa_of_parse_tdm_route(struct tsa *tsa, struct device_node *tdm_np,
}
dev_dbg(tsa->dev, "tdm_id=%u, %s ts %u..%u -> %s\n",
- tdm_id, route_name, ts, ts+count-1, serial_name);
+ tdm_id, route_name, ts, ts + count - 1, serial_name);
ts += count;
ret = tsa_add_entry(tsa, &area, count, serial_id);
@@ -441,7 +680,6 @@ static inline int tsa_of_parse_tdm_tx_route(struct tsa *tsa,
static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np)
{
- struct device_node *tdm_np;
struct tsa_tdm *tdm;
struct clk *clk;
u32 tdm_id, val;
@@ -449,14 +687,13 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np)
int i;
tsa->tdms = 0;
- tsa->tdm[0].is_enable = false;
- tsa->tdm[1].is_enable = false;
+ for (i = 0; i < ARRAY_SIZE(tsa->tdm); i++)
+ tsa->tdm[i].is_enable = false;
- for_each_available_child_of_node(np, tdm_np) {
+ for_each_available_child_of_node_scoped(np, tdm_np) {
ret = of_property_read_u32(tdm_np, "reg", &tdm_id);
if (ret) {
dev_err(tsa->dev, "%pOF: failed to read reg\n", tdm_np);
- of_node_put(tdm_np);
return ret;
}
switch (tdm_id) {
@@ -466,19 +703,28 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np)
case 1:
tsa->tdms |= BIT(TSA_TDMB);
break;
+ case 2:
+ if (!tsa_is_qe(tsa))
+ goto invalid_tdm; /* Not available on CPM1 */
+ tsa->tdms |= BIT(TSA_TDMC);
+ break;
+ case 3:
+ if (!tsa_is_qe(tsa))
+ goto invalid_tdm; /* Not available on CPM1 */
+ tsa->tdms |= BIT(TSA_TDMD);
+ break;
default:
+invalid_tdm:
dev_err(tsa->dev, "%pOF: Invalid tdm_id (%u)\n", tdm_np,
tdm_id);
- of_node_put(tdm_np);
return -EINVAL;
}
}
- for_each_available_child_of_node(np, tdm_np) {
+ for_each_available_child_of_node_scoped(np, tdm_np) {
ret = of_property_read_u32(tdm_np, "reg", &tdm_id);
if (ret) {
dev_err(tsa->dev, "%pOF: failed to read reg\n", tdm_np);
- of_node_put(tdm_np);
return ret;
}
@@ -492,14 +738,12 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np)
dev_err(tsa->dev,
"%pOF: failed to read fsl,rx-frame-sync-delay-bits\n",
tdm_np);
- of_node_put(tdm_np);
return ret;
}
if (val > 3) {
dev_err(tsa->dev,
"%pOF: Invalid fsl,rx-frame-sync-delay-bits (%u)\n",
tdm_np, val);
- of_node_put(tdm_np);
return -EINVAL;
}
tdm->simode_tdm |= TSA_SIMODE_TDM_RFSD(val);
@@ -511,14 +755,12 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np)
dev_err(tsa->dev,
"%pOF: failed to read fsl,tx-frame-sync-delay-bits\n",
tdm_np);
- of_node_put(tdm_np);
return ret;
}
if (val > 3) {
dev_err(tsa->dev,
"%pOF: Invalid fsl,tx-frame-sync-delay-bits (%u)\n",
tdm_np, val);
- of_node_put(tdm_np);
return -EINVAL;
}
tdm->simode_tdm |= TSA_SIMODE_TDM_TFSD(val);
@@ -532,85 +774,88 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np)
if (of_property_read_bool(tdm_np, "fsl,fsync-rising-edge"))
tdm->simode_tdm |= TSA_SIMODE_TDM_FE;
+ if (tsa_is_qe(tsa) &&
+ of_property_read_bool(tdm_np, "fsl,fsync-active-low"))
+ tdm->simode_tdm |= TSA_QE_SIMODE_TDM_SL;
+
if (of_property_read_bool(tdm_np, "fsl,double-speed-clock"))
tdm->simode_tdm |= TSA_SIMODE_TDM_DSC;
- clk = of_clk_get_by_name(tdm_np, "l1rsync");
+ clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "rsync" : "l1rsync");
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
- of_node_put(tdm_np);
goto err;
}
ret = clk_prepare_enable(clk);
if (ret) {
clk_put(clk);
- of_node_put(tdm_np);
goto err;
}
tdm->l1rsync_clk = clk;
- clk = of_clk_get_by_name(tdm_np, "l1rclk");
+ clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "rclk" : "l1rclk");
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
- of_node_put(tdm_np);
goto err;
}
ret = clk_prepare_enable(clk);
if (ret) {
clk_put(clk);
- of_node_put(tdm_np);
goto err;
}
tdm->l1rclk_clk = clk;
if (!(tdm->simode_tdm & TSA_SIMODE_TDM_CRT)) {
- clk = of_clk_get_by_name(tdm_np, "l1tsync");
+ clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "tsync" : "l1tsync");
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
- of_node_put(tdm_np);
goto err;
}
ret = clk_prepare_enable(clk);
if (ret) {
clk_put(clk);
- of_node_put(tdm_np);
goto err;
}
tdm->l1tsync_clk = clk;
- clk = of_clk_get_by_name(tdm_np, "l1tclk");
+ clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "tclk" : "l1tclk");
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
- of_node_put(tdm_np);
goto err;
}
ret = clk_prepare_enable(clk);
if (ret) {
clk_put(clk);
- of_node_put(tdm_np);
goto err;
}
tdm->l1tclk_clk = clk;
}
+ if (tsa_is_qe(tsa)) {
+ /*
+ * The starting address for TSA table must be set.
+ * 512 entries for Tx and 512 entries for Rx are
+ * available for 4 TDMs.
+ * We assign entries equally -> 128 Rx/Tx entries per
+ * TDM. In other words, 4 blocks of 32 entries per TDM.
+ */
+ tdm->simode_tdm |= TSA_QE_SIMODE_TDM_SAD(4 * tdm_id);
+ }
+
ret = tsa_of_parse_tdm_rx_route(tsa, tdm_np, tsa->tdms, tdm_id);
- if (ret) {
- of_node_put(tdm_np);
+ if (ret)
goto err;
- }
ret = tsa_of_parse_tdm_tx_route(tsa, tdm_np, tsa->tdms, tdm_id);
- if (ret) {
- of_node_put(tdm_np);
+ if (ret)
goto err;
- }
tdm->is_enable = true;
}
return 0;
err:
- for (i = 0; i < 2; i++) {
+ for (i = 0; i < ARRAY_SIZE(tsa->tdm); i++) {
if (tsa->tdm[i].l1rsync_clk) {
clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
clk_put(tsa->tdm[i].l1rsync_clk);
@@ -636,8 +881,87 @@ static void tsa_init_si_ram(struct tsa *tsa)
resource_size_t i;
/* Fill all entries as the last one */
- for (i = 0; i < tsa->si_ram_sz; i += 4)
- tsa_write32(tsa->si_ram + i, TSA_SIRAM_ENTRY_LAST);
+ if (tsa_is_qe(tsa)) {
+ for (i = 0; i < tsa->si_ram_sz; i += 2)
+ tsa_write16(tsa->si_ram + i, TSA_QE_SIRAM_ENTRY_LAST);
+ } else {
+ for (i = 0; i < tsa->si_ram_sz; i += 4)
+ tsa_write32(tsa->si_ram + i, TSA_CPM1_SIRAM_ENTRY_LAST);
+ }
+}
+
+static int tsa_cpm1_setup(struct tsa *tsa)
+{
+ u32 val;
+
+ /* Set SIMODE */
+ val = 0;
+ if (tsa->tdm[0].is_enable)
+ val |= TSA_CPM1_SIMODE_TDMA(tsa->tdm[0].simode_tdm);
+ if (tsa->tdm[1].is_enable)
+ val |= TSA_CPM1_SIMODE_TDMB(tsa->tdm[1].simode_tdm);
+
+ tsa_clrsetbits32(tsa->si_regs + TSA_CPM1_SIMODE,
+ TSA_CPM1_SIMODE_TDMA(TSA_CPM1_SIMODE_TDM_MASK) |
+ TSA_CPM1_SIMODE_TDMB(TSA_CPM1_SIMODE_TDM_MASK),
+ val);
+
+ /* Set SIGMR */
+ val = (tsa->tdms == BIT(TSA_TDMA)) ?
+ TSA_CPM1_SIGMR_RDM_STATIC_TDMA : TSA_CPM1_SIGMR_RDM_STATIC_TDMAB;
+ if (tsa->tdms & BIT(TSA_TDMA))
+ val |= TSA_CPM1_SIGMR_ENA;
+ if (tsa->tdms & BIT(TSA_TDMB))
+ val |= TSA_CPM1_SIGMR_ENB;
+ tsa_write8(tsa->si_regs + TSA_CPM1_SIGMR, val);
+
+ return 0;
+}
+
+static int tsa_qe_setup(struct tsa *tsa)
+{
+ unsigned int sixmr;
+ u8 siglmrh = 0;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(tsa->tdm); i++) {
+ if (!tsa->tdm[i].is_enable)
+ continue;
+
+ switch (i) {
+ case 0:
+ sixmr = TSA_QE_SIAMR;
+ siglmrh |= TSA_QE_SIGLMRH_ENA;
+ break;
+ case 1:
+ sixmr = TSA_QE_SIBMR;
+ siglmrh |= TSA_QE_SIGLMRH_ENB;
+ break;
+ case 2:
+ sixmr = TSA_QE_SICMR;
+ siglmrh |= TSA_QE_SIGLMRH_ENC;
+ break;
+ case 3:
+ sixmr = TSA_QE_SIDMR;
+ siglmrh |= TSA_QE_SIGLMRH_END;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Set SI mode register */
+ tsa_write16(tsa->si_regs + sixmr, tsa->tdm[i].simode_tdm);
+ }
+
+ /* Enable TDMs */
+ tsa_write8(tsa->si_regs + TSA_QE_SIGLMRH, siglmrh);
+
+ return 0;
+}
+
+static int tsa_setup(struct tsa *tsa)
+{
+ return tsa_is_qe(tsa) ? tsa_qe_setup(tsa) : tsa_cpm1_setup(tsa);
}
static int tsa_probe(struct platform_device *pdev)
@@ -646,7 +970,6 @@ static int tsa_probe(struct platform_device *pdev)
struct resource *res;
struct tsa *tsa;
unsigned int i;
- u32 val;
int ret;
tsa = devm_kzalloc(&pdev->dev, sizeof(*tsa), GFP_KERNEL);
@@ -654,6 +977,18 @@ static int tsa_probe(struct platform_device *pdev)
return -ENOMEM;
tsa->dev = &pdev->dev;
+ tsa->version = (enum tsa_version)(uintptr_t)of_device_get_match_data(&pdev->dev);
+ switch (tsa->version) {
+ case TSA_CPM1:
+ dev_info(tsa->dev, "CPM1 version\n");
+ break;
+ case TSA_QE:
+ dev_info(tsa->dev, "QE version\n");
+ break;
+ default:
+ dev_err(tsa->dev, "Unknown version (%d)\n", tsa->version);
+ return -EINVAL;
+ }
for (i = 0; i < ARRAY_SIZE(tsa->serials); i++)
tsa->serials[i].id = i;
@@ -680,26 +1015,9 @@ static int tsa_probe(struct platform_device *pdev)
if (ret)
return ret;
- /* Set SIMODE */
- val = 0;
- if (tsa->tdm[0].is_enable)
- val |= TSA_SIMODE_TDMA(tsa->tdm[0].simode_tdm);
- if (tsa->tdm[1].is_enable)
- val |= TSA_SIMODE_TDMB(tsa->tdm[1].simode_tdm);
-
- tsa_clrsetbits32(tsa->si_regs + TSA_SIMODE,
- TSA_SIMODE_TDMA(TSA_SIMODE_TDM_MASK) |
- TSA_SIMODE_TDMB(TSA_SIMODE_TDM_MASK),
- val);
-
- /* Set SIGMR */
- val = (tsa->tdms == BIT(TSA_TDMA)) ?
- TSA_SIGMR_RDM_STATIC_TDMA : TSA_SIGMR_RDM_STATIC_TDMAB;
- if (tsa->tdms & BIT(TSA_TDMA))
- val |= TSA_SIGMR_ENA;
- if (tsa->tdms & BIT(TSA_TDMB))
- val |= TSA_SIGMR_ENB;
- tsa_write8(tsa->si_regs + TSA_SIGMR, val);
+ ret = tsa_setup(tsa);
+ if (ret)
+ return ret;
platform_set_drvdata(pdev, tsa);
@@ -711,7 +1029,7 @@ static void tsa_remove(struct platform_device *pdev)
struct tsa *tsa = platform_get_drvdata(pdev);
int i;
- for (i = 0; i < 2; i++) {
+ for (i = 0; i < ARRAY_SIZE(tsa->tdm); i++) {
if (tsa->tdm[i].l1rsync_clk) {
clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
clk_put(tsa->tdm[i].l1rsync_clk);
@@ -732,7 +1050,12 @@ static void tsa_remove(struct platform_device *pdev)
}
static const struct of_device_id tsa_id_table[] = {
- { .compatible = "fsl,cpm1-tsa" },
+#if IS_ENABLED(CONFIG_CPM1)
+ { .compatible = "fsl,cpm1-tsa", .data = (void *)TSA_CPM1 },
+#endif
+#if IS_ENABLED(CONFIG_QUICC_ENGINE)
+ { .compatible = "fsl,qe-tsa", .data = (void *)TSA_QE },
+#endif
{} /* sentinel */
};
MODULE_DEVICE_TABLE(of, tsa_id_table);
@@ -743,7 +1066,7 @@ static struct platform_driver tsa_driver = {
.of_match_table = of_match_ptr(tsa_id_table),
},
.probe = tsa_probe,
- .remove_new = tsa_remove,
+ .remove = tsa_remove,
};
module_platform_driver(tsa_driver);
@@ -841,5 +1164,5 @@ struct tsa_serial *devm_tsa_serial_get_byphandle(struct device *dev,
EXPORT_SYMBOL(devm_tsa_serial_get_byphandle);
MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
-MODULE_DESCRIPTION("CPM TSA driver");
+MODULE_DESCRIPTION("CPM/QE TSA driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/soc/fsl/qe/tsa.h b/drivers/soc/fsl/qe/tsa.h
index d9df89b6da3e..da137bc0f49b 100644
--- a/drivers/soc/fsl/qe/tsa.h
+++ b/drivers/soc/fsl/qe/tsa.h
@@ -39,4 +39,7 @@ struct tsa_serial_info {
/* Get information */
int tsa_serial_get_info(struct tsa_serial *tsa_serial, struct tsa_serial_info *info);
+/* Get serial number */
+int tsa_serial_get_num(struct tsa_serial *tsa_serial);
+
#endif /* __SOC_FSL_TSA_H__ */
diff --git a/drivers/soc/fsl/qe/ucc.c b/drivers/soc/fsl/qe/ucc.c
index 21dbcd787cd5..892aa5931d5b 100644
--- a/drivers/soc/fsl/qe/ucc.c
+++ b/drivers/soc/fsl/qe/ucc.c
@@ -114,6 +114,7 @@ int ucc_mux_set_grant_tsa_bkpt(unsigned int ucc_num, int set, u32 mask)
return 0;
}
+EXPORT_SYMBOL(ucc_mux_set_grant_tsa_bkpt);
int ucc_set_qe_mux_rxtx(unsigned int ucc_num, enum qe_clock clock,
enum comm_dir mode)
diff --git a/drivers/soc/fsl/rcpm.c b/drivers/soc/fsl/rcpm.c
index 3d0cae30c769..06bd94b29fb3 100644
--- a/drivers/soc/fsl/rcpm.c
+++ b/drivers/soc/fsl/rcpm.c
@@ -36,6 +36,7 @@ static void copy_ippdexpcr1_setting(u32 val)
return;
regs = of_iomap(np, 0);
+ of_node_put(np);
if (!regs)
return;
diff --git a/drivers/soc/fujitsu/a64fx-diag.c b/drivers/soc/fujitsu/a64fx-diag.c
index 330901893577..76cb0b6a221c 100644
--- a/drivers/soc/fujitsu/a64fx-diag.c
+++ b/drivers/soc/fujitsu/a64fx-diag.c
@@ -142,7 +142,7 @@ static struct platform_driver a64fx_diag_driver = {
.acpi_match_table = ACPI_PTR(a64fx_diag_acpi_match),
},
.probe = a64fx_diag_probe,
- .remove_new = a64fx_diag_remove,
+ .remove = a64fx_diag_remove,
};
module_platform_driver(a64fx_diag_driver);
diff --git a/drivers/soc/hisilicon/Kconfig b/drivers/soc/hisilicon/Kconfig
index 0ab688af308f..6d7c244d2e78 100644
--- a/drivers/soc/hisilicon/Kconfig
+++ b/drivers/soc/hisilicon/Kconfig
@@ -6,16 +6,19 @@ menu "Hisilicon SoC drivers"
config KUNPENG_HCCS
tristate "HCCS driver on Kunpeng SoC"
depends on ACPI
- depends on MAILBOX
+ depends on PCC
depends on ARM64 || COMPILE_TEST
help
The Huawei Cache Coherence System (HCCS) is a multi-chip
interconnection bus protocol.
The performance of application may be affected if some HCCS
ports are not in full lane status, have a large number of CRC
- errors and so on.
+ errors and so on. This may support for reducing system power
+ consumption if there are HCCS ports supported low power feature
+ on platform.
Say M here if you want to include support for querying the
- health status and port information of HCCS on Kunpeng SoC.
+ health status and port information of HCCS, or reducing system
+ power consumption on Kunpeng SoC.
endmenu
diff --git a/drivers/soc/hisilicon/kunpeng_hccs.c b/drivers/soc/hisilicon/kunpeng_hccs.c
index 9ff70b38e5e9..444a8f59b7da 100644
--- a/drivers/soc/hisilicon/kunpeng_hccs.c
+++ b/drivers/soc/hisilicon/kunpeng_hccs.c
@@ -21,11 +21,22 @@
* - if all enabled ports are in linked
* - if all linked ports are in full lane
* - CRC error count sum
+ *
+ * - Retrieve all HCCS types used on the platform.
+ *
+ * - Support low power feature for all specified HCCS type ports, and
+ * provide the following interface:
+ * - query HCCS types supported increasing and decreasing lane number.
+ * - decrease lane number of all specified HCCS type ports on idle state.
+ * - increase lane number of all specified HCCS type ports.
*/
#include <linux/acpi.h>
+#include <linux/delay.h>
#include <linux/iopoll.h>
#include <linux/platform_device.h>
+#include <linux/stringify.h>
#include <linux/sysfs.h>
+#include <linux/types.h>
#include <acpi/pcc.h>
@@ -53,6 +64,42 @@ static struct hccs_chip_info *kobj_to_chip_info(struct kobject *k)
return container_of(k, struct hccs_chip_info, kobj);
}
+static struct hccs_dev *device_kobj_to_hccs_dev(struct kobject *k)
+{
+ struct device *dev = container_of(k, struct device, kobj);
+ struct platform_device *pdev =
+ container_of(dev, struct platform_device, dev);
+
+ return platform_get_drvdata(pdev);
+}
+
+static char *hccs_port_type_to_name(struct hccs_dev *hdev, u8 type)
+{
+ u16 i;
+
+ for (i = 0; i < hdev->used_type_num; i++) {
+ if (hdev->type_name_maps[i].type == type)
+ return hdev->type_name_maps[i].name;
+ }
+
+ return NULL;
+}
+
+static int hccs_name_to_port_type(struct hccs_dev *hdev,
+ const char *name, u8 *type)
+{
+ u16 i;
+
+ for (i = 0; i < hdev->used_type_num; i++) {
+ if (strcmp(hdev->type_name_maps[i].name, name) == 0) {
+ *type = hdev->type_name_maps[i].type;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
struct hccs_register_ctx {
struct device *dev;
u8 chan_id;
@@ -144,7 +191,7 @@ static int hccs_register_pcc_channel(struct hccs_dev *hdev)
pcc_chan = pcc_mbox_request_channel(cl, hdev->chan_id);
if (IS_ERR(pcc_chan)) {
- dev_err(dev, "PPC channel request failed.\n");
+ dev_err(dev, "PCC channel request failed.\n");
rc = -ENODEV;
goto out;
}
@@ -170,15 +217,21 @@ static int hccs_register_pcc_channel(struct hccs_dev *hdev)
goto err_mbx_channel_free;
}
- if (pcc_chan->shmem_base_addr) {
- cl_info->pcc_comm_addr = ioremap(pcc_chan->shmem_base_addr,
- pcc_chan->shmem_size);
- if (!cl_info->pcc_comm_addr) {
- dev_err(dev, "Failed to ioremap PCC communication region for channel-%u.\n",
- hdev->chan_id);
- rc = -ENOMEM;
- goto err_mbx_channel_free;
- }
+ if (!pcc_chan->shmem_base_addr ||
+ pcc_chan->shmem_size != HCCS_PCC_SHARE_MEM_BYTES) {
+ dev_err(dev, "The base address or size (%llu) of PCC communication region is invalid.\n",
+ pcc_chan->shmem_size);
+ rc = -EINVAL;
+ goto err_mbx_channel_free;
+ }
+
+ cl_info->pcc_comm_addr = ioremap(pcc_chan->shmem_base_addr,
+ pcc_chan->shmem_size);
+ if (!cl_info->pcc_comm_addr) {
+ dev_err(dev, "Failed to ioremap PCC communication region for channel-%u.\n",
+ hdev->chan_id);
+ rc = -ENOMEM;
+ goto err_mbx_channel_free;
}
return 0;
@@ -451,6 +504,7 @@ static int hccs_query_all_die_info_on_platform(struct hccs_dev *hdev)
struct device *dev = hdev->dev;
struct hccs_chip_info *chip;
struct hccs_die_info *die;
+ bool has_die_info = false;
u8 i, j;
int ret;
@@ -459,6 +513,7 @@ static int hccs_query_all_die_info_on_platform(struct hccs_dev *hdev)
if (!chip->die_num)
continue;
+ has_die_info = true;
chip->dies = devm_kzalloc(hdev->dev,
chip->die_num * sizeof(struct hccs_die_info),
GFP_KERNEL);
@@ -480,7 +535,7 @@ static int hccs_query_all_die_info_on_platform(struct hccs_dev *hdev)
}
}
- return 0;
+ return has_die_info ? 0 : -EINVAL;
}
static int hccs_get_bd_info(struct hccs_dev *hdev, u8 opcode,
@@ -556,6 +611,12 @@ static int hccs_get_all_port_attr(struct hccs_dev *hdev,
start_id = rsp_head.next_id;
}
+ if (left_buf_len != 0) {
+ dev_err(hdev->dev, "failed to get the expected port number(%u) attribute.\n",
+ size);
+ return -EINVAL;
+ }
+
return 0;
}
@@ -580,7 +641,7 @@ static int hccs_get_all_port_info_on_die(struct hccs_dev *hdev,
port = &die->ports[i];
port->port_id = attrs[i].port_id;
port->port_type = attrs[i].port_type;
- port->lane_mode = attrs[i].lane_mode;
+ port->max_lane_num = attrs[i].max_lane_num;
port->enable = attrs[i].enable;
port->die = die;
}
@@ -595,6 +656,7 @@ static int hccs_query_all_port_info_on_platform(struct hccs_dev *hdev)
struct device *dev = hdev->dev;
struct hccs_chip_info *chip;
struct hccs_die_info *die;
+ bool has_port_info = false;
u8 i, j;
int ret;
@@ -605,6 +667,7 @@ static int hccs_query_all_port_info_on_platform(struct hccs_dev *hdev)
if (!die->port_num)
continue;
+ has_port_info = true;
die->ports = devm_kzalloc(dev,
die->port_num * sizeof(struct hccs_port_info),
GFP_KERNEL);
@@ -623,7 +686,7 @@ static int hccs_query_all_port_info_on_platform(struct hccs_dev *hdev)
}
}
- return 0;
+ return has_port_info ? 0 : -EINVAL;
}
static int hccs_get_hw_info(struct hccs_dev *hdev)
@@ -654,6 +717,55 @@ static int hccs_get_hw_info(struct hccs_dev *hdev)
return 0;
}
+static u16 hccs_calc_used_type_num(struct hccs_dev *hdev,
+ unsigned long *hccs_ver)
+{
+ struct hccs_chip_info *chip;
+ struct hccs_port_info *port;
+ struct hccs_die_info *die;
+ u16 used_type_num = 0;
+ u16 i, j, k;
+
+ for (i = 0; i < hdev->chip_num; i++) {
+ chip = &hdev->chips[i];
+ for (j = 0; j < chip->die_num; j++) {
+ die = &chip->dies[j];
+ for (k = 0; k < die->port_num; k++) {
+ port = &die->ports[k];
+ set_bit(port->port_type, hccs_ver);
+ }
+ }
+ }
+
+ for_each_set_bit(i, hccs_ver, HCCS_IP_MAX + 1)
+ used_type_num++;
+
+ return used_type_num;
+}
+
+static int hccs_init_type_name_maps(struct hccs_dev *hdev)
+{
+ DECLARE_BITMAP(hccs_ver, HCCS_IP_MAX + 1) = {};
+ unsigned int i;
+ u16 idx = 0;
+
+ hdev->used_type_num = hccs_calc_used_type_num(hdev, hccs_ver);
+ hdev->type_name_maps = devm_kcalloc(hdev->dev, hdev->used_type_num,
+ sizeof(struct hccs_type_name_map),
+ GFP_KERNEL);
+ if (!hdev->type_name_maps)
+ return -ENOMEM;
+
+ for_each_set_bit(i, hccs_ver, HCCS_IP_MAX + 1) {
+ hdev->type_name_maps[idx].type = i;
+ sprintf(hdev->type_name_maps[idx].name,
+ "%s%u", HCCS_IP_PREFIX, i);
+ idx++;
+ }
+
+ return 0;
+}
+
static int hccs_query_port_link_status(struct hccs_dev *hdev,
const struct hccs_port_info *port,
struct hccs_link_status *link_status)
@@ -814,7 +926,7 @@ static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
{
const struct hccs_port_info *port = kobj_to_port_info(kobj);
- return sysfs_emit(buf, "HCCS-v%u\n", port->port_type);
+ return sysfs_emit(buf, "%s%u\n", HCCS_IP_PREFIX, port->port_type);
}
static struct kobj_attribute hccs_type_attr = __ATTR_RO(type);
@@ -823,7 +935,7 @@ static ssize_t lane_mode_show(struct kobject *kobj, struct kobj_attribute *attr,
{
const struct hccs_port_info *port = kobj_to_port_info(kobj);
- return sysfs_emit(buf, "x%u\n", port->lane_mode);
+ return sysfs_emit(buf, "x%u\n", port->max_lane_num);
}
static struct kobj_attribute lane_mode_attr = __ATTR_RO(lane_mode);
@@ -1118,6 +1230,372 @@ static const struct kobj_type hccs_chip_type = {
.default_groups = hccs_chip_default_groups,
};
+static int hccs_parse_pm_port_type(struct hccs_dev *hdev, const char *buf,
+ u8 *port_type)
+{
+ char hccs_name[HCCS_NAME_MAX_LEN + 1] = "";
+ u8 type;
+ int ret;
+
+ ret = sscanf(buf, "%" __stringify(HCCS_NAME_MAX_LEN) "s", hccs_name);
+ if (ret != 1)
+ return -EINVAL;
+
+ ret = hccs_name_to_port_type(hdev, hccs_name, &type);
+ if (ret) {
+ dev_dbg(hdev->dev, "input invalid, please get the available types from 'used_types'.\n");
+ return ret;
+ }
+
+ if (type == HCCS_V2 && hdev->caps & HCCS_CAPS_HCCS_V2_PM) {
+ *port_type = type;
+ return 0;
+ }
+
+ dev_dbg(hdev->dev, "%s doesn't support for increasing and decreasing lane.\n",
+ hccs_name);
+
+ return -EOPNOTSUPP;
+}
+
+static int hccs_query_port_idle_status(struct hccs_dev *hdev,
+ struct hccs_port_info *port, u8 *idle)
+{
+ const struct hccs_die_info *die = port->die;
+ const struct hccs_chip_info *chip = die->chip;
+ struct hccs_port_comm_req_param *req_param;
+ struct hccs_desc desc;
+ int ret;
+
+ hccs_init_req_desc(&desc);
+ req_param = (struct hccs_port_comm_req_param *)desc.req.data;
+ req_param->chip_id = chip->chip_id;
+ req_param->die_id = die->die_id;
+ req_param->port_id = port->port_id;
+ ret = hccs_pcc_cmd_send(hdev, HCCS_GET_PORT_IDLE_STATUS, &desc);
+ if (ret) {
+ dev_err(hdev->dev,
+ "get port idle status failed, ret = %d.\n", ret);
+ return ret;
+ }
+
+ *idle = *((u8 *)desc.rsp.data);
+ return 0;
+}
+
+static int hccs_get_all_spec_port_idle_sta(struct hccs_dev *hdev, u8 port_type,
+ bool *all_idle)
+{
+ struct hccs_chip_info *chip;
+ struct hccs_port_info *port;
+ struct hccs_die_info *die;
+ int ret = 0;
+ u8 i, j, k;
+ u8 idle;
+
+ *all_idle = false;
+ for (i = 0; i < hdev->chip_num; i++) {
+ chip = &hdev->chips[i];
+ for (j = 0; j < chip->die_num; j++) {
+ die = &chip->dies[j];
+ for (k = 0; k < die->port_num; k++) {
+ port = &die->ports[k];
+ if (port->port_type != port_type)
+ continue;
+ ret = hccs_query_port_idle_status(hdev, port,
+ &idle);
+ if (ret) {
+ dev_err(hdev->dev,
+ "hccs%u on chip%u/die%u get idle status failed, ret = %d.\n",
+ k, i, j, ret);
+ return ret;
+ } else if (idle == 0) {
+ dev_info(hdev->dev, "hccs%u on chip%u/die%u is busy.\n",
+ k, i, j);
+ return 0;
+ }
+ }
+ }
+ }
+ *all_idle = true;
+
+ return 0;
+}
+
+static int hccs_get_all_spec_port_full_lane_sta(struct hccs_dev *hdev,
+ u8 port_type, bool *full_lane)
+{
+ struct hccs_link_status status = {0};
+ struct hccs_chip_info *chip;
+ struct hccs_port_info *port;
+ struct hccs_die_info *die;
+ u8 i, j, k;
+ int ret;
+
+ *full_lane = false;
+ for (i = 0; i < hdev->chip_num; i++) {
+ chip = &hdev->chips[i];
+ for (j = 0; j < chip->die_num; j++) {
+ die = &chip->dies[j];
+ for (k = 0; k < die->port_num; k++) {
+ port = &die->ports[k];
+ if (port->port_type != port_type)
+ continue;
+ ret = hccs_query_port_link_status(hdev, port,
+ &status);
+ if (ret)
+ return ret;
+ if (status.lane_num != port->max_lane_num)
+ return 0;
+ }
+ }
+ }
+ *full_lane = true;
+
+ return 0;
+}
+
+static int hccs_prepare_inc_lane(struct hccs_dev *hdev, u8 type)
+{
+ struct hccs_inc_lane_req_param *req_param;
+ struct hccs_desc desc;
+ int ret;
+
+ hccs_init_req_desc(&desc);
+ req_param = (struct hccs_inc_lane_req_param *)desc.req.data;
+ req_param->port_type = type;
+ req_param->opt_type = HCCS_PREPARE_INC_LANE;
+ ret = hccs_pcc_cmd_send(hdev, HCCS_PM_INC_LANE, &desc);
+ if (ret)
+ dev_err(hdev->dev, "prepare for increasing lane failed, ret = %d.\n",
+ ret);
+
+ return ret;
+}
+
+static int hccs_wait_serdes_adapt_completed(struct hccs_dev *hdev, u8 type)
+{
+#define HCCS_MAX_WAIT_CNT_FOR_ADAPT 10
+#define HCCS_QUERY_ADAPT_RES_DELAY_MS 100
+#define HCCS_SERDES_ADAPT_OK 0
+
+ struct hccs_inc_lane_req_param *req_param;
+ u8 wait_cnt = HCCS_MAX_WAIT_CNT_FOR_ADAPT;
+ struct hccs_desc desc;
+ u8 adapt_res;
+ int ret;
+
+ do {
+ hccs_init_req_desc(&desc);
+ req_param = (struct hccs_inc_lane_req_param *)desc.req.data;
+ req_param->port_type = type;
+ req_param->opt_type = HCCS_GET_ADAPT_RES;
+ ret = hccs_pcc_cmd_send(hdev, HCCS_PM_INC_LANE, &desc);
+ if (ret) {
+ dev_err(hdev->dev, "query adapting result failed, ret = %d.\n",
+ ret);
+ return ret;
+ }
+ adapt_res = *((u8 *)&desc.rsp.data);
+ if (adapt_res == HCCS_SERDES_ADAPT_OK)
+ return 0;
+
+ msleep(HCCS_QUERY_ADAPT_RES_DELAY_MS);
+ } while (--wait_cnt);
+
+ dev_err(hdev->dev, "wait for adapting completed timeout.\n");
+
+ return -ETIMEDOUT;
+}
+
+static int hccs_start_hpcs_retraining(struct hccs_dev *hdev, u8 type)
+{
+ struct hccs_inc_lane_req_param *req_param;
+ struct hccs_desc desc;
+ int ret;
+
+ hccs_init_req_desc(&desc);
+ req_param = (struct hccs_inc_lane_req_param *)desc.req.data;
+ req_param->port_type = type;
+ req_param->opt_type = HCCS_START_RETRAINING;
+ ret = hccs_pcc_cmd_send(hdev, HCCS_PM_INC_LANE, &desc);
+ if (ret)
+ dev_err(hdev->dev, "start hpcs retraining failed, ret = %d.\n",
+ ret);
+
+ return ret;
+}
+
+static int hccs_start_inc_lane(struct hccs_dev *hdev, u8 type)
+{
+ int ret;
+
+ ret = hccs_prepare_inc_lane(hdev, type);
+ if (ret)
+ return ret;
+
+ ret = hccs_wait_serdes_adapt_completed(hdev, type);
+ if (ret)
+ return ret;
+
+ return hccs_start_hpcs_retraining(hdev, type);
+}
+
+static int hccs_start_dec_lane(struct hccs_dev *hdev, u8 type)
+{
+ struct hccs_desc desc;
+ u8 *port_type;
+ int ret;
+
+ hccs_init_req_desc(&desc);
+ port_type = (u8 *)desc.req.data;
+ *port_type = type;
+ ret = hccs_pcc_cmd_send(hdev, HCCS_PM_DEC_LANE, &desc);
+ if (ret)
+ dev_err(hdev->dev, "start to decrease lane failed, ret = %d.\n",
+ ret);
+
+ return ret;
+}
+
+static ssize_t dec_lane_of_type_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hccs_dev *hdev = device_kobj_to_hccs_dev(kobj);
+ bool all_in_idle;
+ u8 port_type;
+ int ret;
+
+ ret = hccs_parse_pm_port_type(hdev, buf, &port_type);
+ if (ret)
+ return ret;
+
+ mutex_lock(&hdev->lock);
+ ret = hccs_get_all_spec_port_idle_sta(hdev, port_type, &all_in_idle);
+ if (ret)
+ goto out;
+ if (!all_in_idle) {
+ ret = -EBUSY;
+ dev_err(hdev->dev, "please don't decrese lanes on high load with %s, ret = %d.\n",
+ hccs_port_type_to_name(hdev, port_type), ret);
+ goto out;
+ }
+
+ ret = hccs_start_dec_lane(hdev, port_type);
+out:
+ mutex_unlock(&hdev->lock);
+
+ return ret == 0 ? count : ret;
+}
+static struct kobj_attribute dec_lane_of_type_attr =
+ __ATTR(dec_lane_of_type, 0200, NULL, dec_lane_of_type_store);
+
+static ssize_t inc_lane_of_type_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hccs_dev *hdev = device_kobj_to_hccs_dev(kobj);
+ bool full_lane;
+ u8 port_type;
+ int ret;
+
+ ret = hccs_parse_pm_port_type(hdev, buf, &port_type);
+ if (ret)
+ return ret;
+
+ mutex_lock(&hdev->lock);
+ ret = hccs_get_all_spec_port_full_lane_sta(hdev, port_type, &full_lane);
+ if (ret || full_lane)
+ goto out;
+
+ ret = hccs_start_inc_lane(hdev, port_type);
+out:
+ mutex_unlock(&hdev->lock);
+ return ret == 0 ? count : ret;
+}
+static struct kobj_attribute inc_lane_of_type_attr =
+ __ATTR(inc_lane_of_type, 0200, NULL, inc_lane_of_type_store);
+
+static ssize_t available_inc_dec_lane_types_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ struct hccs_dev *hdev = device_kobj_to_hccs_dev(kobj);
+
+ if (hdev->caps & HCCS_CAPS_HCCS_V2_PM)
+ return sysfs_emit(buf, "%s\n",
+ hccs_port_type_to_name(hdev, HCCS_V2));
+
+ return -EINVAL;
+}
+static struct kobj_attribute available_inc_dec_lane_types_attr =
+ __ATTR(available_inc_dec_lane_types, 0444,
+ available_inc_dec_lane_types_show, NULL);
+
+static ssize_t used_types_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct hccs_dev *hdev = device_kobj_to_hccs_dev(kobj);
+ int len = 0;
+ u16 i;
+
+ for (i = 0; i < hdev->used_type_num - 1; i++)
+ len += sysfs_emit_at(buf, len, "%s ", hdev->type_name_maps[i].name);
+ len += sysfs_emit_at(buf, len, "%s\n", hdev->type_name_maps[i].name);
+
+ return len;
+}
+static struct kobj_attribute used_types_attr =
+ __ATTR(used_types, 0444, used_types_show, NULL);
+
+static void hccs_remove_misc_sysfs(struct hccs_dev *hdev)
+{
+ sysfs_remove_file(&hdev->dev->kobj, &used_types_attr.attr);
+
+ if (!(hdev->caps & HCCS_CAPS_HCCS_V2_PM))
+ return;
+
+ sysfs_remove_file(&hdev->dev->kobj,
+ &available_inc_dec_lane_types_attr.attr);
+ sysfs_remove_file(&hdev->dev->kobj, &dec_lane_of_type_attr.attr);
+ sysfs_remove_file(&hdev->dev->kobj, &inc_lane_of_type_attr.attr);
+}
+
+static int hccs_add_misc_sysfs(struct hccs_dev *hdev)
+{
+ int ret;
+
+ ret = sysfs_create_file(&hdev->dev->kobj, &used_types_attr.attr);
+ if (ret)
+ return ret;
+
+ if (!(hdev->caps & HCCS_CAPS_HCCS_V2_PM))
+ return 0;
+
+ ret = sysfs_create_file(&hdev->dev->kobj,
+ &available_inc_dec_lane_types_attr.attr);
+ if (ret)
+ goto used_types_remove;
+
+ ret = sysfs_create_file(&hdev->dev->kobj, &dec_lane_of_type_attr.attr);
+ if (ret)
+ goto inc_dec_lane_types_remove;
+
+ ret = sysfs_create_file(&hdev->dev->kobj, &inc_lane_of_type_attr.attr);
+ if (ret)
+ goto dec_lane_of_type_remove;
+
+ return 0;
+
+dec_lane_of_type_remove:
+ sysfs_remove_file(&hdev->dev->kobj, &dec_lane_of_type_attr.attr);
+inc_dec_lane_types_remove:
+ sysfs_remove_file(&hdev->dev->kobj,
+ &available_inc_dec_lane_types_attr.attr);
+used_types_remove:
+ sysfs_remove_file(&hdev->dev->kobj, &used_types_attr.attr);
+ return ret;
+}
+
static void hccs_remove_die_dir(struct hccs_die_info *die)
{
struct hccs_port_info *port;
@@ -1152,6 +1630,8 @@ static void hccs_remove_topo_dirs(struct hccs_dev *hdev)
for (i = 0; i < hdev->chip_num; i++)
hccs_remove_chip_dir(&hdev->chips[i]);
+
+ hccs_remove_misc_sysfs(hdev);
}
static int hccs_create_hccs_dir(struct hccs_dev *hdev,
@@ -1247,6 +1727,12 @@ static int hccs_create_topo_dirs(struct hccs_dev *hdev)
}
}
+ ret = hccs_add_misc_sysfs(hdev);
+ if (ret) {
+ dev_err(hdev->dev, "create misc sysfs interface failed, ret = %d\n", ret);
+ goto err;
+ }
+
return 0;
err:
for (k = 0; k < id; k++)
@@ -1297,6 +1783,10 @@ static int hccs_probe(struct platform_device *pdev)
if (rc)
goto unregister_pcc_chan;
+ rc = hccs_init_type_name_maps(hdev);
+ if (rc)
+ goto unregister_pcc_chan;
+
rc = hccs_create_topo_dirs(hdev);
if (rc)
goto unregister_pcc_chan;
@@ -1342,7 +1832,7 @@ MODULE_DEVICE_TABLE(acpi, hccs_acpi_match);
static struct platform_driver hccs_driver = {
.probe = hccs_probe,
- .remove_new = hccs_remove,
+ .remove = hccs_remove,
.driver = {
.name = "kunpeng_hccs",
.acpi_match_table = hccs_acpi_match,
diff --git a/drivers/soc/hisilicon/kunpeng_hccs.h b/drivers/soc/hisilicon/kunpeng_hccs.h
index c3adbc01b471..dc267136919b 100644
--- a/drivers/soc/hisilicon/kunpeng_hccs.h
+++ b/drivers/soc/hisilicon/kunpeng_hccs.h
@@ -10,6 +10,19 @@
* | P0 | P1 | P2 | P3 | P0 | P1 | P2 | P3 | P0 | P1 | P2 | P3 |P0 | P1 | P2 | P3 |
*/
+enum hccs_port_type {
+ HCCS_V1 = 1,
+ HCCS_V2,
+};
+
+#define HCCS_IP_PREFIX "HCCS-v"
+#define HCCS_IP_MAX 255
+#define HCCS_NAME_MAX_LEN 9
+struct hccs_type_name_map {
+ u8 type;
+ char name[HCCS_NAME_MAX_LEN + 1];
+};
+
/*
* This value cannot be 255, otherwise the loop of the multi-BD communication
* case cannot end.
@@ -19,7 +32,7 @@
struct hccs_port_info {
u8 port_id;
u8 port_type;
- u8 lane_mode;
+ u8 max_lane_num;
bool enable; /* if the port is enabled */
struct kobject kobj;
bool dir_created;
@@ -67,13 +80,18 @@ struct hccs_verspecific_data {
bool has_txdone_irq;
};
+#define HCCS_CAPS_HCCS_V2_PM BIT_ULL(0)
+
struct hccs_dev {
struct device *dev;
struct acpi_device *acpi_dev;
const struct hccs_verspecific_data *verspec_data;
+ /* device capabilities from firmware, like HCCS_CAPS_xxx. */
u64 caps;
u8 chip_num;
struct hccs_chip_info *chips;
+ u16 used_type_num;
+ struct hccs_type_name_map *type_name_maps;
u8 chan_id;
struct mutex lock;
struct hccs_mbox_client_info cl_info;
@@ -91,6 +109,9 @@ enum hccs_subcmd_type {
HCCS_GET_DIE_PORTS_LANE_STA,
HCCS_GET_DIE_PORTS_LINK_STA,
HCCS_GET_DIE_PORTS_CRC_ERR_CNT,
+ HCCS_GET_PORT_IDLE_STATUS,
+ HCCS_PM_DEC_LANE,
+ HCCS_PM_INC_LANE,
HCCS_SUB_CMD_MAX = 255,
};
@@ -113,7 +134,7 @@ struct hccs_die_info_rsp_data {
struct hccs_port_attr {
u8 port_id;
u8 port_type;
- u8 lane_mode;
+ u8 max_lane_num;
u8 enable : 1; /* if the port is enabled */
u16 rsv[2];
};
@@ -134,6 +155,14 @@ struct hccs_port_comm_req_param {
u8 port_id;
};
+#define HCCS_PREPARE_INC_LANE 1
+#define HCCS_GET_ADAPT_RES 2
+#define HCCS_START_RETRAINING 3
+struct hccs_inc_lane_req_param {
+ u8 port_type;
+ u8 opt_type;
+};
+
#define HCCS_PORT_RESET 1
#define HCCS_PORT_SETUP 2
#define HCCS_PORT_CONFIG 3
diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile
index 3ad321ca608a..ca6a5fa1618f 100644
--- a/drivers/soc/imx/Makefile
+++ b/drivers/soc/imx/Makefile
@@ -3,4 +3,4 @@ ifeq ($(CONFIG_ARM),y)
obj-$(CONFIG_ARCH_MXC) += soc-imx.o
endif
obj-$(CONFIG_SOC_IMX8M) += soc-imx8m.o
-obj-$(CONFIG_SOC_IMX9) += imx93-src.o
+obj-$(CONFIG_SOC_IMX9) += imx93-src.o soc-imx9.o
diff --git a/drivers/soc/imx/soc-imx8m.c b/drivers/soc/imx/soc-imx8m.c
index ec87d9d878f3..3ed8161d7d28 100644
--- a/drivers/soc/imx/soc-imx8m.c
+++ b/drivers/soc/imx/soc-imx8m.c
@@ -30,11 +30,9 @@
struct imx8_soc_data {
char *name;
- u32 (*soc_revision)(void);
+ int (*soc_revision)(u32 *socrev, u64 *socuid);
};
-static u64 soc_uid;
-
#ifdef CONFIG_HAVE_ARM_SMCCC
static u32 imx8mq_soc_revision_from_atf(void)
{
@@ -51,24 +49,27 @@ static u32 imx8mq_soc_revision_from_atf(void)
static inline u32 imx8mq_soc_revision_from_atf(void) { return 0; };
#endif
-static u32 __init imx8mq_soc_revision(void)
+static int imx8mq_soc_revision(u32 *socrev, u64 *socuid)
{
- struct device_node *np;
+ struct device_node *np __free(device_node) =
+ of_find_compatible_node(NULL, NULL, "fsl,imx8mq-ocotp");
void __iomem *ocotp_base;
u32 magic;
u32 rev;
struct clk *clk;
+ int ret;
- np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-ocotp");
if (!np)
- return 0;
+ return -EINVAL;
ocotp_base = of_iomap(np, 0);
- WARN_ON(!ocotp_base);
+ if (!ocotp_base)
+ return -EINVAL;
+
clk = of_clk_get_by_name(np, NULL);
if (IS_ERR(clk)) {
- WARN_ON(IS_ERR(clk));
- return 0;
+ ret = PTR_ERR(clk);
+ goto err_clk;
}
clk_prepare_enable(clk);
@@ -84,71 +85,78 @@ static u32 __init imx8mq_soc_revision(void)
rev = REV_B1;
}
- soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH);
- soc_uid <<= 32;
- soc_uid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW);
+ *socuid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH);
+ *socuid <<= 32;
+ *socuid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW);
+
+ *socrev = rev;
clk_disable_unprepare(clk);
clk_put(clk);
iounmap(ocotp_base);
- of_node_put(np);
- return rev;
+ return 0;
+
+err_clk:
+ iounmap(ocotp_base);
+ return ret;
}
-static void __init imx8mm_soc_uid(void)
+static int imx8mm_soc_uid(u64 *socuid)
{
+ struct device_node *np __free(device_node) =
+ of_find_compatible_node(NULL, NULL, "fsl,imx8mm-ocotp");
void __iomem *ocotp_base;
- struct device_node *np;
struct clk *clk;
+ int ret = 0;
u32 offset = of_machine_is_compatible("fsl,imx8mp") ?
IMX8MP_OCOTP_UID_OFFSET : 0;
- np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-ocotp");
if (!np)
- return;
+ return -EINVAL;
ocotp_base = of_iomap(np, 0);
- WARN_ON(!ocotp_base);
+ if (!ocotp_base)
+ return -EINVAL;
+
clk = of_clk_get_by_name(np, NULL);
if (IS_ERR(clk)) {
- WARN_ON(IS_ERR(clk));
- return;
+ ret = PTR_ERR(clk);
+ goto err_clk;
}
clk_prepare_enable(clk);
- soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH + offset);
- soc_uid <<= 32;
- soc_uid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW + offset);
+ *socuid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH + offset);
+ *socuid <<= 32;
+ *socuid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW + offset);
clk_disable_unprepare(clk);
clk_put(clk);
+
+err_clk:
iounmap(ocotp_base);
- of_node_put(np);
+ return ret;
}
-static u32 __init imx8mm_soc_revision(void)
+static int imx8mm_soc_revision(u32 *socrev, u64 *socuid)
{
- struct device_node *np;
+ struct device_node *np __free(device_node) =
+ of_find_compatible_node(NULL, NULL, "fsl,imx8mm-anatop");
void __iomem *anatop_base;
- u32 rev;
- np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-anatop");
if (!np)
- return 0;
+ return -EINVAL;
anatop_base = of_iomap(np, 0);
- WARN_ON(!anatop_base);
+ if (!anatop_base)
+ return -EINVAL;
- rev = readl_relaxed(anatop_base + ANADIG_DIGPROG_IMX8MM);
+ *socrev = readl_relaxed(anatop_base + ANADIG_DIGPROG_IMX8MM);
iounmap(anatop_base);
- of_node_put(np);
- imx8mm_soc_uid();
-
- return rev;
+ return imx8mm_soc_uid(socuid);
}
static const struct imx8_soc_data imx8mq_soc_data = {
@@ -179,21 +187,34 @@ static __maybe_unused const struct of_device_id imx8_soc_match[] = {
{ }
};
-#define imx8_revision(soc_rev) \
- soc_rev ? \
- kasprintf(GFP_KERNEL, "%d.%d", (soc_rev >> 4) & 0xf, soc_rev & 0xf) : \
+#define imx8_revision(dev, soc_rev) \
+ (soc_rev) ? \
+ devm_kasprintf((dev), GFP_KERNEL, "%d.%d", ((soc_rev) >> 4) & 0xf, (soc_rev) & 0xf) : \
"unknown"
-static int __init imx8_soc_init(void)
+static void imx8m_unregister_soc(void *data)
+{
+ soc_device_unregister(data);
+}
+
+static void imx8m_unregister_cpufreq(void *data)
+{
+ platform_device_unregister(data);
+}
+
+static int imx8m_soc_probe(struct platform_device *pdev)
{
struct soc_device_attribute *soc_dev_attr;
- struct soc_device *soc_dev;
+ struct platform_device *cpufreq_dev;
+ const struct imx8_soc_data *data;
+ struct device *dev = &pdev->dev;
const struct of_device_id *id;
+ struct soc_device *soc_dev;
u32 soc_rev = 0;
- const struct imx8_soc_data *data;
+ u64 soc_uid = 0;
int ret;
- soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+ soc_dev_attr = devm_kzalloc(dev, sizeof(*soc_dev_attr), GFP_KERNEL);
if (!soc_dev_attr)
return -ENOMEM;
@@ -201,55 +222,85 @@ static int __init imx8_soc_init(void)
ret = of_property_read_string(of_root, "model", &soc_dev_attr->machine);
if (ret)
- goto free_soc;
+ return ret;
id = of_match_node(imx8_soc_match, of_root);
- if (!id) {
- ret = -ENODEV;
- goto free_soc;
- }
+ if (!id)
+ return -ENODEV;
data = id->data;
if (data) {
soc_dev_attr->soc_id = data->name;
- if (data->soc_revision)
- soc_rev = data->soc_revision();
+ if (data->soc_revision) {
+ ret = data->soc_revision(&soc_rev, &soc_uid);
+ if (ret)
+ return ret;
+ }
}
- soc_dev_attr->revision = imx8_revision(soc_rev);
- if (!soc_dev_attr->revision) {
- ret = -ENOMEM;
- goto free_soc;
- }
+ soc_dev_attr->revision = imx8_revision(dev, soc_rev);
+ if (!soc_dev_attr->revision)
+ return -ENOMEM;
- soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", soc_uid);
- if (!soc_dev_attr->serial_number) {
- ret = -ENOMEM;
- goto free_rev;
- }
+ soc_dev_attr->serial_number = devm_kasprintf(dev, GFP_KERNEL, "%016llX", soc_uid);
+ if (!soc_dev_attr->serial_number)
+ return -ENOMEM;
soc_dev = soc_device_register(soc_dev_attr);
- if (IS_ERR(soc_dev)) {
- ret = PTR_ERR(soc_dev);
- goto free_serial_number;
- }
+ if (IS_ERR(soc_dev))
+ return PTR_ERR(soc_dev);
+
+ ret = devm_add_action(dev, imx8m_unregister_soc, soc_dev);
+ if (ret)
+ return ret;
pr_info("SoC: %s revision %s\n", soc_dev_attr->soc_id,
soc_dev_attr->revision);
- if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT))
- platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0);
+ if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT)) {
+ cpufreq_dev = platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0);
+ if (IS_ERR(cpufreq_dev))
+ return dev_err_probe(dev, PTR_ERR(cpufreq_dev),
+ "Failed to register imx-cpufreq-dev device\n");
+ ret = devm_add_action(dev, imx8m_unregister_cpufreq, cpufreq_dev);
+ if (ret)
+ return ret;
+ }
return 0;
+}
-free_serial_number:
- kfree(soc_dev_attr->serial_number);
-free_rev:
- if (strcmp(soc_dev_attr->revision, "unknown"))
- kfree(soc_dev_attr->revision);
-free_soc:
- kfree(soc_dev_attr);
- return ret;
+static struct platform_driver imx8m_soc_driver = {
+ .probe = imx8m_soc_probe,
+ .driver = {
+ .name = "imx8m-soc",
+ },
+};
+
+static int __init imx8_soc_init(void)
+{
+ struct platform_device *pdev;
+ int ret;
+
+ /* No match means this is non-i.MX8M hardware, do nothing. */
+ if (!of_match_node(imx8_soc_match, of_root))
+ return 0;
+
+ ret = platform_driver_register(&imx8m_soc_driver);
+ if (ret) {
+ pr_err("Failed to register imx8m-soc platform driver: %d\n", ret);
+ return ret;
+ }
+
+ pdev = platform_device_register_simple("imx8m-soc", -1, NULL, 0);
+ if (IS_ERR(pdev)) {
+ pr_err("Failed to register imx8m-soc platform device: %ld\n", PTR_ERR(pdev));
+ platform_driver_unregister(&imx8m_soc_driver);
+ return PTR_ERR(pdev);
+ }
+
+ return 0;
}
device_initcall(imx8_soc_init);
+MODULE_DESCRIPTION("NXP i.MX8M SoC driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/soc/imx/soc-imx9.c b/drivers/soc/imx/soc-imx9.c
new file mode 100644
index 000000000000..b46d22cf0212
--- /dev/null
+++ b/drivers/soc/imx/soc-imx9.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2024 NXP
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sys_soc.h>
+
+#define IMX_SIP_GET_SOC_INFO 0xc2000006
+#define SOC_ID(x) (((x) & 0xFFFF) >> 8)
+#define SOC_REV_MAJOR(x) ((((x) >> 28) & 0xF) - 0x9)
+#define SOC_REV_MINOR(x) (((x) >> 24) & 0xF)
+
+static int imx9_soc_probe(struct platform_device *pdev)
+{
+ struct soc_device_attribute *attr;
+ struct arm_smccc_res res;
+ struct soc_device *sdev;
+ u32 soc_id, rev_major, rev_minor;
+ u64 uid127_64, uid63_0;
+ int err;
+
+ attr = kzalloc(sizeof(*attr), GFP_KERNEL);
+ if (!attr)
+ return -ENOMEM;
+
+ err = of_property_read_string(of_root, "model", &attr->machine);
+ if (err) {
+ pr_err("%s: missing model property: %d\n", __func__, err);
+ goto attr;
+ }
+
+ attr->family = kasprintf(GFP_KERNEL, "Freescale i.MX");
+
+ /*
+ * Retrieve the soc id, rev & uid info:
+ * res.a1[31:16]: soc revision;
+ * res.a1[15:0]: soc id;
+ * res.a2: uid[127:64];
+ * res.a3: uid[63:0];
+ */
+ arm_smccc_smc(IMX_SIP_GET_SOC_INFO, 0, 0, 0, 0, 0, 0, 0, &res);
+ if (res.a0 != SMCCC_RET_SUCCESS) {
+ pr_err("%s: SMC failed: 0x%lx\n", __func__, res.a0);
+ err = -EINVAL;
+ goto family;
+ }
+
+ soc_id = SOC_ID(res.a1);
+ rev_major = SOC_REV_MAJOR(res.a1);
+ rev_minor = SOC_REV_MINOR(res.a1);
+
+ attr->soc_id = kasprintf(GFP_KERNEL, "i.MX%2x", soc_id);
+ attr->revision = kasprintf(GFP_KERNEL, "%d.%d", rev_major, rev_minor);
+
+ uid127_64 = res.a2;
+ uid63_0 = res.a3;
+ attr->serial_number = kasprintf(GFP_KERNEL, "%016llx%016llx", uid127_64, uid63_0);
+
+ sdev = soc_device_register(attr);
+ if (IS_ERR(sdev)) {
+ err = PTR_ERR(sdev);
+ pr_err("%s failed to register SoC as a device: %d\n", __func__, err);
+ goto serial_number;
+ }
+
+ return 0;
+
+serial_number:
+ kfree(attr->serial_number);
+ kfree(attr->revision);
+ kfree(attr->soc_id);
+family:
+ kfree(attr->family);
+attr:
+ kfree(attr);
+ return err;
+}
+
+static __maybe_unused const struct of_device_id imx9_soc_match[] = {
+ { .compatible = "fsl,imx93", },
+ { .compatible = "fsl,imx95", },
+ { }
+};
+
+#define IMX_SOC_DRIVER "imx9-soc"
+
+static struct platform_driver imx9_soc_driver = {
+ .probe = imx9_soc_probe,
+ .driver = {
+ .name = IMX_SOC_DRIVER,
+ },
+};
+
+static int __init imx9_soc_init(void)
+{
+ int ret;
+ struct platform_device *pdev;
+
+ /* No match means it is not an i.MX 9 series SoC, do nothing. */
+ if (!of_match_node(imx9_soc_match, of_root))
+ return 0;
+
+ ret = platform_driver_register(&imx9_soc_driver);
+ if (ret) {
+ pr_err("failed to register imx9_soc platform driver: %d\n", ret);
+ return ret;
+ }
+
+ pdev = platform_device_register_simple(IMX_SOC_DRIVER, -1, NULL, 0);
+ if (IS_ERR(pdev)) {
+ pr_err("failed to register imx9_soc platform device: %ld\n", PTR_ERR(pdev));
+ platform_driver_unregister(&imx9_soc_driver);
+ return PTR_ERR(pdev);
+ }
+
+ return 0;
+}
+device_initcall(imx9_soc_init);
+
+MODULE_AUTHOR("NXP");
+MODULE_DESCRIPTION("NXP i.MX9 SoC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/ixp4xx/ixp4xx-npe.c b/drivers/soc/ixp4xx/ixp4xx-npe.c
index 35825ee95dff..33e2e0366f19 100644
--- a/drivers/soc/ixp4xx/ixp4xx-npe.c
+++ b/drivers/soc/ixp4xx/ixp4xx-npe.c
@@ -759,11 +759,12 @@ static struct platform_driver ixp4xx_npe_driver = {
.of_match_table = ixp4xx_npe_of_match,
},
.probe = ixp4xx_npe_probe,
- .remove_new = ixp4xx_npe_remove,
+ .remove = ixp4xx_npe_remove,
};
module_platform_driver(ixp4xx_npe_driver);
MODULE_AUTHOR("Krzysztof Halasa");
+MODULE_DESCRIPTION("Intel IXP4xx Network Processor Engine driver");
MODULE_LICENSE("GPL v2");
MODULE_FIRMWARE(NPE_A_FIRMWARE);
MODULE_FIRMWARE(NPE_B_FIRMWARE);
diff --git a/drivers/soc/ixp4xx/ixp4xx-qmgr.c b/drivers/soc/ixp4xx/ixp4xx-qmgr.c
index 244ad8d7e80b..475e229039e3 100644
--- a/drivers/soc/ixp4xx/ixp4xx-qmgr.c
+++ b/drivers/soc/ixp4xx/ixp4xx-qmgr.c
@@ -461,10 +461,11 @@ static struct platform_driver ixp4xx_qmgr_driver = {
.of_match_table = ixp4xx_qmgr_of_match,
},
.probe = ixp4xx_qmgr_probe,
- .remove_new = ixp4xx_qmgr_remove,
+ .remove = ixp4xx_qmgr_remove,
};
module_platform_driver(ixp4xx_qmgr_driver);
+MODULE_DESCRIPTION("Intel IXP4xx Queue Manager driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Krzysztof Halasa");
diff --git a/drivers/soc/litex/Kconfig b/drivers/soc/litex/Kconfig
index e6ba3573a772..f3f869639588 100644
--- a/drivers/soc/litex/Kconfig
+++ b/drivers/soc/litex/Kconfig
@@ -7,7 +7,7 @@ config LITEX
config LITEX_SOC_CONTROLLER
tristate "Enable LiteX SoC Controller driver"
- depends on OF || COMPILE_TEST
+ depends on OF
depends on HAS_IOMEM
select LITEX
help
diff --git a/drivers/soc/litex/litex_soc_ctrl.c b/drivers/soc/litex/litex_soc_ctrl.c
index 10813299aa10..104a5f9bfd26 100644
--- a/drivers/soc/litex/litex_soc_ctrl.c
+++ b/drivers/soc/litex/litex_soc_ctrl.c
@@ -69,26 +69,21 @@ static int litex_check_csr_access(void __iomem *reg_addr)
struct litex_soc_ctrl_device {
void __iomem *base;
- struct notifier_block reset_nb;
};
-static int litex_reset_handler(struct notifier_block *this, unsigned long mode,
- void *cmd)
+static int litex_reset_handler(struct sys_off_data *data)
{
- struct litex_soc_ctrl_device *soc_ctrl_dev =
- container_of(this, struct litex_soc_ctrl_device, reset_nb);
+ struct litex_soc_ctrl_device *soc_ctrl_dev = data->cb_data;
litex_write32(soc_ctrl_dev->base + RESET_REG_OFF, RESET_REG_VALUE);
return NOTIFY_DONE;
}
-#ifdef CONFIG_OF
static const struct of_device_id litex_soc_ctrl_of_match[] = {
{.compatible = "litex,soc-controller"},
{},
};
MODULE_DEVICE_TABLE(of, litex_soc_ctrl_of_match);
-#endif /* CONFIG_OF */
static int litex_soc_ctrl_probe(struct platform_device *pdev)
{
@@ -107,11 +102,9 @@ static int litex_soc_ctrl_probe(struct platform_device *pdev)
if (error)
return error;
- platform_set_drvdata(pdev, soc_ctrl_dev);
-
- soc_ctrl_dev->reset_nb.notifier_call = litex_reset_handler;
- soc_ctrl_dev->reset_nb.priority = 128;
- error = register_restart_handler(&soc_ctrl_dev->reset_nb);
+ error = devm_register_restart_handler(&pdev->dev,
+ litex_reset_handler,
+ soc_ctrl_dev);
if (error) {
dev_warn(&pdev->dev, "cannot register restart handler: %d\n",
error);
@@ -120,20 +113,12 @@ static int litex_soc_ctrl_probe(struct platform_device *pdev)
return 0;
}
-static void litex_soc_ctrl_remove(struct platform_device *pdev)
-{
- struct litex_soc_ctrl_device *soc_ctrl_dev = platform_get_drvdata(pdev);
-
- unregister_restart_handler(&soc_ctrl_dev->reset_nb);
-}
-
static struct platform_driver litex_soc_ctrl_driver = {
.driver = {
.name = "litex-soc-controller",
- .of_match_table = of_match_ptr(litex_soc_ctrl_of_match)
+ .of_match_table = litex_soc_ctrl_of_match,
},
.probe = litex_soc_ctrl_probe,
- .remove_new = litex_soc_ctrl_remove,
};
module_platform_driver(litex_soc_ctrl_driver);
diff --git a/drivers/soc/loongson/loongson2_guts.c b/drivers/soc/loongson/loongson2_guts.c
index ef352a0f5022..16913c3ef65c 100644
--- a/drivers/soc/loongson/loongson2_guts.c
+++ b/drivers/soc/loongson/loongson2_guts.c
@@ -114,8 +114,11 @@ static int loongson2_guts_probe(struct platform_device *pdev)
if (of_property_read_string(root, "model", &machine))
of_property_read_string_index(root, "compatible", 0, &machine);
of_node_put(root);
- if (machine)
+ if (machine) {
soc_dev_attr.machine = devm_kstrdup(dev, machine, GFP_KERNEL);
+ if (!soc_dev_attr.machine)
+ return -ENOMEM;
+ }
svr = loongson2_guts_get_svr();
soc_die = loongson2_soc_die_match(svr, loongson2_soc_die);
@@ -169,7 +172,7 @@ static struct platform_driver loongson2_guts_driver = {
.of_match_table = loongson2_guts_of_match,
},
.probe = loongson2_guts_probe,
- .remove_new = loongson2_guts_remove,
+ .remove = loongson2_guts_remove,
};
static int __init loongson2_guts_init(void)
diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
index 0810b5b0c688..d7293977f06e 100644
--- a/drivers/soc/mediatek/Kconfig
+++ b/drivers/soc/mediatek/Kconfig
@@ -26,6 +26,17 @@ config MTK_DEVAPC
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
@@ -68,4 +79,14 @@ config MTK_SVS
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
diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
index 9d3ce7878c5c..0665573e3c4b 100644
--- a/drivers/soc/mediatek/Makefile
+++ b/drivers/soc/mediatek/Makefile
@@ -1,9 +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
diff --git a/drivers/soc/mediatek/mtk-cmdq-helper.c b/drivers/soc/mediatek/mtk-cmdq-helper.c
index b0cd071c4719..455221e8de24 100644
--- a/drivers/soc/mediatek/mtk-cmdq-helper.c
+++ b/drivers/soc/mediatek/mtk-cmdq-helper.c
@@ -12,9 +12,13 @@
#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 1
+#define CMDQ_JUMP_RELATIVE 0
+#define CMDQ_JUMP_ABSOLUTE 1
struct cmdq_instruction {
union {
@@ -42,6 +46,16 @@ struct cmdq_instruction {
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)
{
@@ -55,7 +69,7 @@ int cmdq_dev_get_client_reg(struct device *dev,
"mediatek,gce-client-reg",
3, idx, &spec);
if (err < 0) {
- dev_err(dev,
+ dev_warn(dev,
"error %d can't parse gce-client-reg property (%d)",
err, idx);
@@ -105,22 +119,16 @@ void cmdq_mbox_destroy(struct cmdq_client *client)
}
EXPORT_SYMBOL(cmdq_mbox_destroy);
-struct cmdq_pkt *cmdq_pkt_create(struct cmdq_client *client, size_t size)
+int cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt, size_t size)
{
- struct cmdq_pkt *pkt;
struct device *dev;
dma_addr_t dma_addr;
- pkt = kzalloc(sizeof(*pkt), GFP_KERNEL);
- if (!pkt)
- return ERR_PTR(-ENOMEM);
pkt->va_base = kzalloc(size, GFP_KERNEL);
- if (!pkt->va_base) {
- kfree(pkt);
- return ERR_PTR(-ENOMEM);
- }
+ if (!pkt->va_base)
+ return -ENOMEM;
+
pkt->buf_size = size;
- pkt->cl = (void *)client;
dev = client->chan->mbox->dev;
dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size,
@@ -128,24 +136,20 @@ struct cmdq_pkt *cmdq_pkt_create(struct cmdq_client *client, size_t size)
if (dma_mapping_error(dev, dma_addr)) {
dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size);
kfree(pkt->va_base);
- kfree(pkt);
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
}
pkt->pa_base = dma_addr;
- return pkt;
+ return 0;
}
EXPORT_SYMBOL(cmdq_pkt_create);
-void cmdq_pkt_destroy(struct cmdq_pkt *pkt)
+void cmdq_pkt_destroy(struct cmdq_client *client, struct cmdq_pkt *pkt)
{
- struct cmdq_client *client = (struct cmdq_client *)pkt->cl;
-
dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size,
DMA_TO_DEVICE);
kfree(pkt->va_base);
- kfree(pkt);
}
EXPORT_SYMBOL(cmdq_pkt_destroy);
@@ -176,15 +180,23 @@ static int cmdq_pkt_append_command(struct cmdq_pkt *pkt,
return 0;
}
-int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value)
+static int cmdq_pkt_mask(struct cmdq_pkt *pkt, u32 mask)
{
- struct cmdq_instruction inst;
-
- inst.op = CMDQ_CODE_WRITE;
- inst.value = value;
- inst.offset = offset;
- inst.subsys = subsys;
+ 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);
@@ -192,36 +204,30 @@ EXPORT_SYMBOL(cmdq_pkt_write);
int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
u16 offset, u32 value, u32 mask)
{
- struct cmdq_instruction inst = { {0} };
u16 offset_mask = offset;
int err;
- if (mask != 0xffffffff) {
- inst.op = CMDQ_CODE_MASK;
- inst.mask = ~mask;
- err = cmdq_pkt_append_command(pkt, inst);
+ if (mask != GENMASK(31, 0)) {
+ err = cmdq_pkt_mask(pkt, mask);
if (err < 0)
return err;
offset_mask |= CMDQ_WRITE_ENABLE_MASK;
}
- err = cmdq_pkt_write(pkt, subsys, offset_mask, value);
-
- return err;
+ return cmdq_pkt_write(pkt, subsys, offset_mask, value);
}
EXPORT_SYMBOL(cmdq_pkt_write_mask);
int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, u16 addr_low,
u16 reg_idx)
{
- struct cmdq_instruction inst = {};
-
- inst.op = CMDQ_CODE_READ_S;
- inst.dst_t = CMDQ_REG_TYPE;
- inst.sop = high_addr_reg_idx;
- inst.reg_dst = reg_idx;
- inst.src_reg = addr_low;
-
+ 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);
@@ -229,14 +235,13 @@ EXPORT_SYMBOL(cmdq_pkt_read_s);
int cmdq_pkt_write_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx,
u16 addr_low, u16 src_reg_idx)
{
- struct cmdq_instruction inst = {};
-
- inst.op = CMDQ_CODE_WRITE_S;
- inst.src_t = CMDQ_REG_TYPE;
- inst.sop = high_addr_reg_idx;
- inst.offset = addr_low;
- inst.src_reg = src_reg_idx;
-
+ 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);
@@ -244,22 +249,19 @@ 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 = {};
+ 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;
- inst.op = CMDQ_CODE_MASK;
- inst.mask = ~mask;
- err = cmdq_pkt_append_command(pkt, inst);
+ err = cmdq_pkt_mask(pkt, mask);
if (err < 0)
return err;
- inst.mask = 0;
- inst.op = CMDQ_CODE_WRITE_S_MASK;
- inst.src_t = CMDQ_REG_TYPE;
- inst.sop = high_addr_reg_idx;
- inst.offset = addr_low;
- inst.src_reg = src_reg_idx;
-
return cmdq_pkt_append_command(pkt, inst);
}
EXPORT_SYMBOL(cmdq_pkt_write_s_mask);
@@ -267,13 +269,12 @@ EXPORT_SYMBOL(cmdq_pkt_write_s_mask);
int cmdq_pkt_write_s_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx,
u16 addr_low, u32 value)
{
- struct cmdq_instruction inst = {};
-
- inst.op = CMDQ_CODE_WRITE_S;
- inst.sop = high_addr_reg_idx;
- inst.offset = addr_low;
- inst.value = value;
-
+ 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);
@@ -281,50 +282,89 @@ 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 = {};
+ struct cmdq_instruction inst = {
+ .op = CMDQ_CODE_WRITE_S_MASK,
+ .sop = high_addr_reg_idx,
+ .offset = addr_low,
+ .value = value
+ };
int err;
- inst.op = CMDQ_CODE_MASK;
- inst.mask = ~mask;
- err = cmdq_pkt_append_command(pkt, inst);
+ err = cmdq_pkt_mask(pkt, mask);
if (err < 0)
return err;
- inst.op = CMDQ_CODE_WRITE_S_MASK;
- inst.sop = high_addr_reg_idx;
- inst.offset = addr_low;
- inst.value = value;
-
return cmdq_pkt_append_command(pkt, inst);
}
EXPORT_SYMBOL(cmdq_pkt_write_s_mask_value);
+int cmdq_pkt_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 */
+ 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 */
+ 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)
{
- struct cmdq_instruction inst = { {0} };
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;
- inst.op = CMDQ_CODE_WFE;
- inst.value = CMDQ_WFE_OPTION | clear_option;
- inst.event = event;
-
return cmdq_pkt_append_command(pkt, inst);
}
EXPORT_SYMBOL(cmdq_pkt_wfe);
-int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event)
+int cmdq_pkt_acquire_event(struct cmdq_pkt *pkt, u16 event)
{
- struct cmdq_instruction inst = { {0} };
+ 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;
- inst.op = CMDQ_CODE_WFE;
- inst.value = CMDQ_WFE_UPDATE;
- inst.event = event;
+ 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);
}
@@ -332,15 +372,15 @@ EXPORT_SYMBOL(cmdq_pkt_clear_event);
int cmdq_pkt_set_event(struct cmdq_pkt *pkt, u16 event)
{
- struct cmdq_instruction inst = {};
+ 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;
- inst.op = CMDQ_CODE_WFE;
- inst.value = CMDQ_WFE_UPDATE | CMDQ_WFE_UPDATE_VALUE;
- inst.event = event;
-
return cmdq_pkt_append_command(pkt, inst);
}
EXPORT_SYMBOL(cmdq_pkt_set_event);
@@ -348,97 +388,141 @@ EXPORT_SYMBOL(cmdq_pkt_set_event);
int cmdq_pkt_poll(struct cmdq_pkt *pkt, u8 subsys,
u16 offset, u32 value)
{
- struct cmdq_instruction inst = { {0} };
- int err;
-
- inst.op = CMDQ_CODE_POLL;
- inst.value = value;
- inst.offset = offset;
- inst.subsys = subsys;
- err = cmdq_pkt_append_command(pkt, inst);
-
- return err;
+ 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)
{
- struct cmdq_instruction inst = { {0} };
int err;
- inst.op = CMDQ_CODE_MASK;
- inst.mask = ~mask;
- err = cmdq_pkt_append_command(pkt, inst);
+ err = cmdq_pkt_mask(pkt, mask);
if (err < 0)
return err;
offset = offset | CMDQ_POLL_ENABLE_MASK;
- err = cmdq_pkt_poll(pkt, subsys, offset, value);
-
- return err;
+ return cmdq_pkt_poll(pkt, subsys, offset, value);
}
EXPORT_SYMBOL(cmdq_pkt_poll_mask);
-int cmdq_pkt_assign(struct cmdq_pkt *pkt, u16 reg_idx, u32 value)
+int cmdq_pkt_poll_addr(struct cmdq_pkt *pkt, dma_addr_t addr, u32 value, u32 mask)
{
- struct cmdq_instruction inst = {};
+ 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;
+ }
- inst.op = CMDQ_CODE_LOGIC;
+ /*
+ * 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.reg_dst = reg_idx;
+ inst.sop = CMDQ_POLL_ADDR_GPR;
+ inst.value = addr;
+ 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;
- return cmdq_pkt_append_command(pkt, inst);
+ ret = cmdq_pkt_append_command(pkt, inst);
+ if (ret < 0)
+ return ret;
+
+ return 0;
}
-EXPORT_SYMBOL(cmdq_pkt_assign);
+EXPORT_SYMBOL(cmdq_pkt_poll_addr);
-int cmdq_pkt_jump(struct cmdq_pkt *pkt, dma_addr_t 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 = {};
+ 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);
- inst.op = CMDQ_CODE_JUMP;
- inst.offset = CMDQ_JUMP_RELATIVE;
- inst.value = addr >>
- cmdq_get_shift_pa(((struct cmdq_client *)pkt->cl)->chan);
return cmdq_pkt_append_command(pkt, inst);
}
-EXPORT_SYMBOL(cmdq_pkt_jump);
+EXPORT_SYMBOL(cmdq_pkt_logic_command);
-int cmdq_pkt_finalize(struct cmdq_pkt *pkt)
+int cmdq_pkt_assign(struct cmdq_pkt *pkt, u16 reg_idx, u32 value)
{
- struct cmdq_instruction inst = { {0} };
- int err;
-
- /* insert EOC and generate IRQ for each command iteration */
- inst.op = CMDQ_CODE_EOC;
- inst.value = CMDQ_EOC_IRQ_EN;
- err = cmdq_pkt_append_command(pkt, inst);
- if (err < 0)
- return err;
-
- /* JUMP to end */
- inst.op = CMDQ_CODE_JUMP;
- inst.value = CMDQ_JUMP_PASS >>
- cmdq_get_shift_pa(((struct cmdq_client *)pkt->cl)->chan);
- err = cmdq_pkt_append_command(pkt, inst);
-
- return err;
+ 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_finalize);
+EXPORT_SYMBOL(cmdq_pkt_assign);
-int cmdq_pkt_flush_async(struct cmdq_pkt *pkt)
+int cmdq_pkt_jump_abs(struct cmdq_pkt *pkt, dma_addr_t addr, u8 shift_pa)
{
- int err;
- struct cmdq_client *client = (struct cmdq_client *)pkt->cl;
+ struct cmdq_instruction inst = {
+ .op = CMDQ_CODE_JUMP,
+ .offset = CMDQ_JUMP_ABSOLUTE,
+ .value = addr >> shift_pa
+ };
+ return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_jump_abs);
- err = mbox_send_message(client->chan, pkt);
- if (err < 0)
- return err;
- /* We can send next packet immediately, so just call txdone. */
- mbox_client_txdone(client->chan, 0);
+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);
- return 0;
+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_flush_async);
+EXPORT_SYMBOL(cmdq_pkt_eoc);
+MODULE_DESCRIPTION("MediaTek Command Queue (CMDQ) driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/mediatek/mtk-devapc.c b/drivers/soc/mediatek/mtk-devapc.c
index 56cc345552a4..f54c966138b5 100644
--- a/drivers/soc/mediatek/mtk-devapc.c
+++ b/drivers/soc/mediatek/mtk-devapc.c
@@ -273,23 +273,31 @@ static int mtk_devapc_probe(struct platform_device *pdev)
return -EINVAL;
devapc_irq = irq_of_parse_and_map(node, 0);
- if (!devapc_irq)
- return -EINVAL;
+ 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))
- return -EINVAL;
+ 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)
- return 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)
@@ -297,11 +305,12 @@ 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_new = mtk_devapc_remove,
+ .remove = mtk_devapc_remove,
.driver = {
.name = "mtk-devapc",
.of_match_table = mtk_devapc_dt_match,
diff --git a/drivers/soc/mediatek/mtk-dvfsrc.c b/drivers/soc/mediatek/mtk-dvfsrc.c
new file mode 100644
index 000000000000..83bf46fdcf2d
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-dvfsrc.c
@@ -0,0 +1,545 @@
+// 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/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_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)
+
+/* 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)
+
+/* DVFSRC_VCORE */
+#define DVFSRC_V2_VCORE_REQ_VSCP_LEVEL GENMASK(14, 12)
+
+#define DVFSRC_POLL_TIMEOUT_US 1000
+#define STARTUP_TIME_US 1
+
+#define MTK_SIP_DVFSRC_INIT 0x0
+#define MTK_SIP_DVFSRC_START 0x1
+
+struct dvfsrc_bw_constraints {
+ u16 max_dram_nom_bw;
+ u16 max_dram_peak_bw;
+ u16 max_dram_hrt_bw;
+};
+
+struct dvfsrc_opp {
+ u32 vcore_opp;
+ u32 dram_opp;
+};
+
+struct dvfsrc_opp_desc {
+ const struct dvfsrc_opp *opps;
+ u32 num_opp;
+};
+
+struct dvfsrc_soc_data;
+struct mtk_dvfsrc {
+ struct device *dev;
+ 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 struct dvfsrc_opp_desc *opps_desc;
+ 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);
+ 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);
+ const struct dvfsrc_bw_constraints *bw_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_SW_REQ,
+ DVFSRC_SW_REQ2,
+ DVFSRC_LEVEL,
+ DVFSRC_TARGET_LEVEL,
+ DVFSRC_SW_BW,
+ DVFSRC_SW_PEAK_BW,
+ DVFSRC_SW_HRT_BW,
+ DVFSRC_VCORE,
+ 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 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 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 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_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 void __dvfsrc_set_dram_bw_v1(struct mtk_dvfsrc *dvfsrc, u32 reg,
+ u16 max_bw, u16 min_bw, u64 bw)
+{
+ u32 new_bw = (u32)div_u64(bw, 100 * 1000);
+
+ /* If bw constraints (in mbps) are defined make sure to respect them */
+ if (max_bw)
+ new_bw = min(new_bw, max_bw);
+ if (min_bw && new_bw > 0)
+ new_bw = max(new_bw, min_bw);
+
+ dvfsrc_writel(dvfsrc, reg, new_bw);
+}
+
+static void dvfsrc_set_dram_bw_v1(struct mtk_dvfsrc *dvfsrc, u64 bw)
+{
+ u64 max_bw = dvfsrc->dvd->bw_constraints->max_dram_nom_bw;
+
+ __dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_BW, max_bw, 0, bw);
+};
+
+static void dvfsrc_set_dram_peak_bw_v1(struct mtk_dvfsrc *dvfsrc, u64 bw)
+{
+ u64 max_bw = dvfsrc->dvd->bw_constraints->max_dram_peak_bw;
+
+ __dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_PEAK_BW, max_bw, 0, bw);
+}
+
+static void dvfsrc_set_dram_hrt_bw_v1(struct mtk_dvfsrc *dvfsrc, u64 bw)
+{
+ u64 max_bw = dvfsrc->dvd->bw_constraints->max_dram_hrt_bw;
+
+ __dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_HRT_BW, max_bw, 0, 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);
+}
+
+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);
+
+ 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);
+
+ 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)
+ return dev_err_probe(&pdev->dev, -EINVAL, "Cannot start DVFSRC: %lu\n", ares.a0);
+
+ return 0;
+}
+
+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_bw_constraints dvfsrc_bw_constr_mt8183 = { 0, 0, 0 };
+
+static const struct dvfsrc_soc_data mt8183_data = {
+ .opps_desc = dvfsrc_opp_mt8183_desc,
+ .regs = dvfsrc_mt8183_regs,
+ .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_constraints = &dvfsrc_bw_constr_mt8183,
+};
+
+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_bw_constraints dvfsrc_bw_constr_mt8195 = {
+ .max_dram_nom_bw = 255,
+ .max_dram_peak_bw = 255,
+ .max_dram_hrt_bw = 1023,
+};
+
+static const struct dvfsrc_soc_data mt8195_data = {
+ .opps_desc = dvfsrc_opp_mt8195_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_constraints = &dvfsrc_bw_constr_mt8195,
+};
+
+static const struct of_device_id mtk_dvfsrc_of_match[] = {
+ { .compatible = "mediatek,mt8183-dvfsrc", .data = &mt8183_data },
+ { .compatible = "mediatek,mt8195-dvfsrc", .data = &mt8195_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");
diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c
index f370f4ec4b88..bb4639ca0b8c 100644
--- a/drivers/soc/mediatek/mtk-mmsys.c
+++ b/drivers/soc/mediatek/mtk-mmsys.c
@@ -236,6 +236,7 @@ void mtk_mmsys_mixer_in_config(struct device *dev, int idx, bool alpha_sel, u16
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,
@@ -486,7 +487,7 @@ static struct platform_driver mtk_mmsys_drv = {
.of_match_table = of_match_mtk_mmsys,
},
.probe = mtk_mmsys_probe,
- .remove_new = mtk_mmsys_remove,
+ .remove = mtk_mmsys_remove,
};
module_platform_driver(mtk_mmsys_drv);
diff --git a/drivers/soc/mediatek/mtk-mutex.c b/drivers/soc/mediatek/mtk-mutex.c
index 73c256d3950b..5250c1d702eb 100644
--- a/drivers/soc/mediatek/mtk-mutex.c
+++ b/drivers/soc/mediatek/mtk-mutex.c
@@ -327,11 +327,11 @@ enum mtk_mutex_sof_id {
};
struct mtk_mutex_data {
- const unsigned int *mutex_mod;
- const unsigned int *mutex_sof;
- const unsigned int mutex_mod_reg;
- const unsigned int mutex_sof_reg;
- const unsigned int *mutex_table_mod;
+ const u8 *mutex_mod;
+ const u8 *mutex_table_mod;
+ const u16 *mutex_sof;
+ const u16 mutex_mod_reg;
+ const u16 mutex_sof_reg;
const bool no_clk;
};
@@ -345,7 +345,7 @@ struct mtk_mutex_ctx {
struct cmdq_client_reg cmdq_reg;
};
-static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+static const u8 mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_BLS] = MT2701_MUTEX_MOD_DISP_BLS,
[DDP_COMPONENT_COLOR0] = MT2701_MUTEX_MOD_DISP_COLOR,
[DDP_COMPONENT_OVL0] = MT2701_MUTEX_MOD_DISP_OVL,
@@ -354,7 +354,7 @@ static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_WDMA0] = MT2701_MUTEX_MOD_DISP_WDMA,
};
-static const unsigned int mt2712_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+static const u8 mt2712_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_AAL0] = MT2712_MUTEX_MOD_DISP_AAL0,
[DDP_COMPONENT_AAL1] = MT2712_MUTEX_MOD2_DISP_AAL1,
[DDP_COMPONENT_COLOR0] = MT2712_MUTEX_MOD_DISP_COLOR0,
@@ -374,7 +374,7 @@ static const unsigned int mt2712_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_WDMA1] = MT2712_MUTEX_MOD_DISP_WDMA1,
};
-static const unsigned int mt8167_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+static const u8 mt8167_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_AAL0] = MT8167_MUTEX_MOD_DISP_AAL,
[DDP_COMPONENT_CCORR] = MT8167_MUTEX_MOD_DISP_CCORR,
[DDP_COMPONENT_COLOR0] = MT8167_MUTEX_MOD_DISP_COLOR,
@@ -389,7 +389,7 @@ static const unsigned int mt8167_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_WDMA0] = MT8167_MUTEX_MOD_DISP_WDMA0,
};
-static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+static const u8 mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_AAL0] = MT8173_MUTEX_MOD_DISP_AAL,
[DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0,
[DDP_COMPONENT_COLOR1] = MT8173_MUTEX_MOD_DISP_COLOR1,
@@ -407,7 +407,7 @@ static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_WDMA1] = MT8173_MUTEX_MOD_DISP_WDMA1,
};
-static const unsigned int mt8183_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+static const u8 mt8183_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_AAL0] = MT8183_MUTEX_MOD_DISP_AAL0,
[DDP_COMPONENT_CCORR] = MT8183_MUTEX_MOD_DISP_CCORR0,
[DDP_COMPONENT_COLOR0] = MT8183_MUTEX_MOD_DISP_COLOR0,
@@ -421,7 +421,7 @@ static const unsigned int mt8183_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_WDMA0] = MT8183_MUTEX_MOD_DISP_WDMA0,
};
-static const unsigned int mt8183_mutex_table_mod[MUTEX_MOD_IDX_MAX] = {
+static const u8 mt8183_mutex_table_mod[MUTEX_MOD_IDX_MAX] = {
[MUTEX_MOD_IDX_MDP_RDMA0] = MT8183_MUTEX_MOD_MDP_RDMA0,
[MUTEX_MOD_IDX_MDP_RSZ0] = MT8183_MUTEX_MOD_MDP_RSZ0,
[MUTEX_MOD_IDX_MDP_RSZ1] = MT8183_MUTEX_MOD_MDP_RSZ1,
@@ -432,7 +432,7 @@ static const unsigned int mt8183_mutex_table_mod[MUTEX_MOD_IDX_MAX] = {
[MUTEX_MOD_IDX_MDP_CCORR0] = MT8183_MUTEX_MOD_MDP_CCORR0,
};
-static const unsigned int mt8186_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+static const u8 mt8186_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_AAL0] = MT8186_MUTEX_MOD_DISP_AAL0,
[DDP_COMPONENT_CCORR] = MT8186_MUTEX_MOD_DISP_CCORR0,
[DDP_COMPONENT_COLOR0] = MT8186_MUTEX_MOD_DISP_COLOR0,
@@ -445,7 +445,7 @@ static const unsigned int mt8186_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_RDMA1] = MT8186_MUTEX_MOD_DISP_RDMA1,
};
-static const unsigned int mt8186_mdp_mutex_table_mod[MUTEX_MOD_IDX_MAX] = {
+static const u8 mt8186_mdp_mutex_table_mod[MUTEX_MOD_IDX_MAX] = {
[MUTEX_MOD_IDX_MDP_RDMA0] = MT8186_MUTEX_MOD_MDP_RDMA0,
[MUTEX_MOD_IDX_MDP_RSZ0] = MT8186_MUTEX_MOD_MDP_RSZ0,
[MUTEX_MOD_IDX_MDP_RSZ1] = MT8186_MUTEX_MOD_MDP_RSZ1,
@@ -456,7 +456,7 @@ static const unsigned int mt8186_mdp_mutex_table_mod[MUTEX_MOD_IDX_MAX] = {
[MUTEX_MOD_IDX_MDP_COLOR0] = MT8186_MUTEX_MOD_MDP_COLOR0,
};
-static const unsigned int mt8188_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+static const u8 mt8188_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_OVL0] = MT8188_MUTEX_MOD_DISP_OVL0,
[DDP_COMPONENT_WDMA0] = MT8188_MUTEX_MOD_DISP_WDMA0,
[DDP_COMPONENT_RDMA0] = MT8188_MUTEX_MOD_DISP_RDMA0,
@@ -496,7 +496,41 @@ static const unsigned int mt8188_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_MERGE5] = MT8188_MUTEX_MOD_DISP1_VPP_MERGE4,
};
-static const unsigned int mt8192_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+static const u8 mt8188_mdp_mutex_table_mod[MUTEX_MOD_IDX_MAX] = {
+ [MUTEX_MOD_IDX_MDP_RDMA0] = MT8195_MUTEX_MOD_MDP_RDMA0,
+ [MUTEX_MOD_IDX_MDP_RDMA2] = MT8195_MUTEX_MOD_MDP_RDMA2,
+ [MUTEX_MOD_IDX_MDP_RDMA3] = MT8195_MUTEX_MOD_MDP_RDMA3,
+ [MUTEX_MOD_IDX_MDP_FG0] = MT8195_MUTEX_MOD_MDP_FG0,
+ [MUTEX_MOD_IDX_MDP_FG2] = MT8195_MUTEX_MOD_MDP_FG2,
+ [MUTEX_MOD_IDX_MDP_FG3] = MT8195_MUTEX_MOD_MDP_FG3,
+ [MUTEX_MOD_IDX_MDP_HDR0] = MT8195_MUTEX_MOD_MDP_HDR0,
+ [MUTEX_MOD_IDX_MDP_HDR2] = MT8195_MUTEX_MOD_MDP_HDR2,
+ [MUTEX_MOD_IDX_MDP_HDR3] = MT8195_MUTEX_MOD_MDP_HDR3,
+ [MUTEX_MOD_IDX_MDP_AAL0] = MT8195_MUTEX_MOD_MDP_AAL0,
+ [MUTEX_MOD_IDX_MDP_AAL2] = MT8195_MUTEX_MOD_MDP_AAL2,
+ [MUTEX_MOD_IDX_MDP_AAL3] = MT8195_MUTEX_MOD_MDP_AAL3,
+ [MUTEX_MOD_IDX_MDP_RSZ0] = MT8195_MUTEX_MOD_MDP_RSZ0,
+ [MUTEX_MOD_IDX_MDP_RSZ2] = MT8195_MUTEX_MOD_MDP_RSZ2,
+ [MUTEX_MOD_IDX_MDP_RSZ3] = MT8195_MUTEX_MOD_MDP_RSZ3,
+ [MUTEX_MOD_IDX_MDP_MERGE2] = MT8195_MUTEX_MOD_MDP_MERGE2,
+ [MUTEX_MOD_IDX_MDP_MERGE3] = MT8195_MUTEX_MOD_MDP_MERGE3,
+ [MUTEX_MOD_IDX_MDP_TDSHP0] = MT8195_MUTEX_MOD_MDP_TDSHP0,
+ [MUTEX_MOD_IDX_MDP_TDSHP2] = MT8195_MUTEX_MOD_MDP_TDSHP2,
+ [MUTEX_MOD_IDX_MDP_TDSHP3] = MT8195_MUTEX_MOD_MDP_TDSHP3,
+ [MUTEX_MOD_IDX_MDP_COLOR0] = MT8195_MUTEX_MOD_MDP_COLOR0,
+ [MUTEX_MOD_IDX_MDP_COLOR2] = MT8195_MUTEX_MOD_MDP_COLOR2,
+ [MUTEX_MOD_IDX_MDP_COLOR3] = MT8195_MUTEX_MOD_MDP_COLOR3,
+ [MUTEX_MOD_IDX_MDP_OVL0] = MT8195_MUTEX_MOD_MDP_OVL0,
+ [MUTEX_MOD_IDX_MDP_PAD0] = MT8195_MUTEX_MOD_MDP_PAD0,
+ [MUTEX_MOD_IDX_MDP_PAD2] = MT8195_MUTEX_MOD_MDP_PAD2,
+ [MUTEX_MOD_IDX_MDP_PAD3] = MT8195_MUTEX_MOD_MDP_PAD3,
+ [MUTEX_MOD_IDX_MDP_TCC0] = MT8195_MUTEX_MOD_MDP_TCC0,
+ [MUTEX_MOD_IDX_MDP_WROT0] = MT8195_MUTEX_MOD_MDP_WROT0,
+ [MUTEX_MOD_IDX_MDP_WROT2] = MT8195_MUTEX_MOD_MDP_WROT2,
+ [MUTEX_MOD_IDX_MDP_WROT3] = MT8195_MUTEX_MOD_MDP_WROT3,
+};
+
+static const u8 mt8192_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_AAL0] = MT8192_MUTEX_MOD_DISP_AAL0,
[DDP_COMPONENT_CCORR] = MT8192_MUTEX_MOD_DISP_CCORR0,
[DDP_COMPONENT_COLOR0] = MT8192_MUTEX_MOD_DISP_COLOR0,
@@ -510,7 +544,7 @@ static const unsigned int mt8192_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_RDMA4] = MT8192_MUTEX_MOD_DISP_RDMA4,
};
-static const unsigned int mt8195_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+static const u8 mt8195_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_OVL0] = MT8195_MUTEX_MOD_DISP_OVL0,
[DDP_COMPONENT_WDMA0] = MT8195_MUTEX_MOD_DISP_WDMA0,
[DDP_COMPONENT_RDMA0] = MT8195_MUTEX_MOD_DISP_RDMA0,
@@ -541,7 +575,7 @@ static const unsigned int mt8195_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_DP_INTF1] = MT8195_MUTEX_MOD_DISP1_DP_INTF0,
};
-static const unsigned int mt8195_mutex_table_mod[MUTEX_MOD_IDX_MAX] = {
+static const u8 mt8195_mutex_table_mod[MUTEX_MOD_IDX_MAX] = {
[MUTEX_MOD_IDX_MDP_RDMA0] = MT8195_MUTEX_MOD_MDP_RDMA0,
[MUTEX_MOD_IDX_MDP_RDMA1] = MT8195_MUTEX_MOD_MDP_RDMA1,
[MUTEX_MOD_IDX_MDP_RDMA2] = MT8195_MUTEX_MOD_MDP_RDMA2,
@@ -587,7 +621,7 @@ static const unsigned int mt8195_mutex_table_mod[MUTEX_MOD_IDX_MAX] = {
[MUTEX_MOD_IDX_MDP_WROT3] = MT8195_MUTEX_MOD_MDP_WROT3,
};
-static const unsigned int mt8365_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+static const u8 mt8365_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_AAL0] = MT8365_MUTEX_MOD_DISP_AAL,
[DDP_COMPONENT_CCORR] = MT8365_MUTEX_MOD_DISP_CCORR,
[DDP_COMPONENT_COLOR0] = MT8365_MUTEX_MOD_DISP_COLOR0,
@@ -603,7 +637,7 @@ static const unsigned int mt8365_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_WDMA0] = MT8365_MUTEX_MOD_DISP_WDMA0,
};
-static const unsigned int mt2712_mutex_sof[DDP_MUTEX_SOF_MAX] = {
+static const u16 mt2712_mutex_sof[DDP_MUTEX_SOF_MAX] = {
[MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
[MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0,
[MUTEX_SOF_DSI1] = MUTEX_SOF_DSI1,
@@ -613,14 +647,14 @@ static const unsigned int mt2712_mutex_sof[DDP_MUTEX_SOF_MAX] = {
[MUTEX_SOF_DSI3] = MUTEX_SOF_DSI3,
};
-static const unsigned int mt6795_mutex_sof[DDP_MUTEX_SOF_MAX] = {
+static const u16 mt6795_mutex_sof[DDP_MUTEX_SOF_MAX] = {
[MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
[MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0,
[MUTEX_SOF_DSI1] = MUTEX_SOF_DSI1,
[MUTEX_SOF_DPI0] = MUTEX_SOF_DPI0,
};
-static const unsigned int mt8167_mutex_sof[DDP_MUTEX_SOF_MAX] = {
+static const u16 mt8167_mutex_sof[DDP_MUTEX_SOF_MAX] = {
[MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
[MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0,
[MUTEX_SOF_DPI0] = MT8167_MUTEX_SOF_DPI0,
@@ -628,13 +662,13 @@ static const unsigned int mt8167_mutex_sof[DDP_MUTEX_SOF_MAX] = {
};
/* Add EOF setting so overlay hardware can receive frame done irq */
-static const unsigned int mt8183_mutex_sof[DDP_MUTEX_SOF_MAX] = {
+static const u16 mt8183_mutex_sof[DDP_MUTEX_SOF_MAX] = {
[MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
[MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0 | MT8183_MUTEX_EOF_DSI0,
[MUTEX_SOF_DPI0] = MT8183_MUTEX_SOF_DPI0 | MT8183_MUTEX_EOF_DPI0,
};
-static const unsigned int mt8186_mutex_sof[MUTEX_SOF_DSI3 + 1] = {
+static const u16 mt8186_mutex_sof[MUTEX_SOF_DSI3 + 1] = {
[MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
[MUTEX_SOF_DSI0] = MT8186_MUTEX_SOF_DSI0 | MT8186_MUTEX_EOF_DSI0,
[MUTEX_SOF_DPI0] = MT8186_MUTEX_SOF_DPI0 | MT8186_MUTEX_EOF_DPI0,
@@ -648,7 +682,7 @@ static const unsigned int mt8186_mutex_sof[MUTEX_SOF_DSI3 + 1] = {
* but also detect the error at end of frame(EAEOF) when EOF signal
* arrives.
*/
-static const unsigned int mt8188_mutex_sof[DDP_MUTEX_SOF_MAX] = {
+static const u16 mt8188_mutex_sof[DDP_MUTEX_SOF_MAX] = {
[MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
[MUTEX_SOF_DSI0] =
MT8188_MUTEX_SOF_DSI0 | MT8188_MUTEX_EOF_DSI0,
@@ -658,7 +692,7 @@ static const unsigned int mt8188_mutex_sof[DDP_MUTEX_SOF_MAX] = {
MT8188_MUTEX_SOF_DP_INTF1 | MT8188_MUTEX_EOF_DP_INTF1,
};
-static const unsigned int mt8195_mutex_sof[DDP_MUTEX_SOF_MAX] = {
+static const u16 mt8195_mutex_sof[DDP_MUTEX_SOF_MAX] = {
[MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
[MUTEX_SOF_DSI0] = MT8195_MUTEX_SOF_DSI0 | MT8195_MUTEX_EOF_DSI0,
[MUTEX_SOF_DSI1] = MT8195_MUTEX_SOF_DSI1 | MT8195_MUTEX_EOF_DSI1,
@@ -735,6 +769,13 @@ static const struct mtk_mutex_data mt8188_mutex_driver_data = {
.mutex_sof_reg = MT8183_MUTEX0_SOF0,
};
+static const struct mtk_mutex_data mt8188_vpp_mutex_driver_data = {
+ .mutex_sof = mt8188_mutex_sof,
+ .mutex_mod_reg = MT8183_MUTEX0_MOD0,
+ .mutex_sof_reg = MT8183_MUTEX0_SOF0,
+ .mutex_table_mod = mt8188_mdp_mutex_table_mod,
+};
+
static const struct mtk_mutex_data mt8192_mutex_driver_data = {
.mutex_mod = mt8192_mutex_mod,
.mutex_sof = mt8183_mutex_sof,
@@ -1089,6 +1130,7 @@ static const struct of_device_id mutex_driver_dt_match[] = {
{ .compatible = "mediatek,mt8186-disp-mutex", .data = &mt8186_mutex_driver_data },
{ .compatible = "mediatek,mt8186-mdp3-mutex", .data = &mt8186_mdp_mutex_driver_data },
{ .compatible = "mediatek,mt8188-disp-mutex", .data = &mt8188_mutex_driver_data },
+ { .compatible = "mediatek,mt8188-vpp-mutex", .data = &mt8188_vpp_mutex_driver_data },
{ .compatible = "mediatek,mt8192-disp-mutex", .data = &mt8192_mutex_driver_data },
{ .compatible = "mediatek,mt8195-disp-mutex", .data = &mt8195_mutex_driver_data },
{ .compatible = "mediatek,mt8195-vpp-mutex", .data = &mt8195_vpp_mutex_driver_data },
diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
index efd9cae212dc..0bcd85826375 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -483,7 +483,7 @@ enum pwrap_regs {
PWRAP_MSB_FIRST,
};
-static int mt2701_regs[] = {
+static const int mt2701_regs[] = {
[PWRAP_MUX_SEL] = 0x0,
[PWRAP_WRAP_EN] = 0x4,
[PWRAP_DIO_EN] = 0x8,
@@ -569,7 +569,7 @@ static int mt2701_regs[] = {
[PWRAP_ADC_RDATA_ADDR2] = 0x154,
};
-static int mt6765_regs[] = {
+static const int mt6765_regs[] = {
[PWRAP_MUX_SEL] = 0x0,
[PWRAP_WRAP_EN] = 0x4,
[PWRAP_DIO_EN] = 0x8,
@@ -601,7 +601,7 @@ static int mt6765_regs[] = {
[PWRAP_DCM_DBC_PRD] = 0x1E0,
};
-static int mt6779_regs[] = {
+static const int mt6779_regs[] = {
[PWRAP_MUX_SEL] = 0x0,
[PWRAP_WRAP_EN] = 0x4,
[PWRAP_DIO_EN] = 0x8,
@@ -640,7 +640,7 @@ static int mt6779_regs[] = {
[PWRAP_WACS2_VLDCLR] = 0xC28,
};
-static int mt6795_regs[] = {
+static const int mt6795_regs[] = {
[PWRAP_MUX_SEL] = 0x0,
[PWRAP_WRAP_EN] = 0x4,
[PWRAP_DIO_EN] = 0x8,
@@ -725,7 +725,7 @@ static int mt6795_regs[] = {
[PWRAP_EXT_CK] = 0x14c,
};
-static int mt6797_regs[] = {
+static const int mt6797_regs[] = {
[PWRAP_MUX_SEL] = 0x0,
[PWRAP_WRAP_EN] = 0x4,
[PWRAP_DIO_EN] = 0x8,
@@ -758,7 +758,7 @@ static int mt6797_regs[] = {
[PWRAP_DCM_DBC_PRD] = 0x1D4,
};
-static int mt6873_regs[] = {
+static const int mt6873_regs[] = {
[PWRAP_INIT_DONE2] = 0x0,
[PWRAP_TIMER_EN] = 0x3E0,
[PWRAP_INT_EN] = 0x448,
@@ -769,7 +769,7 @@ static int mt6873_regs[] = {
[PWRAP_WACS2_RDATA] = 0xCA8,
};
-static int mt7622_regs[] = {
+static const int mt7622_regs[] = {
[PWRAP_MUX_SEL] = 0x0,
[PWRAP_WRAP_EN] = 0x4,
[PWRAP_DIO_EN] = 0x8,
@@ -881,7 +881,7 @@ static int mt7622_regs[] = {
[PWRAP_SPI2_CTRL] = 0x244,
};
-static int mt8135_regs[] = {
+static const int mt8135_regs[] = {
[PWRAP_MUX_SEL] = 0x0,
[PWRAP_WRAP_EN] = 0x4,
[PWRAP_DIO_EN] = 0x8,
@@ -954,7 +954,7 @@ static int mt8135_regs[] = {
[PWRAP_DCM_DBC_PRD] = 0x160,
};
-static int mt8173_regs[] = {
+static const int mt8173_regs[] = {
[PWRAP_MUX_SEL] = 0x0,
[PWRAP_WRAP_EN] = 0x4,
[PWRAP_DIO_EN] = 0x8,
@@ -1036,7 +1036,7 @@ static int mt8173_regs[] = {
[PWRAP_DCM_DBC_PRD] = 0x148,
};
-static int mt8183_regs[] = {
+static const int mt8183_regs[] = {
[PWRAP_MUX_SEL] = 0x0,
[PWRAP_WRAP_EN] = 0x4,
[PWRAP_DIO_EN] = 0x8,
@@ -1087,7 +1087,7 @@ static int mt8183_regs[] = {
[PWRAP_WACS2_VLDCLR] = 0xC28,
};
-static int mt8195_regs[] = {
+static const int mt8195_regs[] = {
[PWRAP_INIT_DONE2] = 0x0,
[PWRAP_STAUPD_CTRL] = 0x4C,
[PWRAP_TIMER_EN] = 0x3E4,
@@ -1104,7 +1104,7 @@ static int mt8195_regs[] = {
[PWRAP_WACS2_RDATA] = 0x8A8,
};
-static int mt8365_regs[] = {
+static const int mt8365_regs[] = {
[PWRAP_MUX_SEL] = 0x0,
[PWRAP_WRAP_EN] = 0x4,
[PWRAP_DIO_EN] = 0x8,
@@ -1166,7 +1166,7 @@ static int mt8365_regs[] = {
[PWRAP_WDT_SRC_EN_1] = 0xf8,
};
-static int mt8516_regs[] = {
+static const int mt8516_regs[] = {
[PWRAP_MUX_SEL] = 0x0,
[PWRAP_WRAP_EN] = 0x4,
[PWRAP_DIO_EN] = 0x8,
@@ -1251,7 +1251,7 @@ static int mt8516_regs[] = {
[PWRAP_MSB_FIRST] = 0x170,
};
-static int mt8186_regs[] = {
+static const int mt8186_regs[] = {
[PWRAP_MUX_SEL] = 0x0,
[PWRAP_WRAP_EN] = 0x4,
[PWRAP_DIO_EN] = 0x8,
@@ -1366,10 +1366,6 @@ struct pmic_wrapper {
struct regmap *regmap;
const struct pmic_wrapper_type *master;
const struct pwrap_slv_type *slave;
- struct clk *clk_spi;
- struct clk *clk_wrap;
- struct clk *clk_sys;
- struct clk *clk_tmr;
struct reset_control *rstc;
struct reset_control *rstc_bridge;
@@ -1377,7 +1373,7 @@ struct pmic_wrapper {
};
struct pmic_wrapper_type {
- int *regs;
+ const int *regs;
enum pwrap_type type;
u32 arb_en_all;
u32 int_en_all;
@@ -2397,7 +2393,7 @@ static const struct pmic_wrapper_type pwrap_mt8183 = {
.init_soc_specific = pwrap_mt8183_init_soc_specific,
};
-static struct pmic_wrapper_type pwrap_mt8195 = {
+static const struct pmic_wrapper_type pwrap_mt8195 = {
.regs = mt8195_regs,
.type = PWRAP_MT8195,
.arb_en_all = 0x777f, /* NEED CONFIRM */
@@ -2423,7 +2419,7 @@ static const struct pmic_wrapper_type pwrap_mt8365 = {
.init_soc_specific = NULL,
};
-static struct pmic_wrapper_type pwrap_mt8516 = {
+static const struct pmic_wrapper_type pwrap_mt8516 = {
.regs = mt8516_regs,
.type = PWRAP_MT8516,
.arb_en_all = 0xff,
@@ -2435,7 +2431,7 @@ static struct pmic_wrapper_type pwrap_mt8516 = {
.init_soc_specific = NULL,
};
-static struct pmic_wrapper_type pwrap_mt8186 = {
+static const struct pmic_wrapper_type pwrap_mt8186 = {
.regs = mt8186_regs,
.type = PWRAP_MT8186,
.arb_en_all = 0xfb27f,
@@ -2472,6 +2468,7 @@ static int pwrap_probe(struct platform_device *pdev)
int ret, irq;
u32 mask_done;
struct pmic_wrapper *wrp;
+ struct clk_bulk_data *clk;
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *of_slave_id = NULL;
@@ -2521,49 +2518,10 @@ static int pwrap_probe(struct platform_device *pdev)
}
}
- wrp->clk_spi = devm_clk_get(wrp->dev, "spi");
- if (IS_ERR(wrp->clk_spi)) {
- dev_dbg(wrp->dev, "failed to get clock: %ld\n",
- PTR_ERR(wrp->clk_spi));
- return PTR_ERR(wrp->clk_spi);
- }
-
- wrp->clk_wrap = devm_clk_get(wrp->dev, "wrap");
- if (IS_ERR(wrp->clk_wrap)) {
- dev_dbg(wrp->dev, "failed to get clock: %ld\n",
- PTR_ERR(wrp->clk_wrap));
- return PTR_ERR(wrp->clk_wrap);
- }
-
- wrp->clk_sys = devm_clk_get_optional(wrp->dev, "sys");
- if (IS_ERR(wrp->clk_sys)) {
- return dev_err_probe(wrp->dev, PTR_ERR(wrp->clk_sys),
- "failed to get clock: %pe\n",
- wrp->clk_sys);
- }
-
- wrp->clk_tmr = devm_clk_get_optional(wrp->dev, "tmr");
- if (IS_ERR(wrp->clk_tmr)) {
- return dev_err_probe(wrp->dev, PTR_ERR(wrp->clk_tmr),
- "failed to get clock: %pe\n",
- wrp->clk_tmr);
- }
-
- ret = clk_prepare_enable(wrp->clk_spi);
- if (ret)
- return ret;
-
- ret = clk_prepare_enable(wrp->clk_wrap);
- if (ret)
- goto err_out1;
-
- ret = clk_prepare_enable(wrp->clk_sys);
- if (ret)
- goto err_out2;
-
- ret = clk_prepare_enable(wrp->clk_tmr);
- if (ret)
- goto err_out3;
+ ret = devm_clk_bulk_get_all_enabled(wrp->dev, &clk);
+ if (ret < 0)
+ return dev_err_probe(wrp->dev, ret,
+ "failed to get clocks\n");
/* Enable internal dynamic clock */
if (HAS_CAP(wrp->master->caps, PWRAP_CAP_DCM)) {
@@ -2579,7 +2537,7 @@ static int pwrap_probe(struct platform_device *pdev)
ret = pwrap_init(wrp);
if (ret) {
dev_dbg(wrp->dev, "init failed with %d\n", ret);
- goto err_out4;
+ return ret;
}
}
@@ -2592,8 +2550,7 @@ static int pwrap_probe(struct platform_device *pdev)
if (!(pwrap_readl(wrp, PWRAP_WACS2_RDATA) & mask_done)) {
dev_dbg(wrp->dev, "initialization isn't finished\n");
- ret = -ENODEV;
- goto err_out4;
+ return -ENODEV;
}
/* Initialize watchdog, may not be done by the bootloader */
@@ -2622,42 +2579,27 @@ static int pwrap_probe(struct platform_device *pdev)
pwrap_writel(wrp, wrp->master->int1_en_all, PWRAP_INT1_EN);
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- ret = irq;
- goto err_out2;
- }
+ if (irq < 0)
+ return irq;
ret = devm_request_irq(wrp->dev, irq, pwrap_interrupt,
IRQF_TRIGGER_HIGH,
"mt-pmic-pwrap", wrp);
if (ret)
- goto err_out4;
+ return ret;
wrp->regmap = devm_regmap_init(wrp->dev, NULL, wrp, wrp->slave->regops->regmap);
- if (IS_ERR(wrp->regmap)) {
- ret = PTR_ERR(wrp->regmap);
- goto err_out2;
- }
+ if (IS_ERR(wrp->regmap))
+ return PTR_ERR(wrp->regmap);
ret = of_platform_populate(np, NULL, NULL, wrp->dev);
if (ret) {
dev_dbg(wrp->dev, "failed to create child devices at %pOF\n",
np);
- goto err_out4;
+ return ret;
}
return 0;
-
-err_out4:
- clk_disable_unprepare(wrp->clk_tmr);
-err_out3:
- clk_disable_unprepare(wrp->clk_sys);
-err_out2:
- clk_disable_unprepare(wrp->clk_wrap);
-err_out1:
- clk_disable_unprepare(wrp->clk_spi);
-
- return ret;
}
static struct platform_driver pwrap_drv = {
diff --git a/drivers/soc/mediatek/mtk-regulator-coupler.c b/drivers/soc/mediatek/mtk-regulator-coupler.c
index ad2ed42aa697..0b6a2884145e 100644
--- a/drivers/soc/mediatek/mtk-regulator-coupler.c
+++ b/drivers/soc/mediatek/mtk-regulator-coupler.c
@@ -147,6 +147,7 @@ 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;
diff --git a/drivers/soc/mediatek/mtk-socinfo.c b/drivers/soc/mediatek/mtk-socinfo.c
new file mode 100644
index 000000000000..123b12cd2543
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-socinfo.c
@@ -0,0 +1,199 @@
+// 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("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("MT8395", "MT8395AV/ZA", "Genio 1200", 0x83950100, CELL_NOT_USED),
+};
+
+static int mtk_socinfo_create_socinfo_node(struct mtk_socinfo *mtk_socinfop)
+{
+ struct soc_device_attribute *attrs;
+ static char machine[30] = {0};
+ static const char *soc_manufacturer = "MediaTek";
+
+ attrs = devm_kzalloc(mtk_socinfop->dev, sizeof(*attrs), GFP_KERNEL);
+ if (!attrs)
+ return -ENOMEM;
+
+ snprintf(machine, sizeof(machine), "%s (%s)", mtk_socinfop->socinfo_data->marketing_name,
+ mtk_socinfop->socinfo_data->soc_name);
+ attrs->family = soc_manufacturer;
+ attrs->machine = machine;
+
+ 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", soc_manufacturer, attrs->machine);
+ 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");
diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c
index c832f5c670bc..7c349a94b45c 100644
--- a/drivers/soc/mediatek/mtk-svs.c
+++ b/drivers/soc/mediatek/mtk-svs.c
@@ -1768,6 +1768,7 @@ static int svs_bank_resource_setup(struct svs_platform *svsp)
const struct svs_bank_pdata *bdata;
struct svs_bank *svsb;
struct dev_pm_opp *opp;
+ char tz_name_buf[20];
unsigned long freq;
int count, ret;
u32 idx, i;
@@ -1819,10 +1820,12 @@ static int svs_bank_resource_setup(struct svs_platform *svsp)
}
if (!IS_ERR_OR_NULL(bdata->tzone_name)) {
- svsb->tzd = thermal_zone_get_zone_by_name(bdata->tzone_name);
+ snprintf(tz_name_buf, ARRAY_SIZE(tz_name_buf),
+ "%s-thermal", bdata->tzone_name);
+ svsb->tzd = thermal_zone_get_zone_by_name(tz_name_buf);
if (IS_ERR(svsb->tzd)) {
dev_err(svsb->dev, "cannot get \"%s\" thermal zone\n",
- bdata->tzone_name);
+ tz_name_buf);
return PTR_ERR(svsb->tzd);
}
}
@@ -2130,14 +2133,12 @@ static struct device *svs_get_subsys_device(struct svs_platform *svsp,
}
pdev = of_find_device_by_node(np);
+ of_node_put(np);
if (!pdev) {
- of_node_put(np);
dev_err(svsp->dev, "cannot find pdev by %s\n", node_name);
return ERR_PTR(-ENXIO);
}
- of_node_put(np);
-
return &pdev->dev;
}
diff --git a/drivers/soc/microchip/mpfs-sys-controller.c b/drivers/soc/microchip/mpfs-sys-controller.c
index 7a4936019329..30bc45d17d34 100644
--- a/drivers/soc/microchip/mpfs-sys-controller.c
+++ b/drivers/soc/microchip/mpfs-sys-controller.c
@@ -232,7 +232,7 @@ static struct platform_driver mpfs_sys_controller_driver = {
.of_match_table = mpfs_sys_controller_of_match,
},
.probe = mpfs_sys_controller_probe,
- .remove_new = mpfs_sys_controller_remove,
+ .remove = mpfs_sys_controller_remove,
};
module_platform_driver(mpfs_sys_controller_driver);
diff --git a/drivers/soc/pxa/ssp.c b/drivers/soc/pxa/ssp.c
index 7af04e8b8163..bb0062c165fe 100644
--- a/drivers/soc/pxa/ssp.c
+++ b/drivers/soc/pxa/ssp.c
@@ -25,7 +25,7 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/platform_device.h>
-#include <linux/spi/pxa2xx_spi.h>
+#include <linux/pxa2xx_ssp.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -197,7 +197,7 @@ static const struct platform_device_id ssp_id_table[] = {
static struct platform_driver pxa_ssp_driver = {
.probe = pxa_ssp_probe,
- .remove_new = pxa_ssp_remove,
+ .remove = pxa_ssp_remove,
.driver = {
.name = "pxa2xx-ssp",
.of_match_table = of_match_ptr(pxa_ssp_of_ids),
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index c6ca4de42586..58e63cf0036b 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -72,11 +72,28 @@ config QCOM_OCMEM
requirements. This is typically used by the GPU, camera/video, and
audio components on some Snapdragon SoCs.
+config QCOM_PD_MAPPER
+ tristate "Qualcomm Protection Domain Mapper"
+ select QCOM_QMI_HELPERS
+ select QCOM_PDR_MSG
+ select AUXILIARY_BUS
+ depends on NET && QRTR && (ARCH_QCOM || COMPILE_TEST)
+ default QCOM_RPROC_COMMON
+ help
+ The Protection Domain Mapper maps registered services to the domains
+ and instances handled by the remote DSPs. This is a kernel-space
+ implementation of the service. It is a simpler alternative to the
+ userspace daemon.
+
config QCOM_PDR_HELPERS
tristate
select QCOM_QMI_HELPERS
+ select QCOM_PDR_MSG
depends on NET
+config QCOM_PDR_MSG
+ tristate
+
config QCOM_PMIC_PDCHARGER_ULOG
tristate "Qualcomm PMIC PDCharger ULOG driver"
depends on RPMSG
@@ -122,7 +139,7 @@ config QCOM_RAMP_CTRL
config QCOM_RMTFS_MEM
tristate "Qualcomm Remote Filesystem memory driver"
- depends on ARCH_QCOM
+ depends on ARCH_QCOM || COMPILE_TEST
select QCOM_SCM
help
The Qualcomm remote filesystem memory driver is used for allocating
@@ -194,6 +211,7 @@ config QCOM_SMP2P
config QCOM_SMSM
tristate "Qualcomm Shared Memory State Machine"
+ depends on MAILBOX
depends on QCOM_SMEM
select QCOM_SMEM_STATE
select IRQ_DOMAIN
@@ -268,4 +286,13 @@ config QCOM_INLINE_CRYPTO_ENGINE
tristate
select QCOM_SCM
+config QCOM_PBS
+ tristate "PBS trigger support for Qualcomm Technologies, Inc. PMICS"
+ depends on SPMI
+ help
+ This driver supports configuring software programmable boot sequencer (PBS)
+ trigger event through PBS RAM on Qualcomm Technologies, Inc. PMICs.
+ This module provides the APIs to the client drivers that wants to send the
+ PBS trigger event to the PBS RAM.
+
endmenu
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 05b3d54e8dc9..acbca2ab5cc2 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -1,12 +1,15 @@
# SPDX-License-Identifier: GPL-2.0
CFLAGS_rpmh-rsc.o := -I$(src)
+CFLAGS_qcom_aoss.o := -I$(src)
obj-$(CONFIG_QCOM_AOSS_QMP) += qcom_aoss.o
obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o
obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o
obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o
obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o
obj-$(CONFIG_QCOM_OCMEM) += ocmem.o
+obj-$(CONFIG_QCOM_PD_MAPPER) += qcom_pd_mapper.o
obj-$(CONFIG_QCOM_PDR_HELPERS) += pdr_interface.o
+obj-$(CONFIG_QCOM_PDR_MSG) += qcom_pdr_msg.o
obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink.o
obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink_altmode.o
obj-$(CONFIG_QCOM_PMIC_PDCHARGER_ULOG) += pmic_pdcharger_ulog.o
@@ -22,6 +25,7 @@ qcom_rpmh-y += rpmh.o
obj-$(CONFIG_QCOM_SMD_RPM) += rpm-proc.o smd-rpm.o
obj-$(CONFIG_QCOM_SMEM) += smem.o
obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
+CFLAGS_smp2p.o := -I$(src)
obj-$(CONFIG_QCOM_SMP2P) += smp2p.o
obj-$(CONFIG_QCOM_SMSM) += smsm.o
obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o
@@ -34,3 +38,4 @@ obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) += kryo-l2-accessors.o
obj-$(CONFIG_QCOM_ICC_BWMON) += icc-bwmon.o
qcom_ice-objs += ice.o
obj-$(CONFIG_QCOM_INLINE_CRYPTO_ENGINE) += qcom_ice.o
+obj-$(CONFIG_QCOM_PBS) += qcom-pbs.o
diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c
index 1f8b315576a4..a956c407ce03 100644
--- a/drivers/soc/qcom/apr.c
+++ b/drivers/soc/qcom/apr.c
@@ -338,10 +338,10 @@ static void apr_rxwq(struct work_struct *work)
}
}
-static int apr_device_match(struct device *dev, struct device_driver *drv)
+static int apr_device_match(struct device *dev, const struct device_driver *drv)
{
struct apr_device *adev = to_apr_device(dev);
- struct apr_driver *adrv = to_apr_driver(drv);
+ const struct apr_driver *adrv = to_apr_driver(drv);
const struct apr_device_id *id = adrv->id_table;
/* Attempt an OF style match first */
@@ -399,7 +399,7 @@ static int apr_uevent(const struct device *dev, struct kobj_uevent_env *env)
return add_uevent_var(env, "MODALIAS=apr:%s", adev->name);
}
-struct bus_type aprbus = {
+const struct bus_type aprbus = {
.name = "aprbus",
.match = apr_device_match,
.probe = apr_device_probe,
@@ -485,11 +485,10 @@ static int of_apr_add_pd_lookups(struct device *dev)
{
const char *service_name, *service_path;
struct packet_router *apr = dev_get_drvdata(dev);
- struct device_node *node;
struct pdr_service *pds;
int ret;
- for_each_child_of_node(dev->of_node, node) {
+ for_each_child_of_node_scoped(dev->of_node, node) {
ret = of_property_read_string_index(node, "qcom,protection-domain",
0, &service_name);
if (ret < 0)
@@ -499,14 +498,12 @@ static int of_apr_add_pd_lookups(struct device *dev)
1, &service_path);
if (ret < 0) {
dev_err(dev, "pdr service path missing: %d\n", ret);
- of_node_put(node);
return ret;
}
pds = pdr_add_lookup(apr->pdr, service_name, service_path);
if (IS_ERR(pds) && PTR_ERR(pds) != -EALREADY) {
dev_err(dev, "pdr add lookup failed: %ld\n", PTR_ERR(pds));
- of_node_put(node);
return PTR_ERR(pds);
}
}
diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c
index a5fd68411bed..ae66c2623d25 100644
--- a/drivers/soc/qcom/cmd-db.c
+++ b/drivers/soc/qcom/cmd-db.c
@@ -1,6 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright (c) 2016-2018, 2020, The Linux Foundation. All rights reserved. */
+/*
+ * Copyright (c) 2016-2018, 2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+#include <linux/bitfield.h>
#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -17,6 +21,8 @@
#define MAX_SLV_ID 8
#define SLAVE_ID_MASK 0x7
#define SLAVE_ID_SHIFT 16
+#define SLAVE_ID(addr) FIELD_GET(GENMASK(19, 16), addr)
+#define VRM_ADDR(addr) FIELD_GET(GENMASK(19, 4), addr)
/**
* struct entry_header: header for each entry in cmddb
@@ -147,12 +153,7 @@ static int cmd_db_get_header(const char *id, const struct entry_header **eh,
if (ret)
return ret;
- /*
- * Pad out query string to same length as in DB. NOTE: the output
- * query string is not necessarily '\0' terminated if it bumps up
- * against the max size. That's OK and expected.
- */
- strncpy(query, id, sizeof(query));
+ strtomem_pad(query, id, 0);
for (i = 0; i < MAX_SLV_ID; i++) {
rsc_hdr = &cmd_db_header->header[i];
@@ -221,6 +222,30 @@ const void *cmd_db_read_aux_data(const char *id, size_t *len)
EXPORT_SYMBOL_GPL(cmd_db_read_aux_data);
/**
+ * cmd_db_match_resource_addr() - Compare if both Resource addresses are same
+ *
+ * @addr1: Resource address to compare
+ * @addr2: Resource address to compare
+ *
+ * Return: true if two addresses refer to the same resource, false otherwise
+ */
+bool cmd_db_match_resource_addr(u32 addr1, u32 addr2)
+{
+ /*
+ * Each RPMh VRM accelerator resource has 3 or 4 contiguous 4-byte
+ * aligned addresses associated with it. Ignore the offset to check
+ * for VRM requests.
+ */
+ if (addr1 == addr2)
+ return true;
+ else if (SLAVE_ID(addr1) == CMD_DB_HW_VRM && VRM_ADDR(addr1) == VRM_ADDR(addr2))
+ return true;
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(cmd_db_match_resource_addr);
+
+/**
* cmd_db_read_slave_id - Get the slave ID for a given resource address
*
* @id: Resource id to query the DB for version
@@ -324,7 +349,7 @@ static int cmd_db_dev_probe(struct platform_device *pdev)
return -EINVAL;
}
- cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WB);
+ cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WC);
if (!cmd_db_header) {
ret = -ENOMEM;
cmd_db_header = NULL;
@@ -362,7 +387,7 @@ static int __init cmd_db_device_init(void)
{
return platform_driver_register(&cmd_db_dev_driver);
}
-arch_initcall(cmd_db_device_init);
+core_initcall(cmd_db_device_init);
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Command DB Driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/icc-bwmon.c b/drivers/soc/qcom/icc-bwmon.c
index 656706259353..3dfa448bf8cf 100644
--- a/drivers/soc/qcom/icc-bwmon.c
+++ b/drivers/soc/qcom/icc-bwmon.c
@@ -17,6 +17,8 @@
#include <linux/pm_opp.h>
#include <linux/regmap.h>
#include <linux/sizes.h>
+#define CREATE_TRACE_POINTS
+#include "trace_icc-bwmon.h"
/*
* The BWMON samples data throughput within 'sample_ms' time. With three
@@ -282,7 +284,7 @@ static const struct regmap_config msm8998_bwmon_regmap_cfg = {
* Cache is necessary for using regmap fields with non-readable
* registers.
*/
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static const struct regmap_config msm8998_bwmon_global_regmap_cfg = {
@@ -301,7 +303,7 @@ static const struct regmap_config msm8998_bwmon_global_regmap_cfg = {
* Cache is necessary for using regmap fields with non-readable
* registers.
*/
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static const struct reg_field sdm845_cpu_bwmon_reg_fields[] = {
@@ -369,7 +371,7 @@ static const struct regmap_config sdm845_cpu_bwmon_regmap_cfg = {
* Cache is necessary for using regmap fields with non-readable
* registers.
*/
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
/* BWMON v5 */
@@ -446,7 +448,7 @@ static const struct regmap_config sdm845_llcc_bwmon_regmap_cfg = {
* Cache is necessary for using regmap fields with non-readable
* registers.
*/
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static void bwmon_clear_counters(struct icc_bwmon *bwmon, bool clear_all)
@@ -565,7 +567,7 @@ static void bwmon_start(struct icc_bwmon *bwmon)
int window;
/* No need to check for errors, as this must have succeeded before. */
- dev_pm_opp_find_bw_ceil(bwmon->dev, &bw_low, 0);
+ dev_pm_opp_put(dev_pm_opp_find_bw_ceil(bwmon->dev, &bw_low, 0));
bwmon_clear_counters(bwmon, true);
@@ -645,9 +647,10 @@ static irqreturn_t bwmon_intr_thread(int irq, void *dev_id)
struct icc_bwmon *bwmon = dev_id;
unsigned int irq_enable = 0;
struct dev_pm_opp *opp, *target_opp;
- unsigned int bw_kbps, up_kbps, down_kbps;
+ unsigned int bw_kbps, up_kbps, down_kbps, meas_kbps;
bw_kbps = bwmon->target_kbps;
+ meas_kbps = bwmon->target_kbps;
target_opp = dev_pm_opp_find_bw_ceil(bwmon->dev, &bw_kbps, 0);
if (IS_ERR(target_opp) && PTR_ERR(target_opp) == -ERANGE)
@@ -679,6 +682,7 @@ static irqreturn_t bwmon_intr_thread(int irq, void *dev_id)
bwmon_clear_irq(bwmon);
bwmon_enable(bwmon, irq_enable);
+ trace_qcom_bwmon_update(dev_name(bwmon->dev), meas_kbps, up_kbps, down_kbps);
if (bwmon->target_kbps == bwmon->current_kbps)
goto out;
@@ -772,18 +776,25 @@ static int bwmon_probe(struct platform_device *pdev)
opp = dev_pm_opp_find_bw_floor(dev, &bwmon->max_bw_kbps, 0);
if (IS_ERR(opp))
return dev_err_probe(dev, PTR_ERR(opp), "failed to find max peak bandwidth\n");
+ dev_pm_opp_put(opp);
bwmon->min_bw_kbps = 0;
opp = dev_pm_opp_find_bw_ceil(dev, &bwmon->min_bw_kbps, 0);
if (IS_ERR(opp))
return dev_err_probe(dev, PTR_ERR(opp), "failed to find min peak bandwidth\n");
+ dev_pm_opp_put(opp);
bwmon->dev = dev;
bwmon_disable(bwmon);
- ret = devm_request_threaded_irq(dev, bwmon->irq, bwmon_intr,
- bwmon_intr_thread,
- IRQF_ONESHOT, dev_name(dev), bwmon);
+
+ /*
+ * SoCs with multiple cpu-bwmon instances can end up using a shared interrupt
+ * line. Using the devm_ variant might result in the IRQ handler being executed
+ * after bwmon_disable in bwmon_remove()
+ */
+ ret = request_threaded_irq(bwmon->irq, bwmon_intr, bwmon_intr_thread,
+ IRQF_ONESHOT | IRQF_SHARED, dev_name(dev), bwmon);
if (ret)
return dev_err_probe(dev, ret, "failed to request IRQ\n");
@@ -798,6 +809,7 @@ static void bwmon_remove(struct platform_device *pdev)
struct icc_bwmon *bwmon = platform_get_drvdata(pdev);
bwmon_disable(bwmon);
+ free_irq(bwmon->irq, bwmon);
}
static const struct icc_bwmon_data msm8998_bwmon_data = {
@@ -860,7 +872,7 @@ MODULE_DEVICE_TABLE(of, bwmon_of_match);
static struct platform_driver bwmon_driver = {
.probe = bwmon_probe,
- .remove_new = bwmon_remove,
+ .remove = bwmon_remove,
.driver = {
.name = "qcom-bwmon",
.of_match_table = bwmon_of_match,
diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c
index fbab7fe5c652..393d2d1d275f 100644
--- a/drivers/soc/qcom/ice.c
+++ b/drivers/soc/qcom/ice.c
@@ -8,6 +8,7 @@
*/
#include <linux/bitfield.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/iopoll.h>
@@ -43,7 +44,6 @@
struct qcom_ice {
struct device *dev;
void __iomem *base;
- struct device_link *link;
struct clk *core_clk;
};
@@ -265,9 +265,9 @@ struct qcom_ice *of_qcom_ice_get(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct qcom_ice *ice;
- struct device_node *node;
struct resource *res;
void __iomem *base;
+ struct device_link *link;
if (!dev || !dev->of_node)
return ERR_PTR(-ENODEV);
@@ -292,15 +292,15 @@ struct qcom_ice *of_qcom_ice_get(struct device *dev)
* (legacy DT binding), then it must at least provide a phandle
* to the ICE devicetree node, otherwise ICE is not supported.
*/
- node = of_parse_phandle(dev->of_node, "qcom,ice", 0);
+ struct device_node *node __free(device_node) = of_parse_phandle(dev->of_node,
+ "qcom,ice", 0);
if (!node)
return NULL;
pdev = of_find_device_by_node(node);
if (!pdev) {
dev_err(dev, "Cannot find device node %s\n", node->name);
- ice = ERR_PTR(-EPROBE_DEFER);
- goto out;
+ return ERR_PTR(-EPROBE_DEFER);
}
ice = platform_get_drvdata(pdev);
@@ -308,12 +308,11 @@ struct qcom_ice *of_qcom_ice_get(struct device *dev)
dev_err(dev, "Cannot get ice instance from %s\n",
dev_name(&pdev->dev));
platform_device_put(pdev);
- ice = ERR_PTR(-EPROBE_DEFER);
- goto out;
+ return ERR_PTR(-EPROBE_DEFER);
}
- ice->link = device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER);
- if (!ice->link) {
+ link = device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER);
+ if (!link) {
dev_err(&pdev->dev,
"Failed to create device link to consumer %s\n",
dev_name(dev));
@@ -321,9 +320,6 @@ struct qcom_ice *of_qcom_ice_get(struct device *dev)
ice = ERR_PTR(-EINVAL);
}
-out:
- of_node_put(node);
-
return ice;
}
EXPORT_SYMBOL_GPL(of_qcom_ice_get);
diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c
index 4ca88eaebf06..56823b6a2fac 100644
--- a/drivers/soc/qcom/llcc-qcom.c
+++ b/drivers/soc/qcom/llcc-qcom.c
@@ -7,6 +7,7 @@
#include <linux/bitfield.h>
#include <linux/bitmap.h>
#include <linux/bitops.h>
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/kernel.h>
@@ -26,14 +27,14 @@
#define ACT_CTRL_OPCODE_ACTIVATE BIT(0)
#define ACT_CTRL_OPCODE_DEACTIVATE BIT(1)
#define ACT_CTRL_ACT_TRIG BIT(0)
-#define ACT_CTRL_OPCODE_SHIFT 0x01
-#define ATTR1_PROBE_TARGET_WAYS_SHIFT 0x02
-#define ATTR1_FIXED_SIZE_SHIFT 0x03
-#define ATTR1_PRIORITY_SHIFT 0x04
-#define ATTR1_MAX_CAP_SHIFT 0x10
+#define ACT_CTRL_OPCODE_SHIFT 1
+#define ATTR1_PROBE_TARGET_WAYS_SHIFT 2
+#define ATTR1_FIXED_SIZE_SHIFT 3
+#define ATTR1_PRIORITY_SHIFT 4
+#define ATTR1_MAX_CAP_SHIFT 16
#define ATTR0_RES_WAYS_MASK GENMASK(15, 0)
#define ATTR0_BONUS_WAYS_MASK GENMASK(31, 16)
-#define ATTR0_BONUS_WAYS_SHIFT 0x10
+#define ATTR0_BONUS_WAYS_SHIFT 16
#define LLCC_STATUS_READ_DELAY 100
#define CACHE_LINE_SIZE_SHIFT 6
@@ -135,9 +136,13 @@ struct qcom_llcc_config {
const struct llcc_slice_config *sct_data;
const u32 *reg_offset;
const struct llcc_edac_reg_offset *edac_reg_offset;
+ u32 max_cap_shift; /* instead of ATTR1_MAX_CAP_SHIFT */
+ u32 num_banks;
int size;
- bool need_llcc_cfg;
+ bool skip_llcc_cfg;
bool no_edac;
+ bool irq_configured;
+ bool no_broadcast_register;
};
struct qcom_sct_config {
@@ -150,309 +155,2956 @@ enum llcc_reg_offset {
LLCC_COMMON_STATUS0,
};
+static const struct llcc_slice_config ipq5424_data[] = {
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 768,
+ .priority = 1,
+ .bonus_ways = 0xFFFF,
+ .retain_on_pc = true,
+ .activate_on_init = true,
+ .write_scid_cacheable_en = true,
+ .stale_en = true,
+ .stale_cap_en = true,
+ .alloc_oneway_en = true,
+ .ovcap_en = true,
+ .ovcap_prio = true,
+ .vict_prio = true,
+ },
+ {
+ .usecase_id = LLCC_VIDSC0,
+ .slice_id = 2,
+ .max_cap = 256,
+ .priority = 2,
+ .fixed_size = true,
+ .bonus_ways = 0xF000,
+ .retain_on_pc = true,
+ .activate_on_init = true,
+ .write_scid_cacheable_en = true,
+ .stale_en = true,
+ .stale_cap_en = true,
+ },
+};
+
+static const struct llcc_slice_config sa8775p_data[] = {
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 2048,
+ .priority = 1,
+ .bonus_ways = 0xff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_VIDSC0,
+ .slice_id = 2,
+ .max_cap = 512,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_CPUSS1,
+ .slice_id = 3,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_CPUHWT,
+ .slice_id = 5,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_AUDIO,
+ .slice_id = 6,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_CMPT,
+ .slice_id = 10,
+ .max_cap = 4096,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 12,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ .write_scid_en = true,
+ }, {
+ .usecase_id = LLCC_MMUHWT,
+ .slice_id = 13,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_CMPTDMA,
+ .slice_id = 15,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_DISP,
+ .slice_id = 16,
+ .max_cap = 4096,
+ .priority = 2,
+ .fixed_size = true,
+ .bonus_ways = 0xff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_VIDFW,
+ .slice_id = 17,
+ .max_cap = 3072,
+ .priority = 1,
+ .bonus_ways = 0xff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_AUDHW,
+ .slice_id = 22,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_CVP,
+ .slice_id = 28,
+ .max_cap = 256,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_APTCM,
+ .slice_id = 30,
+ .max_cap = 1024,
+ .priority = 3,
+ .fixed_size = true,
+ .res_ways = 0xf0,
+ .cache_mode = 1,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_WRCACHE,
+ .slice_id = 31,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ },
+};
+
+static const struct llcc_slice_config sar1130p_data[] = {
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 4096,
+ .priority = 1,
+ .bonus_ways = 0x1fff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_VIDSC0,
+ .slice_id = 2,
+ .max_cap = 512,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0x1fff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_AUDIO,
+ .slice_id = 6,
+ .max_cap = 1024,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0x1fff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_CMPT,
+ .slice_id = 10,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x1fff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 0,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x1fff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 12,
+ .max_cap = 3072,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0x1fff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ .write_scid_en = true,
+ }, {
+ .usecase_id = LLCC_MMUHWT,
+ .slice_id = 13,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x1fff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_DISP,
+ .slice_id = 16,
+ .max_cap = 12800,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x1fff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_CVP,
+ .slice_id = 28,
+ .max_cap = 256,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0x1fff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_APTCM,
+ .slice_id = 26,
+ .max_cap = 2048,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0x0,
+ .res_ways = 0x3,
+ .cache_mode = true,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_WRCACHE,
+ .slice_id = 31,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x1fff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_AENPU,
+ .slice_id = 30,
+ .max_cap = 3072,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0x1fff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_DISP_LEFT,
+ .slice_id = 17,
+ .max_cap = 0,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x0,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_DISP_RIGHT,
+ .slice_id = 18,
+ .max_cap = 0,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x0,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_EVCS_LEFT,
+ .slice_id = 22,
+ .max_cap = 0,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x0,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_EVCS_RIGHT,
+ .slice_id = 23,
+ .max_cap = 0,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x0,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ },
+};
+
+static const struct llcc_slice_config sar2130p_data[] = {
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 6144,
+ .priority = 1,
+ .fixed_size = 0,
+ .bonus_ways = 0x3fffffff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_VIDSC0,
+ .slice_id = 2,
+ .max_cap = 128,
+ .priority = 2,
+ .fixed_size = true,
+ .bonus_ways = 0x3fffffff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_AUDIO,
+ .slice_id = 6,
+ .max_cap = 1024,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0x3fffffff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_CMPT,
+ .slice_id = 10,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x3fffffff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 0,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x3fffffff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 12,
+ .max_cap = 1536,
+ .priority = 2,
+ .fixed_size = true,
+ .bonus_ways = 0x3fffffff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ .write_scid_en = true,
+ }, {
+ .usecase_id = LLCC_MMUHWT,
+ .slice_id = 13,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x3fffffff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_DISP,
+ .slice_id = 16,
+ .max_cap = 0,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x3fffffff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_APTCM,
+ .slice_id = 26,
+ .max_cap = 2048,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0x0,
+ .res_ways = 0x3,
+ .cache_mode = true,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_WRCACHE,
+ .slice_id = 31,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x3fffffff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_VIEYE,
+ .slice_id = 7,
+ .max_cap = 7168,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0x3fffffff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_VIDPTH,
+ .slice_id = 8,
+ .max_cap = 7168,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0x3fffffff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPUMV,
+ .slice_id = 9,
+ .max_cap = 2048,
+ .priority = 2,
+ .fixed_size = true,
+ .bonus_ways = 0x3fffffff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_EVA_LEFT,
+ .slice_id = 20,
+ .max_cap = 7168,
+ .priority = 5,
+ .fixed_size = true,
+ .bonus_ways = 0x3ffffffc,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_EVA_RIGHT,
+ .slice_id = 21,
+ .max_cap = 7168,
+ .priority = 5,
+ .fixed_size = true,
+ .bonus_ways = 0x3ffffffc,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_EVAGAIN,
+ .slice_id = 25,
+ .max_cap = 1024,
+ .priority = 2,
+ .fixed_size = true,
+ .bonus_ways = 0x3fffffff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_AENPU,
+ .slice_id = 30,
+ .max_cap = 3072,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0x3fffffff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_VIPTH,
+ .slice_id = 29,
+ .max_cap = 1024,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0x3fffffff,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_DISP_LEFT,
+ .slice_id = 17,
+ .max_cap = 0,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x0,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_DISP_RIGHT,
+ .slice_id = 18,
+ .max_cap = 0,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x0,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_EVCS_LEFT,
+ .slice_id = 22,
+ .max_cap = 0,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x0,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_EVCS_RIGHT,
+ .slice_id = 23,
+ .max_cap = 0,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x0,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_SPAD,
+ .slice_id = 24,
+ .max_cap = 7168,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x0,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ },
+};
+
static const struct llcc_slice_config sc7180_data[] = {
- { LLCC_CPUSS, 1, 256, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 1 },
- { LLCC_MDM, 8, 128, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_GPUHTW, 11, 128, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_GPU, 12, 128, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 0 },
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 256,
+ .priority = 1,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_MDM,
+ .slice_id = 8,
+ .max_cap = 128,
+ .priority = 1,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 128,
+ .priority = 1,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 12,
+ .max_cap = 128,
+ .priority = 1,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ },
};
static const struct llcc_slice_config sc7280_data[] = {
- { LLCC_CPUSS, 1, 768, 1, 0, 0x3f, 0x0, 0, 0, 0, 1, 1, 0},
- { LLCC_MDMHPGRW, 7, 512, 2, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
- { LLCC_CMPT, 10, 768, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
- { LLCC_GPUHTW, 11, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
- { LLCC_GPU, 12, 512, 1, 0, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
- { LLCC_MMUHWT, 13, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 0, 1, 0},
- { LLCC_MDMPNG, 21, 768, 0, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
- { LLCC_WLHW, 24, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
- { LLCC_MODPE, 29, 64, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 768,
+ .priority = 1,
+ .bonus_ways = 0x3f,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_MDMHPGRW,
+ .slice_id = 7,
+ .max_cap = 512,
+ .priority = 2,
+ .fixed_size = true,
+ .bonus_ways = 0x3f,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_CMPT,
+ .slice_id = 10,
+ .max_cap = 768,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x3f,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x3f,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 12,
+ .max_cap = 512,
+ .priority = 1,
+ .bonus_ways = 0x3f,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MMUHWT,
+ .slice_id = 13,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x3f,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_MDMPNG,
+ .slice_id = 21,
+ .max_cap = 768,
+ .priority = 0,
+ .fixed_size = true,
+ .bonus_ways = 0x3f,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_WLHW,
+ .slice_id = 24,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x3f,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MODPE,
+ .slice_id = 29,
+ .max_cap = 64,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x3f,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ },
};
static const struct llcc_slice_config sc8180x_data[] = {
- { LLCC_CPUSS, 1, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 1 },
- { LLCC_VIDSC0, 2, 512, 2, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_VIDSC1, 3, 512, 2, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_AUDIO, 6, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_MDMHPGRW, 7, 3072, 1, 1, 0x3ff, 0xc00, 0, 0, 0, 1, 0 },
- { LLCC_MDM, 8, 3072, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_MODHW, 9, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_CMPT, 10, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_GPUHTW, 11, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_GPU, 12, 5120, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_MMUHWT, 13, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1 },
- { LLCC_CMPTDMA, 15, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_DISP, 16, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_VIDFW, 17, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_MDMHPFX, 20, 1024, 2, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_MDMPNG, 21, 1024, 0, 1, 0xc, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_AUDHW, 22, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_NPU, 23, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_WLHW, 24, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_MODPE, 29, 512, 1, 1, 0xc, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_APTCM, 30, 512, 3, 1, 0x0, 0x1, 1, 0, 0, 1, 0 },
- { LLCC_WRCACHE, 31, 128, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0 },
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 6144,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_VIDSC0,
+ .slice_id = 2,
+ .max_cap = 512,
+ .priority = 2,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_VIDSC1,
+ .slice_id = 3,
+ .max_cap = 512,
+ .priority = 2,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_AUDIO,
+ .slice_id = 6,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MDMHPGRW,
+ .slice_id = 7,
+ .max_cap = 3072,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x3ff,
+ .res_ways = 0xc00,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MDM,
+ .slice_id = 8,
+ .max_cap = 3072,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MODHW,
+ .slice_id = 9,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_CMPT,
+ .slice_id = 10,
+ .max_cap = 6144,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 12,
+ .max_cap = 5120,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MMUHWT,
+ .slice_id = 13,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_CMPTDMA,
+ .slice_id = 15,
+ .max_cap = 6144,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_DISP,
+ .slice_id = 16,
+ .max_cap = 6144,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_VIDFW,
+ .slice_id = 17,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MDMHPFX,
+ .slice_id = 20,
+ .max_cap = 1024,
+ .priority = 2,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MDMPNG,
+ .slice_id = 21,
+ .max_cap = 1024,
+ .priority = 0,
+ .fixed_size = true,
+ .bonus_ways = 0xc,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_AUDHW,
+ .slice_id = 22,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_NPU,
+ .slice_id = 23,
+ .max_cap = 6144,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_WLHW,
+ .slice_id = 24,
+ .max_cap = 6144,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MODPE,
+ .slice_id = 29,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xc,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_APTCM,
+ .slice_id = 30,
+ .max_cap = 512,
+ .priority = 3,
+ .fixed_size = true,
+ .res_ways = 0x1,
+ .cache_mode = 1,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_WRCACHE,
+ .slice_id = 31,
+ .max_cap = 128,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ },
};
static const struct llcc_slice_config sc8280xp_data[] = {
- { LLCC_CPUSS, 1, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 1, 0 },
- { LLCC_VIDSC0, 2, 512, 3, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
- { LLCC_AUDIO, 6, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 0 },
- { LLCC_CMPT, 10, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 0 },
- { LLCC_GPUHTW, 11, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
- { LLCC_GPU, 12, 4096, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 1 },
- { LLCC_MMUHWT, 13, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
- { LLCC_DISP, 16, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
- { LLCC_AUDHW, 22, 2048, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
- { LLCC_ECC, 26, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
- { LLCC_CVP, 28, 512, 3, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
- { LLCC_APTCM, 30, 1024, 3, 1, 0x0, 0x1, 1, 0, 0, 1, 0, 0 },
- { LLCC_WRCACHE, 31, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
- { LLCC_CVPFW, 17, 512, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
- { LLCC_CPUSS1, 3, 2048, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
- { LLCC_CPUHWT, 5, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
-};
-
-static const struct llcc_slice_config sdm845_data[] = {
- { LLCC_CPUSS, 1, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 1 },
- { LLCC_VIDSC0, 2, 512, 2, 1, 0x0, 0x0f0, 0, 0, 1, 1, 0 },
- { LLCC_VIDSC1, 3, 512, 2, 1, 0x0, 0x0f0, 0, 0, 1, 1, 0 },
- { LLCC_ROTATOR, 4, 563, 2, 1, 0x0, 0x00e, 2, 0, 1, 1, 0 },
- { LLCC_VOICE, 5, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0 },
- { LLCC_AUDIO, 6, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0 },
- { LLCC_MDMHPGRW, 7, 1024, 2, 0, 0xfc, 0xf00, 0, 0, 1, 1, 0 },
- { LLCC_MDM, 8, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0 },
- { LLCC_CMPT, 10, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0 },
- { LLCC_GPUHTW, 11, 512, 1, 1, 0xc, 0x0, 0, 0, 1, 1, 0 },
- { LLCC_GPU, 12, 2304, 1, 0, 0xff0, 0x2, 0, 0, 1, 1, 0 },
- { LLCC_MMUHWT, 13, 256, 2, 0, 0x0, 0x1, 0, 0, 1, 0, 1 },
- { LLCC_CMPTDMA, 15, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0 },
- { LLCC_DISP, 16, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0 },
- { LLCC_VIDFW, 17, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0 },
- { LLCC_MDMHPFX, 20, 1024, 2, 1, 0x0, 0xf00, 0, 0, 1, 1, 0 },
- { LLCC_MDMPNG, 21, 1024, 0, 1, 0x1e, 0x0, 0, 0, 1, 1, 0 },
- { LLCC_AUDHW, 22, 1024, 1, 1, 0xffc, 0x2, 0, 0, 1, 1, 0 },
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 6144,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_VIDSC0,
+ .slice_id = 2,
+ .max_cap = 512,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_AUDIO,
+ .slice_id = 6,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_CMPT,
+ .slice_id = 10,
+ .max_cap = 6144,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 12,
+ .max_cap = 4096,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ .write_scid_en = true,
+ }, {
+ .usecase_id = LLCC_MMUHWT,
+ .slice_id = 13,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_DISP,
+ .slice_id = 16,
+ .max_cap = 6144,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_AUDHW,
+ .slice_id = 22,
+ .max_cap = 2048,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_ECC,
+ .slice_id = 26,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_CVP,
+ .slice_id = 28,
+ .max_cap = 512,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_APTCM,
+ .slice_id = 30,
+ .max_cap = 1024,
+ .priority = 3,
+ .fixed_size = true,
+ .res_ways = 0x1,
+ .cache_mode = 1,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_WRCACHE,
+ .slice_id = 31,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_CVPFW,
+ .slice_id = 17,
+ .max_cap = 512,
+ .priority = 1,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_CPUSS1,
+ .slice_id = 3,
+ .max_cap = 2048,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_CPUHWT,
+ .slice_id = 5,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ },
+};
+
+static const struct llcc_slice_config sdm845_data[] = {{
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 2816,
+ .priority = 1,
+ .bonus_ways = 0xffc,
+ .res_ways = 0x2,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_VIDSC0,
+ .slice_id = 2,
+ .max_cap = 512,
+ .priority = 2,
+ .fixed_size = true,
+ .res_ways = 0xf0,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_VIDSC1,
+ .slice_id = 3,
+ .max_cap = 512,
+ .priority = 2,
+ .fixed_size = true,
+ .res_ways = 0xf0,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_ROTATOR,
+ .slice_id = 4,
+ .max_cap = 563,
+ .priority = 2,
+ .fixed_size = true,
+ .res_ways = 0xe,
+ .cache_mode = 2,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_VOICE,
+ .slice_id = 5,
+ .max_cap = 2816,
+ .priority = 1,
+ .bonus_ways = 0xffc,
+ .res_ways = 0x2,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_AUDIO,
+ .slice_id = 6,
+ .max_cap = 2816,
+ .priority = 1,
+ .bonus_ways = 0xffc,
+ .res_ways = 0x2,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MDMHPGRW,
+ .slice_id = 7,
+ .max_cap = 1024,
+ .priority = 2,
+ .bonus_ways = 0xfc,
+ .res_ways = 0xf00,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MDM,
+ .slice_id = 8,
+ .max_cap = 2816,
+ .priority = 1,
+ .bonus_ways = 0xffc,
+ .res_ways = 0x2,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_CMPT,
+ .slice_id = 10,
+ .max_cap = 2816,
+ .priority = 1,
+ .bonus_ways = 0xffc,
+ .res_ways = 0x2,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xc,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 12,
+ .max_cap = 2304,
+ .priority = 1,
+ .bonus_ways = 0xff0,
+ .res_ways = 0x2,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MMUHWT,
+ .slice_id = 13,
+ .max_cap = 256,
+ .priority = 2,
+ .res_ways = 0x1,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_CMPTDMA,
+ .slice_id = 15,
+ .max_cap = 2816,
+ .priority = 1,
+ .bonus_ways = 0xffc,
+ .res_ways = 0x2,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_DISP,
+ .slice_id = 16,
+ .max_cap = 2816,
+ .priority = 1,
+ .bonus_ways = 0xffc,
+ .res_ways = 0x2,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_VIDFW,
+ .slice_id = 17,
+ .max_cap = 2816,
+ .priority = 1,
+ .bonus_ways = 0xffc,
+ .res_ways = 0x2,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MDMHPFX,
+ .slice_id = 20,
+ .max_cap = 1024,
+ .priority = 2,
+ .fixed_size = true,
+ .res_ways = 0xf00,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MDMPNG,
+ .slice_id = 21,
+ .max_cap = 1024,
+ .priority = 0,
+ .fixed_size = true,
+ .bonus_ways = 0x1e,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_AUDHW,
+ .slice_id = 22,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffc,
+ .res_ways = 0x2,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ },
};
static const struct llcc_slice_config sm6350_data[] = {
- { LLCC_CPUSS, 1, 768, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 1 },
- { LLCC_MDM, 8, 512, 2, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 },
- { LLCC_GPUHTW, 11, 256, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 },
- { LLCC_GPU, 12, 512, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 },
- { LLCC_MDMPNG, 21, 768, 0, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 },
- { LLCC_NPU, 23, 768, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 },
- { LLCC_MODPE, 29, 64, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 },
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 768,
+ .priority = 1,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ .write_scid_en = true,
+ }, {
+ .usecase_id = LLCC_MDM,
+ .slice_id = 8,
+ .max_cap = 512,
+ .priority = 2,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 256,
+ .priority = 1,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 12,
+ .max_cap = 512,
+ .priority = 1,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_MDMPNG,
+ .slice_id = 21,
+ .max_cap = 768,
+ .priority = 0,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_NPU,
+ .slice_id = 23,
+ .max_cap = 768,
+ .priority = 1,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_MODPE,
+ .slice_id = 29,
+ .max_cap = 64,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ },
};
static const struct llcc_slice_config sm7150_data[] = {
- { LLCC_CPUSS, 1, 512, 1, 0, 0xF, 0x0, 0, 0, 0, 1, 1 },
- { LLCC_MDM, 8, 128, 2, 0, 0xF, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_GPUHTW, 11, 256, 1, 1, 0xF, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_GPU, 12, 256, 1, 1, 0xF, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_NPU, 23, 512, 1, 0, 0xF, 0x0, 0, 0, 0, 1, 0 },
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 512,
+ .priority = 1,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_MDM,
+ .slice_id = 8,
+ .max_cap = 128,
+ .priority = 2,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 12,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_NPU,
+ .slice_id = 23,
+ .max_cap = 512,
+ .priority = 1,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ },
};
static const struct llcc_slice_config sm8150_data[] = {
- { LLCC_CPUSS, 1, 3072, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 1 },
- { LLCC_VIDSC0, 2, 512, 2, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_VIDSC1, 3, 512, 2, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_AUDIO, 6, 1024, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_MDMHPGRW, 7, 3072, 1, 0, 0xFF, 0xF00, 0, 0, 0, 1, 0 },
- { LLCC_MDM, 8, 3072, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_MODHW, 9, 1024, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_CMPT, 10, 3072, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_GPUHTW , 11, 512, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_GPU, 12, 2560, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_MMUHWT, 13, 1024, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1 },
- { LLCC_CMPTDMA, 15, 3072, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_DISP, 16, 3072, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_MDMHPFX, 20, 1024, 2, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_MDMHPFX, 21, 1024, 0, 1, 0xF, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_AUDHW, 22, 1024, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_NPU, 23, 3072, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_WLHW, 24, 3072, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_MODPE, 29, 256, 1, 1, 0xF, 0x0, 0, 0, 0, 1, 0 },
- { LLCC_APTCM, 30, 256, 3, 1, 0x0, 0x1, 1, 0, 0, 1, 0 },
- { LLCC_WRCACHE, 31, 128, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0 },
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 3072,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_VIDSC0,
+ .slice_id = 2,
+ .max_cap = 512,
+ .priority = 2,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_VIDSC1,
+ .slice_id = 3,
+ .max_cap = 512,
+ .priority = 2,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_AUDIO,
+ .slice_id = 6,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MDMHPGRW,
+ .slice_id = 7,
+ .max_cap = 3072,
+ .priority = 1,
+ .bonus_ways = 0xff,
+ .res_ways = 0xf00,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MDM,
+ .slice_id = 8,
+ .max_cap = 3072,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MODHW,
+ .slice_id = 9,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_CMPT,
+ .slice_id = 10,
+ .max_cap = 3072,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 12,
+ .max_cap = 2560,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MMUHWT,
+ .slice_id = 13,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_CMPTDMA,
+ .slice_id = 15,
+ .max_cap = 3072,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_DISP,
+ .slice_id = 16,
+ .max_cap = 3072,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MDMHPFX,
+ .slice_id = 20,
+ .max_cap = 1024,
+ .priority = 2,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MDMHPFX,
+ .slice_id = 21,
+ .max_cap = 1024,
+ .priority = 0,
+ .fixed_size = true,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_AUDHW,
+ .slice_id = 22,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_NPU,
+ .slice_id = 23,
+ .max_cap = 3072,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_WLHW,
+ .slice_id = 24,
+ .max_cap = 3072,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MODPE,
+ .slice_id = 29,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_APTCM,
+ .slice_id = 30,
+ .max_cap = 256,
+ .priority = 3,
+ .fixed_size = true,
+ .res_ways = 0x1,
+ .cache_mode = 1,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_WRCACHE,
+ .slice_id = 31,
+ .max_cap = 128,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ },
};
static const struct llcc_slice_config sm8250_data[] = {
- { LLCC_CPUSS, 1, 3072, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 1, 0 },
- { LLCC_VIDSC0, 2, 512, 3, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
- { LLCC_AUDIO, 6, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 0, 0, 0 },
- { LLCC_CMPT, 10, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 0, 0, 0 },
- { LLCC_GPUHTW, 11, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
- { LLCC_GPU, 12, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 0, 1 },
- { LLCC_MMUHWT, 13, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
- { LLCC_CMPTDMA, 15, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
- { LLCC_DISP, 16, 3072, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
- { LLCC_VIDFW, 17, 512, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
- { LLCC_AUDHW, 22, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
- { LLCC_NPU, 23, 3072, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
- { LLCC_WLHW, 24, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
- { LLCC_CVP, 28, 256, 3, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
- { LLCC_APTCM, 30, 128, 3, 0, 0x0, 0x3, 1, 0, 0, 1, 0, 0 },
- { LLCC_WRCACHE, 31, 256, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 3072,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_VIDSC0,
+ .slice_id = 2,
+ .max_cap = 512,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_AUDIO,
+ .slice_id = 6,
+ .max_cap = 1024,
+ .priority = 1,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_CMPT,
+ .slice_id = 10,
+ .max_cap = 1024,
+ .priority = 1,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 12,
+ .max_cap = 1024,
+ .priority = 1,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ .write_scid_en = true,
+ }, {
+ .usecase_id = LLCC_MMUHWT,
+ .slice_id = 13,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_CMPTDMA,
+ .slice_id = 15,
+ .max_cap = 1024,
+ .priority = 1,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_DISP,
+ .slice_id = 16,
+ .max_cap = 3072,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_VIDFW,
+ .slice_id = 17,
+ .max_cap = 512,
+ .priority = 1,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_AUDHW,
+ .slice_id = 22,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_NPU,
+ .slice_id = 23,
+ .max_cap = 3072,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_WLHW,
+ .slice_id = 24,
+ .max_cap = 1024,
+ .priority = 1,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_CVP,
+ .slice_id = 28,
+ .max_cap = 256,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_APTCM,
+ .slice_id = 30,
+ .max_cap = 128,
+ .priority = 3,
+ .res_ways = 0x3,
+ .cache_mode = 1,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_WRCACHE,
+ .slice_id = 31,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ },
};
static const struct llcc_slice_config sm8350_data[] = {
- { LLCC_CPUSS, 1, 3072, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 1 },
- { LLCC_VIDSC0, 2, 512, 3, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
- { LLCC_AUDIO, 6, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 0 },
- { LLCC_MDMHPGRW, 7, 1024, 3, 0, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
- { LLCC_MODHW, 9, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
- { LLCC_CMPT, 10, 3072, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
- { LLCC_GPUHTW, 11, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
- { LLCC_GPU, 12, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 1, 0 },
- { LLCC_MMUHWT, 13, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 1 },
- { LLCC_DISP, 16, 3072, 2, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
- { LLCC_MDMPNG, 21, 1024, 0, 1, 0xf, 0x0, 0, 0, 0, 0, 1, 0 },
- { LLCC_AUDHW, 22, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
- { LLCC_CVP, 28, 512, 3, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
- { LLCC_MODPE, 29, 256, 1, 1, 0xf, 0x0, 0, 0, 0, 0, 1, 0 },
- { LLCC_APTCM, 30, 1024, 3, 1, 0x0, 0x1, 1, 0, 0, 0, 1, 0 },
- { LLCC_WRCACHE, 31, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 1 },
- { LLCC_CVPFW, 17, 512, 1, 0, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
- { LLCC_CPUSS1, 3, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
- { LLCC_CPUHWT, 5, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 1 },
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 3072,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ .write_scid_en = true,
+ }, {
+ .usecase_id = LLCC_VIDSC0,
+ .slice_id = 2,
+ .max_cap = 512,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_AUDIO,
+ .slice_id = 6,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_MDMHPGRW,
+ .slice_id = 7,
+ .max_cap = 1024,
+ .priority = 3,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_MODHW,
+ .slice_id = 9,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_CMPT,
+ .slice_id = 10,
+ .max_cap = 3072,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 12,
+ .max_cap = 1024,
+ .priority = 1,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_MMUHWT,
+ .slice_id = 13,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .write_scid_en = true,
+ }, {
+ .usecase_id = LLCC_DISP,
+ .slice_id = 16,
+ .max_cap = 3072,
+ .priority = 2,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_MDMPNG,
+ .slice_id = 21,
+ .max_cap = 1024,
+ .priority = 0,
+ .fixed_size = true,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_AUDHW,
+ .slice_id = 22,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_CVP,
+ .slice_id = 28,
+ .max_cap = 512,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_MODPE,
+ .slice_id = 29,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_APTCM,
+ .slice_id = 30,
+ .max_cap = 1024,
+ .priority = 3,
+ .fixed_size = true,
+ .res_ways = 0x1,
+ .cache_mode = 1,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_WRCACHE,
+ .slice_id = 31,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .write_scid_en = true,
+ }, {
+ .usecase_id = LLCC_CVPFW,
+ .slice_id = 17,
+ .max_cap = 512,
+ .priority = 1,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_CPUSS1,
+ .slice_id = 3,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_CPUHWT,
+ .slice_id = 5,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .write_scid_en = true,
+ },
};
static const struct llcc_slice_config sm8450_data[] = {
- {LLCC_CPUSS, 1, 3072, 1, 0, 0xFFFF, 0x0, 0, 0, 0, 1, 1, 0, 0 },
- {LLCC_VIDSC0, 2, 512, 3, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- {LLCC_AUDIO, 6, 1024, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0 },
- {LLCC_MDMHPGRW, 7, 1024, 3, 0, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- {LLCC_MODHW, 9, 1024, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- {LLCC_CMPT, 10, 4096, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- {LLCC_GPUHTW, 11, 512, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- {LLCC_GPU, 12, 2048, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 1, 0 },
- {LLCC_MMUHWT, 13, 768, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0 },
- {LLCC_DISP, 16, 4096, 2, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- {LLCC_MDMPNG, 21, 1024, 1, 1, 0xF000, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- {LLCC_AUDHW, 22, 1024, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0 },
- {LLCC_CVP, 28, 256, 3, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- {LLCC_MODPE, 29, 64, 1, 1, 0xF000, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- {LLCC_APTCM, 30, 1024, 3, 1, 0x0, 0xF0, 1, 0, 0, 1, 0, 0, 0 },
- {LLCC_WRCACHE, 31, 512, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0 },
- {LLCC_CVPFW, 17, 512, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- {LLCC_CPUSS1, 3, 1024, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- {LLCC_CAMEXP0, 4, 256, 3, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- {LLCC_CPUMTE, 23, 256, 1, 1, 0x0FFF, 0x0, 0, 0, 0, 0, 1, 0, 0 },
- {LLCC_CPUHWT, 5, 512, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 1, 0, 0 },
- {LLCC_CAMEXP1, 27, 256, 3, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- {LLCC_AENPU, 8, 2048, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0 },
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 3072,
+ .priority = 1,
+ .bonus_ways = 0xffff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_VIDSC0,
+ .slice_id = 2,
+ .max_cap = 512,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xffff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_AUDIO,
+ .slice_id = 6,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_MDMHPGRW,
+ .slice_id = 7,
+ .max_cap = 1024,
+ .priority = 3,
+ .bonus_ways = 0xffff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MODHW,
+ .slice_id = 9,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_CMPT,
+ .slice_id = 10,
+ .max_cap = 4096,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 12,
+ .max_cap = 2048,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ .write_scid_en = true,
+ }, {
+ .usecase_id = LLCC_MMUHWT,
+ .slice_id = 13,
+ .max_cap = 768,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_DISP,
+ .slice_id = 16,
+ .max_cap = 4096,
+ .priority = 2,
+ .fixed_size = true,
+ .bonus_ways = 0xffff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MDMPNG,
+ .slice_id = 21,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xf000,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_AUDHW,
+ .slice_id = 22,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_CVP,
+ .slice_id = 28,
+ .max_cap = 256,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xffff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MODPE,
+ .slice_id = 29,
+ .max_cap = 64,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xf000,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_APTCM,
+ .slice_id = 30,
+ .max_cap = 1024,
+ .priority = 3,
+ .fixed_size = true,
+ .res_ways = 0xf0,
+ .cache_mode = 1,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_WRCACHE,
+ .slice_id = 31,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_CVPFW,
+ .slice_id = 17,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_CPUSS1,
+ .slice_id = 3,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_CAMEXP0,
+ .slice_id = 4,
+ .max_cap = 256,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xffff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_CPUMTE,
+ .slice_id = 23,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_CPUHWT,
+ .slice_id = 5,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_CAMEXP1,
+ .slice_id = 27,
+ .max_cap = 256,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xffff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_AENPU,
+ .slice_id = 8,
+ .max_cap = 2048,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffff,
+ .cache_mode = 0,
+ },
};
static const struct llcc_slice_config sm8550_data[] = {
- {LLCC_CPUSS, 1, 5120, 1, 0, 0xFFFFFF, 0x0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_VIDSC0, 2, 512, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_AUDIO, 6, 1024, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_MDMHPGRW, 25, 1024, 4, 0, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_MODHW, 26, 1024, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_CMPT, 10, 4096, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_GPUHTW, 11, 512, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_GPU, 9, 3096, 1, 0, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_MMUHWT, 18, 768, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_DISP, 16, 6144, 1, 1, 0xFFFFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_MDMPNG, 27, 1024, 0, 1, 0xF00000, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_AUDHW, 22, 1024, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_CVP, 8, 256, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_MODPE, 29, 64, 1, 1, 0xF00000, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, },
- {LLCC_WRCACHE, 31, 512, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_CAMEXP0, 4, 256, 4, 1, 0xF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_CPUHWT, 5, 512, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_CAMEXP1, 7, 3200, 3, 1, 0xFFFFF0, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_CMPTHCP, 17, 256, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_LCPDARE, 30, 128, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, },
- {LLCC_AENPU, 3, 3072, 1, 1, 0xFE01FF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_ISLAND1, 12, 1792, 7, 1, 0xFE00, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_ISLAND4, 15, 256, 7, 1, 0x10000, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_CAMEXP2, 19, 3200, 3, 1, 0xFFFFF0, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_CAMEXP3, 20, 3200, 2, 1, 0xFFFFF0, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_CAMEXP4, 21, 3200, 2, 1, 0xFFFFF0, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_DISP_WB, 23, 1024, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_DISP_1, 24, 6144, 1, 1, 0xFFFFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- {LLCC_VIDVSP, 28, 256, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 5120,
+ .priority = 1,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ .write_scid_en = true,
+ }, {
+ .usecase_id = LLCC_VIDSC0,
+ .slice_id = 2,
+ .max_cap = 512,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_AUDIO,
+ .slice_id = 6,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_MDMHPGRW,
+ .slice_id = 25,
+ .max_cap = 1024,
+ .priority = 4,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_MODHW,
+ .slice_id = 26,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_CMPT,
+ .slice_id = 10,
+ .max_cap = 4096,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 9,
+ .max_cap = 3096,
+ .priority = 1,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ .write_scid_en = true,
+ .write_scid_cacheable_en = true,
+ }, {
+ .usecase_id = LLCC_MMUHWT,
+ .slice_id = 18,
+ .max_cap = 768,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_DISP,
+ .slice_id = 16,
+ .max_cap = 6144,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 2,
+ }, {
+ .usecase_id = LLCC_MDMPNG,
+ .slice_id = 27,
+ .max_cap = 1024,
+ .priority = 0,
+ .fixed_size = true,
+ .bonus_ways = 0xf00000,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_AUDHW,
+ .slice_id = 22,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_CVP,
+ .slice_id = 8,
+ .max_cap = 256,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_MODPE,
+ .slice_id = 29,
+ .max_cap = 64,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xf00000,
+ .cache_mode = 0,
+ .alloc_oneway_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_WRCACHE,
+ .slice_id = 31,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_CAMEXP0,
+ .slice_id = 4,
+ .max_cap = 256,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_CPUHWT,
+ .slice_id = 5,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_CAMEXP1,
+ .slice_id = 7,
+ .max_cap = 3200,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xfffff0,
+ .cache_mode = 2,
+ }, {
+ .usecase_id = LLCC_CMPTHCP,
+ .slice_id = 17,
+ .max_cap = 256,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_LCPDARE,
+ .slice_id = 30,
+ .max_cap = 128,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ .alloc_oneway_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_AENPU,
+ .slice_id = 3,
+ .max_cap = 3072,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfe01ff,
+ .cache_mode = 2,
+ }, {
+ .usecase_id = LLCC_ISLAND1,
+ .slice_id = 12,
+ .max_cap = 1792,
+ .priority = 7,
+ .fixed_size = true,
+ .bonus_ways = 0xfe00,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_ISLAND4,
+ .slice_id = 15,
+ .max_cap = 256,
+ .priority = 7,
+ .fixed_size = true,
+ .bonus_ways = 0x10000,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_CAMEXP2,
+ .slice_id = 19,
+ .max_cap = 3200,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xfffff0,
+ .cache_mode = 2,
+ }, {
+ .usecase_id = LLCC_CAMEXP3,
+ .slice_id = 20,
+ .max_cap = 3200,
+ .priority = 2,
+ .fixed_size = true,
+ .bonus_ways = 0xfffff0,
+ .cache_mode = 2,
+ }, {
+ .usecase_id = LLCC_CAMEXP4,
+ .slice_id = 21,
+ .max_cap = 3200,
+ .priority = 2,
+ .fixed_size = true,
+ .bonus_ways = 0xfffff0,
+ .cache_mode = 2,
+ }, {
+ .usecase_id = LLCC_DISP_WB,
+ .slice_id = 23,
+ .max_cap = 1024,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_DISP_1,
+ .slice_id = 24,
+ .max_cap = 6144,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 2,
+ }, {
+ .usecase_id = LLCC_VIDVSP,
+ .slice_id = 28,
+ .max_cap = 256,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ },
};
static const struct llcc_slice_config sm8650_data[] = {
- {LLCC_CPUSS, 1, 5120, 1, 0, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_VIDSC0, 2, 512, 3, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_AUDIO, 6, 512, 1, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_MDMHPGRW, 25, 1024, 3, 0, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_MODHW, 26, 1024, 1, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_CMPT, 10, 4096, 1, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_GPUHTW, 11, 512, 1, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_GPU, 9, 3096, 1, 0, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_MMUHWT, 18, 768, 1, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_DISP, 16, 6144, 1, 1, 0xFFFFFF, 0x0, 2, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_MDMHPFX, 24, 1024, 3, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_MDMPNG, 27, 1024, 0, 1, 0x000000, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_AUDHW, 22, 1024, 1, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_CVP, 8, 256, 3, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_MODPE, 29, 128, 1, 1, 0xF00000, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
- {LLCC_WRCACHE, 31, 512, 1, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_CAMEXP0, 4, 256, 3, 1, 0xF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_CAMEXP1, 7, 3200, 3, 1, 0xFFFFF0, 0x0, 2, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_CMPTHCP, 17, 256, 3, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_LCPDARE, 30, 128, 3, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
- {LLCC_AENPU, 3, 3072, 1, 1, 0xFFFFFF, 0x0, 2, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_ISLAND1, 12, 5888, 7, 1, 0x0, 0x7FFFFF, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_DISP_WB, 23, 1024, 3, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_VIDVSP, 28, 256, 3, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 5120,
+ .priority = 1,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ .stale_en = true,
+ }, {
+ .usecase_id = LLCC_VIDSC0,
+ .slice_id = 2,
+ .max_cap = 512,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_AUDIO,
+ .slice_id = 6,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_MDMHPGRW,
+ .slice_id = 25,
+ .max_cap = 1024,
+ .priority = 3,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_MODHW,
+ .slice_id = 26,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_CMPT,
+ .slice_id = 10,
+ .max_cap = 4096,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 9,
+ .max_cap = 3096,
+ .priority = 1,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ .write_scid_en = true,
+ .write_scid_cacheable_en = true,
+ }, {
+ .usecase_id = LLCC_MMUHWT,
+ .slice_id = 18,
+ .max_cap = 768,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_DISP,
+ .slice_id = 16,
+ .max_cap = 6144,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 2,
+ }, {
+ .usecase_id = LLCC_MDMHPFX,
+ .slice_id = 24,
+ .max_cap = 1024,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_MDMPNG,
+ .slice_id = 27,
+ .max_cap = 1024,
+ .priority = 0,
+ .fixed_size = true,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_AUDHW,
+ .slice_id = 22,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_CVP,
+ .slice_id = 8,
+ .max_cap = 256,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_MODPE,
+ .slice_id = 29,
+ .max_cap = 128,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xf00000,
+ .cache_mode = 0,
+ .alloc_oneway_en = true,
+ }, {
+ .usecase_id = LLCC_WRCACHE,
+ .slice_id = 31,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_CAMEXP0,
+ .slice_id = 4,
+ .max_cap = 256,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_CAMEXP1,
+ .slice_id = 7,
+ .max_cap = 3200,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xfffff0,
+ .cache_mode = 2,
+ }, {
+ .usecase_id = LLCC_CMPTHCP,
+ .slice_id = 17,
+ .max_cap = 256,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_LCPDARE,
+ .slice_id = 30,
+ .max_cap = 128,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ .alloc_oneway_en = true,
+ }, {
+ .usecase_id = LLCC_AENPU,
+ .slice_id = 3,
+ .max_cap = 3072,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 2,
+ }, {
+ .usecase_id = LLCC_ISLAND1,
+ .slice_id = 12,
+ .max_cap = 5888,
+ .priority = 7,
+ .fixed_size = true,
+ .res_ways = 0x7fffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_DISP_WB,
+ .slice_id = 23,
+ .max_cap = 1024,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_VIDVSP,
+ .slice_id = 28,
+ .max_cap = 256,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xffffff,
+ .cache_mode = 0,
+ },
+};
+
+static const struct llcc_slice_config qcs615_data[] = {
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 128,
+ .priority = 1,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ .write_scid_en = true,
+ }, {
+ .usecase_id = LLCC_MDM,
+ .slice_id = 8,
+ .max_cap = 256,
+ .priority = 0,
+ .fixed_size = true,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 128,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 12,
+ .max_cap = 128,
+ .priority = 1,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ },
+};
+
+static const struct llcc_slice_config qcs8300_data[] = {
+ {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 128,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 12,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ .write_scid_en = true,
+ }, {
+ .usecase_id = LLCC_MMUHWT,
+ .slice_id = 13,
+ .max_cap = 128,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_ECC,
+ .slice_id = 26,
+ .max_cap = 256,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_WRCACHE,
+ .slice_id = 31,
+ .max_cap = 128,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xf,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ },
};
static const struct llcc_slice_config qdu1000_data_2ch[] = {
- { LLCC_MDMHPGRW, 7, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- { LLCC_MODHW, 9, 256, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- { LLCC_MDMPNG, 21, 256, 0, 1, 0x3, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- { LLCC_ECC, 26, 512, 3, 1, 0xffc, 0x0, 0, 0, 0, 0, 1, 0, 0 },
- { LLCC_MODPE, 29, 256, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- { LLCC_APTCM, 30, 256, 3, 1, 0x0, 0xc, 1, 0, 0, 1, 0, 0, 0 },
- { LLCC_WRCACHE, 31, 128, 1, 1, 0x3, 0x0, 0, 0, 0, 0, 1, 0, 0 },
+ {
+ .usecase_id = LLCC_MDMHPGRW,
+ .slice_id = 7,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MODHW,
+ .slice_id = 9,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MDMPNG,
+ .slice_id = 21,
+ .max_cap = 256,
+ .priority = 0,
+ .fixed_size = true,
+ .bonus_ways = 0x3,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_ECC,
+ .slice_id = 26,
+ .max_cap = 512,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xffc,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_MODPE,
+ .slice_id = 29,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_APTCM,
+ .slice_id = 30,
+ .max_cap = 256,
+ .priority = 3,
+ .fixed_size = true,
+ .res_ways = 0xc,
+ .cache_mode = 1,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_WRCACHE,
+ .slice_id = 31,
+ .max_cap = 128,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x3,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ },
};
static const struct llcc_slice_config qdu1000_data_4ch[] = {
- { LLCC_MDMHPGRW, 7, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- { LLCC_MODHW, 9, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- { LLCC_MDMPNG, 21, 512, 0, 1, 0x3, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- { LLCC_ECC, 26, 1024, 3, 1, 0xffc, 0x0, 0, 0, 0, 0, 1, 0, 0 },
- { LLCC_MODPE, 29, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- { LLCC_APTCM, 30, 512, 3, 1, 0x0, 0xc, 1, 0, 0, 1, 0, 0, 0 },
- { LLCC_WRCACHE, 31, 256, 1, 1, 0x3, 0x0, 0, 0, 0, 0, 1, 0, 0 },
+ {
+ .usecase_id = LLCC_MDMHPGRW,
+ .slice_id = 7,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MODHW,
+ .slice_id = 9,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MDMPNG,
+ .slice_id = 21,
+ .max_cap = 512,
+ .priority = 0,
+ .fixed_size = true,
+ .bonus_ways = 0x3,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_ECC,
+ .slice_id = 26,
+ .max_cap = 1024,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xffc,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_MODPE,
+ .slice_id = 29,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_APTCM,
+ .slice_id = 30,
+ .max_cap = 512,
+ .priority = 3,
+ .fixed_size = true,
+ .res_ways = 0xc,
+ .cache_mode = 1,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_WRCACHE,
+ .slice_id = 31,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x3,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ },
};
static const struct llcc_slice_config qdu1000_data_8ch[] = {
- { LLCC_MDMHPGRW, 7, 2048, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- { LLCC_MODHW, 9, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- { LLCC_MDMPNG, 21, 1024, 0, 1, 0x3, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- { LLCC_ECC, 26, 2048, 3, 1, 0xffc, 0x0, 0, 0, 0, 0, 1, 0, 0 },
- { LLCC_MODPE, 29, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 },
- { LLCC_APTCM, 30, 1024, 3, 1, 0x0, 0xc, 1, 0, 0, 1, 0, 0, 0 },
- { LLCC_WRCACHE, 31, 512, 1, 1, 0x3, 0x0, 0, 0, 0, 0, 1, 0, 0 },
+ {
+ .usecase_id = LLCC_MDMHPGRW,
+ .slice_id = 7,
+ .max_cap = 2048,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MODHW,
+ .slice_id = 9,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MDMPNG,
+ .slice_id = 21,
+ .max_cap = 1024,
+ .priority = 0,
+ .fixed_size = true,
+ .bonus_ways = 0x3,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_ECC,
+ .slice_id = 26,
+ .max_cap = 2048,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xffc,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_MODPE,
+ .slice_id = 29,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_APTCM,
+ .slice_id = 30,
+ .max_cap = 1024,
+ .priority = 3,
+ .fixed_size = true,
+ .res_ways = 0xc,
+ .cache_mode = 1,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_WRCACHE,
+ .slice_id = 31,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x3,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ },
};
static const struct llcc_slice_config x1e80100_data[] = {
- {LLCC_CPUSS, 1, 6144, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_VIDSC0, 2, 512, 3, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_AUDIO, 6, 3072, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_CMPT, 10, 6144, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_GPUHTW, 11, 1024, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_GPU, 9, 4096, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_MMUHWT, 18, 512, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_AUDHW, 22, 1024, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_CVP, 8, 512, 3, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_WRCACHE, 31, 512, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_CAMEXP1, 7, 3072, 2, 1, 0xFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_LCPDARE, 30, 512, 3, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_AENPU, 3, 3072, 1, 1, 0xFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_ISLAND1, 12, 512, 7, 1, 0x1, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_ISLAND2, 13, 512, 7, 1, 0x2, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_ISLAND3, 14, 512, 7, 1, 0x3, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_ISLAND4, 15, 512, 7, 1, 0x4, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_CAMEXP2, 19, 3072, 3, 1, 0xFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_CAMEXP3, 20, 3072, 3, 1, 0xFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- {LLCC_CAMEXP4, 21, 3072, 3, 1, 0xFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 6144,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_VIDSC0,
+ .slice_id = 2,
+ .max_cap = 512,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_AUDIO,
+ .slice_id = 6,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_CMPT,
+ .slice_id = 10,
+ .max_cap = 6144,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 9,
+ .max_cap = 4608,
+ .priority = 1,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .write_scid_en = true,
+ .write_scid_cacheable_en = true,
+ .stale_en = true,
+ }, {
+ .usecase_id = LLCC_MMUHWT,
+ .slice_id = 18,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_AUDHW,
+ .slice_id = 22,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_CVP,
+ .slice_id = 8,
+ .max_cap = 512,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_WRCACHE,
+ .slice_id = 31,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_CAMEXP0,
+ .slice_id = 4,
+ .max_cap = 256,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0x3,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_CAMEXP1,
+ .slice_id = 7,
+ .max_cap = 3072,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xffc,
+ .cache_mode = 2,
+ }, {
+ .usecase_id = LLCC_LCPDARE,
+ .slice_id = 30,
+ .max_cap = 512,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 0,
+ .activate_on_init = true,
+ .alloc_oneway_en = true,
+ }, {
+ .usecase_id = LLCC_AENPU,
+ .slice_id = 3,
+ .max_cap = 3072,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xfff,
+ .cache_mode = 2,
+ }, {
+ .usecase_id = LLCC_ISLAND1,
+ .slice_id = 12,
+ .max_cap = 2048,
+ .priority = 7,
+ .fixed_size = true,
+ .res_ways = 0xf,
+ .cache_mode = 0,
+ }, {
+ .usecase_id = LLCC_CAMEXP2,
+ .slice_id = 19,
+ .max_cap = 3072,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xffc,
+ .cache_mode = 2,
+ }, {
+ .usecase_id = LLCC_CAMEXP3,
+ .slice_id = 20,
+ .max_cap = 3072,
+ .priority = 2,
+ .fixed_size = true,
+ .bonus_ways = 0xffc,
+ .cache_mode = 2,
+ }, {
+ .usecase_id = LLCC_CAMEXP4,
+ .slice_id = 21,
+ .max_cap = 3072,
+ .priority = 2,
+ .fixed_size = true,
+ .bonus_ways = 0xffc,
+ .cache_mode = 2,
+ },
};
static const struct llcc_edac_reg_offset llcc_v1_edac_reg_offset = {
@@ -521,42 +3173,97 @@ static const u32 llcc_v2_1_reg_offset[] = {
[LLCC_COMMON_STATUS0] = 0x0003400c,
};
+static const struct qcom_llcc_config qcs615_cfg[] = {
+ {
+ .sct_data = qcs615_data,
+ .size = ARRAY_SIZE(qcs615_data),
+ .reg_offset = llcc_v1_reg_offset,
+ .edac_reg_offset = &llcc_v1_edac_reg_offset,
+ },
+};
+
+static const struct qcom_llcc_config qcs8300_cfg[] = {
+ {
+ .sct_data = qcs8300_data,
+ .size = ARRAY_SIZE(qcs8300_data),
+ .reg_offset = llcc_v2_1_reg_offset,
+ .edac_reg_offset = &llcc_v2_1_edac_reg_offset,
+ .num_banks = 4,
+ },
+};
+
static const struct qcom_llcc_config qdu1000_cfg[] = {
{
.sct_data = qdu1000_data_8ch,
.size = ARRAY_SIZE(qdu1000_data_8ch),
- .need_llcc_cfg = true,
.reg_offset = llcc_v2_1_reg_offset,
.edac_reg_offset = &llcc_v2_1_edac_reg_offset,
},
{
.sct_data = qdu1000_data_4ch,
.size = ARRAY_SIZE(qdu1000_data_4ch),
- .need_llcc_cfg = true,
.reg_offset = llcc_v2_1_reg_offset,
.edac_reg_offset = &llcc_v2_1_edac_reg_offset,
},
{
.sct_data = qdu1000_data_4ch,
.size = ARRAY_SIZE(qdu1000_data_4ch),
- .need_llcc_cfg = true,
.reg_offset = llcc_v2_1_reg_offset,
.edac_reg_offset = &llcc_v2_1_edac_reg_offset,
},
{
.sct_data = qdu1000_data_2ch,
.size = ARRAY_SIZE(qdu1000_data_2ch),
- .need_llcc_cfg = true,
.reg_offset = llcc_v2_1_reg_offset,
.edac_reg_offset = &llcc_v2_1_edac_reg_offset,
},
};
+static const struct qcom_llcc_config ipq5424_cfg[] = {
+ {
+ .sct_data = ipq5424_data,
+ .size = ARRAY_SIZE(ipq5424_data),
+ .reg_offset = llcc_v2_1_reg_offset,
+ .edac_reg_offset = &llcc_v2_1_edac_reg_offset,
+ .no_broadcast_register = true,
+ },
+};
+
+static const struct qcom_llcc_config sa8775p_cfg[] = {
+ {
+ .sct_data = sa8775p_data,
+ .size = ARRAY_SIZE(sa8775p_data),
+ .reg_offset = llcc_v2_1_reg_offset,
+ .edac_reg_offset = &llcc_v2_1_edac_reg_offset,
+ },
+};
+
+static const struct qcom_llcc_config sar1130p_cfg[] = {
+ {
+ .sct_data = sar1130p_data,
+ .size = ARRAY_SIZE(sar1130p_data),
+ .reg_offset = llcc_v2_1_reg_offset,
+ .edac_reg_offset = &llcc_v2_1_edac_reg_offset,
+ .max_cap_shift = 14,
+ .num_banks = 2,
+ },
+};
+
+static const struct qcom_llcc_config sar2130p_cfg[] = {
+ {
+ .sct_data = sar2130p_data,
+ .size = ARRAY_SIZE(sar2130p_data),
+ .reg_offset = llcc_v2_1_reg_offset,
+ .edac_reg_offset = &llcc_v2_1_edac_reg_offset,
+ .max_cap_shift = 14,
+ .num_banks = 2,
+ },
+};
+
static const struct qcom_llcc_config sc7180_cfg[] = {
{
.sct_data = sc7180_data,
.size = ARRAY_SIZE(sc7180_data),
- .need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
},
@@ -566,7 +3273,6 @@ static const struct qcom_llcc_config sc7280_cfg[] = {
{
.sct_data = sc7280_data,
.size = ARRAY_SIZE(sc7280_data),
- .need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
},
@@ -576,7 +3282,6 @@ static const struct qcom_llcc_config sc8180x_cfg[] = {
{
.sct_data = sc8180x_data,
.size = ARRAY_SIZE(sc8180x_data),
- .need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
},
@@ -586,7 +3291,6 @@ static const struct qcom_llcc_config sc8280xp_cfg[] = {
{
.sct_data = sc8280xp_data,
.size = ARRAY_SIZE(sc8280xp_data),
- .need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
},
@@ -596,7 +3300,7 @@ static const struct qcom_llcc_config sdm845_cfg[] = {
{
.sct_data = sdm845_data,
.size = ARRAY_SIZE(sdm845_data),
- .need_llcc_cfg = false,
+ .skip_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
.no_edac = true,
@@ -607,7 +3311,6 @@ static const struct qcom_llcc_config sm6350_cfg[] = {
{
.sct_data = sm6350_data,
.size = ARRAY_SIZE(sm6350_data),
- .need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
},
@@ -617,7 +3320,6 @@ static const struct qcom_llcc_config sm7150_cfg[] = {
{
.sct_data = sm7150_data,
.size = ARRAY_SIZE(sm7150_data),
- .need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
},
@@ -627,7 +3329,6 @@ static const struct qcom_llcc_config sm8150_cfg[] = {
{
.sct_data = sm8150_data,
.size = ARRAY_SIZE(sm8150_data),
- .need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
},
@@ -637,7 +3338,6 @@ static const struct qcom_llcc_config sm8250_cfg[] = {
{
.sct_data = sm8250_data,
.size = ARRAY_SIZE(sm8250_data),
- .need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
},
@@ -647,7 +3347,6 @@ static const struct qcom_llcc_config sm8350_cfg[] = {
{
.sct_data = sm8350_data,
.size = ARRAY_SIZE(sm8350_data),
- .need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
},
@@ -657,7 +3356,6 @@ static const struct qcom_llcc_config sm8450_cfg[] = {
{
.sct_data = sm8450_data,
.size = ARRAY_SIZE(sm8450_data),
- .need_llcc_cfg = true,
.reg_offset = llcc_v2_1_reg_offset,
.edac_reg_offset = &llcc_v2_1_edac_reg_offset,
},
@@ -667,7 +3365,6 @@ static const struct qcom_llcc_config sm8550_cfg[] = {
{
.sct_data = sm8550_data,
.size = ARRAY_SIZE(sm8550_data),
- .need_llcc_cfg = true,
.reg_offset = llcc_v2_1_reg_offset,
.edac_reg_offset = &llcc_v2_1_edac_reg_offset,
},
@@ -677,7 +3374,6 @@ static const struct qcom_llcc_config sm8650_cfg[] = {
{
.sct_data = sm8650_data,
.size = ARRAY_SIZE(sm8650_data),
- .need_llcc_cfg = true,
.reg_offset = llcc_v2_1_reg_offset,
.edac_reg_offset = &llcc_v2_1_edac_reg_offset,
},
@@ -687,17 +3383,47 @@ static const struct qcom_llcc_config x1e80100_cfg[] = {
{
.sct_data = x1e80100_data,
.size = ARRAY_SIZE(x1e80100_data),
- .need_llcc_cfg = true,
.reg_offset = llcc_v2_1_reg_offset,
.edac_reg_offset = &llcc_v2_1_edac_reg_offset,
+ .irq_configured = true,
},
};
+static const struct qcom_sct_config qcs615_cfgs = {
+ .llcc_config = qcs615_cfg,
+ .num_config = ARRAY_SIZE(qcs615_cfg),
+};
+
+static const struct qcom_sct_config qcs8300_cfgs = {
+ .llcc_config = qcs8300_cfg,
+ .num_config = ARRAY_SIZE(qcs8300_cfg),
+};
+
static const struct qcom_sct_config qdu1000_cfgs = {
.llcc_config = qdu1000_cfg,
.num_config = ARRAY_SIZE(qdu1000_cfg),
};
+static const struct qcom_sct_config ipq5424_cfgs = {
+ .llcc_config = ipq5424_cfg,
+ .num_config = ARRAY_SIZE(ipq5424_cfg),
+};
+
+static const struct qcom_sct_config sa8775p_cfgs = {
+ .llcc_config = sa8775p_cfg,
+ .num_config = ARRAY_SIZE(sa8775p_cfg),
+};
+
+static const struct qcom_sct_config sar1130p_cfgs = {
+ .llcc_config = sar1130p_cfg,
+ .num_config = ARRAY_SIZE(sar1130p_cfg),
+};
+
+static const struct qcom_sct_config sar2130p_cfgs = {
+ .llcc_config = sar2130p_cfg,
+ .num_config = ARRAY_SIZE(sar2130p_cfg),
+};
+
static const struct qcom_sct_config sc7180_cfgs = {
.llcc_config = sc7180_cfg,
.num_config = ARRAY_SIZE(sc7180_cfg),
@@ -821,6 +3547,7 @@ EXPORT_SYMBOL_GPL(llcc_slice_putd);
static int llcc_update_act_ctrl(u32 sid,
u32 act_ctrl_reg_val, u32 status)
{
+ struct regmap *regmap;
u32 act_ctrl_reg;
u32 act_clear_reg;
u32 status_reg;
@@ -849,7 +3576,8 @@ static int llcc_update_act_ctrl(u32 sid,
return ret;
if (drv_data->version >= LLCC_VERSION_4_1_0_0) {
- ret = regmap_read_poll_timeout(drv_data->bcast_regmap, status_reg,
+ regmap = drv_data->bcast_and_regmap ?: drv_data->bcast_regmap;
+ ret = regmap_read_poll_timeout(regmap, status_reg,
slice_status, (slice_status & ACT_COMPLETE),
0, LLCC_STATUS_READ_DELAY);
if (ret)
@@ -859,6 +3587,8 @@ static int llcc_update_act_ctrl(u32 sid,
ret = regmap_read_poll_timeout(drv_data->bcast_regmap, status_reg,
slice_status, !(slice_status & status),
0, LLCC_STATUS_READ_DELAY);
+ if (ret)
+ return ret;
if (drv_data->version >= LLCC_VERSION_4_1_0_0)
ret = regmap_write(drv_data->bcast_regmap, act_clear_reg,
@@ -1001,7 +3731,10 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
*/
max_cap_cacheline = max_cap_cacheline / drv_data->num_banks;
max_cap_cacheline >>= CACHE_LINE_SIZE_SHIFT;
- attr1_val |= max_cap_cacheline << ATTR1_MAX_CAP_SHIFT;
+ if (cfg->max_cap_shift)
+ attr1_val |= max_cap_cacheline << cfg->max_cap_shift;
+ else
+ attr1_val |= max_cap_cacheline << ATTR1_MAX_CAP_SHIFT;
attr1_cfg = LLCC_TRP_ATTR1_CFGn(config->slice_id);
@@ -1030,7 +3763,8 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
return ret;
}
- if (cfg->need_llcc_cfg) {
+ /* At least SDM845 disallows non-secure writes to these registers */
+ if (!cfg->skip_llcc_cfg) {
u32 disable_cap_alloc, retain_pc;
disable_cap_alloc = config->dis_cap_alloc << config->slice_id;
@@ -1238,12 +3972,17 @@ static int qcom_llcc_probe(struct platform_device *pdev)
goto err;
cfg = &cfgs->llcc_config[cfg_index];
- ret = regmap_read(regmap, cfg->reg_offset[LLCC_COMMON_STATUS0], &num_banks);
- if (ret)
- goto err;
+ if (cfg->num_banks) {
+ num_banks = cfg->num_banks;
+ } else {
+ ret = regmap_read(regmap, cfg->reg_offset[LLCC_COMMON_STATUS0], &num_banks);
+ if (ret)
+ goto err;
+
+ num_banks &= LLCC_LB_CNT_MASK;
+ num_banks >>= LLCC_LB_CNT_SHIFT;
+ }
- num_banks &= LLCC_LB_CNT_MASK;
- num_banks >>= LLCC_LB_CNT_SHIFT;
drv_data->num_banks = num_banks;
drv_data->regmaps = devm_kcalloc(dev, num_banks, sizeof(*drv_data->regmaps), GFP_KERNEL);
@@ -1256,22 +3995,23 @@ static int qcom_llcc_probe(struct platform_device *pdev)
/* Initialize rest of LLCC bank regmaps */
for (i = 1; i < num_banks; i++) {
- char *base = kasprintf(GFP_KERNEL, "llcc%d_base", i);
+ char *base __free(kfree) = kasprintf(GFP_KERNEL, "llcc%d_base", i);
drv_data->regmaps[i] = qcom_llcc_init_mmio(pdev, i, base);
if (IS_ERR(drv_data->regmaps[i])) {
ret = PTR_ERR(drv_data->regmaps[i]);
- kfree(base);
goto err;
}
-
- kfree(base);
}
drv_data->bcast_regmap = qcom_llcc_init_mmio(pdev, i, "llcc_broadcast_base");
if (IS_ERR(drv_data->bcast_regmap)) {
- ret = PTR_ERR(drv_data->bcast_regmap);
- goto err;
+ if (cfg->no_broadcast_register) {
+ drv_data->bcast_regmap = regmap;
+ } else {
+ ret = PTR_ERR(drv_data->bcast_regmap);
+ goto err;
+ }
}
/* Extract version of the IP */
@@ -1282,6 +4022,18 @@ static int qcom_llcc_probe(struct platform_device *pdev)
drv_data->version = version;
+ /* Applicable only when drv_data->version >= 4.1 */
+ if (drv_data->version >= LLCC_VERSION_4_1_0_0) {
+ drv_data->bcast_and_regmap = qcom_llcc_init_mmio(pdev, i + 1, "llcc_broadcast_and_base");
+ if (IS_ERR(drv_data->bcast_and_regmap)) {
+ ret = PTR_ERR(drv_data->bcast_and_regmap);
+ if (ret == -EINVAL)
+ drv_data->bcast_and_regmap = NULL;
+ else
+ goto err;
+ }
+ }
+
llcc_cfg = cfg->sct_data;
sz = cfg->size;
@@ -1299,6 +4051,7 @@ static int qcom_llcc_probe(struct platform_device *pdev)
drv_data->cfg = llcc_cfg;
drv_data->cfg_size = sz;
drv_data->edac_reg_offset = cfg->edac_reg_offset;
+ drv_data->ecc_irq_configured = cfg->irq_configured;
mutex_init(&drv_data->lock);
platform_set_drvdata(pdev, drv_data);
@@ -1329,7 +4082,13 @@ err:
}
static const struct of_device_id qcom_llcc_of_match[] = {
+ { .compatible = "qcom,ipq5424-llcc", .data = &ipq5424_cfgs},
+ { .compatible = "qcom,qcs615-llcc", .data = &qcs615_cfgs},
+ { .compatible = "qcom,qcs8300-llcc", .data = &qcs8300_cfgs},
{ .compatible = "qcom,qdu1000-llcc", .data = &qdu1000_cfgs},
+ { .compatible = "qcom,sa8775p-llcc", .data = &sa8775p_cfgs },
+ { .compatible = "qcom,sar1130p-llcc", .data = &sar1130p_cfgs },
+ { .compatible = "qcom,sar2130p-llcc", .data = &sar2130p_cfgs },
{ .compatible = "qcom,sc7180-llcc", .data = &sc7180_cfgs },
{ .compatible = "qcom,sc7280-llcc", .data = &sc7280_cfgs },
{ .compatible = "qcom,sc8180x-llcc", .data = &sc8180x_cfgs },
@@ -1354,7 +4113,7 @@ static struct platform_driver qcom_llcc_driver = {
.of_match_table = qcom_llcc_of_match,
},
.probe = qcom_llcc_probe,
- .remove_new = qcom_llcc_remove,
+ .remove = qcom_llcc_remove,
};
module_platform_driver(qcom_llcc_driver);
diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c
index 6f177e46fa0f..b2c0fb55d4ae 100644
--- a/drivers/soc/qcom/mdt_loader.c
+++ b/drivers/soc/qcom/mdt_loader.c
@@ -7,6 +7,7 @@
* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*/
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/elf.h>
#include <linux/firmware.h>
@@ -37,13 +38,12 @@ static ssize_t mdt_load_split_segment(void *ptr, const struct elf32_phdr *phdrs,
{
const struct elf32_phdr *phdr = &phdrs[segment];
const struct firmware *seg_fw;
- char *seg_name;
ssize_t ret;
if (strlen(fw_name) < 4)
return -EINVAL;
- seg_name = kstrdup(fw_name, GFP_KERNEL);
+ char *seg_name __free(kfree) = kstrdup(fw_name, GFP_KERNEL);
if (!seg_name)
return -ENOMEM;
@@ -52,7 +52,6 @@ static ssize_t mdt_load_split_segment(void *ptr, const struct elf32_phdr *phdrs,
ptr, phdr->p_filesz);
if (ret) {
dev_err(dev, "error %zd loading %s\n", ret, seg_name);
- kfree(seg_name);
return ret;
}
@@ -64,7 +63,6 @@ static ssize_t mdt_load_split_segment(void *ptr, const struct elf32_phdr *phdrs,
}
release_firmware(seg_fw);
- kfree(seg_name);
return ret;
}
diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c
index e8841d247953..9c3bd37b6579 100644
--- a/drivers/soc/qcom/ocmem.c
+++ b/drivers/soc/qcom/ocmem.c
@@ -10,6 +10,7 @@
*/
#include <linux/bitfield.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/kernel.h>
@@ -185,23 +186,20 @@ static void update_range(struct ocmem *ocmem, struct ocmem_buf *buf,
struct ocmem *of_get_ocmem(struct device *dev)
{
struct platform_device *pdev;
- struct device_node *devnode;
struct ocmem *ocmem;
- devnode = of_parse_phandle(dev->of_node, "sram", 0);
+ struct device_node *devnode __free(device_node) = of_parse_phandle(dev->of_node,
+ "sram", 0);
if (!devnode || !devnode->parent) {
dev_err(dev, "Cannot look up sram phandle\n");
- of_node_put(devnode);
return ERR_PTR(-ENODEV);
}
pdev = of_find_device_by_node(devnode->parent);
if (!pdev) {
dev_err(dev, "Cannot find device node %s\n", devnode->name);
- of_node_put(devnode);
return ERR_PTR(-EPROBE_DEFER);
}
- of_node_put(devnode);
ocmem = platform_get_drvdata(pdev);
if (!ocmem) {
@@ -216,7 +214,6 @@ EXPORT_SYMBOL_GPL(of_get_ocmem);
struct ocmem_buf *ocmem_allocate(struct ocmem *ocmem, enum ocmem_client client,
unsigned long size)
{
- struct ocmem_buf *buf;
int ret;
/* TODO: add support for other clients... */
@@ -229,7 +226,7 @@ struct ocmem_buf *ocmem_allocate(struct ocmem *ocmem, enum ocmem_client client,
if (test_and_set_bit_lock(BIT(client), &ocmem->active_allocations))
return ERR_PTR(-EBUSY);
- buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+ struct ocmem_buf *buf __free(kfree) = kzalloc(sizeof(*buf), GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
goto err_unlock;
@@ -247,7 +244,7 @@ struct ocmem_buf *ocmem_allocate(struct ocmem *ocmem, enum ocmem_client client,
if (ret) {
dev_err(ocmem->dev, "could not lock: %d\n", ret);
ret = -EINVAL;
- goto err_kfree;
+ goto err_unlock;
}
} else {
ocmem_write(ocmem, OCMEM_REG_GFX_MPU_START, buf->offset);
@@ -258,10 +255,8 @@ struct ocmem_buf *ocmem_allocate(struct ocmem *ocmem, enum ocmem_client client,
dev_dbg(ocmem->dev, "using %ldK of OCMEM at 0x%08lx for client %d\n",
size / 1024, buf->addr, client);
- return buf;
+ return_ptr(buf);
-err_kfree:
- kfree(buf);
err_unlock:
clear_bit_unlock(BIT(client), &ocmem->active_allocations);
@@ -444,7 +439,7 @@ MODULE_DEVICE_TABLE(of, ocmem_of_match);
static struct platform_driver ocmem_driver = {
.probe = ocmem_dev_probe,
- .remove_new = ocmem_dev_remove,
+ .remove = ocmem_dev_remove,
.driver = {
.name = "ocmem",
.of_match_table = ocmem_of_match,
diff --git a/drivers/soc/qcom/pdr_interface.c b/drivers/soc/qcom/pdr_interface.c
index a1b6a4081dea..71be378d2e43 100644
--- a/drivers/soc/qcom/pdr_interface.c
+++ b/drivers/soc/qcom/pdr_interface.c
@@ -3,6 +3,7 @@
* Copyright (C) 2020 The Linux Foundation. All rights reserved.
*/
+#include <linux/cleanup.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -74,24 +75,18 @@ static int pdr_locator_new_server(struct qmi_handle *qmi,
{
struct pdr_handle *pdr = container_of(qmi, struct pdr_handle,
locator_hdl);
- struct pdr_service *pds;
+ mutex_lock(&pdr->lock);
/* Create a local client port for QMI communication */
pdr->locator_addr.sq_family = AF_QIPCRTR;
pdr->locator_addr.sq_node = svc->node;
pdr->locator_addr.sq_port = svc->port;
- mutex_lock(&pdr->lock);
pdr->locator_init_complete = true;
mutex_unlock(&pdr->lock);
/* Service pending lookup requests */
- mutex_lock(&pdr->list_lock);
- list_for_each_entry(pds, &pdr->lookups, node) {
- if (pds->need_locator_lookup)
- schedule_work(&pdr->locator_work);
- }
- mutex_unlock(&pdr->list_lock);
+ schedule_work(&pdr->locator_work);
return 0;
}
@@ -104,10 +99,10 @@ static void pdr_locator_del_server(struct qmi_handle *qmi,
mutex_lock(&pdr->lock);
pdr->locator_init_complete = false;
- mutex_unlock(&pdr->lock);
pdr->locator_addr.sq_node = 0;
pdr->locator_addr.sq_port = 0;
+ mutex_unlock(&pdr->lock);
}
static const struct qmi_ops pdr_locator_ops = {
@@ -365,12 +360,14 @@ static int pdr_get_domain_list(struct servreg_get_domain_list_req *req,
if (ret < 0)
return ret;
+ mutex_lock(&pdr->lock);
ret = qmi_send_request(&pdr->locator_hdl,
&pdr->locator_addr,
&txn, SERVREG_GET_DOMAIN_LIST_REQ,
SERVREG_GET_DOMAIN_LIST_REQ_MAX_LEN,
servreg_get_domain_list_req_ei,
req);
+ mutex_unlock(&pdr->lock);
if (ret < 0) {
qmi_txn_cancel(&txn);
return ret;
@@ -394,13 +391,13 @@ static int pdr_get_domain_list(struct servreg_get_domain_list_req *req,
static int pdr_locate_service(struct pdr_handle *pdr, struct pdr_service *pds)
{
- struct servreg_get_domain_list_resp *resp;
struct servreg_get_domain_list_req req;
struct servreg_location_entry *entry;
int domains_read = 0;
int ret, i;
- resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+ struct servreg_get_domain_list_resp *resp __free(kfree) = kzalloc(sizeof(*resp),
+ GFP_KERNEL);
if (!resp)
return -ENOMEM;
@@ -413,9 +410,9 @@ static int pdr_locate_service(struct pdr_handle *pdr, struct pdr_service *pds)
req.domain_offset = domains_read;
ret = pdr_get_domain_list(&req, resp, pdr);
if (ret < 0)
- goto out;
+ return ret;
- for (i = domains_read; i < resp->domain_list_len; i++) {
+ for (i = 0; i < resp->domain_list_len; i++) {
entry = &resp->domain_list[i];
if (strnlen(entry->name, sizeof(entry->name)) == sizeof(entry->name))
@@ -425,7 +422,7 @@ static int pdr_locate_service(struct pdr_handle *pdr, struct pdr_service *pds)
pds->service_data_valid = entry->service_data_valid;
pds->service_data = entry->service_data;
pds->instance = entry->instance;
- goto out;
+ return 0;
}
}
@@ -438,8 +435,7 @@ static int pdr_locate_service(struct pdr_handle *pdr, struct pdr_service *pds)
domains_read += resp->domain_list_len;
} while (domains_read < resp->total_domains);
-out:
- kfree(resp);
+
return ret;
}
@@ -515,8 +511,7 @@ struct pdr_service *pdr_add_lookup(struct pdr_handle *pdr,
const char *service_name,
const char *service_path)
{
- struct pdr_service *pds, *tmp;
- int ret;
+ struct pdr_service *tmp;
if (IS_ERR_OR_NULL(pdr))
return ERR_PTR(-EINVAL);
@@ -525,7 +520,7 @@ struct pdr_service *pdr_add_lookup(struct pdr_handle *pdr,
!service_path || strlen(service_path) > SERVREG_NAME_LENGTH)
return ERR_PTR(-EINVAL);
- pds = kzalloc(sizeof(*pds), GFP_KERNEL);
+ struct pdr_service *pds __free(kfree) = kzalloc(sizeof(*pds), GFP_KERNEL);
if (!pds)
return ERR_PTR(-ENOMEM);
@@ -540,8 +535,7 @@ struct pdr_service *pdr_add_lookup(struct pdr_handle *pdr,
continue;
mutex_unlock(&pdr->list_lock);
- ret = -EALREADY;
- goto err;
+ return ERR_PTR(-EALREADY);
}
list_add(&pds->node, &pdr->lookups);
@@ -549,10 +543,7 @@ struct pdr_service *pdr_add_lookup(struct pdr_handle *pdr,
schedule_work(&pdr->locator_work);
- return pds;
-err:
- kfree(pds);
- return ERR_PTR(ret);
+ return_ptr(pds);
}
EXPORT_SYMBOL_GPL(pdr_add_lookup);
@@ -649,13 +640,12 @@ struct pdr_handle *pdr_handle_alloc(void (*status)(int state,
char *service_path,
void *priv), void *priv)
{
- struct pdr_handle *pdr;
int ret;
if (!status)
return ERR_PTR(-EINVAL);
- pdr = kzalloc(sizeof(*pdr), GFP_KERNEL);
+ struct pdr_handle *pdr __free(kfree) = kzalloc(sizeof(*pdr), GFP_KERNEL);
if (!pdr)
return ERR_PTR(-ENOMEM);
@@ -674,10 +664,8 @@ struct pdr_handle *pdr_handle_alloc(void (*status)(int state,
INIT_WORK(&pdr->indack_work, pdr_indack_work);
pdr->notifier_wq = create_singlethread_workqueue("pdr_notifier_wq");
- if (!pdr->notifier_wq) {
- ret = -ENOMEM;
- goto free_pdr_handle;
- }
+ if (!pdr->notifier_wq)
+ return ERR_PTR(-ENOMEM);
pdr->indack_wq = alloc_ordered_workqueue("pdr_indack_wq", WQ_HIGHPRI);
if (!pdr->indack_wq) {
@@ -702,7 +690,7 @@ struct pdr_handle *pdr_handle_alloc(void (*status)(int state,
if (ret < 0)
goto release_qmi_handle;
- return pdr;
+ return_ptr(pdr);
release_qmi_handle:
qmi_handle_release(&pdr->locator_hdl);
@@ -710,8 +698,6 @@ destroy_indack:
destroy_workqueue(pdr->indack_wq);
destroy_notifier:
destroy_workqueue(pdr->notifier_wq);
-free_pdr_handle:
- kfree(pdr);
return ERR_PTR(ret);
}
diff --git a/drivers/soc/qcom/pdr_internal.h b/drivers/soc/qcom/pdr_internal.h
index 03c282b7f17e..8d17f7fb79e7 100644
--- a/drivers/soc/qcom/pdr_internal.h
+++ b/drivers/soc/qcom/pdr_internal.h
@@ -13,6 +13,8 @@
#define SERVREG_SET_ACK_REQ 0x23
#define SERVREG_RESTART_PD_REQ 0x24
+#define SERVREG_LOC_PFR_REQ 0x24
+
#define SERVREG_DOMAIN_LIST_LENGTH 32
#define SERVREG_RESTART_PD_REQ_MAX_LEN 67
#define SERVREG_REGISTER_LISTENER_REQ_LEN 71
@@ -20,6 +22,7 @@
#define SERVREG_GET_DOMAIN_LIST_REQ_MAX_LEN 74
#define SERVREG_STATE_UPDATED_IND_MAX_LEN 79
#define SERVREG_GET_DOMAIN_LIST_RESP_MAX_LEN 2389
+#define SERVREG_LOC_PFR_RESP_MAX_LEN 10
struct servreg_location_entry {
char name[SERVREG_NAME_LENGTH + 1];
@@ -28,83 +31,12 @@ struct servreg_location_entry {
u32 instance;
};
-static const struct qmi_elem_info servreg_location_entry_ei[] = {
- {
- .data_type = QMI_STRING,
- .elem_len = SERVREG_NAME_LENGTH + 1,
- .elem_size = sizeof(char),
- .array_type = NO_ARRAY,
- .tlv_type = 0,
- .offset = offsetof(struct servreg_location_entry,
- name),
- },
- {
- .data_type = QMI_UNSIGNED_4_BYTE,
- .elem_len = 1,
- .elem_size = sizeof(u32),
- .array_type = NO_ARRAY,
- .tlv_type = 0,
- .offset = offsetof(struct servreg_location_entry,
- instance),
- },
- {
- .data_type = QMI_UNSIGNED_1_BYTE,
- .elem_len = 1,
- .elem_size = sizeof(u8),
- .array_type = NO_ARRAY,
- .tlv_type = 0,
- .offset = offsetof(struct servreg_location_entry,
- service_data_valid),
- },
- {
- .data_type = QMI_UNSIGNED_4_BYTE,
- .elem_len = 1,
- .elem_size = sizeof(u32),
- .array_type = NO_ARRAY,
- .tlv_type = 0,
- .offset = offsetof(struct servreg_location_entry,
- service_data),
- },
- {}
-};
-
struct servreg_get_domain_list_req {
char service_name[SERVREG_NAME_LENGTH + 1];
u8 domain_offset_valid;
u32 domain_offset;
};
-static const struct qmi_elem_info servreg_get_domain_list_req_ei[] = {
- {
- .data_type = QMI_STRING,
- .elem_len = SERVREG_NAME_LENGTH + 1,
- .elem_size = sizeof(char),
- .array_type = NO_ARRAY,
- .tlv_type = 0x01,
- .offset = offsetof(struct servreg_get_domain_list_req,
- service_name),
- },
- {
- .data_type = QMI_OPT_FLAG,
- .elem_len = 1,
- .elem_size = sizeof(u8),
- .array_type = NO_ARRAY,
- .tlv_type = 0x10,
- .offset = offsetof(struct servreg_get_domain_list_req,
- domain_offset_valid),
- },
- {
- .data_type = QMI_UNSIGNED_4_BYTE,
- .elem_len = 1,
- .elem_size = sizeof(u32),
- .array_type = NO_ARRAY,
- .tlv_type = 0x10,
- .offset = offsetof(struct servreg_get_domain_list_req,
- domain_offset),
- },
- {}
-};
-
struct servreg_get_domain_list_resp {
struct qmi_response_type_v01 resp;
u8 total_domains_valid;
@@ -116,264 +48,60 @@ struct servreg_get_domain_list_resp {
struct servreg_location_entry domain_list[SERVREG_DOMAIN_LIST_LENGTH];
};
-static const struct qmi_elem_info servreg_get_domain_list_resp_ei[] = {
- {
- .data_type = QMI_STRUCT,
- .elem_len = 1,
- .elem_size = sizeof(struct qmi_response_type_v01),
- .array_type = NO_ARRAY,
- .tlv_type = 0x02,
- .offset = offsetof(struct servreg_get_domain_list_resp,
- resp),
- .ei_array = qmi_response_type_v01_ei,
- },
- {
- .data_type = QMI_OPT_FLAG,
- .elem_len = 1,
- .elem_size = sizeof(u8),
- .array_type = NO_ARRAY,
- .tlv_type = 0x10,
- .offset = offsetof(struct servreg_get_domain_list_resp,
- total_domains_valid),
- },
- {
- .data_type = QMI_UNSIGNED_2_BYTE,
- .elem_len = 1,
- .elem_size = sizeof(u16),
- .array_type = NO_ARRAY,
- .tlv_type = 0x10,
- .offset = offsetof(struct servreg_get_domain_list_resp,
- total_domains),
- },
- {
- .data_type = QMI_OPT_FLAG,
- .elem_len = 1,
- .elem_size = sizeof(u8),
- .array_type = NO_ARRAY,
- .tlv_type = 0x11,
- .offset = offsetof(struct servreg_get_domain_list_resp,
- db_rev_count_valid),
- },
- {
- .data_type = QMI_UNSIGNED_2_BYTE,
- .elem_len = 1,
- .elem_size = sizeof(u16),
- .array_type = NO_ARRAY,
- .tlv_type = 0x11,
- .offset = offsetof(struct servreg_get_domain_list_resp,
- db_rev_count),
- },
- {
- .data_type = QMI_OPT_FLAG,
- .elem_len = 1,
- .elem_size = sizeof(u8),
- .array_type = NO_ARRAY,
- .tlv_type = 0x12,
- .offset = offsetof(struct servreg_get_domain_list_resp,
- domain_list_valid),
- },
- {
- .data_type = QMI_DATA_LEN,
- .elem_len = 1,
- .elem_size = sizeof(u8),
- .array_type = NO_ARRAY,
- .tlv_type = 0x12,
- .offset = offsetof(struct servreg_get_domain_list_resp,
- domain_list_len),
- },
- {
- .data_type = QMI_STRUCT,
- .elem_len = SERVREG_DOMAIN_LIST_LENGTH,
- .elem_size = sizeof(struct servreg_location_entry),
- .array_type = VAR_LEN_ARRAY,
- .tlv_type = 0x12,
- .offset = offsetof(struct servreg_get_domain_list_resp,
- domain_list),
- .ei_array = servreg_location_entry_ei,
- },
- {}
-};
-
struct servreg_register_listener_req {
u8 enable;
char service_path[SERVREG_NAME_LENGTH + 1];
};
-static const struct qmi_elem_info servreg_register_listener_req_ei[] = {
- {
- .data_type = QMI_UNSIGNED_1_BYTE,
- .elem_len = 1,
- .elem_size = sizeof(u8),
- .array_type = NO_ARRAY,
- .tlv_type = 0x01,
- .offset = offsetof(struct servreg_register_listener_req,
- enable),
- },
- {
- .data_type = QMI_STRING,
- .elem_len = SERVREG_NAME_LENGTH + 1,
- .elem_size = sizeof(char),
- .array_type = NO_ARRAY,
- .tlv_type = 0x02,
- .offset = offsetof(struct servreg_register_listener_req,
- service_path),
- },
- {}
-};
-
struct servreg_register_listener_resp {
struct qmi_response_type_v01 resp;
u8 curr_state_valid;
enum servreg_service_state curr_state;
};
-static const struct qmi_elem_info servreg_register_listener_resp_ei[] = {
- {
- .data_type = QMI_STRUCT,
- .elem_len = 1,
- .elem_size = sizeof(struct qmi_response_type_v01),
- .array_type = NO_ARRAY,
- .tlv_type = 0x02,
- .offset = offsetof(struct servreg_register_listener_resp,
- resp),
- .ei_array = qmi_response_type_v01_ei,
- },
- {
- .data_type = QMI_OPT_FLAG,
- .elem_len = 1,
- .elem_size = sizeof(u8),
- .array_type = NO_ARRAY,
- .tlv_type = 0x10,
- .offset = offsetof(struct servreg_register_listener_resp,
- curr_state_valid),
- },
- {
- .data_type = QMI_SIGNED_4_BYTE_ENUM,
- .elem_len = 1,
- .elem_size = sizeof(enum servreg_service_state),
- .array_type = NO_ARRAY,
- .tlv_type = 0x10,
- .offset = offsetof(struct servreg_register_listener_resp,
- curr_state),
- },
- {}
-};
-
struct servreg_restart_pd_req {
char service_path[SERVREG_NAME_LENGTH + 1];
};
-static const struct qmi_elem_info servreg_restart_pd_req_ei[] = {
- {
- .data_type = QMI_STRING,
- .elem_len = SERVREG_NAME_LENGTH + 1,
- .elem_size = sizeof(char),
- .array_type = NO_ARRAY,
- .tlv_type = 0x01,
- .offset = offsetof(struct servreg_restart_pd_req,
- service_path),
- },
- {}
-};
-
struct servreg_restart_pd_resp {
struct qmi_response_type_v01 resp;
};
-static const struct qmi_elem_info servreg_restart_pd_resp_ei[] = {
- {
- .data_type = QMI_STRUCT,
- .elem_len = 1,
- .elem_size = sizeof(struct qmi_response_type_v01),
- .array_type = NO_ARRAY,
- .tlv_type = 0x02,
- .offset = offsetof(struct servreg_restart_pd_resp,
- resp),
- .ei_array = qmi_response_type_v01_ei,
- },
- {}
-};
-
struct servreg_state_updated_ind {
enum servreg_service_state curr_state;
char service_path[SERVREG_NAME_LENGTH + 1];
u16 transaction_id;
};
-static const struct qmi_elem_info servreg_state_updated_ind_ei[] = {
- {
- .data_type = QMI_SIGNED_4_BYTE_ENUM,
- .elem_len = 1,
- .elem_size = sizeof(u32),
- .array_type = NO_ARRAY,
- .tlv_type = 0x01,
- .offset = offsetof(struct servreg_state_updated_ind,
- curr_state),
- },
- {
- .data_type = QMI_STRING,
- .elem_len = SERVREG_NAME_LENGTH + 1,
- .elem_size = sizeof(char),
- .array_type = NO_ARRAY,
- .tlv_type = 0x02,
- .offset = offsetof(struct servreg_state_updated_ind,
- service_path),
- },
- {
- .data_type = QMI_UNSIGNED_2_BYTE,
- .elem_len = 1,
- .elem_size = sizeof(u16),
- .array_type = NO_ARRAY,
- .tlv_type = 0x03,
- .offset = offsetof(struct servreg_state_updated_ind,
- transaction_id),
- },
- {}
-};
-
struct servreg_set_ack_req {
char service_path[SERVREG_NAME_LENGTH + 1];
u16 transaction_id;
};
-static const struct qmi_elem_info servreg_set_ack_req_ei[] = {
- {
- .data_type = QMI_STRING,
- .elem_len = SERVREG_NAME_LENGTH + 1,
- .elem_size = sizeof(char),
- .array_type = NO_ARRAY,
- .tlv_type = 0x01,
- .offset = offsetof(struct servreg_set_ack_req,
- service_path),
- },
- {
- .data_type = QMI_UNSIGNED_2_BYTE,
- .elem_len = 1,
- .elem_size = sizeof(u16),
- .array_type = NO_ARRAY,
- .tlv_type = 0x02,
- .offset = offsetof(struct servreg_set_ack_req,
- transaction_id),
- },
- {}
-};
-
struct servreg_set_ack_resp {
struct qmi_response_type_v01 resp;
};
-static const struct qmi_elem_info servreg_set_ack_resp_ei[] = {
- {
- .data_type = QMI_STRUCT,
- .elem_len = 1,
- .elem_size = sizeof(struct qmi_response_type_v01),
- .array_type = NO_ARRAY,
- .tlv_type = 0x02,
- .offset = offsetof(struct servreg_set_ack_resp,
- resp),
- .ei_array = qmi_response_type_v01_ei,
- },
- {}
+struct servreg_loc_pfr_req {
+ char service[SERVREG_NAME_LENGTH + 1];
+ char reason[257];
};
+struct servreg_loc_pfr_resp {
+ struct qmi_response_type_v01 rsp;
+};
+
+extern const struct qmi_elem_info servreg_location_entry_ei[];
+extern const struct qmi_elem_info servreg_get_domain_list_req_ei[];
+extern const struct qmi_elem_info servreg_get_domain_list_resp_ei[];
+extern const struct qmi_elem_info servreg_register_listener_req_ei[];
+extern const struct qmi_elem_info servreg_register_listener_resp_ei[];
+extern const struct qmi_elem_info servreg_restart_pd_req_ei[];
+extern const struct qmi_elem_info servreg_restart_pd_resp_ei[];
+extern const struct qmi_elem_info servreg_state_updated_ind_ei[];
+extern const struct qmi_elem_info servreg_set_ack_req_ei[];
+extern const struct qmi_elem_info servreg_set_ack_resp_ei[];
+extern const struct qmi_elem_info servreg_loc_pfr_req_ei[];
+extern const struct qmi_elem_info servreg_loc_pfr_resp_ei[];
+
#endif
diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c
index f913e9bd57ed..cde19cdfd3c7 100644
--- a/drivers/soc/qcom/pmic_glink.c
+++ b/drivers/soc/qcom/pmic_glink.c
@@ -4,6 +4,8 @@
* Copyright (c) 2022, Linaro Ltd
*/
#include <linux/auxiliary_bus.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -11,6 +13,9 @@
#include <linux/slab.h>
#include <linux/soc/qcom/pdr.h>
#include <linux/soc/qcom/pmic_glink.h>
+#include <linux/spinlock.h>
+
+#define PMIC_GLINK_SEND_TIMEOUT (5 * HZ)
enum {
PMIC_GLINK_CLIENT_BATT = 0,
@@ -36,7 +41,7 @@ struct pmic_glink {
unsigned int pdr_state;
/* serializing clients list updates */
- struct mutex client_lock;
+ spinlock_t client_lock;
struct list_head clients;
};
@@ -58,17 +63,18 @@ static void _devm_pmic_glink_release_client(struct device *dev, void *res)
{
struct pmic_glink_client *client = (struct pmic_glink_client *)res;
struct pmic_glink *pg = client->pg;
+ unsigned long flags;
- mutex_lock(&pg->client_lock);
+ spin_lock_irqsave(&pg->client_lock, flags);
list_del(&client->node);
- mutex_unlock(&pg->client_lock);
+ spin_unlock_irqrestore(&pg->client_lock, flags);
}
-struct pmic_glink_client *devm_pmic_glink_register_client(struct device *dev,
- unsigned int id,
- void (*cb)(const void *, size_t, void *),
- void (*pdr)(void *, int),
- void *priv)
+struct pmic_glink_client *devm_pmic_glink_client_alloc(struct device *dev,
+ unsigned int id,
+ void (*cb)(const void *, size_t, void *),
+ void (*pdr)(void *, int),
+ void *priv)
{
struct pmic_glink_client *client;
struct pmic_glink *pg = dev_get_drvdata(dev->parent);
@@ -82,22 +88,57 @@ struct pmic_glink_client *devm_pmic_glink_register_client(struct device *dev,
client->cb = cb;
client->pdr_notify = pdr;
client->priv = priv;
-
- mutex_lock(&pg->client_lock);
- list_add(&client->node, &pg->clients);
- mutex_unlock(&pg->client_lock);
+ INIT_LIST_HEAD(&client->node);
devres_add(dev, client);
return client;
}
-EXPORT_SYMBOL_GPL(devm_pmic_glink_register_client);
+EXPORT_SYMBOL_GPL(devm_pmic_glink_client_alloc);
+
+void pmic_glink_client_register(struct pmic_glink_client *client)
+{
+ struct pmic_glink *pg = client->pg;
+ unsigned long flags;
+
+ guard(mutex)(&pg->state_lock);
+ spin_lock_irqsave(&pg->client_lock, flags);
+
+ list_add(&client->node, &pg->clients);
+ client->pdr_notify(client->priv, pg->client_state);
+
+ spin_unlock_irqrestore(&pg->client_lock, flags);
+}
+EXPORT_SYMBOL_GPL(pmic_glink_client_register);
int pmic_glink_send(struct pmic_glink_client *client, void *data, size_t len)
{
struct pmic_glink *pg = client->pg;
+ bool timeout_reached = false;
+ unsigned long start;
+ int ret;
+
+ guard(mutex)(&pg->state_lock);
+ if (!pg->ept) {
+ return -ECONNRESET;
+ }
+
+ start = jiffies;
+ for (;;) {
+ ret = rpmsg_send(pg->ept, data, len);
+ if (ret != -EAGAIN)
+ break;
- return rpmsg_send(pg->ept, data, len);
+ if (timeout_reached) {
+ ret = -ETIMEDOUT;
+ break;
+ }
+
+ usleep_range(1000, 5000);
+ timeout_reached = time_after(jiffies, start + PMIC_GLINK_SEND_TIMEOUT);
+ }
+
+ return ret;
}
EXPORT_SYMBOL_GPL(pmic_glink_send);
@@ -107,6 +148,7 @@ static int pmic_glink_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
struct pmic_glink_client *client;
struct pmic_glink_hdr *hdr;
struct pmic_glink *pg = dev_get_drvdata(&rpdev->dev);
+ unsigned long flags;
if (len < sizeof(*hdr)) {
dev_warn(pg->dev, "ignoring truncated message\n");
@@ -115,10 +157,12 @@ static int pmic_glink_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
hdr = data;
+ spin_lock_irqsave(&pg->client_lock, flags);
list_for_each_entry(client, &pg->clients, node) {
if (client->id == le32_to_cpu(hdr->owner))
client->cb(data, len, client->priv);
}
+ spin_unlock_irqrestore(&pg->client_lock, flags);
return 0;
}
@@ -158,18 +202,21 @@ static void pmic_glink_state_notify_clients(struct pmic_glink *pg)
{
struct pmic_glink_client *client;
unsigned int new_state = pg->client_state;
+ unsigned long flags;
if (pg->client_state != SERVREG_SERVICE_STATE_UP) {
if (pg->pdr_state == SERVREG_SERVICE_STATE_UP && pg->ept)
new_state = SERVREG_SERVICE_STATE_UP;
} else {
- if (pg->pdr_state == SERVREG_SERVICE_STATE_UP && pg->ept)
+ if (pg->pdr_state == SERVREG_SERVICE_STATE_DOWN || !pg->ept)
new_state = SERVREG_SERVICE_STATE_DOWN;
}
if (new_state != pg->client_state) {
+ spin_lock_irqsave(&pg->client_lock, flags);
list_for_each_entry(client, &pg->clients, node)
client->pdr_notify(client->priv, new_state);
+ spin_unlock_irqrestore(&pg->client_lock, flags);
pg->client_state = new_state;
}
}
@@ -178,51 +225,42 @@ static void pmic_glink_pdr_callback(int state, char *svc_path, void *priv)
{
struct pmic_glink *pg = priv;
- mutex_lock(&pg->state_lock);
+ guard(mutex)(&pg->state_lock);
pg->pdr_state = state;
pmic_glink_state_notify_clients(pg);
- mutex_unlock(&pg->state_lock);
}
static int pmic_glink_rpmsg_probe(struct rpmsg_device *rpdev)
{
- struct pmic_glink *pg = __pmic_glink;
- int ret = 0;
+ struct pmic_glink *pg;
- mutex_lock(&__pmic_glink_lock);
- if (!pg) {
- ret = dev_err_probe(&rpdev->dev, -ENODEV, "no pmic_glink device to attach to\n");
- goto out_unlock;
- }
+ guard(mutex)(&__pmic_glink_lock);
+ pg = __pmic_glink;
+ if (!pg)
+ return dev_err_probe(&rpdev->dev, -ENODEV, "no pmic_glink device to attach to\n");
dev_set_drvdata(&rpdev->dev, pg);
- mutex_lock(&pg->state_lock);
+ guard(mutex)(&pg->state_lock);
pg->ept = rpdev->ept;
pmic_glink_state_notify_clients(pg);
- mutex_unlock(&pg->state_lock);
-out_unlock:
- mutex_unlock(&__pmic_glink_lock);
- return ret;
+ return 0;
}
static void pmic_glink_rpmsg_remove(struct rpmsg_device *rpdev)
{
struct pmic_glink *pg;
- mutex_lock(&__pmic_glink_lock);
+ guard(mutex)(&__pmic_glink_lock);
pg = __pmic_glink;
if (!pg)
- goto out_unlock;
+ return;
- mutex_lock(&pg->state_lock);
+ guard(mutex)(&pg->state_lock);
pg->ept = NULL;
pmic_glink_state_notify_clients(pg);
- mutex_unlock(&pg->state_lock);
-out_unlock:
- mutex_unlock(&__pmic_glink_lock);
}
static const struct rpmsg_device_id pmic_glink_rpmsg_id_match[] = {
@@ -256,7 +294,7 @@ static int pmic_glink_probe(struct platform_device *pdev)
pg->dev = &pdev->dev;
INIT_LIST_HEAD(&pg->clients);
- mutex_init(&pg->client_lock);
+ spin_lock_init(&pg->client_lock);
mutex_init(&pg->state_lock);
match_data = (unsigned long *)of_device_get_match_data(&pdev->dev);
@@ -329,21 +367,19 @@ static void pmic_glink_remove(struct platform_device *pdev)
if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI))
pmic_glink_del_aux_device(pg, &pg->ucsi_aux);
- mutex_lock(&__pmic_glink_lock);
+ guard(mutex)(&__pmic_glink_lock);
__pmic_glink = NULL;
- mutex_unlock(&__pmic_glink_lock);
}
-static const unsigned long pmic_glink_sc8180x_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) |
- BIT(PMIC_GLINK_CLIENT_ALTMODE);
+static const unsigned long pmic_glink_sc8280xp_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) |
+ BIT(PMIC_GLINK_CLIENT_ALTMODE);
static const unsigned long pmic_glink_sm8450_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) |
BIT(PMIC_GLINK_CLIENT_ALTMODE) |
BIT(PMIC_GLINK_CLIENT_UCSI);
static const struct of_device_id pmic_glink_of_match[] = {
- { .compatible = "qcom,sc8180x-pmic-glink", .data = &pmic_glink_sc8180x_client_mask },
- { .compatible = "qcom,sc8280xp-pmic-glink", .data = &pmic_glink_sc8180x_client_mask },
+ { .compatible = "qcom,sc8280xp-pmic-glink", .data = &pmic_glink_sc8280xp_client_mask },
{ .compatible = "qcom,pmic-glink", .data = &pmic_glink_sm8450_client_mask },
{}
};
@@ -351,7 +387,7 @@ MODULE_DEVICE_TABLE(of, pmic_glink_of_match);
static struct platform_driver pmic_glink_driver = {
.probe = pmic_glink_probe,
- .remove_new = pmic_glink_remove,
+ .remove = pmic_glink_remove,
.driver = {
.name = "qcom_pmic_glink",
.of_match_table = pmic_glink_of_match,
@@ -360,8 +396,17 @@ static struct platform_driver pmic_glink_driver = {
static int pmic_glink_init(void)
{
- platform_driver_register(&pmic_glink_driver);
- register_rpmsg_driver(&pmic_glink_rpmsg_driver);
+ int ret;
+
+ ret = platform_driver_register(&pmic_glink_driver);
+ if (ret < 0)
+ return ret;
+
+ ret = register_rpmsg_driver(&pmic_glink_rpmsg_driver);
+ if (ret < 0) {
+ platform_driver_unregister(&pmic_glink_driver);
+ return ret;
+ }
return 0;
}
diff --git a/drivers/soc/qcom/pmic_glink_altmode.c b/drivers/soc/qcom/pmic_glink_altmode.c
index b3808fc24c69..bd06ce161804 100644
--- a/drivers/soc/qcom/pmic_glink_altmode.c
+++ b/drivers/soc/qcom/pmic_glink_altmode.c
@@ -5,6 +5,7 @@
*/
#include <linux/auxiliary_bus.h>
#include <linux/bitfield.h>
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -20,7 +21,7 @@
#include <linux/soc/qcom/pmic_glink.h>
-#define PMIC_GLINK_MAX_PORTS 2
+#define PMIC_GLINK_MAX_PORTS 3
#define USBC_SC8180X_NOTIFY_IND 0x13
#define USBC_CMD_WRITE_REQ 0x15
@@ -114,7 +115,7 @@ static int pmic_glink_altmode_request(struct pmic_glink_altmode *altmode, u32 cm
* The USBC_CMD_WRITE_REQ ack doesn't identify the request, so wait for
* one ack at a time.
*/
- mutex_lock(&altmode->lock);
+ guard(mutex)(&altmode->lock);
req.hdr.owner = cpu_to_le32(altmode->owner_id);
req.hdr.type = cpu_to_le32(PMIC_GLINK_REQ_RESP);
@@ -125,18 +126,16 @@ static int pmic_glink_altmode_request(struct pmic_glink_altmode *altmode, u32 cm
ret = pmic_glink_send(altmode->client, &req, sizeof(req));
if (ret) {
dev_err(altmode->dev, "failed to send altmode request: %#x (%d)\n", cmd, ret);
- goto out_unlock;
+ return ret;
}
left = wait_for_completion_timeout(&altmode->pan_ack, 5 * HZ);
if (!left) {
dev_err(altmode->dev, "timeout waiting for altmode request ack for: %#x\n", cmd);
- ret = -ETIMEDOUT;
+ return -ETIMEDOUT;
}
-out_unlock:
- mutex_unlock(&altmode->lock);
- return ret;
+ return 0;
}
static void pmic_glink_altmode_enable_dp(struct pmic_glink_altmode *altmode,
@@ -520,12 +519,17 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev,
return ret;
}
- altmode->client = devm_pmic_glink_register_client(dev,
- altmode->owner_id,
- pmic_glink_altmode_callback,
- pmic_glink_altmode_pdr_notify,
- altmode);
- return PTR_ERR_OR_ZERO(altmode->client);
+ altmode->client = devm_pmic_glink_client_alloc(dev,
+ altmode->owner_id,
+ pmic_glink_altmode_callback,
+ pmic_glink_altmode_pdr_notify,
+ altmode);
+ if (IS_ERR(altmode->client))
+ return PTR_ERR(altmode->client);
+
+ pmic_glink_client_register(altmode->client);
+
+ return 0;
}
static const struct auxiliary_device_id pmic_glink_altmode_id_table[] = {
diff --git a/drivers/soc/qcom/pmic_pdcharger_ulog.c b/drivers/soc/qcom/pmic_pdcharger_ulog.c
index 238cd38589dc..39f412bbf2c1 100644
--- a/drivers/soc/qcom/pmic_pdcharger_ulog.c
+++ b/drivers/soc/qcom/pmic_pdcharger_ulog.c
@@ -150,6 +150,10 @@ static const struct rpmsg_device_id pmic_pdcharger_ulog_rpmsg_id_match[] = {
{ "PMIC_LOGS_ADSP_APPS" },
{}
};
+/*
+ * No MODULE_DEVICE_TABLE intentionally: that's a debugging module, to be
+ * loaded manually only.
+ */
static struct rpmsg_driver pmic_pdcharger_ulog_rpmsg_driver = {
.probe = pmic_pdcharger_ulog_rpmsg_probe,
diff --git a/drivers/soc/qcom/pmic_pdcharger_ulog.h b/drivers/soc/qcom/pmic_pdcharger_ulog.h
index 152e3a6b5480..1cfa58f0e34c 100644
--- a/drivers/soc/qcom/pmic_pdcharger_ulog.h
+++ b/drivers/soc/qcom/pmic_pdcharger_ulog.h
@@ -18,7 +18,7 @@ TRACE_EVENT(pmic_pdcharger_ulog_msg,
__string(msg, msg)
),
TP_fast_assign(
- __assign_str(msg, msg);
+ __assign_str(msg);
),
TP_printk("%s", __get_str(msg))
);
diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c
index bdcf44b85b2f..4cb959106efa 100644
--- a/drivers/soc/qcom/qcom-geni-se.c
+++ b/drivers/soc/qcom/qcom-geni-se.c
@@ -89,7 +89,6 @@
* @base: Base address of this instance of QUP wrapper core
* @clks: Handle to the primary & optional secondary AHB clocks
* @num_clks: Count of clocks
- * @to_core: Core ICC path
*/
struct geni_wrapper {
struct device *dev;
@@ -586,7 +585,8 @@ int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl)
for (i = 0; i < MAX_CLK_PERF_LEVEL; i++) {
freq = clk_round_rate(se->clk, freq + 1);
- if (freq <= 0 || freq == se->clk_perf_tbl[i - 1])
+ if (freq <= 0 ||
+ (i > 0 && freq == se->clk_perf_tbl[i - 1]))
break;
se->clk_perf_tbl[i] = freq;
}
diff --git a/drivers/soc/qcom/qcom-pbs.c b/drivers/soc/qcom/qcom-pbs.c
new file mode 100644
index 000000000000..1cc5d045f9dd
--- /dev/null
+++ b/drivers/soc/qcom/qcom-pbs.c
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/spmi.h>
+#include <linux/soc/qcom/qcom-pbs.h>
+
+#define PBS_CLIENT_TRIG_CTL 0x42
+#define PBS_CLIENT_SW_TRIG_BIT BIT(7)
+#define PBS_CLIENT_SCRATCH1 0x50
+#define PBS_CLIENT_SCRATCH2 0x51
+#define PBS_CLIENT_SCRATCH2_ERROR 0xFF
+
+#define RETRIES 2000
+#define DELAY 1100
+
+struct pbs_dev {
+ struct device *dev;
+ struct regmap *regmap;
+ struct mutex lock;
+ struct device_link *link;
+
+ u32 base;
+};
+
+static int qcom_pbs_wait_for_ack(struct pbs_dev *pbs, u8 bit_pos)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read_poll_timeout(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH2,
+ val, val & BIT(bit_pos), DELAY, DELAY * RETRIES);
+
+ if (ret < 0) {
+ dev_err(pbs->dev, "Timeout for PBS ACK/NACK for bit %u\n", bit_pos);
+ return -ETIMEDOUT;
+ }
+
+ if (val == PBS_CLIENT_SCRATCH2_ERROR) {
+ ret = regmap_write(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH2, 0);
+ dev_err(pbs->dev, "NACK from PBS for bit %u\n", bit_pos);
+ return -EINVAL;
+ }
+
+ dev_dbg(pbs->dev, "PBS sequence for bit %u executed!\n", bit_pos);
+ return 0;
+}
+
+/**
+ * qcom_pbs_trigger_event() - Trigger the PBS RAM sequence
+ * @pbs: Pointer to PBS device
+ * @bitmap: bitmap
+ *
+ * This function is used to trigger the PBS RAM sequence to be
+ * executed by the client driver.
+ *
+ * The PBS trigger sequence involves
+ * 1. setting the PBS sequence bit in PBS_CLIENT_SCRATCH1
+ * 2. Initiating the SW PBS trigger
+ * 3. Checking the equivalent bit in PBS_CLIENT_SCRATCH2 for the
+ * completion of the sequence.
+ * 4. If PBS_CLIENT_SCRATCH2 == 0xFF, the PBS sequence failed to execute
+ *
+ * Return: 0 on success, < 0 on failure
+ */
+int qcom_pbs_trigger_event(struct pbs_dev *pbs, u8 bitmap)
+{
+ unsigned int val;
+ u16 bit_pos;
+ int ret;
+
+ if (WARN_ON(!bitmap))
+ return -EINVAL;
+
+ if (IS_ERR_OR_NULL(pbs))
+ return -EINVAL;
+
+ guard(mutex)(&pbs->lock);
+ ret = regmap_read(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH2, &val);
+ if (ret < 0)
+ return ret;
+
+ if (val == PBS_CLIENT_SCRATCH2_ERROR) {
+ /* PBS error - clear SCRATCH2 register */
+ ret = regmap_write(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH2, 0);
+ if (ret < 0)
+ return ret;
+ }
+
+ for (bit_pos = 0; bit_pos < 8; bit_pos++) {
+ if (!(bitmap & BIT(bit_pos)))
+ continue;
+
+ /* Clear the PBS sequence bit position */
+ ret = regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH2,
+ BIT(bit_pos), 0);
+ if (ret < 0)
+ break;
+
+ /* Set the PBS sequence bit position */
+ ret = regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH1,
+ BIT(bit_pos), BIT(bit_pos));
+ if (ret < 0)
+ break;
+
+ /* Initiate the SW trigger */
+ ret = regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_TRIG_CTL,
+ PBS_CLIENT_SW_TRIG_BIT, PBS_CLIENT_SW_TRIG_BIT);
+ if (ret < 0)
+ break;
+
+ ret = qcom_pbs_wait_for_ack(pbs, bit_pos);
+ if (ret < 0)
+ break;
+
+ /* Clear the PBS sequence bit position */
+ regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH1, BIT(bit_pos), 0);
+ regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH2, BIT(bit_pos), 0);
+ }
+
+ /* Clear all the requested bitmap */
+ return regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH1, bitmap, 0);
+}
+EXPORT_SYMBOL_GPL(qcom_pbs_trigger_event);
+
+/**
+ * get_pbs_client_device() - Get the PBS device used by client
+ * @dev: Client device
+ *
+ * This function is used to get the PBS device that is being
+ * used by the client.
+ *
+ * Return: pbs_dev on success, ERR_PTR on failure
+ */
+struct pbs_dev *get_pbs_client_device(struct device *dev)
+{
+ struct platform_device *pdev;
+ struct pbs_dev *pbs;
+
+ struct device_node *pbs_dev_node __free(device_node) = of_parse_phandle(dev->of_node,
+ "qcom,pbs", 0);
+ if (!pbs_dev_node) {
+ dev_err(dev, "Missing qcom,pbs property\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ pdev = of_find_device_by_node(pbs_dev_node);
+ if (!pdev) {
+ dev_err(dev, "Unable to find PBS dev_node\n");
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+
+ pbs = platform_get_drvdata(pdev);
+ if (!pbs) {
+ dev_err(dev, "Cannot get pbs instance from %s\n", dev_name(&pdev->dev));
+ platform_device_put(pdev);
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+
+ pbs->link = device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER);
+ if (!pbs->link) {
+ dev_err(&pdev->dev, "Failed to create device link to consumer %s\n", dev_name(dev));
+ platform_device_put(pdev);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return pbs;
+}
+EXPORT_SYMBOL_GPL(get_pbs_client_device);
+
+static int qcom_pbs_probe(struct platform_device *pdev)
+{
+ struct pbs_dev *pbs;
+ u32 val;
+ int ret;
+
+ pbs = devm_kzalloc(&pdev->dev, sizeof(*pbs), GFP_KERNEL);
+ if (!pbs)
+ return -ENOMEM;
+
+ pbs->dev = &pdev->dev;
+ pbs->regmap = dev_get_regmap(pbs->dev->parent, NULL);
+ if (!pbs->regmap) {
+ dev_err(pbs->dev, "Couldn't get parent's regmap\n");
+ return -EINVAL;
+ }
+
+ ret = device_property_read_u32(pbs->dev, "reg", &val);
+ if (ret < 0) {
+ dev_err(pbs->dev, "Couldn't find reg, ret = %d\n", ret);
+ return ret;
+ }
+ pbs->base = val;
+ mutex_init(&pbs->lock);
+
+ platform_set_drvdata(pdev, pbs);
+
+ return 0;
+}
+
+static const struct of_device_id qcom_pbs_match_table[] = {
+ { .compatible = "qcom,pbs" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, qcom_pbs_match_table);
+
+static struct platform_driver qcom_pbs_driver = {
+ .driver = {
+ .name = "qcom-pbs",
+ .of_match_table = qcom_pbs_match_table,
+ },
+ .probe = qcom_pbs_probe,
+};
+module_platform_driver(qcom_pbs_driver)
+
+MODULE_DESCRIPTION("QCOM PBS DRIVER");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c
index aff0cfb71482..0320ad3b9148 100644
--- a/drivers/soc/qcom/qcom_aoss.c
+++ b/drivers/soc/qcom/qcom_aoss.c
@@ -3,6 +3,7 @@
* Copyright (c) 2019, Linaro Ltd
*/
#include <linux/clk-provider.h>
+#include <linux/debugfs.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/mailbox_client.h>
@@ -13,6 +14,9 @@
#include <linux/slab.h>
#include <linux/soc/qcom/qcom_aoss.h>
+#define CREATE_TRACE_POINTS
+#include "trace-aoss.h"
+
#define QMP_DESC_MAGIC 0x0
#define QMP_DESC_VERSION 0x4
#define QMP_DESC_FEATURES 0x8
@@ -44,6 +48,8 @@
#define QMP_NUM_COOLING_RESOURCES 2
+#define QMP_DEBUGFS_FILES 4
+
static bool qmp_cdev_max_state = 1;
struct qmp_cooling_device {
@@ -65,6 +71,8 @@ struct qmp_cooling_device {
* @tx_lock: provides synchronization between multiple callers of qmp_send()
* @qdss_clk: QDSS clock hw struct
* @cooling_devs: thermal cooling devices
+ * @debugfs_root: directory for the developer/tester interface
+ * @debugfs_files: array of individual debugfs entries under debugfs_root
*/
struct qmp {
void __iomem *msgram;
@@ -82,6 +90,8 @@ struct qmp {
struct clk_hw qdss_clk;
struct qmp_cooling_device *cooling_devs;
+ struct dentry *debugfs_root;
+ struct dentry *debugfs_files[QMP_DEBUGFS_FILES];
};
static void qmp_kick(struct qmp *qmp)
@@ -214,7 +224,7 @@ static bool qmp_message_empty(struct qmp *qmp)
*
* Return: 0 on success, negative errno on failure
*/
-int qmp_send(struct qmp *qmp, const char *fmt, ...)
+int __printf(2, 3) qmp_send(struct qmp *qmp, const char *fmt, ...)
{
char buf[QMP_MSG_LEN];
long time_left;
@@ -235,6 +245,8 @@ int qmp_send(struct qmp *qmp, const char *fmt, ...)
mutex_lock(&qmp->tx_lock);
+ trace_aoss_send(buf);
+
/* The message RAM only implements 32-bit accesses */
__iowrite32_copy(qmp->msgram + qmp->offset + sizeof(u32),
buf, sizeof(buf) / sizeof(u32));
@@ -256,6 +268,8 @@ int qmp_send(struct qmp *qmp, const char *fmt, ...)
ret = 0;
}
+ trace_aoss_send_done(buf, ret);
+
mutex_unlock(&qmp->tx_lock);
return ret;
@@ -380,7 +394,7 @@ static int qmp_cooling_device_add(struct qmp *qmp,
static int qmp_cooling_devices_register(struct qmp *qmp)
{
- struct device_node *np, *child;
+ struct device_node *np;
int count = 0;
int ret;
@@ -393,15 +407,13 @@ static int qmp_cooling_devices_register(struct qmp *qmp)
if (!qmp->cooling_devs)
return -ENOMEM;
- for_each_available_child_of_node(np, child) {
+ for_each_available_child_of_node_scoped(np, child) {
if (!of_property_present(child, "#cooling-cells"))
continue;
ret = qmp_cooling_device_add(qmp, &qmp->cooling_devs[count++],
child);
- if (ret) {
- of_node_put(child);
+ if (ret)
goto unroll;
- }
}
if (!count)
@@ -475,6 +487,91 @@ void qmp_put(struct qmp *qmp)
}
EXPORT_SYMBOL_GPL(qmp_put);
+struct qmp_debugfs_entry {
+ const char *name;
+ const char *fmt;
+ bool is_bool;
+ const char *true_val;
+ const char *false_val;
+};
+
+static const struct qmp_debugfs_entry qmp_debugfs_entries[QMP_DEBUGFS_FILES] = {
+ { "ddr_frequency_mhz", "{class: ddr, res: fixed, val: %u}", false },
+ { "prevent_aoss_sleep", "{class: aoss_slp, res: sleep: %s}", true, "enable", "disable" },
+ { "prevent_cx_collapse", "{class: cx_mol, res: cx, val: %s}", true, "mol", "off" },
+ { "prevent_ddr_collapse", "{class: ddr_mol, res: ddr, val: %s}", true, "mol", "off" },
+};
+
+static ssize_t qmp_debugfs_write(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *pos)
+{
+ const struct qmp_debugfs_entry *entry = NULL;
+ struct qmp *qmp = file->private_data;
+ char buf[QMP_MSG_LEN];
+ unsigned int uint_val;
+ const char *str_val;
+ bool bool_val;
+ int ret;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(qmp->debugfs_files); i++) {
+ if (qmp->debugfs_files[i] == file->f_path.dentry) {
+ entry = &qmp_debugfs_entries[i];
+ break;
+ }
+ }
+ if (WARN_ON(!entry))
+ return -EFAULT;
+
+ if (entry->is_bool) {
+ ret = kstrtobool_from_user(user_buf, count, &bool_val);
+ if (ret)
+ return ret;
+
+ str_val = bool_val ? entry->true_val : entry->false_val;
+
+ ret = snprintf(buf, sizeof(buf), entry->fmt, str_val);
+ if (ret >= sizeof(buf))
+ return -EINVAL;
+ } else {
+ ret = kstrtou32_from_user(user_buf, count, 0, &uint_val);
+ if (ret)
+ return ret;
+
+ ret = snprintf(buf, sizeof(buf), entry->fmt, uint_val);
+ if (ret >= sizeof(buf))
+ return -EINVAL;
+ }
+
+ ret = qmp_send(qmp, buf);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static const struct file_operations qmp_debugfs_fops = {
+ .open = simple_open,
+ .write = qmp_debugfs_write,
+};
+
+static void qmp_debugfs_create(struct qmp *qmp)
+{
+ const struct qmp_debugfs_entry *entry;
+ int i;
+
+ qmp->debugfs_root = debugfs_create_dir("qcom_aoss", NULL);
+
+ for (i = 0; i < ARRAY_SIZE(qmp->debugfs_files); i++) {
+ entry = &qmp_debugfs_entries[i];
+
+ qmp->debugfs_files[i] = debugfs_create_file(entry->name, 0200,
+ qmp->debugfs_root,
+ qmp,
+ &qmp_debugfs_fops);
+ }
+}
+
static int qmp_probe(struct platform_device *pdev)
{
struct qmp *qmp;
@@ -523,6 +620,8 @@ static int qmp_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, qmp);
+ qmp_debugfs_create(qmp);
+
return 0;
err_close_qmp:
@@ -537,6 +636,8 @@ static void qmp_remove(struct platform_device *pdev)
{
struct qmp *qmp = platform_get_drvdata(pdev);
+ debugfs_remove_recursive(qmp->debugfs_root);
+
qmp_qdss_clk_remove(qmp);
qmp_cooling_devices_remove(qmp);
@@ -563,7 +664,7 @@ static struct platform_driver qmp_driver = {
.suppress_bind_attrs = true,
},
.probe = qmp_probe,
- .remove_new = qmp_remove,
+ .remove = qmp_remove,
};
module_platform_driver(qmp_driver);
diff --git a/drivers/soc/qcom/qcom_gsbi.c b/drivers/soc/qcom/qcom_gsbi.c
index f04b9a324ea9..8f1158e0c631 100644
--- a/drivers/soc/qcom/qcom_gsbi.c
+++ b/drivers/soc/qcom/qcom_gsbi.c
@@ -232,7 +232,7 @@ static struct platform_driver gsbi_driver = {
.of_match_table = gsbi_dt_match,
},
.probe = gsbi_probe,
- .remove_new = gsbi_remove,
+ .remove = gsbi_remove,
};
module_platform_driver(gsbi_driver);
diff --git a/drivers/soc/qcom/qcom_pd_mapper.c b/drivers/soc/qcom/qcom_pd_mapper.c
new file mode 100644
index 000000000000..154ca5beb471
--- /dev/null
+++ b/drivers/soc/qcom/qcom_pd_mapper.c
@@ -0,0 +1,697 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Qualcomm Protection Domain mapper
+ *
+ * Copyright (c) 2023 Linaro Ltd.
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/refcount.h>
+#include <linux/slab.h>
+#include <linux/soc/qcom/qmi.h>
+
+#include "pdr_internal.h"
+
+#define SERVREG_QMI_VERSION 0x101
+#define SERVREG_QMI_INSTANCE 0
+
+#define TMS_SERVREG_SERVICE "tms/servreg"
+
+struct qcom_pdm_domain_data {
+ const char *domain;
+ u32 instance_id;
+ /* NULL-terminated array */
+ const char * services[];
+};
+
+struct qcom_pdm_domain {
+ struct list_head list;
+ const char *name;
+ u32 instance_id;
+};
+
+struct qcom_pdm_service {
+ struct list_head list;
+ struct list_head domains;
+ const char *name;
+};
+
+struct qcom_pdm_data {
+ refcount_t refcnt;
+ struct qmi_handle handle;
+ struct list_head services;
+};
+
+static DEFINE_MUTEX(qcom_pdm_mutex); /* protects __qcom_pdm_data */
+static struct qcom_pdm_data *__qcom_pdm_data;
+
+static struct qcom_pdm_service *qcom_pdm_find(struct qcom_pdm_data *data,
+ const char *name)
+{
+ struct qcom_pdm_service *service;
+
+ list_for_each_entry(service, &data->services, list) {
+ if (!strcmp(service->name, name))
+ return service;
+ }
+
+ return NULL;
+}
+
+static int qcom_pdm_add_service_domain(struct qcom_pdm_data *data,
+ const char *service_name,
+ const char *domain_name,
+ u32 instance_id)
+{
+ struct qcom_pdm_service *service;
+ struct qcom_pdm_domain *domain;
+
+ service = qcom_pdm_find(data, service_name);
+ if (service) {
+ list_for_each_entry(domain, &service->domains, list) {
+ if (!strcmp(domain->name, domain_name))
+ return -EBUSY;
+ }
+ } else {
+ service = kzalloc(sizeof(*service), GFP_KERNEL);
+ if (!service)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&service->domains);
+ service->name = service_name;
+
+ list_add_tail(&service->list, &data->services);
+ }
+
+ domain = kzalloc(sizeof(*domain), GFP_KERNEL);
+ if (!domain) {
+ if (list_empty(&service->domains)) {
+ list_del(&service->list);
+ kfree(service);
+ }
+
+ return -ENOMEM;
+ }
+
+ domain->name = domain_name;
+ domain->instance_id = instance_id;
+ list_add_tail(&domain->list, &service->domains);
+
+ return 0;
+}
+
+static int qcom_pdm_add_domain(struct qcom_pdm_data *data,
+ const struct qcom_pdm_domain_data *domain)
+{
+ int ret;
+ int i;
+
+ ret = qcom_pdm_add_service_domain(data,
+ TMS_SERVREG_SERVICE,
+ domain->domain,
+ domain->instance_id);
+ if (ret)
+ return ret;
+
+ for (i = 0; domain->services[i]; i++) {
+ ret = qcom_pdm_add_service_domain(data,
+ domain->services[i],
+ domain->domain,
+ domain->instance_id);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+
+}
+
+static void qcom_pdm_free_domains(struct qcom_pdm_data *data)
+{
+ struct qcom_pdm_service *service, *tservice;
+ struct qcom_pdm_domain *domain, *tdomain;
+
+ list_for_each_entry_safe(service, tservice, &data->services, list) {
+ list_for_each_entry_safe(domain, tdomain, &service->domains, list) {
+ list_del(&domain->list);
+ kfree(domain);
+ }
+
+ list_del(&service->list);
+ kfree(service);
+ }
+}
+
+static void qcom_pdm_get_domain_list(struct qmi_handle *qmi,
+ struct sockaddr_qrtr *sq,
+ struct qmi_txn *txn,
+ const void *decoded)
+{
+ struct qcom_pdm_data *data = container_of(qmi, struct qcom_pdm_data, handle);
+ const struct servreg_get_domain_list_req *req = decoded;
+ struct servreg_get_domain_list_resp *rsp;
+ struct qcom_pdm_service *service;
+ u32 offset;
+ int ret;
+
+ rsp = kzalloc(sizeof(*rsp), GFP_KERNEL);
+ if (!rsp)
+ return;
+
+ offset = req->domain_offset_valid ? req->domain_offset : 0;
+
+ rsp->resp.result = QMI_RESULT_SUCCESS_V01;
+ rsp->resp.error = QMI_ERR_NONE_V01;
+
+ rsp->db_rev_count_valid = true;
+ rsp->db_rev_count = 1;
+
+ rsp->total_domains_valid = true;
+ rsp->total_domains = 0;
+
+ mutex_lock(&qcom_pdm_mutex);
+
+ service = qcom_pdm_find(data, req->service_name);
+ if (service) {
+ struct qcom_pdm_domain *domain;
+
+ rsp->domain_list_valid = true;
+ rsp->domain_list_len = 0;
+
+ list_for_each_entry(domain, &service->domains, list) {
+ u32 i = rsp->total_domains++;
+
+ if (i >= offset && i < SERVREG_DOMAIN_LIST_LENGTH) {
+ u32 j = rsp->domain_list_len++;
+
+ strscpy(rsp->domain_list[j].name, domain->name,
+ sizeof(rsp->domain_list[i].name));
+ rsp->domain_list[j].instance = domain->instance_id;
+
+ pr_debug("PDM: found %s / %d\n", domain->name,
+ domain->instance_id);
+ }
+ }
+ }
+
+ pr_debug("PDM: service '%s' offset %d returning %d domains (of %d)\n", req->service_name,
+ req->domain_offset_valid ? req->domain_offset : -1, rsp->domain_list_len, rsp->total_domains);
+
+ ret = qmi_send_response(qmi, sq, txn, SERVREG_GET_DOMAIN_LIST_REQ,
+ SERVREG_GET_DOMAIN_LIST_RESP_MAX_LEN,
+ servreg_get_domain_list_resp_ei, rsp);
+ if (ret)
+ pr_err("Error sending servreg response: %d\n", ret);
+
+ mutex_unlock(&qcom_pdm_mutex);
+
+ kfree(rsp);
+}
+
+static void qcom_pdm_pfr(struct qmi_handle *qmi,
+ struct sockaddr_qrtr *sq,
+ struct qmi_txn *txn,
+ const void *decoded)
+{
+ const struct servreg_loc_pfr_req *req = decoded;
+ struct servreg_loc_pfr_resp rsp = {};
+ int ret;
+
+ pr_warn_ratelimited("PDM: service '%s' crash: '%s'\n", req->service, req->reason);
+
+ rsp.rsp.result = QMI_RESULT_SUCCESS_V01;
+ rsp.rsp.error = QMI_ERR_NONE_V01;
+
+ ret = qmi_send_response(qmi, sq, txn, SERVREG_LOC_PFR_REQ,
+ SERVREG_LOC_PFR_RESP_MAX_LEN,
+ servreg_loc_pfr_resp_ei, &rsp);
+ if (ret)
+ pr_err("Error sending servreg response: %d\n", ret);
+}
+
+static const struct qmi_msg_handler qcom_pdm_msg_handlers[] = {
+ {
+ .type = QMI_REQUEST,
+ .msg_id = SERVREG_GET_DOMAIN_LIST_REQ,
+ .ei = servreg_get_domain_list_req_ei,
+ .decoded_size = sizeof(struct servreg_get_domain_list_req),
+ .fn = qcom_pdm_get_domain_list,
+ },
+ {
+ .type = QMI_REQUEST,
+ .msg_id = SERVREG_LOC_PFR_REQ,
+ .ei = servreg_loc_pfr_req_ei,
+ .decoded_size = sizeof(struct servreg_loc_pfr_req),
+ .fn = qcom_pdm_pfr,
+ },
+ { },
+};
+
+static const struct qcom_pdm_domain_data adsp_audio_pd = {
+ .domain = "msm/adsp/audio_pd",
+ .instance_id = 74,
+ .services = {
+ "avs/audio",
+ NULL,
+ },
+};
+
+static const struct qcom_pdm_domain_data adsp_charger_pd = {
+ .domain = "msm/adsp/charger_pd",
+ .instance_id = 74,
+ .services = { NULL },
+};
+
+static const struct qcom_pdm_domain_data adsp_root_pd = {
+ .domain = "msm/adsp/root_pd",
+ .instance_id = 74,
+ .services = { NULL },
+};
+
+static const struct qcom_pdm_domain_data adsp_root_pd_pdr = {
+ .domain = "msm/adsp/root_pd",
+ .instance_id = 74,
+ .services = {
+ "tms/pdr_enabled",
+ NULL,
+ },
+};
+
+static const struct qcom_pdm_domain_data adsp_sensor_pd = {
+ .domain = "msm/adsp/sensor_pd",
+ .instance_id = 74,
+ .services = { NULL },
+};
+
+static const struct qcom_pdm_domain_data msm8996_adsp_audio_pd = {
+ .domain = "msm/adsp/audio_pd",
+ .instance_id = 4,
+ .services = { NULL },
+};
+
+static const struct qcom_pdm_domain_data msm8996_adsp_root_pd = {
+ .domain = "msm/adsp/root_pd",
+ .instance_id = 4,
+ .services = { NULL },
+};
+
+static const struct qcom_pdm_domain_data cdsp_root_pd = {
+ .domain = "msm/cdsp/root_pd",
+ .instance_id = 76,
+ .services = { NULL },
+};
+
+static const struct qcom_pdm_domain_data slpi_root_pd = {
+ .domain = "msm/slpi/root_pd",
+ .instance_id = 90,
+ .services = { NULL },
+};
+
+static const struct qcom_pdm_domain_data slpi_sensor_pd = {
+ .domain = "msm/slpi/sensor_pd",
+ .instance_id = 90,
+ .services = { NULL },
+};
+
+static const struct qcom_pdm_domain_data mpss_root_pd = {
+ .domain = "msm/modem/root_pd",
+ .instance_id = 180,
+ .services = {
+ NULL,
+ },
+};
+
+static const struct qcom_pdm_domain_data mpss_root_pd_gps = {
+ .domain = "msm/modem/root_pd",
+ .instance_id = 180,
+ .services = {
+ "gps/gps_service",
+ NULL,
+ },
+};
+
+static const struct qcom_pdm_domain_data mpss_root_pd_gps_pdr = {
+ .domain = "msm/modem/root_pd",
+ .instance_id = 180,
+ .services = {
+ "gps/gps_service",
+ "tms/pdr_enabled",
+ NULL,
+ },
+};
+
+static const struct qcom_pdm_domain_data msm8996_mpss_root_pd = {
+ .domain = "msm/modem/root_pd",
+ .instance_id = 100,
+ .services = { NULL },
+};
+
+static const struct qcom_pdm_domain_data mpss_wlan_pd = {
+ .domain = "msm/modem/wlan_pd",
+ .instance_id = 180,
+ .services = {
+ "kernel/elf_loader",
+ "wlan/fw",
+ NULL,
+ },
+};
+
+static const struct qcom_pdm_domain_data *msm8996_domains[] = {
+ &msm8996_adsp_audio_pd,
+ &msm8996_adsp_root_pd,
+ &msm8996_mpss_root_pd,
+ NULL,
+};
+
+static const struct qcom_pdm_domain_data *msm8998_domains[] = {
+ &mpss_root_pd,
+ &mpss_wlan_pd,
+ NULL,
+};
+
+static const struct qcom_pdm_domain_data *qcm2290_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd,
+ &adsp_sensor_pd,
+ &mpss_root_pd_gps,
+ &mpss_wlan_pd,
+ NULL,
+};
+
+static const struct qcom_pdm_domain_data *qcs404_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd,
+ &adsp_sensor_pd,
+ &cdsp_root_pd,
+ &mpss_root_pd,
+ &mpss_wlan_pd,
+ NULL,
+};
+
+static const struct qcom_pdm_domain_data *sc7180_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd_pdr,
+ &adsp_sensor_pd,
+ &mpss_root_pd_gps_pdr,
+ &mpss_wlan_pd,
+ NULL,
+};
+
+static const struct qcom_pdm_domain_data *sc7280_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd_pdr,
+ &adsp_charger_pd,
+ &adsp_sensor_pd,
+ &cdsp_root_pd,
+ &mpss_root_pd_gps_pdr,
+ NULL,
+};
+
+static const struct qcom_pdm_domain_data *sc8180x_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd,
+ &adsp_charger_pd,
+ &cdsp_root_pd,
+ &mpss_root_pd_gps,
+ &mpss_wlan_pd,
+ NULL,
+};
+
+static const struct qcom_pdm_domain_data *sc8280xp_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd_pdr,
+ &adsp_charger_pd,
+ &cdsp_root_pd,
+ NULL,
+};
+
+static const struct qcom_pdm_domain_data *sdm660_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd,
+ &adsp_sensor_pd,
+ &cdsp_root_pd,
+ &mpss_root_pd,
+ &mpss_wlan_pd,
+ NULL,
+};
+
+static const struct qcom_pdm_domain_data *sdm670_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd,
+ &cdsp_root_pd,
+ &mpss_root_pd,
+ &mpss_wlan_pd,
+ NULL,
+};
+
+static const struct qcom_pdm_domain_data *sdm845_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd,
+ &cdsp_root_pd,
+ &mpss_root_pd,
+ &mpss_wlan_pd,
+ &slpi_root_pd,
+ &slpi_sensor_pd,
+ NULL,
+};
+
+static const struct qcom_pdm_domain_data *sm6115_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd,
+ &adsp_sensor_pd,
+ &cdsp_root_pd,
+ &mpss_root_pd_gps,
+ &mpss_wlan_pd,
+ NULL,
+};
+
+static const struct qcom_pdm_domain_data *sm6350_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd,
+ &adsp_sensor_pd,
+ &cdsp_root_pd,
+ &mpss_wlan_pd,
+ NULL,
+};
+
+static const struct qcom_pdm_domain_data *sm8150_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd,
+ &cdsp_root_pd,
+ &mpss_root_pd_gps,
+ &mpss_wlan_pd,
+ NULL,
+};
+
+static const struct qcom_pdm_domain_data *sm8250_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd,
+ &cdsp_root_pd,
+ &slpi_root_pd,
+ &slpi_sensor_pd,
+ NULL,
+};
+
+static const struct qcom_pdm_domain_data *sm8350_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd_pdr,
+ &adsp_charger_pd,
+ &cdsp_root_pd,
+ &mpss_root_pd_gps,
+ &slpi_root_pd,
+ &slpi_sensor_pd,
+ NULL,
+};
+
+static const struct qcom_pdm_domain_data *sm8550_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd,
+ &adsp_charger_pd,
+ &adsp_sensor_pd,
+ &cdsp_root_pd,
+ &mpss_root_pd_gps,
+ NULL,
+};
+
+static const struct qcom_pdm_domain_data *x1e80100_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd,
+ &adsp_charger_pd,
+ &adsp_sensor_pd,
+ &cdsp_root_pd,
+ NULL,
+};
+
+static const struct of_device_id qcom_pdm_domains[] __maybe_unused = {
+ { .compatible = "qcom,apq8016", .data = NULL, },
+ { .compatible = "qcom,apq8064", .data = NULL, },
+ { .compatible = "qcom,apq8074", .data = NULL, },
+ { .compatible = "qcom,apq8084", .data = NULL, },
+ { .compatible = "qcom,apq8096", .data = msm8996_domains, },
+ { .compatible = "qcom,msm8226", .data = NULL, },
+ { .compatible = "qcom,msm8909", .data = NULL, },
+ { .compatible = "qcom,msm8916", .data = NULL, },
+ { .compatible = "qcom,msm8939", .data = NULL, },
+ { .compatible = "qcom,msm8974", .data = NULL, },
+ { .compatible = "qcom,msm8996", .data = msm8996_domains, },
+ { .compatible = "qcom,msm8998", .data = msm8998_domains, },
+ { .compatible = "qcom,qcm2290", .data = qcm2290_domains, },
+ { .compatible = "qcom,qcm6490", .data = sc7280_domains, },
+ { .compatible = "qcom,qcs404", .data = qcs404_domains, },
+ { .compatible = "qcom,sc7180", .data = sc7180_domains, },
+ { .compatible = "qcom,sc7280", .data = sc7280_domains, },
+ { .compatible = "qcom,sc8180x", .data = sc8180x_domains, },
+ { .compatible = "qcom,sc8280xp", .data = sc8280xp_domains, },
+ { .compatible = "qcom,sda660", .data = sdm660_domains, },
+ { .compatible = "qcom,sdm660", .data = sdm660_domains, },
+ { .compatible = "qcom,sdm670", .data = sdm670_domains, },
+ { .compatible = "qcom,sdm845", .data = sdm845_domains, },
+ { .compatible = "qcom,sm4250", .data = sm6115_domains, },
+ { .compatible = "qcom,sm6115", .data = sm6115_domains, },
+ { .compatible = "qcom,sm6350", .data = sm6350_domains, },
+ { .compatible = "qcom,sm7225", .data = sm6350_domains, },
+ { .compatible = "qcom,sm7325", .data = sc7280_domains, },
+ { .compatible = "qcom,sm8150", .data = sm8150_domains, },
+ { .compatible = "qcom,sm8250", .data = sm8250_domains, },
+ { .compatible = "qcom,sm8350", .data = sm8350_domains, },
+ { .compatible = "qcom,sm8450", .data = sm8350_domains, },
+ { .compatible = "qcom,sm8550", .data = sm8550_domains, },
+ { .compatible = "qcom,sm8650", .data = sm8550_domains, },
+ { .compatible = "qcom,x1e80100", .data = x1e80100_domains, },
+ { .compatible = "qcom,x1p42100", .data = x1e80100_domains, },
+ {},
+};
+
+static void qcom_pdm_stop(struct qcom_pdm_data *data)
+{
+ qcom_pdm_free_domains(data);
+
+ /* The server is removed automatically */
+ qmi_handle_release(&data->handle);
+
+ kfree(data);
+}
+
+static struct qcom_pdm_data *qcom_pdm_start(void)
+{
+ const struct qcom_pdm_domain_data * const *domains;
+ const struct of_device_id *match;
+ struct qcom_pdm_data *data;
+ struct device_node *root;
+ int ret, i;
+
+ root = of_find_node_by_path("/");
+ if (!root)
+ return ERR_PTR(-ENODEV);
+
+ match = of_match_node(qcom_pdm_domains, root);
+ of_node_put(root);
+ if (!match) {
+ pr_notice("PDM: no support for the platform, userspace daemon might be required.\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ domains = match->data;
+ if (!domains) {
+ pr_debug("PDM: no domains\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&data->services);
+
+ ret = qmi_handle_init(&data->handle, SERVREG_GET_DOMAIN_LIST_REQ_MAX_LEN,
+ NULL, qcom_pdm_msg_handlers);
+ if (ret) {
+ kfree(data);
+ return ERR_PTR(ret);
+ }
+
+ refcount_set(&data->refcnt, 1);
+
+ for (i = 0; domains[i]; i++) {
+ ret = qcom_pdm_add_domain(data, domains[i]);
+ if (ret)
+ goto err_stop;
+ }
+
+ ret = qmi_add_server(&data->handle, SERVREG_LOCATOR_SERVICE,
+ SERVREG_QMI_VERSION, SERVREG_QMI_INSTANCE);
+ if (ret) {
+ pr_err("PDM: error adding server %d\n", ret);
+ goto err_stop;
+ }
+
+ return data;
+
+err_stop:
+ qcom_pdm_stop(data);
+
+ return ERR_PTR(ret);
+}
+
+static int qcom_pdm_probe(struct auxiliary_device *auxdev,
+ const struct auxiliary_device_id *id)
+
+{
+ struct qcom_pdm_data *data;
+ int ret = 0;
+
+ mutex_lock(&qcom_pdm_mutex);
+
+ if (!__qcom_pdm_data) {
+ data = qcom_pdm_start();
+
+ if (IS_ERR(data))
+ ret = PTR_ERR(data);
+ else
+ __qcom_pdm_data = data;
+ } else {
+ refcount_inc(&__qcom_pdm_data->refcnt);
+ }
+
+ auxiliary_set_drvdata(auxdev, __qcom_pdm_data);
+
+ mutex_unlock(&qcom_pdm_mutex);
+
+ return ret;
+}
+
+static void qcom_pdm_remove(struct auxiliary_device *auxdev)
+{
+ struct qcom_pdm_data *data;
+
+ data = auxiliary_get_drvdata(auxdev);
+ if (!data)
+ return;
+
+ if (refcount_dec_and_mutex_lock(&data->refcnt, &qcom_pdm_mutex)) {
+ __qcom_pdm_data = NULL;
+ qcom_pdm_stop(data);
+ mutex_unlock(&qcom_pdm_mutex);
+ }
+}
+
+static const struct auxiliary_device_id qcom_pdm_table[] = {
+ { .name = "qcom_common.pd-mapper" },
+ {},
+};
+MODULE_DEVICE_TABLE(auxiliary, qcom_pdm_table);
+
+static struct auxiliary_driver qcom_pdm_drv = {
+ .name = "qcom-pdm-mapper",
+ .id_table = qcom_pdm_table,
+ .probe = qcom_pdm_probe,
+ .remove = qcom_pdm_remove,
+};
+module_auxiliary_driver(qcom_pdm_drv);
+
+MODULE_DESCRIPTION("Qualcomm Protection Domain Mapper");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/qcom/qcom_pdr_msg.c b/drivers/soc/qcom/qcom_pdr_msg.c
new file mode 100644
index 000000000000..bf3e4a47165e
--- /dev/null
+++ b/drivers/soc/qcom/qcom_pdr_msg.c
@@ -0,0 +1,353 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/soc/qcom/qmi.h>
+
+#include "pdr_internal.h"
+
+const struct qmi_elem_info servreg_location_entry_ei[] = {
+ {
+ .data_type = QMI_STRING,
+ .elem_len = SERVREG_NAME_LENGTH + 1,
+ .elem_size = sizeof(char),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct servreg_location_entry,
+ name),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct servreg_location_entry,
+ instance),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct servreg_location_entry,
+ service_data_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct servreg_location_entry,
+ service_data),
+ },
+ {}
+};
+EXPORT_SYMBOL_GPL(servreg_location_entry_ei);
+
+const struct qmi_elem_info servreg_get_domain_list_req_ei[] = {
+ {
+ .data_type = QMI_STRING,
+ .elem_len = SERVREG_NAME_LENGTH + 1,
+ .elem_size = sizeof(char),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct servreg_get_domain_list_req,
+ service_name),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct servreg_get_domain_list_req,
+ domain_offset_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct servreg_get_domain_list_req,
+ domain_offset),
+ },
+ {}
+};
+EXPORT_SYMBOL_GPL(servreg_get_domain_list_req_ei);
+
+const struct qmi_elem_info servreg_get_domain_list_resp_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct servreg_get_domain_list_resp,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct servreg_get_domain_list_resp,
+ total_domains_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_2_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct servreg_get_domain_list_resp,
+ total_domains),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct servreg_get_domain_list_resp,
+ db_rev_count_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_2_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct servreg_get_domain_list_resp,
+ db_rev_count),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct servreg_get_domain_list_resp,
+ domain_list_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct servreg_get_domain_list_resp,
+ domain_list_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = SERVREG_DOMAIN_LIST_LENGTH,
+ .elem_size = sizeof(struct servreg_location_entry),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct servreg_get_domain_list_resp,
+ domain_list),
+ .ei_array = servreg_location_entry_ei,
+ },
+ {}
+};
+EXPORT_SYMBOL_GPL(servreg_get_domain_list_resp_ei);
+
+const struct qmi_elem_info servreg_register_listener_req_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct servreg_register_listener_req,
+ enable),
+ },
+ {
+ .data_type = QMI_STRING,
+ .elem_len = SERVREG_NAME_LENGTH + 1,
+ .elem_size = sizeof(char),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct servreg_register_listener_req,
+ service_path),
+ },
+ {}
+};
+EXPORT_SYMBOL_GPL(servreg_register_listener_req_ei);
+
+const struct qmi_elem_info servreg_register_listener_resp_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct servreg_register_listener_resp,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct servreg_register_listener_resp,
+ curr_state_valid),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum servreg_service_state),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct servreg_register_listener_resp,
+ curr_state),
+ },
+ {}
+};
+EXPORT_SYMBOL_GPL(servreg_register_listener_resp_ei);
+
+const struct qmi_elem_info servreg_restart_pd_req_ei[] = {
+ {
+ .data_type = QMI_STRING,
+ .elem_len = SERVREG_NAME_LENGTH + 1,
+ .elem_size = sizeof(char),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct servreg_restart_pd_req,
+ service_path),
+ },
+ {}
+};
+EXPORT_SYMBOL_GPL(servreg_restart_pd_req_ei);
+
+const struct qmi_elem_info servreg_restart_pd_resp_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct servreg_restart_pd_resp,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {}
+};
+EXPORT_SYMBOL_GPL(servreg_restart_pd_resp_ei);
+
+const struct qmi_elem_info servreg_state_updated_ind_ei[] = {
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct servreg_state_updated_ind,
+ curr_state),
+ },
+ {
+ .data_type = QMI_STRING,
+ .elem_len = SERVREG_NAME_LENGTH + 1,
+ .elem_size = sizeof(char),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct servreg_state_updated_ind,
+ service_path),
+ },
+ {
+ .data_type = QMI_UNSIGNED_2_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(struct servreg_state_updated_ind,
+ transaction_id),
+ },
+ {}
+};
+EXPORT_SYMBOL_GPL(servreg_state_updated_ind_ei);
+
+const struct qmi_elem_info servreg_set_ack_req_ei[] = {
+ {
+ .data_type = QMI_STRING,
+ .elem_len = SERVREG_NAME_LENGTH + 1,
+ .elem_size = sizeof(char),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct servreg_set_ack_req,
+ service_path),
+ },
+ {
+ .data_type = QMI_UNSIGNED_2_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct servreg_set_ack_req,
+ transaction_id),
+ },
+ {}
+};
+EXPORT_SYMBOL_GPL(servreg_set_ack_req_ei);
+
+const struct qmi_elem_info servreg_set_ack_resp_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct servreg_set_ack_resp,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {}
+};
+EXPORT_SYMBOL_GPL(servreg_set_ack_resp_ei);
+
+const struct qmi_elem_info servreg_loc_pfr_req_ei[] = {
+ {
+ .data_type = QMI_STRING,
+ .elem_len = SERVREG_NAME_LENGTH + 1,
+ .elem_size = sizeof(char),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct servreg_loc_pfr_req, service)
+ },
+ {
+ .data_type = QMI_STRING,
+ .elem_len = SERVREG_NAME_LENGTH + 1,
+ .elem_size = sizeof(char),
+ .array_type = VAR_LEN_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct servreg_loc_pfr_req, reason)
+ },
+ {}
+};
+EXPORT_SYMBOL_GPL(servreg_loc_pfr_req_ei);
+
+const struct qmi_elem_info servreg_loc_pfr_resp_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof_field(struct servreg_loc_pfr_resp, rsp),
+ .tlv_type = 0x02,
+ .offset = offsetof(struct servreg_loc_pfr_resp, rsp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {}
+};
+EXPORT_SYMBOL_GPL(servreg_loc_pfr_resp_ei);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Qualcomm Protection Domain messages data");
diff --git a/drivers/soc/qcom/qcom_stats.c b/drivers/soc/qcom/qcom_stats.c
index 0216fc24f2ca..5de99cf59b9f 100644
--- a/drivers/soc/qcom/qcom_stats.c
+++ b/drivers/soc/qcom/qcom_stats.c
@@ -35,11 +35,15 @@ static const struct subsystem_data subsystems[] = {
{ "wpss", 605, 13 },
{ "adsp", 606, 2 },
{ "cdsp", 607, 5 },
+ { "cdsp1", 607, 12 },
+ { "gpdsp0", 607, 17 },
+ { "gpdsp1", 607, 18 },
{ "slpi", 608, 3 },
{ "gpu", 609, 0 },
{ "display", 610, 0 },
{ "adsp_island", 613, 2 },
{ "slpi_island", 613, 3 },
+ { "apss", 631, QCOM_SMEM_HOST_ANY },
};
struct stats_config {
@@ -270,7 +274,7 @@ MODULE_DEVICE_TABLE(of, qcom_stats_table);
static struct platform_driver qcom_stats = {
.probe = qcom_stats_probe,
- .remove_new = qcom_stats_remove,
+ .remove = qcom_stats_remove,
.driver = {
.name = "qcom_stats",
.of_match_table = qcom_stats_table,
diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c
index bb98b06e87f8..bc6d6379d8b1 100644
--- a/drivers/soc/qcom/qmi_interface.c
+++ b/drivers/soc/qcom/qmi_interface.c
@@ -195,8 +195,8 @@ static void qmi_send_new_lookup(struct qmi_handle *qmi, struct qmi_service *svc)
* qmi_add_lookup() - register a new lookup with the name service
* @qmi: qmi handle
* @service: service id of the request
- * @instance: instance id of the request
* @version: version number of the request
+ * @instance: instance id of the request
*
* Registering a lookup query with the name server will cause the name server
* to send NEW_SERVER and DEL_SERVER control messages to this socket as
diff --git a/drivers/soc/qcom/ramp_controller.c b/drivers/soc/qcom/ramp_controller.c
index e9a0cca07189..349bdfbc61ef 100644
--- a/drivers/soc/qcom/ramp_controller.c
+++ b/drivers/soc/qcom/ramp_controller.c
@@ -331,8 +331,8 @@ static struct platform_driver qcom_ramp_controller_driver = {
.of_match_table = qcom_ramp_controller_match_table,
.suppress_bind_attrs = true,
},
- .probe = qcom_ramp_controller_probe,
- .remove_new = qcom_ramp_controller_remove,
+ .probe = qcom_ramp_controller_probe,
+ .remove = qcom_ramp_controller_remove,
};
static int __init qcom_ramp_controller_init(void)
diff --git a/drivers/soc/qcom/rmtfs_mem.c b/drivers/soc/qcom/rmtfs_mem.c
index df850d073102..1b32469f2789 100644
--- a/drivers/soc/qcom/rmtfs_mem.c
+++ b/drivers/soc/qcom/rmtfs_mem.c
@@ -125,7 +125,7 @@ static int qcom_rmtfs_mem_release(struct inode *inode, struct file *filp)
return 0;
}
-static struct class rmtfs_class = {
+static const struct class rmtfs_class = {
.name = "rmtfs",
};
@@ -315,7 +315,7 @@ MODULE_DEVICE_TABLE(of, qcom_rmtfs_mem_of_match);
static struct platform_driver qcom_rmtfs_mem_driver = {
.probe = qcom_rmtfs_mem_probe,
- .remove_new = qcom_rmtfs_mem_remove,
+ .remove = qcom_rmtfs_mem_remove,
.driver = {
.name = "qcom_rmtfs_mem",
.of_match_table = qcom_rmtfs_mem_of_match,
diff --git a/drivers/soc/qcom/rpm-proc.c b/drivers/soc/qcom/rpm-proc.c
index 2995d9b90190..2466d0400c2e 100644
--- a/drivers/soc/qcom/rpm-proc.c
+++ b/drivers/soc/qcom/rpm-proc.c
@@ -53,7 +53,7 @@ MODULE_DEVICE_TABLE(of, rpm_proc_of_match);
static struct platform_driver rpm_proc_driver = {
.probe = rpm_proc_probe,
- .remove_new = rpm_proc_remove,
+ .remove = rpm_proc_remove,
.driver = {
.name = "qcom-rpm-proc",
.of_match_table = rpm_proc_of_match,
diff --git a/drivers/soc/qcom/rpm_master_stats.c b/drivers/soc/qcom/rpm_master_stats.c
index 9ca13bcf67d3..49e4f9457279 100644
--- a/drivers/soc/qcom/rpm_master_stats.c
+++ b/drivers/soc/qcom/rpm_master_stats.c
@@ -148,10 +148,14 @@ static const struct of_device_id rpm_master_table[] = {
{ .compatible = "qcom,rpm-master-stats" },
{ },
};
+/*
+ * No MODULE_DEVICE_TABLE intentionally: that's a debugging module, to be
+ * loaded manually only.
+ */
static struct platform_driver master_stats_driver = {
.probe = master_stats_probe,
- .remove_new = master_stats_remove,
+ .remove = master_stats_remove,
.driver = {
.name = "qcom_rpm_master_stats",
.of_match_table = rpm_master_table,
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index a021dc71807b..cb82e887b51d 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#define pr_fmt(fmt) "%s " fmt, KBUILD_MODNAME
@@ -557,7 +558,7 @@ static int check_for_req_inflight(struct rsc_drv *drv, struct tcs_group *tcs,
for_each_set_bit(j, &curr_enabled, MAX_CMDS_PER_TCS) {
addr = read_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], i, j);
for (k = 0; k < msg->num_cmds; k++) {
- if (addr == msg->cmds[k].addr)
+ if (cmd_db_match_resource_addr(msg->cmds[k].addr, addr))
return -EBUSY;
}
}
@@ -645,13 +646,14 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
{
struct tcs_group *tcs;
int tcs_id;
- unsigned long flags;
+
+ might_sleep();
tcs = get_tcs_for_msg(drv, msg);
if (IS_ERR(tcs))
return PTR_ERR(tcs);
- spin_lock_irqsave(&drv->lock, flags);
+ spin_lock_irq(&drv->lock);
/* Wait forever for a free tcs. It better be there eventually! */
wait_event_lock_irq(drv->tcs_wait,
@@ -669,7 +671,7 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
write_tcs_reg_sync(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, 0);
enable_tcs_irq(drv, tcs_id, true);
}
- spin_unlock_irqrestore(&drv->lock, flags);
+ spin_unlock_irq(&drv->lock);
/*
* These two can be done after the lock is released because:
@@ -1043,12 +1045,9 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
* do. To avoid adding this check to our children we'll do it now.
*/
ret = cmd_db_ready();
- if (ret) {
- if (ret != -EPROBE_DEFER)
- dev_err(&pdev->dev, "Command DB not available (%d)\n",
- ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Command DB not available\n");
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
@@ -1154,7 +1153,7 @@ static int __init rpmh_driver_init(void)
{
return platform_driver_register(&rpmh_driver);
}
-arch_initcall(rpmh_driver_init);
+core_initcall(rpmh_driver_init);
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. RPMh Driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 9f26d7f9b9dc..8903ed956312 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -183,7 +183,6 @@ static int __rpmh_write(const struct device *dev, enum rpmh_state state,
}
if (state == RPMH_ACTIVE_ONLY_STATE) {
- WARN_ON(irqs_disabled());
ret = rpmh_rsc_send_data(ctrlr_to_drv(ctrlr), &rpm_msg->msg);
} else {
/* Clean up our call by spoofing tx_done */
diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c
index b7056aed4c7d..f2b3e02abdf1 100644
--- a/drivers/soc/qcom/smd-rpm.c
+++ b/drivers/soc/qcom/smd-rpm.c
@@ -196,9 +196,6 @@ static int qcom_smd_rpm_probe(struct rpmsg_device *rpdev)
{
struct qcom_smd_rpm *rpm;
- if (!rpdev->dev.of_node)
- return -EINVAL;
-
rpm = devm_kzalloc(&rpdev->dev, sizeof(*rpm), GFP_KERNEL);
if (!rpm)
return -ENOMEM;
@@ -218,18 +215,44 @@ static void qcom_smd_rpm_remove(struct rpmsg_device *rpdev)
of_platform_depopulate(&rpdev->dev);
}
-static const struct rpmsg_device_id qcom_smd_rpm_id_table[] = {
- { .name = "rpm_requests", },
- { /* sentinel */ }
+static const struct of_device_id qcom_smd_rpm_of_match[] = {
+ { .compatible = "qcom,glink-smd-rpm" },
+ { .compatible = "qcom,smd-rpm" },
+ /*
+ * Don't add any more compatibles to the list, two previous entryes
+ * should match all defined devices.
+ */
+ { .compatible = "qcom,rpm-apq8084" },
+ { .compatible = "qcom,rpm-ipq6018" },
+ { .compatible = "qcom,rpm-ipq9574" },
+ { .compatible = "qcom,rpm-msm8226" },
+ { .compatible = "qcom,rpm-msm8909" },
+ { .compatible = "qcom,rpm-msm8916" },
+ { .compatible = "qcom,rpm-msm8936" },
+ { .compatible = "qcom,rpm-msm8953" },
+ { .compatible = "qcom,rpm-msm8974" },
+ { .compatible = "qcom,rpm-msm8976" },
+ { .compatible = "qcom,rpm-msm8994" },
+ { .compatible = "qcom,rpm-msm8996" },
+ { .compatible = "qcom,rpm-msm8998" },
+ { .compatible = "qcom,rpm-sdm660" },
+ { .compatible = "qcom,rpm-sm6115" },
+ { .compatible = "qcom,rpm-sm6125" },
+ { .compatible = "qcom,rpm-sm6375" },
+ { .compatible = "qcom,rpm-qcm2290" },
+ { .compatible = "qcom,rpm-qcs404" },
+ {}
};
-MODULE_DEVICE_TABLE(rpmsg, qcom_smd_rpm_id_table);
+MODULE_DEVICE_TABLE(of, qcom_smd_rpm_of_match);
static struct rpmsg_driver qcom_smd_rpm_driver = {
.probe = qcom_smd_rpm_probe,
.remove = qcom_smd_rpm_remove,
.callback = qcom_smd_rpm_callback,
- .id_table = qcom_smd_rpm_id_table,
- .drv.name = "qcom_smd_rpm",
+ .drv = {
+ .name = "qcom_smd_rpm",
+ .of_match_table = qcom_smd_rpm_of_match,
+ },
};
static int __init qcom_smd_rpm_init(void)
diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c
index 690afc9a12f4..592819701809 100644
--- a/drivers/soc/qcom/smem.c
+++ b/drivers/soc/qcom/smem.c
@@ -359,6 +359,32 @@ static struct qcom_smem *__smem;
/* Timeout (ms) for the trylock of remote spinlocks */
#define HWSPINLOCK_TIMEOUT 1000
+/* The qcom hwspinlock id is always plus one from the smem host id */
+#define SMEM_HOST_ID_TO_HWSPINLOCK_ID(__x) ((__x) + 1)
+
+/**
+ * qcom_smem_bust_hwspin_lock_by_host() - bust the smem hwspinlock for a host
+ * @host: remote processor id
+ *
+ * Busts the hwspin_lock for the given smem host id. This helper is intended
+ * for remoteproc drivers that manage remoteprocs with an equivalent smem
+ * driver instance in the remote firmware. Drivers can force a release of the
+ * smem hwspin_lock if the rproc unexpectedly goes into a bad state.
+ *
+ * Context: Process context.
+ *
+ * Returns: 0 on success, otherwise negative errno.
+ */
+int qcom_smem_bust_hwspin_lock_by_host(unsigned int host)
+{
+ /* This function is for remote procs, so ignore SMEM_HOST_APPS */
+ if (host == SMEM_HOST_APPS || host >= SMEM_HOST_COUNT)
+ return -EINVAL;
+
+ return hwspin_lock_bust(__smem->hwlock, SMEM_HOST_ID_TO_HWSPINLOCK_ID(host));
+}
+EXPORT_SYMBOL_GPL(qcom_smem_bust_hwspin_lock_by_host);
+
/**
* qcom_smem_is_available() - Check if SMEM is available
*
@@ -473,6 +499,8 @@ static int qcom_smem_alloc_global(struct qcom_smem *smem,
*
* Allocate space for a given smem item of size @size, given that the item is
* not yet allocated.
+ *
+ * Return: 0 on success, negative errno on failure.
*/
int qcom_smem_alloc(unsigned host, unsigned item, size_t size)
{
@@ -651,12 +679,12 @@ invalid_canary:
*
* Looks up smem item and returns pointer to it. Size of smem
* item is returned in @size.
+ *
+ * Return: a pointer to an SMEM item on success, ERR_PTR() on failure.
*/
void *qcom_smem_get(unsigned host, unsigned item, size_t *size)
{
struct smem_partition *part;
- unsigned long flags;
- int ret;
void *ptr = ERR_PTR(-EPROBE_DEFER);
if (!__smem)
@@ -665,12 +693,6 @@ void *qcom_smem_get(unsigned host, unsigned item, size_t *size)
if (WARN_ON(item >= __smem->item_count))
return ERR_PTR(-EINVAL);
- ret = hwspin_lock_timeout_irqsave(__smem->hwlock,
- HWSPINLOCK_TIMEOUT,
- &flags);
- if (ret)
- return ERR_PTR(ret);
-
if (host < SMEM_HOST_COUNT && __smem->partitions[host].virt_base) {
part = &__smem->partitions[host];
ptr = qcom_smem_get_private(__smem, part, item, size);
@@ -681,10 +703,7 @@ void *qcom_smem_get(unsigned host, unsigned item, size_t *size)
ptr = qcom_smem_get_global(__smem, item, size);
}
- hwspin_unlock_irqrestore(__smem->hwlock, &flags);
-
return ptr;
-
}
EXPORT_SYMBOL_GPL(qcom_smem_get);
@@ -694,6 +713,8 @@ EXPORT_SYMBOL_GPL(qcom_smem_get);
*
* To be used by smem clients as a quick way to determine if any new
* allocations has been made.
+ *
+ * Return: number of available bytes on success, negative errno on failure.
*/
int qcom_smem_get_free_space(unsigned host)
{
@@ -743,7 +764,7 @@ static bool addr_in_range(void __iomem *base, size_t size, void *addr)
* with an smem item pointer (previously returned by qcom_smem_get()
* @p: the virtual address to convert
*
- * Returns 0 if the pointer provided is not within any smem region.
+ * Return: physical address of the SMEM item (if found), 0 otherwise
*/
phys_addr_t qcom_smem_virt_to_phys(void *p)
{
@@ -806,6 +827,39 @@ int qcom_smem_get_soc_id(u32 *id)
}
EXPORT_SYMBOL_GPL(qcom_smem_get_soc_id);
+/**
+ * qcom_smem_get_feature_code() - return the feature code
+ * @code: On success, return the feature code here.
+ *
+ * Look up the feature code identifier from SMEM and return it.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int qcom_smem_get_feature_code(u32 *code)
+{
+ struct socinfo *info;
+ u32 raw_code;
+
+ info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_HW_SW_BUILD_ID, NULL);
+ if (IS_ERR(info))
+ return PTR_ERR(info);
+
+ /* This only makes sense for socinfo >= 16 */
+ if (__le32_to_cpu(info->fmt) < SOCINFO_VERSION(0, 16))
+ return -EOPNOTSUPP;
+
+ raw_code = __le32_to_cpu(info->feature_code);
+
+ /* Ensure the value makes sense */
+ if (raw_code > SOCINFO_FC_INT_MAX)
+ raw_code = SOCINFO_FC_UNKNOWN;
+
+ *code = raw_code;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_smem_get_feature_code);
+
static int qcom_smem_get_sbl_version(struct qcom_smem *smem)
{
struct smem_header *header;
@@ -1132,11 +1186,9 @@ static int qcom_smem_probe(struct platform_device *pdev)
}
hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0);
- if (hwlock_id < 0) {
- if (hwlock_id != -EPROBE_DEFER)
- dev_err(&pdev->dev, "failed to retrieve hwlock\n");
- return hwlock_id;
- }
+ if (hwlock_id < 0)
+ return dev_err_probe(&pdev->dev, hwlock_id,
+ "failed to retrieve hwlock\n");
smem->hwlock = hwspin_lock_request_specific(hwlock_id);
if (!smem->hwlock)
@@ -1203,7 +1255,7 @@ MODULE_DEVICE_TABLE(of, qcom_smem_of_match);
static struct platform_driver qcom_smem_driver = {
.probe = qcom_smem_probe,
- .remove_new = qcom_smem_remove,
+ .remove = qcom_smem_remove,
.driver = {
.name = "qcom-smem",
.of_match_table = qcom_smem_of_match,
diff --git a/drivers/soc/qcom/smem_state.c b/drivers/soc/qcom/smem_state.c
index e848cc9a3cf8..cc5be8019b6a 100644
--- a/drivers/soc/qcom/smem_state.c
+++ b/drivers/soc/qcom/smem_state.c
@@ -3,6 +3,7 @@
* Copyright (c) 2015, Sony Mobile Communications Inc.
* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*/
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/module.h>
@@ -60,20 +61,15 @@ static struct qcom_smem_state *of_node_to_state(struct device_node *np)
{
struct qcom_smem_state *state;
- mutex_lock(&list_lock);
+ guard(mutex)(&list_lock);
list_for_each_entry(state, &smem_states, list) {
if (state->of_node == np) {
kref_get(&state->refcount);
- goto unlock;
+ return state;
}
}
- state = ERR_PTR(-EPROBE_DEFER);
-
-unlock:
- mutex_unlock(&list_lock);
-
- return state;
+ return ERR_PTR(-EPROBE_DEFER);
}
/**
@@ -116,7 +112,8 @@ struct qcom_smem_state *qcom_smem_state_get(struct device *dev,
if (args.args_count != 1) {
dev_err(dev, "invalid #qcom,smem-state-cells\n");
- return ERR_PTR(-EINVAL);
+ state = ERR_PTR(-EINVAL);
+ goto put;
}
state = of_node_to_state(args.np);
diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c
index 914b2246148f..a3e88ced328a 100644
--- a/drivers/soc/qcom/smp2p.c
+++ b/drivers/soc/qcom/smp2p.c
@@ -16,6 +16,7 @@
#include <linux/platform_device.h>
#include <linux/pm_wakeirq.h>
#include <linux/regmap.h>
+#include <linux/seq_file.h>
#include <linux/soc/qcom/smem.h>
#include <linux/soc/qcom/smem_state.h>
#include <linux/spinlock.h>
@@ -58,8 +59,8 @@
* @valid_entries: number of allocated entries
* @flags:
* @entries: individual communication entries
- * @name: name of the entry
- * @value: content of the entry
+ * @entries.name: name of the entry
+ * @entries.value: content of the entry
*/
struct smp2p_smem_item {
u32 magic;
@@ -160,6 +161,9 @@ struct qcom_smp2p {
struct list_head outbound;
};
+#define CREATE_TRACE_POINTS
+#include "trace-smp2p.h"
+
static void qcom_smp2p_kick(struct qcom_smp2p *smp2p)
{
/* Make sure any updated data is written before the kick */
@@ -191,6 +195,7 @@ static void qcom_smp2p_do_ssr_ack(struct qcom_smp2p *smp2p)
struct smp2p_smem_item *out = smp2p->out;
u32 val;
+ trace_smp2p_ssr_ack(smp2p->dev);
smp2p->ssr_ack = !smp2p->ssr_ack;
val = out->flags & ~BIT(SMP2P_FLAGS_RESTART_ACK_BIT);
@@ -213,6 +218,7 @@ static void qcom_smp2p_negotiate(struct qcom_smp2p *smp2p)
smp2p->ssr_ack_enabled = true;
smp2p->negotiation_done = true;
+ trace_smp2p_negotiate(smp2p->dev, out->features);
}
}
@@ -251,6 +257,8 @@ static void qcom_smp2p_notify_in(struct qcom_smp2p *smp2p)
status = val ^ entry->last_value;
entry->last_value = val;
+ trace_smp2p_notify_in(entry, status, val);
+
/* No changes of this entry? */
if (!status)
continue;
@@ -275,6 +283,8 @@ static void qcom_smp2p_notify_in(struct qcom_smp2p *smp2p)
*
* Handle notifications from the remote side to handle newly allocated entries
* or any changes to the state bits of existing entries.
+ *
+ * Return: %IRQ_HANDLED
*/
static irqreturn_t qcom_smp2p_intr(int irq, void *data)
{
@@ -351,11 +361,19 @@ static int smp2p_set_irq_type(struct irq_data *irqd, unsigned int type)
return 0;
}
+static void smp2p_irq_print_chip(struct irq_data *irqd, struct seq_file *p)
+{
+ struct smp2p_entry *entry = irq_data_get_irq_chip_data(irqd);
+
+ seq_printf(p, "%8s", dev_name(entry->smp2p->dev));
+}
+
static struct irq_chip smp2p_irq_chip = {
.name = "smp2p",
.irq_mask = smp2p_mask_irq,
.irq_unmask = smp2p_unmask_irq,
.irq_set_type = smp2p_set_irq_type,
+ .irq_print_chip = smp2p_irq_print_chip,
};
static int smp2p_irq_map(struct irq_domain *d,
@@ -404,6 +422,8 @@ static int smp2p_update_bits(void *data, u32 mask, u32 value)
writel(val, entry->value);
spin_unlock_irqrestore(&entry->lock, flags);
+ trace_smp2p_update_bits(entry, orig, val);
+
if (val != orig)
qcom_smp2p_kick(entry->smp2p);
@@ -447,12 +467,9 @@ static int qcom_smp2p_alloc_outbound_item(struct qcom_smp2p *smp2p)
int ret;
ret = qcom_smem_alloc(pid, smem_id, sizeof(*out));
- if (ret < 0 && ret != -EEXIST) {
- if (ret != -EPROBE_DEFER)
- dev_err(smp2p->dev,
- "unable to allocate local smp2p item\n");
- return ret;
- }
+ if (ret < 0 && ret != -EEXIST)
+ return dev_err_probe(smp2p->dev, ret,
+ "unable to allocate local smp2p item\n");
out = qcom_smem_get(pid, smem_id, NULL);
if (IS_ERR(out)) {
@@ -519,7 +536,6 @@ static int smp2p_parse_ipc(struct qcom_smp2p *smp2p)
static int qcom_smp2p_probe(struct platform_device *pdev)
{
struct smp2p_entry *entry;
- struct device_node *node;
struct qcom_smp2p *smp2p;
const char *key;
int irq;
@@ -573,11 +589,10 @@ static int qcom_smp2p_probe(struct platform_device *pdev)
if (ret < 0)
goto release_mbox;
- for_each_available_child_of_node(pdev->dev.of_node, node) {
+ for_each_available_child_of_node_scoped(pdev->dev.of_node, node) {
entry = devm_kzalloc(&pdev->dev, sizeof(*entry), GFP_KERNEL);
if (!entry) {
ret = -ENOMEM;
- of_node_put(node);
goto unwind_interfaces;
}
@@ -585,25 +600,19 @@ static int qcom_smp2p_probe(struct platform_device *pdev)
spin_lock_init(&entry->lock);
ret = of_property_read_string(node, "qcom,entry-name", &entry->name);
- if (ret < 0) {
- of_node_put(node);
+ if (ret < 0)
goto unwind_interfaces;
- }
if (of_property_read_bool(node, "interrupt-controller")) {
ret = qcom_smp2p_inbound_entry(smp2p, entry, node);
- if (ret < 0) {
- of_node_put(node);
+ if (ret < 0)
goto unwind_interfaces;
- }
list_add(&entry->node, &smp2p->inbound);
} else {
ret = qcom_smp2p_outbound_entry(smp2p, entry, node);
- if (ret < 0) {
- of_node_put(node);
+ if (ret < 0)
goto unwind_interfaces;
- }
list_add(&entry->node, &smp2p->outbound);
}
@@ -615,7 +624,7 @@ static int qcom_smp2p_probe(struct platform_device *pdev)
ret = devm_request_threaded_irq(&pdev->dev, irq,
NULL, qcom_smp2p_intr,
IRQF_ONESHOT,
- "smp2p", (void *)smp2p);
+ NULL, (void *)smp2p);
if (ret) {
dev_err(&pdev->dev, "failed to request interrupt\n");
goto unwind_interfaces;
@@ -686,7 +695,7 @@ MODULE_DEVICE_TABLE(of, qcom_smp2p_of_match);
static struct platform_driver qcom_smp2p_driver = {
.probe = qcom_smp2p_probe,
- .remove_new = qcom_smp2p_remove,
+ .remove = qcom_smp2p_remove,
.driver = {
.name = "qcom_smp2p",
.of_match_table = qcom_smp2p_of_match,
diff --git a/drivers/soc/qcom/smsm.c b/drivers/soc/qcom/smsm.c
index e7c7e9a640a6..e803ea342c97 100644
--- a/drivers/soc/qcom/smsm.c
+++ b/drivers/soc/qcom/smsm.c
@@ -5,6 +5,7 @@
*/
#include <linux/interrupt.h>
+#include <linux/mailbox_client.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_irq.h>
@@ -71,6 +72,7 @@ struct smsm_host;
* @lock: spinlock for read-modify-write of the outgoing state
* @entries: context for each of the entries
* @hosts: context for each of the hosts
+ * @mbox_client: mailbox client handle
*/
struct qcom_smsm {
struct device *dev;
@@ -88,6 +90,8 @@ struct qcom_smsm {
struct smsm_entry *entries;
struct smsm_host *hosts;
+
+ struct mbox_client mbox_client;
};
/**
@@ -120,11 +124,14 @@ struct smsm_entry {
* @ipc_regmap: regmap for outgoing interrupt
* @ipc_offset: offset in @ipc_regmap for outgoing interrupt
* @ipc_bit: bit in @ipc_regmap + @ipc_offset for outgoing interrupt
+ * @mbox_chan: apcs ipc mailbox channel handle
*/
struct smsm_host {
struct regmap *ipc_regmap;
int ipc_offset;
int ipc_bit;
+
+ struct mbox_chan *mbox_chan;
};
/**
@@ -172,7 +179,13 @@ static int smsm_update_bits(void *data, u32 mask, u32 value)
hostp = &smsm->hosts[host];
val = readl(smsm->subscription + host);
- if (val & changes && hostp->ipc_regmap) {
+ if (!(val & changes))
+ continue;
+
+ if (hostp->mbox_chan) {
+ mbox_send_message(hostp->mbox_chan, NULL);
+ mbox_client_txdone(hostp->mbox_chan, 0);
+ } else if (hostp->ipc_regmap) {
regmap_write(hostp->ipc_regmap,
hostp->ipc_offset,
BIT(hostp->ipc_bit));
@@ -353,6 +366,28 @@ static const struct irq_domain_ops smsm_irq_ops = {
};
/**
+ * smsm_parse_mbox() - requests an mbox channel
+ * @smsm: smsm driver context
+ * @host_id: index of the remote host to be resolved
+ *
+ * Requests the desired channel using the mbox interface which is needed for
+ * sending the outgoing interrupts to a remove hosts - identified by @host_id.
+ */
+static int smsm_parse_mbox(struct qcom_smsm *smsm, unsigned int host_id)
+{
+ struct smsm_host *host = &smsm->hosts[host_id];
+ int ret = 0;
+
+ host->mbox_chan = mbox_request_channel(&smsm->mbox_client, host_id);
+ if (IS_ERR(host->mbox_chan)) {
+ ret = PTR_ERR(host->mbox_chan);
+ host->mbox_chan = NULL;
+ }
+
+ return ret;
+}
+
+/**
* smsm_parse_ipc() - parses a qcom,ipc-%d device tree property
* @smsm: smsm driver context
* @host_id: index of the remote host to be resolved
@@ -521,8 +556,16 @@ static int qcom_smsm_probe(struct platform_device *pdev)
"qcom,local-host",
&smsm->local_host);
+ smsm->mbox_client.dev = &pdev->dev;
+ smsm->mbox_client.knows_txdone = true;
+
/* Parse the host properties */
for (id = 0; id < smsm->num_hosts; id++) {
+ /* Try using mbox interface first, otherwise fall back to syscon */
+ ret = smsm_parse_mbox(smsm, id);
+ if (!ret)
+ continue;
+
ret = smsm_parse_ipc(smsm, id);
if (ret < 0)
goto out_put;
@@ -609,6 +652,9 @@ unwind_interfaces:
qcom_smem_state_unregister(smsm->state);
out_put:
+ for (id = 0; id < smsm->num_hosts; id++)
+ mbox_free_channel(smsm->hosts[id].mbox_chan);
+
of_node_put(local_node);
return ret;
}
@@ -622,6 +668,9 @@ static void qcom_smsm_remove(struct platform_device *pdev)
if (smsm->entries[id].domain)
irq_domain_remove(smsm->entries[id].domain);
+ for (id = 0; id < smsm->num_hosts; id++)
+ mbox_free_channel(smsm->hosts[id].mbox_chan);
+
qcom_smem_state_unregister(smsm->state);
}
@@ -633,9 +682,9 @@ MODULE_DEVICE_TABLE(of, qcom_smsm_of_match);
static struct platform_driver qcom_smsm_driver = {
.probe = qcom_smsm_probe,
- .remove_new = qcom_smsm_remove,
- .driver = {
- .name = "qcom-smsm",
+ .remove = qcom_smsm_remove,
+ .driver = {
+ .name = "qcom-smsm",
.of_match_table = qcom_smsm_of_match,
},
};
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 6349a0debeb5..18d7f1be9093 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -17,18 +17,10 @@
#include <linux/sys_soc.h>
#include <linux/types.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <dt-bindings/arm/qcom,ids.h>
-/*
- * SoC version type with major number in the upper 16 bits and minor
- * number in the lower 16 bits.
- */
-#define SOCINFO_MAJOR(ver) (((ver) >> 16) & 0xffff)
-#define SOCINFO_MINOR(ver) ((ver) & 0xffff)
-#define SOCINFO_VERSION(maj, min) ((((maj) & 0xffff) << 16)|((min) & 0xffff))
-
/* Helper macros to create soc_id table */
#define qcom_board_id(id) QCOM_ID_ ## id, __stringify(id)
#define qcom_board_id_named(id, name) QCOM_ID_ ## id, (name)
@@ -124,7 +116,8 @@ static const char *const pmic_models[] = {
[50] = "PM8350B",
[51] = "PMR735A",
[52] = "PMR735B",
- [55] = "PM2250",
+ [54] = "PM6350",
+ [55] = "PM4125",
[58] = "PM8450",
[65] = "PM8010",
[69] = "PM8550VS",
@@ -133,6 +126,8 @@ static const char *const pmic_models[] = {
[72] = "PMR735D",
[73] = "PM8550",
[74] = "PMK8550",
+ [82] = "PMC8380",
+ [83] = "SMB2360",
};
struct socinfo_params {
@@ -347,6 +342,7 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(SDA630) },
{ qcom_board_id(MSM8905) },
{ qcom_board_id(SDX202) },
+ { qcom_board_id(SDM670) },
{ qcom_board_id(SDM450) },
{ qcom_board_id(SM8150) },
{ qcom_board_id(SDA845) },
@@ -405,11 +401,13 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(SA8540P) },
{ qcom_board_id(QCM4290) },
{ qcom_board_id(QCS4290) },
+ { qcom_board_id(SM7325) },
{ qcom_board_id_named(SM8450_2, "SM8450") },
{ qcom_board_id_named(SM8450_3, "SM8450") },
{ qcom_board_id(SC7280) },
{ qcom_board_id(SC7180P) },
{ qcom_board_id(QCM6490) },
+ { qcom_board_id(SM7325P) },
{ qcom_board_id(IPQ5000) },
{ qcom_board_id(IPQ0509) },
{ qcom_board_id(IPQ0518) },
@@ -424,11 +422,18 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(IPQ9510) },
{ qcom_board_id(QRB4210) },
{ qcom_board_id(QRB2210) },
+ { qcom_board_id(SAR2130P) },
+ { qcom_board_id(SM8475) },
+ { qcom_board_id(SM8475P) },
+ { qcom_board_id(SA8255P) },
{ qcom_board_id(SA8775P) },
{ qcom_board_id(QRU1000) },
+ { qcom_board_id(SM8475_2) },
{ qcom_board_id(QDU1000) },
+ { qcom_board_id(X1E80100) },
{ qcom_board_id(SM8650) },
{ qcom_board_id(SM4450) },
+ { qcom_board_id(SAR1130P) },
{ qcom_board_id(QDU1010) },
{ qcom_board_id(QRU1032) },
{ qcom_board_id(QRU1052) },
@@ -437,7 +442,17 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(IPQ5322) },
{ qcom_board_id(IPQ5312) },
{ qcom_board_id(IPQ5302) },
+ { qcom_board_id(QCS8550) },
+ { qcom_board_id(QCM8550) },
{ qcom_board_id(IPQ5300) },
+ { qcom_board_id(IPQ5321) },
+ { qcom_board_id(IPQ5424) },
+ { qcom_board_id(IPQ5404) },
+ { qcom_board_id(QCS9100) },
+ { qcom_board_id(QCS8300) },
+ { qcom_board_id(QCS8275) },
+ { qcom_board_id(QCS9075) },
+ { qcom_board_id(QCS615) },
};
static const char *socinfo_machine(struct device *dev, unsigned int id)
@@ -779,10 +794,16 @@ static int qcom_socinfo_probe(struct platform_device *pdev)
qs->attr.revision = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%u.%u",
SOCINFO_MAJOR(le32_to_cpu(info->ver)),
SOCINFO_MINOR(le32_to_cpu(info->ver)));
- if (offsetof(struct socinfo, serial_num) <= item_size)
+ if (!qs->attr.soc_id || !qs->attr.revision)
+ return -ENOMEM;
+
+ if (offsetofend(struct socinfo, serial_num) <= item_size) {
qs->attr.serial_number = devm_kasprintf(&pdev->dev, GFP_KERNEL,
"%u",
le32_to_cpu(info->serial_num));
+ if (!qs->attr.serial_number)
+ return -ENOMEM;
+ }
qs->soc_dev = soc_device_register(&qs->attr);
if (IS_ERR(qs->soc_dev))
@@ -809,7 +830,7 @@ static void qcom_socinfo_remove(struct platform_device *pdev)
static struct platform_driver qcom_socinfo_driver = {
.probe = qcom_socinfo_probe,
- .remove_new = qcom_socinfo_remove,
+ .remove = qcom_socinfo_remove,
.driver = {
.name = "qcom-socinfo",
},
diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c
index 2f0b1bfe7658..f75659fff287 100644
--- a/drivers/soc/qcom/spm.c
+++ b/drivers/soc/qcom/spm.c
@@ -6,20 +6,40 @@
* SAW power controller driver
*/
-#include <linux/kernel.h>
+#include <linux/bitfield.h>
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/linear_range.h>
#include <linux/module.h>
-#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/err.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+
+#include <linux/regulator/driver.h>
+
#include <soc/qcom/spm.h>
+#define FIELD_SET(current, mask, val) \
+ (((current) & ~(mask)) | FIELD_PREP((mask), (val)))
+
#define SPM_CTL_INDEX 0x7f
#define SPM_CTL_INDEX_SHIFT 4
#define SPM_CTL_EN BIT(0)
+/* These registers might be specific to SPM 1.1 */
+#define SPM_VCTL_VLVL GENMASK(7, 0)
+#define SPM_PMIC_DATA_0_VLVL GENMASK(7, 0)
+#define SPM_PMIC_DATA_1_MIN_VSEL GENMASK(5, 0)
+#define SPM_PMIC_DATA_1_MAX_VSEL GENMASK(21, 16)
+
+#define SPM_1_1_AVS_CTL_AVS_ENABLED BIT(27)
+#define SPM_AVS_CTL_MAX_VLVL GENMASK(22, 17)
+#define SPM_AVS_CTL_MIN_VLVL GENMASK(15, 10)
+
enum spm_reg {
SPM_REG_CFG,
SPM_REG_SPM_CTL,
@@ -29,13 +49,44 @@ enum spm_reg {
SPM_REG_PMIC_DATA_1,
SPM_REG_VCTL,
SPM_REG_SEQ_ENTRY,
- SPM_REG_SPM_STS,
+ SPM_REG_STS0,
+ SPM_REG_STS1,
SPM_REG_PMIC_STS,
SPM_REG_AVS_CTL,
SPM_REG_AVS_LIMIT,
+ SPM_REG_RST,
SPM_REG_NR,
};
+#define MAX_PMIC_DATA 2
+#define MAX_SEQ_DATA 64
+
+struct spm_reg_data {
+ const u16 *reg_offset;
+ u32 spm_cfg;
+ u32 spm_dly;
+ u32 pmic_dly;
+ u32 pmic_data[MAX_PMIC_DATA];
+ u32 avs_ctl;
+ u32 avs_limit;
+ u8 seq[MAX_SEQ_DATA];
+ u8 start_index[PM_SLEEP_MODE_NR];
+
+ smp_call_func_t set_vdd;
+ /* for now we support only a single range */
+ struct linear_range *range;
+ unsigned int ramp_delay;
+ unsigned int init_uV;
+};
+
+struct spm_driver_data {
+ void __iomem *reg_base;
+ const struct spm_reg_data *reg_data;
+ struct device *dev;
+ unsigned int volt_sel;
+ int reg_cpu;
+};
+
static const u16 spm_reg_offset_v4_1[SPM_REG_NR] = {
[SPM_REG_AVS_CTL] = 0x904,
[SPM_REG_AVS_LIMIT] = 0x908,
@@ -169,6 +220,10 @@ static const struct spm_reg_data spm_reg_8226_cpu = {
static const u16 spm_reg_offset_v1_1[SPM_REG_NR] = {
[SPM_REG_CFG] = 0x08,
+ [SPM_REG_STS0] = 0x0c,
+ [SPM_REG_STS1] = 0x10,
+ [SPM_REG_VCTL] = 0x14,
+ [SPM_REG_AVS_CTL] = 0x18,
[SPM_REG_SPM_CTL] = 0x20,
[SPM_REG_PMIC_DLY] = 0x24,
[SPM_REG_PMIC_DATA_0] = 0x28,
@@ -176,7 +231,12 @@ static const u16 spm_reg_offset_v1_1[SPM_REG_NR] = {
[SPM_REG_SEQ_ENTRY] = 0x80,
};
+static void smp_set_vdd_v1_1(void *data);
+
/* SPM register data for 8064 */
+static struct linear_range spm_v1_1_regulator_range =
+ REGULATOR_LINEAR_RANGE(700000, 0, 56, 12500);
+
static const struct spm_reg_data spm_reg_8064_cpu = {
.reg_offset = spm_reg_offset_v1_1,
.spm_cfg = 0x1F,
@@ -187,6 +247,10 @@ static const struct spm_reg_data spm_reg_8064_cpu = {
0x10, 0x54, 0x30, 0x0C, 0x24, 0x30, 0x0F },
.start_index[PM_SLEEP_MODE_STBY] = 0,
.start_index[PM_SLEEP_MODE_SPC] = 2,
+ .set_vdd = smp_set_vdd_v1_1,
+ .range = &spm_v1_1_regulator_range,
+ .init_uV = 1300000,
+ .ramp_delay = 1250,
};
static inline void spm_register_write(struct spm_driver_data *drv,
@@ -238,6 +302,178 @@ void spm_set_low_power_mode(struct spm_driver_data *drv,
spm_register_write_sync(drv, SPM_REG_SPM_CTL, ctl_val);
}
+static int spm_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector)
+{
+ struct spm_driver_data *drv = rdev_get_drvdata(rdev);
+
+ drv->volt_sel = selector;
+
+ /* Always do the SAW register writes on the corresponding CPU */
+ return smp_call_function_single(drv->reg_cpu, drv->reg_data->set_vdd, drv, true);
+}
+
+static int spm_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct spm_driver_data *drv = rdev_get_drvdata(rdev);
+
+ return drv->volt_sel;
+}
+
+static const struct regulator_ops spm_reg_ops = {
+ .set_voltage_sel = spm_set_voltage_sel,
+ .get_voltage_sel = spm_get_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static void smp_set_vdd_v1_1(void *data)
+{
+ struct spm_driver_data *drv = data;
+ unsigned int vctl, data0, data1, avs_ctl, sts;
+ unsigned int vlevel, volt_sel;
+ bool avs_enabled;
+
+ volt_sel = drv->volt_sel;
+ vlevel = volt_sel | 0x80; /* band */
+
+ avs_ctl = spm_register_read(drv, SPM_REG_AVS_CTL);
+ vctl = spm_register_read(drv, SPM_REG_VCTL);
+ data0 = spm_register_read(drv, SPM_REG_PMIC_DATA_0);
+ data1 = spm_register_read(drv, SPM_REG_PMIC_DATA_1);
+
+ avs_enabled = avs_ctl & SPM_1_1_AVS_CTL_AVS_ENABLED;
+
+ /* If AVS is enabled, switch it off during the voltage change */
+ if (avs_enabled) {
+ avs_ctl &= ~SPM_1_1_AVS_CTL_AVS_ENABLED;
+ spm_register_write(drv, SPM_REG_AVS_CTL, avs_ctl);
+ }
+
+ /* Kick the state machine back to idle */
+ spm_register_write(drv, SPM_REG_RST, 1);
+
+ vctl = FIELD_SET(vctl, SPM_VCTL_VLVL, vlevel);
+ data0 = FIELD_SET(data0, SPM_PMIC_DATA_0_VLVL, vlevel);
+ data1 = FIELD_SET(data1, SPM_PMIC_DATA_1_MIN_VSEL, volt_sel);
+ data1 = FIELD_SET(data1, SPM_PMIC_DATA_1_MAX_VSEL, volt_sel);
+
+ spm_register_write(drv, SPM_REG_VCTL, vctl);
+ spm_register_write(drv, SPM_REG_PMIC_DATA_0, data0);
+ spm_register_write(drv, SPM_REG_PMIC_DATA_1, data1);
+
+ if (read_poll_timeout_atomic(spm_register_read,
+ sts, sts == vlevel,
+ 1, 200, false,
+ drv, SPM_REG_STS1)) {
+ dev_err_ratelimited(drv->dev, "timeout setting the voltage (%x %x)!\n", sts, vlevel);
+ goto enable_avs;
+ }
+
+ if (avs_enabled) {
+ unsigned int max_avs = volt_sel;
+ unsigned int min_avs = max(max_avs, 4U) - 4;
+
+ avs_ctl = FIELD_SET(avs_ctl, SPM_AVS_CTL_MIN_VLVL, min_avs);
+ avs_ctl = FIELD_SET(avs_ctl, SPM_AVS_CTL_MAX_VLVL, max_avs);
+ spm_register_write(drv, SPM_REG_AVS_CTL, avs_ctl);
+ }
+
+enable_avs:
+ if (avs_enabled) {
+ avs_ctl |= SPM_1_1_AVS_CTL_AVS_ENABLED;
+ spm_register_write(drv, SPM_REG_AVS_CTL, avs_ctl);
+ }
+}
+
+static int spm_get_cpu(struct device *dev)
+{
+ int cpu;
+ bool found;
+
+ for_each_possible_cpu(cpu) {
+ struct device_node *cpu_node, *saw_node;
+
+ cpu_node = of_cpu_device_node_get(cpu);
+ if (!cpu_node)
+ continue;
+
+ saw_node = of_parse_phandle(cpu_node, "qcom,saw", 0);
+ found = (saw_node == dev->of_node);
+ of_node_put(saw_node);
+ of_node_put(cpu_node);
+
+ if (found)
+ return cpu;
+ }
+
+ /* L2 SPM is not bound to any CPU, voltage setting is not supported */
+
+ return -EOPNOTSUPP;
+}
+
+static int spm_register_regulator(struct device *dev, struct spm_driver_data *drv)
+{
+ struct regulator_config config = {
+ .dev = dev,
+ .driver_data = drv,
+ };
+ struct regulator_desc *rdesc;
+ struct regulator_dev *rdev;
+ int ret;
+ bool found;
+
+ if (!drv->reg_data->set_vdd)
+ return 0;
+
+ rdesc = devm_kzalloc(dev, sizeof(*rdesc), GFP_KERNEL);
+ if (!rdesc)
+ return -ENOMEM;
+
+ rdesc->name = "spm";
+ rdesc->of_match = of_match_ptr("regulator");
+ rdesc->type = REGULATOR_VOLTAGE;
+ rdesc->owner = THIS_MODULE;
+ rdesc->ops = &spm_reg_ops;
+
+ rdesc->linear_ranges = drv->reg_data->range;
+ rdesc->n_linear_ranges = 1;
+ rdesc->n_voltages = rdesc->linear_ranges[rdesc->n_linear_ranges - 1].max_sel + 1;
+ rdesc->ramp_delay = drv->reg_data->ramp_delay;
+
+ ret = spm_get_cpu(dev);
+ if (ret < 0)
+ return ret;
+
+ drv->reg_cpu = ret;
+ dev_dbg(dev, "SAW2 bound to CPU %d\n", drv->reg_cpu);
+
+ /*
+ * Program initial voltage, otherwise registration will also try
+ * setting the voltage, which might result in undervolting the CPU.
+ */
+ drv->volt_sel = DIV_ROUND_UP(drv->reg_data->init_uV - rdesc->min_uV,
+ rdesc->uV_step);
+ ret = linear_range_get_selector_high(drv->reg_data->range,
+ drv->reg_data->init_uV,
+ &drv->volt_sel,
+ &found);
+ if (ret) {
+ dev_err(dev, "Initial uV value out of bounds\n");
+ return ret;
+ }
+
+ /* Always do the SAW register writes on the corresponding CPU */
+ smp_call_function_single(drv->reg_cpu, drv->reg_data->set_vdd, drv, true);
+
+ rdev = devm_regulator_register(dev, rdesc, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(dev, "failed to register regulator\n");
+ return PTR_ERR(rdev);
+ }
+
+ return 0;
+}
+
static const struct of_device_id spm_match_table[] = {
{ .compatible = "qcom,sdm660-gold-saw2-v4.1-l2",
.data = &spm_reg_660_gold_l2 },
@@ -288,6 +524,7 @@ static int spm_dev_probe(struct platform_device *pdev)
return -ENODEV;
drv->reg_data = match_id->data;
+ drv->dev = &pdev->dev;
platform_set_drvdata(pdev, drv);
/* Write the SPM sequences first.. */
@@ -315,6 +552,9 @@ static int spm_dev_probe(struct platform_device *pdev)
if (drv->reg_data->reg_offset[SPM_REG_SPM_CTL])
spm_set_low_power_mode(drv, PM_SLEEP_MODE_STBY);
+ if (IS_ENABLED(CONFIG_REGULATOR))
+ return spm_register_regulator(&pdev->dev, drv);
+
return 0;
}
@@ -332,4 +572,5 @@ static int __init qcom_spm_init(void)
}
arch_initcall(qcom_spm_init);
+MODULE_DESCRIPTION("Qualcomm Subsystem Power Manager (SPM)");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/trace-aoss.h b/drivers/soc/qcom/trace-aoss.h
new file mode 100644
index 000000000000..fb5b0470c40d
--- /dev/null
+++ b/drivers/soc/qcom/trace-aoss.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM qcom_aoss
+
+#if !defined(_TRACE_QCOM_AOSS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_QCOM_AOSS_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(aoss_send,
+ TP_PROTO(const char *msg),
+ TP_ARGS(msg),
+ TP_STRUCT__entry(
+ __string(msg, msg)
+ ),
+ TP_fast_assign(
+ __assign_str(msg);
+ ),
+ TP_printk("%s", __get_str(msg))
+);
+
+TRACE_EVENT(aoss_send_done,
+ TP_PROTO(const char *msg, int ret),
+ TP_ARGS(msg, ret),
+ TP_STRUCT__entry(
+ __string(msg, msg)
+ __field(int, ret)
+ ),
+ TP_fast_assign(
+ __assign_str(msg);
+ __entry->ret = ret;
+ ),
+ TP_printk("%s: %d", __get_str(msg), __entry->ret)
+);
+
+#endif /* _TRACE_QCOM_AOSS_H */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace-aoss
+
+#include <trace/define_trace.h>
diff --git a/drivers/soc/qcom/trace-rpmh.h b/drivers/soc/qcom/trace-rpmh.h
index be6b42ecc1f8..593ec1d4e010 100644
--- a/drivers/soc/qcom/trace-rpmh.h
+++ b/drivers/soc/qcom/trace-rpmh.h
@@ -26,7 +26,7 @@ TRACE_EVENT(rpmh_tx_done,
),
TP_fast_assign(
- __assign_str(name, d->name);
+ __assign_str(name);
__entry->m = m;
__entry->addr = r->cmds[0].addr;
__entry->data = r->cmds[0].data;
@@ -55,7 +55,7 @@ TRACE_EVENT(rpmh_send_msg,
),
TP_fast_assign(
- __assign_str(name, d->name);
+ __assign_str(name);
__entry->m = m;
__entry->state = state;
__entry->n = n;
diff --git a/drivers/soc/qcom/trace-smp2p.h b/drivers/soc/qcom/trace-smp2p.h
new file mode 100644
index 000000000000..9a6392043f10
--- /dev/null
+++ b/drivers/soc/qcom/trace-smp2p.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM qcom_smp2p
+
+#if !defined(__QCOM_SMP2P_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ)
+#define __QCOM_SMP2P_TRACE_H__
+
+#include <linux/device.h>
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(smp2p_ssr_ack,
+ TP_PROTO(const struct device *dev),
+ TP_ARGS(dev),
+ TP_STRUCT__entry(
+ __string(dev_name, dev_name(dev))
+ ),
+ TP_fast_assign(
+ __assign_str(dev_name);
+ ),
+ TP_printk("%s: SSR detected", __get_str(dev_name))
+);
+
+TRACE_EVENT(smp2p_negotiate,
+ TP_PROTO(const struct device *dev, unsigned int features),
+ TP_ARGS(dev, features),
+ TP_STRUCT__entry(
+ __string(dev_name, dev_name(dev))
+ __field(u32, out_features)
+ ),
+ TP_fast_assign(
+ __assign_str(dev_name);
+ __entry->out_features = features;
+ ),
+ TP_printk("%s: state=open out_features=%s", __get_str(dev_name),
+ __print_flags(__entry->out_features, "|",
+ {SMP2P_FEATURE_SSR_ACK, "SMP2P_FEATURE_SSR_ACK"})
+ )
+);
+
+TRACE_EVENT(smp2p_notify_in,
+ TP_PROTO(struct smp2p_entry *smp2p_entry, unsigned long status, u32 val),
+ TP_ARGS(smp2p_entry, status, val),
+ TP_STRUCT__entry(
+ __string(dev_name, dev_name(smp2p_entry->smp2p->dev))
+ __string(client_name, smp2p_entry->name)
+ __field(unsigned long, status)
+ __field(u32, val)
+ ),
+ TP_fast_assign(
+ __assign_str(dev_name);
+ __assign_str(client_name);
+ __entry->status = status;
+ __entry->val = val;
+ ),
+ TP_printk("%s: %s: status:0x%0lx val:0x%0x",
+ __get_str(dev_name),
+ __get_str(client_name),
+ __entry->status,
+ __entry->val
+ )
+);
+
+TRACE_EVENT(smp2p_update_bits,
+ TP_PROTO(struct smp2p_entry *smp2p_entry, u32 orig, u32 val),
+ TP_ARGS(smp2p_entry, orig, val),
+ TP_STRUCT__entry(
+ __string(dev_name, dev_name(smp2p_entry->smp2p->dev))
+ __string(client_name, smp2p_entry->name)
+ __field(u32, orig)
+ __field(u32, val)
+ ),
+ TP_fast_assign(
+ __assign_str(dev_name);
+ __assign_str(client_name);
+ __entry->orig = orig;
+ __entry->val = val;
+ ),
+ TP_printk("%s: %s: orig:0x%0x new:0x%0x",
+ __get_str(dev_name),
+ __get_str(client_name),
+ __entry->orig,
+ __entry->val
+ )
+);
+
+#endif /* __QCOM_SMP2P_TRACE_H__ */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace-smp2p
+
+#include <trace/define_trace.h>
diff --git a/drivers/soc/qcom/trace_icc-bwmon.h b/drivers/soc/qcom/trace_icc-bwmon.h
new file mode 100644
index 000000000000..beb8e6b485a9
--- /dev/null
+++ b/drivers/soc/qcom/trace_icc-bwmon.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM icc_bwmon
+
+#if !defined(_TRACE_ICC_BWMON_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_ICC_BWMON_H
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(qcom_bwmon_update,
+ TP_PROTO(const char *name,
+ unsigned int meas_kbps, unsigned int up_kbps, unsigned int down_kbps),
+
+ TP_ARGS(name, meas_kbps, up_kbps, down_kbps),
+
+ TP_STRUCT__entry(
+ __string(name, name)
+ __field(unsigned int, meas_kbps)
+ __field(unsigned int, up_kbps)
+ __field(unsigned int, down_kbps)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name);
+ __entry->meas_kbps = meas_kbps;
+ __entry->up_kbps = up_kbps;
+ __entry->down_kbps = down_kbps;
+ ),
+
+ TP_printk("name=%s meas_kbps=%u up_kbps=%u down_kbps=%u",
+ __get_str(name),
+ __entry->meas_kbps,
+ __entry->up_kbps,
+ __entry->down_kbps)
+);
+
+#endif /* _TRACE_ICC_BWMON_H */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../drivers/soc/qcom/
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace_icc-bwmon
+
+#include <trace/define_trace.h>
diff --git a/drivers/soc/qcom/wcnss_ctrl.c b/drivers/soc/qcom/wcnss_ctrl.c
index 148bcbac332d..62b424e90d90 100644
--- a/drivers/soc/qcom/wcnss_ctrl.c
+++ b/drivers/soc/qcom/wcnss_ctrl.c
@@ -3,6 +3,7 @@
* Copyright (c) 2016, Linaro Ltd.
* Copyright (c) 2015, Sony Mobile Communications Inc.
*/
+#include <linux/cleanup.h>
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -198,7 +199,6 @@ static int wcnss_request_version(struct wcnss_ctrl *wcnss)
*/
static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc)
{
- struct wcnss_download_nv_req *req;
const struct firmware *fw;
struct device *dev = wcnss->dev;
const char *nvbin = NVBIN_FILE;
@@ -206,18 +206,19 @@ static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc)
ssize_t left;
int ret;
- req = kzalloc(sizeof(*req) + NV_FRAGMENT_SIZE, GFP_KERNEL);
+ struct wcnss_download_nv_req *req __free(kfree) = kzalloc(sizeof(*req) + NV_FRAGMENT_SIZE,
+ GFP_KERNEL);
if (!req)
return -ENOMEM;
ret = of_property_read_string(dev->of_node, "firmware-name", &nvbin);
if (ret < 0 && ret != -EINVAL)
- goto free_req;
+ return ret;
ret = request_firmware(&fw, nvbin, dev);
if (ret < 0) {
dev_err(dev, "Failed to load nv file %s: %d\n", nvbin, ret);
- goto free_req;
+ return ret;
}
data = fw->data;
@@ -263,8 +264,6 @@ static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc)
release_fw:
release_firmware(fw);
-free_req:
- kfree(req);
return ret;
}
diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig
index 0986672f6375..6d2e135eed89 100644
--- a/drivers/soc/renesas/Kconfig
+++ b/drivers/soc/renesas/Kconfig
@@ -24,6 +24,7 @@ config ARCH_RCAR_GEN2
select RENESAS_IRQC
select RST_RCAR
select SYS_SUPPORTS_SH_CMT
+ select SYS_SUPPORTS_SH_TMU
config ARCH_RCAR_GEN3
bool
@@ -34,6 +35,10 @@ config ARCH_RCAR_GEN3
select SYS_SUPPORTS_SH_CMT
select SYS_SUPPORTS_SH_TMU
+config ARCH_RCAR_GEN4
+ bool
+ select ARCH_RCAR_GEN3
+
config ARCH_RMOBILE
bool
select PM
@@ -240,7 +245,7 @@ config ARCH_R8A77961
config ARCH_R8A779F0
bool "ARM64 Platform support for R-Car S4-8"
- select ARCH_RCAR_GEN3
+ select ARCH_RCAR_GEN4
select SYSC_R8A779F0
help
This enables support for the Renesas R-Car S4-8 SoC.
@@ -261,18 +266,25 @@ config ARCH_R8A77970
config ARCH_R8A779A0
bool "ARM64 Platform support for R-Car V3U"
- select ARCH_RCAR_GEN3
+ select ARCH_RCAR_GEN4
select SYSC_R8A779A0
help
This enables support for the Renesas R-Car V3U SoC.
config ARCH_R8A779G0
bool "ARM64 Platform support for R-Car V4H"
- select ARCH_RCAR_GEN3
+ select ARCH_RCAR_GEN4
select SYSC_R8A779G0
help
This enables support for the Renesas R-Car V4H SoC.
+config ARCH_R8A779H0
+ bool "ARM64 Platform support for R-Car V4M"
+ select ARCH_RCAR_GEN4
+ select SYSC_R8A779H0
+ help
+ This enables support for the Renesas R-Car V4M SoC.
+
config ARCH_R8A774C0
bool "ARM64 Platform support for RZ/G2E"
select ARCH_RCAR_GEN3
@@ -333,6 +345,17 @@ config ARCH_R9A09G011
help
This enables support for the Renesas RZ/V2M SoC.
+config ARCH_R9A09G047
+ bool "ARM64 Platform support for RZ/G3E"
+ help
+ This enables support for the Renesas RZ/G3E SoC variants.
+
+config ARCH_R9A09G057
+ bool "ARM64 Platform support for RZ/V2H(P)"
+ select RENESAS_RZV2H_ICU
+ help
+ This enables support for the Renesas RZ/V2H(P) SoC variants.
+
endif # ARM64
if RISCV
diff --git a/drivers/soc/renesas/rcar-rst.c b/drivers/soc/renesas/rcar-rst.c
index 98fd97da6cd4..7ba02f3a4a4f 100644
--- a/drivers/soc/renesas/rcar-rst.c
+++ b/drivers/soc/renesas/rcar-rst.c
@@ -117,6 +117,7 @@ static const struct of_device_id rcar_rst_matches[] __initconst = {
{ .compatible = "renesas,r8a779a0-rst", .data = &rcar_rst_v3u },
{ .compatible = "renesas,r8a779f0-rst", .data = &rcar_rst_gen4 },
{ .compatible = "renesas,r8a779g0-rst", .data = &rcar_rst_gen4 },
+ { .compatible = "renesas,r8a779h0-rst", .data = &rcar_rst_gen4 },
{ /* sentinel */ }
};
diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c
index 27eae1a354ab..172d59e6fbcf 100644
--- a/drivers/soc/renesas/renesas-soc.c
+++ b/drivers/soc/renesas/renesas-soc.c
@@ -75,6 +75,10 @@ static const struct renesas_family fam_rzg3s __initconst __maybe_unused = {
.name = "RZ/G3S",
};
+static const struct renesas_family fam_rzv2h __initconst __maybe_unused = {
+ .name = "RZ/V2H",
+};
+
static const struct renesas_family fam_rzv2l __initconst __maybe_unused = {
.name = "RZ/V2L",
};
@@ -177,6 +181,11 @@ static const struct renesas_soc soc_rz_g3s __initconst __maybe_unused = {
.id = 0x85e0447,
};
+static const struct renesas_soc soc_rz_v2h __initconst __maybe_unused = {
+ .family = &fam_rzv2h,
+ .id = 0x847a447,
+};
+
static const struct renesas_soc soc_rz_v2l __initconst __maybe_unused = {
.family = &fam_rzv2l,
.id = 0x8447447,
@@ -270,6 +279,11 @@ static const struct renesas_soc soc_rcar_v4h __initconst __maybe_unused = {
.id = 0x5c,
};
+static const struct renesas_soc soc_rcar_v4m __initconst __maybe_unused = {
+ .family = &fam_rcar_gen4,
+ .id = 0x5d,
+};
+
static const struct renesas_soc soc_shmobile_ag5 __initconst __maybe_unused = {
.family = &fam_shmobile,
.id = 0x37,
@@ -380,6 +394,9 @@ static const struct of_device_id renesas_socs[] __initconst __maybe_unused = {
#ifdef CONFIG_ARCH_R8A779G0
{ .compatible = "renesas,r8a779g0", .data = &soc_rcar_v4h },
#endif
+#ifdef CONFIG_ARCH_R8A779H0
+ { .compatible = "renesas,r8a779h0", .data = &soc_rcar_v4m },
+#endif
#ifdef CONFIG_ARCH_R9A07G043
#ifdef CONFIG_RISCV
{ .compatible = "renesas,r9a07g043", .data = &soc_rz_five },
@@ -399,6 +416,9 @@ static const struct of_device_id renesas_socs[] __initconst __maybe_unused = {
#ifdef CONFIG_ARCH_R9A09G011
{ .compatible = "renesas,r9a09g011", .data = &soc_rz_v2m },
#endif
+#ifdef CONFIG_ARCH_R9A09G057
+ { .compatible = "renesas,r9a09g057", .data = &soc_rz_v2h },
+#endif
#ifdef CONFIG_ARCH_SH73A0
{ .compatible = "renesas,sh73a0", .data = &soc_shmobile_ag5 },
#endif
@@ -424,6 +444,11 @@ static const struct renesas_id id_rzg2l __initconst = {
.mask = 0xfffffff,
};
+static const struct renesas_id id_rzv2h __initconst = {
+ .offset = 0x304,
+ .mask = 0xfffffff,
+};
+
static const struct renesas_id id_rzv2m __initconst = {
.offset = 0x104,
.mask = 0xff,
@@ -441,6 +466,7 @@ static const struct of_device_id renesas_ids[] __initconst = {
{ .compatible = "renesas,r9a07g054-sysc", .data = &id_rzg2l },
{ .compatible = "renesas,r9a08g045-sysc", .data = &id_rzg2l },
{ .compatible = "renesas,r9a09g011-sys", .data = &id_rzv2m },
+ { .compatible = "renesas,r9a09g057-sys", .data = &id_rzv2h },
{ .compatible = "renesas,prr", .data = &id_prr },
{ /* sentinel */ }
};
@@ -505,7 +531,7 @@ static int __init renesas_soc_init(void)
eslo = product & 0xf;
soc_dev_attr->revision = kasprintf(GFP_KERNEL, "ES%u.%u",
eshi, eslo);
- } else if (id == &id_rzg2l) {
+ } else if (id == &id_rzg2l || id == &id_rzv2h) {
eshi = ((product >> 28) & 0x0f);
soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%u",
eshi);
diff --git a/drivers/soc/rockchip/grf.c b/drivers/soc/rockchip/grf.c
index 5fd62046b28a..1eab4bb0eacf 100644
--- a/drivers/soc/rockchip/grf.c
+++ b/drivers/soc/rockchip/grf.c
@@ -41,9 +41,11 @@ static const struct rockchip_grf_info rk3036_grf __initconst = {
};
#define RK3128_GRF_SOC_CON0 0x140
+#define RK3128_GRF_SOC_CON1 0x144
static const struct rockchip_grf_value rk3128_defaults[] __initconst = {
{ "jtag switching", RK3128_GRF_SOC_CON0, HIWORD_UPDATE(0, 1, 8) },
+ { "vpu main clock", RK3128_GRF_SOC_CON1, HIWORD_UPDATE(0, 1, 10) },
};
static const struct rockchip_grf_info rk3128_grf __initconst = {
@@ -121,6 +123,29 @@ static const struct rockchip_grf_info rk3566_pipegrf __initconst = {
.num_values = ARRAY_SIZE(rk3566_defaults),
};
+#define RK3576_SYSGRF_SOC_CON1 0x0004
+
+static const struct rockchip_grf_value rk3576_defaults_sys_grf[] __initconst = {
+ { "i3c0 weakpull", RK3576_SYSGRF_SOC_CON1, HIWORD_UPDATE(3, 3, 6) },
+ { "i3c1 weakpull", RK3576_SYSGRF_SOC_CON1, HIWORD_UPDATE(3, 3, 8) },
+};
+
+static const struct rockchip_grf_info rk3576_sysgrf __initconst = {
+ .values = rk3576_defaults_sys_grf,
+ .num_values = ARRAY_SIZE(rk3576_defaults_sys_grf),
+};
+
+#define RK3576_IOCGRF_MISC_CON 0x04F0
+
+static const struct rockchip_grf_value rk3576_defaults_ioc_grf[] __initconst = {
+ { "jtag switching", RK3576_IOCGRF_MISC_CON, HIWORD_UPDATE(0, 1, 1) },
+};
+
+static const struct rockchip_grf_info rk3576_iocgrf __initconst = {
+ .values = rk3576_defaults_ioc_grf,
+ .num_values = ARRAY_SIZE(rk3576_defaults_ioc_grf),
+};
+
#define RK3588_GRF_SOC_CON6 0x0318
static const struct rockchip_grf_value rk3588_defaults[] __initconst = {
@@ -132,7 +157,6 @@ static const struct rockchip_grf_info rk3588_sysgrf __initconst = {
.num_values = ARRAY_SIZE(rk3588_defaults),
};
-
static const struct of_device_id rockchip_grf_dt_match[] __initconst = {
{
.compatible = "rockchip,rk3036-grf",
@@ -159,6 +183,12 @@ static const struct of_device_id rockchip_grf_dt_match[] __initconst = {
.compatible = "rockchip,rk3566-pipe-grf",
.data = (void *)&rk3566_pipegrf,
}, {
+ .compatible = "rockchip,rk3576-sys-grf",
+ .data = (void *)&rk3576_sysgrf,
+ }, {
+ .compatible = "rockchip,rk3576-ioc-grf",
+ .data = (void *)&rk3576_iocgrf,
+ }, {
.compatible = "rockchip,rk3588-sys-grf",
.data = (void *)&rk3588_sysgrf,
},
diff --git a/drivers/soc/rockchip/io-domain.c b/drivers/soc/rockchip/io-domain.c
index 18f809c160a7..f94985a905c2 100644
--- a/drivers/soc/rockchip/io-domain.c
+++ b/drivers/soc/rockchip/io-domain.c
@@ -39,6 +39,10 @@
#define RK3288_SOC_CON2_FLASH0 BIT(7)
#define RK3288_SOC_FLASH_SUPPLY_NUM 2
+#define RK3308_SOC_CON0 0x300
+#define RK3308_SOC_CON0_VCCIO3 BIT(8)
+#define RK3308_SOC_VCCIO3_SUPPLY_NUM 3
+
#define RK3328_SOC_CON4 0x410
#define RK3328_SOC_CON4_VCCIO2 BIT(7)
#define RK3328_SOC_VCCIO2_SUPPLY_NUM 1
@@ -229,6 +233,25 @@ static void rk3288_iodomain_init(struct rockchip_iodomain *iod)
dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
}
+static void rk3308_iodomain_init(struct rockchip_iodomain *iod)
+{
+ int ret;
+ u32 val;
+
+ /* if no vccio3 supply we should leave things alone */
+ if (!iod->supplies[RK3308_SOC_VCCIO3_SUPPLY_NUM].reg)
+ return;
+
+ /*
+ * set vccio3 iodomain to also use this framework
+ * instead of a special gpio.
+ */
+ val = RK3308_SOC_CON0_VCCIO3 | (RK3308_SOC_CON0_VCCIO3 << 16);
+ ret = regmap_write(iod->grf, RK3308_SOC_CON0, val);
+ if (ret < 0)
+ dev_warn(iod->dev, "couldn't update vccio3 vsel ctrl\n");
+}
+
static void rk3328_iodomain_init(struct rockchip_iodomain *iod)
{
int ret;
@@ -376,6 +399,19 @@ static const struct rockchip_iodomain_soc_data soc_data_rk3288 = {
.init = rk3288_iodomain_init,
};
+static const struct rockchip_iodomain_soc_data soc_data_rk3308 = {
+ .grf_offset = 0x300,
+ .supply_names = {
+ "vccio0",
+ "vccio1",
+ "vccio2",
+ "vccio3",
+ "vccio4",
+ "vccio5",
+ },
+ .init = rk3308_iodomain_init,
+};
+
static const struct rockchip_iodomain_soc_data soc_data_rk3328 = {
.grf_offset = 0x410,
.supply_names = {
@@ -529,6 +565,10 @@ static const struct of_device_id rockchip_iodomain_match[] = {
.data = &soc_data_rk3288
},
{
+ .compatible = "rockchip,rk3308-io-voltage-domain",
+ .data = &soc_data_rk3308
+ },
+ {
.compatible = "rockchip,rk3328-io-voltage-domain",
.data = &soc_data_rk3328
},
@@ -702,10 +742,10 @@ static void rockchip_iodomain_remove(struct platform_device *pdev)
}
static struct platform_driver rockchip_iodomain_driver = {
- .probe = rockchip_iodomain_probe,
- .remove_new = rockchip_iodomain_remove,
- .driver = {
- .name = "rockchip-iodomain",
+ .probe = rockchip_iodomain_probe,
+ .remove = rockchip_iodomain_remove,
+ .driver = {
+ .name = "rockchip-iodomain",
.of_match_table = rockchip_iodomain_match,
},
};
diff --git a/drivers/soc/samsung/Kconfig b/drivers/soc/samsung/Kconfig
index 27ec99af77e3..1a5dfdc978dc 100644
--- a/drivers/soc/samsung/Kconfig
+++ b/drivers/soc/samsung/Kconfig
@@ -42,6 +42,7 @@ config EXYNOS_PMU
depends on ARCH_EXYNOS || ((ARM || ARM64) && COMPILE_TEST)
select EXYNOS_PMU_ARM_DRIVERS if ARM && ARCH_EXYNOS
select MFD_CORE
+ select REGMAP_MMIO
# There is no need to enable these drivers for ARMv8
config EXYNOS_PMU_ARM_DRIVERS
diff --git a/drivers/soc/samsung/exynos-asv.c b/drivers/soc/samsung/exynos-asv.c
index d60af8acc391..97006cc3b946 100644
--- a/drivers/soc/samsung/exynos-asv.c
+++ b/drivers/soc/samsung/exynos-asv.c
@@ -11,6 +11,7 @@
#include <linux/cpu.h>
#include <linux/device.h>
+#include <linux/energy_model.h>
#include <linux/errno.h>
#include <linux/of.h>
#include <linux/pm_opp.h>
@@ -97,9 +98,16 @@ static int exynos_asv_update_opps(struct exynos_asv *asv)
last_opp_table = opp_table;
ret = exynos_asv_update_cpu_opps(asv, cpu);
- if (ret < 0)
+ if (!ret) {
+ /*
+ * Update EM power values since OPP
+ * voltage values may have changed.
+ */
+ em_dev_update_chip_binning(cpu);
+ } else {
dev_err(asv->dev, "Couldn't udate OPPs for cpu%d\n",
cpuid);
+ }
}
dev_pm_opp_put_opp_table(opp_table);
diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c
index b1118d37779e..e37dde1fb588 100644
--- a/drivers/soc/samsung/exynos-chipid.c
+++ b/drivers/soc/samsung/exynos-chipid.c
@@ -58,6 +58,9 @@ static const struct exynos_soc_id {
/* Compatible with: samsung,exynos850-chipid */
{ "EXYNOS7885", 0xE7885000 },
{ "EXYNOS850", 0xE3830000 },
+ { "EXYNOS8895", 0xE8895000 },
+ { "EXYNOS9810", 0xE9810000 },
+ { "EXYNOS990", 0xE9830000 },
{ "EXYNOSAUTOV9", 0xAAA80000 },
{ "EXYNOSAUTOV920", 0x0A920000 },
};
@@ -195,8 +198,8 @@ static struct platform_driver exynos_chipid_driver = {
.name = "exynos-chipid",
.of_match_table = exynos_chipid_of_device_ids,
},
- .probe = exynos_chipid_probe,
- .remove_new = exynos_chipid_remove,
+ .probe = exynos_chipid_probe,
+ .remove = exynos_chipid_remove,
};
module_platform_driver(exynos_chipid_driver);
diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c
index 250537d7cfd6..dd5256e5aae1 100644
--- a/drivers/soc/samsung/exynos-pmu.c
+++ b/drivers/soc/samsung/exynos-pmu.c
@@ -5,6 +5,7 @@
//
// Exynos - CPU PMU(Power Management Unit) support
+#include <linux/arm-smccc.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/mfd/core.h>
@@ -12,19 +13,150 @@
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
+#include <linux/regmap.h>
#include <linux/soc/samsung/exynos-regs-pmu.h>
#include <linux/soc/samsung/exynos-pmu.h>
#include "exynos-pmu.h"
+#define PMUALIVE_MASK GENMASK(13, 0)
+#define TENSOR_SET_BITS (BIT(15) | BIT(14))
+#define TENSOR_CLR_BITS BIT(15)
+#define TENSOR_SMC_PMU_SEC_REG 0x82000504
+#define TENSOR_PMUREG_READ 0
+#define TENSOR_PMUREG_WRITE 1
+#define TENSOR_PMUREG_RMW 2
+
struct exynos_pmu_context {
struct device *dev;
const struct exynos_pmu_data *pmu_data;
+ struct regmap *pmureg;
};
void __iomem *pmu_base_addr;
static struct exynos_pmu_context *pmu_context;
+/* forward declaration */
+static struct platform_driver exynos_pmu_driver;
+
+/*
+ * Tensor SoCs are configured so that PMU_ALIVE registers can only be written
+ * from EL3, but are still read accessible. As Linux needs to write some of
+ * these registers, the following functions are provided and exposed via
+ * regmap.
+ *
+ * Note: This SMC interface is known to be implemented on gs101 and derivative
+ * SoCs.
+ */
+
+/* Write to a protected PMU register. */
+static int tensor_sec_reg_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ struct arm_smccc_res res;
+ unsigned long pmu_base = (unsigned long)context;
+
+ arm_smccc_smc(TENSOR_SMC_PMU_SEC_REG, pmu_base + reg,
+ TENSOR_PMUREG_WRITE, val, 0, 0, 0, 0, &res);
+
+ /* returns -EINVAL if access isn't allowed or 0 */
+ if (res.a0)
+ pr_warn("%s(): SMC failed: %d\n", __func__, (int)res.a0);
+
+ return (int)res.a0;
+}
+
+/* Read/Modify/Write a protected PMU register. */
+static int tensor_sec_reg_rmw(void *context, unsigned int reg,
+ unsigned int mask, unsigned int val)
+{
+ struct arm_smccc_res res;
+ unsigned long pmu_base = (unsigned long)context;
+
+ arm_smccc_smc(TENSOR_SMC_PMU_SEC_REG, pmu_base + reg,
+ TENSOR_PMUREG_RMW, mask, val, 0, 0, 0, &res);
+
+ /* returns -EINVAL if access isn't allowed or 0 */
+ if (res.a0)
+ pr_warn("%s(): SMC failed: %d\n", __func__, (int)res.a0);
+
+ return (int)res.a0;
+}
+
+/*
+ * Read a protected PMU register. All PMU registers can be read by Linux.
+ * Note: The SMC read register is not used, as only registers that can be
+ * written are readable via SMC.
+ */
+static int tensor_sec_reg_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ *val = pmu_raw_readl(reg);
+ return 0;
+}
+
+/*
+ * For SoCs that have set/clear bit hardware this function can be used when
+ * the PMU register will be accessed by multiple masters.
+ *
+ * For example, to set bits 13:8 in PMU reg offset 0x3e80
+ * tensor_set_bits_atomic(ctx, 0x3e80, 0x3f00, 0x3f00);
+ *
+ * Set bit 8, and clear bits 13:9 PMU reg offset 0x3e80
+ * tensor_set_bits_atomic(0x3e80, 0x100, 0x3f00);
+ */
+static int tensor_set_bits_atomic(void *ctx, unsigned int offset, u32 val,
+ u32 mask)
+{
+ int ret;
+ unsigned int i;
+
+ for (i = 0; i < 32; i++) {
+ if (!(mask & BIT(i)))
+ continue;
+
+ offset &= ~TENSOR_SET_BITS;
+
+ if (val & BIT(i))
+ offset |= TENSOR_SET_BITS;
+ else
+ offset |= TENSOR_CLR_BITS;
+
+ ret = tensor_sec_reg_write(ctx, offset, i);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static bool tensor_is_atomic(unsigned int reg)
+{
+ /*
+ * Use atomic operations for PMU_ALIVE registers (offset 0~0x3FFF)
+ * as the target registers can be accessed by multiple masters. SFRs
+ * that don't support atomic are added to the switch statement below.
+ */
+ if (reg > PMUALIVE_MASK)
+ return false;
+
+ switch (reg) {
+ case GS101_SYSIP_DAT0:
+ case GS101_SYSTEM_CONFIGURATION:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static int tensor_sec_update_bits(void *ctx, unsigned int reg,
+ unsigned int mask, unsigned int val)
+{
+
+ if (!tensor_is_atomic(reg))
+ return tensor_sec_reg_rmw(ctx, reg, mask, val);
+
+ return tensor_set_bits_atomic(ctx, reg, val, mask);
+}
void pmu_raw_writel(u32 val, u32 offset)
{
@@ -75,11 +207,31 @@ void exynos_sys_powerdown_conf(enum sys_powerdown mode)
#define exynos_pmu_data_arm_ptr(data) NULL
#endif
+static const struct regmap_config regmap_smccfg = {
+ .name = "pmu_regs",
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .fast_io = true,
+ .use_single_read = true,
+ .use_single_write = true,
+ .reg_read = tensor_sec_reg_read,
+ .reg_write = tensor_sec_reg_write,
+ .reg_update_bits = tensor_sec_update_bits,
+};
+
+static const struct exynos_pmu_data gs101_pmu_data = {
+ .pmu_secure = true
+};
+
/*
* PMU platform driver and devicetree bindings.
*/
static const struct of_device_id exynos_pmu_of_device_ids[] = {
{
+ .compatible = "google,gs101-pmu",
+ .data = &gs101_pmu_data,
+ }, {
.compatible = "samsung,exynos3250-pmu",
.data = exynos_pmu_data_arm_ptr(exynos3250_pmu_data),
}, {
@@ -113,19 +265,72 @@ static const struct mfd_cell exynos_pmu_devs[] = {
{ .name = "exynos-clkout", },
};
+/**
+ * exynos_get_pmu_regmap() - Obtain pmureg regmap
+ *
+ * Find the pmureg regmap previously configured in probe() and return regmap
+ * pointer.
+ *
+ * Return: A pointer to regmap if found or ERR_PTR error value.
+ */
struct regmap *exynos_get_pmu_regmap(void)
{
struct device_node *np = of_find_matching_node(NULL,
exynos_pmu_of_device_ids);
if (np)
- return syscon_node_to_regmap(np);
+ return exynos_get_pmu_regmap_by_phandle(np, NULL);
return ERR_PTR(-ENODEV);
}
EXPORT_SYMBOL_GPL(exynos_get_pmu_regmap);
+/**
+ * exynos_get_pmu_regmap_by_phandle() - Obtain pmureg regmap via phandle
+ * @np: Device node holding PMU phandle property
+ * @propname: Name of property holding phandle value
+ *
+ * Find the pmureg regmap previously configured in probe() and return regmap
+ * pointer.
+ *
+ * Return: A pointer to regmap if found or ERR_PTR error value.
+ */
+struct regmap *exynos_get_pmu_regmap_by_phandle(struct device_node *np,
+ const char *propname)
+{
+ struct device_node *pmu_np;
+ struct device *dev;
+
+ if (propname)
+ pmu_np = of_parse_phandle(np, propname, 0);
+ else
+ pmu_np = np;
+
+ if (!pmu_np)
+ return ERR_PTR(-ENODEV);
+
+ /*
+ * Determine if exynos-pmu device has probed and therefore regmap
+ * has been created and can be returned to the caller. Otherwise we
+ * return -EPROBE_DEFER.
+ */
+ dev = driver_find_device_by_of_node(&exynos_pmu_driver.driver,
+ (void *)pmu_np);
+
+ if (propname)
+ of_node_put(pmu_np);
+
+ if (!dev)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ return syscon_node_to_regmap(pmu_np);
+}
+EXPORT_SYMBOL_GPL(exynos_get_pmu_regmap_by_phandle);
+
static int exynos_pmu_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct regmap_config pmu_regmcfg;
+ struct regmap *regmap;
+ struct resource *res;
int ret;
pmu_base_addr = devm_platform_ioremap_resource(pdev, 0);
@@ -137,9 +342,41 @@ static int exynos_pmu_probe(struct platform_device *pdev)
GFP_KERNEL);
if (!pmu_context)
return -ENOMEM;
- pmu_context->dev = dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
pmu_context->pmu_data = of_device_get_match_data(dev);
+ /* For SoCs that secure PMU register writes use custom regmap */
+ if (pmu_context->pmu_data && pmu_context->pmu_data->pmu_secure) {
+ pmu_regmcfg = regmap_smccfg;
+ pmu_regmcfg.max_register = resource_size(res) -
+ pmu_regmcfg.reg_stride;
+ /* Need physical address for SMC call */
+ regmap = devm_regmap_init(dev, NULL,
+ (void *)(uintptr_t)res->start,
+ &pmu_regmcfg);
+
+ if (IS_ERR(regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(regmap),
+ "regmap init failed\n");
+
+ ret = of_syscon_register_regmap(dev->of_node, regmap);
+ if (ret)
+ return ret;
+ } else {
+ /* let syscon create mmio regmap */
+ regmap = syscon_node_to_regmap(dev->of_node);
+ if (IS_ERR(regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(regmap),
+ "syscon_node_to_regmap failed\n");
+ }
+
+ pmu_context->pmureg = regmap;
+ pmu_context->dev = dev;
+
if (pmu_context->pmu_data && pmu_context->pmu_data->pmu_init)
pmu_context->pmu_data->pmu_init();
diff --git a/drivers/soc/samsung/exynos-pmu.h b/drivers/soc/samsung/exynos-pmu.h
index 1c652ffd79b4..0a49a2c9a08e 100644
--- a/drivers/soc/samsung/exynos-pmu.h
+++ b/drivers/soc/samsung/exynos-pmu.h
@@ -21,6 +21,7 @@ struct exynos_pmu_conf {
struct exynos_pmu_data {
const struct exynos_pmu_conf *pmu_config;
const struct exynos_pmu_conf *pmu_config_extra;
+ bool pmu_secure;
void (*pmu_init)(void);
void (*powerdown_conf)(enum sys_powerdown);
diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
index 4458b2e0562b..2781a091a6a6 100644
--- a/drivers/soc/sunxi/sunxi_sram.c
+++ b/drivers/soc/sunxi/sunxi_sram.c
@@ -33,7 +33,6 @@ struct sunxi_sram_data {
u8 offset;
u8 width;
struct sunxi_sram_func *func;
- struct list_head list;
};
struct sunxi_sram_desc {
@@ -103,7 +102,6 @@ static const struct of_device_id sunxi_sram_dt_ids[] = {
};
static struct device *sram_dev;
-static LIST_HEAD(claimed_sram);
static DEFINE_SPINLOCK(sram_lock);
static void __iomem *base;
@@ -287,6 +285,7 @@ EXPORT_SYMBOL(sunxi_sram_release);
struct sunxi_sramc_variant {
int num_emac_clocks;
bool has_ldo_ctrl;
+ bool has_ths_offset;
};
static const struct sunxi_sramc_variant sun4i_a10_sramc_variant = {
@@ -308,8 +307,10 @@ static const struct sunxi_sramc_variant sun50i_a64_sramc_variant = {
static const struct sunxi_sramc_variant sun50i_h616_sramc_variant = {
.num_emac_clocks = 2,
+ .has_ths_offset = true,
};
+#define SUNXI_SRAM_THS_OFFSET_REG 0x0
#define SUNXI_SRAM_EMAC_CLOCK_REG 0x30
#define SUNXI_SYS_LDO_CTRL_REG 0x150
@@ -318,6 +319,8 @@ static bool sunxi_sram_regmap_accessible_reg(struct device *dev,
{
const struct sunxi_sramc_variant *variant = dev_get_drvdata(dev);
+ if (reg == SUNXI_SRAM_THS_OFFSET_REG && variant->has_ths_offset)
+ return true;
if (reg >= SUNXI_SRAM_EMAC_CLOCK_REG &&
reg < SUNXI_SRAM_EMAC_CLOCK_REG + variant->num_emac_clocks * 4)
return true;
@@ -327,7 +330,21 @@ static bool sunxi_sram_regmap_accessible_reg(struct device *dev,
return false;
}
-static struct regmap_config sunxi_sram_regmap_config = {
+static void sunxi_sram_lock(void *_lock)
+{
+ spinlock_t *lock = _lock;
+
+ spin_lock(lock);
+}
+
+static void sunxi_sram_unlock(void *_lock)
+{
+ spinlock_t *lock = _lock;
+
+ spin_unlock(lock);
+}
+
+static const struct regmap_config sunxi_sram_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
@@ -336,6 +353,9 @@ static struct regmap_config sunxi_sram_regmap_config = {
/* other devices have no business accessing other registers */
.readable_reg = sunxi_sram_regmap_accessible_reg,
.writeable_reg = sunxi_sram_regmap_accessible_reg,
+ .lock = sunxi_sram_lock,
+ .unlock = sunxi_sram_unlock,
+ .lock_arg = &sram_lock,
};
static int __init sunxi_sram_probe(struct platform_device *pdev)
diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig
index f16beeabaa92..33512558af9f 100644
--- a/drivers/soc/tegra/Kconfig
+++ b/drivers/soc/tegra/Kconfig
@@ -133,6 +133,11 @@ config ARCH_TEGRA_234_SOC
help
Enable support for the NVIDIA Tegra234 SoC.
+config ARCH_TEGRA_241_SOC
+ bool "NVIDIA Tegra241 SoC"
+ help
+ Enable support for the NVIDIA Tegra241 SoC.
+
endif
endif
diff --git a/drivers/soc/tegra/cbb/tegra-cbb.c b/drivers/soc/tegra/cbb/tegra-cbb.c
index 84ab46c9d9f5..6215c6a84fbe 100644
--- a/drivers/soc/tegra/cbb/tegra-cbb.c
+++ b/drivers/soc/tegra/cbb/tegra-cbb.c
@@ -69,19 +69,12 @@ static int tegra_cbb_err_show(struct seq_file *file, void *data)
}
DEFINE_SHOW_ATTRIBUTE(tegra_cbb_err);
-static int tegra_cbb_err_debugfs_init(struct tegra_cbb *cbb)
+static void tegra_cbb_err_debugfs_init(struct tegra_cbb *cbb)
{
static struct dentry *root;
- if (!root) {
+ if (!root)
root = debugfs_create_file("tegra_cbb_err", 0444, NULL, cbb, &tegra_cbb_err_fops);
- if (IS_ERR_OR_NULL(root)) {
- pr_err("%s(): could not create debugfs node\n", __func__);
- return PTR_ERR(root);
- }
- }
-
- return 0;
}
void tegra_cbb_stall_enable(struct tegra_cbb *cbb)
@@ -148,13 +141,8 @@ int tegra_cbb_register(struct tegra_cbb *cbb)
{
int ret;
- if (IS_ENABLED(CONFIG_DEBUG_FS)) {
- ret = tegra_cbb_err_debugfs_init(cbb);
- if (ret) {
- dev_err(cbb->dev, "failed to create debugfs\n");
- return ret;
- }
- }
+ if (IS_ENABLED(CONFIG_DEBUG_FS))
+ tegra_cbb_err_debugfs_init(cbb);
/* register interrupt handler for errors due to different initiators */
ret = cbb->ops->interrupt_enable(cbb);
diff --git a/drivers/soc/tegra/cbb/tegra194-cbb.c b/drivers/soc/tegra/cbb/tegra194-cbb.c
index 9cbc562ae7d3..846b17ffc2f9 100644
--- a/drivers/soc/tegra/cbb/tegra194-cbb.c
+++ b/drivers/soc/tegra/cbb/tegra194-cbb.c
@@ -2330,7 +2330,7 @@ static const struct dev_pm_ops tegra194_cbb_pm = {
static struct platform_driver tegra194_cbb_driver = {
.probe = tegra194_cbb_probe,
- .remove_new = tegra194_cbb_remove,
+ .remove = tegra194_cbb_remove,
.driver = {
.name = "tegra194-cbb",
.of_match_table = of_match_ptr(tegra194_cbb_match),
diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c
index 5cf0e8c34164..c74629af9bb5 100644
--- a/drivers/soc/tegra/cbb/tegra234-cbb.c
+++ b/drivers/soc/tegra/cbb/tegra234-cbb.c
@@ -277,7 +277,7 @@ static void tegra234_lookup_slave_timeout(struct seq_file *file, struct tegra234
* which timed out.
* a) Get block number from the index of set bit in
* <FABRIC>_SN_AXI2APB_<>_BLOCK_TMO_STATUS_0 register.
- * b) Get address of register repective to block number i.e.
+ * b) Get address of register respective to block number i.e.
* <FABRIC>_SN_AXI2APB_<>_BLOCK<index-set-bit>_TMO_0.
* c) Read the register in above step to get client_id which
* timed out as per the set bits.
diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c
index a2c28f493a75..d27667283846 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra.c
@@ -3,11 +3,13 @@
* Copyright (c) 2013-2023, NVIDIA CORPORATION. All rights reserved.
*/
+#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/kobject.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/mod_devicetable.h>
#include <linux/nvmem-consumer.h>
#include <linux/nvmem-provider.h>
#include <linux/of.h>
@@ -113,6 +115,28 @@ static void tegra_fuse_restore(void *base)
fuse->clk = NULL;
}
+static void tegra_fuse_print_sku_info(struct tegra_sku_info *tegra_sku_info)
+{
+ pr_info("Tegra Revision: %s SKU: %d CPU Process: %d SoC Process: %d\n",
+ tegra_revision_name[tegra_sku_info->revision],
+ tegra_sku_info->sku_id, tegra_sku_info->cpu_process_id,
+ tegra_sku_info->soc_process_id);
+ pr_debug("Tegra CPU Speedo ID %d, SoC Speedo ID %d\n",
+ tegra_sku_info->cpu_speedo_id, tegra_sku_info->soc_speedo_id);
+}
+
+static int tegra_fuse_add_lookups(struct tegra_fuse *fuse)
+{
+ fuse->lookups = kmemdup_array(fuse->soc->lookups, fuse->soc->num_lookups,
+ sizeof(*fuse->lookups), GFP_KERNEL);
+ if (!fuse->lookups)
+ return -ENOMEM;
+
+ nvmem_add_cell_lookups(fuse->lookups, fuse->soc->num_lookups);
+
+ return 0;
+}
+
static int tegra_fuse_probe(struct platform_device *pdev)
{
void __iomem *base = fuse->base;
@@ -130,15 +154,46 @@ static int tegra_fuse_probe(struct platform_device *pdev)
return PTR_ERR(fuse->base);
fuse->phys = res->start;
- fuse->clk = devm_clk_get(&pdev->dev, "fuse");
- if (IS_ERR(fuse->clk)) {
- if (PTR_ERR(fuse->clk) != -EPROBE_DEFER)
- dev_err(&pdev->dev, "failed to get FUSE clock: %ld",
- PTR_ERR(fuse->clk));
+ /* Initialize the soc data and lookups if using ACPI boot. */
+ if (is_acpi_node(dev_fwnode(&pdev->dev)) && !fuse->soc) {
+ u8 chip;
- return PTR_ERR(fuse->clk);
+ tegra_acpi_init_apbmisc();
+
+ chip = tegra_get_chip_id();
+ switch (chip) {
+#if defined(CONFIG_ARCH_TEGRA_194_SOC)
+ case TEGRA194:
+ fuse->soc = &tegra194_fuse_soc;
+ break;
+#endif
+#if defined(CONFIG_ARCH_TEGRA_234_SOC)
+ case TEGRA234:
+ fuse->soc = &tegra234_fuse_soc;
+ break;
+#endif
+#if defined(CONFIG_ARCH_TEGRA_241_SOC)
+ case TEGRA241:
+ fuse->soc = &tegra241_fuse_soc;
+ break;
+#endif
+ default:
+ return dev_err_probe(&pdev->dev, -EINVAL, "Unsupported SoC: %02x\n", chip);
+ }
+
+ fuse->soc->init(fuse);
+ tegra_fuse_print_sku_info(&tegra_sku_info);
+ tegra_soc_device_register();
+
+ err = tegra_fuse_add_lookups(fuse);
+ if (err)
+ return dev_err_probe(&pdev->dev, err, "failed to add FUSE lookups\n");
}
+ fuse->clk = devm_clk_get_optional(&pdev->dev, "fuse");
+ if (IS_ERR(fuse->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(fuse->clk), "failed to get FUSE clock\n");
+
platform_set_drvdata(pdev, fuse);
fuse->dev = &pdev->dev;
@@ -179,12 +234,8 @@ static int tegra_fuse_probe(struct platform_device *pdev)
}
fuse->rst = devm_reset_control_get_optional(&pdev->dev, "fuse");
- if (IS_ERR(fuse->rst)) {
- err = PTR_ERR(fuse->rst);
- dev_err(&pdev->dev, "failed to get FUSE reset: %pe\n",
- fuse->rst);
- return err;
- }
+ if (IS_ERR(fuse->rst))
+ return dev_err_probe(&pdev->dev, PTR_ERR(fuse->rst), "failed to get FUSE reset\n");
/*
* FUSE clock is enabled at a boot time, hence this resume/suspend
@@ -262,10 +313,17 @@ static const struct dev_pm_ops tegra_fuse_pm = {
SET_SYSTEM_SLEEP_PM_OPS(tegra_fuse_suspend, tegra_fuse_resume)
};
+static const struct acpi_device_id tegra_fuse_acpi_match[] = {
+ { "NVDA200F" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(acpi, tegra_fuse_acpi_match);
+
static struct platform_driver tegra_fuse_driver = {
.driver = {
.name = "tegra-fuse",
.of_match_table = tegra_fuse_match,
+ .acpi_match_table = tegra_fuse_acpi_match,
.pm = &tegra_fuse_pm,
.suppress_bind_attrs = true,
},
@@ -287,7 +345,16 @@ u32 __init tegra_fuse_read_early(unsigned int offset)
int tegra_fuse_readl(unsigned long offset, u32 *value)
{
- if (!fuse->read || !fuse->clk)
+ if (!fuse->dev)
+ return -EPROBE_DEFER;
+
+ /*
+ * Wait for fuse->clk to be initialized if device-tree boot is used.
+ */
+ if (is_of_node(dev_fwnode(fuse->dev)) && !fuse->clk)
+ return -EPROBE_DEFER;
+
+ if (!fuse->read)
return -EPROBE_DEFER;
if (IS_ERR(fuse->clk))
@@ -343,7 +410,8 @@ const struct attribute_group tegra_soc_attr_group = {
};
#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
- IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
+ IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) || \
+ IS_ENABLED(CONFIG_ARCH_TEGRA_241_SOC)
static ssize_t platform_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -370,7 +438,7 @@ const struct attribute_group tegra194_soc_attr_group = {
};
#endif
-struct device * __init tegra_soc_device_register(void)
+struct device *tegra_soc_device_register(void)
{
struct soc_device_attribute *attr;
struct soc_device *dev;
@@ -407,6 +475,7 @@ static int __init tegra_init_fuse(void)
const struct of_device_id *match;
struct device_node *np;
struct resource regs;
+ int err;
tegra_init_apbmisc();
@@ -497,22 +566,13 @@ static int __init tegra_init_fuse(void)
fuse->soc->init(fuse);
- pr_info("Tegra Revision: %s SKU: %d CPU Process: %d SoC Process: %d\n",
- tegra_revision_name[tegra_sku_info.revision],
- tegra_sku_info.sku_id, tegra_sku_info.cpu_process_id,
- tegra_sku_info.soc_process_id);
- pr_debug("Tegra CPU Speedo ID %d, SoC Speedo ID %d\n",
- tegra_sku_info.cpu_speedo_id, tegra_sku_info.soc_speedo_id);
+ tegra_fuse_print_sku_info(&tegra_sku_info);
- if (fuse->soc->lookups) {
- size_t size = sizeof(*fuse->lookups) * fuse->soc->num_lookups;
-
- fuse->lookups = kmemdup(fuse->soc->lookups, size, GFP_KERNEL);
- if (fuse->lookups)
- nvmem_add_cell_lookups(fuse->lookups, fuse->soc->num_lookups);
- }
+ err = tegra_fuse_add_lookups(fuse);
+ if (err)
+ pr_err("failed to add FUSE lookups\n");
- return 0;
+ return err;
}
early_initcall(tegra_init_fuse);
diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c
index e94d46372a63..e24ab5f7d2bf 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra30.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra30.c
@@ -38,7 +38,8 @@
defined(CONFIG_ARCH_TEGRA_210_SOC) || \
defined(CONFIG_ARCH_TEGRA_186_SOC) || \
defined(CONFIG_ARCH_TEGRA_194_SOC) || \
- defined(CONFIG_ARCH_TEGRA_234_SOC)
+ defined(CONFIG_ARCH_TEGRA_234_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_241_SOC)
static u32 tegra30_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset)
{
if (WARN_ON(!fuse->base))
@@ -646,15 +647,20 @@ static const struct nvmem_cell_lookup tegra234_fuse_lookups[] = {
};
static const struct nvmem_keepout tegra234_fuse_keepouts[] = {
- { .start = 0x01c, .end = 0x0c8 },
- { .start = 0x12c, .end = 0x184 },
+ { .start = 0x01c, .end = 0x064 },
+ { .start = 0x084, .end = 0x0a0 },
+ { .start = 0x0a4, .end = 0x0c8 },
+ { .start = 0x12c, .end = 0x164 },
+ { .start = 0x16c, .end = 0x184 },
{ .start = 0x190, .end = 0x198 },
{ .start = 0x1a0, .end = 0x204 },
- { .start = 0x21c, .end = 0x250 },
- { .start = 0x25c, .end = 0x2f0 },
+ { .start = 0x21c, .end = 0x2f0 },
{ .start = 0x310, .end = 0x3d8 },
- { .start = 0x400, .end = 0x4f0 },
- { .start = 0x4f8, .end = 0x7e8 },
+ { .start = 0x400, .end = 0x420 },
+ { .start = 0x444, .end = 0x490 },
+ { .start = 0x4bc, .end = 0x4f0 },
+ { .start = 0x4f8, .end = 0x54c },
+ { .start = 0x57c, .end = 0x7e8 },
{ .start = 0x8d0, .end = 0x8d8 },
{ .start = 0xacc, .end = 0xf00 }
};
@@ -678,3 +684,23 @@ const struct tegra_fuse_soc tegra234_fuse_soc = {
.clk_suspend_on = false,
};
#endif
+
+#if defined(CONFIG_ARCH_TEGRA_241_SOC)
+static const struct tegra_fuse_info tegra241_fuse_info = {
+ .read = tegra30_fuse_read,
+ .size = 0x16008,
+ .spare = 0xcf0,
+};
+
+static const struct nvmem_keepout tegra241_fuse_keepouts[] = {
+ { .start = 0xc, .end = 0x1600c }
+};
+
+const struct tegra_fuse_soc tegra241_fuse_soc = {
+ .init = tegra30_fuse_init,
+ .info = &tegra241_fuse_info,
+ .keepouts = tegra241_fuse_keepouts,
+ .num_keepouts = ARRAY_SIZE(tegra241_fuse_keepouts),
+ .soc_attr_group = &tegra194_soc_attr_group,
+};
+#endif
diff --git a/drivers/soc/tegra/fuse/fuse.h b/drivers/soc/tegra/fuse/fuse.h
index 90f23be73894..9fee6ad6ad9e 100644
--- a/drivers/soc/tegra/fuse/fuse.h
+++ b/drivers/soc/tegra/fuse/fuse.h
@@ -69,6 +69,7 @@ struct tegra_fuse {
void tegra_init_revision(void);
void tegra_init_apbmisc(void);
+void tegra_acpi_init_apbmisc(void);
u32 __init tegra_fuse_read_spare(unsigned int spare);
u32 __init tegra_fuse_read_early(unsigned int offset);
@@ -123,7 +124,8 @@ extern const struct tegra_fuse_soc tegra186_fuse_soc;
#endif
#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
- IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
+ IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) || \
+ IS_ENABLED(CONFIG_ARCH_TEGRA_241_SOC)
extern const struct attribute_group tegra194_soc_attr_group;
#endif
@@ -135,4 +137,8 @@ extern const struct tegra_fuse_soc tegra194_fuse_soc;
extern const struct tegra_fuse_soc tegra234_fuse_soc;
#endif
+#ifdef CONFIG_ARCH_TEGRA_241_SOC
+extern const struct tegra_fuse_soc tegra241_fuse_soc;
+#endif
+
#endif
diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c
index da970f3dbf35..e2ca5d55fd31 100644
--- a/drivers/soc/tegra/fuse/tegra-apbmisc.c
+++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c
@@ -3,9 +3,11 @@
* Copyright (c) 2014-2023, NVIDIA CORPORATION. All rights reserved.
*/
+#include <linux/acpi.h>
#include <linux/export.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -62,6 +64,7 @@ bool tegra_is_silicon(void)
switch (tegra_get_chip_id()) {
case TEGRA194:
case TEGRA234:
+ case TEGRA241:
case TEGRA264:
if (tegra_get_platform() == 0)
return true;
@@ -160,9 +163,34 @@ void __init tegra_init_revision(void)
tegra_sku_info.platform = tegra_get_platform();
}
-void __init tegra_init_apbmisc(void)
+static void tegra_init_apbmisc_resources(struct resource *apbmisc,
+ struct resource *straps)
{
void __iomem *strapping_base;
+
+ apbmisc_base = ioremap(apbmisc->start, resource_size(apbmisc));
+ if (apbmisc_base)
+ chipid = readl_relaxed(apbmisc_base + 4);
+ else
+ pr_err("failed to map APBMISC registers\n");
+
+ strapping_base = ioremap(straps->start, resource_size(straps));
+ if (strapping_base) {
+ strapping = readl_relaxed(strapping_base);
+ iounmap(strapping_base);
+ } else {
+ pr_err("failed to map strapping options registers\n");
+ }
+}
+
+/**
+ * tegra_init_apbmisc - Initializes Tegra APBMISC and Strapping registers.
+ *
+ * This is called during early init as some of the old 32-bit ARM code needs
+ * information from the APBMISC registers very early during boot.
+ */
+void __init tegra_init_apbmisc(void)
+{
struct resource apbmisc, straps;
struct device_node *np;
@@ -219,23 +247,73 @@ void __init tegra_init_apbmisc(void)
}
}
- apbmisc_base = ioremap(apbmisc.start, resource_size(&apbmisc));
- if (!apbmisc_base) {
- pr_err("failed to map APBMISC registers\n");
- } else {
- chipid = readl_relaxed(apbmisc_base + 4);
+ tegra_init_apbmisc_resources(&apbmisc, &straps);
+ long_ram_code = of_property_read_bool(np, "nvidia,long-ram-code");
+
+put:
+ of_node_put(np);
+}
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id apbmisc_acpi_match[] = {
+ { "NVDA2010" },
+ { /* sentinel */ }
+};
+
+void tegra_acpi_init_apbmisc(void)
+{
+ struct resource *resources[2] = { NULL };
+ struct resource_entry *rentry;
+ struct acpi_device *adev = NULL;
+ struct list_head resource_list;
+ int rcount = 0;
+ int ret;
+
+ adev = acpi_dev_get_first_match_dev(apbmisc_acpi_match[0].id, NULL, -1);
+ if (!adev)
+ return;
+
+ INIT_LIST_HEAD(&resource_list);
+
+ ret = acpi_dev_get_memory_resources(adev, &resource_list);
+ if (ret < 0) {
+ pr_err("failed to get APBMISC memory resources");
+ goto out_put_acpi_dev;
}
- strapping_base = ioremap(straps.start, resource_size(&straps));
- if (!strapping_base) {
- pr_err("failed to map strapping options registers\n");
- } else {
- strapping = readl_relaxed(strapping_base);
- iounmap(strapping_base);
+ /*
+ * Get required memory resources.
+ *
+ * resources[0]: apbmisc.
+ * resources[1]: straps.
+ */
+ resource_list_for_each_entry(rentry, &resource_list) {
+ if (rcount >= ARRAY_SIZE(resources))
+ break;
+
+ resources[rcount++] = rentry->res;
}
- long_ram_code = of_property_read_bool(np, "nvidia,long-ram-code");
+ if (!resources[0]) {
+ pr_err("failed to get APBMISC registers\n");
+ goto out_free_resource_list;
+ }
-put:
- of_node_put(np);
+ if (!resources[1]) {
+ pr_err("failed to get strapping options registers\n");
+ goto out_free_resource_list;
+ }
+
+ tegra_init_apbmisc_resources(resources[0], resources[1]);
+
+out_free_resource_list:
+ acpi_dev_free_resource_list(&resource_list);
+
+out_put_acpi_dev:
+ acpi_dev_put(adev);
+}
+#else
+void tegra_acpi_init_apbmisc(void)
+{
}
+#endif
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index f432aa022ace..a08c377933c5 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -3,7 +3,7 @@
* drivers/soc/tegra/pmc.c
*
* Copyright (c) 2010 Google, Inc
- * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved.
*
* Author:
* Colin Cross <ccross@google.com>
@@ -384,6 +384,7 @@ struct tegra_pmc_soc {
bool has_blink_output;
bool has_usb_sleepwalk;
bool supports_core_domain;
+ bool has_single_mmio_aperture;
};
/**
@@ -1437,7 +1438,7 @@ static int tegra_powergate_init(struct tegra_pmc *pmc,
struct device_node *parent)
{
struct of_phandle_args child_args, parent_args;
- struct device_node *np, *child;
+ struct device_node *np;
int err = 0;
/*
@@ -1456,12 +1457,10 @@ static int tegra_powergate_init(struct tegra_pmc *pmc,
if (!np)
return 0;
- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
err = tegra_powergate_add(pmc, child);
- if (err < 0) {
- of_node_put(child);
+ if (err < 0)
break;
- }
if (of_parse_phandle_with_args(child, "power-domains",
"#power-domain-cells",
@@ -1473,10 +1472,8 @@ static int tegra_powergate_init(struct tegra_pmc *pmc,
err = of_genpd_add_subdomain(&parent_args, &child_args);
of_node_put(parent_args.np);
- if (err) {
- of_node_put(child);
+ if (err)
break;
- }
}
of_node_put(np);
@@ -1777,30 +1774,6 @@ static int tegra_io_pad_get_voltage(struct tegra_pmc *pmc, enum tegra_io_pad id)
return TEGRA_IO_PAD_VOLTAGE_3V3;
}
-/**
- * tegra_io_rail_power_on() - enable power to I/O rail
- * @id: Tegra I/O pad ID for which to enable power
- *
- * See also: tegra_io_pad_power_enable()
- */
-int tegra_io_rail_power_on(unsigned int id)
-{
- return tegra_io_pad_power_enable(id);
-}
-EXPORT_SYMBOL(tegra_io_rail_power_on);
-
-/**
- * tegra_io_rail_power_off() - disable power to I/O rail
- * @id: Tegra I/O pad ID for which to disable power
- *
- * See also: tegra_io_pad_power_disable()
- */
-int tegra_io_rail_power_off(unsigned int id)
-{
- return tegra_io_pad_power_disable(id);
-}
-EXPORT_SYMBOL(tegra_io_rail_power_off);
-
#ifdef CONFIG_PM_SLEEP
enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void)
{
@@ -2909,31 +2882,29 @@ static int tegra_pmc_probe(struct platform_device *pdev)
if (IS_ERR(base))
return PTR_ERR(base);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wake");
- if (res) {
- pmc->wake = devm_ioremap_resource(&pdev->dev, res);
+ if (pmc->soc->has_single_mmio_aperture) {
+ pmc->wake = base;
+ pmc->aotag = base;
+ pmc->scratch = base;
+ } else {
+ pmc->wake = devm_platform_ioremap_resource_byname(pdev, "wake");
if (IS_ERR(pmc->wake))
return PTR_ERR(pmc->wake);
- } else {
- pmc->wake = base;
- }
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aotag");
- if (res) {
- pmc->aotag = devm_ioremap_resource(&pdev->dev, res);
+ pmc->aotag = devm_platform_ioremap_resource_byname(pdev, "aotag");
if (IS_ERR(pmc->aotag))
return PTR_ERR(pmc->aotag);
- } else {
- pmc->aotag = base;
- }
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scratch");
- if (res) {
- pmc->scratch = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(pmc->scratch))
- return PTR_ERR(pmc->scratch);
- } else {
- pmc->scratch = base;
+ /* "scratch" is an optional aperture */
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "scratch");
+ if (res) {
+ pmc->scratch = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pmc->scratch))
+ return PTR_ERR(pmc->scratch);
+ } else {
+ pmc->scratch = NULL;
+ }
}
pmc->clk = devm_clk_get_optional(&pdev->dev, "pclk");
@@ -2945,12 +2916,15 @@ static int tegra_pmc_probe(struct platform_device *pdev)
* PMC should be last resort for restarting since it soft-resets
* CPU without resetting everything else.
*/
- err = devm_register_reboot_notifier(&pdev->dev,
- &tegra_pmc_reboot_notifier);
- if (err) {
- dev_err(&pdev->dev, "unable to register reboot notifier, %d\n",
- err);
- return err;
+ if (pmc->scratch) {
+ err = devm_register_reboot_notifier(&pdev->dev,
+ &tegra_pmc_reboot_notifier);
+ if (err) {
+ dev_err(&pdev->dev,
+ "unable to register reboot notifier, %d\n",
+ err);
+ return err;
+ }
}
err = devm_register_sys_off_handler(&pdev->dev,
@@ -3324,6 +3298,7 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = {
.num_pmc_clks = 0,
.has_blink_output = true,
.has_usb_sleepwalk = true,
+ .has_single_mmio_aperture = true,
};
static const char * const tegra30_powergates[] = {
@@ -3385,6 +3360,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
.has_blink_output = true,
.has_usb_sleepwalk = true,
+ .has_single_mmio_aperture = true,
};
static const char * const tegra114_powergates[] = {
@@ -3442,6 +3418,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
.has_blink_output = true,
.has_usb_sleepwalk = true,
+ .has_single_mmio_aperture = true,
};
static const char * const tegra124_powergates[] = {
@@ -3586,6 +3563,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
.has_blink_output = true,
.has_usb_sleepwalk = true,
+ .has_single_mmio_aperture = true,
};
static const char * const tegra210_powergates[] = {
@@ -3749,6 +3727,7 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
.has_blink_output = true,
.has_usb_sleepwalk = true,
+ .has_single_mmio_aperture = true,
};
static const struct tegra_io_pad_soc tegra186_io_pads[] = {
@@ -3946,6 +3925,7 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
.num_pmc_clks = 0,
.has_blink_output = false,
.has_usb_sleepwalk = false,
+ .has_single_mmio_aperture = false,
};
static const struct tegra_io_pad_soc tegra194_io_pads[] = {
@@ -4086,6 +4066,7 @@ static const char * const tegra194_reset_sources[] = {
};
static const struct tegra_wake_event tegra194_wake_events[] = {
+ TEGRA_WAKE_GPIO("eqos", 20, 0, TEGRA194_MAIN_GPIO(G, 4)),
TEGRA_WAKE_IRQ("pmu", 24, 209),
TEGRA_WAKE_GPIO("power", 29, 1, TEGRA194_AON_GPIO(EE, 4)),
TEGRA_WAKE_IRQ("rtc", 73, 10),
@@ -4131,6 +4112,7 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = {
.num_pmc_clks = 0,
.has_blink_output = false,
.has_usb_sleepwalk = false,
+ .has_single_mmio_aperture = false,
};
static const struct tegra_io_pad_soc tegra234_io_pads[] = {
@@ -4220,6 +4202,8 @@ static const char * const tegra234_reset_sources[] = {
};
static const struct tegra_wake_event tegra234_wake_events[] = {
+ TEGRA_WAKE_GPIO("sd-wake", 8, 0, TEGRA234_MAIN_GPIO(G, 7)),
+ TEGRA_WAKE_GPIO("eqos", 20, 0, TEGRA234_MAIN_GPIO(G, 4)),
TEGRA_WAKE_IRQ("pmu", 24, 209),
TEGRA_WAKE_GPIO("power", 29, 1, TEGRA234_AON_GPIO(EE, 4)),
TEGRA_WAKE_GPIO("mgbe", 56, 0, TEGRA234_MAIN_GPIO(Y, 3)),
@@ -4259,6 +4243,7 @@ static const struct tegra_pmc_soc tegra234_pmc_soc = {
.pmc_clks_data = NULL,
.num_pmc_clks = 0,
.has_blink_output = false,
+ .has_single_mmio_aperture = false,
};
static const struct of_device_id tegra_pmc_match[] = {
diff --git a/drivers/soc/ti/k3-ringacc.c b/drivers/soc/ti/k3-ringacc.c
index fd4251d75935..82a15cad1c6c 100644
--- a/drivers/soc/ti/k3-ringacc.c
+++ b/drivers/soc/ti/k3-ringacc.c
@@ -161,7 +161,7 @@ struct k3_ring {
struct k3_ringacc_proxy_target_regs __iomem *proxy;
dma_addr_t ring_mem_dma;
void *ring_mem_virt;
- struct k3_ring_ops *ops;
+ const struct k3_ring_ops *ops;
u32 size;
enum k3_ring_size elm_size;
enum k3_ring_mode mode;
@@ -268,17 +268,17 @@ static int k3_ringacc_ring_pop_mem(struct k3_ring *ring, void *elem);
static int k3_dmaring_fwd_pop(struct k3_ring *ring, void *elem);
static int k3_dmaring_reverse_pop(struct k3_ring *ring, void *elem);
-static struct k3_ring_ops k3_ring_mode_ring_ops = {
+static const struct k3_ring_ops k3_ring_mode_ring_ops = {
.push_tail = k3_ringacc_ring_push_mem,
.pop_head = k3_ringacc_ring_pop_mem,
};
-static struct k3_ring_ops k3_dmaring_fwd_ops = {
+static const struct k3_ring_ops k3_dmaring_fwd_ops = {
.push_tail = k3_ringacc_ring_push_mem,
.pop_head = k3_dmaring_fwd_pop,
};
-static struct k3_ring_ops k3_dmaring_reverse_ops = {
+static const struct k3_ring_ops k3_dmaring_reverse_ops = {
/* Reverse side of the DMA ring can only be popped by SW */
.pop_head = k3_dmaring_reverse_pop,
};
@@ -288,7 +288,7 @@ static int k3_ringacc_ring_pop_io(struct k3_ring *ring, void *elem);
static int k3_ringacc_ring_push_head_io(struct k3_ring *ring, void *elem);
static int k3_ringacc_ring_pop_tail_io(struct k3_ring *ring, void *elem);
-static struct k3_ring_ops k3_ring_mode_msg_ops = {
+static const struct k3_ring_ops k3_ring_mode_msg_ops = {
.push_tail = k3_ringacc_ring_push_io,
.push_head = k3_ringacc_ring_push_head_io,
.pop_tail = k3_ringacc_ring_pop_tail_io,
@@ -300,7 +300,7 @@ static int k3_ringacc_ring_push_tail_proxy(struct k3_ring *ring, void *elem);
static int k3_ringacc_ring_pop_head_proxy(struct k3_ring *ring, void *elem);
static int k3_ringacc_ring_pop_tail_proxy(struct k3_ring *ring, void *elem);
-static struct k3_ring_ops k3_ring_mode_proxy_ops = {
+static const struct k3_ring_ops k3_ring_mode_proxy_ops = {
.push_tail = k3_ringacc_ring_push_tail_proxy,
.push_head = k3_ringacc_ring_push_head_proxy,
.pop_tail = k3_ringacc_ring_pop_tail_proxy,
@@ -1562,7 +1562,7 @@ static void k3_ringacc_remove(struct platform_device *pdev)
static struct platform_driver k3_ringacc_driver = {
.probe = k3_ringacc_probe,
- .remove_new = k3_ringacc_remove,
+ .remove = k3_ringacc_remove,
.driver = {
.name = "k3-ringacc",
.of_match_table = k3_ringacc_of_match,
diff --git a/drivers/soc/ti/k3-socinfo.c b/drivers/soc/ti/k3-socinfo.c
index 59101bf7cf23..4fb0f0a24828 100644
--- a/drivers/soc/ti/k3-socinfo.c
+++ b/drivers/soc/ti/k3-socinfo.c
@@ -61,7 +61,7 @@ static const struct k3_soc_id {
};
static const char * const j721e_rev_string_map[] = {
- "1.0", "1.1",
+ "1.0", "1.1", "2.0",
};
static int
diff --git a/drivers/soc/ti/knav_dma.c b/drivers/soc/ti/knav_dma.c
index 6023006685fc..a25ebe6cd503 100644
--- a/drivers/soc/ti/knav_dma.c
+++ b/drivers/soc/ti/knav_dma.c
@@ -602,7 +602,7 @@ static int dma_init(struct device_node *cloud, struct device_node *dma_node)
unsigned max_tx_chan, max_rx_chan, max_rx_flow, max_tx_sched;
struct device_node *node = dma_node;
struct knav_dma_device *dma;
- int ret, len, num_chan = 0;
+ int ret, num_chan = 0;
resource_size_t size;
u32 timeout;
u32 i;
@@ -615,25 +615,13 @@ static int dma_init(struct device_node *cloud, struct device_node *dma_node)
INIT_LIST_HEAD(&dma->list);
INIT_LIST_HEAD(&dma->chan_list);
- if (!of_find_property(cloud, "ti,navigator-cloud-address", &len)) {
- dev_err(kdev->dev, "unspecified navigator cloud addresses\n");
- return -ENODEV;
- }
-
- dma->logical_queue_managers = len / sizeof(u32);
- if (dma->logical_queue_managers > DMA_MAX_QMS) {
- dev_warn(kdev->dev, "too many queue mgrs(>%d) rest ignored\n",
- dma->logical_queue_managers);
- dma->logical_queue_managers = DMA_MAX_QMS;
- }
-
- ret = of_property_read_u32_array(cloud, "ti,navigator-cloud-address",
- dma->qm_base_address,
- dma->logical_queue_managers);
- if (ret) {
+ ret = of_property_read_variable_u32_array(cloud, "ti,navigator-cloud-address",
+ dma->qm_base_address, 1, DMA_MAX_QMS);
+ if (ret < 0) {
dev_err(kdev->dev, "invalid navigator cloud addresses\n");
return -ENODEV;
}
+ dma->logical_queue_managers = ret;
dma->reg_global = pktdma_get_regs(dma, node, 0, &size);
if (IS_ERR(dma->reg_global))
@@ -795,8 +783,8 @@ MODULE_DEVICE_TABLE(of, of_match);
static struct platform_driver knav_dma_driver = {
.probe = knav_dma_probe,
- .remove_new = knav_dma_remove,
- .driver = {
+ .remove = knav_dma_remove,
+ .driver = {
.name = "keystone-navigator-dma",
.of_match_table = of_match,
},
diff --git a/drivers/soc/ti/knav_qmss.h b/drivers/soc/ti/knav_qmss.h
index a01eda720bf6..9325e8ce2e25 100644
--- a/drivers/soc/ti/knav_qmss.h
+++ b/drivers/soc/ti/knav_qmss.h
@@ -333,7 +333,7 @@ struct knav_range_info {
void *queue_base_inst;
unsigned flags;
struct list_head list;
- struct knav_range_ops *ops;
+ const struct knav_range_ops *ops;
struct knav_acc_info acc_info;
struct knav_acc_channel *acc;
unsigned num_irqs;
diff --git a/drivers/soc/ti/knav_qmss_acc.c b/drivers/soc/ti/knav_qmss_acc.c
index 3d388646ed43..269b4e75ae40 100644
--- a/drivers/soc/ti/knav_qmss_acc.c
+++ b/drivers/soc/ti/knav_qmss_acc.c
@@ -450,7 +450,7 @@ static int knav_acc_free_range(struct knav_range_info *range)
return 0;
}
-static struct knav_range_ops knav_acc_range_ops = {
+static const struct knav_range_ops knav_acc_range_ops = {
.set_notify = knav_acc_set_notify,
.init_queue = knav_acc_init_queue,
.open_queue = knav_acc_open_queue,
diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c
index 06fb5505c22c..ea52425864a9 100644
--- a/drivers/soc/ti/knav_qmss_queue.c
+++ b/drivers/soc/ti/knav_qmss_queue.c
@@ -119,11 +119,10 @@ static int knav_queue_setup_irq(struct knav_range_info *range,
if (range->flags & RANGE_HAS_IRQ) {
irq = range->irqs[queue].irq;
- ret = request_irq(irq, knav_queue_int_handler, 0,
- inst->irq_name, inst);
+ ret = request_irq(irq, knav_queue_int_handler, IRQF_NO_AUTOEN,
+ inst->irq_name, inst);
if (ret)
return ret;
- disable_irq(irq);
if (range->irqs[queue].cpu_mask) {
ret = irq_set_affinity_hint(irq, range->irqs[queue].cpu_mask);
if (ret) {
@@ -411,7 +410,7 @@ static int knav_gp_close_queue(struct knav_range_info *range,
return 0;
}
-static struct knav_range_ops knav_gp_range_ops = {
+static const struct knav_range_ops knav_gp_range_ops = {
.set_notify = knav_gp_set_notify,
.open_queue = knav_gp_open_queue,
.close_queue = knav_gp_close_queue,
@@ -723,7 +722,6 @@ static void kdesc_empty_pool(struct knav_pool *pool)
if (!desc) {
dev_dbg(pool->kdev->dev,
"couldn't unmap desc, continuing\n");
- continue;
}
}
WARN_ON(i != pool->num_desc);
@@ -1076,14 +1074,20 @@ static const char *knav_queue_find_name(struct device_node *node)
}
static int knav_queue_setup_regions(struct knav_device *kdev,
- struct device_node *regions)
+ struct device_node *node)
{
struct device *dev = kdev->dev;
+ struct device_node *regions __free(device_node) =
+ of_get_child_by_name(node, "descriptor-regions");
struct knav_region *region;
struct device_node *child;
u32 temp[2];
int ret;
+ if (!regions)
+ return dev_err_probe(dev, -ENODEV,
+ "descriptor-regions not specified\n");
+
for_each_child_of_node(regions, child) {
region = devm_kzalloc(dev, sizeof(*region), GFP_KERNEL);
if (!region) {
@@ -1104,11 +1108,6 @@ static int knav_queue_setup_regions(struct knav_device *kdev,
continue;
}
- if (!of_get_property(child, "link-index", NULL)) {
- dev_err(dev, "No link info for %s\n", region->name);
- devm_kfree(dev, region);
- continue;
- }
ret = of_property_read_u32(child, "link-index",
&region->link_index);
if (ret) {
@@ -1121,10 +1120,9 @@ static int knav_queue_setup_regions(struct knav_device *kdev,
INIT_LIST_HEAD(&region->pools);
list_add_tail(&region->list, &kdev->regions);
}
- if (list_empty(&kdev->regions)) {
- dev_err(dev, "no valid region information found\n");
- return -ENODEV;
- }
+ if (list_empty(&kdev->regions))
+ return dev_err_probe(dev, -ENODEV,
+ "no valid region information found\n");
/* Next, we run through the regions and set things up */
for_each_region(kdev, region)
@@ -1306,10 +1304,16 @@ static int knav_setup_queue_range(struct knav_device *kdev,
}
static int knav_setup_queue_pools(struct knav_device *kdev,
- struct device_node *queue_pools)
+ struct device_node *node)
{
+ struct device_node *queue_pools __free(device_node) =
+ of_get_child_by_name(node, "queue-pools");
struct device_node *type, *range;
+ if (!queue_pools)
+ return dev_err_probe(kdev->dev, -ENODEV,
+ "queue-pools not specified\n");
+
for_each_child_of_node(queue_pools, type) {
for_each_child_of_node(type, range) {
/* return value ignored, we init the rest... */
@@ -1318,10 +1322,9 @@ static int knav_setup_queue_pools(struct knav_device *kdev,
}
/* ... and barf if they all failed! */
- if (list_empty(&kdev->queue_ranges)) {
- dev_err(kdev->dev, "no valid queue range found\n");
- return -ENODEV;
- }
+ if (list_empty(&kdev->queue_ranges))
+ return dev_err_probe(kdev->dev, -ENODEV,
+ "no valid queue range found\n");
return 0;
}
@@ -1389,14 +1392,20 @@ static void __iomem *knav_queue_map_reg(struct knav_device *kdev,
}
static int knav_queue_init_qmgrs(struct knav_device *kdev,
- struct device_node *qmgrs)
+ struct device_node *node)
{
struct device *dev = kdev->dev;
+ struct device_node *qmgrs __free(device_node) =
+ of_get_child_by_name(node, "qmgrs");
struct knav_qmgr_info *qmgr;
struct device_node *child;
u32 temp[2];
int ret;
+ if (!qmgrs)
+ return dev_err_probe(dev, -ENODEV,
+ "queue manager info not specified\n");
+
for_each_child_of_node(qmgrs, child) {
qmgr = devm_kzalloc(dev, sizeof(*qmgr), GFP_KERNEL);
if (!qmgr) {
@@ -1668,6 +1677,26 @@ static int knav_queue_start_pdsps(struct knav_device *kdev)
return 0;
}
+static int knav_queue_setup_pdsps(struct knav_device *kdev,
+ struct device_node *node)
+{
+ struct device_node *pdsps __free(device_node) =
+ of_get_child_by_name(node, "pdsps");
+
+ if (pdsps) {
+ int ret;
+
+ ret = knav_queue_init_pdsps(kdev, pdsps);
+ if (ret)
+ return ret;
+
+ ret = knav_queue_start_pdsps(kdev);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
static inline struct knav_qmgr_info *knav_find_qmgr(unsigned id)
{
struct knav_qmgr_info *qmgr;
@@ -1755,7 +1784,6 @@ MODULE_DEVICE_TABLE(of, keystone_qmss_of_match);
static int knav_queue_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
- struct device_node *qmgrs, *queue_pools, *regions, *pdsps;
struct device *dev = &pdev->dev;
u32 temp[2];
int ret;
@@ -1799,39 +1827,17 @@ static int knav_queue_probe(struct platform_device *pdev)
kdev->num_queues = temp[1];
/* Initialize queue managers using device tree configuration */
- qmgrs = of_get_child_by_name(node, "qmgrs");
- if (!qmgrs) {
- dev_err(dev, "queue manager info not specified\n");
- ret = -ENODEV;
- goto err;
- }
- ret = knav_queue_init_qmgrs(kdev, qmgrs);
- of_node_put(qmgrs);
+ ret = knav_queue_init_qmgrs(kdev, node);
if (ret)
goto err;
/* get pdsp configuration values from device tree */
- pdsps = of_get_child_by_name(node, "pdsps");
- if (pdsps) {
- ret = knav_queue_init_pdsps(kdev, pdsps);
- if (ret)
- goto err;
-
- ret = knav_queue_start_pdsps(kdev);
- if (ret)
- goto err;
- }
- of_node_put(pdsps);
+ ret = knav_queue_setup_pdsps(kdev, node);
+ if (ret)
+ goto err;
/* get usable queue range values from device tree */
- queue_pools = of_get_child_by_name(node, "queue-pools");
- if (!queue_pools) {
- dev_err(dev, "queue-pools not specified\n");
- ret = -ENODEV;
- goto err;
- }
- ret = knav_setup_queue_pools(kdev, queue_pools);
- of_node_put(queue_pools);
+ ret = knav_setup_queue_pools(kdev, node);
if (ret)
goto err;
@@ -1853,14 +1859,7 @@ static int knav_queue_probe(struct platform_device *pdev)
if (ret)
goto err;
- regions = of_get_child_by_name(node, "descriptor-regions");
- if (!regions) {
- dev_err(dev, "descriptor-regions not specified\n");
- ret = -ENODEV;
- goto err;
- }
- ret = knav_queue_setup_regions(kdev, regions);
- of_node_put(regions);
+ ret = knav_queue_setup_regions(kdev, node);
if (ret)
goto err;
@@ -1893,7 +1892,7 @@ static void knav_queue_remove(struct platform_device *pdev)
static struct platform_driver keystone_qmss_driver = {
.probe = knav_queue_probe,
- .remove_new = knav_queue_remove,
+ .remove = knav_queue_remove,
.driver = {
.name = "keystone-navigator-qmss",
.of_match_table = keystone_qmss_of_match,
diff --git a/drivers/soc/ti/pm33xx.c b/drivers/soc/ti/pm33xx.c
index 8e983c3c4e03..dfdff186c805 100644
--- a/drivers/soc/ti/pm33xx.c
+++ b/drivers/soc/ti/pm33xx.c
@@ -383,54 +383,44 @@ static void am33xx_pm_free_sram(void)
*/
static int am33xx_pm_alloc_sram(void)
{
- struct device_node *np;
- int ret = 0;
+ struct device_node *np __free(device_node) =
+ of_find_compatible_node(NULL, NULL, "ti,omap3-mpu");
- np = of_find_compatible_node(NULL, NULL, "ti,omap3-mpu");
if (!np) {
np = of_find_compatible_node(NULL, NULL, "ti,omap4-mpu");
- if (!np) {
- dev_err(pm33xx_dev, "PM: %s: Unable to find device node for mpu\n",
- __func__);
- return -ENODEV;
- }
+ if (!np)
+ return dev_err_probe(pm33xx_dev, -ENODEV,
+ "PM: %s: Unable to find device node for mpu\n",
+ __func__);
}
sram_pool = of_gen_pool_get(np, "pm-sram", 0);
- if (!sram_pool) {
- dev_err(pm33xx_dev, "PM: %s: Unable to get sram pool for ocmcram\n",
- __func__);
- ret = -ENODEV;
- goto mpu_put_node;
- }
+ if (!sram_pool)
+ return dev_err_probe(pm33xx_dev, -ENODEV,
+ "PM: %s: Unable to get sram pool for ocmcram\n",
+ __func__);
sram_pool_data = of_gen_pool_get(np, "pm-sram", 1);
- if (!sram_pool_data) {
- dev_err(pm33xx_dev, "PM: %s: Unable to get sram data pool for ocmcram\n",
- __func__);
- ret = -ENODEV;
- goto mpu_put_node;
- }
+ if (!sram_pool_data)
+ return dev_err_probe(pm33xx_dev, -ENODEV,
+ "PM: %s: Unable to get sram data pool for ocmcram\n",
+ __func__);
ocmcram_location = gen_pool_alloc(sram_pool, *pm_sram->do_wfi_sz);
- if (!ocmcram_location) {
- dev_err(pm33xx_dev, "PM: %s: Unable to allocate memory from ocmcram\n",
- __func__);
- ret = -ENOMEM;
- goto mpu_put_node;
- }
+ if (!ocmcram_location)
+ return dev_err_probe(pm33xx_dev, -ENOMEM,
+ "PM: %s: Unable to allocate memory from ocmcram\n",
+ __func__);
ocmcram_location_data = gen_pool_alloc(sram_pool_data,
sizeof(struct emif_regs_amx3));
if (!ocmcram_location_data) {
- dev_err(pm33xx_dev, "PM: Unable to allocate memory from ocmcram\n");
gen_pool_free(sram_pool, ocmcram_location, *pm_sram->do_wfi_sz);
- ret = -ENOMEM;
+ return dev_err_probe(pm33xx_dev, -ENOMEM,
+ "PM: Unable to allocate memory from ocmcram\n");
}
-mpu_put_node:
- of_node_put(np);
- return ret;
+ return 0;
}
static int am33xx_pm_rtc_setup(void)
@@ -450,14 +440,14 @@ static int am33xx_pm_rtc_setup(void)
rtc_base_virt = of_iomap(np, 0);
if (!rtc_base_virt) {
- pr_warn("PM: could not iomap rtc");
+ pr_warn("PM: could not iomap rtc\n");
error = -ENODEV;
goto err_clk_put;
}
omap_rtc = rtc_class_open("rtc0");
if (!omap_rtc) {
- pr_warn("PM: rtc0 not available");
+ pr_warn("PM: rtc0 not available\n");
error = -EPROBE_DEFER;
goto err_iounmap;
}
@@ -601,7 +591,7 @@ static struct platform_driver am33xx_pm_driver = {
.name = "pm33xx",
},
.probe = am33xx_pm_probe,
- .remove_new = am33xx_pm_remove,
+ .remove = am33xx_pm_remove,
};
module_platform_driver(am33xx_pm_driver);
diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c
index 24a42e0b645c..d7634bf5413a 100644
--- a/drivers/soc/ti/pruss.c
+++ b/drivers/soc/ti/pruss.c
@@ -380,39 +380,81 @@ put_clk_mux_np:
static int pruss_clk_init(struct pruss *pruss, struct device_node *cfg_node)
{
- const struct pruss_private_data *data;
- struct device_node *clks_np;
struct device *dev = pruss->dev;
- int ret = 0;
-
- data = of_device_get_match_data(dev);
+ struct device_node *clks_np __free(device_node) =
+ of_get_child_by_name(cfg_node, "clocks");
+ const struct pruss_private_data *data = of_device_get_match_data(dev);
+ int ret;
- clks_np = of_get_child_by_name(cfg_node, "clocks");
- if (!clks_np) {
- dev_err(dev, "%pOF is missing its 'clocks' node\n", cfg_node);
- return -ENODEV;
- }
+ if (!clks_np)
+ return dev_err_probe(dev, -ENODEV,
+ "%pOF is missing its 'clocks' node\n",
+ cfg_node);
if (data && data->has_core_mux_clock) {
ret = pruss_clk_mux_setup(pruss, pruss->core_clk_mux,
"coreclk-mux", clks_np);
- if (ret) {
- dev_err(dev, "failed to setup coreclk-mux\n");
- goto put_clks_node;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to setup coreclk-mux\n");
}
ret = pruss_clk_mux_setup(pruss, pruss->iep_clk_mux, "iepclk-mux",
clks_np);
- if (ret) {
- dev_err(dev, "failed to setup iepclk-mux\n");
- goto put_clks_node;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to setup iepclk-mux\n");
-put_clks_node:
- of_node_put(clks_np);
+ return 0;
+}
- return ret;
+static int pruss_of_setup_memories(struct device *dev, struct pruss *pruss)
+{
+ struct device_node *np = dev_of_node(dev);
+ struct device_node *child __free(device_node) =
+ of_get_child_by_name(np, "memories");
+ const struct pruss_private_data *data = of_device_get_match_data(dev);
+ const char *mem_names[PRUSS_MEM_MAX] = { "dram0", "dram1", "shrdram2" };
+ int i;
+
+ if (!child)
+ return dev_err_probe(dev, -ENODEV,
+ "%pOF is missing its 'memories' node\n",
+ child);
+
+ for (i = 0; i < PRUSS_MEM_MAX; i++) {
+ struct resource res;
+ int index;
+
+ /*
+ * On AM437x one of two PRUSS units don't contain Shared RAM,
+ * skip it
+ */
+ if (data && data->has_no_sharedram && i == PRUSS_MEM_SHRD_RAM2)
+ continue;
+
+ index = of_property_match_string(child, "reg-names",
+ mem_names[i]);
+ if (index < 0)
+ return index;
+
+ if (of_address_to_resource(child, index, &res))
+ return -EINVAL;
+
+ pruss->mem_regions[i].va = devm_ioremap(dev, res.start,
+ resource_size(&res));
+ if (!pruss->mem_regions[i].va)
+ return dev_err_probe(dev, -ENOMEM,
+ "failed to parse and map memory resource %d %s\n",
+ i, mem_names[i]);
+ pruss->mem_regions[i].pa = res.start;
+ pruss->mem_regions[i].size = resource_size(&res);
+
+ dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %pK\n",
+ mem_names[i], &pruss->mem_regions[i].pa,
+ pruss->mem_regions[i].size, pruss->mem_regions[i].va);
+ }
+
+ return 0;
}
static struct regmap_config regmap_conf = {
@@ -424,26 +466,21 @@ static struct regmap_config regmap_conf = {
static int pruss_cfg_of_init(struct device *dev, struct pruss *pruss)
{
struct device_node *np = dev_of_node(dev);
- struct device_node *child;
+ struct device_node *child __free(device_node) =
+ of_get_child_by_name(np, "cfg");
struct resource res;
int ret;
- child = of_get_child_by_name(np, "cfg");
- if (!child) {
- dev_err(dev, "%pOF is missing its 'cfg' node\n", child);
- return -ENODEV;
- }
+ if (!child)
+ return dev_err_probe(dev, -ENODEV,
+ "%pOF is missing its 'cfg' node\n", child);
- if (of_address_to_resource(child, 0, &res)) {
- ret = -ENOMEM;
- goto node_put;
- }
+ if (of_address_to_resource(child, 0, &res))
+ return -ENOMEM;
pruss->cfg_base = devm_ioremap(dev, res.start, resource_size(&res));
- if (!pruss->cfg_base) {
- ret = -ENOMEM;
- goto node_put;
- }
+ if (!pruss->cfg_base)
+ return -ENOMEM;
regmap_conf.name = kasprintf(GFP_KERNEL, "%pOFn@%llx", child,
(u64)res.start);
@@ -452,34 +489,22 @@ static int pruss_cfg_of_init(struct device *dev, struct pruss *pruss)
pruss->cfg_regmap = devm_regmap_init_mmio(dev, pruss->cfg_base,
&regmap_conf);
kfree(regmap_conf.name);
- if (IS_ERR(pruss->cfg_regmap)) {
- dev_err(dev, "regmap_init_mmio failed for cfg, ret = %ld\n",
- PTR_ERR(pruss->cfg_regmap));
- ret = PTR_ERR(pruss->cfg_regmap);
- goto node_put;
- }
+ if (IS_ERR(pruss->cfg_regmap))
+ return dev_err_probe(dev, PTR_ERR(pruss->cfg_regmap),
+ "regmap_init_mmio failed for cfg\n");
ret = pruss_clk_init(pruss, child);
if (ret)
- dev_err(dev, "pruss_clk_init failed, ret = %d\n", ret);
+ return dev_err_probe(dev, ret, "pruss_clk_init failed\n");
-node_put:
- of_node_put(child);
- return ret;
+ return 0;
}
static int pruss_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *np = dev_of_node(dev);
- struct device_node *child;
struct pruss *pruss;
- struct resource res;
- int ret, i, index;
- const struct pruss_private_data *data;
- const char *mem_names[PRUSS_MEM_MAX] = { "dram0", "dram1", "shrdram2" };
-
- data = of_device_get_match_data(&pdev->dev);
+ int ret;
ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
if (ret) {
@@ -494,48 +519,9 @@ static int pruss_probe(struct platform_device *pdev)
pruss->dev = dev;
mutex_init(&pruss->lock);
- child = of_get_child_by_name(np, "memories");
- if (!child) {
- dev_err(dev, "%pOF is missing its 'memories' node\n", child);
- return -ENODEV;
- }
-
- for (i = 0; i < PRUSS_MEM_MAX; i++) {
- /*
- * On AM437x one of two PRUSS units don't contain Shared RAM,
- * skip it
- */
- if (data && data->has_no_sharedram && i == PRUSS_MEM_SHRD_RAM2)
- continue;
-
- index = of_property_match_string(child, "reg-names",
- mem_names[i]);
- if (index < 0) {
- of_node_put(child);
- return index;
- }
-
- if (of_address_to_resource(child, index, &res)) {
- of_node_put(child);
- return -EINVAL;
- }
-
- pruss->mem_regions[i].va = devm_ioremap(dev, res.start,
- resource_size(&res));
- if (!pruss->mem_regions[i].va) {
- dev_err(dev, "failed to parse and map memory resource %d %s\n",
- i, mem_names[i]);
- of_node_put(child);
- return -ENOMEM;
- }
- pruss->mem_regions[i].pa = res.start;
- pruss->mem_regions[i].size = resource_size(&res);
-
- dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %pK\n",
- mem_names[i], &pruss->mem_regions[i].pa,
- pruss->mem_regions[i].size, pruss->mem_regions[i].va);
- }
- of_node_put(child);
+ ret = pruss_of_setup_memories(dev, pruss);
+ if (ret < 0)
+ return ret;
platform_set_drvdata(pdev, pruss);
@@ -607,8 +593,8 @@ static struct platform_driver pruss_driver = {
.name = "pruss",
.of_match_table = pruss_of_match,
},
- .probe = pruss_probe,
- .remove_new = pruss_remove,
+ .probe = pruss_probe,
+ .remove = pruss_remove,
};
module_platform_driver(pruss_driver);
diff --git a/drivers/soc/ti/smartreflex.c b/drivers/soc/ti/smartreflex.c
index d6219060b616..ced3a73929e3 100644
--- a/drivers/soc/ti/smartreflex.c
+++ b/drivers/soc/ti/smartreflex.c
@@ -202,10 +202,10 @@ static int sr_late_init(struct omap_sr *sr_info)
if (sr_class->notify && sr_class->notify_flags && sr_info->irq) {
ret = devm_request_irq(&sr_info->pdev->dev, sr_info->irq,
- sr_interrupt, 0, sr_info->name, sr_info);
+ sr_interrupt, IRQF_NO_AUTOEN,
+ sr_info->name, sr_info);
if (ret)
goto error;
- disable_irq(sr_info->irq);
}
return ret;
@@ -969,7 +969,7 @@ MODULE_DEVICE_TABLE(of, omap_sr_match);
static struct platform_driver smartreflex_driver = {
.probe = omap_sr_probe,
- .remove_new = omap_sr_remove,
+ .remove = omap_sr_remove,
.shutdown = omap_sr_shutdown,
.driver = {
.name = DRIVER_NAME,
diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c
index 6a1c6b34c414..79dde9a7ec63 100644
--- a/drivers/soc/ti/wkup_m3_ipc.c
+++ b/drivers/soc/ti/wkup_m3_ipc.c
@@ -16,7 +16,6 @@
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/omap-mailbox.h>
#include <linux/platform_device.h>
#include <linux/remoteproc.h>
#include <linux/suspend.h>
@@ -314,7 +313,6 @@ static irqreturn_t wkup_m3_txev_handler(int irq, void *ipc_data)
static int wkup_m3_ping(struct wkup_m3_ipc *m3_ipc)
{
struct device *dev = m3_ipc->dev;
- mbox_msg_t dummy_msg = 0;
int ret;
if (!m3_ipc->mbox) {
@@ -330,7 +328,7 @@ static int wkup_m3_ping(struct wkup_m3_ipc *m3_ipc)
* the RX callback to avoid multiple interrupts being received
* by the CM3.
*/
- ret = mbox_send_message(m3_ipc->mbox, &dummy_msg);
+ ret = mbox_send_message(m3_ipc->mbox, NULL);
if (ret < 0) {
dev_err(dev, "%s: mbox_send_message() failed: %d\n",
__func__, ret);
@@ -352,7 +350,6 @@ static int wkup_m3_ping(struct wkup_m3_ipc *m3_ipc)
static int wkup_m3_ping_noirq(struct wkup_m3_ipc *m3_ipc)
{
struct device *dev = m3_ipc->dev;
- mbox_msg_t dummy_msg = 0;
int ret;
if (!m3_ipc->mbox) {
@@ -361,7 +358,7 @@ static int wkup_m3_ping_noirq(struct wkup_m3_ipc *m3_ipc)
return -EIO;
}
- ret = mbox_send_message(m3_ipc->mbox, &dummy_msg);
+ ret = mbox_send_message(m3_ipc->mbox, NULL);
if (ret < 0) {
dev_err(dev, "%s: mbox_send_message() failed: %d\n",
__func__, ret);
@@ -758,7 +755,7 @@ MODULE_DEVICE_TABLE(of, wkup_m3_ipc_of_match);
static struct platform_driver wkup_m3_ipc_driver = {
.probe = wkup_m3_ipc_probe,
- .remove_new = wkup_m3_ipc_remove,
+ .remove = wkup_m3_ipc_remove,
.driver = {
.name = "wkup_m3_ipc",
.of_match_table = wkup_m3_ipc_of_match,
diff --git a/drivers/soc/versatile/Kconfig b/drivers/soc/versatile/Kconfig
index c3792c0a84ac..7bbf54a8d879 100644
--- a/drivers/soc/versatile/Kconfig
+++ b/drivers/soc/versatile/Kconfig
@@ -4,7 +4,7 @@
#
config SOC_INTEGRATOR_CM
bool "SoC bus device for the ARM Integrator platform core modules"
- depends on ARCH_INTEGRATOR
+ depends on ARCH_INTEGRATOR || COMPILE_TEST
select SOC_BUS
help
Include support for the SoC bus on the ARM Integrator platform
@@ -13,7 +13,7 @@ config SOC_INTEGRATOR_CM
config SOC_REALVIEW
bool "SoC bus device for the ARM RealView platforms"
- depends on ARCH_REALVIEW
+ depends on ARCH_REALVIEW || COMPILE_TEST
select SOC_BUS
help
Include support for the SoC bus on the ARM RealView platforms
diff --git a/drivers/soc/versatile/soc-integrator.c b/drivers/soc/versatile/soc-integrator.c
index bab4ad87aa75..d5099a3386b4 100644
--- a/drivers/soc/versatile/soc-integrator.c
+++ b/drivers/soc/versatile/soc-integrator.c
@@ -113,6 +113,7 @@ static int __init integrator_soc_init(void)
return -ENODEV;
syscon_regmap = syscon_node_to_regmap(np);
+ of_node_put(np);
if (IS_ERR(syscon_regmap))
return PTR_ERR(syscon_regmap);
diff --git a/drivers/soc/versatile/soc-realview.c b/drivers/soc/versatile/soc-realview.c
index c6876d232d8f..cf91abe07d38 100644
--- a/drivers/soc/versatile/soc-realview.c
+++ b/drivers/soc/versatile/soc-realview.c
@@ -4,6 +4,7 @@
*
* Author: Linus Walleij <linus.walleij@linaro.org>
*/
+#include <linux/device.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/slab.h>
@@ -81,6 +82,13 @@ static struct attribute *realview_attrs[] = {
ATTRIBUTE_GROUPS(realview);
+static void realview_soc_socdev_release(void *data)
+{
+ struct soc_device *soc_dev = data;
+
+ soc_device_unregister(soc_dev);
+}
+
static int realview_soc_probe(struct platform_device *pdev)
{
struct regmap *syscon_regmap;
@@ -93,7 +101,7 @@ static int realview_soc_probe(struct platform_device *pdev)
if (IS_ERR(syscon_regmap))
return PTR_ERR(syscon_regmap);
- soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+ soc_dev_attr = devm_kzalloc(&pdev->dev, sizeof(*soc_dev_attr), GFP_KERNEL);
if (!soc_dev_attr)
return -ENOMEM;
@@ -106,10 +114,14 @@ static int realview_soc_probe(struct platform_device *pdev)
soc_dev_attr->family = "Versatile";
soc_dev_attr->custom_attr_group = realview_groups[0];
soc_dev = soc_device_register(soc_dev_attr);
- if (IS_ERR(soc_dev)) {
- kfree(soc_dev_attr);
+ if (IS_ERR(soc_dev))
return -ENODEV;
- }
+
+ ret = devm_add_action_or_reset(&pdev->dev, realview_soc_socdev_release,
+ soc_dev);
+ if (ret)
+ return ret;
+
ret = regmap_read(syscon_regmap, REALVIEW_SYS_ID_OFFSET,
&realview_coreid);
if (ret)
diff --git a/drivers/soc/xilinx/xlnx_event_manager.c b/drivers/soc/xilinx/xlnx_event_manager.c
index 253299e4214d..a572d15f6161 100644
--- a/drivers/soc/xilinx/xlnx_event_manager.c
+++ b/drivers/soc/xilinx/xlnx_event_manager.c
@@ -3,6 +3,7 @@
* Xilinx Event Management Driver
*
* Copyright (C) 2021 Xilinx, Inc.
+ * Copyright (C) 2024 Advanced Micro Devices, Inc.
*
* Abhyuday Godhasara <abhyuday.godhasara@xilinx.com>
*/
@@ -19,7 +20,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
-static DEFINE_PER_CPU_READ_MOSTLY(int, cpu_number1);
+static DEFINE_PER_CPU_READ_MOSTLY(int, dummy_cpu_number);
static int virq_sgi;
static int event_manager_availability = -EACCES;
@@ -35,7 +36,6 @@ static int event_manager_availability = -EACCES;
#define MAX_BITS (32U) /* Number of bits available for error mask */
-#define FIRMWARE_VERSION_MASK (0xFFFFU)
#define REGISTER_NOTIFIER_FIRMWARE_VERSION (2U)
static DEFINE_HASHTABLE(reg_driver_map, REGISTERED_DRIVER_MAX_ORDER);
@@ -188,8 +188,10 @@ static int xlnx_add_cb_for_suspend(event_cb_func_t cb_fun, void *data)
INIT_LIST_HEAD(&eve_data->cb_list_head);
cb_data = kmalloc(sizeof(*cb_data), GFP_KERNEL);
- if (!cb_data)
+ if (!cb_data) {
+ kfree(eve_data);
return -ENOMEM;
+ }
cb_data->eve_cb = cb_fun;
cb_data->agent_data = data;
@@ -570,7 +572,6 @@ static void xlnx_disable_percpu_irq(void *data)
static int xlnx_event_init_sgi(struct platform_device *pdev)
{
int ret = 0;
- int cpu;
/*
* IRQ related structures are used for the following:
* for each SGI interrupt ensure its mapped by GIC IRQ domain
@@ -607,11 +608,8 @@ static int xlnx_event_init_sgi(struct platform_device *pdev)
sgi_fwspec.param[0] = sgi_num;
virq_sgi = irq_create_fwspec_mapping(&sgi_fwspec);
- cpu = get_cpu();
- per_cpu(cpu_number1, cpu) = cpu;
ret = request_percpu_irq(virq_sgi, xlnx_event_handler, "xlnx_event_mgmt",
- &cpu_number1);
- put_cpu();
+ &dummy_cpu_number);
WARN_ON(ret);
if (ret) {
@@ -627,16 +625,12 @@ static int xlnx_event_init_sgi(struct platform_device *pdev)
static void xlnx_event_cleanup_sgi(struct platform_device *pdev)
{
- int cpu = smp_processor_id();
-
- per_cpu(cpu_number1, cpu) = cpu;
-
cpuhp_remove_state(CPUHP_AP_ONLINE_DYN);
on_each_cpu(xlnx_disable_percpu_irq, NULL, 1);
irq_clear_status_flags(virq_sgi, IRQ_PER_CPU);
- free_percpu_irq(virq_sgi, &cpu_number1);
+ free_percpu_irq(virq_sgi, &dummy_cpu_number);
irq_dispose_mapping(virq_sgi);
}
@@ -717,7 +711,7 @@ static void xlnx_event_manager_remove(struct platform_device *pdev)
static struct platform_driver xlnx_event_manager_driver = {
.probe = xlnx_event_manager_probe,
- .remove_new = xlnx_event_manager_remove,
+ .remove = xlnx_event_manager_remove,
.driver = {
.name = "xlnx_event_manager",
},
diff --git a/drivers/soc/xilinx/zynqmp_power.c b/drivers/soc/xilinx/zynqmp_power.c
index 965b1143936a..ae59bf16659a 100644
--- a/drivers/soc/xilinx/zynqmp_power.c
+++ b/drivers/soc/xilinx/zynqmp_power.c
@@ -30,9 +30,27 @@ struct zynqmp_pm_work_struct {
u32 args[CB_ARG_CNT];
};
-static struct zynqmp_pm_work_struct *zynqmp_pm_init_suspend_work;
+/**
+ * struct zynqmp_pm_event_info - event related information
+ * @cb_fun: Function pointer to store the callback function.
+ * @cb_type: Type of callback from pm_api_cb_id,
+ * PM_NOTIFY_CB - for Error Events,
+ * PM_INIT_SUSPEND_CB - for suspend callback.
+ * @node_id: Node-Id related to event.
+ * @event: Event Mask for the Error Event.
+ * @wake: Flag specifying whether the subsystem should be woken upon
+ * event notification.
+ */
+struct zynqmp_pm_event_info {
+ event_cb_func_t cb_fun;
+ enum pm_api_cb_id cb_type;
+ u32 node_id;
+ u32 event;
+ bool wake;
+};
+
+static struct zynqmp_pm_work_struct *zynqmp_pm_init_suspend_work, *zynqmp_pm_init_restart_work;
static struct mbox_chan *rx_chan;
-static bool event_registered;
enum pm_suspend_mode {
PM_SUSPEND_MODE_FIRST = 0,
@@ -54,6 +72,19 @@ static void zynqmp_pm_get_callback_data(u32 *buf)
zynqmp_pm_invoke_fn(GET_CALLBACK_DATA, buf, 0);
}
+static void subsystem_restart_event_callback(const u32 *payload, void *data)
+{
+ /* First element is callback API ID, others are callback arguments */
+ if (work_pending(&zynqmp_pm_init_restart_work->callback_work))
+ return;
+
+ /* Copy callback arguments into work's structure */
+ memcpy(zynqmp_pm_init_restart_work->args, &payload[0],
+ sizeof(zynqmp_pm_init_restart_work->args));
+
+ queue_work(system_unbound_wq, &zynqmp_pm_init_restart_work->callback_work);
+}
+
static void suspend_event_callback(const u32 *payload, void *data)
{
/* First element is callback API ID, others are callback arguments */
@@ -120,6 +151,37 @@ static void ipi_receive_callback(struct mbox_client *cl, void *data)
}
/**
+ * zynqmp_pm_subsystem_restart_work_fn - Initiate Subsystem restart
+ * @work: Pointer to work_struct
+ *
+ * Bottom-half of PM callback IRQ handler.
+ */
+static void zynqmp_pm_subsystem_restart_work_fn(struct work_struct *work)
+{
+ int ret;
+ struct zynqmp_pm_work_struct *pm_work = container_of(work, struct zynqmp_pm_work_struct,
+ callback_work);
+
+ /* First element is callback API ID, others are callback arguments */
+ if (pm_work->args[0] == PM_NOTIFY_CB) {
+ if (pm_work->args[2] == EVENT_SUBSYSTEM_RESTART) {
+ ret = zynqmp_pm_system_shutdown(ZYNQMP_PM_SHUTDOWN_TYPE_SETSCOPE_ONLY,
+ ZYNQMP_PM_SHUTDOWN_SUBTYPE_SUBSYSTEM);
+ if (ret) {
+ pr_err("unable to set shutdown scope\n");
+ return;
+ }
+
+ kernel_restart(NULL);
+ } else {
+ pr_err("%s Unsupported Event - %d\n", __func__, pm_work->args[2]);
+ }
+ } else {
+ pr_err("%s() Unsupported Callback %d\n", __func__, pm_work->args[0]);
+ }
+}
+
+/**
* zynqmp_pm_init_suspend_work_fn - Initialize suspend
* @work: Pointer to work_struct
*
@@ -184,13 +246,51 @@ static ssize_t suspend_mode_store(struct device *dev,
static DEVICE_ATTR_RW(suspend_mode);
+static void unregister_event(struct device *dev, void *res)
+{
+ struct zynqmp_pm_event_info *event_info = res;
+
+ xlnx_unregister_event(event_info->cb_type, event_info->node_id,
+ event_info->event, event_info->cb_fun, NULL);
+}
+
+static int register_event(struct device *dev, const enum pm_api_cb_id cb_type, const u32 node_id,
+ const u32 event, const bool wake, event_cb_func_t cb_fun)
+{
+ int ret;
+ struct zynqmp_pm_event_info *event_info;
+
+ event_info = devres_alloc(unregister_event, sizeof(struct zynqmp_pm_event_info),
+ GFP_KERNEL);
+ if (!event_info)
+ return -ENOMEM;
+
+ event_info->cb_type = cb_type;
+ event_info->node_id = node_id;
+ event_info->event = event;
+ event_info->wake = wake;
+ event_info->cb_fun = cb_fun;
+
+ ret = xlnx_register_event(event_info->cb_type, event_info->node_id,
+ event_info->event, event_info->wake, event_info->cb_fun, NULL);
+ if (ret) {
+ devres_free(event_info);
+ return ret;
+ }
+
+ devres_add(dev, event_info);
+ return 0;
+}
+
static int zynqmp_pm_probe(struct platform_device *pdev)
{
int ret, irq;
- u32 pm_api_version;
+ u32 pm_api_version, pm_family_code, pm_sub_family_code, node_id;
struct mbox_client *client;
- zynqmp_pm_get_api_version(&pm_api_version);
+ ret = zynqmp_pm_get_api_version(&pm_api_version);
+ if (ret)
+ return ret;
/* Check PM API version number */
if (pm_api_version < ZYNQMP_PM_VERSION)
@@ -203,21 +303,43 @@ static int zynqmp_pm_probe(struct platform_device *pdev)
* is not available to use) or -ENODEV(Xilinx Event Manager not compiled),
* then use ipi-mailbox or interrupt method.
*/
- ret = xlnx_register_event(PM_INIT_SUSPEND_CB, 0, 0, false,
- suspend_event_callback, NULL);
+ ret = register_event(&pdev->dev, PM_INIT_SUSPEND_CB, 0, 0, false,
+ suspend_event_callback);
if (!ret) {
zynqmp_pm_init_suspend_work = devm_kzalloc(&pdev->dev,
sizeof(struct zynqmp_pm_work_struct),
GFP_KERNEL);
- if (!zynqmp_pm_init_suspend_work) {
- xlnx_unregister_event(PM_INIT_SUSPEND_CB, 0, 0,
- suspend_event_callback, NULL);
+ if (!zynqmp_pm_init_suspend_work)
return -ENOMEM;
- }
- event_registered = true;
INIT_WORK(&zynqmp_pm_init_suspend_work->callback_work,
zynqmp_pm_init_suspend_work_fn);
+
+ ret = zynqmp_pm_get_family_info(&pm_family_code, &pm_sub_family_code);
+ if (ret < 0)
+ return ret;
+
+ if (pm_sub_family_code == VERSALNET_SUB_FAMILY_CODE)
+ node_id = PM_DEV_ACPU_0_0;
+ else
+ node_id = PM_DEV_ACPU_0;
+
+ ret = register_event(&pdev->dev, PM_NOTIFY_CB, node_id, EVENT_SUBSYSTEM_RESTART,
+ false, subsystem_restart_event_callback);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to Register with Xilinx Event manager %d\n",
+ ret);
+ return ret;
+ }
+
+ zynqmp_pm_init_restart_work = devm_kzalloc(&pdev->dev,
+ sizeof(struct zynqmp_pm_work_struct),
+ GFP_KERNEL);
+ if (!zynqmp_pm_init_restart_work)
+ return -ENOMEM;
+
+ INIT_WORK(&zynqmp_pm_init_restart_work->callback_work,
+ zynqmp_pm_subsystem_restart_work_fn);
} else if (ret != -EACCES && ret != -ENODEV) {
dev_err(&pdev->dev, "Failed to Register with Xilinx Event manager %d\n", ret);
return ret;
@@ -264,15 +386,8 @@ static int zynqmp_pm_probe(struct platform_device *pdev)
}
ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_suspend_mode.attr);
- if (ret) {
- if (event_registered) {
- xlnx_unregister_event(PM_INIT_SUSPEND_CB, 0, 0, suspend_event_callback,
- NULL);
- event_registered = false;
- }
- dev_err(&pdev->dev, "unable to create sysfs interface\n");
+ if (ret)
return ret;
- }
return 0;
}
@@ -280,8 +395,6 @@ static int zynqmp_pm_probe(struct platform_device *pdev)
static void zynqmp_pm_remove(struct platform_device *pdev)
{
sysfs_remove_file(&pdev->dev.kobj, &dev_attr_suspend_mode.attr);
- if (event_registered)
- xlnx_unregister_event(PM_INIT_SUSPEND_CB, 0, 0, suspend_event_callback, NULL);
if (!rx_chan)
mbox_free_channel(rx_chan);
@@ -295,7 +408,7 @@ MODULE_DEVICE_TABLE(of, pm_of_match);
static struct platform_driver zynqmp_pm_platform_driver = {
.probe = zynqmp_pm_probe,
- .remove_new = zynqmp_pm_remove,
+ .remove = zynqmp_pm_remove,
.driver = {
.name = "zynqmp_power",
.of_match_table = pm_of_match,