summaryrefslogtreecommitdiff
path: root/drivers/soc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/soc')
-rw-r--r--drivers/soc/Kconfig7
-rw-r--r--drivers/soc/Makefile11
-rw-r--r--drivers/soc/actions/Kconfig17
-rw-r--r--drivers/soc/actions/Makefile4
-rw-r--r--drivers/soc/actions/owl-sps-helper.c48
-rw-r--r--drivers/soc/actions/owl-sps.c320
-rw-r--r--drivers/soc/amlogic/Kconfig35
-rw-r--r--drivers/soc/amlogic/Makefile3
-rw-r--r--drivers/soc/amlogic/meson-canvas.c13
-rw-r--r--drivers/soc/amlogic/meson-clk-measure.c462
-rw-r--r--drivers/soc/amlogic/meson-ee-pwrc.c619
-rw-r--r--drivers/soc/amlogic/meson-gx-pwrc-vpu.c382
-rw-r--r--drivers/soc/amlogic/meson-gx-socinfo.c23
-rw-r--r--drivers/soc/amlogic/meson-secure-pwrc.c231
-rw-r--r--drivers/soc/apple/Kconfig23
-rw-r--r--drivers/soc/apple/Makefile4
-rw-r--r--drivers/soc/apple/apple-pmgr-pwrstate.c324
-rw-r--r--drivers/soc/apple/mailbox.c463
-rw-r--r--drivers/soc/apple/mailbox.h48
-rw-r--r--drivers/soc/apple/rtkit-crashlog.c93
-rw-r--r--drivers/soc/apple/rtkit-internal.h9
-rw-r--r--drivers/soc/apple/rtkit.c298
-rw-r--r--drivers/soc/apple/sart.c73
-rw-r--r--drivers/soc/aspeed/aspeed-lpc-ctrl.c18
-rw-r--r--drivers/soc/aspeed/aspeed-lpc-snoop.c230
-rw-r--r--drivers/soc/aspeed/aspeed-p2a-ctrl.c20
-rw-r--r--drivers/soc/aspeed/aspeed-socinfo.c5
-rw-r--r--drivers/soc/aspeed/aspeed-uart-routing.c9
-rw-r--r--drivers/soc/atmel/sfr.c1
-rw-r--r--drivers/soc/atmel/soc.c39
-rw-r--r--drivers/soc/atmel/soc.h15
-rw-r--r--drivers/soc/bcm/Kconfig33
-rw-r--r--drivers/soc/bcm/Makefile3
-rw-r--r--drivers/soc/bcm/bcm2835-power.c720
-rw-r--r--drivers/soc/bcm/bcm63xx/Kconfig21
-rw-r--r--drivers/soc/bcm/bcm63xx/Makefile3
-rw-r--r--drivers/soc/bcm/bcm63xx/bcm-pmb.c364
-rw-r--r--drivers/soc/bcm/bcm63xx/bcm63xx-power.c376
-rw-r--r--drivers/soc/bcm/brcmstb/Kconfig4
-rw-r--r--drivers/soc/bcm/brcmstb/biuctrl.c16
-rw-r--r--drivers/soc/bcm/brcmstb/pm/Makefile1
-rw-r--r--drivers/soc/bcm/brcmstb/pm/aon_defs.h105
-rw-r--r--drivers/soc/bcm/brcmstb/pm/pm-arm.c874
-rw-r--r--drivers/soc/bcm/brcmstb/pm/pm.h2
-rw-r--r--drivers/soc/bcm/brcmstb/pm/s2-arm.S69
-rw-r--r--drivers/soc/bcm/raspberrypi-power.c246
-rw-r--r--drivers/soc/canaan/Kconfig9
-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/dove/pmu.c12
-rw-r--r--drivers/soc/fsl/Kconfig4
-rw-r--r--drivers/soc/fsl/dpaa2-console.c7
-rw-r--r--drivers/soc/fsl/dpio/dpio-driver.c8
-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.c20
-rw-r--r--drivers/soc/fsl/qbman/dpaa_sys.h4
-rw-r--r--drivers/soc/fsl/qbman/qman.c34
-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.c10
-rw-r--r--drivers/soc/fsl/qe/Kconfig29
-rw-r--r--drivers/soc/fsl/qe/Makefile2
-rw-r--r--drivers/soc/fsl/qe/gpio.c149
-rw-r--r--drivers/soc/fsl/qe/qe.c9
-rw-r--r--drivers/soc/fsl/qe/qe_common.c85
-rw-r--r--drivers/soc/fsl/qe/qe_ic.c24
-rw-r--r--drivers/soc/fsl/qe/qe_tdm.c4
-rw-r--r--drivers/soc/fsl/qe/qmc.c2269
-rw-r--r--drivers/soc/fsl/qe/tsa.c1168
-rw-r--r--drivers/soc/fsl/qe/tsa.h45
-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.c5
-rw-r--r--drivers/soc/hisilicon/Kconfig24
-rw-r--r--drivers/soc/hisilicon/Makefile2
-rw-r--r--drivers/soc/hisilicon/kunpeng_hccs.c1834
-rw-r--r--drivers/soc/hisilicon/kunpeng_hccs.h233
-rw-r--r--drivers/soc/imx/Kconfig10
-rw-r--r--drivers/soc/imx/Makefile7
-rw-r--r--drivers/soc/imx/gpc.c554
-rw-r--r--drivers/soc/imx/gpcv2.c1550
-rw-r--r--drivers/soc/imx/imx8m-blk-ctrl.c878
-rw-r--r--drivers/soc/imx/imx8mp-blk-ctrl.c758
-rw-r--r--drivers/soc/imx/imx93-blk-ctrl.c436
-rw-r--r--drivers/soc/imx/imx93-pd.c177
-rw-r--r--drivers/soc/imx/imx93-src.c1
-rw-r--r--drivers/soc/imx/soc-imx8m.c285
-rw-r--r--drivers/soc/imx/soc-imx9.c128
-rw-r--r--drivers/soc/ixp4xx/ixp4xx-npe.c11
-rw-r--r--drivers/soc/ixp4xx/ixp4xx-qmgr.c4
-rw-r--r--drivers/soc/litex/Kconfig2
-rw-r--r--drivers/soc/litex/litex_soc_ctrl.c28
-rw-r--r--drivers/soc/loongson/Kconfig11
-rw-r--r--drivers/soc/loongson/Makefile1
-rw-r--r--drivers/soc/loongson/loongson2_guts.c15
-rw-r--r--drivers/soc/loongson/loongson2_pm.c220
-rw-r--r--drivers/soc/mediatek/Kconfig48
-rw-r--r--drivers/soc/mediatek/Makefile5
-rw-r--r--drivers/soc/mediatek/mt6795-pm-domains.h112
-rw-r--r--drivers/soc/mediatek/mt8167-mmsys.h31
-rw-r--r--drivers/soc/mediatek/mt8167-pm-domains.h105
-rw-r--r--drivers/soc/mediatek/mt8173-mmsys.h80
-rw-r--r--drivers/soc/mediatek/mt8173-pm-domains.h123
-rw-r--r--drivers/soc/mediatek/mt8183-mmsys.h50
-rw-r--r--drivers/soc/mediatek/mt8183-pm-domains.h266
-rw-r--r--drivers/soc/mediatek/mt8186-mmsys.h88
-rw-r--r--drivers/soc/mediatek/mt8186-pm-domains.h344
-rw-r--r--drivers/soc/mediatek/mt8188-mmsys.h327
-rw-r--r--drivers/soc/mediatek/mt8192-mmsys.h71
-rw-r--r--drivers/soc/mediatek/mt8192-pm-domains.h355
-rw-r--r--drivers/soc/mediatek/mt8195-mmsys.h645
-rw-r--r--drivers/soc/mediatek/mt8195-pm-domains.h613
-rw-r--r--drivers/soc/mediatek/mt8365-mmsys.h84
-rw-r--r--drivers/soc/mediatek/mtk-cmdq-helper.c387
-rw-r--r--drivers/soc/mediatek/mtk-devapc.c36
-rw-r--r--drivers/soc/mediatek/mtk-dvfsrc.c578
-rw-r--r--drivers/soc/mediatek/mtk-mmsys.c349
-rw-r--r--drivers/soc/mediatek/mtk-mmsys.h50
-rw-r--r--drivers/soc/mediatek/mtk-mutex.c503
-rw-r--r--drivers/soc/mediatek/mtk-pm-domains.c675
-rw-r--r--drivers/soc/mediatek/mtk-pm-domains.h106
-rw-r--r--drivers/soc/mediatek/mtk-pmic-wrap.c413
-rw-r--r--drivers/soc/mediatek/mtk-regulator-coupler.c160
-rw-r--r--drivers/soc/mediatek/mtk-scpsys.c1147
-rw-r--r--drivers/soc/mediatek/mtk-socinfo.c212
-rw-r--r--drivers/soc/mediatek/mtk-svs.c1901
-rw-r--r--drivers/soc/microchip/Kconfig15
-rw-r--r--drivers/soc/microchip/Makefile1
-rw-r--r--drivers/soc/microchip/mpfs-control-scb.c38
-rw-r--r--drivers/soc/microchip/mpfs-mss-top-sysreg.c44
-rw-r--r--drivers/soc/microchip/mpfs-sys-controller.c93
-rw-r--r--drivers/soc/nuvoton/Kconfig11
-rw-r--r--drivers/soc/nuvoton/Makefile2
-rw-r--r--drivers/soc/nuvoton/wpcm450-soc.c109
-rw-r--r--drivers/soc/pxa/ssp.c10
-rw-r--r--drivers/soc/qcom/Kconfig133
-rw-r--r--drivers/soc/qcom/Makefile19
-rw-r--r--drivers/soc/qcom/apr.c19
-rw-r--r--drivers/soc/qcom/cmd-db.c53
-rw-r--r--drivers/soc/qcom/cpr.c1757
-rw-r--r--drivers/soc/qcom/icc-bwmon.c292
-rw-r--r--drivers/soc/qcom/ice.c754
-rw-r--r--drivers/soc/qcom/kryo-l2-accessors.c4
-rw-r--r--drivers/soc/qcom/llcc-qcom.c4579
-rw-r--r--drivers/soc/qcom/mdt_loader.c174
-rw-r--r--drivers/soc/qcom/ocmem.c107
-rw-r--r--drivers/soc/qcom/pdr_interface.c62
-rw-r--r--drivers/soc/qcom/pdr_internal.h317
-rw-r--r--drivers/soc/qcom/pmic_glink.c431
-rw-r--r--drivers/soc/qcom/pmic_glink_altmode.c558
-rw-r--r--drivers/soc/qcom/pmic_pdcharger_ulog.c170
-rw-r--r--drivers/soc/qcom/pmic_pdcharger_ulog.h36
-rw-r--r--drivers/soc/qcom/qcom-geni-se.c652
-rw-r--r--drivers/soc/qcom/qcom-pbs.c228
-rw-r--r--drivers/soc/qcom/qcom_aoss.c175
-rw-r--r--drivers/soc/qcom/qcom_gsbi.c23
-rw-r--r--drivers/soc/qcom/qcom_pd_mapper.c731
-rw-r--r--drivers/soc/qcom/qcom_pdr_msg.c352
-rw-r--r--drivers/soc/qcom/qcom_stats.c151
-rw-r--r--drivers/soc/qcom/qmi_encdec.c62
-rw-r--r--drivers/soc/qcom/qmi_interface.c33
-rw-r--r--drivers/soc/qcom/ramp_controller.c345
-rw-r--r--drivers/soc/qcom/rmtfs_mem.c54
-rw-r--r--drivers/soc/qcom/rpm-proc.c77
-rw-r--r--drivers/soc/qcom/rpm_master_stats.c167
-rw-r--r--drivers/soc/qcom/rpmh-rsc.c32
-rw-r--r--drivers/soc/qcom/rpmh.c9
-rw-r--r--drivers/soc/qcom/rpmhpd.c820
-rw-r--r--drivers/soc/qcom/rpmpd.c713
-rw-r--r--drivers/soc/qcom/smd-rpm.c28
-rw-r--r--drivers/soc/qcom/smem.c180
-rw-r--r--drivers/soc/qcom/smem_state.c15
-rw-r--r--drivers/soc/qcom/smp2p.c59
-rw-r--r--drivers/soc/qcom/smsm.c72
-rw-r--r--drivers/soc/qcom/socinfo.c399
-rw-r--r--drivers/soc/qcom/spm.c255
-rw-r--r--drivers/soc/qcom/trace-aoss.h48
-rw-r--r--drivers/soc/qcom/trace-rpmh.h20
-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/ubwc_config.c317
-rw-r--r--drivers/soc/qcom/wcnss_ctrl.c15
-rw-r--r--drivers/soc/renesas/Kconfig512
-rw-r--r--drivers/soc/renesas/Makefile33
-rw-r--r--drivers/soc/renesas/pwc-rzv2m.c143
-rw-r--r--drivers/soc/renesas/r8a7742-sysc.c42
-rw-r--r--drivers/soc/renesas/r8a7743-sysc.c28
-rw-r--r--drivers/soc/renesas/r8a7745-sysc.c28
-rw-r--r--drivers/soc/renesas/r8a77470-sysc.c28
-rw-r--r--drivers/soc/renesas/r8a774a1-sysc.c44
-rw-r--r--drivers/soc/renesas/r8a774b1-sysc.c37
-rw-r--r--drivers/soc/renesas/r8a774c0-sysc.c55
-rw-r--r--drivers/soc/renesas/r8a774e1-sysc.c43
-rw-r--r--drivers/soc/renesas/r8a7779-sysc.c30
-rw-r--r--drivers/soc/renesas/r8a7790-sysc.c44
-rw-r--r--drivers/soc/renesas/r8a7791-sysc.c29
-rw-r--r--drivers/soc/renesas/r8a7792-sysc.c30
-rw-r--r--drivers/soc/renesas/r8a7794-sysc.c29
-rw-r--r--drivers/soc/renesas/r8a7795-sysc.c96
-rw-r--r--drivers/soc/renesas/r8a7796-sysc.c67
-rw-r--r--drivers/soc/renesas/r8a77965-sysc.c38
-rw-r--r--drivers/soc/renesas/r8a77970-sysc.c37
-rw-r--r--drivers/soc/renesas/r8a77980-sysc.c54
-rw-r--r--drivers/soc/renesas/r8a77990-sysc.c55
-rw-r--r--drivers/soc/renesas/r8a77995-sysc.c26
-rw-r--r--drivers/soc/renesas/r8a779a0-sysc.c76
-rw-r--r--drivers/soc/renesas/r8a779f0-sysc.c47
-rw-r--r--drivers/soc/renesas/r8a779g0-sysc.c62
-rw-r--r--drivers/soc/renesas/r9a08g045-sysc.c93
-rw-r--r--drivers/soc/renesas/r9a09g047-sys.c147
-rw-r--r--drivers/soc/renesas/r9a09g056-sys.c144
-rw-r--r--drivers/soc/renesas/r9a09g057-sys.c169
-rw-r--r--drivers/soc/renesas/rcar-gen4-sysc.c379
-rw-r--r--drivers/soc/renesas/rcar-gen4-sysc.h44
-rw-r--r--drivers/soc/renesas/rcar-rst.c17
-rw-r--r--drivers/soc/renesas/rcar-sysc.c494
-rw-r--r--drivers/soc/renesas/rcar-sysc.h82
-rw-r--r--drivers/soc/renesas/renesas-soc.c51
-rw-r--r--drivers/soc/renesas/rmobile-sysc.c354
-rw-r--r--drivers/soc/renesas/rz-sysc.c169
-rw-r--r--drivers/soc/renesas/rz-sysc.h53
-rw-r--r--drivers/soc/rockchip/Kconfig12
-rw-r--r--drivers/soc/rockchip/Makefile1
-rw-r--r--drivers/soc/rockchip/dtpm.c54
-rw-r--r--drivers/soc/rockchip/grf.c86
-rw-r--r--drivers/soc/rockchip/io-domain.c52
-rw-r--r--drivers/soc/rockchip/pm_domains.c1305
-rw-r--r--drivers/soc/samsung/Kconfig31
-rw-r--r--drivers/soc/samsung/Makefile5
-rw-r--r--drivers/soc/samsung/exynos-asv.c11
-rw-r--r--drivers/soc/samsung/exynos-chipid.c36
-rw-r--r--drivers/soc/samsung/exynos-pmu.c434
-rw-r--r--drivers/soc/samsung/exynos-pmu.h41
-rw-r--r--drivers/soc/samsung/exynos-usi.c108
-rw-r--r--drivers/soc/samsung/exynos3250-pmu.c1
-rw-r--r--drivers/soc/samsung/exynos4-pmu.c13
-rw-r--r--drivers/soc/samsung/exynos5250-pmu.c1
-rw-r--r--drivers/soc/samsung/exynos5420-pmu.c1
-rw-r--r--drivers/soc/samsung/gs101-pmu.c446
-rw-r--r--drivers/soc/samsung/pm_domains.c166
-rw-r--r--drivers/soc/samsung/s3c-pm-debug.c79
-rw-r--r--drivers/soc/sifive/Kconfig10
-rw-r--r--drivers/soc/sifive/Makefile3
-rw-r--r--drivers/soc/sifive/sifive_ccache.c272
-rw-r--r--drivers/soc/sophgo/Kconfig34
-rw-r--r--drivers/soc/sophgo/Makefile4
-rw-r--r--drivers/soc/sophgo/cv1800-rtcsys.c63
-rw-r--r--drivers/soc/sophgo/sg2044-topsys.c45
-rw-r--r--drivers/soc/sunxi/sunxi_mbus.c2
-rw-r--r--drivers/soc/sunxi/sunxi_sram.c46
-rw-r--r--drivers/soc/tegra/Kconfig29
-rw-r--r--drivers/soc/tegra/Makefile1
-rw-r--r--drivers/soc/tegra/cbb/tegra-cbb.c33
-rw-r--r--drivers/soc/tegra/cbb/tegra194-cbb.c50
-rw-r--r--drivers/soc/tegra/cbb/tegra234-cbb.c771
-rw-r--r--drivers/soc/tegra/common.c12
-rw-r--r--drivers/soc/tegra/flowctrl.c4
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra.c129
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra20.c2
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra30.c166
-rw-r--r--drivers/soc/tegra/fuse/fuse.h8
-rw-r--r--drivers/soc/tegra/fuse/speedo-tegra210.c63
-rw-r--r--drivers/soc/tegra/fuse/tegra-apbmisc.c116
-rw-r--r--drivers/soc/tegra/pmc.c405
-rw-r--r--drivers/soc/tegra/powergate-bpmp.c361
-rw-r--r--drivers/soc/ti/Kconfig14
-rw-r--r--drivers/soc/ti/Makefile2
-rw-r--r--drivers/soc/ti/k3-ringacc.c55
-rw-r--r--drivers/soc/ti/k3-socinfo.c101
-rw-r--r--drivers/soc/ti/knav_dma.c46
-rw-r--r--drivers/soc/ti/knav_qmss.h2
-rw-r--r--drivers/soc/ti/knav_qmss_acc.c4
-rw-r--r--drivers/soc/ti/knav_qmss_queue.c131
-rw-r--r--drivers/soc/ti/omap_prm.c994
-rw-r--r--drivers/soc/ti/pm33xx.c66
-rw-r--r--drivers/soc/ti/pruss.c449
-rw-r--r--drivers/soc/ti/pruss.h88
-rw-r--r--drivers/soc/ti/smartreflex.c45
-rw-r--r--drivers/soc/ti/ti_sci_inta_msi.c13
-rw-r--r--drivers/soc/ti/ti_sci_pm_domains.c208
-rw-r--r--drivers/soc/ti/wkup_m3_ipc.c27
-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/vt8500/Kconfig19
-rw-r--r--drivers/soc/vt8500/Makefile2
-rw-r--r--drivers/soc/vt8500/wmt-socinfo.c125
-rw-r--r--drivers/soc/xilinx/Kconfig9
-rw-r--r--drivers/soc/xilinx/Makefile1
-rw-r--r--drivers/soc/xilinx/xlnx_event_manager.c68
-rw-r--r--drivers/soc/xilinx/zynqmp_pm_domains.c322
-rw-r--r--drivers/soc/xilinx/zynqmp_power.c182
295 files changed, 28814 insertions, 27569 deletions
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index 5dbb09f843f7..a2d65adffb80 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -1,32 +1,35 @@
# SPDX-License-Identifier: GPL-2.0-only
menu "SOC (System On Chip) specific Drivers"
-source "drivers/soc/actions/Kconfig"
source "drivers/soc/amlogic/Kconfig"
source "drivers/soc/apple/Kconfig"
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"
source "drivers/soc/imx/Kconfig"
source "drivers/soc/ixp4xx/Kconfig"
source "drivers/soc/litex/Kconfig"
source "drivers/soc/loongson/Kconfig"
source "drivers/soc/mediatek/Kconfig"
source "drivers/soc/microchip/Kconfig"
+source "drivers/soc/nuvoton/Kconfig"
source "drivers/soc/pxa/Kconfig"
source "drivers/soc/qcom/Kconfig"
source "drivers/soc/renesas/Kconfig"
source "drivers/soc/rockchip/Kconfig"
source "drivers/soc/samsung/Kconfig"
-source "drivers/soc/sifive/Kconfig"
+source "drivers/soc/sophgo/Kconfig"
source "drivers/soc/sunxi/Kconfig"
source "drivers/soc/tegra/Kconfig"
source "drivers/soc/ti/Kconfig"
source "drivers/soc/ux500/Kconfig"
source "drivers/soc/versatile/Kconfig"
+source "drivers/soc/vt8500/Kconfig"
source "drivers/soc/xilinx/Kconfig"
endmenu
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index fff513bd522d..c9e689080ceb 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -3,17 +3,18 @@
# Makefile for the Linux Kernel SOC specific device drivers.
#
-obj-$(CONFIG_ARCH_ACTIONS) += actions/
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/
obj-y += fujitsu/
obj-$(CONFIG_ARCH_GEMINI) += gemini/
+obj-y += hisilicon/
obj-y += imx/
obj-y += ixp4xx/
obj-$(CONFIG_SOC_XWAY) += lantiq/
@@ -21,16 +22,18 @@ obj-$(CONFIG_LITEX_SOC_CONTROLLER) += litex/
obj-y += loongson/
obj-y += mediatek/
obj-y += microchip/
+obj-y += nuvoton/
obj-y += pxa/
obj-y += amlogic/
obj-y += qcom/
obj-y += renesas/
obj-y += rockchip/
obj-$(CONFIG_SOC_SAMSUNG) += samsung/
-obj-$(CONFIG_SOC_SIFIVE) += sifive/
+obj-y += sophgo/
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 += vt8500/
obj-y += xilinx/
diff --git a/drivers/soc/actions/Kconfig b/drivers/soc/actions/Kconfig
deleted file mode 100644
index 1aca2058a40c..000000000000
--- a/drivers/soc/actions/Kconfig
+++ /dev/null
@@ -1,17 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-if ARCH_ACTIONS || COMPILE_TEST
-
-config OWL_PM_DOMAINS_HELPER
- bool
-
-config OWL_PM_DOMAINS
- bool "Actions Semi SPS power domains"
- depends on PM
- select OWL_PM_DOMAINS_HELPER
- select PM_GENERIC_DOMAINS
- help
- Say 'y' here to enable support for Smart Power System (SPS)
- power-gating on Actions Semiconductor S500, S700 and S900 SoCs.
- If unsure, say 'n'.
-
-endif
diff --git a/drivers/soc/actions/Makefile b/drivers/soc/actions/Makefile
deleted file mode 100644
index 4db9e7b050e5..000000000000
--- a/drivers/soc/actions/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0+
-
-obj-$(CONFIG_OWL_PM_DOMAINS_HELPER) += owl-sps-helper.o
-obj-$(CONFIG_OWL_PM_DOMAINS) += owl-sps.o
diff --git a/drivers/soc/actions/owl-sps-helper.c b/drivers/soc/actions/owl-sps-helper.c
deleted file mode 100644
index e3f36603dd53..000000000000
--- a/drivers/soc/actions/owl-sps-helper.c
+++ /dev/null
@@ -1,48 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Actions Semi Owl Smart Power System (SPS) shared helpers
- *
- * Copyright 2012 Actions Semi Inc.
- * Author: Actions Semi, Inc.
- *
- * Copyright (c) 2017 Andreas Färber
- */
-
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/soc/actions/owl-sps.h>
-
-#define OWL_SPS_PG_CTL 0x0
-
-int owl_sps_set_pg(void __iomem *base, u32 pwr_mask, u32 ack_mask, bool enable)
-{
- u32 val;
- bool ack;
- int timeout;
-
- val = readl(base + OWL_SPS_PG_CTL);
- ack = val & ack_mask;
- if (ack == enable)
- return 0;
-
- if (enable)
- val |= pwr_mask;
- else
- val &= ~pwr_mask;
-
- writel(val, base + OWL_SPS_PG_CTL);
-
- for (timeout = 5000; timeout > 0; timeout -= 50) {
- val = readl(base + OWL_SPS_PG_CTL);
- if ((val & ack_mask) == (enable ? ack_mask : 0))
- break;
- udelay(50);
- }
- if (timeout <= 0)
- return -ETIMEDOUT;
-
- udelay(10);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(owl_sps_set_pg);
diff --git a/drivers/soc/actions/owl-sps.c b/drivers/soc/actions/owl-sps.c
deleted file mode 100644
index 73a9e0bb7e8e..000000000000
--- a/drivers/soc/actions/owl-sps.c
+++ /dev/null
@@ -1,320 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Actions Semi Owl Smart Power System (SPS)
- *
- * Copyright 2012 Actions Semi Inc.
- * Author: Actions Semi, Inc.
- *
- * Copyright (c) 2017 Andreas Färber
- */
-
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <linux/pm_domain.h>
-#include <linux/soc/actions/owl-sps.h>
-#include <dt-bindings/power/owl-s500-powergate.h>
-#include <dt-bindings/power/owl-s700-powergate.h>
-#include <dt-bindings/power/owl-s900-powergate.h>
-
-struct owl_sps_domain_info {
- const char *name;
- int pwr_bit;
- int ack_bit;
- unsigned int genpd_flags;
-};
-
-struct owl_sps_info {
- unsigned num_domains;
- const struct owl_sps_domain_info *domains;
-};
-
-struct owl_sps {
- struct device *dev;
- const struct owl_sps_info *info;
- void __iomem *base;
- struct genpd_onecell_data genpd_data;
- struct generic_pm_domain *domains[];
-};
-
-#define to_owl_pd(gpd) container_of(gpd, struct owl_sps_domain, genpd)
-
-struct owl_sps_domain {
- struct generic_pm_domain genpd;
- const struct owl_sps_domain_info *info;
- struct owl_sps *sps;
-};
-
-static int owl_sps_set_power(struct owl_sps_domain *pd, bool enable)
-{
- u32 pwr_mask, ack_mask;
-
- ack_mask = BIT(pd->info->ack_bit);
- pwr_mask = BIT(pd->info->pwr_bit);
-
- return owl_sps_set_pg(pd->sps->base, pwr_mask, ack_mask, enable);
-}
-
-static int owl_sps_power_on(struct generic_pm_domain *domain)
-{
- struct owl_sps_domain *pd = to_owl_pd(domain);
-
- dev_dbg(pd->sps->dev, "%s power on", pd->info->name);
-
- return owl_sps_set_power(pd, true);
-}
-
-static int owl_sps_power_off(struct generic_pm_domain *domain)
-{
- struct owl_sps_domain *pd = to_owl_pd(domain);
-
- dev_dbg(pd->sps->dev, "%s power off", pd->info->name);
-
- return owl_sps_set_power(pd, false);
-}
-
-static int owl_sps_init_domain(struct owl_sps *sps, int index)
-{
- struct owl_sps_domain *pd;
-
- pd = devm_kzalloc(sps->dev, sizeof(*pd), GFP_KERNEL);
- if (!pd)
- return -ENOMEM;
-
- pd->info = &sps->info->domains[index];
- pd->sps = sps;
-
- pd->genpd.name = pd->info->name;
- pd->genpd.power_on = owl_sps_power_on;
- pd->genpd.power_off = owl_sps_power_off;
- pd->genpd.flags = pd->info->genpd_flags;
- pm_genpd_init(&pd->genpd, NULL, false);
-
- sps->genpd_data.domains[index] = &pd->genpd;
-
- return 0;
-}
-
-static int owl_sps_probe(struct platform_device *pdev)
-{
- const struct of_device_id *match;
- const struct owl_sps_info *sps_info;
- struct owl_sps *sps;
- int i, ret;
-
- if (!pdev->dev.of_node) {
- dev_err(&pdev->dev, "no device node\n");
- return -ENODEV;
- }
-
- match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev);
- if (!match || !match->data) {
- dev_err(&pdev->dev, "unknown compatible or missing data\n");
- return -EINVAL;
- }
-
- sps_info = match->data;
-
- sps = devm_kzalloc(&pdev->dev,
- struct_size(sps, domains, sps_info->num_domains),
- GFP_KERNEL);
- if (!sps)
- return -ENOMEM;
-
- sps->base = of_io_request_and_map(pdev->dev.of_node, 0, "owl-sps");
- if (IS_ERR(sps->base)) {
- dev_err(&pdev->dev, "failed to map sps registers\n");
- return PTR_ERR(sps->base);
- }
-
- sps->dev = &pdev->dev;
- sps->info = sps_info;
- sps->genpd_data.domains = sps->domains;
- sps->genpd_data.num_domains = sps_info->num_domains;
-
- for (i = 0; i < sps_info->num_domains; i++) {
- ret = owl_sps_init_domain(sps, i);
- if (ret)
- return ret;
- }
-
- ret = of_genpd_add_provider_onecell(pdev->dev.of_node, &sps->genpd_data);
- if (ret) {
- dev_err(&pdev->dev, "failed to add provider (%d)", ret);
- return ret;
- }
-
- return 0;
-}
-
-static const struct owl_sps_domain_info s500_sps_domains[] = {
- [S500_PD_VDE] = {
- .name = "VDE",
- .pwr_bit = 0,
- .ack_bit = 16,
- },
- [S500_PD_VCE_SI] = {
- .name = "VCE_SI",
- .pwr_bit = 1,
- .ack_bit = 17,
- },
- [S500_PD_USB2_1] = {
- .name = "USB2_1",
- .pwr_bit = 2,
- .ack_bit = 18,
- },
- [S500_PD_CPU2] = {
- .name = "CPU2",
- .pwr_bit = 5,
- .ack_bit = 21,
- .genpd_flags = GENPD_FLAG_ALWAYS_ON,
- },
- [S500_PD_CPU3] = {
- .name = "CPU3",
- .pwr_bit = 6,
- .ack_bit = 22,
- .genpd_flags = GENPD_FLAG_ALWAYS_ON,
- },
- [S500_PD_DMA] = {
- .name = "DMA",
- .pwr_bit = 8,
- .ack_bit = 12,
- },
- [S500_PD_DS] = {
- .name = "DS",
- .pwr_bit = 9,
- .ack_bit = 13,
- },
- [S500_PD_USB3] = {
- .name = "USB3",
- .pwr_bit = 10,
- .ack_bit = 14,
- },
- [S500_PD_USB2_0] = {
- .name = "USB2_0",
- .pwr_bit = 11,
- .ack_bit = 15,
- },
-};
-
-static const struct owl_sps_info s500_sps_info = {
- .num_domains = ARRAY_SIZE(s500_sps_domains),
- .domains = s500_sps_domains,
-};
-
-static const struct owl_sps_domain_info s700_sps_domains[] = {
- [S700_PD_VDE] = {
- .name = "VDE",
- .pwr_bit = 0,
- },
- [S700_PD_VCE_SI] = {
- .name = "VCE_SI",
- .pwr_bit = 1,
- },
- [S700_PD_USB2_1] = {
- .name = "USB2_1",
- .pwr_bit = 2,
- },
- [S700_PD_HDE] = {
- .name = "HDE",
- .pwr_bit = 7,
- },
- [S700_PD_DMA] = {
- .name = "DMA",
- .pwr_bit = 8,
- },
- [S700_PD_DS] = {
- .name = "DS",
- .pwr_bit = 9,
- },
- [S700_PD_USB3] = {
- .name = "USB3",
- .pwr_bit = 10,
- },
- [S700_PD_USB2_0] = {
- .name = "USB2_0",
- .pwr_bit = 11,
- },
-};
-
-static const struct owl_sps_info s700_sps_info = {
- .num_domains = ARRAY_SIZE(s700_sps_domains),
- .domains = s700_sps_domains,
-};
-
-static const struct owl_sps_domain_info s900_sps_domains[] = {
- [S900_PD_GPU_B] = {
- .name = "GPU_B",
- .pwr_bit = 3,
- },
- [S900_PD_VCE] = {
- .name = "VCE",
- .pwr_bit = 4,
- },
- [S900_PD_SENSOR] = {
- .name = "SENSOR",
- .pwr_bit = 5,
- },
- [S900_PD_VDE] = {
- .name = "VDE",
- .pwr_bit = 6,
- },
- [S900_PD_HDE] = {
- .name = "HDE",
- .pwr_bit = 7,
- },
- [S900_PD_USB3] = {
- .name = "USB3",
- .pwr_bit = 8,
- },
- [S900_PD_DDR0] = {
- .name = "DDR0",
- .pwr_bit = 9,
- },
- [S900_PD_DDR1] = {
- .name = "DDR1",
- .pwr_bit = 10,
- },
- [S900_PD_DE] = {
- .name = "DE",
- .pwr_bit = 13,
- },
- [S900_PD_NAND] = {
- .name = "NAND",
- .pwr_bit = 14,
- },
- [S900_PD_USB2_H0] = {
- .name = "USB2_H0",
- .pwr_bit = 15,
- },
- [S900_PD_USB2_H1] = {
- .name = "USB2_H1",
- .pwr_bit = 16,
- },
-};
-
-static const struct owl_sps_info s900_sps_info = {
- .num_domains = ARRAY_SIZE(s900_sps_domains),
- .domains = s900_sps_domains,
-};
-
-static const struct of_device_id owl_sps_of_matches[] = {
- { .compatible = "actions,s500-sps", .data = &s500_sps_info },
- { .compatible = "actions,s700-sps", .data = &s700_sps_info },
- { .compatible = "actions,s900-sps", .data = &s900_sps_info },
- { }
-};
-
-static struct platform_driver owl_sps_platform_driver = {
- .probe = owl_sps_probe,
- .driver = {
- .name = "owl-sps",
- .of_match_table = owl_sps_of_matches,
- .suppress_bind_attrs = true,
- },
-};
-
-static int __init owl_sps_init(void)
-{
- return platform_driver_register(&owl_sps_platform_driver);
-}
-postcore_initcall(owl_sps_init);
diff --git a/drivers/soc/amlogic/Kconfig b/drivers/soc/amlogic/Kconfig
index 174a9b011461..d08e398bdad4 100644
--- a/drivers/soc/amlogic/Kconfig
+++ b/drivers/soc/amlogic/Kconfig
@@ -26,41 +26,6 @@ config MESON_GX_SOCINFO
Say yes to support decoding of Amlogic Meson GX SoC family
information about the type, package and version.
-config MESON_GX_PM_DOMAINS
- tristate "Amlogic Meson GX Power Domains driver"
- depends on ARCH_MESON || COMPILE_TEST
- depends on PM && OF
- default ARCH_MESON
- select PM_GENERIC_DOMAINS
- select PM_GENERIC_DOMAINS_OF
- help
- Say yes to expose Amlogic Meson GX Power Domains as
- Generic Power Domains.
-
-config MESON_EE_PM_DOMAINS
- tristate "Amlogic Meson Everything-Else Power Domains driver"
- depends on ARCH_MESON || COMPILE_TEST
- depends on PM && OF
- default ARCH_MESON
- select PM_GENERIC_DOMAINS
- select PM_GENERIC_DOMAINS_OF
- help
- Say yes to expose Amlogic Meson Everything-Else Power Domains as
- Generic Power Domains.
-
-config MESON_SECURE_PM_DOMAINS
- tristate "Amlogic Meson Secure Power Domains driver"
- depends on (ARCH_MESON || COMPILE_TEST) && MESON_SM
- depends on PM && OF
- depends on HAVE_ARM_SMCCC
- default ARCH_MESON
- select PM_GENERIC_DOMAINS
- select PM_GENERIC_DOMAINS_OF
- help
- Support for the power controller on Amlogic A1/C1 series.
- Say yes to expose Amlogic Meson Secure Power Domains as Generic
- Power Domains.
-
config MESON_MX_SOCINFO
bool "Amlogic Meson MX SoC Information driver"
depends on (ARM && ARCH_MESON) || COMPILE_TEST
diff --git a/drivers/soc/amlogic/Makefile b/drivers/soc/amlogic/Makefile
index 7b8c5d323f5c..c25f835e6a26 100644
--- a/drivers/soc/amlogic/Makefile
+++ b/drivers/soc/amlogic/Makefile
@@ -2,7 +2,4 @@
obj-$(CONFIG_MESON_CANVAS) += meson-canvas.o
obj-$(CONFIG_MESON_CLK_MEASURE) += meson-clk-measure.o
obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o
-obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o
obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o
-obj-$(CONFIG_MESON_EE_PM_DOMAINS) += meson-ee-pwrc.o
-obj-$(CONFIG_MESON_SECURE_PM_DOMAINS) += meson-secure-pwrc.o
diff --git a/drivers/soc/amlogic/meson-canvas.c b/drivers/soc/amlogic/meson-canvas.c
index 383b0cfc584e..79681afea8c6 100644
--- a/drivers/soc/amlogic/meson-canvas.c
+++ b/drivers/soc/amlogic/meson-canvas.c
@@ -8,6 +8,7 @@
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
+#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/soc/amlogic/meson-canvas.h>
#include <linux/of_address.h>
@@ -59,12 +60,9 @@ struct meson_canvas *meson_canvas_get(struct device *dev)
return ERR_PTR(-ENODEV);
canvas_pdev = of_find_device_by_node(canvas_node);
- if (!canvas_pdev) {
- of_node_put(canvas_node);
- return ERR_PTR(-EPROBE_DEFER);
- }
-
of_node_put(canvas_node);
+ if (!canvas_pdev)
+ return ERR_PTR(-EPROBE_DEFER);
/*
* If priv is NULL, it's probably because the canvas hasn't
@@ -72,10 +70,9 @@ struct meson_canvas *meson_canvas_get(struct device *dev)
* current state, this driver probe cannot return -EPROBE_DEFER
*/
canvas = dev_get_drvdata(&canvas_pdev->dev);
- if (!canvas) {
- put_device(&canvas_pdev->dev);
+ put_device(&canvas_pdev->dev);
+ if (!canvas)
return ERR_PTR(-EINVAL);
- }
return canvas;
}
diff --git a/drivers/soc/amlogic/meson-clk-measure.c b/drivers/soc/amlogic/meson-clk-measure.c
index 3f3039600357..d862e30a244e 100644
--- a/drivers/soc/amlogic/meson-clk-measure.c
+++ b/drivers/soc/amlogic/meson-clk-measure.c
@@ -14,11 +14,6 @@
static DEFINE_MUTEX(measure_lock);
-#define MSR_CLK_DUTY 0x0
-#define MSR_CLK_REG0 0x4
-#define MSR_CLK_REG1 0x8
-#define MSR_CLK_REG2 0xc
-
#define MSR_DURATION GENMASK(15, 0)
#define MSR_ENABLE BIT(16)
#define MSR_CONT BIT(17) /* continuous measurement */
@@ -33,23 +28,34 @@ static DEFINE_MUTEX(measure_lock);
#define DIV_STEP 32
#define DIV_MAX 640
-#define CLK_MSR_MAX 128
-
struct meson_msr_id {
struct meson_msr *priv;
unsigned int id;
const char *name;
};
+struct msr_reg_offset {
+ unsigned int duty_val;
+ unsigned int freq_ctrl;
+ unsigned int duty_ctrl;
+ unsigned int freq_val;
+};
+
+struct meson_msr_data {
+ struct meson_msr_id *msr_table;
+ unsigned int msr_count;
+ const struct msr_reg_offset *reg;
+};
+
struct meson_msr {
struct regmap *regmap;
- struct meson_msr_id msr_table[CLK_MSR_MAX];
+ struct meson_msr_data data;
};
#define CLK_MSR_ID(__id, __name) \
[__id] = {.id = __id, .name = __name,}
-static struct meson_msr_id clk_msr_m8[CLK_MSR_MAX] = {
+static const struct meson_msr_id clk_msr_m8[] = {
CLK_MSR_ID(0, "ring_osc_out_ee0"),
CLK_MSR_ID(1, "ring_osc_out_ee1"),
CLK_MSR_ID(2, "ring_osc_out_ee2"),
@@ -98,7 +104,7 @@ static struct meson_msr_id clk_msr_m8[CLK_MSR_MAX] = {
CLK_MSR_ID(63, "mipi_csi_cfg"),
};
-static struct meson_msr_id clk_msr_gx[CLK_MSR_MAX] = {
+static const struct meson_msr_id clk_msr_gx[] = {
CLK_MSR_ID(0, "ring_osc_out_ee_0"),
CLK_MSR_ID(1, "ring_osc_out_ee_1"),
CLK_MSR_ID(2, "ring_osc_out_ee_2"),
@@ -168,7 +174,7 @@ static struct meson_msr_id clk_msr_gx[CLK_MSR_MAX] = {
CLK_MSR_ID(82, "ge2d"),
};
-static struct meson_msr_id clk_msr_axg[CLK_MSR_MAX] = {
+static const struct meson_msr_id clk_msr_axg[] = {
CLK_MSR_ID(0, "ring_osc_out_ee_0"),
CLK_MSR_ID(1, "ring_osc_out_ee_1"),
CLK_MSR_ID(2, "ring_osc_out_ee_2"),
@@ -242,7 +248,7 @@ static struct meson_msr_id clk_msr_axg[CLK_MSR_MAX] = {
CLK_MSR_ID(109, "audio_locker_in"),
};
-static struct meson_msr_id clk_msr_g12a[CLK_MSR_MAX] = {
+static const struct meson_msr_id clk_msr_g12a[] = {
CLK_MSR_ID(0, "ring_osc_out_ee_0"),
CLK_MSR_ID(1, "ring_osc_out_ee_1"),
CLK_MSR_ID(2, "ring_osc_out_ee_2"),
@@ -358,7 +364,7 @@ static struct meson_msr_id clk_msr_g12a[CLK_MSR_MAX] = {
CLK_MSR_ID(122, "audio_pdm_dclk"),
};
-static struct meson_msr_id clk_msr_sm1[CLK_MSR_MAX] = {
+static const struct meson_msr_id clk_msr_sm1[] = {
CLK_MSR_ID(0, "ring_osc_out_ee_0"),
CLK_MSR_ID(1, "ring_osc_out_ee_1"),
CLK_MSR_ID(2, "ring_osc_out_ee_2"),
@@ -488,10 +494,304 @@ static struct meson_msr_id clk_msr_sm1[CLK_MSR_MAX] = {
CLK_MSR_ID(127, "csi2_data"),
};
+static const struct meson_msr_id clk_msr_c3[] = {
+ CLK_MSR_ID(0, "sys_clk"),
+ CLK_MSR_ID(1, "axi_clk"),
+ CLK_MSR_ID(2, "rtc_clk"),
+ CLK_MSR_ID(3, "p20_usb2_ckout"),
+ CLK_MSR_ID(4, "eth_mpll_test"),
+ CLK_MSR_ID(5, "sys_pll"),
+ CLK_MSR_ID(6, "cpu_clk_div16"),
+ CLK_MSR_ID(7, "ts_pll"),
+ CLK_MSR_ID(8, "fclk_div2"),
+ CLK_MSR_ID(9, "fclk_div2p5"),
+ CLK_MSR_ID(10, "fclk_div3"),
+ CLK_MSR_ID(11, "fclk_div4"),
+ CLK_MSR_ID(12, "fclk_div5"),
+ CLK_MSR_ID(13, "fclk_div7"),
+ CLK_MSR_ID(15, "fclk_50m"),
+ CLK_MSR_ID(16, "sys_oscin32k_i"),
+ CLK_MSR_ID(17, "mclk_pll"),
+ CLK_MSR_ID(19, "hifi_pll"),
+ CLK_MSR_ID(20, "gp0_pll"),
+ CLK_MSR_ID(21, "gp1_pll"),
+ CLK_MSR_ID(22, "eth_mppll_50m_ckout"),
+ CLK_MSR_ID(23, "sys_pll_div16"),
+ CLK_MSR_ID(24, "ddr_dpll_pt_clk"),
+ CLK_MSR_ID(26, "nna_core"),
+ CLK_MSR_ID(27, "rtc_sec_pulse_out"),
+ CLK_MSR_ID(28, "rtc_osc_clk_out"),
+ CLK_MSR_ID(29, "debug_in_clk"),
+ CLK_MSR_ID(30, "mod_eth_phy_ref_clk"),
+ CLK_MSR_ID(31, "mod_eth_tx_clk"),
+ CLK_MSR_ID(32, "eth_125m"),
+ CLK_MSR_ID(33, "eth_rmii"),
+ CLK_MSR_ID(34, "co_clkin_to_mac"),
+ CLK_MSR_ID(36, "co_rx_clk"),
+ CLK_MSR_ID(37, "co_tx_clk"),
+ CLK_MSR_ID(38, "eth_phy_rxclk"),
+ CLK_MSR_ID(39, "eth_phy_plltxclk"),
+ CLK_MSR_ID(40, "ephy_test_clk"),
+ CLK_MSR_ID(66, "vapb"),
+ CLK_MSR_ID(67, "ge2d"),
+ CLK_MSR_ID(68, "dewarpa"),
+ CLK_MSR_ID(70, "mipi_dsi_meas"),
+ CLK_MSR_ID(71, "dsi_phy"),
+ CLK_MSR_ID(79, "rama"),
+ CLK_MSR_ID(94, "vc9000e_core"),
+ CLK_MSR_ID(95, "vc9000e_sys"),
+ CLK_MSR_ID(96, "vc9000e_aclk"),
+ CLK_MSR_ID(97, "hcodec"),
+ CLK_MSR_ID(106, "deskew_pll_clk_div32_out"),
+ CLK_MSR_ID(107, "mipi_csi_phy_clk_out[0]"),
+ CLK_MSR_ID(108, "mipi_csi_phy_clk_out[1]"),
+ CLK_MSR_ID(110, "spifc"),
+ CLK_MSR_ID(111, "saradc"),
+ CLK_MSR_ID(112, "ts"),
+ CLK_MSR_ID(113, "sd_emmc_c"),
+ CLK_MSR_ID(114, "sd_emmc_b"),
+ CLK_MSR_ID(115, "sd_emmc_a"),
+ CLK_MSR_ID(116, "gpio_msr_clk"),
+ CLK_MSR_ID(117, "spicc_b"),
+ CLK_MSR_ID(118, "spicc_a"),
+ CLK_MSR_ID(122, "mod_audio_pdm_dclk_o"),
+ CLK_MSR_ID(124, "o_earcrx_dmac_clk"),
+ CLK_MSR_ID(125, "o_earcrx_cmdc_clk"),
+ CLK_MSR_ID(126, "o_earctx_dmac_clk"),
+ CLK_MSR_ID(127, "o_earctx_cmdc_clk"),
+ CLK_MSR_ID(128, "o_tohdmitx_bclk"),
+ CLK_MSR_ID(129, "o_tohdmitx_mclk"),
+ CLK_MSR_ID(130, "o_tohdmitx_spdif_clk"),
+ CLK_MSR_ID(131, "o_toacodec_bclk"),
+ CLK_MSR_ID(132, "o_toacodec_mclk"),
+ CLK_MSR_ID(133, "o_spdifout_b_mst_clk"),
+ CLK_MSR_ID(134, "o_spdifout_mst_clk"),
+ CLK_MSR_ID(135, "o_spdifin_mst_clk"),
+ CLK_MSR_ID(136, "o_audio_mclk"),
+ CLK_MSR_ID(137, "o_vad_clk"),
+ CLK_MSR_ID(138, "o_tdmout_d_sclk"),
+ CLK_MSR_ID(139, "o_tdmout_c_sclk"),
+ CLK_MSR_ID(140, "o_tdmout_b_sclk"),
+ CLK_MSR_ID(141, "o_tdmout_a_sclk"),
+ CLK_MSR_ID(142, "o_tdminb_1b_sclk"),
+ CLK_MSR_ID(143, "o_tdmin_1b_sclk"),
+ CLK_MSR_ID(144, "o_tdmin_d_sclk"),
+ CLK_MSR_ID(145, "o_tdmin_c_sclk"),
+ CLK_MSR_ID(146, "o_tdmin_b_sclk"),
+ CLK_MSR_ID(147, "o_tdmin_a_sclk"),
+ CLK_MSR_ID(148, "o_resampleb_clk"),
+ CLK_MSR_ID(149, "o_resamplea_clk"),
+ CLK_MSR_ID(150, "o_pdmb_sysclk"),
+ CLK_MSR_ID(151, "o_pdmb_dclk"),
+ CLK_MSR_ID(152, "o_pdm_sysclk"),
+ CLK_MSR_ID(153, "o_pdm_dclk"),
+ CLK_MSR_ID(154, "c_alockerb_out_clk"),
+ CLK_MSR_ID(155, "c_alockerb_in_clk"),
+ CLK_MSR_ID(156, "c_alocker_out_clk"),
+ CLK_MSR_ID(157, "c_alocker_in_clk"),
+ CLK_MSR_ID(158, "audio_mst_clk[34]"),
+ CLK_MSR_ID(159, "audio_mst_clk[35]"),
+ CLK_MSR_ID(160, "pwm_n"),
+ CLK_MSR_ID(161, "pwm_m"),
+ CLK_MSR_ID(162, "pwm_l"),
+ CLK_MSR_ID(163, "pwm_k"),
+ CLK_MSR_ID(164, "pwm_j"),
+ CLK_MSR_ID(165, "pwm_i"),
+ CLK_MSR_ID(166, "pwm_h"),
+ CLK_MSR_ID(167, "pwm_g"),
+ CLK_MSR_ID(168, "pwm_f"),
+ CLK_MSR_ID(169, "pwm_e"),
+ CLK_MSR_ID(170, "pwm_d"),
+ CLK_MSR_ID(171, "pwm_c"),
+ CLK_MSR_ID(172, "pwm_b"),
+ CLK_MSR_ID(173, "pwm_a"),
+ CLK_MSR_ID(174, "AU_DAC1_CLK_TO_GPIO"),
+ CLK_MSR_ID(175, "AU_ADC_CLK_TO_GPIO"),
+ CLK_MSR_ID(176, "rng_ring_osc_clk[0]"),
+ CLK_MSR_ID(177, "rng_ring_osc_clk[1]"),
+ CLK_MSR_ID(178, "rng_ring_osc_clk[2]"),
+ CLK_MSR_ID(179, "rng_ring_osc_clk[3]"),
+ CLK_MSR_ID(180, "sys_cpu_ring_osc_clk[0]"),
+ CLK_MSR_ID(181, "sys_cpu_ring_osc_clk[1]"),
+ CLK_MSR_ID(182, "sys_cpu_ring_osc_clk[2]"),
+ CLK_MSR_ID(183, "sys_cpu_ring_osc_clk[3]"),
+ CLK_MSR_ID(184, "sys_cpu_ring_osc_clk[4]"),
+ CLK_MSR_ID(185, "sys_cpu_ring_osc_clk[5]"),
+ CLK_MSR_ID(186, "sys_cpu_ring_osc_clk[6]"),
+ CLK_MSR_ID(187, "sys_cpu_ring_osc_clk[7]"),
+ CLK_MSR_ID(188, "sys_cpu_ring_osc_clk[8]"),
+ CLK_MSR_ID(189, "sys_cpu_ring_osc_clk[9]"),
+ CLK_MSR_ID(190, "sys_cpu_ring_osc_clk[10]"),
+ CLK_MSR_ID(191, "sys_cpu_ring_osc_clk[11]"),
+ CLK_MSR_ID(192, "am_ring_osc_clk_out[12](dmc)"),
+ CLK_MSR_ID(193, "am_ring_osc_clk_out[13](rama)"),
+ CLK_MSR_ID(194, "am_ring_osc_clk_out[14](nna)"),
+ CLK_MSR_ID(195, "am_ring_osc_clk_out[15](nna)"),
+ CLK_MSR_ID(200, "rng_ring_osc_clk_1[0]"),
+ CLK_MSR_ID(201, "rng_ring_osc_clk_1[1]"),
+ CLK_MSR_ID(202, "rng_ring_osc_clk_1[2]"),
+ CLK_MSR_ID(203, "rng_ring_osc_clk_1[3]"),
+
+};
+
+static const struct meson_msr_id clk_msr_s4[] = {
+ CLK_MSR_ID(0, "sys_clk"),
+ CLK_MSR_ID(1, "axi_clk"),
+ CLK_MSR_ID(2, "rtc_clk"),
+ CLK_MSR_ID(5, "mali"),
+ CLK_MSR_ID(6, "cpu_clk_div16"),
+ CLK_MSR_ID(7, "ceca_clk"),
+ CLK_MSR_ID(8, "cecb_clk"),
+ CLK_MSR_ID(10, "fclk_div5"),
+ CLK_MSR_ID(11, "mpll0"),
+ CLK_MSR_ID(12, "mpll1"),
+ CLK_MSR_ID(13, "mpll2"),
+ CLK_MSR_ID(14, "mpll3"),
+ CLK_MSR_ID(15, "fclk_50m"),
+ CLK_MSR_ID(16, "pcie_clk_inp"),
+ CLK_MSR_ID(17, "pcie_clk_inn"),
+ CLK_MSR_ID(18, "mpll_clk_test_out"),
+ CLK_MSR_ID(19, "hifi_pll"),
+ CLK_MSR_ID(20, "gp0_pll"),
+ CLK_MSR_ID(21, "gp1_pll"),
+ CLK_MSR_ID(22, "eth_mppll_50m_ckout"),
+ CLK_MSR_ID(23, "sys_pll_div16"),
+ CLK_MSR_ID(24, "ddr_dpll_pt_clk"),
+ CLK_MSR_ID(30, "mod_eth_phy_ref_clk"),
+ CLK_MSR_ID(31, "mod_eth_tx_clk"),
+ CLK_MSR_ID(32, "eth_125m"),
+ CLK_MSR_ID(33, "eth_rmii"),
+ CLK_MSR_ID(34, "co_clkin_to_mac"),
+ CLK_MSR_ID(35, "mod_eth_rx_clk_rmii"),
+ CLK_MSR_ID(36, "co_rx_clk"),
+ CLK_MSR_ID(37, "co_tx_clk"),
+ CLK_MSR_ID(38, "eth_phy_rxclk"),
+ CLK_MSR_ID(39, "eth_phy_plltxclk"),
+ CLK_MSR_ID(40, "ephy_test_clk"),
+ CLK_MSR_ID(50, "vid_pll_div_clk_out"),
+ CLK_MSR_ID(51, "enci"),
+ CLK_MSR_ID(52, "encp"),
+ CLK_MSR_ID(53, "encl"),
+ CLK_MSR_ID(54, "vdac"),
+ CLK_MSR_ID(55, "cdac_clk_c"),
+ CLK_MSR_ID(56, "mod_tcon_clko"),
+ CLK_MSR_ID(57, "lcd_an_clk_ph2"),
+ CLK_MSR_ID(58, "lcd_an_clk_ph3"),
+ CLK_MSR_ID(59, "hdmitx_pixel"),
+ CLK_MSR_ID(60, "vdin_meas"),
+ CLK_MSR_ID(61, "vpu"),
+ CLK_MSR_ID(62, "vpu_clkb"),
+ CLK_MSR_ID(63, "vpu_clkb_tmp"),
+ CLK_MSR_ID(64, "vpu_clkc"),
+ CLK_MSR_ID(65, "vid_lock"),
+ CLK_MSR_ID(66, "vapb"),
+ CLK_MSR_ID(67, "ge2d"),
+ CLK_MSR_ID(68, "cts_hdcp22_esmclk"),
+ CLK_MSR_ID(69, "cts_hdcp22_skpclk"),
+ CLK_MSR_ID(76, "hdmitx_tmds"),
+ CLK_MSR_ID(77, "hdmitx_sys_clk"),
+ CLK_MSR_ID(78, "hdmitx_fe_clk"),
+ CLK_MSR_ID(79, "rama"),
+ CLK_MSR_ID(93, "vdec"),
+ CLK_MSR_ID(99, "hevcf"),
+ CLK_MSR_ID(100, "demod_core"),
+ CLK_MSR_ID(101, "adc_extclk_in"),
+ CLK_MSR_ID(102, "cts_demod_core_t2_clk"),
+ CLK_MSR_ID(103, "adc_dpll_intclk"),
+ CLK_MSR_ID(104, "adc_dpll_clk_b3"),
+ CLK_MSR_ID(105, "s2_adc_clk"),
+ CLK_MSR_ID(106, "deskew_pll_clk_div32_out"),
+ CLK_MSR_ID(110, "sc"),
+ CLK_MSR_ID(111, "sar_adc"),
+ CLK_MSR_ID(113, "sd_emmc_c"),
+ CLK_MSR_ID(114, "sd_emmc_b"),
+ CLK_MSR_ID(115, "sd_emmc_a"),
+ CLK_MSR_ID(116, "gpio_msr_clk"),
+ CLK_MSR_ID(118, "spicc0"),
+ CLK_MSR_ID(121, "ts"),
+ CLK_MSR_ID(130, "audio_vad_clk"),
+ CLK_MSR_ID(131, "acodec_dac_clk_x128"),
+ CLK_MSR_ID(132, "audio_locker_in_clk"),
+ CLK_MSR_ID(133, "audio_locker_out_clk"),
+ CLK_MSR_ID(134, "audio_tdmout_c_sclk"),
+ CLK_MSR_ID(135, "audio_tdmout_b_sclk"),
+ CLK_MSR_ID(136, "audio_tdmout_a_sclk"),
+ CLK_MSR_ID(137, "audio_tdmin_lb_sclk"),
+ CLK_MSR_ID(138, "audio_tdmin_c_sclk"),
+ CLK_MSR_ID(139, "audio_tdmin_b_sclk"),
+ CLK_MSR_ID(140, "audio_tdmin_a_sclk"),
+ CLK_MSR_ID(141, "audio_resamplea_clk"),
+ CLK_MSR_ID(142, "audio_pdm_sysclk"),
+ CLK_MSR_ID(143, "audio_spdifout_b_mst_clk"),
+ CLK_MSR_ID(144, "audio_spdifout_mst_clk"),
+ CLK_MSR_ID(145, "audio_spdifin_mst_clk"),
+ CLK_MSR_ID(146, "audio_pdm_dclk"),
+ CLK_MSR_ID(147, "audio_resampleb_clk"),
+ CLK_MSR_ID(160, "pwm_j"),
+ CLK_MSR_ID(161, "pwm_i"),
+ CLK_MSR_ID(162, "pwm_h"),
+ CLK_MSR_ID(163, "pwm_g"),
+ CLK_MSR_ID(164, "pwm_f"),
+ CLK_MSR_ID(165, "pwm_e"),
+ CLK_MSR_ID(166, "pwm_d"),
+ CLK_MSR_ID(167, "pwm_c"),
+ CLK_MSR_ID(168, "pwm_b"),
+ CLK_MSR_ID(169, "pwm_a"),
+ CLK_MSR_ID(176, "rng_ring_0"),
+ CLK_MSR_ID(177, "rng_ring_1"),
+ CLK_MSR_ID(178, "rng_ring_2"),
+ CLK_MSR_ID(179, "rng_ring_3"),
+ CLK_MSR_ID(180, "dmc_osc_ring(LVT16)"),
+ CLK_MSR_ID(181, "gpu_osc_ring0(LVT16)"),
+ CLK_MSR_ID(182, "gpu_osc_ring1(ULVT16)"),
+ CLK_MSR_ID(183, "gpu_osc_ring2(SLVT16)"),
+ CLK_MSR_ID(184, "vpu_osc_ring0(SVT24)"),
+ CLK_MSR_ID(185, "vpu_osc_ring1(LVT20)"),
+ CLK_MSR_ID(186, "vpu_osc_ring2(LVT16)"),
+ CLK_MSR_ID(187, "dos_osc_ring0(SVT24)"),
+ CLK_MSR_ID(188, "dos_osc_ring1(SVT16)"),
+ CLK_MSR_ID(189, "dos_osc_ring2(LVT16)"),
+ CLK_MSR_ID(190, "dos_osc_ring3(ULVT20)"),
+ CLK_MSR_ID(192, "axi_sram_osc_ring(SVT16)"),
+ CLK_MSR_ID(193, "demod_osc_ring0"),
+ CLK_MSR_ID(194, "demod_osc_ring1"),
+ CLK_MSR_ID(195, "sar_osc_ring"),
+ CLK_MSR_ID(196, "sys_cpu_osc_ring0"),
+ CLK_MSR_ID(197, "sys_cpu_osc_ring1"),
+ CLK_MSR_ID(198, "sys_cpu_osc_ring2"),
+ CLK_MSR_ID(199, "sys_cpu_osc_ring3"),
+ CLK_MSR_ID(200, "sys_cpu_osc_ring4"),
+ CLK_MSR_ID(201, "sys_cpu_osc_ring5"),
+ CLK_MSR_ID(202, "sys_cpu_osc_ring6"),
+ CLK_MSR_ID(203, "sys_cpu_osc_ring7"),
+ CLK_MSR_ID(204, "sys_cpu_osc_ring8"),
+ CLK_MSR_ID(205, "sys_cpu_osc_ring9"),
+ CLK_MSR_ID(206, "sys_cpu_osc_ring10"),
+ CLK_MSR_ID(207, "sys_cpu_osc_ring11"),
+ CLK_MSR_ID(208, "sys_cpu_osc_ring12"),
+ CLK_MSR_ID(209, "sys_cpu_osc_ring13"),
+ CLK_MSR_ID(210, "sys_cpu_osc_ring14"),
+ CLK_MSR_ID(211, "sys_cpu_osc_ring15"),
+ CLK_MSR_ID(212, "sys_cpu_osc_ring16"),
+ CLK_MSR_ID(213, "sys_cpu_osc_ring17"),
+ CLK_MSR_ID(214, "sys_cpu_osc_ring18"),
+ CLK_MSR_ID(215, "sys_cpu_osc_ring19"),
+ CLK_MSR_ID(216, "sys_cpu_osc_ring20"),
+ CLK_MSR_ID(217, "sys_cpu_osc_ring21"),
+ CLK_MSR_ID(218, "sys_cpu_osc_ring22"),
+ CLK_MSR_ID(219, "sys_cpu_osc_ring23"),
+ CLK_MSR_ID(220, "sys_cpu_osc_ring24"),
+ CLK_MSR_ID(221, "sys_cpu_osc_ring25"),
+ CLK_MSR_ID(222, "sys_cpu_osc_ring26"),
+ CLK_MSR_ID(223, "sys_cpu_osc_ring27"),
+
+};
+
static int meson_measure_id(struct meson_msr_id *clk_msr_id,
- unsigned int duration)
+ unsigned int duration)
{
struct meson_msr *priv = clk_msr_id->priv;
+ const struct msr_reg_offset *reg = priv->data.reg;
unsigned int val;
int ret;
@@ -499,22 +799,22 @@ static int meson_measure_id(struct meson_msr_id *clk_msr_id,
if (ret)
return ret;
- regmap_write(priv->regmap, MSR_CLK_REG0, 0);
+ regmap_write(priv->regmap, reg->freq_ctrl, 0);
/* Set measurement duration */
- regmap_update_bits(priv->regmap, MSR_CLK_REG0, MSR_DURATION,
+ regmap_update_bits(priv->regmap, reg->freq_ctrl, MSR_DURATION,
FIELD_PREP(MSR_DURATION, duration - 1));
/* Set ID */
- regmap_update_bits(priv->regmap, MSR_CLK_REG0, MSR_CLK_SRC,
+ regmap_update_bits(priv->regmap, reg->freq_ctrl, MSR_CLK_SRC,
FIELD_PREP(MSR_CLK_SRC, clk_msr_id->id));
/* Enable & Start */
- regmap_update_bits(priv->regmap, MSR_CLK_REG0,
+ regmap_update_bits(priv->regmap, reg->freq_ctrl,
MSR_RUN | MSR_ENABLE,
MSR_RUN | MSR_ENABLE);
- ret = regmap_read_poll_timeout(priv->regmap, MSR_CLK_REG0,
+ ret = regmap_read_poll_timeout(priv->regmap, reg->freq_ctrl,
val, !(val & MSR_BUSY), 10, 10000);
if (ret) {
mutex_unlock(&measure_lock);
@@ -522,10 +822,10 @@ static int meson_measure_id(struct meson_msr_id *clk_msr_id,
}
/* Disable */
- regmap_update_bits(priv->regmap, MSR_CLK_REG0, MSR_ENABLE, 0);
+ regmap_update_bits(priv->regmap, reg->freq_ctrl, MSR_ENABLE, 0);
/* Get the value in multiple of gate time counts */
- regmap_read(priv->regmap, MSR_CLK_REG2, &val);
+ regmap_read(priv->regmap, reg->freq_val, &val);
mutex_unlock(&measure_lock);
@@ -573,13 +873,14 @@ DEFINE_SHOW_ATTRIBUTE(clk_msr);
static int clk_msr_summary_show(struct seq_file *s, void *data)
{
struct meson_msr_id *msr_table = s->private;
+ unsigned int msr_count = msr_table->priv->data.msr_count;
unsigned int precision = 0;
int val, i;
seq_puts(s, " clock rate precision\n");
seq_puts(s, "---------------------------------------------\n");
- for (i = 0 ; i < CLK_MSR_MAX ; ++i) {
+ for (i = 0 ; i < msr_count ; ++i) {
if (!msr_table[i].name)
continue;
@@ -595,18 +896,18 @@ static int clk_msr_summary_show(struct seq_file *s, void *data)
}
DEFINE_SHOW_ATTRIBUTE(clk_msr_summary);
-static const struct regmap_config meson_clk_msr_regmap_config = {
+static struct regmap_config meson_clk_msr_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
- .max_register = MSR_CLK_REG2,
};
static int meson_msr_probe(struct platform_device *pdev)
{
- const struct meson_msr_id *match_data;
+ const struct meson_msr_data *match_data;
struct meson_msr *priv;
struct dentry *root, *clks;
+ struct resource *res;
void __iomem *base;
int i;
@@ -621,60 +922,142 @@ static int meson_msr_probe(struct platform_device *pdev)
return -ENODEV;
}
- memcpy(priv->msr_table, match_data, sizeof(priv->msr_table));
+ priv->data.msr_table = devm_kcalloc(&pdev->dev,
+ match_data->msr_count,
+ sizeof(struct meson_msr_id),
+ GFP_KERNEL);
+ if (!priv->data.msr_table)
+ return -ENOMEM;
- base = devm_platform_ioremap_resource(pdev, 0);
+ memcpy(priv->data.msr_table, match_data->msr_table,
+ match_data->msr_count * sizeof(struct meson_msr_id));
+ priv->data.msr_count = match_data->msr_count;
+
+ base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(base))
return PTR_ERR(base);
+ meson_clk_msr_regmap_config.max_register = resource_size(res) - 4;
priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
&meson_clk_msr_regmap_config);
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);
+ priv->data.reg = devm_kzalloc(&pdev->dev, sizeof(struct msr_reg_offset),
+ GFP_KERNEL);
+ if (!priv->data.reg)
+ return -ENOMEM;
+
+ memcpy((void *)priv->data.reg, match_data->reg,
+ sizeof(struct msr_reg_offset));
+
root = debugfs_create_dir("meson-clk-msr", NULL);
clks = debugfs_create_dir("clks", root);
debugfs_create_file("measure_summary", 0444, root,
- priv->msr_table, &clk_msr_summary_fops);
+ priv->data.msr_table, &clk_msr_summary_fops);
- for (i = 0 ; i < CLK_MSR_MAX ; ++i) {
- if (!priv->msr_table[i].name)
+ for (i = 0 ; i < priv->data.msr_count ; ++i) {
+ if (!priv->data.msr_table[i].name)
continue;
- priv->msr_table[i].priv = priv;
+ priv->data.msr_table[i].priv = priv;
- debugfs_create_file(priv->msr_table[i].name, 0444, clks,
- &priv->msr_table[i], &clk_msr_fops);
+ debugfs_create_file(priv->data.msr_table[i].name, 0444, clks,
+ &priv->data.msr_table[i], &clk_msr_fops);
}
return 0;
}
+static const struct msr_reg_offset msr_reg_offset = {
+ .duty_val = 0x0,
+ .freq_ctrl = 0x4,
+ .duty_ctrl = 0x8,
+ .freq_val = 0xc,
+};
+
+static const struct meson_msr_data clk_msr_gx_data = {
+ .msr_table = (void *)clk_msr_gx,
+ .msr_count = ARRAY_SIZE(clk_msr_gx),
+ .reg = &msr_reg_offset,
+};
+
+static const struct meson_msr_data clk_msr_m8_data = {
+ .msr_table = (void *)clk_msr_m8,
+ .msr_count = ARRAY_SIZE(clk_msr_m8),
+ .reg = &msr_reg_offset,
+};
+
+static const struct meson_msr_data clk_msr_axg_data = {
+ .msr_table = (void *)clk_msr_axg,
+ .msr_count = ARRAY_SIZE(clk_msr_axg),
+ .reg = &msr_reg_offset,
+};
+
+static const struct meson_msr_data clk_msr_g12a_data = {
+ .msr_table = (void *)clk_msr_g12a,
+ .msr_count = ARRAY_SIZE(clk_msr_g12a),
+ .reg = &msr_reg_offset,
+};
+
+static const struct meson_msr_data clk_msr_sm1_data = {
+ .msr_table = (void *)clk_msr_sm1,
+ .msr_count = ARRAY_SIZE(clk_msr_sm1),
+ .reg = &msr_reg_offset,
+};
+
+static const struct msr_reg_offset msr_reg_offset_v2 = {
+ .freq_ctrl = 0x0,
+ .duty_ctrl = 0x4,
+ .freq_val = 0x8,
+ .duty_val = 0x18,
+};
+
+static const struct meson_msr_data clk_msr_c3_data = {
+ .msr_table = (void *)clk_msr_c3,
+ .msr_count = ARRAY_SIZE(clk_msr_c3),
+ .reg = &msr_reg_offset_v2,
+};
+
+static const struct meson_msr_data clk_msr_s4_data = {
+ .msr_table = (void *)clk_msr_s4,
+ .msr_count = ARRAY_SIZE(clk_msr_s4),
+ .reg = &msr_reg_offset_v2,
+};
+
static const struct of_device_id meson_msr_match_table[] = {
{
.compatible = "amlogic,meson-gx-clk-measure",
- .data = (void *)clk_msr_gx,
+ .data = &clk_msr_gx_data,
},
{
.compatible = "amlogic,meson8-clk-measure",
- .data = (void *)clk_msr_m8,
+ .data = &clk_msr_m8_data,
},
{
.compatible = "amlogic,meson8b-clk-measure",
- .data = (void *)clk_msr_m8,
+ .data = &clk_msr_m8_data,
},
{
.compatible = "amlogic,meson-axg-clk-measure",
- .data = (void *)clk_msr_axg,
+ .data = &clk_msr_axg_data,
},
{
.compatible = "amlogic,meson-g12a-clk-measure",
- .data = (void *)clk_msr_g12a,
+ .data = &clk_msr_g12a_data,
},
{
.compatible = "amlogic,meson-sm1-clk-measure",
- .data = (void *)clk_msr_sm1,
+ .data = &clk_msr_sm1_data,
+ },
+ {
+ .compatible = "amlogic,c3-clk-measure",
+ .data = &clk_msr_c3_data,
+ },
+ {
+ .compatible = "amlogic,s4-clk-measure",
+ .data = &clk_msr_s4_data,
},
{ /* sentinel */ }
};
@@ -688,4 +1071,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-ee-pwrc.c b/drivers/soc/amlogic/meson-ee-pwrc.c
deleted file mode 100644
index dd5f2a13ceb5..000000000000
--- a/drivers/soc/amlogic/meson-ee-pwrc.c
+++ /dev/null
@@ -1,619 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (c) 2019 BayLibre, SAS
- * Author: Neil Armstrong <narmstrong@baylibre.com>
- */
-
-#include <linux/of_address.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <linux/bitfield.h>
-#include <linux/regmap.h>
-#include <linux/mfd/syscon.h>
-#include <linux/of_device.h>
-#include <linux/reset-controller.h>
-#include <linux/reset.h>
-#include <linux/clk.h>
-#include <linux/module.h>
-#include <dt-bindings/power/meson8-power.h>
-#include <dt-bindings/power/meson-axg-power.h>
-#include <dt-bindings/power/meson-g12a-power.h>
-#include <dt-bindings/power/meson-gxbb-power.h>
-#include <dt-bindings/power/meson-sm1-power.h>
-
-/* AO Offsets */
-
-#define GX_AO_RTI_GEN_PWR_SLEEP0 (0x3a << 2)
-#define GX_AO_RTI_GEN_PWR_ISO0 (0x3b << 2)
-
-/*
- * Meson8/Meson8b/Meson8m2 only expose the power management registers of the
- * AO-bus as syscon. 0x3a from GX translates to 0x02, 0x3b translates to 0x03
- * and so on.
- */
-#define MESON8_AO_RTI_GEN_PWR_SLEEP0 (0x02 << 2)
-#define MESON8_AO_RTI_GEN_PWR_ISO0 (0x03 << 2)
-
-/* HHI Offsets */
-
-#define HHI_MEM_PD_REG0 (0x40 << 2)
-#define HHI_VPU_MEM_PD_REG0 (0x41 << 2)
-#define HHI_VPU_MEM_PD_REG1 (0x42 << 2)
-#define HHI_VPU_MEM_PD_REG3 (0x43 << 2)
-#define HHI_VPU_MEM_PD_REG4 (0x44 << 2)
-#define HHI_AUDIO_MEM_PD_REG0 (0x45 << 2)
-#define HHI_NANOQ_MEM_PD_REG0 (0x46 << 2)
-#define HHI_NANOQ_MEM_PD_REG1 (0x47 << 2)
-#define HHI_VPU_MEM_PD_REG2 (0x4d << 2)
-
-struct meson_ee_pwrc;
-struct meson_ee_pwrc_domain;
-
-struct meson_ee_pwrc_mem_domain {
- unsigned int reg;
- unsigned int mask;
-};
-
-struct meson_ee_pwrc_top_domain {
- unsigned int sleep_reg;
- unsigned int sleep_mask;
- unsigned int iso_reg;
- unsigned int iso_mask;
-};
-
-struct meson_ee_pwrc_domain_desc {
- char *name;
- unsigned int reset_names_count;
- unsigned int clk_names_count;
- struct meson_ee_pwrc_top_domain *top_pd;
- unsigned int mem_pd_count;
- struct meson_ee_pwrc_mem_domain *mem_pd;
- bool (*is_powered_off)(struct meson_ee_pwrc_domain *pwrc_domain);
-};
-
-struct meson_ee_pwrc_domain_data {
- unsigned int count;
- struct meson_ee_pwrc_domain_desc *domains;
-};
-
-/* TOP Power Domains */
-
-static struct meson_ee_pwrc_top_domain gx_pwrc_vpu = {
- .sleep_reg = GX_AO_RTI_GEN_PWR_SLEEP0,
- .sleep_mask = BIT(8),
- .iso_reg = GX_AO_RTI_GEN_PWR_SLEEP0,
- .iso_mask = BIT(9),
-};
-
-static struct meson_ee_pwrc_top_domain meson8_pwrc_vpu = {
- .sleep_reg = MESON8_AO_RTI_GEN_PWR_SLEEP0,
- .sleep_mask = BIT(8),
- .iso_reg = MESON8_AO_RTI_GEN_PWR_SLEEP0,
- .iso_mask = BIT(9),
-};
-
-#define SM1_EE_PD(__bit) \
- { \
- .sleep_reg = GX_AO_RTI_GEN_PWR_SLEEP0, \
- .sleep_mask = BIT(__bit), \
- .iso_reg = GX_AO_RTI_GEN_PWR_ISO0, \
- .iso_mask = BIT(__bit), \
- }
-
-static struct meson_ee_pwrc_top_domain sm1_pwrc_vpu = SM1_EE_PD(8);
-static struct meson_ee_pwrc_top_domain sm1_pwrc_nna = SM1_EE_PD(16);
-static struct meson_ee_pwrc_top_domain sm1_pwrc_usb = SM1_EE_PD(17);
-static struct meson_ee_pwrc_top_domain sm1_pwrc_pci = SM1_EE_PD(18);
-static struct meson_ee_pwrc_top_domain sm1_pwrc_ge2d = SM1_EE_PD(19);
-
-/* Memory PD Domains */
-
-#define VPU_MEMPD(__reg) \
- { __reg, GENMASK(1, 0) }, \
- { __reg, GENMASK(3, 2) }, \
- { __reg, GENMASK(5, 4) }, \
- { __reg, GENMASK(7, 6) }, \
- { __reg, GENMASK(9, 8) }, \
- { __reg, GENMASK(11, 10) }, \
- { __reg, GENMASK(13, 12) }, \
- { __reg, GENMASK(15, 14) }, \
- { __reg, GENMASK(17, 16) }, \
- { __reg, GENMASK(19, 18) }, \
- { __reg, GENMASK(21, 20) }, \
- { __reg, GENMASK(23, 22) }, \
- { __reg, GENMASK(25, 24) }, \
- { __reg, GENMASK(27, 26) }, \
- { __reg, GENMASK(29, 28) }, \
- { __reg, GENMASK(31, 30) }
-
-#define VPU_HHI_MEMPD(__reg) \
- { __reg, BIT(8) }, \
- { __reg, BIT(9) }, \
- { __reg, BIT(10) }, \
- { __reg, BIT(11) }, \
- { __reg, BIT(12) }, \
- { __reg, BIT(13) }, \
- { __reg, BIT(14) }, \
- { __reg, BIT(15) }
-
-static struct meson_ee_pwrc_mem_domain axg_pwrc_mem_vpu[] = {
- VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
- VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
-};
-
-static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_vpu[] = {
- VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
- VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
- VPU_MEMPD(HHI_VPU_MEM_PD_REG2),
- VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
-};
-
-static struct meson_ee_pwrc_mem_domain gxbb_pwrc_mem_vpu[] = {
- VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
- VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
- VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
-};
-
-static struct meson_ee_pwrc_mem_domain meson_pwrc_mem_eth[] = {
- { HHI_MEM_PD_REG0, GENMASK(3, 2) },
-};
-
-static struct meson_ee_pwrc_mem_domain meson8_pwrc_audio_dsp_mem[] = {
- { HHI_MEM_PD_REG0, GENMASK(1, 0) },
-};
-
-static struct meson_ee_pwrc_mem_domain meson8_pwrc_mem_vpu[] = {
- VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
- VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
- VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
-};
-
-static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_vpu[] = {
- VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
- VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
- VPU_MEMPD(HHI_VPU_MEM_PD_REG2),
- VPU_MEMPD(HHI_VPU_MEM_PD_REG3),
- { HHI_VPU_MEM_PD_REG4, GENMASK(1, 0) },
- { HHI_VPU_MEM_PD_REG4, GENMASK(3, 2) },
- { HHI_VPU_MEM_PD_REG4, GENMASK(5, 4) },
- { HHI_VPU_MEM_PD_REG4, GENMASK(7, 6) },
- VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
-};
-
-static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_nna[] = {
- { HHI_NANOQ_MEM_PD_REG0, 0xff },
- { HHI_NANOQ_MEM_PD_REG1, 0xff },
-};
-
-static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_usb[] = {
- { HHI_MEM_PD_REG0, GENMASK(31, 30) },
-};
-
-static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_pcie[] = {
- { HHI_MEM_PD_REG0, GENMASK(29, 26) },
-};
-
-static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_ge2d[] = {
- { HHI_MEM_PD_REG0, GENMASK(25, 18) },
-};
-
-static struct meson_ee_pwrc_mem_domain axg_pwrc_mem_audio[] = {
- { HHI_MEM_PD_REG0, GENMASK(5, 4) },
-};
-
-static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = {
- { HHI_MEM_PD_REG0, GENMASK(5, 4) },
- { HHI_AUDIO_MEM_PD_REG0, GENMASK(1, 0) },
- { HHI_AUDIO_MEM_PD_REG0, GENMASK(3, 2) },
- { HHI_AUDIO_MEM_PD_REG0, GENMASK(5, 4) },
- { HHI_AUDIO_MEM_PD_REG0, GENMASK(7, 6) },
- { HHI_AUDIO_MEM_PD_REG0, GENMASK(13, 12) },
- { HHI_AUDIO_MEM_PD_REG0, GENMASK(15, 14) },
- { HHI_AUDIO_MEM_PD_REG0, GENMASK(17, 16) },
- { HHI_AUDIO_MEM_PD_REG0, GENMASK(19, 18) },
- { HHI_AUDIO_MEM_PD_REG0, GENMASK(21, 20) },
- { HHI_AUDIO_MEM_PD_REG0, GENMASK(23, 22) },
- { HHI_AUDIO_MEM_PD_REG0, GENMASK(25, 24) },
- { HHI_AUDIO_MEM_PD_REG0, GENMASK(27, 26) },
-};
-
-#define VPU_PD(__name, __top_pd, __mem, __is_pwr_off, __resets, __clks) \
- { \
- .name = __name, \
- .reset_names_count = __resets, \
- .clk_names_count = __clks, \
- .top_pd = __top_pd, \
- .mem_pd_count = ARRAY_SIZE(__mem), \
- .mem_pd = __mem, \
- .is_powered_off = __is_pwr_off, \
- }
-
-#define TOP_PD(__name, __top_pd, __mem, __is_pwr_off) \
- { \
- .name = __name, \
- .top_pd = __top_pd, \
- .mem_pd_count = ARRAY_SIZE(__mem), \
- .mem_pd = __mem, \
- .is_powered_off = __is_pwr_off, \
- }
-
-#define MEM_PD(__name, __mem) \
- TOP_PD(__name, NULL, __mem, NULL)
-
-static bool pwrc_ee_is_powered_off(struct meson_ee_pwrc_domain *pwrc_domain);
-
-static struct meson_ee_pwrc_domain_desc axg_pwrc_domains[] = {
- [PWRC_AXG_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, axg_pwrc_mem_vpu,
- pwrc_ee_is_powered_off, 5, 2),
- [PWRC_AXG_ETHERNET_MEM_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),
- [PWRC_AXG_AUDIO_ID] = MEM_PD("AUDIO", axg_pwrc_mem_audio),
-};
-
-static struct meson_ee_pwrc_domain_desc g12a_pwrc_domains[] = {
- [PWRC_G12A_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, g12a_pwrc_mem_vpu,
- pwrc_ee_is_powered_off, 11, 2),
- [PWRC_G12A_ETH_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),
-};
-
-static struct meson_ee_pwrc_domain_desc gxbb_pwrc_domains[] = {
- [PWRC_GXBB_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, gxbb_pwrc_mem_vpu,
- pwrc_ee_is_powered_off, 12, 2),
- [PWRC_GXBB_ETHERNET_MEM_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),
-};
-
-static struct meson_ee_pwrc_domain_desc meson8_pwrc_domains[] = {
- [PWRC_MESON8_VPU_ID] = VPU_PD("VPU", &meson8_pwrc_vpu,
- meson8_pwrc_mem_vpu,
- pwrc_ee_is_powered_off, 0, 1),
- [PWRC_MESON8_ETHERNET_MEM_ID] = MEM_PD("ETHERNET_MEM",
- meson_pwrc_mem_eth),
- [PWRC_MESON8_AUDIO_DSP_MEM_ID] = MEM_PD("AUDIO_DSP_MEM",
- meson8_pwrc_audio_dsp_mem),
-};
-
-static struct meson_ee_pwrc_domain_desc meson8b_pwrc_domains[] = {
- [PWRC_MESON8_VPU_ID] = VPU_PD("VPU", &meson8_pwrc_vpu,
- meson8_pwrc_mem_vpu,
- pwrc_ee_is_powered_off, 11, 1),
- [PWRC_MESON8_ETHERNET_MEM_ID] = MEM_PD("ETHERNET_MEM",
- meson_pwrc_mem_eth),
- [PWRC_MESON8_AUDIO_DSP_MEM_ID] = MEM_PD("AUDIO_DSP_MEM",
- meson8_pwrc_audio_dsp_mem),
-};
-
-static struct meson_ee_pwrc_domain_desc sm1_pwrc_domains[] = {
- [PWRC_SM1_VPU_ID] = VPU_PD("VPU", &sm1_pwrc_vpu, sm1_pwrc_mem_vpu,
- pwrc_ee_is_powered_off, 11, 2),
- [PWRC_SM1_NNA_ID] = TOP_PD("NNA", &sm1_pwrc_nna, sm1_pwrc_mem_nna,
- pwrc_ee_is_powered_off),
- [PWRC_SM1_USB_ID] = TOP_PD("USB", &sm1_pwrc_usb, sm1_pwrc_mem_usb,
- pwrc_ee_is_powered_off),
- [PWRC_SM1_PCIE_ID] = TOP_PD("PCI", &sm1_pwrc_pci, sm1_pwrc_mem_pcie,
- pwrc_ee_is_powered_off),
- [PWRC_SM1_GE2D_ID] = TOP_PD("GE2D", &sm1_pwrc_ge2d, sm1_pwrc_mem_ge2d,
- pwrc_ee_is_powered_off),
- [PWRC_SM1_AUDIO_ID] = MEM_PD("AUDIO", sm1_pwrc_mem_audio),
- [PWRC_SM1_ETH_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),
-};
-
-struct meson_ee_pwrc_domain {
- struct generic_pm_domain base;
- bool enabled;
- struct meson_ee_pwrc *pwrc;
- struct meson_ee_pwrc_domain_desc desc;
- struct clk_bulk_data *clks;
- int num_clks;
- struct reset_control *rstc;
- int num_rstc;
-};
-
-struct meson_ee_pwrc {
- struct regmap *regmap_ao;
- struct regmap *regmap_hhi;
- struct meson_ee_pwrc_domain *domains;
- struct genpd_onecell_data xlate;
-};
-
-static bool pwrc_ee_is_powered_off(struct meson_ee_pwrc_domain *pwrc_domain)
-{
- u32 reg;
-
- regmap_read(pwrc_domain->pwrc->regmap_ao,
- pwrc_domain->desc.top_pd->sleep_reg, &reg);
-
- return (reg & pwrc_domain->desc.top_pd->sleep_mask);
-}
-
-static int meson_ee_pwrc_off(struct generic_pm_domain *domain)
-{
- struct meson_ee_pwrc_domain *pwrc_domain =
- container_of(domain, struct meson_ee_pwrc_domain, base);
- int i;
-
- if (pwrc_domain->desc.top_pd)
- regmap_update_bits(pwrc_domain->pwrc->regmap_ao,
- pwrc_domain->desc.top_pd->sleep_reg,
- pwrc_domain->desc.top_pd->sleep_mask,
- pwrc_domain->desc.top_pd->sleep_mask);
- udelay(20);
-
- for (i = 0 ; i < pwrc_domain->desc.mem_pd_count ; ++i)
- regmap_update_bits(pwrc_domain->pwrc->regmap_hhi,
- pwrc_domain->desc.mem_pd[i].reg,
- pwrc_domain->desc.mem_pd[i].mask,
- pwrc_domain->desc.mem_pd[i].mask);
-
- udelay(20);
-
- if (pwrc_domain->desc.top_pd)
- regmap_update_bits(pwrc_domain->pwrc->regmap_ao,
- pwrc_domain->desc.top_pd->iso_reg,
- pwrc_domain->desc.top_pd->iso_mask,
- pwrc_domain->desc.top_pd->iso_mask);
-
- if (pwrc_domain->num_clks) {
- msleep(20);
- clk_bulk_disable_unprepare(pwrc_domain->num_clks,
- pwrc_domain->clks);
- }
-
- return 0;
-}
-
-static int meson_ee_pwrc_on(struct generic_pm_domain *domain)
-{
- struct meson_ee_pwrc_domain *pwrc_domain =
- container_of(domain, struct meson_ee_pwrc_domain, base);
- int i, ret;
-
- if (pwrc_domain->desc.top_pd)
- regmap_update_bits(pwrc_domain->pwrc->regmap_ao,
- pwrc_domain->desc.top_pd->sleep_reg,
- pwrc_domain->desc.top_pd->sleep_mask, 0);
- udelay(20);
-
- for (i = 0 ; i < pwrc_domain->desc.mem_pd_count ; ++i)
- regmap_update_bits(pwrc_domain->pwrc->regmap_hhi,
- pwrc_domain->desc.mem_pd[i].reg,
- pwrc_domain->desc.mem_pd[i].mask, 0);
-
- udelay(20);
-
- ret = reset_control_assert(pwrc_domain->rstc);
- if (ret)
- return ret;
-
- if (pwrc_domain->desc.top_pd)
- regmap_update_bits(pwrc_domain->pwrc->regmap_ao,
- pwrc_domain->desc.top_pd->iso_reg,
- pwrc_domain->desc.top_pd->iso_mask, 0);
-
- ret = reset_control_deassert(pwrc_domain->rstc);
- if (ret)
- return ret;
-
- return clk_bulk_prepare_enable(pwrc_domain->num_clks,
- pwrc_domain->clks);
-}
-
-static int meson_ee_pwrc_init_domain(struct platform_device *pdev,
- struct meson_ee_pwrc *pwrc,
- struct meson_ee_pwrc_domain *dom)
-{
- int ret;
-
- dom->pwrc = pwrc;
- dom->num_rstc = dom->desc.reset_names_count;
- dom->num_clks = dom->desc.clk_names_count;
-
- if (dom->num_rstc) {
- int count = reset_control_get_count(&pdev->dev);
-
- if (count != dom->num_rstc)
- dev_warn(&pdev->dev, "Invalid resets count %d for domain %s\n",
- count, dom->desc.name);
-
- dom->rstc = devm_reset_control_array_get_exclusive(&pdev->dev);
- if (IS_ERR(dom->rstc))
- return PTR_ERR(dom->rstc);
- }
-
- if (dom->num_clks) {
- int ret = devm_clk_bulk_get_all(&pdev->dev, &dom->clks);
- if (ret < 0)
- return ret;
-
- if (dom->num_clks != ret) {
- dev_warn(&pdev->dev, "Invalid clocks count %d for domain %s\n",
- ret, dom->desc.name);
- dom->num_clks = ret;
- }
- }
-
- dom->base.name = dom->desc.name;
- dom->base.power_on = meson_ee_pwrc_on;
- dom->base.power_off = meson_ee_pwrc_off;
-
- /*
- * TOFIX: This is a special case for the VPU power domain, which can
- * be enabled previously by the bootloader. In this case the VPU
- * pipeline may be functional but no driver maybe never attach
- * to this power domain, and if the domain is disabled it could
- * cause system errors. This is why the pm_domain_always_on_gov
- * is used here.
- * For the same reason, the clocks should be enabled in case
- * we need to power the domain off, otherwise the internal clocks
- * prepare/enable counters won't be in sync.
- */
- if (dom->num_clks && dom->desc.is_powered_off && !dom->desc.is_powered_off(dom)) {
- ret = clk_bulk_prepare_enable(dom->num_clks, dom->clks);
- if (ret)
- return ret;
-
- dom->base.flags = GENPD_FLAG_ALWAYS_ON;
- ret = pm_genpd_init(&dom->base, NULL, false);
- if (ret)
- return ret;
- } else {
- ret = pm_genpd_init(&dom->base, NULL,
- (dom->desc.is_powered_off ?
- dom->desc.is_powered_off(dom) : true));
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int meson_ee_pwrc_probe(struct platform_device *pdev)
-{
- const struct meson_ee_pwrc_domain_data *match;
- struct regmap *regmap_ao, *regmap_hhi;
- struct device_node *parent_np;
- struct meson_ee_pwrc *pwrc;
- int i, ret;
-
- match = of_device_get_match_data(&pdev->dev);
- if (!match) {
- dev_err(&pdev->dev, "failed to get match data\n");
- return -ENODEV;
- }
-
- pwrc = devm_kzalloc(&pdev->dev, sizeof(*pwrc), GFP_KERNEL);
- if (!pwrc)
- return -ENOMEM;
-
- pwrc->xlate.domains = devm_kcalloc(&pdev->dev, match->count,
- sizeof(*pwrc->xlate.domains),
- GFP_KERNEL);
- if (!pwrc->xlate.domains)
- return -ENOMEM;
-
- pwrc->domains = devm_kcalloc(&pdev->dev, match->count,
- sizeof(*pwrc->domains), GFP_KERNEL);
- if (!pwrc->domains)
- return -ENOMEM;
-
- pwrc->xlate.num_domains = match->count;
-
- parent_np = of_get_parent(pdev->dev.of_node);
- regmap_hhi = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap_hhi)) {
- dev_err(&pdev->dev, "failed to get HHI regmap\n");
- return PTR_ERR(regmap_hhi);
- }
-
- regmap_ao = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
- "amlogic,ao-sysctrl");
- if (IS_ERR(regmap_ao)) {
- dev_err(&pdev->dev, "failed to get AO regmap\n");
- return PTR_ERR(regmap_ao);
- }
-
- pwrc->regmap_ao = regmap_ao;
- pwrc->regmap_hhi = regmap_hhi;
-
- platform_set_drvdata(pdev, pwrc);
-
- for (i = 0 ; i < match->count ; ++i) {
- struct meson_ee_pwrc_domain *dom = &pwrc->domains[i];
-
- memcpy(&dom->desc, &match->domains[i], sizeof(dom->desc));
-
- ret = meson_ee_pwrc_init_domain(pdev, pwrc, dom);
- if (ret)
- return ret;
-
- pwrc->xlate.domains[i] = &dom->base;
- }
-
- return of_genpd_add_provider_onecell(pdev->dev.of_node, &pwrc->xlate);
-}
-
-static void meson_ee_pwrc_shutdown(struct platform_device *pdev)
-{
- struct meson_ee_pwrc *pwrc = platform_get_drvdata(pdev);
- int i;
-
- for (i = 0 ; i < pwrc->xlate.num_domains ; ++i) {
- struct meson_ee_pwrc_domain *dom = &pwrc->domains[i];
-
- if (dom->desc.is_powered_off && !dom->desc.is_powered_off(dom))
- meson_ee_pwrc_off(&dom->base);
- }
-}
-
-static struct meson_ee_pwrc_domain_data meson_ee_g12a_pwrc_data = {
- .count = ARRAY_SIZE(g12a_pwrc_domains),
- .domains = g12a_pwrc_domains,
-};
-
-static struct meson_ee_pwrc_domain_data meson_ee_axg_pwrc_data = {
- .count = ARRAY_SIZE(axg_pwrc_domains),
- .domains = axg_pwrc_domains,
-};
-
-static struct meson_ee_pwrc_domain_data meson_ee_gxbb_pwrc_data = {
- .count = ARRAY_SIZE(gxbb_pwrc_domains),
- .domains = gxbb_pwrc_domains,
-};
-
-static struct meson_ee_pwrc_domain_data meson_ee_m8_pwrc_data = {
- .count = ARRAY_SIZE(meson8_pwrc_domains),
- .domains = meson8_pwrc_domains,
-};
-
-static struct meson_ee_pwrc_domain_data meson_ee_m8b_pwrc_data = {
- .count = ARRAY_SIZE(meson8b_pwrc_domains),
- .domains = meson8b_pwrc_domains,
-};
-
-static struct meson_ee_pwrc_domain_data meson_ee_sm1_pwrc_data = {
- .count = ARRAY_SIZE(sm1_pwrc_domains),
- .domains = sm1_pwrc_domains,
-};
-
-static const struct of_device_id meson_ee_pwrc_match_table[] = {
- {
- .compatible = "amlogic,meson8-pwrc",
- .data = &meson_ee_m8_pwrc_data,
- },
- {
- .compatible = "amlogic,meson8b-pwrc",
- .data = &meson_ee_m8b_pwrc_data,
- },
- {
- .compatible = "amlogic,meson8m2-pwrc",
- .data = &meson_ee_m8b_pwrc_data,
- },
- {
- .compatible = "amlogic,meson-axg-pwrc",
- .data = &meson_ee_axg_pwrc_data,
- },
- {
- .compatible = "amlogic,meson-gxbb-pwrc",
- .data = &meson_ee_gxbb_pwrc_data,
- },
- {
- .compatible = "amlogic,meson-g12a-pwrc",
- .data = &meson_ee_g12a_pwrc_data,
- },
- {
- .compatible = "amlogic,meson-sm1-pwrc",
- .data = &meson_ee_sm1_pwrc_data,
- },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, meson_ee_pwrc_match_table);
-
-static struct platform_driver meson_ee_pwrc_driver = {
- .probe = meson_ee_pwrc_probe,
- .shutdown = meson_ee_pwrc_shutdown,
- .driver = {
- .name = "meson_ee_pwrc",
- .of_match_table = meson_ee_pwrc_match_table,
- },
-};
-module_platform_driver(meson_ee_pwrc_driver);
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c
deleted file mode 100644
index 312fd9afccb0..000000000000
--- a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Copyright (c) 2017 BayLibre, SAS
- * Author: Neil Armstrong <narmstrong@baylibre.com>
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <linux/of_address.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <linux/bitfield.h>
-#include <linux/regmap.h>
-#include <linux/mfd/syscon.h>
-#include <linux/of_device.h>
-#include <linux/reset.h>
-#include <linux/clk.h>
-#include <linux/module.h>
-
-/* AO Offsets */
-
-#define AO_RTI_GEN_PWR_SLEEP0 (0x3a << 2)
-
-#define GEN_PWR_VPU_HDMI BIT(8)
-#define GEN_PWR_VPU_HDMI_ISO BIT(9)
-
-/* HHI Offsets */
-
-#define HHI_MEM_PD_REG0 (0x40 << 2)
-#define HHI_VPU_MEM_PD_REG0 (0x41 << 2)
-#define HHI_VPU_MEM_PD_REG1 (0x42 << 2)
-#define HHI_VPU_MEM_PD_REG2 (0x4d << 2)
-
-struct meson_gx_pwrc_vpu {
- struct generic_pm_domain genpd;
- struct regmap *regmap_ao;
- struct regmap *regmap_hhi;
- struct reset_control *rstc;
- struct clk *vpu_clk;
- struct clk *vapb_clk;
-};
-
-static inline
-struct meson_gx_pwrc_vpu *genpd_to_pd(struct generic_pm_domain *d)
-{
- return container_of(d, struct meson_gx_pwrc_vpu, genpd);
-}
-
-static int meson_gx_pwrc_vpu_power_off(struct generic_pm_domain *genpd)
-{
- struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
- int i;
-
- regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
- GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
- udelay(20);
-
- /* Power Down Memories */
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
- 0x3 << i, 0x3 << i);
- udelay(5);
- }
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
- 0x3 << i, 0x3 << i);
- udelay(5);
- }
- for (i = 8; i < 16; i++) {
- regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
- BIT(i), BIT(i));
- udelay(5);
- }
- udelay(20);
-
- regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
- GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
-
- msleep(20);
-
- clk_disable_unprepare(pd->vpu_clk);
- clk_disable_unprepare(pd->vapb_clk);
-
- return 0;
-}
-
-static int meson_g12a_pwrc_vpu_power_off(struct generic_pm_domain *genpd)
-{
- struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
- int i;
-
- regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
- GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
- udelay(20);
-
- /* Power Down Memories */
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
- 0x3 << i, 0x3 << i);
- udelay(5);
- }
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
- 0x3 << i, 0x3 << i);
- udelay(5);
- }
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2,
- 0x3 << i, 0x3 << i);
- udelay(5);
- }
- for (i = 8; i < 16; i++) {
- regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
- BIT(i), BIT(i));
- udelay(5);
- }
- udelay(20);
-
- regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
- GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
-
- msleep(20);
-
- clk_disable_unprepare(pd->vpu_clk);
- clk_disable_unprepare(pd->vapb_clk);
-
- return 0;
-}
-
-static int meson_gx_pwrc_vpu_setup_clk(struct meson_gx_pwrc_vpu *pd)
-{
- int ret;
-
- ret = clk_prepare_enable(pd->vpu_clk);
- if (ret)
- return ret;
-
- ret = clk_prepare_enable(pd->vapb_clk);
- if (ret)
- clk_disable_unprepare(pd->vpu_clk);
-
- return ret;
-}
-
-static int meson_gx_pwrc_vpu_power_on(struct generic_pm_domain *genpd)
-{
- struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
- int ret;
- int i;
-
- regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
- GEN_PWR_VPU_HDMI, 0);
- udelay(20);
-
- /* Power Up Memories */
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
- 0x3 << i, 0);
- udelay(5);
- }
-
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
- 0x3 << i, 0);
- udelay(5);
- }
-
- for (i = 8; i < 16; i++) {
- regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
- BIT(i), 0);
- udelay(5);
- }
- udelay(20);
-
- ret = reset_control_assert(pd->rstc);
- if (ret)
- return ret;
-
- regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
- GEN_PWR_VPU_HDMI_ISO, 0);
-
- ret = reset_control_deassert(pd->rstc);
- if (ret)
- return ret;
-
- ret = meson_gx_pwrc_vpu_setup_clk(pd);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int meson_g12a_pwrc_vpu_power_on(struct generic_pm_domain *genpd)
-{
- struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
- int ret;
- int i;
-
- regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
- GEN_PWR_VPU_HDMI, 0);
- udelay(20);
-
- /* Power Up Memories */
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
- 0x3 << i, 0);
- udelay(5);
- }
-
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
- 0x3 << i, 0);
- udelay(5);
- }
-
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2,
- 0x3 << i, 0);
- udelay(5);
- }
-
- for (i = 8; i < 16; i++) {
- regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
- BIT(i), 0);
- udelay(5);
- }
- udelay(20);
-
- ret = reset_control_assert(pd->rstc);
- if (ret)
- return ret;
-
- regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
- GEN_PWR_VPU_HDMI_ISO, 0);
-
- ret = reset_control_deassert(pd->rstc);
- if (ret)
- return ret;
-
- ret = meson_gx_pwrc_vpu_setup_clk(pd);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static bool meson_gx_pwrc_vpu_get_power(struct meson_gx_pwrc_vpu *pd)
-{
- u32 reg;
-
- regmap_read(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, &reg);
-
- return (reg & GEN_PWR_VPU_HDMI);
-}
-
-static struct meson_gx_pwrc_vpu vpu_hdmi_pd = {
- .genpd = {
- .name = "vpu_hdmi",
- .power_off = meson_gx_pwrc_vpu_power_off,
- .power_on = meson_gx_pwrc_vpu_power_on,
- },
-};
-
-static struct meson_gx_pwrc_vpu vpu_hdmi_pd_g12a = {
- .genpd = {
- .name = "vpu_hdmi",
- .power_off = meson_g12a_pwrc_vpu_power_off,
- .power_on = meson_g12a_pwrc_vpu_power_on,
- },
-};
-
-static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
-{
- const struct meson_gx_pwrc_vpu *vpu_pd_match;
- struct regmap *regmap_ao, *regmap_hhi;
- struct meson_gx_pwrc_vpu *vpu_pd;
- struct device_node *parent_np;
- struct reset_control *rstc;
- struct clk *vpu_clk;
- struct clk *vapb_clk;
- bool powered_off;
- int ret;
-
- vpu_pd_match = of_device_get_match_data(&pdev->dev);
- if (!vpu_pd_match) {
- dev_err(&pdev->dev, "failed to get match data\n");
- return -ENODEV;
- }
-
- vpu_pd = devm_kzalloc(&pdev->dev, sizeof(*vpu_pd), GFP_KERNEL);
- if (!vpu_pd)
- return -ENOMEM;
-
- memcpy(vpu_pd, vpu_pd_match, sizeof(*vpu_pd));
-
- parent_np = of_get_parent(pdev->dev.of_node);
- regmap_ao = syscon_node_to_regmap(parent_np);
- of_node_put(parent_np);
- if (IS_ERR(regmap_ao)) {
- dev_err(&pdev->dev, "failed to get regmap\n");
- return PTR_ERR(regmap_ao);
- }
-
- regmap_hhi = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
- "amlogic,hhi-sysctrl");
- if (IS_ERR(regmap_hhi)) {
- dev_err(&pdev->dev, "failed to get HHI regmap\n");
- return PTR_ERR(regmap_hhi);
- }
-
- rstc = devm_reset_control_array_get_exclusive(&pdev->dev);
- if (IS_ERR(rstc)) {
- if (PTR_ERR(rstc) != -EPROBE_DEFER)
- dev_err(&pdev->dev, "failed to get reset lines\n");
- return PTR_ERR(rstc);
- }
-
- vpu_clk = devm_clk_get(&pdev->dev, "vpu");
- if (IS_ERR(vpu_clk)) {
- dev_err(&pdev->dev, "vpu clock request failed\n");
- return PTR_ERR(vpu_clk);
- }
-
- vapb_clk = devm_clk_get(&pdev->dev, "vapb");
- if (IS_ERR(vapb_clk)) {
- dev_err(&pdev->dev, "vapb clock request failed\n");
- return PTR_ERR(vapb_clk);
- }
-
- vpu_pd->regmap_ao = regmap_ao;
- vpu_pd->regmap_hhi = regmap_hhi;
- vpu_pd->rstc = rstc;
- vpu_pd->vpu_clk = vpu_clk;
- vpu_pd->vapb_clk = vapb_clk;
-
- platform_set_drvdata(pdev, vpu_pd);
-
- powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd);
-
- /* If already powered, sync the clock states */
- if (!powered_off) {
- ret = meson_gx_pwrc_vpu_setup_clk(vpu_pd);
- if (ret)
- return ret;
- }
-
- vpu_pd->genpd.flags = GENPD_FLAG_ALWAYS_ON;
- pm_genpd_init(&vpu_pd->genpd, NULL, powered_off);
-
- return of_genpd_add_provider_simple(pdev->dev.of_node,
- &vpu_pd->genpd);
-}
-
-static void meson_gx_pwrc_vpu_shutdown(struct platform_device *pdev)
-{
- struct meson_gx_pwrc_vpu *vpu_pd = platform_get_drvdata(pdev);
- bool powered_off;
-
- powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd);
- if (!powered_off)
- vpu_pd->genpd.power_off(&vpu_pd->genpd);
-}
-
-static const struct of_device_id meson_gx_pwrc_vpu_match_table[] = {
- { .compatible = "amlogic,meson-gx-pwrc-vpu", .data = &vpu_hdmi_pd },
- {
- .compatible = "amlogic,meson-g12a-pwrc-vpu",
- .data = &vpu_hdmi_pd_g12a
- },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, meson_gx_pwrc_vpu_match_table);
-
-static struct platform_driver meson_gx_pwrc_vpu_driver = {
- .probe = meson_gx_pwrc_vpu_probe,
- .shutdown = meson_gx_pwrc_vpu_shutdown,
- .driver = {
- .name = "meson_gx_pwrc_vpu",
- .of_match_table = meson_gx_pwrc_vpu_match_table,
- },
-};
-module_platform_driver(meson_gx_pwrc_vpu_driver);
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/amlogic/meson-gx-socinfo.c b/drivers/soc/amlogic/meson-gx-socinfo.c
index 165f7548401b..2a54ca43cd13 100644
--- a/drivers/soc/amlogic/meson-gx-socinfo.c
+++ b/drivers/soc/amlogic/meson-gx-socinfo.c
@@ -41,6 +41,14 @@ static const struct meson_gx_soc_id {
{ "G12B", 0x29 },
{ "SM1", 0x2b },
{ "A1", 0x2c },
+ { "T7", 0x36 },
+ { "S4", 0x37 },
+ { "A5", 0x3c },
+ { "C3", 0x3d },
+ { "A4", 0x40 },
+ { "S7", 0x46 },
+ { "S7D", 0x47 },
+ { "S6", 0x48 },
};
static const struct meson_gx_package_id {
@@ -63,7 +71,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 +84,14 @@ 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 },
+ { "S805X3", 0x46, 0x3, 0xf },
+ { "S905X5M", 0x47, 0x1, 0xf },
+ { "S905X5", 0x48, 0x1, 0xf },
};
static inline unsigned int socinfo_to_major(u32 socinfo)
@@ -174,11 +192,6 @@ static int __init meson_gx_socinfo_init(void)
return -ENODEV;
soc_dev_attr->family = "Amlogic Meson";
-
- np = of_find_node_by_path("/");
- of_property_read_string(np, "model", &soc_dev_attr->machine);
- of_node_put(np);
-
soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%x:%x - %x:%x",
socinfo_to_major(socinfo),
socinfo_to_minor(socinfo),
diff --git a/drivers/soc/amlogic/meson-secure-pwrc.c b/drivers/soc/amlogic/meson-secure-pwrc.c
deleted file mode 100644
index e93518763526..000000000000
--- a/drivers/soc/amlogic/meson-secure-pwrc.c
+++ /dev/null
@@ -1,231 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
-/*
- * Copyright (c) 2019 Amlogic, Inc.
- * Author: Jianxin Pan <jianxin.pan@amlogic.com>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/io.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <dt-bindings/power/meson-a1-power.h>
-#include <dt-bindings/power/meson-s4-power.h>
-#include <linux/arm-smccc.h>
-#include <linux/firmware/meson/meson_sm.h>
-#include <linux/module.h>
-
-#define PWRC_ON 1
-#define PWRC_OFF 0
-
-struct meson_secure_pwrc_domain {
- struct generic_pm_domain base;
- unsigned int index;
- struct meson_secure_pwrc *pwrc;
-};
-
-struct meson_secure_pwrc {
- struct meson_secure_pwrc_domain *domains;
- struct genpd_onecell_data xlate;
- struct meson_sm_firmware *fw;
-};
-
-struct meson_secure_pwrc_domain_desc {
- unsigned int index;
- unsigned int flags;
- char *name;
- bool (*is_off)(struct meson_secure_pwrc_domain *pwrc_domain);
-};
-
-struct meson_secure_pwrc_domain_data {
- unsigned int count;
- struct meson_secure_pwrc_domain_desc *domains;
-};
-
-static bool pwrc_secure_is_off(struct meson_secure_pwrc_domain *pwrc_domain)
-{
- int is_off = 1;
-
- if (meson_sm_call(pwrc_domain->pwrc->fw, SM_A1_PWRC_GET, &is_off,
- pwrc_domain->index, 0, 0, 0, 0) < 0)
- pr_err("failed to get power domain status\n");
-
- return is_off;
-}
-
-static int meson_secure_pwrc_off(struct generic_pm_domain *domain)
-{
- int ret = 0;
- struct meson_secure_pwrc_domain *pwrc_domain =
- container_of(domain, struct meson_secure_pwrc_domain, base);
-
- if (meson_sm_call(pwrc_domain->pwrc->fw, SM_A1_PWRC_SET, NULL,
- pwrc_domain->index, PWRC_OFF, 0, 0, 0) < 0) {
- pr_err("failed to set power domain off\n");
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int meson_secure_pwrc_on(struct generic_pm_domain *domain)
-{
- int ret = 0;
- struct meson_secure_pwrc_domain *pwrc_domain =
- container_of(domain, struct meson_secure_pwrc_domain, base);
-
- if (meson_sm_call(pwrc_domain->pwrc->fw, SM_A1_PWRC_SET, NULL,
- pwrc_domain->index, PWRC_ON, 0, 0, 0) < 0) {
- pr_err("failed to set power domain on\n");
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-#define SEC_PD(__name, __flag) \
-[PWRC_##__name##_ID] = \
-{ \
- .name = #__name, \
- .index = PWRC_##__name##_ID, \
- .is_off = pwrc_secure_is_off, \
- .flags = __flag, \
-}
-
-static struct meson_secure_pwrc_domain_desc a1_pwrc_domains[] = {
- SEC_PD(DSPA, 0),
- SEC_PD(DSPB, 0),
- /* UART should keep working in ATF after suspend and before resume */
- SEC_PD(UART, GENPD_FLAG_ALWAYS_ON),
- /* DMC is for DDR PHY ana/dig and DMC, and should be always on */
- SEC_PD(DMC, GENPD_FLAG_ALWAYS_ON),
- SEC_PD(I2C, 0),
- SEC_PD(PSRAM, 0),
- SEC_PD(ACODEC, 0),
- SEC_PD(AUDIO, 0),
- SEC_PD(OTP, 0),
- SEC_PD(DMA, 0),
- SEC_PD(SD_EMMC, 0),
- SEC_PD(RAMA, 0),
- /* SRAMB is used as ATF runtime memory, and should be always on */
- SEC_PD(RAMB, GENPD_FLAG_ALWAYS_ON),
- SEC_PD(IR, 0),
- SEC_PD(SPICC, 0),
- SEC_PD(SPIFC, 0),
- SEC_PD(USB, 0),
- /* NIC is for the Arm NIC-400 interconnect, and should be always on */
- SEC_PD(NIC, GENPD_FLAG_ALWAYS_ON),
- SEC_PD(PDMIN, 0),
- SEC_PD(RSA, 0),
-};
-
-static struct meson_secure_pwrc_domain_desc s4_pwrc_domains[] = {
- SEC_PD(S4_DOS_HEVC, 0),
- SEC_PD(S4_DOS_VDEC, 0),
- SEC_PD(S4_VPU_HDMI, 0),
- SEC_PD(S4_USB_COMB, 0),
- SEC_PD(S4_GE2D, 0),
- /* ETH is for ethernet online wakeup, and should be always on */
- SEC_PD(S4_ETH, GENPD_FLAG_ALWAYS_ON),
- SEC_PD(S4_DEMOD, 0),
- SEC_PD(S4_AUDIO, 0),
-};
-
-static int meson_secure_pwrc_probe(struct platform_device *pdev)
-{
- int i;
- struct device_node *sm_np;
- struct meson_secure_pwrc *pwrc;
- const struct meson_secure_pwrc_domain_data *match;
-
- match = of_device_get_match_data(&pdev->dev);
- if (!match) {
- dev_err(&pdev->dev, "failed to get match data\n");
- return -ENODEV;
- }
-
- sm_np = of_find_compatible_node(NULL, NULL, "amlogic,meson-gxbb-sm");
- if (!sm_np) {
- dev_err(&pdev->dev, "no secure-monitor node\n");
- return -ENODEV;
- }
-
- pwrc = devm_kzalloc(&pdev->dev, sizeof(*pwrc), GFP_KERNEL);
- if (!pwrc) {
- of_node_put(sm_np);
- return -ENOMEM;
- }
-
- pwrc->fw = meson_sm_get(sm_np);
- of_node_put(sm_np);
- if (!pwrc->fw)
- return -EPROBE_DEFER;
-
- pwrc->xlate.domains = devm_kcalloc(&pdev->dev, match->count,
- sizeof(*pwrc->xlate.domains),
- GFP_KERNEL);
- if (!pwrc->xlate.domains)
- return -ENOMEM;
-
- pwrc->domains = devm_kcalloc(&pdev->dev, match->count,
- sizeof(*pwrc->domains), GFP_KERNEL);
- if (!pwrc->domains)
- return -ENOMEM;
-
- pwrc->xlate.num_domains = match->count;
- platform_set_drvdata(pdev, pwrc);
-
- for (i = 0 ; i < match->count ; ++i) {
- struct meson_secure_pwrc_domain *dom = &pwrc->domains[i];
-
- if (!match->domains[i].index)
- continue;
-
- dom->pwrc = pwrc;
- dom->index = match->domains[i].index;
- dom->base.name = match->domains[i].name;
- dom->base.flags = match->domains[i].flags;
- dom->base.power_on = meson_secure_pwrc_on;
- dom->base.power_off = meson_secure_pwrc_off;
-
- pm_genpd_init(&dom->base, NULL, match->domains[i].is_off(dom));
-
- pwrc->xlate.domains[i] = &dom->base;
- }
-
- return of_genpd_add_provider_onecell(pdev->dev.of_node, &pwrc->xlate);
-}
-
-static struct meson_secure_pwrc_domain_data meson_secure_a1_pwrc_data = {
- .domains = a1_pwrc_domains,
- .count = ARRAY_SIZE(a1_pwrc_domains),
-};
-
-static struct meson_secure_pwrc_domain_data meson_secure_s4_pwrc_data = {
- .domains = s4_pwrc_domains,
- .count = ARRAY_SIZE(s4_pwrc_domains),
-};
-
-static const struct of_device_id meson_secure_pwrc_match_table[] = {
- {
- .compatible = "amlogic,meson-a1-pwrc",
- .data = &meson_secure_a1_pwrc_data,
- },
- {
- .compatible = "amlogic,meson-s4-pwrc",
- .data = &meson_secure_s4_pwrc_data,
- },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, meson_secure_pwrc_match_table);
-
-static struct platform_driver meson_secure_pwrc_driver = {
- .probe = meson_secure_pwrc_probe,
- .driver = {
- .name = "meson_secure_pwrc",
- .of_match_table = meson_secure_pwrc_match_table,
- },
-};
-module_platform_driver(meson_secure_pwrc_driver);
-MODULE_LICENSE("Dual MIT/GPL");
diff --git a/drivers/soc/apple/Kconfig b/drivers/soc/apple/Kconfig
index a1596fefacff..ad6736889231 100644
--- a/drivers/soc/apple/Kconfig
+++ b/drivers/soc/apple/Kconfig
@@ -4,24 +4,22 @@ if ARCH_APPLE || COMPILE_TEST
menu "Apple SoC drivers"
-config APPLE_PMGR_PWRSTATE
- bool "Apple SoC PMGR power state control"
+config APPLE_MAILBOX
+ tristate "Apple SoC mailboxes"
depends on PM
- select REGMAP
- select MFD_SYSCON
- select PM_GENERIC_DOMAINS
- select RESET_CONTROLLER
- default ARCH_APPLE
+ depends on ARCH_APPLE || (64BIT && COMPILE_TEST)
help
- The PMGR block in Apple SoCs provides high-level power state
- controls for SoC devices. This driver manages them through the
- generic power domain framework, and also provides reset support.
+ Apple SoCs have various co-processors required for certain
+ peripherals to work (NVMe, display controller, etc.). This
+ driver adds support for the mailbox controller used to
+ communicate with those.
+
+ Say Y here if you have an Apple SoC.
config APPLE_RTKIT
tristate "Apple RTKit co-processor IPC protocol"
- depends on MAILBOX
+ depends on APPLE_MAILBOX
depends on ARCH_APPLE || COMPILE_TEST
- default ARCH_APPLE
help
Apple SoCs such as the M1 come with various co-processors running
their proprietary RTKit operating system. This option enables support
@@ -33,7 +31,6 @@ config APPLE_RTKIT
config APPLE_SART
tristate "Apple SART DMA address filter"
depends on ARCH_APPLE || COMPILE_TEST
- default ARCH_APPLE
help
Apple SART is a simple DMA address filter used on Apple SoCs such
as the M1. It is usually required for the NVMe coprocessor which does
diff --git a/drivers/soc/apple/Makefile b/drivers/soc/apple/Makefile
index e293770cf66d..4d9ab8f3037b 100644
--- a/drivers/soc/apple/Makefile
+++ b/drivers/soc/apple/Makefile
@@ -1,5 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_APPLE_PMGR_PWRSTATE) += apple-pmgr-pwrstate.o
+
+obj-$(CONFIG_APPLE_MAILBOX) += apple-mailbox.o
+apple-mailbox-y = mailbox.o
obj-$(CONFIG_APPLE_RTKIT) += apple-rtkit.o
apple-rtkit-y = rtkit.o rtkit-crashlog.o
diff --git a/drivers/soc/apple/apple-pmgr-pwrstate.c b/drivers/soc/apple/apple-pmgr-pwrstate.c
deleted file mode 100644
index e1122288409a..000000000000
--- a/drivers/soc/apple/apple-pmgr-pwrstate.c
+++ /dev/null
@@ -1,324 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only OR MIT
-/*
- * Apple SoC PMGR device power state driver
- *
- * Copyright The Asahi Linux Contributors
- */
-
-#include <linux/bitops.h>
-#include <linux/bitfield.h>
-#include <linux/err.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <linux/regmap.h>
-#include <linux/mfd/syscon.h>
-#include <linux/reset-controller.h>
-#include <linux/module.h>
-
-#define APPLE_PMGR_RESET BIT(31)
-#define APPLE_PMGR_AUTO_ENABLE BIT(28)
-#define APPLE_PMGR_PS_AUTO GENMASK(27, 24)
-#define APPLE_PMGR_PS_MIN GENMASK(19, 16)
-#define APPLE_PMGR_PARENT_OFF BIT(11)
-#define APPLE_PMGR_DEV_DISABLE BIT(10)
-#define APPLE_PMGR_WAS_CLKGATED BIT(9)
-#define APPLE_PMGR_WAS_PWRGATED BIT(8)
-#define APPLE_PMGR_PS_ACTUAL GENMASK(7, 4)
-#define APPLE_PMGR_PS_TARGET GENMASK(3, 0)
-
-#define APPLE_PMGR_FLAGS (APPLE_PMGR_WAS_CLKGATED | APPLE_PMGR_WAS_PWRGATED)
-
-#define APPLE_PMGR_PS_ACTIVE 0xf
-#define APPLE_PMGR_PS_CLKGATE 0x4
-#define APPLE_PMGR_PS_PWRGATE 0x0
-
-#define APPLE_PMGR_PS_SET_TIMEOUT 100
-#define APPLE_PMGR_RESET_TIME 1
-
-struct apple_pmgr_ps {
- struct device *dev;
- struct generic_pm_domain genpd;
- struct reset_controller_dev rcdev;
- struct regmap *regmap;
- u32 offset;
- u32 min_state;
-};
-
-#define genpd_to_apple_pmgr_ps(_genpd) container_of(_genpd, struct apple_pmgr_ps, genpd)
-#define rcdev_to_apple_pmgr_ps(_rcdev) container_of(_rcdev, struct apple_pmgr_ps, rcdev)
-
-static int apple_pmgr_ps_set(struct generic_pm_domain *genpd, u32 pstate, bool auto_enable)
-{
- int ret;
- struct apple_pmgr_ps *ps = genpd_to_apple_pmgr_ps(genpd);
- u32 reg;
-
- ret = regmap_read(ps->regmap, ps->offset, &reg);
- if (ret < 0)
- return ret;
-
- /* Resets are synchronous, and only work if the device is powered and clocked. */
- if (reg & APPLE_PMGR_RESET && pstate != APPLE_PMGR_PS_ACTIVE)
- dev_err(ps->dev, "PS %s: powering off with RESET active\n",
- genpd->name);
-
- reg &= ~(APPLE_PMGR_AUTO_ENABLE | APPLE_PMGR_FLAGS | APPLE_PMGR_PS_TARGET);
- reg |= FIELD_PREP(APPLE_PMGR_PS_TARGET, pstate);
-
- dev_dbg(ps->dev, "PS %s: pwrstate = 0x%x: 0x%x\n", genpd->name, pstate, reg);
-
- regmap_write(ps->regmap, ps->offset, reg);
-
- ret = regmap_read_poll_timeout_atomic(
- ps->regmap, ps->offset, reg,
- (FIELD_GET(APPLE_PMGR_PS_ACTUAL, reg) == pstate), 1,
- APPLE_PMGR_PS_SET_TIMEOUT);
- if (ret < 0)
- dev_err(ps->dev, "PS %s: Failed to reach power state 0x%x (now: 0x%x)\n",
- genpd->name, pstate, reg);
-
- if (auto_enable) {
- /* Not all devices implement this; this is a no-op where not implemented. */
- reg &= ~APPLE_PMGR_FLAGS;
- reg |= APPLE_PMGR_AUTO_ENABLE;
- regmap_write(ps->regmap, ps->offset, reg);
- }
-
- return ret;
-}
-
-static bool apple_pmgr_ps_is_active(struct apple_pmgr_ps *ps)
-{
- u32 reg = 0;
-
- regmap_read(ps->regmap, ps->offset, &reg);
- /*
- * We consider domains as active if they are actually on, or if they have auto-PM
- * enabled and the intended target is on.
- */
- return (FIELD_GET(APPLE_PMGR_PS_ACTUAL, reg) == APPLE_PMGR_PS_ACTIVE ||
- (FIELD_GET(APPLE_PMGR_PS_TARGET, reg) == APPLE_PMGR_PS_ACTIVE &&
- reg & APPLE_PMGR_AUTO_ENABLE));
-}
-
-static int apple_pmgr_ps_power_on(struct generic_pm_domain *genpd)
-{
- return apple_pmgr_ps_set(genpd, APPLE_PMGR_PS_ACTIVE, true);
-}
-
-static int apple_pmgr_ps_power_off(struct generic_pm_domain *genpd)
-{
- return apple_pmgr_ps_set(genpd, APPLE_PMGR_PS_PWRGATE, false);
-}
-
-static int apple_pmgr_reset_assert(struct reset_controller_dev *rcdev, unsigned long id)
-{
- struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev);
-
- mutex_lock(&ps->genpd.mlock);
-
- if (ps->genpd.status == GENPD_STATE_OFF)
- dev_err(ps->dev, "PS 0x%x: asserting RESET while powered down\n", ps->offset);
-
- dev_dbg(ps->dev, "PS 0x%x: assert reset\n", ps->offset);
- /* Quiesce device before asserting reset */
- regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_DEV_DISABLE,
- APPLE_PMGR_DEV_DISABLE);
- regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_RESET,
- APPLE_PMGR_RESET);
-
- mutex_unlock(&ps->genpd.mlock);
-
- return 0;
-}
-
-static int apple_pmgr_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
-{
- struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev);
-
- mutex_lock(&ps->genpd.mlock);
-
- dev_dbg(ps->dev, "PS 0x%x: deassert reset\n", ps->offset);
- regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_RESET, 0);
- regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_DEV_DISABLE, 0);
-
- if (ps->genpd.status == GENPD_STATE_OFF)
- dev_err(ps->dev, "PS 0x%x: RESET was deasserted while powered down\n", ps->offset);
-
- mutex_unlock(&ps->genpd.mlock);
-
- return 0;
-}
-
-static int apple_pmgr_reset_reset(struct reset_controller_dev *rcdev, unsigned long id)
-{
- int ret;
-
- ret = apple_pmgr_reset_assert(rcdev, id);
- if (ret)
- return ret;
-
- usleep_range(APPLE_PMGR_RESET_TIME, 2 * APPLE_PMGR_RESET_TIME);
-
- return apple_pmgr_reset_deassert(rcdev, id);
-}
-
-static int apple_pmgr_reset_status(struct reset_controller_dev *rcdev, unsigned long id)
-{
- struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev);
- u32 reg = 0;
-
- regmap_read(ps->regmap, ps->offset, &reg);
-
- return !!(reg & APPLE_PMGR_RESET);
-}
-
-const struct reset_control_ops apple_pmgr_reset_ops = {
- .assert = apple_pmgr_reset_assert,
- .deassert = apple_pmgr_reset_deassert,
- .reset = apple_pmgr_reset_reset,
- .status = apple_pmgr_reset_status,
-};
-
-static int apple_pmgr_reset_xlate(struct reset_controller_dev *rcdev,
- const struct of_phandle_args *reset_spec)
-{
- return 0;
-}
-
-static int apple_pmgr_ps_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct device_node *node = dev->of_node;
- struct apple_pmgr_ps *ps;
- struct regmap *regmap;
- struct of_phandle_iterator it;
- int ret;
- const char *name;
- bool active;
-
- regmap = syscon_node_to_regmap(node->parent);
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- ps = devm_kzalloc(dev, sizeof(*ps), GFP_KERNEL);
- if (!ps)
- return -ENOMEM;
-
- ps->dev = dev;
- ps->regmap = regmap;
-
- ret = of_property_read_string(node, "label", &name);
- if (ret < 0) {
- dev_err(dev, "missing label property\n");
- return ret;
- }
-
- ret = of_property_read_u32(node, "reg", &ps->offset);
- if (ret < 0) {
- dev_err(dev, "missing reg property\n");
- return ret;
- }
-
- ps->genpd.name = name;
- ps->genpd.power_on = apple_pmgr_ps_power_on;
- ps->genpd.power_off = apple_pmgr_ps_power_off;
-
- ret = of_property_read_u32(node, "apple,min-state", &ps->min_state);
- if (ret == 0 && ps->min_state <= APPLE_PMGR_PS_ACTIVE)
- regmap_update_bits(regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_PS_MIN,
- FIELD_PREP(APPLE_PMGR_PS_MIN, ps->min_state));
-
- active = apple_pmgr_ps_is_active(ps);
- if (of_property_read_bool(node, "apple,always-on")) {
- ps->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
- if (!active) {
- dev_warn(dev, "always-on domain %s is not on at boot\n", name);
- /* Turn it on so pm_genpd_init does not fail */
- active = apple_pmgr_ps_power_on(&ps->genpd) == 0;
- }
- }
-
- /* Turn on auto-PM if the domain is already on */
- if (active)
- regmap_update_bits(regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_AUTO_ENABLE,
- APPLE_PMGR_AUTO_ENABLE);
-
- ret = pm_genpd_init(&ps->genpd, NULL, !active);
- if (ret < 0) {
- dev_err(dev, "pm_genpd_init failed\n");
- return ret;
- }
-
- ret = of_genpd_add_provider_simple(node, &ps->genpd);
- if (ret < 0) {
- dev_err(dev, "of_genpd_add_provider_simple failed\n");
- return ret;
- }
-
- of_for_each_phandle(&it, ret, node, "power-domains", "#power-domain-cells", -1) {
- struct of_phandle_args parent, child;
-
- parent.np = it.node;
- parent.args_count = of_phandle_iterator_args(&it, parent.args, MAX_PHANDLE_ARGS);
- child.np = node;
- child.args_count = 0;
- ret = of_genpd_add_subdomain(&parent, &child);
-
- if (ret == -EPROBE_DEFER) {
- of_node_put(parent.np);
- goto err_remove;
- } else if (ret < 0) {
- dev_err(dev, "failed to add to parent domain: %d (%s -> %s)\n",
- ret, it.node->name, node->name);
- of_node_put(parent.np);
- goto err_remove;
- }
- }
-
- /*
- * Do not participate in regular PM; parent power domains are handled via the
- * genpd hierarchy.
- */
- pm_genpd_remove_device(dev);
-
- ps->rcdev.owner = THIS_MODULE;
- ps->rcdev.nr_resets = 1;
- ps->rcdev.ops = &apple_pmgr_reset_ops;
- ps->rcdev.of_node = dev->of_node;
- ps->rcdev.of_reset_n_cells = 0;
- ps->rcdev.of_xlate = apple_pmgr_reset_xlate;
-
- ret = devm_reset_controller_register(dev, &ps->rcdev);
- if (ret < 0)
- goto err_remove;
-
- return 0;
-err_remove:
- of_genpd_del_provider(node);
- pm_genpd_remove(&ps->genpd);
- return ret;
-}
-
-static const struct of_device_id apple_pmgr_ps_of_match[] = {
- { .compatible = "apple,pmgr-pwrstate" },
- {}
-};
-
-MODULE_DEVICE_TABLE(of, apple_pmgr_ps_of_match);
-
-static struct platform_driver apple_pmgr_ps_driver = {
- .probe = apple_pmgr_ps_probe,
- .driver = {
- .name = "apple-pmgr-pwrstate",
- .of_match_table = apple_pmgr_ps_of_match,
- },
-};
-
-MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
-MODULE_DESCRIPTION("PMGR power state driver for Apple SoCs");
-MODULE_LICENSE("GPL v2");
-
-module_platform_driver(apple_pmgr_ps_driver);
diff --git a/drivers/soc/apple/mailbox.c b/drivers/soc/apple/mailbox.c
new file mode 100644
index 000000000000..5c48455185c9
--- /dev/null
+++ b/drivers/soc/apple/mailbox.c
@@ -0,0 +1,463 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Apple mailbox driver
+ *
+ * Copyright The Asahi Linux Contributors
+ *
+ * This driver adds support for two mailbox variants (called ASC and M3 by
+ * Apple) found in Apple SoCs such as the M1. It consists of two FIFOs used to
+ * exchange 64+32 bit messages between the main CPU and a co-processor.
+ * Various coprocessors implement different IPC protocols based on these simple
+ * messages and shared memory buffers.
+ *
+ * Both the main CPU and the co-processor see the same set of registers but
+ * the first FIFO (A2I) is always used to transfer messages from the application
+ * processor (us) to the I/O processor and the second one (I2A) for the
+ * other direction.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.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/pm_runtime.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include "mailbox.h"
+
+#define APPLE_ASC_MBOX_CONTROL_FULL BIT(16)
+#define APPLE_ASC_MBOX_CONTROL_EMPTY BIT(17)
+
+#define APPLE_ASC_MBOX_A2I_CONTROL 0x110
+#define APPLE_ASC_MBOX_A2I_SEND0 0x800
+#define APPLE_ASC_MBOX_A2I_SEND1 0x808
+#define APPLE_ASC_MBOX_A2I_RECV0 0x810
+#define APPLE_ASC_MBOX_A2I_RECV1 0x818
+
+#define APPLE_ASC_MBOX_I2A_CONTROL 0x114
+#define APPLE_ASC_MBOX_I2A_SEND0 0x820
+#define APPLE_ASC_MBOX_I2A_SEND1 0x828
+#define APPLE_ASC_MBOX_I2A_RECV0 0x830
+#define APPLE_ASC_MBOX_I2A_RECV1 0x838
+
+#define APPLE_T8015_MBOX_A2I_CONTROL 0x108
+#define APPLE_T8015_MBOX_I2A_CONTROL 0x10c
+
+#define APPLE_M3_MBOX_CONTROL_FULL BIT(16)
+#define APPLE_M3_MBOX_CONTROL_EMPTY BIT(17)
+
+#define APPLE_M3_MBOX_A2I_CONTROL 0x50
+#define APPLE_M3_MBOX_A2I_SEND0 0x60
+#define APPLE_M3_MBOX_A2I_SEND1 0x68
+#define APPLE_M3_MBOX_A2I_RECV0 0x70
+#define APPLE_M3_MBOX_A2I_RECV1 0x78
+
+#define APPLE_M3_MBOX_I2A_CONTROL 0x80
+#define APPLE_M3_MBOX_I2A_SEND0 0x90
+#define APPLE_M3_MBOX_I2A_SEND1 0x98
+#define APPLE_M3_MBOX_I2A_RECV0 0xa0
+#define APPLE_M3_MBOX_I2A_RECV1 0xa8
+
+#define APPLE_M3_MBOX_IRQ_ENABLE 0x48
+#define APPLE_M3_MBOX_IRQ_ACK 0x4c
+#define APPLE_M3_MBOX_IRQ_A2I_EMPTY BIT(0)
+#define APPLE_M3_MBOX_IRQ_A2I_NOT_EMPTY BIT(1)
+#define APPLE_M3_MBOX_IRQ_I2A_EMPTY BIT(2)
+#define APPLE_M3_MBOX_IRQ_I2A_NOT_EMPTY BIT(3)
+
+#define APPLE_MBOX_MSG1_OUTCNT GENMASK(56, 52)
+#define APPLE_MBOX_MSG1_INCNT GENMASK(51, 48)
+#define APPLE_MBOX_MSG1_OUTPTR GENMASK(47, 44)
+#define APPLE_MBOX_MSG1_INPTR GENMASK(43, 40)
+#define APPLE_MBOX_MSG1_MSG GENMASK(31, 0)
+
+#define APPLE_MBOX_TX_TIMEOUT 500
+
+struct apple_mbox_hw {
+ unsigned int control_full;
+ unsigned int control_empty;
+
+ unsigned int a2i_control;
+ unsigned int a2i_send0;
+ unsigned int a2i_send1;
+
+ unsigned int i2a_control;
+ unsigned int i2a_recv0;
+ unsigned int i2a_recv1;
+
+ bool has_irq_controls;
+ unsigned int irq_enable;
+ unsigned int irq_ack;
+ unsigned int irq_bit_recv_not_empty;
+ unsigned int irq_bit_send_empty;
+};
+
+int apple_mbox_send(struct apple_mbox *mbox, const struct apple_mbox_msg msg,
+ bool atomic)
+{
+ unsigned long flags;
+ int ret;
+ u32 mbox_ctrl;
+ long t;
+
+ spin_lock_irqsave(&mbox->tx_lock, flags);
+ mbox_ctrl = readl_relaxed(mbox->regs + mbox->hw->a2i_control);
+
+ while (mbox_ctrl & mbox->hw->control_full) {
+ if (atomic) {
+ ret = readl_poll_timeout_atomic(
+ mbox->regs + mbox->hw->a2i_control, mbox_ctrl,
+ !(mbox_ctrl & mbox->hw->control_full), 100,
+ APPLE_MBOX_TX_TIMEOUT * 1000);
+
+ if (ret) {
+ spin_unlock_irqrestore(&mbox->tx_lock, flags);
+ return ret;
+ }
+
+ break;
+ }
+ /*
+ * The interrupt is level triggered and will keep firing as long as the
+ * FIFO is empty. It will also keep firing if the FIFO was empty
+ * at any point in the past until it has been acknowledged at the
+ * mailbox level. By acknowledging it here we can ensure that we will
+ * only get the interrupt once the FIFO has been cleared again.
+ * If the FIFO is already empty before the ack it will fire again
+ * immediately after the ack.
+ */
+ if (mbox->hw->has_irq_controls) {
+ writel_relaxed(mbox->hw->irq_bit_send_empty,
+ mbox->regs + mbox->hw->irq_ack);
+ }
+ enable_irq(mbox->irq_send_empty);
+ reinit_completion(&mbox->tx_empty);
+ spin_unlock_irqrestore(&mbox->tx_lock, flags);
+
+ t = wait_for_completion_interruptible_timeout(
+ &mbox->tx_empty,
+ msecs_to_jiffies(APPLE_MBOX_TX_TIMEOUT));
+ if (t < 0)
+ return t;
+ else if (t == 0)
+ return -ETIMEDOUT;
+
+ spin_lock_irqsave(&mbox->tx_lock, flags);
+ mbox_ctrl = readl_relaxed(mbox->regs + mbox->hw->a2i_control);
+ }
+
+ writeq_relaxed(msg.msg0, mbox->regs + mbox->hw->a2i_send0);
+ writeq_relaxed(FIELD_PREP(APPLE_MBOX_MSG1_MSG, msg.msg1),
+ mbox->regs + mbox->hw->a2i_send1);
+
+ spin_unlock_irqrestore(&mbox->tx_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(apple_mbox_send);
+
+static irqreturn_t apple_mbox_send_empty_irq(int irq, void *data)
+{
+ struct apple_mbox *mbox = data;
+
+ /*
+ * We don't need to acknowledge the interrupt at the mailbox level
+ * here even if supported by the hardware. It will keep firing but that
+ * doesn't matter since it's disabled at the main interrupt controller.
+ * apple_mbox_send will acknowledge it before enabling
+ * it at the main controller again.
+ */
+ spin_lock(&mbox->tx_lock);
+ disable_irq_nosync(mbox->irq_send_empty);
+ complete(&mbox->tx_empty);
+ spin_unlock(&mbox->tx_lock);
+
+ return IRQ_HANDLED;
+}
+
+static int apple_mbox_poll_locked(struct apple_mbox *mbox)
+{
+ struct apple_mbox_msg msg;
+ int ret = 0;
+
+ u32 mbox_ctrl = readl_relaxed(mbox->regs + mbox->hw->i2a_control);
+
+ while (!(mbox_ctrl & mbox->hw->control_empty)) {
+ msg.msg0 = readq_relaxed(mbox->regs + mbox->hw->i2a_recv0);
+ msg.msg1 = FIELD_GET(
+ APPLE_MBOX_MSG1_MSG,
+ readq_relaxed(mbox->regs + mbox->hw->i2a_recv1));
+
+ mbox->rx(mbox, msg, mbox->cookie);
+ ret++;
+ mbox_ctrl = readl_relaxed(mbox->regs + mbox->hw->i2a_control);
+ }
+
+ /*
+ * The interrupt will keep firing even if there are no more messages
+ * unless we also acknowledge it at the mailbox level here.
+ * There's no race if a message comes in between the check in the while
+ * loop above and the ack below: If a new messages arrives inbetween
+ * those two the interrupt will just fire again immediately after the
+ * ack since it's level triggered.
+ */
+ if (mbox->hw->has_irq_controls) {
+ writel_relaxed(mbox->hw->irq_bit_recv_not_empty,
+ mbox->regs + mbox->hw->irq_ack);
+ }
+
+ return ret;
+}
+
+static irqreturn_t apple_mbox_recv_irq(int irq, void *data)
+{
+ struct apple_mbox *mbox = data;
+
+ spin_lock(&mbox->rx_lock);
+ apple_mbox_poll_locked(mbox);
+ spin_unlock(&mbox->rx_lock);
+
+ return IRQ_HANDLED;
+}
+
+int apple_mbox_poll(struct apple_mbox *mbox)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&mbox->rx_lock, flags);
+ ret = apple_mbox_poll_locked(mbox);
+ spin_unlock_irqrestore(&mbox->rx_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(apple_mbox_poll);
+
+int apple_mbox_start(struct apple_mbox *mbox)
+{
+ int ret;
+
+ if (mbox->active)
+ return 0;
+
+ ret = pm_runtime_resume_and_get(mbox->dev);
+ if (ret)
+ return ret;
+
+ /*
+ * Only some variants of this mailbox HW provide interrupt control
+ * at the mailbox level. We therefore need to handle enabling/disabling
+ * interrupts at the main interrupt controller anyway for hardware that
+ * doesn't. Just always keep the interrupts we care about enabled at
+ * the mailbox level so that both hardware revisions behave almost
+ * the same.
+ */
+ if (mbox->hw->has_irq_controls) {
+ writel_relaxed(mbox->hw->irq_bit_recv_not_empty |
+ mbox->hw->irq_bit_send_empty,
+ mbox->regs + mbox->hw->irq_enable);
+ }
+
+ enable_irq(mbox->irq_recv_not_empty);
+ mbox->active = true;
+ return 0;
+}
+EXPORT_SYMBOL(apple_mbox_start);
+
+void apple_mbox_stop(struct apple_mbox *mbox)
+{
+ if (!mbox->active)
+ return;
+
+ mbox->active = false;
+ disable_irq(mbox->irq_recv_not_empty);
+ pm_runtime_mark_last_busy(mbox->dev);
+ pm_runtime_put_autosuspend(mbox->dev);
+}
+EXPORT_SYMBOL(apple_mbox_stop);
+
+struct apple_mbox *apple_mbox_get(struct device *dev, int index)
+{
+ struct of_phandle_args args;
+ struct platform_device *pdev;
+ struct apple_mbox *mbox;
+ int ret;
+
+ ret = of_parse_phandle_with_args(dev->of_node, "mboxes", "#mbox-cells",
+ index, &args);
+ if (ret || !args.np)
+ return ERR_PTR(ret);
+
+ pdev = of_find_device_by_node(args.np);
+ of_node_put(args.np);
+
+ if (!pdev)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ mbox = platform_get_drvdata(pdev);
+ if (!mbox) {
+ mbox = ERR_PTR(-EPROBE_DEFER);
+ goto out_put_pdev;
+ }
+
+ if (!device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_CONSUMER)) {
+ mbox = ERR_PTR(-ENODEV);
+ goto out_put_pdev;
+ }
+
+out_put_pdev:
+ put_device(&pdev->dev);
+
+ return mbox;
+}
+EXPORT_SYMBOL(apple_mbox_get);
+
+struct apple_mbox *apple_mbox_get_byname(struct device *dev, const char *name)
+{
+ int index;
+
+ index = of_property_match_string(dev->of_node, "mbox-names", name);
+ if (index < 0)
+ return ERR_PTR(index);
+
+ return apple_mbox_get(dev, index);
+}
+EXPORT_SYMBOL(apple_mbox_get_byname);
+
+static int apple_mbox_probe(struct platform_device *pdev)
+{
+ int ret;
+ char *irqname;
+ struct apple_mbox *mbox;
+ struct device *dev = &pdev->dev;
+
+ mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
+ if (!mbox)
+ return -ENOMEM;
+
+ mbox->dev = &pdev->dev;
+ mbox->hw = of_device_get_match_data(dev);
+ if (!mbox->hw)
+ return -EINVAL;
+
+ mbox->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(mbox->regs))
+ return PTR_ERR(mbox->regs);
+
+ mbox->irq_recv_not_empty =
+ platform_get_irq_byname(pdev, "recv-not-empty");
+ if (mbox->irq_recv_not_empty < 0)
+ return -ENODEV;
+
+ mbox->irq_send_empty = platform_get_irq_byname(pdev, "send-empty");
+ if (mbox->irq_send_empty < 0)
+ return -ENODEV;
+
+ spin_lock_init(&mbox->rx_lock);
+ spin_lock_init(&mbox->tx_lock);
+ init_completion(&mbox->tx_empty);
+
+ irqname = devm_kasprintf(dev, GFP_KERNEL, "%s-recv", dev_name(dev));
+ if (!irqname)
+ return -ENOMEM;
+
+ ret = devm_request_irq(dev, mbox->irq_recv_not_empty,
+ apple_mbox_recv_irq,
+ IRQF_NO_AUTOEN | IRQF_NO_SUSPEND, irqname, mbox);
+ if (ret)
+ return ret;
+
+ irqname = devm_kasprintf(dev, GFP_KERNEL, "%s-send", dev_name(dev));
+ if (!irqname)
+ return -ENOMEM;
+
+ ret = devm_request_irq(dev, mbox->irq_send_empty,
+ apple_mbox_send_empty_irq,
+ IRQF_NO_AUTOEN | IRQF_NO_SUSPEND, irqname, mbox);
+ if (ret)
+ return ret;
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, mbox);
+ return 0;
+}
+
+static const struct apple_mbox_hw apple_mbox_t8015_hw = {
+ .control_full = APPLE_ASC_MBOX_CONTROL_FULL,
+ .control_empty = APPLE_ASC_MBOX_CONTROL_EMPTY,
+
+ .a2i_control = APPLE_T8015_MBOX_A2I_CONTROL,
+ .a2i_send0 = APPLE_ASC_MBOX_A2I_SEND0,
+ .a2i_send1 = APPLE_ASC_MBOX_A2I_SEND1,
+
+ .i2a_control = APPLE_T8015_MBOX_I2A_CONTROL,
+ .i2a_recv0 = APPLE_ASC_MBOX_I2A_RECV0,
+ .i2a_recv1 = APPLE_ASC_MBOX_I2A_RECV1,
+
+ .has_irq_controls = false,
+};
+
+static const struct apple_mbox_hw apple_mbox_asc_hw = {
+ .control_full = APPLE_ASC_MBOX_CONTROL_FULL,
+ .control_empty = APPLE_ASC_MBOX_CONTROL_EMPTY,
+
+ .a2i_control = APPLE_ASC_MBOX_A2I_CONTROL,
+ .a2i_send0 = APPLE_ASC_MBOX_A2I_SEND0,
+ .a2i_send1 = APPLE_ASC_MBOX_A2I_SEND1,
+
+ .i2a_control = APPLE_ASC_MBOX_I2A_CONTROL,
+ .i2a_recv0 = APPLE_ASC_MBOX_I2A_RECV0,
+ .i2a_recv1 = APPLE_ASC_MBOX_I2A_RECV1,
+
+ .has_irq_controls = false,
+};
+
+static const struct apple_mbox_hw apple_mbox_m3_hw = {
+ .control_full = APPLE_M3_MBOX_CONTROL_FULL,
+ .control_empty = APPLE_M3_MBOX_CONTROL_EMPTY,
+
+ .a2i_control = APPLE_M3_MBOX_A2I_CONTROL,
+ .a2i_send0 = APPLE_M3_MBOX_A2I_SEND0,
+ .a2i_send1 = APPLE_M3_MBOX_A2I_SEND1,
+
+ .i2a_control = APPLE_M3_MBOX_I2A_CONTROL,
+ .i2a_recv0 = APPLE_M3_MBOX_I2A_RECV0,
+ .i2a_recv1 = APPLE_M3_MBOX_I2A_RECV1,
+
+ .has_irq_controls = true,
+ .irq_enable = APPLE_M3_MBOX_IRQ_ENABLE,
+ .irq_ack = APPLE_M3_MBOX_IRQ_ACK,
+ .irq_bit_recv_not_empty = APPLE_M3_MBOX_IRQ_I2A_NOT_EMPTY,
+ .irq_bit_send_empty = APPLE_M3_MBOX_IRQ_A2I_EMPTY,
+};
+
+static const struct of_device_id apple_mbox_of_match[] = {
+ { .compatible = "apple,asc-mailbox-v4", .data = &apple_mbox_asc_hw },
+ { .compatible = "apple,t8015-asc-mailbox", .data = &apple_mbox_t8015_hw },
+ { .compatible = "apple,m3-mailbox-v2", .data = &apple_mbox_m3_hw },
+ {}
+};
+MODULE_DEVICE_TABLE(of, apple_mbox_of_match);
+
+static struct platform_driver apple_mbox_driver = {
+ .driver = {
+ .name = "apple-mailbox",
+ .of_match_table = apple_mbox_of_match,
+ },
+ .probe = apple_mbox_probe,
+};
+module_platform_driver(apple_mbox_driver);
+
+MODULE_LICENSE("Dual MIT/GPL");
+MODULE_AUTHOR("Sven Peter <sven@svenpeter.dev>");
+MODULE_DESCRIPTION("Apple Mailbox driver");
diff --git a/drivers/soc/apple/mailbox.h b/drivers/soc/apple/mailbox.h
new file mode 100644
index 000000000000..f73a8913da95
--- /dev/null
+++ b/drivers/soc/apple/mailbox.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
+/*
+ * Apple mailbox message format
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+#ifndef _APPLE_MAILBOX_H_
+#define _APPLE_MAILBOX_H_
+
+#include <linux/device.h>
+#include <linux/types.h>
+
+/* encodes a single 96bit message sent over the single channel */
+struct apple_mbox_msg {
+ u64 msg0;
+ u32 msg1;
+};
+
+struct apple_mbox {
+ struct device *dev;
+ void __iomem *regs;
+ const struct apple_mbox_hw *hw;
+ bool active;
+
+ int irq_recv_not_empty;
+ int irq_send_empty;
+
+ spinlock_t rx_lock;
+ spinlock_t tx_lock;
+
+ struct completion tx_empty;
+
+ /** Receive callback for incoming messages */
+ void (*rx)(struct apple_mbox *mbox, struct apple_mbox_msg msg, void *cookie);
+ void *cookie;
+};
+
+struct apple_mbox *apple_mbox_get(struct device *dev, int index);
+struct apple_mbox *apple_mbox_get_byname(struct device *dev, const char *name);
+
+int apple_mbox_start(struct apple_mbox *mbox);
+void apple_mbox_stop(struct apple_mbox *mbox);
+int apple_mbox_poll(struct apple_mbox *mbox);
+int apple_mbox_send(struct apple_mbox *mbox, struct apple_mbox_msg msg,
+ bool atomic);
+
+#endif
diff --git a/drivers/soc/apple/rtkit-crashlog.c b/drivers/soc/apple/rtkit-crashlog.c
index 732deed64660..8319e365110b 100644
--- a/drivers/soc/apple/rtkit-crashlog.c
+++ b/drivers/soc/apple/rtkit-crashlog.c
@@ -13,6 +13,17 @@
#define APPLE_RTKIT_CRASHLOG_VERSION FOURCC('C', 'v', 'e', 'r')
#define APPLE_RTKIT_CRASHLOG_MBOX FOURCC('C', 'm', 'b', 'x')
#define APPLE_RTKIT_CRASHLOG_TIME FOURCC('C', 't', 'i', 'm')
+#define APPLE_RTKIT_CRASHLOG_REGS FOURCC('C', 'r', 'g', '8')
+
+/* For COMPILE_TEST on non-ARM64 architectures */
+#ifndef PSR_MODE_EL0t
+#define PSR_MODE_EL0t 0x00000000
+#define PSR_MODE_EL1t 0x00000004
+#define PSR_MODE_EL1h 0x00000005
+#define PSR_MODE_EL2t 0x00000008
+#define PSR_MODE_EL2h 0x00000009
+#define PSR_MODE_MASK 0x0000000f
+#endif
struct apple_rtkit_crashlog_header {
u32 fourcc;
@@ -31,6 +42,24 @@ struct apple_rtkit_crashlog_mbox_entry {
};
static_assert(sizeof(struct apple_rtkit_crashlog_mbox_entry) == 0x18);
+struct apple_rtkit_crashlog_regs {
+ u32 unk_0;
+ u32 unk_4;
+ u64 regs[31];
+ u64 sp;
+ u64 pc;
+ u64 psr;
+ u64 cpacr;
+ u64 fpsr;
+ u64 fpcr;
+ u64 unk[64];
+ u64 far;
+ u64 unk_X;
+ u64 esr;
+ u64 unk_Z;
+} __packed;
+static_assert(sizeof(struct apple_rtkit_crashlog_regs) == 0x350);
+
static void apple_rtkit_crashlog_dump_str(struct apple_rtkit *rtk, u8 *bfr,
size_t size)
{
@@ -94,6 +123,66 @@ static void apple_rtkit_crashlog_dump_mailbox(struct apple_rtkit *rtk, u8 *bfr,
}
}
+static void apple_rtkit_crashlog_dump_regs(struct apple_rtkit *rtk, u8 *bfr,
+ size_t size)
+{
+ struct apple_rtkit_crashlog_regs *regs;
+ const char *el;
+ int i;
+
+ if (size < sizeof(*regs)) {
+ dev_warn(rtk->dev, "RTKit: Regs section too small: 0x%zx", size);
+ return;
+ }
+
+ regs = (struct apple_rtkit_crashlog_regs *)bfr;
+
+ switch (regs->psr & PSR_MODE_MASK) {
+ case PSR_MODE_EL0t:
+ el = "EL0t";
+ break;
+ case PSR_MODE_EL1t:
+ el = "EL1t";
+ break;
+ case PSR_MODE_EL1h:
+ el = "EL1h";
+ break;
+ case PSR_MODE_EL2t:
+ el = "EL2t";
+ break;
+ case PSR_MODE_EL2h:
+ el = "EL2h";
+ break;
+ default:
+ el = "unknown";
+ break;
+ }
+
+ dev_warn(rtk->dev, "RTKit: Exception dump:");
+ dev_warn(rtk->dev, " == Exception taken from %s ==", el);
+ dev_warn(rtk->dev, " PSR = 0x%llx", regs->psr);
+ dev_warn(rtk->dev, " PC = 0x%llx\n", regs->pc);
+ dev_warn(rtk->dev, " ESR = 0x%llx\n", regs->esr);
+ dev_warn(rtk->dev, " FAR = 0x%llx\n", regs->far);
+ dev_warn(rtk->dev, " SP = 0x%llx\n", regs->sp);
+ dev_warn(rtk->dev, "\n");
+
+ for (i = 0; i < 31; i += 4) {
+ if (i < 28)
+ dev_warn(rtk->dev,
+ " x%02d-x%02d = %016llx %016llx %016llx %016llx\n",
+ i, i + 3,
+ regs->regs[i], regs->regs[i + 1],
+ regs->regs[i + 2], regs->regs[i + 3]);
+ else
+ dev_warn(rtk->dev,
+ " x%02d-x%02d = %016llx %016llx %016llx\n", i, i + 3,
+ regs->regs[i], regs->regs[i + 1], regs->regs[i + 2]);
+ }
+
+ dev_warn(rtk->dev, "\n");
+}
+
void apple_rtkit_crashlog_dump(struct apple_rtkit *rtk, u8 *bfr, size_t size)
{
size_t offset;
@@ -140,6 +229,10 @@ void apple_rtkit_crashlog_dump(struct apple_rtkit *rtk, u8 *bfr, size_t size)
apple_rtkit_crashlog_dump_time(rtk, bfr + offset + 16,
section_size);
break;
+ case APPLE_RTKIT_CRASHLOG_REGS:
+ apple_rtkit_crashlog_dump_regs(rtk, bfr + offset + 16,
+ section_size);
+ break;
default:
dev_warn(rtk->dev,
"RTKit: Unknown crashlog section: %x",
diff --git a/drivers/soc/apple/rtkit-internal.h b/drivers/soc/apple/rtkit-internal.h
index 24bd619ec5e4..b8d5244678f0 100644
--- a/drivers/soc/apple/rtkit-internal.h
+++ b/drivers/soc/apple/rtkit-internal.h
@@ -7,18 +7,17 @@
#ifndef _APPLE_RTKIT_INTERAL_H
#define _APPLE_RTKIT_INTERAL_H
-#include <linux/apple-mailbox.h>
#include <linux/bitfield.h>
#include <linux/bitmap.h>
#include <linux/completion.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/kernel.h>
-#include <linux/mailbox_client.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/soc/apple/rtkit.h>
#include <linux/workqueue.h>
+#include "mailbox.h"
#define APPLE_RTKIT_APP_ENDPOINT_START 0x20
#define APPLE_RTKIT_MAX_ENDPOINTS 0x100
@@ -28,10 +27,7 @@ struct apple_rtkit {
const struct apple_rtkit_ops *ops;
struct device *dev;
- const char *mbox_name;
- int mbox_idx;
- struct mbox_client mbox_cl;
- struct mbox_chan *mbox_chan;
+ struct apple_mbox *mbox;
struct completion epmap_completion;
struct completion iop_pwr_ack_completion;
@@ -48,6 +44,7 @@ struct apple_rtkit {
struct apple_rtkit_shmem ioreport_buffer;
struct apple_rtkit_shmem crashlog_buffer;
+ struct apple_rtkit_shmem oslog_buffer;
struct apple_rtkit_shmem syslog_buffer;
char *syslog_msg_buffer;
diff --git a/drivers/soc/apple/rtkit.c b/drivers/soc/apple/rtkit.c
index 8ec74d7539eb..b8d4da147d23 100644
--- a/drivers/soc/apple/rtkit.c
+++ b/drivers/soc/apple/rtkit.c
@@ -9,8 +9,10 @@
enum {
APPLE_RTKIT_PWR_STATE_OFF = 0x00, /* power off, cannot be restarted */
APPLE_RTKIT_PWR_STATE_SLEEP = 0x01, /* sleeping, can be restarted */
+ APPLE_RTKIT_PWR_STATE_IDLE = 0x201, /* sleeping, retain state */
APPLE_RTKIT_PWR_STATE_QUIESCED = 0x10, /* running but no communication */
APPLE_RTKIT_PWR_STATE_ON = 0x20, /* normal operating state */
+ APPLE_RTKIT_PWR_STATE_INIT = 0x220, /* init after starting the coproc */
};
enum {
@@ -54,7 +56,7 @@ enum {
#define APPLE_RTKIT_BUFFER_REQUEST 1
#define APPLE_RTKIT_BUFFER_REQUEST_SIZE GENMASK_ULL(51, 44)
-#define APPLE_RTKIT_BUFFER_REQUEST_IOVA GENMASK_ULL(41, 0)
+#define APPLE_RTKIT_BUFFER_REQUEST_IOVA GENMASK_ULL(43, 0)
#define APPLE_RTKIT_SYSLOG_TYPE GENMASK_ULL(59, 52)
@@ -65,17 +67,13 @@ enum {
#define APPLE_RTKIT_SYSLOG_MSG_SIZE GENMASK_ULL(31, 24)
#define APPLE_RTKIT_OSLOG_TYPE GENMASK_ULL(63, 56)
-#define APPLE_RTKIT_OSLOG_INIT 1
-#define APPLE_RTKIT_OSLOG_ACK 3
+#define APPLE_RTKIT_OSLOG_BUFFER_REQUEST 1
+#define APPLE_RTKIT_OSLOG_SIZE GENMASK_ULL(55, 36)
+#define APPLE_RTKIT_OSLOG_IOVA GENMASK_ULL(35, 0)
#define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11
#define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12
-struct apple_rtkit_msg {
- struct completion *completion;
- struct apple_mbox_msg mbox_msg;
-};
-
struct apple_rtkit_rx_work {
struct apple_rtkit *rtk;
u8 ep;
@@ -101,12 +99,19 @@ bool apple_rtkit_is_crashed(struct apple_rtkit *rtk)
}
EXPORT_SYMBOL_GPL(apple_rtkit_is_crashed);
-static void apple_rtkit_management_send(struct apple_rtkit *rtk, u8 type,
+static int apple_rtkit_management_send(struct apple_rtkit *rtk, u8 type,
u64 msg)
{
+ int ret;
+
msg &= ~APPLE_RTKIT_MGMT_TYPE;
msg |= FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, type);
- apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_MGMT, msg, NULL, false);
+ ret = apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_MGMT, msg, NULL, false);
+
+ if (ret)
+ dev_err(rtk->dev, "RTKit: Failed to send management message: %d\n", ret);
+
+ return ret;
}
static void apple_rtkit_management_rx_hello(struct apple_rtkit *rtk, u64 msg)
@@ -255,21 +260,26 @@ static int apple_rtkit_common_rx_get_buffer(struct apple_rtkit *rtk,
struct apple_rtkit_shmem *buffer,
u8 ep, u64 msg)
{
- size_t n_4kpages = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg);
u64 reply;
int err;
+ /* The different size vs. IOVA shifts look odd but are indeed correct this way */
+ if (ep == APPLE_RTKIT_EP_OSLOG) {
+ buffer->size = FIELD_GET(APPLE_RTKIT_OSLOG_SIZE, msg);
+ buffer->iova = FIELD_GET(APPLE_RTKIT_OSLOG_IOVA, msg) << 12;
+ } else {
+ buffer->size = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg) << 12;
+ buffer->iova = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg);
+ }
+
buffer->buffer = NULL;
buffer->iomem = NULL;
buffer->is_mapped = false;
- buffer->iova = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg);
- buffer->size = n_4kpages << 12;
dev_dbg(rtk->dev, "RTKit: buffer request for 0x%zx bytes at %pad\n",
buffer->size, &buffer->iova);
- if (buffer->iova &&
- (!rtk->ops->shmem_setup || !rtk->ops->shmem_destroy)) {
+ if (buffer->iova && !rtk->ops->shmem_setup) {
err = -EINVAL;
goto error;
}
@@ -288,17 +298,30 @@ static int apple_rtkit_common_rx_get_buffer(struct apple_rtkit *rtk,
}
if (!buffer->is_mapped) {
- reply = FIELD_PREP(APPLE_RTKIT_SYSLOG_TYPE,
- APPLE_RTKIT_BUFFER_REQUEST);
- reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, n_4kpages);
- reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA,
- buffer->iova);
+ /* oslog uses different fields and needs a shifted IOVA instead of size */
+ if (ep == APPLE_RTKIT_EP_OSLOG) {
+ reply = FIELD_PREP(APPLE_RTKIT_OSLOG_TYPE,
+ APPLE_RTKIT_OSLOG_BUFFER_REQUEST);
+ reply |= FIELD_PREP(APPLE_RTKIT_OSLOG_SIZE, buffer->size);
+ reply |= FIELD_PREP(APPLE_RTKIT_OSLOG_IOVA,
+ buffer->iova >> 12);
+ } else {
+ reply = FIELD_PREP(APPLE_RTKIT_SYSLOG_TYPE,
+ APPLE_RTKIT_BUFFER_REQUEST);
+ reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE,
+ buffer->size >> 12);
+ reply |= FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA,
+ buffer->iova);
+ }
apple_rtkit_send_message(rtk, ep, reply, NULL, false);
}
return 0;
error:
+ dev_err(rtk->dev, "RTKit: failed buffer request for 0x%zx bytes (%d)\n",
+ buffer->size, err);
+
buffer->buffer = NULL;
buffer->iomem = NULL;
buffer->iova = 0;
@@ -364,7 +387,6 @@ static void apple_rtkit_crashlog_rx(struct apple_rtkit *rtk, u64 msg)
apple_rtkit_memcpy(rtk, bfr, &rtk->crashlog_buffer, 0,
rtk->crashlog_buffer.size);
apple_rtkit_crashlog_dump(rtk, bfr, rtk->crashlog_buffer.size);
- kfree(bfr);
} else {
dev_err(rtk->dev,
"RTKit: Couldn't allocate crashlog shadow buffer\n");
@@ -372,7 +394,9 @@ static void apple_rtkit_crashlog_rx(struct apple_rtkit *rtk, u64 msg)
rtk->crashed = true;
if (rtk->ops->crashed)
- rtk->ops->crashed(rtk->cookie);
+ rtk->ops->crashed(rtk->cookie, bfr, rtk->crashlog_buffer.size);
+
+ kfree(bfr);
}
static void apple_rtkit_ioreport_rx(struct apple_rtkit *rtk, u64 msg)
@@ -408,11 +432,17 @@ static void apple_rtkit_syslog_rx_init(struct apple_rtkit *rtk, u64 msg)
rtk->syslog_n_entries, rtk->syslog_msg_size);
}
+static bool should_crop_syslog_char(char c)
+{
+ return c == '\n' || c == '\r' || c == ' ' || c == '\0';
+}
+
static void apple_rtkit_syslog_rx_log(struct apple_rtkit *rtk, u64 msg)
{
u8 idx = msg & 0xff;
char log_context[24];
size_t entry_size = 0x20 + rtk->syslog_msg_size;
+ int msglen;
if (!rtk->syslog_msg_buffer) {
dev_warn(
@@ -445,7 +475,13 @@ static void apple_rtkit_syslog_rx_log(struct apple_rtkit *rtk, u64 msg)
rtk->syslog_msg_size);
log_context[sizeof(log_context) - 1] = 0;
- rtk->syslog_msg_buffer[rtk->syslog_msg_size - 1] = 0;
+
+ msglen = strnlen(rtk->syslog_msg_buffer, rtk->syslog_msg_size - 1);
+ while (msglen > 0 &&
+ should_crop_syslog_char(rtk->syslog_msg_buffer[msglen - 1]))
+ msglen--;
+
+ rtk->syslog_msg_buffer[msglen] = 0;
dev_info(rtk->dev, "RTKit: syslog message: %s: %s\n", log_context,
rtk->syslog_msg_buffer);
@@ -474,25 +510,18 @@ static void apple_rtkit_syslog_rx(struct apple_rtkit *rtk, u64 msg)
}
}
-static void apple_rtkit_oslog_rx_init(struct apple_rtkit *rtk, u64 msg)
-{
- u64 ack;
-
- dev_dbg(rtk->dev, "RTKit: oslog init: msg: 0x%llx\n", msg);
- ack = FIELD_PREP(APPLE_RTKIT_OSLOG_TYPE, APPLE_RTKIT_OSLOG_ACK);
- apple_rtkit_send_message(rtk, APPLE_RTKIT_EP_OSLOG, ack, NULL, false);
-}
-
static void apple_rtkit_oslog_rx(struct apple_rtkit *rtk, u64 msg)
{
u8 type = FIELD_GET(APPLE_RTKIT_OSLOG_TYPE, msg);
switch (type) {
- case APPLE_RTKIT_OSLOG_INIT:
- apple_rtkit_oslog_rx_init(rtk, msg);
+ case APPLE_RTKIT_OSLOG_BUFFER_REQUEST:
+ apple_rtkit_common_rx_get_buffer(rtk, &rtk->oslog_buffer,
+ APPLE_RTKIT_EP_OSLOG, msg);
break;
default:
- dev_warn(rtk->dev, "RTKit: Unknown oslog message: %llx\n", msg);
+ dev_warn(rtk->dev, "RTKit: Unknown oslog message: %llx\n",
+ msg);
}
}
@@ -537,12 +566,12 @@ static void apple_rtkit_rx_work(struct work_struct *work)
kfree(rtk_work);
}
-static void apple_rtkit_rx(struct mbox_client *cl, void *mssg)
+static void apple_rtkit_rx(struct apple_mbox *mbox, struct apple_mbox_msg msg,
+ void *cookie)
{
- struct apple_rtkit *rtk = container_of(cl, struct apple_rtkit, mbox_cl);
- struct apple_mbox_msg *msg = mssg;
+ struct apple_rtkit *rtk = cookie;
struct apple_rtkit_rx_work *work;
- u8 ep = msg->msg1;
+ u8 ep = msg.msg1;
/*
* The message was read from a MMIO FIFO and we have to make
@@ -558,7 +587,7 @@ static void apple_rtkit_rx(struct mbox_client *cl, void *mssg)
if (ep >= APPLE_RTKIT_APP_ENDPOINT_START &&
rtk->ops->recv_message_early &&
- rtk->ops->recv_message_early(rtk->cookie, ep, msg->msg0))
+ rtk->ops->recv_message_early(rtk->cookie, ep, msg.msg0))
return;
work = kzalloc(sizeof(*work), GFP_ATOMIC);
@@ -567,49 +596,31 @@ static void apple_rtkit_rx(struct mbox_client *cl, void *mssg)
work->rtk = rtk;
work->ep = ep;
- work->msg = msg->msg0;
+ work->msg = msg.msg0;
INIT_WORK(&work->work, apple_rtkit_rx_work);
queue_work(rtk->wq, &work->work);
}
-static void apple_rtkit_tx_done(struct mbox_client *cl, void *mssg, int r)
-{
- struct apple_rtkit_msg *msg =
- container_of(mssg, struct apple_rtkit_msg, mbox_msg);
-
- if (r == -ETIME)
- return;
-
- if (msg->completion)
- complete(msg->completion);
- kfree(msg);
-}
-
int apple_rtkit_send_message(struct apple_rtkit *rtk, u8 ep, u64 message,
struct completion *completion, bool atomic)
{
- struct apple_rtkit_msg *msg;
- int ret;
- gfp_t flags;
+ struct apple_mbox_msg msg = {
+ .msg0 = message,
+ .msg1 = ep,
+ };
- if (rtk->crashed)
+ if (rtk->crashed) {
+ dev_warn(rtk->dev,
+ "RTKit: Device is crashed, cannot send message\n");
return -EINVAL;
+ }
+
if (ep >= APPLE_RTKIT_APP_ENDPOINT_START &&
- !apple_rtkit_is_running(rtk))
+ !apple_rtkit_is_running(rtk)) {
+ dev_warn(rtk->dev,
+ "RTKit: Endpoint 0x%02x is not running, cannot send message\n", ep);
return -EINVAL;
-
- if (atomic)
- flags = GFP_ATOMIC;
- else
- flags = GFP_KERNEL;
-
- msg = kzalloc(sizeof(*msg), flags);
- if (!msg)
- return -ENOMEM;
-
- msg->mbox_msg.msg0 = message;
- msg->mbox_msg.msg1 = ep;
- msg->completion = completion;
+ }
/*
* The message will be sent with a MMIO write. We need the barrier
@@ -618,51 +629,13 @@ int apple_rtkit_send_message(struct apple_rtkit *rtk, u8 ep, u64 message,
*/
dma_wmb();
- ret = mbox_send_message(rtk->mbox_chan, &msg->mbox_msg);
- if (ret < 0) {
- kfree(msg);
- return ret;
- }
-
- return 0;
+ return apple_mbox_send(rtk->mbox, msg, atomic);
}
EXPORT_SYMBOL_GPL(apple_rtkit_send_message);
-int apple_rtkit_send_message_wait(struct apple_rtkit *rtk, u8 ep, u64 message,
- unsigned long timeout, bool atomic)
-{
- DECLARE_COMPLETION_ONSTACK(completion);
- int ret;
- long t;
-
- ret = apple_rtkit_send_message(rtk, ep, message, &completion, atomic);
- if (ret < 0)
- return ret;
-
- if (atomic) {
- ret = mbox_flush(rtk->mbox_chan, timeout);
- if (ret < 0)
- return ret;
-
- if (try_wait_for_completion(&completion))
- return 0;
-
- return -ETIME;
- } else {
- t = wait_for_completion_interruptible_timeout(
- &completion, msecs_to_jiffies(timeout));
- if (t < 0)
- return t;
- else if (t == 0)
- return -ETIME;
- return 0;
- }
-}
-EXPORT_SYMBOL_GPL(apple_rtkit_send_message_wait);
-
int apple_rtkit_poll(struct apple_rtkit *rtk)
{
- return mbox_client_peek_data(rtk->mbox_chan);
+ return apple_mbox_poll(rtk->mbox);
}
EXPORT_SYMBOL_GPL(apple_rtkit_poll);
@@ -684,21 +657,7 @@ int apple_rtkit_start_ep(struct apple_rtkit *rtk, u8 endpoint)
}
EXPORT_SYMBOL_GPL(apple_rtkit_start_ep);
-static int apple_rtkit_request_mbox_chan(struct apple_rtkit *rtk)
-{
- if (rtk->mbox_name)
- rtk->mbox_chan = mbox_request_channel_byname(&rtk->mbox_cl,
- rtk->mbox_name);
- else
- rtk->mbox_chan =
- mbox_request_channel(&rtk->mbox_cl, rtk->mbox_idx);
-
- if (IS_ERR(rtk->mbox_chan))
- return PTR_ERR(rtk->mbox_chan);
- return 0;
-}
-
-static struct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie,
+struct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie,
const char *mbox_name, int mbox_idx,
const struct apple_rtkit_ops *ops)
{
@@ -723,22 +682,27 @@ static struct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie,
bitmap_zero(rtk->endpoints, APPLE_RTKIT_MAX_ENDPOINTS);
set_bit(APPLE_RTKIT_EP_MGMT, rtk->endpoints);
- rtk->mbox_name = mbox_name;
- rtk->mbox_idx = mbox_idx;
- rtk->mbox_cl.dev = dev;
- rtk->mbox_cl.tx_block = false;
- rtk->mbox_cl.knows_txdone = false;
- rtk->mbox_cl.rx_callback = &apple_rtkit_rx;
- rtk->mbox_cl.tx_done = &apple_rtkit_tx_done;
+ if (mbox_name)
+ rtk->mbox = apple_mbox_get_byname(dev, mbox_name);
+ else
+ rtk->mbox = apple_mbox_get(dev, mbox_idx);
+
+ if (IS_ERR(rtk->mbox)) {
+ ret = PTR_ERR(rtk->mbox);
+ goto free_rtk;
+ }
+
+ rtk->mbox->rx = apple_rtkit_rx;
+ rtk->mbox->cookie = rtk;
- rtk->wq = alloc_ordered_workqueue("rtkit-%s", WQ_MEM_RECLAIM,
+ rtk->wq = alloc_ordered_workqueue("rtkit-%s", WQ_HIGHPRI | WQ_MEM_RECLAIM,
dev_name(rtk->dev));
if (!rtk->wq) {
ret = -ENOMEM;
goto free_rtk;
}
- ret = apple_rtkit_request_mbox_chan(rtk);
+ ret = apple_mbox_start(rtk->mbox);
if (ret)
goto destroy_wq;
@@ -750,6 +714,7 @@ free_rtk:
kfree(rtk);
return ERR_PTR(ret);
}
+EXPORT_SYMBOL_GPL(apple_rtkit_init);
static int apple_rtkit_wait_for_completion(struct completion *c)
{
@@ -768,11 +733,12 @@ static int apple_rtkit_wait_for_completion(struct completion *c)
int apple_rtkit_reinit(struct apple_rtkit *rtk)
{
/* make sure we don't handle any messages while reinitializing */
- mbox_free_channel(rtk->mbox_chan);
+ apple_mbox_stop(rtk->mbox);
flush_workqueue(rtk->wq);
apple_rtkit_free_buffer(rtk, &rtk->ioreport_buffer);
apple_rtkit_free_buffer(rtk, &rtk->crashlog_buffer);
+ apple_rtkit_free_buffer(rtk, &rtk->oslog_buffer);
apple_rtkit_free_buffer(rtk, &rtk->syslog_buffer);
kfree(rtk->syslog_msg_buffer);
@@ -792,7 +758,7 @@ int apple_rtkit_reinit(struct apple_rtkit *rtk)
rtk->iop_power_state = APPLE_RTKIT_PWR_STATE_OFF;
rtk->ap_power_state = APPLE_RTKIT_PWR_STATE_OFF;
- return apple_rtkit_request_mbox_chan(rtk);
+ return apple_mbox_start(rtk->mbox);
}
EXPORT_SYMBOL_GPL(apple_rtkit_reinit);
@@ -805,8 +771,10 @@ static int apple_rtkit_set_ap_power_state(struct apple_rtkit *rtk,
reinit_completion(&rtk->ap_pwr_ack_completion);
msg = FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, state);
- apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_SET_AP_PWR_STATE,
- msg);
+ ret = apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_SET_AP_PWR_STATE,
+ msg);
+ if (ret)
+ return ret;
ret = apple_rtkit_wait_for_completion(&rtk->ap_pwr_ack_completion);
if (ret)
@@ -826,8 +794,10 @@ static int apple_rtkit_set_iop_power_state(struct apple_rtkit *rtk,
reinit_completion(&rtk->iop_pwr_ack_completion);
msg = FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, state);
- apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE,
- msg);
+ ret = apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE,
+ msg);
+ if (ret)
+ return ret;
ret = apple_rtkit_wait_for_completion(&rtk->iop_pwr_ack_completion);
if (ret)
@@ -881,6 +851,26 @@ int apple_rtkit_shutdown(struct apple_rtkit *rtk)
}
EXPORT_SYMBOL_GPL(apple_rtkit_shutdown);
+int apple_rtkit_idle(struct apple_rtkit *rtk)
+{
+ int ret;
+
+ /* if OFF is used here the co-processor will not wake up again */
+ ret = apple_rtkit_set_ap_power_state(rtk,
+ APPLE_RTKIT_PWR_STATE_IDLE);
+ if (ret)
+ return ret;
+
+ ret = apple_rtkit_set_iop_power_state(rtk, APPLE_RTKIT_PWR_STATE_IDLE);
+ if (ret)
+ return ret;
+
+ rtk->iop_power_state = APPLE_RTKIT_PWR_STATE_IDLE;
+ rtk->ap_power_state = APPLE_RTKIT_PWR_STATE_IDLE;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(apple_rtkit_idle);
+
int apple_rtkit_quiesce(struct apple_rtkit *rtk)
{
int ret;
@@ -908,6 +898,7 @@ EXPORT_SYMBOL_GPL(apple_rtkit_quiesce);
int apple_rtkit_wake(struct apple_rtkit *rtk)
{
u64 msg;
+ int ret;
if (apple_rtkit_is_running(rtk))
return -EINVAL;
@@ -918,28 +909,35 @@ int apple_rtkit_wake(struct apple_rtkit *rtk)
* Use open-coded apple_rtkit_set_iop_power_state since apple_rtkit_boot
* will wait for the completion anyway.
*/
- msg = FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, APPLE_RTKIT_PWR_STATE_ON);
- apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE,
- msg);
+ msg = FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, APPLE_RTKIT_PWR_STATE_INIT);
+ ret = apple_rtkit_management_send(rtk, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE,
+ msg);
+ if (ret)
+ return ret;
return apple_rtkit_boot(rtk);
}
EXPORT_SYMBOL_GPL(apple_rtkit_wake);
-static void apple_rtkit_free(void *data)
+void apple_rtkit_free(struct apple_rtkit *rtk)
{
- struct apple_rtkit *rtk = data;
-
- mbox_free_channel(rtk->mbox_chan);
+ apple_mbox_stop(rtk->mbox);
destroy_workqueue(rtk->wq);
apple_rtkit_free_buffer(rtk, &rtk->ioreport_buffer);
apple_rtkit_free_buffer(rtk, &rtk->crashlog_buffer);
+ apple_rtkit_free_buffer(rtk, &rtk->oslog_buffer);
apple_rtkit_free_buffer(rtk, &rtk->syslog_buffer);
kfree(rtk->syslog_msg_buffer);
kfree(rtk);
}
+EXPORT_SYMBOL_GPL(apple_rtkit_free);
+
+static void apple_rtkit_free_wrapper(void *data)
+{
+ apple_rtkit_free(data);
+}
struct apple_rtkit *devm_apple_rtkit_init(struct device *dev, void *cookie,
const char *mbox_name, int mbox_idx,
@@ -952,7 +950,7 @@ struct apple_rtkit *devm_apple_rtkit_init(struct device *dev, void *cookie,
if (IS_ERR(rtk))
return rtk;
- ret = devm_add_action_or_reset(dev, apple_rtkit_free, rtk);
+ ret = devm_add_action_or_reset(dev, apple_rtkit_free_wrapper, rtk);
if (ret)
return ERR_PTR(ret);
diff --git a/drivers/soc/apple/sart.c b/drivers/soc/apple/sart.c
index afa111736899..9eaf3febb382 100644
--- a/drivers/soc/apple/sart.c
+++ b/drivers/soc/apple/sart.c
@@ -25,8 +25,17 @@
#define APPLE_SART_MAX_ENTRIES 16
-/* This is probably a bitfield but the exact meaning of each bit is unknown. */
-#define APPLE_SART_FLAGS_ALLOW 0xff
+/* SARTv0 registers */
+#define APPLE_SART0_CONFIG(idx) (0x00 + 4 * (idx))
+#define APPLE_SART0_CONFIG_FLAGS GENMASK(28, 24)
+#define APPLE_SART0_CONFIG_SIZE GENMASK(18, 0)
+#define APPLE_SART0_CONFIG_SIZE_SHIFT 12
+#define APPLE_SART0_CONFIG_SIZE_MAX GENMASK(18, 0)
+
+#define APPLE_SART0_PADDR(idx) (0x40 + 4 * (idx))
+#define APPLE_SART0_PADDR_SHIFT 12
+
+#define APPLE_SART0_FLAGS_ALLOW 0xf
/* SARTv2 registers */
#define APPLE_SART2_CONFIG(idx) (0x00 + 4 * (idx))
@@ -38,6 +47,8 @@
#define APPLE_SART2_PADDR(idx) (0x40 + 4 * (idx))
#define APPLE_SART2_PADDR_SHIFT 12
+#define APPLE_SART2_FLAGS_ALLOW 0xff
+
/* SARTv3 registers */
#define APPLE_SART3_CONFIG(idx) (0x00 + 4 * (idx))
@@ -48,11 +59,15 @@
#define APPLE_SART3_SIZE_SHIFT 12
#define APPLE_SART3_SIZE_MAX GENMASK(29, 0)
+#define APPLE_SART3_FLAGS_ALLOW 0xff
+
struct apple_sart_ops {
void (*get_entry)(struct apple_sart *sart, int index, u8 *flags,
phys_addr_t *paddr, size_t *size);
void (*set_entry)(struct apple_sart *sart, int index, u8 flags,
phys_addr_t paddr_shifted, size_t size_shifted);
+ /* This is probably a bitfield but the exact meaning of each bit is unknown. */
+ unsigned int flags_allow;
unsigned int size_shift;
unsigned int paddr_shift;
size_t size_max;
@@ -68,6 +83,39 @@ struct apple_sart {
unsigned long used_entries;
};
+static void sart0_get_entry(struct apple_sart *sart, int index, u8 *flags,
+ phys_addr_t *paddr, size_t *size)
+{
+ u32 cfg = readl(sart->regs + APPLE_SART0_CONFIG(index));
+ phys_addr_t paddr_ = readl(sart->regs + APPLE_SART0_PADDR(index));
+ size_t size_ = FIELD_GET(APPLE_SART0_CONFIG_SIZE, cfg);
+
+ *flags = FIELD_GET(APPLE_SART0_CONFIG_FLAGS, cfg);
+ *size = size_ << APPLE_SART0_CONFIG_SIZE_SHIFT;
+ *paddr = paddr_ << APPLE_SART0_PADDR_SHIFT;
+}
+
+static void sart0_set_entry(struct apple_sart *sart, int index, u8 flags,
+ phys_addr_t paddr_shifted, size_t size_shifted)
+{
+ u32 cfg;
+
+ cfg = FIELD_PREP(APPLE_SART0_CONFIG_FLAGS, flags);
+ cfg |= FIELD_PREP(APPLE_SART0_CONFIG_SIZE, size_shifted);
+
+ writel(paddr_shifted, sart->regs + APPLE_SART0_PADDR(index));
+ writel(cfg, sart->regs + APPLE_SART0_CONFIG(index));
+}
+
+static struct apple_sart_ops sart_ops_v0 = {
+ .get_entry = sart0_get_entry,
+ .set_entry = sart0_set_entry,
+ .flags_allow = APPLE_SART0_FLAGS_ALLOW,
+ .size_shift = APPLE_SART0_CONFIG_SIZE_SHIFT,
+ .paddr_shift = APPLE_SART0_PADDR_SHIFT,
+ .size_max = APPLE_SART0_CONFIG_SIZE_MAX,
+};
+
static void sart2_get_entry(struct apple_sart *sart, int index, u8 *flags,
phys_addr_t *paddr, size_t *size)
{
@@ -95,6 +143,7 @@ static void sart2_set_entry(struct apple_sart *sart, int index, u8 flags,
static struct apple_sart_ops sart_ops_v2 = {
.get_entry = sart2_get_entry,
.set_entry = sart2_set_entry,
+ .flags_allow = APPLE_SART2_FLAGS_ALLOW,
.size_shift = APPLE_SART2_CONFIG_SIZE_SHIFT,
.paddr_shift = APPLE_SART2_PADDR_SHIFT,
.size_max = APPLE_SART2_CONFIG_SIZE_MAX,
@@ -122,6 +171,7 @@ static void sart3_set_entry(struct apple_sart *sart, int index, u8 flags,
static struct apple_sart_ops sart_ops_v3 = {
.get_entry = sart3_get_entry,
.set_entry = sart3_set_entry,
+ .flags_allow = APPLE_SART3_FLAGS_ALLOW,
.size_shift = APPLE_SART3_SIZE_SHIFT,
.paddr_shift = APPLE_SART3_PADDR_SHIFT,
.size_max = APPLE_SART3_SIZE_MAX,
@@ -164,17 +214,11 @@ static int apple_sart_probe(struct platform_device *pdev)
return 0;
}
-static void apple_sart_put_device(void *dev)
-{
- put_device(dev);
-}
-
struct apple_sart *devm_apple_sart_get(struct device *dev)
{
struct device_node *sart_node;
struct platform_device *sart_pdev;
struct apple_sart *sart;
- int ret;
sart_node = of_parse_phandle(dev->of_node, "apple,sart", 0);
if (!sart_node)
@@ -192,14 +236,11 @@ struct apple_sart *devm_apple_sart_get(struct device *dev)
return ERR_PTR(-EPROBE_DEFER);
}
- ret = devm_add_action_or_reset(dev, apple_sart_put_device,
- &sart_pdev->dev);
- if (ret)
- return ERR_PTR(ret);
-
device_link_add(dev, &sart_pdev->dev,
DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_SUPPLIER);
+ put_device(&sart_pdev->dev);
+
return sart;
}
EXPORT_SYMBOL_GPL(devm_apple_sart_get);
@@ -233,7 +274,7 @@ int apple_sart_add_allowed_region(struct apple_sart *sart, phys_addr_t paddr,
if (test_and_set_bit(i, &sart->used_entries))
continue;
- ret = sart_set_entry(sart, i, APPLE_SART_FLAGS_ALLOW, paddr,
+ ret = sart_set_entry(sart, i, sart->ops->flags_allow, paddr,
size);
if (ret) {
dev_dbg(sart->dev,
@@ -314,6 +355,10 @@ static const struct of_device_id apple_sart_of_match[] = {
.compatible = "apple,t8103-sart",
.data = &sart_ops_v2,
},
+ {
+ .compatible = "apple,t8015-sart",
+ .data = &sart_ops_v0,
+ },
{}
};
MODULE_DEVICE_TABLE(of, apple_sart_of_match);
diff --git a/drivers/soc/aspeed/aspeed-lpc-ctrl.c b/drivers/soc/aspeed/aspeed-lpc-ctrl.c
index 258894ed234b..b7dbb12bd095 100644
--- a/drivers/soc/aspeed/aspeed-lpc-ctrl.c
+++ b/drivers/soc/aspeed/aspeed-lpc-ctrl.c
@@ -10,6 +10,7 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/of_address.h>
+#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/poll.h>
#include <linux/regmap.h>
@@ -254,17 +255,8 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, lpc_ctrl);
/* If memory-region is described in device tree then store */
- node = of_parse_phandle(dev->of_node, "memory-region", 0);
- if (!node) {
- dev_dbg(dev, "Didn't find reserved memory\n");
- } else {
- rc = of_address_to_resource(node, 0, &resm);
- of_node_put(node);
- if (rc) {
- dev_err(dev, "Couldn't address to resource for reserved memory\n");
- return -ENXIO;
- }
-
+ rc = of_reserved_mem_region_to_resource(dev->of_node, 0, &resm);
+ if (!rc) {
lpc_ctrl->mem_size = resource_size(&resm);
lpc_ctrl->mem_base = resm.start;
@@ -332,14 +324,12 @@ err:
return rc;
}
-static int aspeed_lpc_ctrl_remove(struct platform_device *pdev)
+static void aspeed_lpc_ctrl_remove(struct platform_device *pdev)
{
struct aspeed_lpc_ctrl *lpc_ctrl = dev_get_drvdata(&pdev->dev);
misc_deregister(&lpc_ctrl->miscdev);
clk_disable_unprepare(lpc_ctrl->clk);
-
- return 0;
}
static const struct of_device_id aspeed_lpc_ctrl_match[] = {
diff --git a/drivers/soc/aspeed/aspeed-lpc-snoop.c b/drivers/soc/aspeed/aspeed-lpc-snoop.c
index eceeaf8dfbeb..b03310c0830d 100644
--- a/drivers/soc/aspeed/aspeed-lpc-snoop.c
+++ b/drivers/soc/aspeed/aspeed-lpc-snoop.c
@@ -12,6 +12,7 @@
#include <linux/bitops.h>
#include <linux/clk.h>
+#include <linux/dev_printk.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/kfifo.h>
@@ -19,14 +20,12 @@
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/poll.h>
#include <linux/regmap.h>
#define DEVICE_NAME "aspeed-lpc-snoop"
-#define NUM_SNOOP_CHANNELS 2
#define SNOOP_FIFO_SIZE 2048
#define HICR5 0x80
@@ -58,7 +57,23 @@ struct aspeed_lpc_snoop_model_data {
unsigned int has_hicrb_ensnp;
};
+enum aspeed_lpc_snoop_index {
+ ASPEED_LPC_SNOOP_INDEX_0 = 0,
+ ASPEED_LPC_SNOOP_INDEX_1 = 1,
+ ASPEED_LPC_SNOOP_INDEX_MAX = ASPEED_LPC_SNOOP_INDEX_1,
+};
+
+struct aspeed_lpc_snoop_channel_cfg {
+ enum aspeed_lpc_snoop_index index;
+ u32 hicr5_en;
+ u32 snpwadr_mask;
+ u32 snpwadr_shift;
+ u32 hicrb_en;
+};
+
struct aspeed_lpc_snoop_channel {
+ const struct aspeed_lpc_snoop_channel_cfg *cfg;
+ bool enabled;
struct kfifo fifo;
wait_queue_head_t wq;
struct miscdevice miscdev;
@@ -68,7 +83,24 @@ struct aspeed_lpc_snoop {
struct regmap *regmap;
int irq;
struct clk *clk;
- struct aspeed_lpc_snoop_channel chan[NUM_SNOOP_CHANNELS];
+ struct aspeed_lpc_snoop_channel chan[ASPEED_LPC_SNOOP_INDEX_MAX + 1];
+};
+
+static const struct aspeed_lpc_snoop_channel_cfg channel_cfgs[ASPEED_LPC_SNOOP_INDEX_MAX + 1] = {
+ {
+ .index = ASPEED_LPC_SNOOP_INDEX_0,
+ .hicr5_en = HICR5_EN_SNP0W | HICR5_ENINT_SNP0W,
+ .snpwadr_mask = SNPWADR_CH0_MASK,
+ .snpwadr_shift = SNPWADR_CH0_SHIFT,
+ .hicrb_en = HICRB_ENSNP0D,
+ },
+ {
+ .index = ASPEED_LPC_SNOOP_INDEX_1,
+ .hicr5_en = HICR5_EN_SNP1W | HICR5_ENINT_SNP1W,
+ .snpwadr_mask = SNPWADR_CH1_MASK,
+ .snpwadr_shift = SNPWADR_CH1_SHIFT,
+ .hicrb_en = HICRB_ENSNP1D,
+ },
};
static struct aspeed_lpc_snoop_channel *snoop_file_to_chan(struct file *file)
@@ -167,7 +199,7 @@ static int aspeed_lpc_snoop_config_irq(struct aspeed_lpc_snoop *lpc_snoop,
int rc;
lpc_snoop->irq = platform_get_irq(pdev, 0);
- if (!lpc_snoop->irq)
+ if (lpc_snoop->irq < 0)
return -ENODEV;
rc = devm_request_irq(dev, lpc_snoop->irq,
@@ -182,87 +214,88 @@ static int aspeed_lpc_snoop_config_irq(struct aspeed_lpc_snoop *lpc_snoop,
return 0;
}
-static int aspeed_lpc_enable_snoop(struct aspeed_lpc_snoop *lpc_snoop,
- struct device *dev,
- int channel, u16 lpc_port)
+__attribute__((nonnull))
+static int aspeed_lpc_enable_snoop(struct device *dev,
+ struct aspeed_lpc_snoop *lpc_snoop,
+ struct aspeed_lpc_snoop_channel *channel,
+ const struct aspeed_lpc_snoop_channel_cfg *cfg,
+ u16 lpc_port)
{
+ const struct aspeed_lpc_snoop_model_data *model_data;
int rc = 0;
- u32 hicr5_en, snpwadr_mask, snpwadr_shift, hicrb_en;
- const struct aspeed_lpc_snoop_model_data *model_data =
- of_device_get_match_data(dev);
-
- init_waitqueue_head(&lpc_snoop->chan[channel].wq);
- /* Create FIFO datastructure */
- rc = kfifo_alloc(&lpc_snoop->chan[channel].fifo,
- SNOOP_FIFO_SIZE, GFP_KERNEL);
+
+ if (WARN_ON(channel->enabled))
+ return -EBUSY;
+
+ init_waitqueue_head(&channel->wq);
+
+ channel->cfg = cfg;
+ channel->miscdev.minor = MISC_DYNAMIC_MINOR;
+ channel->miscdev.fops = &snoop_fops;
+ channel->miscdev.parent = dev;
+
+ channel->miscdev.name =
+ devm_kasprintf(dev, GFP_KERNEL, "%s%d", DEVICE_NAME, cfg->index);
+ if (!channel->miscdev.name)
+ return -ENOMEM;
+
+ rc = kfifo_alloc(&channel->fifo, SNOOP_FIFO_SIZE, GFP_KERNEL);
if (rc)
return rc;
- lpc_snoop->chan[channel].miscdev.minor = MISC_DYNAMIC_MINOR;
- lpc_snoop->chan[channel].miscdev.name =
- devm_kasprintf(dev, GFP_KERNEL, "%s%d", DEVICE_NAME, channel);
- lpc_snoop->chan[channel].miscdev.fops = &snoop_fops;
- lpc_snoop->chan[channel].miscdev.parent = dev;
- rc = misc_register(&lpc_snoop->chan[channel].miscdev);
+ rc = misc_register(&channel->miscdev);
if (rc)
- return rc;
+ goto err_free_fifo;
/* Enable LPC snoop channel at requested port */
- switch (channel) {
- case 0:
- hicr5_en = HICR5_EN_SNP0W | HICR5_ENINT_SNP0W;
- snpwadr_mask = SNPWADR_CH0_MASK;
- snpwadr_shift = SNPWADR_CH0_SHIFT;
- hicrb_en = HICRB_ENSNP0D;
- break;
- case 1:
- hicr5_en = HICR5_EN_SNP1W | HICR5_ENINT_SNP1W;
- snpwadr_mask = SNPWADR_CH1_MASK;
- snpwadr_shift = SNPWADR_CH1_SHIFT;
- hicrb_en = HICRB_ENSNP1D;
- break;
- default:
- return -EINVAL;
- }
+ regmap_set_bits(lpc_snoop->regmap, HICR5, cfg->hicr5_en);
+ regmap_update_bits(lpc_snoop->regmap, SNPWADR, cfg->snpwadr_mask,
+ lpc_port << cfg->snpwadr_shift);
+
+ model_data = of_device_get_match_data(dev);
+ if (model_data && model_data->has_hicrb_ensnp)
+ regmap_set_bits(lpc_snoop->regmap, HICRB, cfg->hicrb_en);
- regmap_update_bits(lpc_snoop->regmap, HICR5, hicr5_en, hicr5_en);
- regmap_update_bits(lpc_snoop->regmap, SNPWADR, snpwadr_mask,
- lpc_port << snpwadr_shift);
- if (model_data->has_hicrb_ensnp)
- regmap_update_bits(lpc_snoop->regmap, HICRB,
- hicrb_en, hicrb_en);
+ channel->enabled = true;
+ return 0;
+
+err_free_fifo:
+ kfifo_free(&channel->fifo);
return rc;
}
+__attribute__((nonnull))
static void aspeed_lpc_disable_snoop(struct aspeed_lpc_snoop *lpc_snoop,
- int channel)
+ struct aspeed_lpc_snoop_channel *channel)
{
- switch (channel) {
- case 0:
- regmap_update_bits(lpc_snoop->regmap, HICR5,
- HICR5_EN_SNP0W | HICR5_ENINT_SNP0W,
- 0);
- break;
- case 1:
- regmap_update_bits(lpc_snoop->regmap, HICR5,
- HICR5_EN_SNP1W | HICR5_ENINT_SNP1W,
- 0);
- break;
- default:
+ if (!channel->enabled)
return;
- }
- kfifo_free(&lpc_snoop->chan[channel].fifo);
- misc_deregister(&lpc_snoop->chan[channel].miscdev);
+ /* Disable interrupts along with the device */
+ regmap_clear_bits(lpc_snoop->regmap, HICR5, channel->cfg->hicr5_en);
+
+ channel->enabled = false;
+ /* Consider improving safety wrt concurrent reader(s) */
+ misc_deregister(&channel->miscdev);
+ kfifo_free(&channel->fifo);
+}
+
+static void aspeed_lpc_snoop_remove(struct platform_device *pdev)
+{
+ struct aspeed_lpc_snoop *lpc_snoop = dev_get_drvdata(&pdev->dev);
+
+ /* Disable both snoop channels */
+ aspeed_lpc_disable_snoop(lpc_snoop, &lpc_snoop->chan[0]);
+ aspeed_lpc_disable_snoop(lpc_snoop, &lpc_snoop->chan[1]);
}
static int aspeed_lpc_snoop_probe(struct platform_device *pdev)
{
struct aspeed_lpc_snoop *lpc_snoop;
- struct device *dev;
struct device_node *np;
- u32 port;
+ struct device *dev;
+ int idx;
int rc;
dev = &pdev->dev;
@@ -280,69 +313,40 @@ static int aspeed_lpc_snoop_probe(struct platform_device *pdev)
}
lpc_snoop->regmap = syscon_node_to_regmap(np);
- if (IS_ERR(lpc_snoop->regmap)) {
- dev_err(dev, "Couldn't get regmap\n");
- return -ENODEV;
- }
+ if (IS_ERR(lpc_snoop->regmap))
+ return dev_err_probe(dev, PTR_ERR(lpc_snoop->regmap), "Couldn't get regmap\n");
dev_set_drvdata(&pdev->dev, lpc_snoop);
- rc = of_property_read_u32_index(dev->of_node, "snoop-ports", 0, &port);
- if (rc) {
- dev_err(dev, "no snoop ports configured\n");
- return -ENODEV;
- }
-
- lpc_snoop->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(lpc_snoop->clk)) {
- rc = PTR_ERR(lpc_snoop->clk);
- if (rc != -EPROBE_DEFER)
- dev_err(dev, "couldn't get clock\n");
- return rc;
- }
- rc = clk_prepare_enable(lpc_snoop->clk);
- if (rc) {
- dev_err(dev, "couldn't enable clock\n");
- return rc;
- }
+ lpc_snoop->clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(lpc_snoop->clk))
+ return dev_err_probe(dev, PTR_ERR(lpc_snoop->clk), "couldn't get clock");
rc = aspeed_lpc_snoop_config_irq(lpc_snoop, pdev);
if (rc)
- goto err;
-
- rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 0, port);
- if (rc)
- goto err;
-
- /* Configuration of 2nd snoop channel port is optional */
- if (of_property_read_u32_index(dev->of_node, "snoop-ports",
- 1, &port) == 0) {
- rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 1, port);
- if (rc) {
- aspeed_lpc_disable_snoop(lpc_snoop, 0);
- goto err;
- }
- }
-
- return 0;
+ return rc;
-err:
- clk_disable_unprepare(lpc_snoop->clk);
+ static_assert(ARRAY_SIZE(channel_cfgs) == ARRAY_SIZE(lpc_snoop->chan),
+ "Broken implementation assumption regarding cfg count");
+ for (idx = ASPEED_LPC_SNOOP_INDEX_0; idx <= ASPEED_LPC_SNOOP_INDEX_MAX; idx++) {
+ u32 port;
- return rc;
-}
+ rc = of_property_read_u32_index(dev->of_node, "snoop-ports", idx, &port);
+ if (rc)
+ break;
-static int aspeed_lpc_snoop_remove(struct platform_device *pdev)
-{
- struct aspeed_lpc_snoop *lpc_snoop = dev_get_drvdata(&pdev->dev);
+ rc = aspeed_lpc_enable_snoop(dev, lpc_snoop, &lpc_snoop->chan[idx],
+ &channel_cfgs[idx], port);
+ if (rc)
+ goto cleanup_channels;
+ }
- /* Disable both snoop channels */
- aspeed_lpc_disable_snoop(lpc_snoop, 0);
- aspeed_lpc_disable_snoop(lpc_snoop, 1);
+ return idx == ASPEED_LPC_SNOOP_INDEX_0 ? -ENODEV : 0;
- clk_disable_unprepare(lpc_snoop->clk);
+cleanup_channels:
+ aspeed_lpc_snoop_remove(pdev);
- return 0;
+ return rc;
}
static const struct aspeed_lpc_snoop_model_data ast2400_model_data = {
diff --git a/drivers/soc/aspeed/aspeed-p2a-ctrl.c b/drivers/soc/aspeed/aspeed-p2a-ctrl.c
index 20b5fb2a207c..3be2e1b1085b 100644
--- a/drivers/soc/aspeed/aspeed-p2a-ctrl.c
+++ b/drivers/soc/aspeed/aspeed-p2a-ctrl.c
@@ -18,8 +18,8 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -334,7 +334,6 @@ static int aspeed_p2a_ctrl_probe(struct platform_device *pdev)
struct aspeed_p2a_ctrl *misc_ctrl;
struct device *dev;
struct resource resm;
- struct device_node *node;
int rc = 0;
dev = &pdev->dev;
@@ -346,15 +345,8 @@ static int aspeed_p2a_ctrl_probe(struct platform_device *pdev)
mutex_init(&misc_ctrl->tracking);
/* optional. */
- node = of_parse_phandle(dev->of_node, "memory-region", 0);
- if (node) {
- rc = of_address_to_resource(node, 0, &resm);
- of_node_put(node);
- if (rc) {
- dev_err(dev, "Couldn't address to resource for reserved memory\n");
- return -ENODEV;
- }
-
+ rc = of_reserved_mem_region_to_resource(dev->of_node, 0, &resm);
+ if (!rc) {
misc_ctrl->mem_size = resource_size(&resm);
misc_ctrl->mem_base = resm.start;
}
@@ -383,13 +375,11 @@ static int aspeed_p2a_ctrl_probe(struct platform_device *pdev)
return rc;
}
-static int aspeed_p2a_ctrl_remove(struct platform_device *pdev)
+static void aspeed_p2a_ctrl_remove(struct platform_device *pdev)
{
struct aspeed_p2a_ctrl *p2a_ctrl = dev_get_drvdata(&pdev->dev);
misc_deregister(&p2a_ctrl->miscdev);
-
- return 0;
}
#define SCU2C_DRAM BIT(25)
diff --git a/drivers/soc/aspeed/aspeed-socinfo.c b/drivers/soc/aspeed/aspeed-socinfo.c
index 1ca140356a08..67e9ac3d08ec 100644
--- a/drivers/soc/aspeed/aspeed-socinfo.c
+++ b/drivers/soc/aspeed/aspeed-socinfo.c
@@ -27,6 +27,10 @@ static struct {
{ "AST2620", 0x05010203 },
{ "AST2605", 0x05030103 },
{ "AST2625", 0x05030403 },
+ /* AST2700 */
+ { "AST2750", 0x06000003 },
+ { "AST2700", 0x06000103 },
+ { "AST2720", 0x06000203 },
};
static const char *siliconid_to_name(u32 siliconid)
@@ -137,6 +141,7 @@ static int __init aspeed_socinfo_init(void)
soc_dev = soc_device_register(attrs);
if (IS_ERR(soc_dev)) {
+ kfree(attrs->machine);
kfree(attrs->soc_id);
kfree(attrs->serial_number);
kfree(attrs);
diff --git a/drivers/soc/aspeed/aspeed-uart-routing.c b/drivers/soc/aspeed/aspeed-uart-routing.c
index ef8b24fd1851..0191e36e66e1 100644
--- a/drivers/soc/aspeed/aspeed-uart-routing.c
+++ b/drivers/soc/aspeed/aspeed-uart-routing.c
@@ -5,8 +5,7 @@
*/
#include <linux/device.h>
#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/platform_device.h>
@@ -524,7 +523,7 @@ static ssize_t aspeed_uart_routing_store(struct device *dev,
struct aspeed_uart_routing_selector *sel = to_routing_selector(attr);
int val;
- val = match_string(sel->options, -1, buf);
+ val = __sysfs_match_string(sel->options, -1, buf);
if (val < 0) {
dev_err(dev, "invalid value \"%s\"\n", buf);
return -EINVAL;
@@ -566,14 +565,12 @@ static int aspeed_uart_routing_probe(struct platform_device *pdev)
return 0;
}
-static int aspeed_uart_routing_remove(struct platform_device *pdev)
+static void aspeed_uart_routing_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct aspeed_uart_routing *uart_routing = platform_get_drvdata(pdev);
sysfs_remove_group(&dev->kobj, uart_routing->attr_grp);
-
- return 0;
}
static const struct of_device_id aspeed_uart_routing_table[] = {
diff --git a/drivers/soc/atmel/sfr.c b/drivers/soc/atmel/sfr.c
index 0525eef49d1a..cc94ca1b494c 100644
--- a/drivers/soc/atmel/sfr.c
+++ b/drivers/soc/atmel/sfr.c
@@ -10,7 +10,6 @@
#include <linux/nvmem-provider.h>
#include <linux/random.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
diff --git a/drivers/soc/atmel/soc.c b/drivers/soc/atmel/soc.c
index dae8a2e0f745..09347bccdb1d 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,
@@ -223,6 +246,9 @@ static const struct at91_soc socs[] __initconst = {
"samv70q19", "samv7"),
#endif
#ifdef CONFIG_SOC_SAMA7
+ AT91_SOC(SAMA7D65_CIDR_MATCH, AT91_CIDR_MASK_SAMA7G5,
+ AT91_CIDR_VERSION_MASK_SAMA7G5, SAMA7D65_EXID_MATCH,
+ "sama7d65", "sama7d6"),
AT91_SOC(SAMA7G5_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
AT91_CIDR_VERSION_MASK_SAMA7G5, SAMA7G51_EXID_MATCH,
"sama7g51", "sama7g5"),
@@ -235,6 +261,15 @@ static const struct at91_soc socs[] __initconst = {
AT91_SOC(SAMA7G5_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
AT91_CIDR_VERSION_MASK_SAMA7G5, SAMA7G54_EXID_MATCH,
"sama7g54", "sama7g5"),
+ AT91_SOC(SAMA7G5_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
+ AT91_CIDR_VERSION_MASK_SAMA7G5, SAMA7G54_D1G_EXID_MATCH,
+ "SAMA7G54 1Gb DDR3L SiP", "sama7g5"),
+ AT91_SOC(SAMA7G5_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
+ AT91_CIDR_VERSION_MASK_SAMA7G5, SAMA7G54_D2G_EXID_MATCH,
+ "SAMA7G54 2Gb DDR3L SiP", "sama7g5"),
+ AT91_SOC(SAMA7G5_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
+ AT91_CIDR_VERSION_MASK_SAMA7G5, SAMA7G54_D4G_EXID_MATCH,
+ "SAMA7G54 4Gb DDR3L SiP", "sama7g5"),
#endif
{ /* sentinel */ },
};
@@ -273,6 +308,7 @@ static int __init at91_get_cidr_exid_from_chipid(u32 *cidr, u32 *exid)
void __iomem *regs;
static const struct of_device_id chipids[] = {
{ .compatible = "atmel,sama5d2-chipid" },
+ { .compatible = "microchip,sama7d65-chipid" },
{ .compatible = "microchip,sama7g5-chipid" },
{ },
};
@@ -361,13 +397,14 @@ static const struct of_device_id at91_soc_allowed_list[] __initconst = {
{ .compatible = "atmel,at91sam9", },
{ .compatible = "atmel,sama5", },
{ .compatible = "atmel,samv7", },
+ { .compatible = "microchip,sama7d65", },
{ .compatible = "microchip,sama7g5", },
{ }
};
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 2ecaa75b00f0..66a74017d9a3 100644
--- a/drivers/soc/atmel/soc.h
+++ b/drivers/soc/atmel/soc.h
@@ -44,6 +44,8 @@ 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 SAMA7D65_CIDR_MATCH 0x00262100
#define SAMA7G5_CIDR_MATCH 0x00162100
#define AT91SAM9M11_EXID_MATCH 0x00000001
@@ -66,10 +68,23 @@ 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 SAMA7D65_EXID_MATCH 0x00000080
+
#define SAMA7G51_EXID_MATCH 0x3
#define SAMA7G52_EXID_MATCH 0x2
#define SAMA7G53_EXID_MATCH 0x1
#define SAMA7G54_EXID_MATCH 0x0
+#define SAMA7G54_D1G_EXID_MATCH 0x00000018
+#define SAMA7G54_D2G_EXID_MATCH 0x00000020
+#define SAMA7G54_D4G_EXID_MATCH 0x00000028
#define AT91SAM9XE128_CIDR_MATCH 0x329973a0
#define AT91SAM9XE256_CIDR_MATCH 0x329a93a0
diff --git a/drivers/soc/bcm/Kconfig b/drivers/soc/bcm/Kconfig
index 24f92a6e882a..c921a22f6c11 100644
--- a/drivers/soc/bcm/Kconfig
+++ b/drivers/soc/bcm/Kconfig
@@ -1,39 +1,9 @@
# SPDX-License-Identifier: GPL-2.0-only
menu "Broadcom SoC drivers"
-config BCM2835_POWER
- bool "BCM2835 power domain driver"
- depends on ARCH_BCM2835 || (COMPILE_TEST && OF)
- default y if ARCH_BCM2835
- select PM_GENERIC_DOMAINS if PM
- select RESET_CONTROLLER
- help
- This enables support for the BCM2835 power domains and reset
- controller. Any usage of power domains by the Raspberry Pi
- firmware means that Linux usage of the same power domain
- must be accessed using the RASPBERRYPI_POWER driver
-
-config RASPBERRYPI_POWER
- bool "Raspberry Pi power domain driver"
- depends on ARCH_BCM2835 || (COMPILE_TEST && OF)
- depends on RASPBERRYPI_FIRMWARE=y
- select PM_GENERIC_DOMAINS if PM
- help
- This enables support for the RPi power domains which can be enabled
- or disabled via the RPi firmware.
-
-config SOC_BCM63XX
- bool "Broadcom 63xx SoC drivers"
- depends on BMIPS_GENERIC || COMPILE_TEST
- help
- Enables drivers for the Broadcom 63xx series of chips.
- Drivers can be enabled individually within this menu.
-
- If unsure, say N.
-
config SOC_BRCMSTB
bool "Broadcom STB SoC drivers"
- depends on ARM || ARM64 || BMIPS_GENERIC || COMPILE_TEST
+ depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST
select SOC_BUS
help
Enables drivers for the Broadcom Set-Top Box (STB) series of chips.
@@ -42,7 +12,6 @@ config SOC_BRCMSTB
If unsure, say N.
-source "drivers/soc/bcm/bcm63xx/Kconfig"
source "drivers/soc/bcm/brcmstb/Kconfig"
endmenu
diff --git a/drivers/soc/bcm/Makefile b/drivers/soc/bcm/Makefile
index 0f0efa28d92b..32424b1032c7 100644
--- a/drivers/soc/bcm/Makefile
+++ b/drivers/soc/bcm/Makefile
@@ -1,5 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_BCM2835_POWER) += bcm2835-power.o
-obj-$(CONFIG_RASPBERRYPI_POWER) += raspberrypi-power.o
-obj-y += bcm63xx/
obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/
diff --git a/drivers/soc/bcm/bcm2835-power.c b/drivers/soc/bcm/bcm2835-power.c
deleted file mode 100644
index 5bcd047768b6..000000000000
--- a/drivers/soc/bcm/bcm2835-power.c
+++ /dev/null
@@ -1,720 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Power domain driver for Broadcom BCM2835
- *
- * Copyright (C) 2018 Broadcom
- */
-
-#include <dt-bindings/soc/bcm2835-pm.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/mfd/bcm2835-pm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <linux/reset-controller.h>
-#include <linux/types.h>
-
-#define PM_GNRIC 0x00
-#define PM_AUDIO 0x04
-#define PM_STATUS 0x18
-#define PM_RSTC 0x1c
-#define PM_RSTS 0x20
-#define PM_WDOG 0x24
-#define PM_PADS0 0x28
-#define PM_PADS2 0x2c
-#define PM_PADS3 0x30
-#define PM_PADS4 0x34
-#define PM_PADS5 0x38
-#define PM_PADS6 0x3c
-#define PM_CAM0 0x44
-#define PM_CAM0_LDOHPEN BIT(2)
-#define PM_CAM0_LDOLPEN BIT(1)
-#define PM_CAM0_CTRLEN BIT(0)
-
-#define PM_CAM1 0x48
-#define PM_CAM1_LDOHPEN BIT(2)
-#define PM_CAM1_LDOLPEN BIT(1)
-#define PM_CAM1_CTRLEN BIT(0)
-
-#define PM_CCP2TX 0x4c
-#define PM_CCP2TX_LDOEN BIT(1)
-#define PM_CCP2TX_CTRLEN BIT(0)
-
-#define PM_DSI0 0x50
-#define PM_DSI0_LDOHPEN BIT(2)
-#define PM_DSI0_LDOLPEN BIT(1)
-#define PM_DSI0_CTRLEN BIT(0)
-
-#define PM_DSI1 0x54
-#define PM_DSI1_LDOHPEN BIT(2)
-#define PM_DSI1_LDOLPEN BIT(1)
-#define PM_DSI1_CTRLEN BIT(0)
-
-#define PM_HDMI 0x58
-#define PM_HDMI_RSTDR BIT(19)
-#define PM_HDMI_LDOPD BIT(1)
-#define PM_HDMI_CTRLEN BIT(0)
-
-#define PM_USB 0x5c
-/* The power gates must be enabled with this bit before enabling the LDO in the
- * USB block.
- */
-#define PM_USB_CTRLEN BIT(0)
-
-#define PM_PXLDO 0x60
-#define PM_PXBG 0x64
-#define PM_DFT 0x68
-#define PM_SMPS 0x6c
-#define PM_XOSC 0x70
-#define PM_SPAREW 0x74
-#define PM_SPARER 0x78
-#define PM_AVS_RSTDR 0x7c
-#define PM_AVS_STAT 0x80
-#define PM_AVS_EVENT 0x84
-#define PM_AVS_INTEN 0x88
-#define PM_DUMMY 0xfc
-
-#define PM_IMAGE 0x108
-#define PM_GRAFX 0x10c
-#define PM_PROC 0x110
-#define PM_ENAB BIT(12)
-#define PM_ISPRSTN BIT(8)
-#define PM_H264RSTN BIT(7)
-#define PM_PERIRSTN BIT(6)
-#define PM_V3DRSTN BIT(6)
-#define PM_ISFUNC BIT(5)
-#define PM_MRDONE BIT(4)
-#define PM_MEMREP BIT(3)
-#define PM_ISPOW BIT(2)
-#define PM_POWOK BIT(1)
-#define PM_POWUP BIT(0)
-#define PM_INRUSH_SHIFT 13
-#define PM_INRUSH_3_5_MA 0
-#define PM_INRUSH_5_MA 1
-#define PM_INRUSH_10_MA 2
-#define PM_INRUSH_20_MA 3
-#define PM_INRUSH_MASK (3 << PM_INRUSH_SHIFT)
-
-#define PM_PASSWORD 0x5a000000
-
-#define PM_WDOG_TIME_SET 0x000fffff
-#define PM_RSTC_WRCFG_CLR 0xffffffcf
-#define PM_RSTS_HADWRH_SET 0x00000040
-#define PM_RSTC_WRCFG_SET 0x00000030
-#define PM_RSTC_WRCFG_FULL_RESET 0x00000020
-#define PM_RSTC_RESET 0x00000102
-
-#define PM_READ(reg) readl(power->base + (reg))
-#define PM_WRITE(reg, val) writel(PM_PASSWORD | (val), power->base + (reg))
-
-#define ASB_BRDG_VERSION 0x00
-#define ASB_CPR_CTRL 0x04
-
-#define ASB_V3D_S_CTRL 0x08
-#define ASB_V3D_M_CTRL 0x0c
-#define ASB_ISP_S_CTRL 0x10
-#define ASB_ISP_M_CTRL 0x14
-#define ASB_H264_S_CTRL 0x18
-#define ASB_H264_M_CTRL 0x1c
-
-#define ASB_REQ_STOP BIT(0)
-#define ASB_ACK BIT(1)
-#define ASB_EMPTY BIT(2)
-#define ASB_FULL BIT(3)
-
-#define ASB_AXI_BRDG_ID 0x20
-
-#define BCM2835_BRDG_ID 0x62726467
-
-struct bcm2835_power_domain {
- struct generic_pm_domain base;
- struct bcm2835_power *power;
- u32 domain;
- struct clk *clk;
-};
-
-struct bcm2835_power {
- struct device *dev;
- /* PM registers. */
- void __iomem *base;
- /* AXI Async bridge registers. */
- void __iomem *asb;
- /* RPiVid bridge registers. */
- void __iomem *rpivid_asb;
-
- struct genpd_onecell_data pd_xlate;
- struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT];
- struct reset_controller_dev reset;
-};
-
-static int bcm2835_asb_control(struct bcm2835_power *power, u32 reg, bool enable)
-{
- void __iomem *base = power->asb;
- u64 start;
- u32 val;
-
- switch (reg) {
- case 0:
- return 0;
- case ASB_V3D_S_CTRL:
- case ASB_V3D_M_CTRL:
- if (power->rpivid_asb)
- base = power->rpivid_asb;
- break;
- }
-
- start = ktime_get_ns();
-
- /* Enable the module's async AXI bridges. */
- if (enable) {
- val = readl(base + reg) & ~ASB_REQ_STOP;
- } else {
- val = readl(base + reg) | ASB_REQ_STOP;
- }
- writel(PM_PASSWORD | val, base + reg);
-
- while (readl(base + reg) & ASB_ACK) {
- cpu_relax();
- if (ktime_get_ns() - start >= 1000)
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg)
-{
- return bcm2835_asb_control(power, reg, true);
-}
-
-static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg)
-{
- return bcm2835_asb_control(power, reg, false);
-}
-
-static int bcm2835_power_power_off(struct bcm2835_power_domain *pd, u32 pm_reg)
-{
- struct bcm2835_power *power = pd->power;
-
- /* We don't run this on BCM2711 */
- if (power->rpivid_asb)
- return 0;
-
- /* Enable functional isolation */
- PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC);
-
- /* Enable electrical isolation */
- PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW);
-
- /* Open the power switches. */
- PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_POWUP);
-
- return 0;
-}
-
-static int bcm2835_power_power_on(struct bcm2835_power_domain *pd, u32 pm_reg)
-{
- struct bcm2835_power *power = pd->power;
- struct device *dev = power->dev;
- u64 start;
- int ret;
- int inrush;
- bool powok;
-
- /* We don't run this on BCM2711 */
- if (power->rpivid_asb)
- return 0;
-
- /* If it was already powered on by the fw, leave it that way. */
- if (PM_READ(pm_reg) & PM_POWUP)
- return 0;
-
- /* Enable power. Allowing too much current at once may result
- * in POWOK never getting set, so start low and ramp it up as
- * necessary to succeed.
- */
- powok = false;
- for (inrush = PM_INRUSH_3_5_MA; inrush <= PM_INRUSH_20_MA; inrush++) {
- PM_WRITE(pm_reg,
- (PM_READ(pm_reg) & ~PM_INRUSH_MASK) |
- (inrush << PM_INRUSH_SHIFT) |
- PM_POWUP);
-
- start = ktime_get_ns();
- while (!(powok = !!(PM_READ(pm_reg) & PM_POWOK))) {
- cpu_relax();
- if (ktime_get_ns() - start >= 3000)
- break;
- }
- }
- if (!powok) {
- dev_err(dev, "Timeout waiting for %s power OK\n",
- pd->base.name);
- ret = -ETIMEDOUT;
- goto err_disable_powup;
- }
-
- /* Disable electrical isolation */
- PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISPOW);
-
- /* Repair memory */
- PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_MEMREP);
- start = ktime_get_ns();
- while (!(PM_READ(pm_reg) & PM_MRDONE)) {
- cpu_relax();
- if (ktime_get_ns() - start >= 1000) {
- dev_err(dev, "Timeout waiting for %s memory repair\n",
- pd->base.name);
- ret = -ETIMEDOUT;
- goto err_disable_ispow;
- }
- }
-
- /* Disable functional isolation */
- PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISFUNC);
-
- return 0;
-
-err_disable_ispow:
- PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW);
-err_disable_powup:
- PM_WRITE(pm_reg, PM_READ(pm_reg) & ~(PM_POWUP | PM_INRUSH_MASK));
- return ret;
-}
-
-static int bcm2835_asb_power_on(struct bcm2835_power_domain *pd,
- u32 pm_reg,
- u32 asb_m_reg,
- u32 asb_s_reg,
- u32 reset_flags)
-{
- struct bcm2835_power *power = pd->power;
- int ret;
-
- ret = clk_prepare_enable(pd->clk);
- if (ret) {
- dev_err(power->dev, "Failed to enable clock for %s\n",
- pd->base.name);
- return ret;
- }
-
- /* Wait 32 clocks for reset to propagate, 1 us will be enough */
- udelay(1);
-
- clk_disable_unprepare(pd->clk);
-
- /* Deassert the resets. */
- PM_WRITE(pm_reg, PM_READ(pm_reg) | reset_flags);
-
- ret = clk_prepare_enable(pd->clk);
- if (ret) {
- dev_err(power->dev, "Failed to enable clock for %s\n",
- pd->base.name);
- goto err_enable_resets;
- }
-
- ret = bcm2835_asb_enable(power, asb_m_reg);
- if (ret) {
- dev_err(power->dev, "Failed to enable ASB master for %s\n",
- pd->base.name);
- goto err_disable_clk;
- }
- ret = bcm2835_asb_enable(power, asb_s_reg);
- if (ret) {
- dev_err(power->dev, "Failed to enable ASB slave for %s\n",
- pd->base.name);
- goto err_disable_asb_master;
- }
-
- return 0;
-
-err_disable_asb_master:
- bcm2835_asb_disable(power, asb_m_reg);
-err_disable_clk:
- clk_disable_unprepare(pd->clk);
-err_enable_resets:
- PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags);
- return ret;
-}
-
-static int bcm2835_asb_power_off(struct bcm2835_power_domain *pd,
- u32 pm_reg,
- u32 asb_m_reg,
- u32 asb_s_reg,
- u32 reset_flags)
-{
- struct bcm2835_power *power = pd->power;
- int ret;
-
- ret = bcm2835_asb_disable(power, asb_s_reg);
- if (ret) {
- dev_warn(power->dev, "Failed to disable ASB slave for %s\n",
- pd->base.name);
- return ret;
- }
- ret = bcm2835_asb_disable(power, asb_m_reg);
- if (ret) {
- dev_warn(power->dev, "Failed to disable ASB master for %s\n",
- pd->base.name);
- bcm2835_asb_enable(power, asb_s_reg);
- return ret;
- }
-
- clk_disable_unprepare(pd->clk);
-
- /* Assert the resets. */
- PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags);
-
- return 0;
-}
-
-static int bcm2835_power_pd_power_on(struct generic_pm_domain *domain)
-{
- struct bcm2835_power_domain *pd =
- container_of(domain, struct bcm2835_power_domain, base);
- struct bcm2835_power *power = pd->power;
-
- switch (pd->domain) {
- case BCM2835_POWER_DOMAIN_GRAFX:
- return bcm2835_power_power_on(pd, PM_GRAFX);
-
- case BCM2835_POWER_DOMAIN_GRAFX_V3D:
- return bcm2835_asb_power_on(pd, PM_GRAFX,
- ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
- PM_V3DRSTN);
-
- case BCM2835_POWER_DOMAIN_IMAGE:
- return bcm2835_power_power_on(pd, PM_IMAGE);
-
- case BCM2835_POWER_DOMAIN_IMAGE_PERI:
- return bcm2835_asb_power_on(pd, PM_IMAGE,
- 0, 0,
- PM_PERIRSTN);
-
- case BCM2835_POWER_DOMAIN_IMAGE_ISP:
- return bcm2835_asb_power_on(pd, PM_IMAGE,
- ASB_ISP_M_CTRL, ASB_ISP_S_CTRL,
- PM_ISPRSTN);
-
- case BCM2835_POWER_DOMAIN_IMAGE_H264:
- return bcm2835_asb_power_on(pd, PM_IMAGE,
- ASB_H264_M_CTRL, ASB_H264_S_CTRL,
- PM_H264RSTN);
-
- case BCM2835_POWER_DOMAIN_USB:
- PM_WRITE(PM_USB, PM_USB_CTRLEN);
- return 0;
-
- case BCM2835_POWER_DOMAIN_DSI0:
- PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN);
- PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN | PM_DSI0_LDOHPEN);
- return 0;
-
- case BCM2835_POWER_DOMAIN_DSI1:
- PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN);
- PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN | PM_DSI1_LDOHPEN);
- return 0;
-
- case BCM2835_POWER_DOMAIN_CCP2TX:
- PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN);
- PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN | PM_CCP2TX_LDOEN);
- return 0;
-
- case BCM2835_POWER_DOMAIN_HDMI:
- PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_RSTDR);
- PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_CTRLEN);
- PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_LDOPD);
- usleep_range(100, 200);
- PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_RSTDR);
- return 0;
-
- default:
- dev_err(power->dev, "Invalid domain %d\n", pd->domain);
- return -EINVAL;
- }
-}
-
-static int bcm2835_power_pd_power_off(struct generic_pm_domain *domain)
-{
- struct bcm2835_power_domain *pd =
- container_of(domain, struct bcm2835_power_domain, base);
- struct bcm2835_power *power = pd->power;
-
- switch (pd->domain) {
- case BCM2835_POWER_DOMAIN_GRAFX:
- return bcm2835_power_power_off(pd, PM_GRAFX);
-
- case BCM2835_POWER_DOMAIN_GRAFX_V3D:
- return bcm2835_asb_power_off(pd, PM_GRAFX,
- ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
- PM_V3DRSTN);
-
- case BCM2835_POWER_DOMAIN_IMAGE:
- return bcm2835_power_power_off(pd, PM_IMAGE);
-
- case BCM2835_POWER_DOMAIN_IMAGE_PERI:
- return bcm2835_asb_power_off(pd, PM_IMAGE,
- 0, 0,
- PM_PERIRSTN);
-
- case BCM2835_POWER_DOMAIN_IMAGE_ISP:
- return bcm2835_asb_power_off(pd, PM_IMAGE,
- ASB_ISP_M_CTRL, ASB_ISP_S_CTRL,
- PM_ISPRSTN);
-
- case BCM2835_POWER_DOMAIN_IMAGE_H264:
- return bcm2835_asb_power_off(pd, PM_IMAGE,
- ASB_H264_M_CTRL, ASB_H264_S_CTRL,
- PM_H264RSTN);
-
- case BCM2835_POWER_DOMAIN_USB:
- PM_WRITE(PM_USB, 0);
- return 0;
-
- case BCM2835_POWER_DOMAIN_DSI0:
- PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN);
- PM_WRITE(PM_DSI0, 0);
- return 0;
-
- case BCM2835_POWER_DOMAIN_DSI1:
- PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN);
- PM_WRITE(PM_DSI1, 0);
- return 0;
-
- case BCM2835_POWER_DOMAIN_CCP2TX:
- PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN);
- PM_WRITE(PM_CCP2TX, 0);
- return 0;
-
- case BCM2835_POWER_DOMAIN_HDMI:
- PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_LDOPD);
- PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_CTRLEN);
- return 0;
-
- default:
- dev_err(power->dev, "Invalid domain %d\n", pd->domain);
- return -EINVAL;
- }
-}
-
-static int
-bcm2835_init_power_domain(struct bcm2835_power *power,
- int pd_xlate_index, const char *name)
-{
- struct device *dev = power->dev;
- struct bcm2835_power_domain *dom = &power->domains[pd_xlate_index];
-
- dom->clk = devm_clk_get(dev->parent, name);
- if (IS_ERR(dom->clk)) {
- int ret = PTR_ERR(dom->clk);
-
- if (ret == -EPROBE_DEFER)
- return ret;
-
- /* Some domains don't have a clk, so make sure that we
- * don't deref an error pointer later.
- */
- dom->clk = NULL;
- }
-
- dom->base.name = name;
- dom->base.power_on = bcm2835_power_pd_power_on;
- dom->base.power_off = bcm2835_power_pd_power_off;
-
- dom->domain = pd_xlate_index;
- dom->power = power;
-
- /* XXX: on/off at boot? */
- pm_genpd_init(&dom->base, NULL, true);
-
- power->pd_xlate.domains[pd_xlate_index] = &dom->base;
-
- return 0;
-}
-
-/** bcm2835_reset_reset - Resets a block that has a reset line in the
- * PM block.
- *
- * The consumer of the reset controller must have the power domain up
- * -- there's no reset ability with the power domain down. To reset
- * the sub-block, we just disable its access to memory through the
- * ASB, reset, and re-enable.
- */
-static int bcm2835_reset_reset(struct reset_controller_dev *rcdev,
- unsigned long id)
-{
- struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power,
- reset);
- struct bcm2835_power_domain *pd;
- int ret;
-
- switch (id) {
- case BCM2835_RESET_V3D:
- pd = &power->domains[BCM2835_POWER_DOMAIN_GRAFX_V3D];
- break;
- case BCM2835_RESET_H264:
- pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_H264];
- break;
- case BCM2835_RESET_ISP:
- pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_ISP];
- break;
- default:
- dev_err(power->dev, "Bad reset id %ld\n", id);
- return -EINVAL;
- }
-
- ret = bcm2835_power_pd_power_off(&pd->base);
- if (ret)
- return ret;
-
- return bcm2835_power_pd_power_on(&pd->base);
-}
-
-static int bcm2835_reset_status(struct reset_controller_dev *rcdev,
- unsigned long id)
-{
- struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power,
- reset);
-
- switch (id) {
- case BCM2835_RESET_V3D:
- return !PM_READ(PM_GRAFX & PM_V3DRSTN);
- case BCM2835_RESET_H264:
- return !PM_READ(PM_IMAGE & PM_H264RSTN);
- case BCM2835_RESET_ISP:
- return !PM_READ(PM_IMAGE & PM_ISPRSTN);
- default:
- return -EINVAL;
- }
-}
-
-static const struct reset_control_ops bcm2835_reset_ops = {
- .reset = bcm2835_reset_reset,
- .status = bcm2835_reset_status,
-};
-
-static const char *const power_domain_names[] = {
- [BCM2835_POWER_DOMAIN_GRAFX] = "grafx",
- [BCM2835_POWER_DOMAIN_GRAFX_V3D] = "v3d",
-
- [BCM2835_POWER_DOMAIN_IMAGE] = "image",
- [BCM2835_POWER_DOMAIN_IMAGE_PERI] = "peri_image",
- [BCM2835_POWER_DOMAIN_IMAGE_H264] = "h264",
- [BCM2835_POWER_DOMAIN_IMAGE_ISP] = "isp",
-
- [BCM2835_POWER_DOMAIN_USB] = "usb",
- [BCM2835_POWER_DOMAIN_DSI0] = "dsi0",
- [BCM2835_POWER_DOMAIN_DSI1] = "dsi1",
- [BCM2835_POWER_DOMAIN_CAM0] = "cam0",
- [BCM2835_POWER_DOMAIN_CAM1] = "cam1",
- [BCM2835_POWER_DOMAIN_CCP2TX] = "ccp2tx",
- [BCM2835_POWER_DOMAIN_HDMI] = "hdmi",
-};
-
-static int bcm2835_power_probe(struct platform_device *pdev)
-{
- struct bcm2835_pm *pm = dev_get_drvdata(pdev->dev.parent);
- struct device *dev = &pdev->dev;
- struct bcm2835_power *power;
- static const struct {
- int parent, child;
- } domain_deps[] = {
- { BCM2835_POWER_DOMAIN_GRAFX, BCM2835_POWER_DOMAIN_GRAFX_V3D },
- { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_PERI },
- { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_H264 },
- { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_ISP },
- { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_USB },
- { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM0 },
- { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM1 },
- };
- int ret = 0, i;
- u32 id;
-
- power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
- if (!power)
- return -ENOMEM;
- platform_set_drvdata(pdev, power);
-
- power->dev = dev;
- power->base = pm->base;
- power->asb = pm->asb;
- power->rpivid_asb = pm->rpivid_asb;
-
- id = readl(power->asb + ASB_AXI_BRDG_ID);
- if (id != BCM2835_BRDG_ID /* "BRDG" */) {
- dev_err(dev, "ASB register ID returned 0x%08x\n", id);
- return -ENODEV;
- }
-
- if (power->rpivid_asb) {
- id = readl(power->rpivid_asb + ASB_AXI_BRDG_ID);
- if (id != BCM2835_BRDG_ID /* "BRDG" */) {
- dev_err(dev, "RPiVid ASB register ID returned 0x%08x\n",
- id);
- return -ENODEV;
- }
- }
-
- power->pd_xlate.domains = devm_kcalloc(dev,
- ARRAY_SIZE(power_domain_names),
- sizeof(*power->pd_xlate.domains),
- GFP_KERNEL);
- if (!power->pd_xlate.domains)
- return -ENOMEM;
-
- power->pd_xlate.num_domains = ARRAY_SIZE(power_domain_names);
-
- for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) {
- ret = bcm2835_init_power_domain(power, i, power_domain_names[i]);
- if (ret)
- goto fail;
- }
-
- for (i = 0; i < ARRAY_SIZE(domain_deps); i++) {
- pm_genpd_add_subdomain(&power->domains[domain_deps[i].parent].base,
- &power->domains[domain_deps[i].child].base);
- }
-
- power->reset.owner = THIS_MODULE;
- power->reset.nr_resets = BCM2835_RESET_COUNT;
- power->reset.ops = &bcm2835_reset_ops;
- power->reset.of_node = dev->parent->of_node;
-
- ret = devm_reset_controller_register(dev, &power->reset);
- if (ret)
- goto fail;
-
- of_genpd_add_provider_onecell(dev->parent->of_node, &power->pd_xlate);
-
- dev_info(dev, "Broadcom BCM2835 power domains driver");
- return 0;
-
-fail:
- for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) {
- struct generic_pm_domain *dom = &power->domains[i].base;
-
- if (dom->name)
- pm_genpd_remove(dom);
- }
- return ret;
-}
-
-static int bcm2835_power_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
-static struct platform_driver bcm2835_power_driver = {
- .probe = bcm2835_power_probe,
- .remove = bcm2835_power_remove,
- .driver = {
- .name = "bcm2835-power",
- },
-};
-module_platform_driver(bcm2835_power_driver);
-
-MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
-MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM power domains and reset");
-MODULE_LICENSE("GPL");
diff --git a/drivers/soc/bcm/bcm63xx/Kconfig b/drivers/soc/bcm/bcm63xx/Kconfig
deleted file mode 100644
index 355c34482076..000000000000
--- a/drivers/soc/bcm/bcm63xx/Kconfig
+++ /dev/null
@@ -1,21 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-if SOC_BCM63XX
-
-config BCM63XX_POWER
- bool "BCM63xx power domain driver"
- depends on BMIPS_GENERIC || (COMPILE_TEST && OF)
- select PM_GENERIC_DOMAINS if PM
- help
- This enables support for the BCM63xx power domains controller on
- BCM6318, BCM6328, BCM6362 and BCM63268 SoCs.
-
-endif # SOC_BCM63XX
-
-config BCM_PMB
- bool "Broadcom PMB (Power Management Bus) driver"
- depends on ARCH_BCMBCA || (COMPILE_TEST && OF)
- default ARCH_BCMBCA
- select PM_GENERIC_DOMAINS if PM
- help
- This enables support for the Broadcom's PMB (Power Management Bus) that
- is used for disabling and enabling SoC devices.
diff --git a/drivers/soc/bcm/bcm63xx/Makefile b/drivers/soc/bcm/bcm63xx/Makefile
deleted file mode 100644
index 557eed3d67bd..000000000000
--- a/drivers/soc/bcm/bcm63xx/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_BCM63XX_POWER) += bcm63xx-power.o
-obj-$(CONFIG_BCM_PMB) += bcm-pmb.o
diff --git a/drivers/soc/bcm/bcm63xx/bcm-pmb.c b/drivers/soc/bcm/bcm63xx/bcm-pmb.c
deleted file mode 100644
index 9407cac47fdb..000000000000
--- a/drivers/soc/bcm/bcm63xx/bcm-pmb.c
+++ /dev/null
@@ -1,364 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (c) 2013 Broadcom
- * Copyright (C) 2020 Rafał Miłecki <rafal@milecki.pl>
- */
-
-#include <dt-bindings/soc/bcm-pmb.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <linux/reset/bcm63xx_pmb.h>
-
-#define BPCM_ID_REG 0x00
-#define BPCM_CAPABILITIES 0x04
-#define BPCM_CAP_NUM_ZONES 0x000000ff
-#define BPCM_CAP_SR_REG_BITS 0x0000ff00
-#define BPCM_CAP_PLLTYPE 0x00030000
-#define BPCM_CAP_UBUS 0x00080000
-#define BPCM_CONTROL 0x08
-#define BPCM_STATUS 0x0c
-#define BPCM_ROSC_CONTROL 0x10
-#define BPCM_ROSC_THRESH_H 0x14
-#define BPCM_ROSC_THRESHOLD_BCM6838 0x14
-#define BPCM_ROSC_THRESH_S 0x18
-#define BPCM_ROSC_COUNT_BCM6838 0x18
-#define BPCM_ROSC_COUNT 0x1c
-#define BPCM_PWD_CONTROL_BCM6838 0x1c
-#define BPCM_PWD_CONTROL 0x20
-#define BPCM_SR_CONTROL_BCM6838 0x20
-#define BPCM_PWD_ACCUM_CONTROL 0x24
-#define BPCM_SR_CONTROL 0x28
-#define BPCM_GLOBAL_CONTROL 0x2c
-#define BPCM_MISC_CONTROL 0x30
-#define BPCM_MISC_CONTROL2 0x34
-#define BPCM_SGPHY_CNTL 0x38
-#define BPCM_SGPHY_STATUS 0x3c
-#define BPCM_ZONE0 0x40
-#define BPCM_ZONE_CONTROL 0x00
-#define BPCM_ZONE_CONTROL_MANUAL_CLK_EN 0x00000001
-#define BPCM_ZONE_CONTROL_MANUAL_RESET_CTL 0x00000002
-#define BPCM_ZONE_CONTROL_FREQ_SCALE_USED 0x00000004 /* R/O */
-#define BPCM_ZONE_CONTROL_DPG_CAPABLE 0x00000008 /* R/O */
-#define BPCM_ZONE_CONTROL_MANUAL_MEM_PWR 0x00000030
-#define BPCM_ZONE_CONTROL_MANUAL_ISO_CTL 0x00000040
-#define BPCM_ZONE_CONTROL_MANUAL_CTL 0x00000080
-#define BPCM_ZONE_CONTROL_DPG_CTL_EN 0x00000100
-#define BPCM_ZONE_CONTROL_PWR_DN_REQ 0x00000200
-#define BPCM_ZONE_CONTROL_PWR_UP_REQ 0x00000400
-#define BPCM_ZONE_CONTROL_MEM_PWR_CTL_EN 0x00000800
-#define BPCM_ZONE_CONTROL_BLK_RESET_ASSERT 0x00001000
-#define BPCM_ZONE_CONTROL_MEM_STBY 0x00002000
-#define BPCM_ZONE_CONTROL_RESERVED 0x0007c000
-#define BPCM_ZONE_CONTROL_PWR_CNTL_STATE 0x00f80000
-#define BPCM_ZONE_CONTROL_FREQ_SCALAR_DYN_SEL 0x01000000 /* R/O */
-#define BPCM_ZONE_CONTROL_PWR_OFF_STATE 0x02000000 /* R/O */
-#define BPCM_ZONE_CONTROL_PWR_ON_STATE 0x04000000 /* R/O */
-#define BPCM_ZONE_CONTROL_PWR_GOOD 0x08000000 /* R/O */
-#define BPCM_ZONE_CONTROL_DPG_PWR_STATE 0x10000000 /* R/O */
-#define BPCM_ZONE_CONTROL_MEM_PWR_STATE 0x20000000 /* R/O */
-#define BPCM_ZONE_CONTROL_ISO_STATE 0x40000000 /* R/O */
-#define BPCM_ZONE_CONTROL_RESET_STATE 0x80000000 /* R/O */
-#define BPCM_ZONE_CONFIG1 0x04
-#define BPCM_ZONE_CONFIG2 0x08
-#define BPCM_ZONE_FREQ_SCALAR_CONTROL 0x0c
-#define BPCM_ZONE_SIZE 0x10
-
-struct bcm_pmb {
- struct device *dev;
- void __iomem *base;
- spinlock_t lock;
- bool little_endian;
- struct genpd_onecell_data genpd_onecell_data;
-};
-
-struct bcm_pmb_pd_data {
- const char * const name;
- int id;
- u8 bus;
- u8 device;
-};
-
-struct bcm_pmb_pm_domain {
- struct bcm_pmb *pmb;
- const struct bcm_pmb_pd_data *data;
- struct generic_pm_domain genpd;
-};
-
-static int bcm_pmb_bpcm_read(struct bcm_pmb *pmb, int bus, u8 device,
- int offset, u32 *val)
-{
- void __iomem *base = pmb->base + bus * 0x20;
- unsigned long flags;
- int err;
-
- spin_lock_irqsave(&pmb->lock, flags);
- err = bpcm_rd(base, device, offset, val);
- spin_unlock_irqrestore(&pmb->lock, flags);
-
- if (!err)
- *val = pmb->little_endian ? le32_to_cpu(*val) : be32_to_cpu(*val);
-
- return err;
-}
-
-static int bcm_pmb_bpcm_write(struct bcm_pmb *pmb, int bus, u8 device,
- int offset, u32 val)
-{
- void __iomem *base = pmb->base + bus * 0x20;
- unsigned long flags;
- int err;
-
- val = pmb->little_endian ? cpu_to_le32(val) : cpu_to_be32(val);
-
- spin_lock_irqsave(&pmb->lock, flags);
- err = bpcm_wr(base, device, offset, val);
- spin_unlock_irqrestore(&pmb->lock, flags);
-
- return err;
-}
-
-static int bcm_pmb_power_off_zone(struct bcm_pmb *pmb, int bus, u8 device,
- int zone)
-{
- int offset;
- u32 val;
- int err;
-
- offset = BPCM_ZONE0 + zone * BPCM_ZONE_SIZE + BPCM_ZONE_CONTROL;
-
- err = bcm_pmb_bpcm_read(pmb, bus, device, offset, &val);
- if (err)
- return err;
-
- val |= BPCM_ZONE_CONTROL_PWR_DN_REQ;
- val &= ~BPCM_ZONE_CONTROL_PWR_UP_REQ;
-
- err = bcm_pmb_bpcm_write(pmb, bus, device, offset, val);
-
- return err;
-}
-
-static int bcm_pmb_power_on_zone(struct bcm_pmb *pmb, int bus, u8 device,
- int zone)
-{
- int offset;
- u32 val;
- int err;
-
- offset = BPCM_ZONE0 + zone * BPCM_ZONE_SIZE + BPCM_ZONE_CONTROL;
-
- err = bcm_pmb_bpcm_read(pmb, bus, device, offset, &val);
- if (err)
- return err;
-
- if (!(val & BPCM_ZONE_CONTROL_PWR_ON_STATE)) {
- val &= ~BPCM_ZONE_CONTROL_PWR_DN_REQ;
- val |= BPCM_ZONE_CONTROL_DPG_CTL_EN;
- val |= BPCM_ZONE_CONTROL_PWR_UP_REQ;
- val |= BPCM_ZONE_CONTROL_MEM_PWR_CTL_EN;
- val |= BPCM_ZONE_CONTROL_BLK_RESET_ASSERT;
-
- err = bcm_pmb_bpcm_write(pmb, bus, device, offset, val);
- }
-
- return err;
-}
-
-static int bcm_pmb_power_off_device(struct bcm_pmb *pmb, int bus, u8 device)
-{
- int offset;
- u32 val;
- int err;
-
- /* Entire device can be powered off by powering off the 0th zone */
- offset = BPCM_ZONE0 + BPCM_ZONE_CONTROL;
-
- err = bcm_pmb_bpcm_read(pmb, bus, device, offset, &val);
- if (err)
- return err;
-
- if (!(val & BPCM_ZONE_CONTROL_PWR_OFF_STATE)) {
- val = BPCM_ZONE_CONTROL_PWR_DN_REQ;
-
- err = bcm_pmb_bpcm_write(pmb, bus, device, offset, val);
- }
-
- return err;
-}
-
-static int bcm_pmb_power_on_device(struct bcm_pmb *pmb, int bus, u8 device)
-{
- u32 val;
- int err;
- int i;
-
- err = bcm_pmb_bpcm_read(pmb, bus, device, BPCM_CAPABILITIES, &val);
- if (err)
- return err;
-
- for (i = 0; i < (val & BPCM_CAP_NUM_ZONES); i++) {
- err = bcm_pmb_power_on_zone(pmb, bus, device, i);
- if (err)
- return err;
- }
-
- return err;
-}
-
-static int bcm_pmb_power_on_sata(struct bcm_pmb *pmb, int bus, u8 device)
-{
- int err;
-
- err = bcm_pmb_power_on_zone(pmb, bus, device, 0);
- if (err)
- return err;
-
- /* Does not apply to the BCM963158 */
- err = bcm_pmb_bpcm_write(pmb, bus, device, BPCM_MISC_CONTROL, 0);
- if (err)
- return err;
-
- err = bcm_pmb_bpcm_write(pmb, bus, device, BPCM_SR_CONTROL, 0xffffffff);
- if (err)
- return err;
-
- err = bcm_pmb_bpcm_write(pmb, bus, device, BPCM_SR_CONTROL, 0);
-
- return err;
-}
-
-static int bcm_pmb_power_on(struct generic_pm_domain *genpd)
-{
- struct bcm_pmb_pm_domain *pd = container_of(genpd, struct bcm_pmb_pm_domain, genpd);
- const struct bcm_pmb_pd_data *data = pd->data;
- struct bcm_pmb *pmb = pd->pmb;
-
- switch (data->id) {
- case BCM_PMB_PCIE0:
- case BCM_PMB_PCIE1:
- case BCM_PMB_PCIE2:
- return bcm_pmb_power_on_zone(pmb, data->bus, data->device, 0);
- case BCM_PMB_HOST_USB:
- return bcm_pmb_power_on_device(pmb, data->bus, data->device);
- case BCM_PMB_SATA:
- return bcm_pmb_power_on_sata(pmb, data->bus, data->device);
- default:
- dev_err(pmb->dev, "unsupported device id: %d\n", data->id);
- return -EINVAL;
- }
-}
-
-static int bcm_pmb_power_off(struct generic_pm_domain *genpd)
-{
- struct bcm_pmb_pm_domain *pd = container_of(genpd, struct bcm_pmb_pm_domain, genpd);
- const struct bcm_pmb_pd_data *data = pd->data;
- struct bcm_pmb *pmb = pd->pmb;
-
- switch (data->id) {
- case BCM_PMB_PCIE0:
- case BCM_PMB_PCIE1:
- case BCM_PMB_PCIE2:
- return bcm_pmb_power_off_zone(pmb, data->bus, data->device, 0);
- case BCM_PMB_HOST_USB:
- return bcm_pmb_power_off_device(pmb, data->bus, data->device);
- default:
- dev_err(pmb->dev, "unsupported device id: %d\n", data->id);
- return -EINVAL;
- }
-}
-
-static int bcm_pmb_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- const struct bcm_pmb_pd_data *table;
- const struct bcm_pmb_pd_data *e;
- struct bcm_pmb *pmb;
- int max_id;
- int err;
-
- pmb = devm_kzalloc(dev, sizeof(*pmb), GFP_KERNEL);
- if (!pmb)
- return -ENOMEM;
-
- pmb->dev = dev;
-
- pmb->base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(pmb->base))
- return PTR_ERR(pmb->base);
-
- spin_lock_init(&pmb->lock);
-
- pmb->little_endian = !of_device_is_big_endian(dev->of_node);
-
- table = of_device_get_match_data(dev);
- if (!table)
- return -EINVAL;
-
- max_id = 0;
- for (e = table; e->name; e++)
- max_id = max(max_id, e->id);
-
- pmb->genpd_onecell_data.num_domains = max_id + 1;
- pmb->genpd_onecell_data.domains =
- devm_kcalloc(dev, pmb->genpd_onecell_data.num_domains,
- sizeof(struct generic_pm_domain *), GFP_KERNEL);
- if (!pmb->genpd_onecell_data.domains)
- return -ENOMEM;
-
- for (e = table; e->name; e++) {
- struct bcm_pmb_pm_domain *pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
-
- if (!pd)
- return -ENOMEM;
-
- pd->pmb = pmb;
- pd->data = e;
- pd->genpd.name = e->name;
- pd->genpd.power_on = bcm_pmb_power_on;
- pd->genpd.power_off = bcm_pmb_power_off;
-
- pm_genpd_init(&pd->genpd, NULL, true);
- pmb->genpd_onecell_data.domains[e->id] = &pd->genpd;
- }
-
- err = of_genpd_add_provider_onecell(dev->of_node, &pmb->genpd_onecell_data);
- if (err) {
- dev_err(dev, "failed to add genpd provider: %d\n", err);
- return err;
- }
-
- return 0;
-}
-
-static const struct bcm_pmb_pd_data bcm_pmb_bcm4908_data[] = {
- { .name = "pcie2", .id = BCM_PMB_PCIE2, .bus = 0, .device = 2, },
- { .name = "pcie0", .id = BCM_PMB_PCIE0, .bus = 1, .device = 14, },
- { .name = "pcie1", .id = BCM_PMB_PCIE1, .bus = 1, .device = 15, },
- { .name = "usb", .id = BCM_PMB_HOST_USB, .bus = 1, .device = 17, },
- { },
-};
-
-static const struct bcm_pmb_pd_data bcm_pmb_bcm63138_data[] = {
- { .name = "sata", .id = BCM_PMB_SATA, .bus = 0, .device = 3, },
- { },
-};
-
-static const struct of_device_id bcm_pmb_of_match[] = {
- { .compatible = "brcm,bcm4908-pmb", .data = &bcm_pmb_bcm4908_data, },
- { .compatible = "brcm,bcm63138-pmb", .data = &bcm_pmb_bcm63138_data, },
- { },
-};
-
-static struct platform_driver bcm_pmb_driver = {
- .driver = {
- .name = "bcm-pmb",
- .of_match_table = bcm_pmb_of_match,
- },
- .probe = bcm_pmb_probe,
-};
-
-builtin_platform_driver(bcm_pmb_driver);
diff --git a/drivers/soc/bcm/bcm63xx/bcm63xx-power.c b/drivers/soc/bcm/bcm63xx/bcm63xx-power.c
deleted file mode 100644
index aa72e13d5d0e..000000000000
--- a/drivers/soc/bcm/bcm63xx/bcm63xx-power.c
+++ /dev/null
@@ -1,376 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * BCM63xx Power Domain Controller Driver
- *
- * Copyright (C) 2020 Álvaro Fernández Rojas <noltari@gmail.com>
- */
-
-#include <dt-bindings/soc/bcm6318-pm.h>
-#include <dt-bindings/soc/bcm6328-pm.h>
-#include <dt-bindings/soc/bcm6362-pm.h>
-#include <dt-bindings/soc/bcm63268-pm.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-
-struct bcm63xx_power_dev {
- struct generic_pm_domain genpd;
- struct bcm63xx_power *power;
- uint32_t mask;
-};
-
-struct bcm63xx_power {
- void __iomem *base;
- spinlock_t lock;
- struct bcm63xx_power_dev *dev;
- struct genpd_onecell_data genpd_data;
- struct generic_pm_domain **genpd;
-};
-
-struct bcm63xx_power_data {
- const char * const name;
- uint8_t bit;
- unsigned int flags;
-};
-
-static int bcm63xx_power_get_state(struct bcm63xx_power_dev *pmd, bool *is_on)
-{
- struct bcm63xx_power *power = pmd->power;
-
- if (!pmd->mask) {
- *is_on = false;
- return -EINVAL;
- }
-
- *is_on = !(__raw_readl(power->base) & pmd->mask);
-
- return 0;
-}
-
-static int bcm63xx_power_set_state(struct bcm63xx_power_dev *pmd, bool on)
-{
- struct bcm63xx_power *power = pmd->power;
- unsigned long flags;
- uint32_t val;
-
- if (!pmd->mask)
- return -EINVAL;
-
- spin_lock_irqsave(&power->lock, flags);
- val = __raw_readl(power->base);
- if (on)
- val &= ~pmd->mask;
- else
- val |= pmd->mask;
- __raw_writel(val, power->base);
- spin_unlock_irqrestore(&power->lock, flags);
-
- return 0;
-}
-
-static int bcm63xx_power_on(struct generic_pm_domain *genpd)
-{
- struct bcm63xx_power_dev *pmd = container_of(genpd,
- struct bcm63xx_power_dev, genpd);
-
- return bcm63xx_power_set_state(pmd, true);
-}
-
-static int bcm63xx_power_off(struct generic_pm_domain *genpd)
-{
- struct bcm63xx_power_dev *pmd = container_of(genpd,
- struct bcm63xx_power_dev, genpd);
-
- return bcm63xx_power_set_state(pmd, false);
-}
-
-static int bcm63xx_power_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
- const struct bcm63xx_power_data *entry, *table;
- struct bcm63xx_power *power;
- unsigned int ndom;
- uint8_t max_bit = 0;
- int ret;
-
- power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
- if (!power)
- return -ENOMEM;
-
- power->base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(power->base))
- return PTR_ERR(power->base);
-
- table = of_device_get_match_data(dev);
- if (!table)
- return -EINVAL;
-
- power->genpd_data.num_domains = 0;
- ndom = 0;
- for (entry = table; entry->name; entry++) {
- max_bit = max(max_bit, entry->bit);
- ndom++;
- }
-
- if (!ndom)
- return -ENODEV;
-
- power->genpd_data.num_domains = max_bit + 1;
-
- power->dev = devm_kcalloc(dev, power->genpd_data.num_domains,
- sizeof(struct bcm63xx_power_dev),
- GFP_KERNEL);
- if (!power->dev)
- return -ENOMEM;
-
- power->genpd = devm_kcalloc(dev, power->genpd_data.num_domains,
- sizeof(struct generic_pm_domain *),
- GFP_KERNEL);
- if (!power->genpd)
- return -ENOMEM;
-
- power->genpd_data.domains = power->genpd;
-
- ndom = 0;
- for (entry = table; entry->name; entry++) {
- struct bcm63xx_power_dev *pmd = &power->dev[ndom];
- bool is_on;
-
- pmd->power = power;
- pmd->mask = BIT(entry->bit);
- pmd->genpd.name = entry->name;
- pmd->genpd.flags = entry->flags;
-
- ret = bcm63xx_power_get_state(pmd, &is_on);
- if (ret)
- dev_warn(dev, "unable to get current state for %s\n",
- pmd->genpd.name);
-
- pmd->genpd.power_on = bcm63xx_power_on;
- pmd->genpd.power_off = bcm63xx_power_off;
-
- pm_genpd_init(&pmd->genpd, NULL, !is_on);
- power->genpd[entry->bit] = &pmd->genpd;
-
- ndom++;
- }
-
- spin_lock_init(&power->lock);
-
- ret = of_genpd_add_provider_onecell(np, &power->genpd_data);
- if (ret) {
- dev_err(dev, "failed to register genpd driver: %d\n", ret);
- return ret;
- }
-
- dev_info(dev, "registered %u power domains\n", ndom);
-
- return 0;
-}
-
-static const struct bcm63xx_power_data bcm6318_power_domains[] = {
- {
- .name = "pcie",
- .bit = BCM6318_POWER_DOMAIN_PCIE,
- }, {
- .name = "usb",
- .bit = BCM6318_POWER_DOMAIN_USB,
- }, {
- .name = "ephy0",
- .bit = BCM6318_POWER_DOMAIN_EPHY0,
- }, {
- .name = "ephy1",
- .bit = BCM6318_POWER_DOMAIN_EPHY1,
- }, {
- .name = "ephy2",
- .bit = BCM6318_POWER_DOMAIN_EPHY2,
- }, {
- .name = "ephy3",
- .bit = BCM6318_POWER_DOMAIN_EPHY3,
- }, {
- .name = "ldo2p5",
- .bit = BCM6318_POWER_DOMAIN_LDO2P5,
- .flags = GENPD_FLAG_ALWAYS_ON,
- }, {
- .name = "ldo2p9",
- .bit = BCM6318_POWER_DOMAIN_LDO2P9,
- .flags = GENPD_FLAG_ALWAYS_ON,
- }, {
- .name = "sw1p0",
- .bit = BCM6318_POWER_DOMAIN_SW1P0,
- .flags = GENPD_FLAG_ALWAYS_ON,
- }, {
- .name = "pad",
- .bit = BCM6318_POWER_DOMAIN_PAD,
- .flags = GENPD_FLAG_ALWAYS_ON,
- }, {
- /* sentinel */
- },
-};
-
-static const struct bcm63xx_power_data bcm6328_power_domains[] = {
- {
- .name = "adsl2-mips",
- .bit = BCM6328_POWER_DOMAIN_ADSL2_MIPS,
- }, {
- .name = "adsl2-phy",
- .bit = BCM6328_POWER_DOMAIN_ADSL2_PHY,
- }, {
- .name = "adsl2-afe",
- .bit = BCM6328_POWER_DOMAIN_ADSL2_AFE,
- }, {
- .name = "sar",
- .bit = BCM6328_POWER_DOMAIN_SAR,
- }, {
- .name = "pcm",
- .bit = BCM6328_POWER_DOMAIN_PCM,
- }, {
- .name = "usbd",
- .bit = BCM6328_POWER_DOMAIN_USBD,
- }, {
- .name = "usbh",
- .bit = BCM6328_POWER_DOMAIN_USBH,
- }, {
- .name = "pcie",
- .bit = BCM6328_POWER_DOMAIN_PCIE,
- }, {
- .name = "robosw",
- .bit = BCM6328_POWER_DOMAIN_ROBOSW,
- }, {
- .name = "ephy",
- .bit = BCM6328_POWER_DOMAIN_EPHY,
- }, {
- /* sentinel */
- },
-};
-
-static const struct bcm63xx_power_data bcm6362_power_domains[] = {
- {
- .name = "sar",
- .bit = BCM6362_POWER_DOMAIN_SAR,
- }, {
- .name = "ipsec",
- .bit = BCM6362_POWER_DOMAIN_IPSEC,
- }, {
- .name = "mips",
- .bit = BCM6362_POWER_DOMAIN_MIPS,
- .flags = GENPD_FLAG_ALWAYS_ON,
- }, {
- .name = "dect",
- .bit = BCM6362_POWER_DOMAIN_DECT,
- }, {
- .name = "usbh",
- .bit = BCM6362_POWER_DOMAIN_USBH,
- }, {
- .name = "usbd",
- .bit = BCM6362_POWER_DOMAIN_USBD,
- }, {
- .name = "robosw",
- .bit = BCM6362_POWER_DOMAIN_ROBOSW,
- }, {
- .name = "pcm",
- .bit = BCM6362_POWER_DOMAIN_PCM,
- }, {
- .name = "periph",
- .bit = BCM6362_POWER_DOMAIN_PERIPH,
- .flags = GENPD_FLAG_ALWAYS_ON,
- }, {
- .name = "adsl-phy",
- .bit = BCM6362_POWER_DOMAIN_ADSL_PHY,
- }, {
- .name = "gmii-pads",
- .bit = BCM6362_POWER_DOMAIN_GMII_PADS,
- }, {
- .name = "fap",
- .bit = BCM6362_POWER_DOMAIN_FAP,
- }, {
- .name = "pcie",
- .bit = BCM6362_POWER_DOMAIN_PCIE,
- }, {
- .name = "wlan-pads",
- .bit = BCM6362_POWER_DOMAIN_WLAN_PADS,
- }, {
- /* sentinel */
- },
-};
-
-static const struct bcm63xx_power_data bcm63268_power_domains[] = {
- {
- .name = "sar",
- .bit = BCM63268_POWER_DOMAIN_SAR,
- }, {
- .name = "ipsec",
- .bit = BCM63268_POWER_DOMAIN_IPSEC,
- }, {
- .name = "mips",
- .bit = BCM63268_POWER_DOMAIN_MIPS,
- .flags = GENPD_FLAG_ALWAYS_ON,
- }, {
- .name = "dect",
- .bit = BCM63268_POWER_DOMAIN_DECT,
- }, {
- .name = "usbh",
- .bit = BCM63268_POWER_DOMAIN_USBH,
- }, {
- .name = "usbd",
- .bit = BCM63268_POWER_DOMAIN_USBD,
- }, {
- .name = "robosw",
- .bit = BCM63268_POWER_DOMAIN_ROBOSW,
- }, {
- .name = "pcm",
- .bit = BCM63268_POWER_DOMAIN_PCM,
- }, {
- .name = "periph",
- .bit = BCM63268_POWER_DOMAIN_PERIPH,
- .flags = GENPD_FLAG_ALWAYS_ON,
- }, {
- .name = "vdsl-phy",
- .bit = BCM63268_POWER_DOMAIN_VDSL_PHY,
- }, {
- .name = "vdsl-mips",
- .bit = BCM63268_POWER_DOMAIN_VDSL_MIPS,
- }, {
- .name = "fap",
- .bit = BCM63268_POWER_DOMAIN_FAP,
- }, {
- .name = "pcie",
- .bit = BCM63268_POWER_DOMAIN_PCIE,
- }, {
- .name = "wlan-pads",
- .bit = BCM63268_POWER_DOMAIN_WLAN_PADS,
- }, {
- /* sentinel */
- },
-};
-
-static const struct of_device_id bcm63xx_power_of_match[] = {
- {
- .compatible = "brcm,bcm6318-power-controller",
- .data = &bcm6318_power_domains,
- }, {
- .compatible = "brcm,bcm6328-power-controller",
- .data = &bcm6328_power_domains,
- }, {
- .compatible = "brcm,bcm6362-power-controller",
- .data = &bcm6362_power_domains,
- }, {
- .compatible = "brcm,bcm63268-power-controller",
- .data = &bcm63268_power_domains,
- }, {
- /* sentinel */
- }
-};
-
-static struct platform_driver bcm63xx_power_driver = {
- .driver = {
- .name = "bcm63xx-power-controller",
- .of_match_table = bcm63xx_power_of_match,
- },
- .probe = bcm63xx_power_probe,
-};
-builtin_platform_driver(bcm63xx_power_driver);
diff --git a/drivers/soc/bcm/brcmstb/Kconfig b/drivers/soc/bcm/brcmstb/Kconfig
index 38e476905d96..c68d0e5267c4 100644
--- a/drivers/soc/bcm/brcmstb/Kconfig
+++ b/drivers/soc/bcm/brcmstb/Kconfig
@@ -4,8 +4,6 @@ if SOC_BRCMSTB
config BRCMSTB_PM
bool "Support suspend/resume for STB platforms"
default y
- depends on PM
- depends on ARCH_BRCMSTB || BMIPS_GENERIC
- select ARM_CPU_SUSPEND if ARM
+ depends on PM && BMIPS_GENERIC
endif # SOC_BRCMSTB
diff --git a/drivers/soc/bcm/brcmstb/biuctrl.c b/drivers/soc/bcm/brcmstb/biuctrl.c
index e1d7b4543248..bd830649b60d 100644
--- a/drivers/soc/bcm/brcmstb/biuctrl.c
+++ b/drivers/soc/bcm/brcmstb/biuctrl.c
@@ -288,13 +288,17 @@ static int __init setup_hifcpubiuctrl_regs(struct device_node *np)
if (BRCM_ID(family_id) == 0x7260 && BRCM_REV(family_id) == 0)
cpubiuctrl_regs = b53_cpubiuctrl_no_wb_regs;
out:
+ if (ret && cpubiuctrl_base) {
+ iounmap(cpubiuctrl_base);
+ cpubiuctrl_base = NULL;
+ }
return ret;
}
#ifdef CONFIG_PM_SLEEP
static u32 cpubiuctrl_reg_save[NUM_CPU_BIUCTRL_REGS];
-static int brcmstb_cpu_credit_reg_suspend(void)
+static int brcmstb_cpu_credit_reg_suspend(void *data)
{
unsigned int i;
@@ -307,7 +311,7 @@ static int brcmstb_cpu_credit_reg_suspend(void)
return 0;
}
-static void brcmstb_cpu_credit_reg_resume(void)
+static void brcmstb_cpu_credit_reg_resume(void *data)
{
unsigned int i;
@@ -318,10 +322,14 @@ static void brcmstb_cpu_credit_reg_resume(void)
cbc_writel(cpubiuctrl_reg_save[i], i);
}
-static struct syscore_ops brcmstb_cpu_credit_syscore_ops = {
+static const struct syscore_ops brcmstb_cpu_credit_syscore_ops = {
.suspend = brcmstb_cpu_credit_reg_suspend,
.resume = brcmstb_cpu_credit_reg_resume,
};
+
+static struct syscore brcmstb_cpu_credit_syscore = {
+ .ops = &brcmstb_cpu_credit_syscore_ops,
+};
#endif
@@ -350,7 +358,7 @@ static int __init brcmstb_biuctrl_init(void)
a72_b53_rac_enable_all(np);
mcp_a72_b53_set();
#ifdef CONFIG_PM_SLEEP
- register_syscore_ops(&brcmstb_cpu_credit_syscore_ops);
+ register_syscore(&brcmstb_cpu_credit_syscore);
#endif
ret = 0;
out_put:
diff --git a/drivers/soc/bcm/brcmstb/pm/Makefile b/drivers/soc/bcm/brcmstb/pm/Makefile
index f849cfa69446..9133a9ee0782 100644
--- a/drivers/soc/bcm/brcmstb/pm/Makefile
+++ b/drivers/soc/bcm/brcmstb/pm/Makefile
@@ -1,3 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_ARM) += s2-arm.o pm-arm.o
obj-$(CONFIG_BMIPS_GENERIC) += s2-mips.o s3-mips.o pm-mips.o
diff --git a/drivers/soc/bcm/brcmstb/pm/aon_defs.h b/drivers/soc/bcm/brcmstb/pm/aon_defs.h
deleted file mode 100644
index f695262ac930..000000000000
--- a/drivers/soc/bcm/brcmstb/pm/aon_defs.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Always ON (AON) register interface between bootloader and Linux
- *
- * Copyright © 2014-2017 Broadcom
- */
-
-#ifndef __BRCMSTB_AON_DEFS_H__
-#define __BRCMSTB_AON_DEFS_H__
-
-#include <linux/compiler.h>
-
-/* Magic number in upper 16-bits */
-#define BRCMSTB_S3_MAGIC_MASK 0xffff0000
-#define BRCMSTB_S3_MAGIC_SHORT 0x5AFE0000
-
-enum {
- /* Restore random key for AES memory verification (off = fixed key) */
- S3_FLAG_LOAD_RANDKEY = (1 << 0),
-
- /* Scratch buffer page table is present */
- S3_FLAG_SCRATCH_BUFFER_TABLE = (1 << 1),
-
- /* Skip all memory verification */
- S3_FLAG_NO_MEM_VERIFY = (1 << 2),
-
- /*
- * Modification of this bit reserved for bootloader only.
- * 1=PSCI started Linux, 0=Direct jump to Linux.
- */
- S3_FLAG_PSCI_BOOT = (1 << 3),
-
- /*
- * Modification of this bit reserved for bootloader only.
- * 1=64 bit boot, 0=32 bit boot.
- */
- S3_FLAG_BOOTED64 = (1 << 4),
-};
-
-#define BRCMSTB_HASH_LEN (128 / 8) /* 128-bit hash */
-
-#define AON_REG_MAGIC_FLAGS 0x00
-#define AON_REG_CONTROL_LOW 0x04
-#define AON_REG_CONTROL_HIGH 0x08
-#define AON_REG_S3_HASH 0x0c /* hash of S3 params */
-#define AON_REG_CONTROL_HASH_LEN 0x1c
-#define AON_REG_PANIC 0x20
-
-#define BRCMSTB_S3_MAGIC 0x5AFEB007
-#define BRCMSTB_PANIC_MAGIC 0x512E115E
-#define BOOTLOADER_SCRATCH_SIZE 64
-#define BRCMSTB_DTU_STATE_MAP_ENTRIES (8*1024)
-#define BRCMSTB_DTU_CONFIG_ENTRIES (512)
-#define BRCMSTB_DTU_COUNT (2)
-
-#define IMAGE_DESCRIPTORS_BUFSIZE (2 * 1024)
-#define S3_BOOTLOADER_RESERVED (S3_FLAG_PSCI_BOOT | S3_FLAG_BOOTED64)
-
-struct brcmstb_bootloader_dtu_table {
- uint32_t dtu_state_map[BRCMSTB_DTU_STATE_MAP_ENTRIES];
- uint32_t dtu_config[BRCMSTB_DTU_CONFIG_ENTRIES];
-};
-
-/*
- * Bootloader utilizes a custom parameter block left in DRAM for handling S3
- * warm resume
- */
-struct brcmstb_s3_params {
- /* scratch memory for bootloader */
- uint8_t scratch[BOOTLOADER_SCRATCH_SIZE];
-
- uint32_t magic; /* BRCMSTB_S3_MAGIC */
- uint64_t reentry; /* PA */
-
- /* descriptors */
- uint32_t hash[BRCMSTB_HASH_LEN / 4];
-
- /*
- * If 0, then ignore this parameter (there is only one set of
- * descriptors)
- *
- * If non-0, then a second set of descriptors is stored at:
- *
- * descriptors + desc_offset_2
- *
- * The MAC result of both descriptors is XOR'd and stored in @hash
- */
- uint32_t desc_offset_2;
-
- /*
- * (Physical) address of a brcmstb_bootloader_scratch_table, for
- * providing a large DRAM buffer to the bootloader
- */
- uint64_t buffer_table;
-
- uint32_t spare[70];
-
- uint8_t descriptors[IMAGE_DESCRIPTORS_BUFSIZE];
- /*
- * Must be last member of struct. See brcmstb_pm_s3_finish() for reason.
- */
- struct brcmstb_bootloader_dtu_table dtu[BRCMSTB_DTU_COUNT];
-} __packed;
-
-#endif /* __BRCMSTB_AON_DEFS_H__ */
diff --git a/drivers/soc/bcm/brcmstb/pm/pm-arm.c b/drivers/soc/bcm/brcmstb/pm/pm-arm.c
deleted file mode 100644
index d681cd24c6e1..000000000000
--- a/drivers/soc/bcm/brcmstb/pm/pm-arm.c
+++ /dev/null
@@ -1,874 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * ARM-specific support for Broadcom STB S2/S3/S5 power management
- *
- * S2: clock gate CPUs and as many peripherals as possible
- * S3: power off all of the chip except the Always ON (AON) island; keep DDR is
- * self-refresh
- * S5: (a.k.a. S3 cold boot) much like S3, except DDR is powered down, so we
- * treat this mode like a soft power-off, with wakeup allowed from AON
- *
- * Copyright © 2014-2017 Broadcom
- */
-
-#define pr_fmt(fmt) "brcmstb-pm: " fmt
-
-#include <linux/bitops.h>
-#include <linux/compiler.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/kconfig.h>
-#include <linux/kernel.h>
-#include <linux/memblock.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/panic_notifier.h>
-#include <linux/platform_device.h>
-#include <linux/pm.h>
-#include <linux/printk.h>
-#include <linux/proc_fs.h>
-#include <linux/sizes.h>
-#include <linux/slab.h>
-#include <linux/sort.h>
-#include <linux/suspend.h>
-#include <linux/types.h>
-#include <linux/uaccess.h>
-#include <linux/soc/brcmstb/brcmstb.h>
-
-#include <asm/fncpy.h>
-#include <asm/setup.h>
-#include <asm/suspend.h>
-
-#include "pm.h"
-#include "aon_defs.h"
-
-#define SHIMPHY_DDR_PAD_CNTRL 0x8c
-
-/* Method #0 */
-#define SHIMPHY_PAD_PLL_SEQUENCE BIT(8)
-#define SHIMPHY_PAD_GATE_PLL_S3 BIT(9)
-
-/* Method #1 */
-#define PWRDWN_SEQ_NO_SEQUENCING 0
-#define PWRDWN_SEQ_HOLD_CHANNEL 1
-#define PWRDWN_SEQ_RESET_PLL 2
-#define PWRDWN_SEQ_POWERDOWN_PLL 3
-
-#define SHIMPHY_PAD_S3_PWRDWN_SEQ_MASK 0x00f00000
-#define SHIMPHY_PAD_S3_PWRDWN_SEQ_SHIFT 20
-
-#define DDR_FORCE_CKE_RST_N BIT(3)
-#define DDR_PHY_RST_N BIT(2)
-#define DDR_PHY_CKE BIT(1)
-
-#define DDR_PHY_NO_CHANNEL 0xffffffff
-
-#define MAX_NUM_MEMC 3
-
-struct brcmstb_memc {
- void __iomem *ddr_phy_base;
- void __iomem *ddr_shimphy_base;
- void __iomem *ddr_ctrl;
-};
-
-struct brcmstb_pm_control {
- void __iomem *aon_ctrl_base;
- void __iomem *aon_sram;
- struct brcmstb_memc memcs[MAX_NUM_MEMC];
-
- void __iomem *boot_sram;
- size_t boot_sram_len;
-
- bool support_warm_boot;
- size_t pll_status_offset;
- int num_memc;
-
- struct brcmstb_s3_params *s3_params;
- dma_addr_t s3_params_pa;
- int s3entry_method;
- u32 warm_boot_offset;
- u32 phy_a_standby_ctrl_offs;
- u32 phy_b_standby_ctrl_offs;
- bool needs_ddr_pad;
- struct platform_device *pdev;
-};
-
-enum bsp_initiate_command {
- BSP_CLOCK_STOP = 0x00,
- BSP_GEN_RANDOM_KEY = 0x4A,
- BSP_RESTORE_RANDOM_KEY = 0x55,
- BSP_GEN_FIXED_KEY = 0x63,
-};
-
-#define PM_INITIATE 0x01
-#define PM_INITIATE_SUCCESS 0x00
-#define PM_INITIATE_FAIL 0xfe
-
-static struct brcmstb_pm_control ctrl;
-
-noinline int brcmstb_pm_s3_finish(void);
-
-static int (*brcmstb_pm_do_s2_sram)(void __iomem *aon_ctrl_base,
- void __iomem *ddr_phy_pll_status);
-
-static int brcmstb_init_sram(struct device_node *dn)
-{
- void __iomem *sram;
- struct resource res;
- int ret;
-
- ret = of_address_to_resource(dn, 0, &res);
- if (ret)
- return ret;
-
- /* Uncached, executable remapping of SRAM */
- sram = __arm_ioremap_exec(res.start, resource_size(&res), false);
- if (!sram)
- return -ENOMEM;
-
- ctrl.boot_sram = sram;
- ctrl.boot_sram_len = resource_size(&res);
-
- return 0;
-}
-
-static const struct of_device_id sram_dt_ids[] = {
- { .compatible = "mmio-sram" },
- { /* sentinel */ }
-};
-
-static int do_bsp_initiate_command(enum bsp_initiate_command cmd)
-{
- void __iomem *base = ctrl.aon_ctrl_base;
- int ret;
- int timeo = 1000 * 1000; /* 1 second */
-
- writel_relaxed(0, base + AON_CTRL_PM_INITIATE);
- (void)readl_relaxed(base + AON_CTRL_PM_INITIATE);
-
- /* Go! */
- writel_relaxed((cmd << 1) | PM_INITIATE, base + AON_CTRL_PM_INITIATE);
-
- /*
- * If firmware doesn't support the 'ack', then just assume it's done
- * after 10ms. Note that this only works for command 0, BSP_CLOCK_STOP
- */
- if (of_machine_is_compatible("brcm,bcm74371a0")) {
- (void)readl_relaxed(base + AON_CTRL_PM_INITIATE);
- mdelay(10);
- return 0;
- }
-
- for (;;) {
- ret = readl_relaxed(base + AON_CTRL_PM_INITIATE);
- if (!(ret & PM_INITIATE))
- break;
- if (timeo <= 0) {
- pr_err("error: timeout waiting for BSP (%x)\n", ret);
- break;
- }
- timeo -= 50;
- udelay(50);
- }
-
- return (ret & 0xff) != PM_INITIATE_SUCCESS;
-}
-
-static int brcmstb_pm_handshake(void)
-{
- void __iomem *base = ctrl.aon_ctrl_base;
- u32 tmp;
- int ret;
-
- /* BSP power handshake, v1 */
- tmp = readl_relaxed(base + AON_CTRL_HOST_MISC_CMDS);
- tmp &= ~1UL;
- writel_relaxed(tmp, base + AON_CTRL_HOST_MISC_CMDS);
- (void)readl_relaxed(base + AON_CTRL_HOST_MISC_CMDS);
-
- ret = do_bsp_initiate_command(BSP_CLOCK_STOP);
- if (ret)
- pr_err("BSP handshake failed\n");
-
- /*
- * HACK: BSP may have internal race on the CLOCK_STOP command.
- * Avoid touching the BSP for a few milliseconds.
- */
- mdelay(3);
-
- return ret;
-}
-
-static inline void shimphy_set(u32 value, u32 mask)
-{
- int i;
-
- if (!ctrl.needs_ddr_pad)
- return;
-
- for (i = 0; i < ctrl.num_memc; i++) {
- u32 tmp;
-
- tmp = readl_relaxed(ctrl.memcs[i].ddr_shimphy_base +
- SHIMPHY_DDR_PAD_CNTRL);
- tmp = value | (tmp & mask);
- writel_relaxed(tmp, ctrl.memcs[i].ddr_shimphy_base +
- SHIMPHY_DDR_PAD_CNTRL);
- }
- wmb(); /* Complete sequence in order. */
-}
-
-static inline void ddr_ctrl_set(bool warmboot)
-{
- int i;
-
- for (i = 0; i < ctrl.num_memc; i++) {
- u32 tmp;
-
- tmp = readl_relaxed(ctrl.memcs[i].ddr_ctrl +
- ctrl.warm_boot_offset);
- if (warmboot)
- tmp |= 1;
- else
- tmp &= ~1; /* Cold boot */
- writel_relaxed(tmp, ctrl.memcs[i].ddr_ctrl +
- ctrl.warm_boot_offset);
- }
- /* Complete sequence in order */
- wmb();
-}
-
-static inline void s3entry_method0(void)
-{
- shimphy_set(SHIMPHY_PAD_GATE_PLL_S3 | SHIMPHY_PAD_PLL_SEQUENCE,
- 0xffffffff);
-}
-
-static inline void s3entry_method1(void)
-{
- /*
- * S3 Entry Sequence
- * -----------------
- * Step 1: SHIMPHY_ADDR_CNTL_0_DDR_PAD_CNTRL [ S3_PWRDWN_SEQ ] = 3
- * Step 2: MEMC_DDR_0_WARM_BOOT [ WARM_BOOT ] = 1
- */
- shimphy_set((PWRDWN_SEQ_POWERDOWN_PLL <<
- SHIMPHY_PAD_S3_PWRDWN_SEQ_SHIFT),
- ~SHIMPHY_PAD_S3_PWRDWN_SEQ_MASK);
-
- ddr_ctrl_set(true);
-}
-
-static inline void s5entry_method1(void)
-{
- int i;
-
- /*
- * S5 Entry Sequence
- * -----------------
- * Step 1: SHIMPHY_ADDR_CNTL_0_DDR_PAD_CNTRL [ S3_PWRDWN_SEQ ] = 3
- * Step 2: MEMC_DDR_0_WARM_BOOT [ WARM_BOOT ] = 0
- * Step 3: DDR_PHY_CONTROL_REGS_[AB]_0_STANDBY_CONTROL[ CKE ] = 0
- * DDR_PHY_CONTROL_REGS_[AB]_0_STANDBY_CONTROL[ RST_N ] = 0
- */
- shimphy_set((PWRDWN_SEQ_POWERDOWN_PLL <<
- SHIMPHY_PAD_S3_PWRDWN_SEQ_SHIFT),
- ~SHIMPHY_PAD_S3_PWRDWN_SEQ_MASK);
-
- ddr_ctrl_set(false);
-
- for (i = 0; i < ctrl.num_memc; i++) {
- u32 tmp;
-
- /* Step 3: Channel A (RST_N = CKE = 0) */
- tmp = readl_relaxed(ctrl.memcs[i].ddr_phy_base +
- ctrl.phy_a_standby_ctrl_offs);
- tmp &= ~(DDR_PHY_RST_N | DDR_PHY_RST_N);
- writel_relaxed(tmp, ctrl.memcs[i].ddr_phy_base +
- ctrl.phy_a_standby_ctrl_offs);
-
- /* Step 3: Channel B? */
- if (ctrl.phy_b_standby_ctrl_offs != DDR_PHY_NO_CHANNEL) {
- tmp = readl_relaxed(ctrl.memcs[i].ddr_phy_base +
- ctrl.phy_b_standby_ctrl_offs);
- tmp &= ~(DDR_PHY_RST_N | DDR_PHY_RST_N);
- writel_relaxed(tmp, ctrl.memcs[i].ddr_phy_base +
- ctrl.phy_b_standby_ctrl_offs);
- }
- }
- /* Must complete */
- wmb();
-}
-
-/*
- * Run a Power Management State Machine (PMSM) shutdown command and put the CPU
- * into a low-power mode
- */
-static void brcmstb_do_pmsm_power_down(unsigned long base_cmd, bool onewrite)
-{
- void __iomem *base = ctrl.aon_ctrl_base;
-
- if ((ctrl.s3entry_method == 1) && (base_cmd == PM_COLD_CONFIG))
- s5entry_method1();
-
- /* pm_start_pwrdn transition 0->1 */
- writel_relaxed(base_cmd, base + AON_CTRL_PM_CTRL);
-
- if (!onewrite) {
- (void)readl_relaxed(base + AON_CTRL_PM_CTRL);
-
- writel_relaxed(base_cmd | PM_PWR_DOWN, base + AON_CTRL_PM_CTRL);
- (void)readl_relaxed(base + AON_CTRL_PM_CTRL);
- }
- wfi();
-}
-
-/* Support S5 cold boot out of "poweroff" */
-static void brcmstb_pm_poweroff(void)
-{
- brcmstb_pm_handshake();
-
- /* Clear magic S3 warm-boot value */
- writel_relaxed(0, ctrl.aon_sram + AON_REG_MAGIC_FLAGS);
- (void)readl_relaxed(ctrl.aon_sram + AON_REG_MAGIC_FLAGS);
-
- /* Skip wait-for-interrupt signal; just use a countdown */
- writel_relaxed(0x10, ctrl.aon_ctrl_base + AON_CTRL_PM_CPU_WAIT_COUNT);
- (void)readl_relaxed(ctrl.aon_ctrl_base + AON_CTRL_PM_CPU_WAIT_COUNT);
-
- if (ctrl.s3entry_method == 1) {
- shimphy_set((PWRDWN_SEQ_POWERDOWN_PLL <<
- SHIMPHY_PAD_S3_PWRDWN_SEQ_SHIFT),
- ~SHIMPHY_PAD_S3_PWRDWN_SEQ_MASK);
- ddr_ctrl_set(false);
- brcmstb_do_pmsm_power_down(M1_PM_COLD_CONFIG, true);
- return; /* We should never actually get here */
- }
-
- brcmstb_do_pmsm_power_down(PM_COLD_CONFIG, false);
-}
-
-static void *brcmstb_pm_copy_to_sram(void *fn, size_t len)
-{
- unsigned int size = ALIGN(len, FNCPY_ALIGN);
-
- if (ctrl.boot_sram_len < size) {
- pr_err("standby code will not fit in SRAM\n");
- return NULL;
- }
-
- return fncpy(ctrl.boot_sram, fn, size);
-}
-
-/*
- * S2 suspend/resume picks up where we left off, so we must execute carefully
- * from SRAM, in order to allow DDR to come back up safely before we continue.
- */
-static int brcmstb_pm_s2(void)
-{
- /* A previous S3 can set a value hazardous to S2, so make sure. */
- if (ctrl.s3entry_method == 1) {
- shimphy_set((PWRDWN_SEQ_NO_SEQUENCING <<
- SHIMPHY_PAD_S3_PWRDWN_SEQ_SHIFT),
- ~SHIMPHY_PAD_S3_PWRDWN_SEQ_MASK);
- ddr_ctrl_set(false);
- }
-
- brcmstb_pm_do_s2_sram = brcmstb_pm_copy_to_sram(&brcmstb_pm_do_s2,
- brcmstb_pm_do_s2_sz);
- if (!brcmstb_pm_do_s2_sram)
- return -EINVAL;
-
- return brcmstb_pm_do_s2_sram(ctrl.aon_ctrl_base,
- ctrl.memcs[0].ddr_phy_base +
- ctrl.pll_status_offset);
-}
-
-/*
- * This function is called on a new stack, so don't allow inlining (which will
- * generate stack references on the old stack). It cannot be made static because
- * it is referenced from brcmstb_pm_s3()
- */
-noinline int brcmstb_pm_s3_finish(void)
-{
- struct brcmstb_s3_params *params = ctrl.s3_params;
- dma_addr_t params_pa = ctrl.s3_params_pa;
- phys_addr_t reentry = virt_to_phys(&cpu_resume_arm);
- enum bsp_initiate_command cmd;
- u32 flags;
-
- /*
- * Clear parameter structure, but not DTU area, which has already been
- * filled in. We know DTU is a the end, so we can just subtract its
- * size.
- */
- memset(params, 0, sizeof(*params) - sizeof(params->dtu));
-
- flags = readl_relaxed(ctrl.aon_sram + AON_REG_MAGIC_FLAGS);
-
- flags &= S3_BOOTLOADER_RESERVED;
- flags |= S3_FLAG_NO_MEM_VERIFY;
- flags |= S3_FLAG_LOAD_RANDKEY;
-
- /* Load random / fixed key */
- if (flags & S3_FLAG_LOAD_RANDKEY)
- cmd = BSP_GEN_RANDOM_KEY;
- else
- cmd = BSP_GEN_FIXED_KEY;
- if (do_bsp_initiate_command(cmd)) {
- pr_info("key loading failed\n");
- return -EIO;
- }
-
- params->magic = BRCMSTB_S3_MAGIC;
- params->reentry = reentry;
-
- /* No more writes to DRAM */
- flush_cache_all();
-
- flags |= BRCMSTB_S3_MAGIC_SHORT;
-
- writel_relaxed(flags, ctrl.aon_sram + AON_REG_MAGIC_FLAGS);
- writel_relaxed(lower_32_bits(params_pa),
- ctrl.aon_sram + AON_REG_CONTROL_LOW);
- writel_relaxed(upper_32_bits(params_pa),
- ctrl.aon_sram + AON_REG_CONTROL_HIGH);
-
- switch (ctrl.s3entry_method) {
- case 0:
- s3entry_method0();
- brcmstb_do_pmsm_power_down(PM_WARM_CONFIG, false);
- break;
- case 1:
- s3entry_method1();
- brcmstb_do_pmsm_power_down(M1_PM_WARM_CONFIG, true);
- break;
- default:
- return -EINVAL;
- }
-
- /* Must have been interrupted from wfi()? */
- return -EINTR;
-}
-
-static int brcmstb_pm_do_s3(unsigned long sp)
-{
- unsigned long save_sp;
- int ret;
-
- asm volatile (
- "mov %[save], sp\n"
- "mov sp, %[new]\n"
- "bl brcmstb_pm_s3_finish\n"
- "mov %[ret], r0\n"
- "mov %[new], sp\n"
- "mov sp, %[save]\n"
- : [save] "=&r" (save_sp), [ret] "=&r" (ret)
- : [new] "r" (sp)
- );
-
- return ret;
-}
-
-static int brcmstb_pm_s3(void)
-{
- void __iomem *sp = ctrl.boot_sram + ctrl.boot_sram_len;
-
- return cpu_suspend((unsigned long)sp, brcmstb_pm_do_s3);
-}
-
-static int brcmstb_pm_standby(bool deep_standby)
-{
- int ret;
-
- if (brcmstb_pm_handshake())
- return -EIO;
-
- if (deep_standby)
- ret = brcmstb_pm_s3();
- else
- ret = brcmstb_pm_s2();
- if (ret)
- pr_err("%s: standby failed\n", __func__);
-
- return ret;
-}
-
-static int brcmstb_pm_enter(suspend_state_t state)
-{
- int ret = -EINVAL;
-
- switch (state) {
- case PM_SUSPEND_STANDBY:
- ret = brcmstb_pm_standby(false);
- break;
- case PM_SUSPEND_MEM:
- ret = brcmstb_pm_standby(true);
- break;
- }
-
- return ret;
-}
-
-static int brcmstb_pm_valid(suspend_state_t state)
-{
- switch (state) {
- case PM_SUSPEND_STANDBY:
- return true;
- case PM_SUSPEND_MEM:
- return ctrl.support_warm_boot;
- default:
- return false;
- }
-}
-
-static const struct platform_suspend_ops brcmstb_pm_ops = {
- .enter = brcmstb_pm_enter,
- .valid = brcmstb_pm_valid,
-};
-
-static const struct of_device_id aon_ctrl_dt_ids[] = {
- { .compatible = "brcm,brcmstb-aon-ctrl" },
- {}
-};
-
-struct ddr_phy_ofdata {
- bool supports_warm_boot;
- size_t pll_status_offset;
- int s3entry_method;
- u32 warm_boot_offset;
- u32 phy_a_standby_ctrl_offs;
- u32 phy_b_standby_ctrl_offs;
-};
-
-static struct ddr_phy_ofdata ddr_phy_71_1 = {
- .supports_warm_boot = true,
- .pll_status_offset = 0x0c,
- .s3entry_method = 1,
- .warm_boot_offset = 0x2c,
- .phy_a_standby_ctrl_offs = 0x198,
- .phy_b_standby_ctrl_offs = DDR_PHY_NO_CHANNEL
-};
-
-static struct ddr_phy_ofdata ddr_phy_72_0 = {
- .supports_warm_boot = true,
- .pll_status_offset = 0x10,
- .s3entry_method = 1,
- .warm_boot_offset = 0x40,
- .phy_a_standby_ctrl_offs = 0x2a4,
- .phy_b_standby_ctrl_offs = 0x8a4
-};
-
-static struct ddr_phy_ofdata ddr_phy_225_1 = {
- .supports_warm_boot = false,
- .pll_status_offset = 0x4,
- .s3entry_method = 0
-};
-
-static struct ddr_phy_ofdata ddr_phy_240_1 = {
- .supports_warm_boot = true,
- .pll_status_offset = 0x4,
- .s3entry_method = 0
-};
-
-static const struct of_device_id ddr_phy_dt_ids[] = {
- {
- .compatible = "brcm,brcmstb-ddr-phy-v71.1",
- .data = &ddr_phy_71_1,
- },
- {
- .compatible = "brcm,brcmstb-ddr-phy-v72.0",
- .data = &ddr_phy_72_0,
- },
- {
- .compatible = "brcm,brcmstb-ddr-phy-v225.1",
- .data = &ddr_phy_225_1,
- },
- {
- .compatible = "brcm,brcmstb-ddr-phy-v240.1",
- .data = &ddr_phy_240_1,
- },
- {
- /* Same as v240.1, for the registers we care about */
- .compatible = "brcm,brcmstb-ddr-phy-v240.2",
- .data = &ddr_phy_240_1,
- },
- {}
-};
-
-struct ddr_seq_ofdata {
- bool needs_ddr_pad;
- u32 warm_boot_offset;
-};
-
-static const struct ddr_seq_ofdata ddr_seq_b22 = {
- .needs_ddr_pad = false,
- .warm_boot_offset = 0x2c,
-};
-
-static const struct ddr_seq_ofdata ddr_seq = {
- .needs_ddr_pad = true,
-};
-
-static const struct of_device_id ddr_shimphy_dt_ids[] = {
- { .compatible = "brcm,brcmstb-ddr-shimphy-v1.0" },
- {}
-};
-
-static const struct of_device_id brcmstb_memc_of_match[] = {
- {
- .compatible = "brcm,brcmstb-memc-ddr-rev-b.2.1",
- .data = &ddr_seq,
- },
- {
- .compatible = "brcm,brcmstb-memc-ddr-rev-b.2.2",
- .data = &ddr_seq_b22,
- },
- {
- .compatible = "brcm,brcmstb-memc-ddr-rev-b.2.3",
- .data = &ddr_seq_b22,
- },
- {
- .compatible = "brcm,brcmstb-memc-ddr-rev-b.3.0",
- .data = &ddr_seq_b22,
- },
- {
- .compatible = "brcm,brcmstb-memc-ddr-rev-b.3.1",
- .data = &ddr_seq_b22,
- },
- {
- .compatible = "brcm,brcmstb-memc-ddr",
- .data = &ddr_seq,
- },
- {},
-};
-
-static void __iomem *brcmstb_ioremap_match(const struct of_device_id *matches,
- int index, const void **ofdata)
-{
- struct device_node *dn;
- const struct of_device_id *match;
-
- dn = of_find_matching_node_and_match(NULL, matches, &match);
- if (!dn)
- return ERR_PTR(-EINVAL);
-
- if (ofdata)
- *ofdata = match->data;
-
- return of_io_request_and_map(dn, index, dn->full_name);
-}
-/*
- * The AON is a small domain in the SoC that can retain its state across
- * various system wide sleep states and specific reset conditions; the
- * AON DATA RAM is a small RAM of a few words (< 1KB) which can store
- * persistent information across such events.
- *
- * The purpose of the below panic notifier is to help with notifying
- * the bootloader that a panic occurred and so that it should try its
- * best to preserve the DRAM contents holding that buffer for recovery
- * by the kernel as opposed to wiping out DRAM clean again.
- *
- * Reference: comment from Florian Fainelli, at
- * https://lore.kernel.org/lkml/781cafb0-8d06-8b56-907a-5175c2da196a@gmail.com
- */
-static int brcmstb_pm_panic_notify(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- writel_relaxed(BRCMSTB_PANIC_MAGIC, ctrl.aon_sram + AON_REG_PANIC);
-
- return NOTIFY_DONE;
-}
-
-static struct notifier_block brcmstb_pm_panic_nb = {
- .notifier_call = brcmstb_pm_panic_notify,
-};
-
-static int brcmstb_pm_probe(struct platform_device *pdev)
-{
- const struct ddr_phy_ofdata *ddr_phy_data;
- const struct ddr_seq_ofdata *ddr_seq_data;
- const struct of_device_id *of_id = NULL;
- struct device_node *dn;
- void __iomem *base;
- int ret, i, s;
-
- /* AON ctrl registers */
- base = brcmstb_ioremap_match(aon_ctrl_dt_ids, 0, NULL);
- if (IS_ERR(base)) {
- pr_err("error mapping AON_CTRL\n");
- ret = PTR_ERR(base);
- goto aon_err;
- }
- ctrl.aon_ctrl_base = base;
-
- /* AON SRAM registers */
- base = brcmstb_ioremap_match(aon_ctrl_dt_ids, 1, NULL);
- if (IS_ERR(base)) {
- /* Assume standard offset */
- ctrl.aon_sram = ctrl.aon_ctrl_base +
- AON_CTRL_SYSTEM_DATA_RAM_OFS;
- s = 0;
- } else {
- ctrl.aon_sram = base;
- s = 1;
- }
-
- writel_relaxed(0, ctrl.aon_sram + AON_REG_PANIC);
-
- /* DDR PHY registers */
- base = brcmstb_ioremap_match(ddr_phy_dt_ids, 0,
- (const void **)&ddr_phy_data);
- if (IS_ERR(base)) {
- pr_err("error mapping DDR PHY\n");
- ret = PTR_ERR(base);
- goto ddr_phy_err;
- }
- ctrl.support_warm_boot = ddr_phy_data->supports_warm_boot;
- ctrl.pll_status_offset = ddr_phy_data->pll_status_offset;
- /* Only need DDR PHY 0 for now? */
- ctrl.memcs[0].ddr_phy_base = base;
- ctrl.s3entry_method = ddr_phy_data->s3entry_method;
- ctrl.phy_a_standby_ctrl_offs = ddr_phy_data->phy_a_standby_ctrl_offs;
- ctrl.phy_b_standby_ctrl_offs = ddr_phy_data->phy_b_standby_ctrl_offs;
- /*
- * Slightly gross to use the phy ver to get a memc,
- * offset but that is the only versioned things so far
- * we can test for.
- */
- ctrl.warm_boot_offset = ddr_phy_data->warm_boot_offset;
-
- /* DDR SHIM-PHY registers */
- for_each_matching_node(dn, ddr_shimphy_dt_ids) {
- i = ctrl.num_memc;
- if (i >= MAX_NUM_MEMC) {
- of_node_put(dn);
- pr_warn("too many MEMCs (max %d)\n", MAX_NUM_MEMC);
- break;
- }
-
- base = of_io_request_and_map(dn, 0, dn->full_name);
- if (IS_ERR(base)) {
- of_node_put(dn);
- if (!ctrl.support_warm_boot)
- break;
-
- pr_err("error mapping DDR SHIMPHY %d\n", i);
- ret = PTR_ERR(base);
- goto ddr_shimphy_err;
- }
- ctrl.memcs[i].ddr_shimphy_base = base;
- ctrl.num_memc++;
- }
-
- /* Sequencer DRAM Param and Control Registers */
- i = 0;
- for_each_matching_node(dn, brcmstb_memc_of_match) {
- base = of_iomap(dn, 0);
- if (!base) {
- of_node_put(dn);
- pr_err("error mapping DDR Sequencer %d\n", i);
- ret = -ENOMEM;
- goto brcmstb_memc_err;
- }
-
- of_id = of_match_node(brcmstb_memc_of_match, dn);
- if (!of_id) {
- iounmap(base);
- of_node_put(dn);
- ret = -EINVAL;
- goto brcmstb_memc_err;
- }
-
- ddr_seq_data = of_id->data;
- ctrl.needs_ddr_pad = ddr_seq_data->needs_ddr_pad;
- /* Adjust warm boot offset based on the DDR sequencer */
- if (ddr_seq_data->warm_boot_offset)
- ctrl.warm_boot_offset = ddr_seq_data->warm_boot_offset;
-
- ctrl.memcs[i].ddr_ctrl = base;
- i++;
- }
-
- pr_debug("PM: supports warm boot:%d, method:%d, wboffs:%x\n",
- ctrl.support_warm_boot, ctrl.s3entry_method,
- ctrl.warm_boot_offset);
-
- dn = of_find_matching_node(NULL, sram_dt_ids);
- if (!dn) {
- pr_err("SRAM not found\n");
- ret = -EINVAL;
- goto brcmstb_memc_err;
- }
-
- ret = brcmstb_init_sram(dn);
- of_node_put(dn);
- if (ret) {
- pr_err("error setting up SRAM for PM\n");
- goto brcmstb_memc_err;
- }
-
- ctrl.pdev = pdev;
-
- ctrl.s3_params = kmalloc(sizeof(*ctrl.s3_params), GFP_KERNEL);
- if (!ctrl.s3_params) {
- ret = -ENOMEM;
- goto s3_params_err;
- }
- ctrl.s3_params_pa = dma_map_single(&pdev->dev, ctrl.s3_params,
- sizeof(*ctrl.s3_params),
- DMA_TO_DEVICE);
- if (dma_mapping_error(&pdev->dev, ctrl.s3_params_pa)) {
- pr_err("error mapping DMA memory\n");
- ret = -ENOMEM;
- goto out;
- }
-
- atomic_notifier_chain_register(&panic_notifier_list,
- &brcmstb_pm_panic_nb);
-
- pm_power_off = brcmstb_pm_poweroff;
- suspend_set_ops(&brcmstb_pm_ops);
-
- return 0;
-
-out:
- kfree(ctrl.s3_params);
-s3_params_err:
- iounmap(ctrl.boot_sram);
-brcmstb_memc_err:
- for (i--; i >= 0; i--)
- iounmap(ctrl.memcs[i].ddr_ctrl);
-ddr_shimphy_err:
- for (i = 0; i < ctrl.num_memc; i++)
- iounmap(ctrl.memcs[i].ddr_shimphy_base);
-
- iounmap(ctrl.memcs[0].ddr_phy_base);
-ddr_phy_err:
- iounmap(ctrl.aon_ctrl_base);
- if (s)
- iounmap(ctrl.aon_sram);
-aon_err:
- pr_warn("PM: initialization failed with code %d\n", ret);
-
- return ret;
-}
-
-static struct platform_driver brcmstb_pm_driver = {
- .driver = {
- .name = "brcmstb-pm",
- .of_match_table = aon_ctrl_dt_ids,
- },
-};
-
-static int __init brcmstb_pm_init(void)
-{
- return platform_driver_probe(&brcmstb_pm_driver,
- brcmstb_pm_probe);
-}
-module_init(brcmstb_pm_init);
diff --git a/drivers/soc/bcm/brcmstb/pm/pm.h b/drivers/soc/bcm/brcmstb/pm/pm.h
index 94a380470a2f..17f7a06a7a83 100644
--- a/drivers/soc/bcm/brcmstb/pm/pm.h
+++ b/drivers/soc/bcm/brcmstb/pm/pm.h
@@ -60,7 +60,7 @@
PM_DEEP_STANDBY | \
PM_PLL_PWRDOWN | PM_PWR_DOWN)
-#ifndef __ASSEMBLY__
+#ifndef __ASSEMBLER__
#ifndef CONFIG_MIPS
extern const unsigned long brcmstb_pm_do_s2_sz;
diff --git a/drivers/soc/bcm/brcmstb/pm/s2-arm.S b/drivers/soc/bcm/brcmstb/pm/s2-arm.S
deleted file mode 100644
index 0d693795de27..000000000000
--- a/drivers/soc/bcm/brcmstb/pm/s2-arm.S
+++ /dev/null
@@ -1,69 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright © 2014-2017 Broadcom
- */
-
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-
-#include "pm.h"
-
- .arch armv7-a
- .text
- .align 3
-
-#define AON_CTRL_REG r10
-#define DDR_PHY_STATUS_REG r11
-
-/*
- * r0: AON_CTRL base address
- * r1: DDRY PHY PLL status register address
- */
-ENTRY(brcmstb_pm_do_s2)
- stmfd sp!, {r4-r11, lr}
- mov AON_CTRL_REG, r0
- mov DDR_PHY_STATUS_REG, r1
-
- /* Flush memory transactions */
- dsb
-
- /* Cache DDR_PHY_STATUS_REG translation */
- ldr r0, [DDR_PHY_STATUS_REG]
-
- /* power down request */
- ldr r0, =PM_S2_COMMAND
- ldr r1, =0
- str r1, [AON_CTRL_REG, #AON_CTRL_PM_CTRL]
- ldr r1, [AON_CTRL_REG, #AON_CTRL_PM_CTRL]
- str r0, [AON_CTRL_REG, #AON_CTRL_PM_CTRL]
- ldr r0, [AON_CTRL_REG, #AON_CTRL_PM_CTRL]
-
- /* Wait for interrupt */
- wfi
- nop
-
- /* Bring MEMC back up */
-1: ldr r0, [DDR_PHY_STATUS_REG]
- ands r0, #1
- beq 1b
-
- /* Power-up handshake */
- ldr r0, =1
- str r0, [AON_CTRL_REG, #AON_CTRL_HOST_MISC_CMDS]
- ldr r0, [AON_CTRL_REG, #AON_CTRL_HOST_MISC_CMDS]
-
- ldr r0, =0
- str r0, [AON_CTRL_REG, #AON_CTRL_PM_CTRL]
- ldr r0, [AON_CTRL_REG, #AON_CTRL_PM_CTRL]
-
- /* Return to caller */
- ldr r0, =0
- ldmfd sp!, {r4-r11, pc}
-
- ENDPROC(brcmstb_pm_do_s2)
-
- /* Place literal pool here */
- .ltorg
-
-ENTRY(brcmstb_pm_do_s2_sz)
- .word . - brcmstb_pm_do_s2
diff --git a/drivers/soc/bcm/raspberrypi-power.c b/drivers/soc/bcm/raspberrypi-power.c
deleted file mode 100644
index 068715d6e66d..000000000000
--- a/drivers/soc/bcm/raspberrypi-power.c
+++ /dev/null
@@ -1,246 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* (C) 2015 Pengutronix, Alexander Aring <aar@pengutronix.de>
- *
- * Authors:
- * Alexander Aring <aar@pengutronix.de>
- * Eric Anholt <eric@anholt.net>
- */
-
-#include <linux/module.h>
-#include <linux/of_platform.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <dt-bindings/power/raspberrypi-power.h>
-#include <soc/bcm2835/raspberrypi-firmware.h>
-
-/*
- * Firmware indices for the old power domains interface. Only a few
- * of them were actually implemented.
- */
-#define RPI_OLD_POWER_DOMAIN_USB 3
-#define RPI_OLD_POWER_DOMAIN_V3D 10
-
-struct rpi_power_domain {
- u32 domain;
- bool enabled;
- bool old_interface;
- struct generic_pm_domain base;
- struct rpi_firmware *fw;
-};
-
-struct rpi_power_domains {
- bool has_new_interface;
- struct genpd_onecell_data xlate;
- struct rpi_firmware *fw;
- struct rpi_power_domain domains[RPI_POWER_DOMAIN_COUNT];
-};
-
-/*
- * Packet definition used by RPI_FIRMWARE_SET_POWER_STATE and
- * RPI_FIRMWARE_SET_DOMAIN_STATE
- */
-struct rpi_power_domain_packet {
- u32 domain;
- u32 on;
-};
-
-/*
- * Asks the firmware to enable or disable power on a specific power
- * domain.
- */
-static int rpi_firmware_set_power(struct rpi_power_domain *rpi_domain, bool on)
-{
- struct rpi_power_domain_packet packet;
-
- packet.domain = rpi_domain->domain;
- packet.on = on;
- return rpi_firmware_property(rpi_domain->fw,
- rpi_domain->old_interface ?
- RPI_FIRMWARE_SET_POWER_STATE :
- RPI_FIRMWARE_SET_DOMAIN_STATE,
- &packet, sizeof(packet));
-}
-
-static int rpi_domain_off(struct generic_pm_domain *domain)
-{
- struct rpi_power_domain *rpi_domain =
- container_of(domain, struct rpi_power_domain, base);
-
- return rpi_firmware_set_power(rpi_domain, false);
-}
-
-static int rpi_domain_on(struct generic_pm_domain *domain)
-{
- struct rpi_power_domain *rpi_domain =
- container_of(domain, struct rpi_power_domain, base);
-
- return rpi_firmware_set_power(rpi_domain, true);
-}
-
-static void rpi_common_init_power_domain(struct rpi_power_domains *rpi_domains,
- int xlate_index, const char *name)
-{
- struct rpi_power_domain *dom = &rpi_domains->domains[xlate_index];
-
- dom->fw = rpi_domains->fw;
-
- dom->base.name = name;
- dom->base.power_on = rpi_domain_on;
- dom->base.power_off = rpi_domain_off;
-
- /*
- * Treat all power domains as off at boot.
- *
- * The firmware itself may be keeping some domains on, but
- * from Linux's perspective all we control is the refcounts
- * that we give to the firmware, and we can't ask the firmware
- * to turn off something that we haven't ourselves turned on.
- */
- pm_genpd_init(&dom->base, NULL, true);
-
- rpi_domains->xlate.domains[xlate_index] = &dom->base;
-}
-
-static void rpi_init_power_domain(struct rpi_power_domains *rpi_domains,
- int xlate_index, const char *name)
-{
- struct rpi_power_domain *dom = &rpi_domains->domains[xlate_index];
-
- if (!rpi_domains->has_new_interface)
- return;
-
- /* The DT binding index is the firmware's domain index minus one. */
- dom->domain = xlate_index + 1;
-
- rpi_common_init_power_domain(rpi_domains, xlate_index, name);
-}
-
-static void rpi_init_old_power_domain(struct rpi_power_domains *rpi_domains,
- int xlate_index, int domain,
- const char *name)
-{
- struct rpi_power_domain *dom = &rpi_domains->domains[xlate_index];
-
- dom->old_interface = true;
- dom->domain = domain;
-
- rpi_common_init_power_domain(rpi_domains, xlate_index, name);
-}
-
-/*
- * Detects whether the firmware supports the new power domains interface.
- *
- * The firmware doesn't actually return an error on an unknown tag,
- * and just skips over it, so we do the detection by putting an
- * unexpected value in the return field and checking if it was
- * unchanged.
- */
-static bool
-rpi_has_new_domain_support(struct rpi_power_domains *rpi_domains)
-{
- struct rpi_power_domain_packet packet;
- int ret;
-
- packet.domain = RPI_POWER_DOMAIN_ARM;
- packet.on = ~0;
-
- ret = rpi_firmware_property(rpi_domains->fw,
- RPI_FIRMWARE_GET_DOMAIN_STATE,
- &packet, sizeof(packet));
-
- return ret == 0 && packet.on != ~0;
-}
-
-static int rpi_power_probe(struct platform_device *pdev)
-{
- struct device_node *fw_np;
- struct device *dev = &pdev->dev;
- struct rpi_power_domains *rpi_domains;
-
- rpi_domains = devm_kzalloc(dev, sizeof(*rpi_domains), GFP_KERNEL);
- if (!rpi_domains)
- return -ENOMEM;
-
- rpi_domains->xlate.domains =
- devm_kcalloc(dev,
- RPI_POWER_DOMAIN_COUNT,
- sizeof(*rpi_domains->xlate.domains),
- GFP_KERNEL);
- if (!rpi_domains->xlate.domains)
- return -ENOMEM;
-
- rpi_domains->xlate.num_domains = RPI_POWER_DOMAIN_COUNT;
-
- fw_np = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
- if (!fw_np) {
- dev_err(&pdev->dev, "no firmware node\n");
- return -ENODEV;
- }
-
- rpi_domains->fw = devm_rpi_firmware_get(&pdev->dev, fw_np);
- of_node_put(fw_np);
- if (!rpi_domains->fw)
- return -EPROBE_DEFER;
-
- rpi_domains->has_new_interface =
- rpi_has_new_domain_support(rpi_domains);
-
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_I2C0, "I2C0");
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_I2C1, "I2C1");
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_I2C2, "I2C2");
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_VIDEO_SCALER,
- "VIDEO_SCALER");
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_VPU1, "VPU1");
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_HDMI, "HDMI");
-
- /*
- * Use the old firmware interface for USB power, so that we
- * can turn it on even if the firmware hasn't been updated.
- */
- rpi_init_old_power_domain(rpi_domains, RPI_POWER_DOMAIN_USB,
- RPI_OLD_POWER_DOMAIN_USB, "USB");
-
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_VEC, "VEC");
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_JPEG, "JPEG");
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_H264, "H264");
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_V3D, "V3D");
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_ISP, "ISP");
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_UNICAM0, "UNICAM0");
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_UNICAM1, "UNICAM1");
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CCP2RX, "CCP2RX");
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CSI2, "CSI2");
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CPI, "CPI");
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_DSI0, "DSI0");
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_DSI1, "DSI1");
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_TRANSPOSER,
- "TRANSPOSER");
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CCP2TX, "CCP2TX");
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CDP, "CDP");
- rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_ARM, "ARM");
-
- of_genpd_add_provider_onecell(dev->of_node, &rpi_domains->xlate);
-
- platform_set_drvdata(pdev, rpi_domains);
-
- return 0;
-}
-
-static const struct of_device_id rpi_power_of_match[] = {
- { .compatible = "raspberrypi,bcm2835-power", },
- {},
-};
-MODULE_DEVICE_TABLE(of, rpi_power_of_match);
-
-static struct platform_driver rpi_power_driver = {
- .driver = {
- .name = "raspberrypi-power",
- .of_match_table = rpi_power_of_match,
- },
- .probe = rpi_power_probe,
-};
-builtin_platform_driver(rpi_power_driver);
-
-MODULE_AUTHOR("Alexander Aring <aar@pengutronix.de>");
-MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
-MODULE_DESCRIPTION("Raspberry Pi power domain driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/canaan/Kconfig b/drivers/soc/canaan/Kconfig
index 2527cf5757ec..3121d351fea6 100644
--- a/drivers/soc/canaan/Kconfig
+++ b/drivers/soc/canaan/Kconfig
@@ -2,9 +2,10 @@
config SOC_K210_SYSCTL
bool "Canaan Kendryte K210 SoC system controller"
- depends on RISCV && SOC_CANAAN && OF
- default SOC_CANAAN
- select PM
- select MFD_SYSCON
+ depends on RISCV && SOC_CANAAN_K210 && OF
+ depends on COMMON_CLK_K210
+ default SOC_CANAAN_K210
+ select PM
+ select MFD_SYSCON
help
Canaan Kendryte K210 SoC system controller driver.
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/dove/pmu.c b/drivers/soc/dove/pmu.c
index ffc5311c0ed8..7bbd3f940e4d 100644
--- a/drivers/soc/dove/pmu.c
+++ b/drivers/soc/dove/pmu.c
@@ -257,10 +257,9 @@ static void pmu_irq_handler(struct irq_desc *desc)
* So, let's structure the code so that the window is as small as
* possible.
*/
- irq_gc_lock(gc);
+ guard(raw_spinlock)(&gc->lock);
done &= readl_relaxed(base + PMC_IRQ_CAUSE);
writel_relaxed(done, base + PMC_IRQ_CAUSE);
- irq_gc_unlock(gc);
}
static int __init dove_init_pmu_irq(struct pmu_data *pmu, int irq)
@@ -274,8 +273,8 @@ static int __init dove_init_pmu_irq(struct pmu_data *pmu, int irq)
writel(0, pmu->pmc_base + PMC_IRQ_MASK);
writel(0, pmu->pmc_base + PMC_IRQ_CAUSE);
- domain = irq_domain_add_linear(pmu->of_node, NR_PMU_IRQS,
- &irq_generic_chip_ops, NULL);
+ domain = irq_domain_create_linear(of_fwnode_handle(pmu->of_node), NR_PMU_IRQS,
+ &irq_generic_chip_ops, NULL);
if (!domain) {
pr_err("%s: unable to add irq domain\n", name);
return -ENOMEM;
@@ -410,13 +409,16 @@ int __init dove_init_pmu(void)
struct pmu_domain *domain;
domain = kzalloc(sizeof(*domain), GFP_KERNEL);
- if (!domain)
+ if (!domain) {
+ of_node_put(np);
break;
+ }
domain->pmu = pmu;
domain->base.name = kasprintf(GFP_KERNEL, "%pOFn", np);
if (!domain->base.name) {
kfree(domain);
+ of_node_put(np);
break;
}
diff --git a/drivers/soc/fsl/Kconfig b/drivers/soc/fsl/Kconfig
index fcec6ed83d5e..47870e29c290 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
@@ -36,7 +36,7 @@ config FSL_MC_DPIO
config DPAA2_CONSOLE
tristate "QorIQ DPAA2 console driver"
depends on OF && (ARCH_LAYERSCAPE || COMPILE_TEST)
- default y
+ default ARCH_LAYERSCAPE
help
Console driver for DPAA2 platforms. Exports 2 char devices,
/dev/dpaa2_mc_console and /dev/dpaa2_aiop_console,
diff --git a/drivers/soc/fsl/dpaa2-console.c b/drivers/soc/fsl/dpaa2-console.c
index 53917410f2bd..6310f54e68a2 100644
--- a/drivers/soc/fsl/dpaa2-console.c
+++ b/drivers/soc/fsl/dpaa2-console.c
@@ -9,9 +9,10 @@
#define pr_fmt(fmt) "dpaa2-console: " fmt
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/fs.h>
@@ -299,12 +300,10 @@ err_register_mc:
return error;
}
-static int dpaa2_console_remove(struct platform_device *pdev)
+static void dpaa2_console_remove(struct platform_device *pdev)
{
misc_deregister(&dpaa2_mc_console_dev);
misc_deregister(&dpaa2_aiop_console_dev);
-
- return 0;
}
static const struct of_device_id dpaa2_console_match_table[] = {
diff --git a/drivers/soc/fsl/dpio/dpio-driver.c b/drivers/soc/fsl/dpio/dpio-driver.c
index 74eace3109a1..9e3fddd8f5a9 100644
--- a/drivers/soc/fsl/dpio/dpio-driver.c
+++ b/drivers/soc/fsl/dpio/dpio-driver.c
@@ -270,7 +270,7 @@ static void dpio_teardown_irqs(struct fsl_mc_device *dpio_dev)
fsl_mc_free_irqs(dpio_dev);
}
-static int dpaa2_dpio_remove(struct fsl_mc_device *dpio_dev)
+static void dpaa2_dpio_remove(struct fsl_mc_device *dpio_dev)
{
struct device *dev;
struct dpio_priv *priv;
@@ -297,14 +297,8 @@ static int dpaa2_dpio_remove(struct fsl_mc_device *dpio_dev)
dpio_close(dpio_dev->mc_io, 0, dpio_dev->mc_handle);
- fsl_mc_portal_free(dpio_dev->mc_io);
-
- return 0;
-
err_open:
fsl_mc_portal_free(dpio_dev->mc_io);
-
- return err;
}
static const struct fsl_mc_device_id dpaa2_dpio_match_id_table[] = {
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 9dd8bb571dbc..e1d7b79cc450 100644
--- a/drivers/soc/fsl/qbman/dpaa_sys.c
+++ b/drivers/soc/fsl/qbman/dpaa_sys.c
@@ -34,19 +34,22 @@
/*
* 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;
- struct property *prop;
- int len, err;
+ int err;
__be32 *res_array;
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);
@@ -63,8 +66,9 @@ int qbman_init_private_mem(struct device *dev, int idx, dma_addr_t *addr,
* This is needed because QBMan HW does not allow the base address/
* size to be modified once set.
*/
- prop = of_find_property(mem_node, "reg", &len);
- if (!prop) {
+ if (!of_property_present(mem_node, "reg")) {
+ struct property *prop;
+
prop = devm_kzalloc(dev, sizeof(*prop), GFP_KERNEL);
if (!prop)
return -ENOMEM;
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..6b392b3ad4b1 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];
@@ -1073,7 +1073,7 @@ EXPORT_SYMBOL(qman_portal_set_iperiod);
int qman_wq_alloc(void)
{
- qm_portal_wq = alloc_workqueue("qman_portal_wq", 0, 1);
+ qm_portal_wq = alloc_workqueue("qman_portal_wq", WQ_PERCPU, 1);
if (!qm_portal_wq)
return -ENOMEM;
return 0;
@@ -1270,7 +1270,7 @@ static int qman_create_portal(struct qman_portal *portal,
qm_dqrr_set_ithresh(p, QMAN_PIRQ_DQRR_ITHRESH);
qm_mr_set_ithresh(p, QMAN_PIRQ_MR_ITHRESH);
qm_out(p, QM_REG_ITPR, QMAN_PIRQ_IPERIOD);
- portal->cgrs = kmalloc_array(2, sizeof(*cgrs), GFP_KERNEL);
+ portal->cgrs = kmalloc_array(2, sizeof(*portal->cgrs), GFP_KERNEL);
if (!portal->cgrs)
goto fail_cgrs;
/* initial snapshot is no-depletion */
@@ -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..6009e8b32c44 100644
--- a/drivers/soc/fsl/qbman/qman_test_stash.c
+++ b/drivers/soc/fsl/qbman/qman_test_stash.c
@@ -103,19 +103,17 @@ static int on_all_cpus(int (*fn)(void))
{
int cpu;
- for_each_cpu(cpu, cpu_online_mask) {
+ for_each_online_cpu(cpu) {
struct bstrap bstrap = {
.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
@@ -221,7 +219,7 @@ static int allocate_frame_data(void)
pcfg = qman_get_qm_portal_config(qman_dma_portal);
- __frame_ptr = kmalloc(4 * HP_NUM_WORDS, GFP_KERNEL);
+ __frame_ptr = kmalloc_array(4, HP_NUM_WORDS, GFP_KERNEL);
if (!__frame_ptr)
return -ENOMEM;
diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig
index 357c5800b112..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,7 +31,31 @@ 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/QE TSA support"
+ depends on OF && HAS_IOMEM
+ depends on CPM1 || QUICC_ENGINE || \
+ ((CPM || QUICC_ENGINE) && COMPILE_TEST)
+ help
+ Freescale CPM/QE Time Slot Assigner (TSA)
+ controller.
+
+ This option enables support for this
+ controller
+
+config CPM_QMC
+ tristate "CPM/QE QMC support"
+ depends on OF && HAS_IOMEM
+ depends on FSL_SOC
+ depends on CPM_TSA
+ help
+ Freescale CPM/QE QUICC Multichannel Controller
+ (QMC)
+
+ This option enables support for this
+ controller
config QE_TDM
bool
@@ -39,6 +63,7 @@ config QE_TDM
config QE_USB
bool
+ depends on QUICC_ENGINE
default y if USB_FSL_QE
help
QE USB Controller support
diff --git a/drivers/soc/fsl/qe/Makefile b/drivers/soc/fsl/qe/Makefile
index 55a555304f3a..ec8506e13113 100644
--- a/drivers/soc/fsl/qe/Makefile
+++ b/drivers/soc/fsl/qe/Makefile
@@ -4,6 +4,8 @@
#
obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_common.o qe_ic.o qe_io.o
obj-$(CONFIG_CPM) += qe_common.o
+obj-$(CONFIG_CPM_TSA) += tsa.o
+obj-$(CONFIG_CPM_QMC) += qmc.o
obj-$(CONFIG_UCC) += ucc.o
obj-$(CONFIG_UCC_SLOW) += ucc_slow.o
obj-$(CONFIG_UCC_FAST) += ucc_fast.o
diff --git a/drivers/soc/fsl/qe/gpio.c b/drivers/soc/fsl/qe/gpio.c
index 1c41eb49d5a7..c54154b404df 100644
--- a/drivers/soc/fsl/qe/gpio.c
+++ b/drivers/soc/fsl/qe/gpio.c
@@ -12,18 +12,19 @@
#include <linux/spinlock.h>
#include <linux/err.h>
#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h> /* for of_mm_gpio_chip */
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/slab.h>
#include <linux/export.h>
-#include <linux/property.h>
+#include <linux/platform_device.h>
#include <soc/fsl/qe/qe.h>
+#define PIN_MASK(gpio) (1UL << (QE_PIO_PINS - 1 - (gpio)))
+
struct qe_gpio_chip {
- struct of_mm_gpio_chip mm_gc;
+ struct gpio_chip gc;
+ void __iomem *regs;
spinlock_t lock;
/* shadowed data register to clear/set bits safely */
@@ -33,11 +34,9 @@ struct qe_gpio_chip {
struct qe_pio_regs saved_regs;
};
-static void qe_gpio_save_regs(struct of_mm_gpio_chip *mm_gc)
+static void qe_gpio_save_regs(struct qe_gpio_chip *qe_gc)
{
- struct qe_gpio_chip *qe_gc =
- container_of(mm_gc, struct qe_gpio_chip, mm_gc);
- struct qe_pio_regs __iomem *regs = mm_gc->regs;
+ struct qe_pio_regs __iomem *regs = qe_gc->regs;
qe_gc->cpdata = ioread32be(&regs->cpdata);
qe_gc->saved_regs.cpdata = qe_gc->cpdata;
@@ -50,20 +49,19 @@ static void qe_gpio_save_regs(struct of_mm_gpio_chip *mm_gc)
static int qe_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct qe_pio_regs __iomem *regs = mm_gc->regs;
- u32 pin_mask = 1 << (QE_PIO_PINS - 1 - gpio);
+ struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc);
+ struct qe_pio_regs __iomem *regs = qe_gc->regs;
+ u32 pin_mask = PIN_MASK(gpio);
return !!(ioread32be(&regs->cpdata) & pin_mask);
}
-static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+static int qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc);
- struct qe_pio_regs __iomem *regs = mm_gc->regs;
+ struct qe_pio_regs __iomem *regs = qe_gc->regs;
unsigned long flags;
- u32 pin_mask = 1 << (QE_PIO_PINS - 1 - gpio);
+ u32 pin_mask = PIN_MASK(gpio);
spin_lock_irqsave(&qe_gc->lock, flags);
@@ -75,14 +73,15 @@ static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
iowrite32be(qe_gc->cpdata, &regs->cpdata);
spin_unlock_irqrestore(&qe_gc->lock, flags);
+
+ return 0;
}
-static void qe_gpio_set_multiple(struct gpio_chip *gc,
- unsigned long *mask, unsigned long *bits)
+static int qe_gpio_set_multiple(struct gpio_chip *gc,
+ unsigned long *mask, unsigned long *bits)
{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc);
- struct qe_pio_regs __iomem *regs = mm_gc->regs;
+ struct qe_pio_regs __iomem *regs = qe_gc->regs;
unsigned long flags;
int i;
@@ -93,26 +92,27 @@ static void qe_gpio_set_multiple(struct gpio_chip *gc,
break;
if (__test_and_clear_bit(i, mask)) {
if (test_bit(i, bits))
- qe_gc->cpdata |= (1U << (QE_PIO_PINS - 1 - i));
+ qe_gc->cpdata |= PIN_MASK(i);
else
- qe_gc->cpdata &= ~(1U << (QE_PIO_PINS - 1 - i));
+ qe_gc->cpdata &= ~PIN_MASK(i);
}
}
iowrite32be(qe_gc->cpdata, &regs->cpdata);
spin_unlock_irqrestore(&qe_gc->lock, flags);
+
+ return 0;
}
static int qe_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&qe_gc->lock, flags);
- __par_io_config_pin(mm_gc->regs, gpio, QE_PIO_DIR_IN, 0, 0, 0);
+ __par_io_config_pin(qe_gc->regs, gpio, QE_PIO_DIR_IN, 0, 0, 0);
spin_unlock_irqrestore(&qe_gc->lock, flags);
@@ -121,7 +121,6 @@ static int qe_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
static int qe_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc);
unsigned long flags;
@@ -129,7 +128,7 @@ static int qe_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
spin_lock_irqsave(&qe_gc->lock, flags);
- __par_io_config_pin(mm_gc->regs, gpio, QE_PIO_DIR_OUT, 0, 0, 0);
+ __par_io_config_pin(qe_gc->regs, gpio, QE_PIO_DIR_OUT, 0, 0, 0);
spin_unlock_irqrestore(&qe_gc->lock, flags);
@@ -235,7 +234,7 @@ EXPORT_SYMBOL(qe_pin_free);
void qe_pin_set_dedicated(struct qe_pin *qe_pin)
{
struct qe_gpio_chip *qe_gc = qe_pin->controller;
- struct qe_pio_regs __iomem *regs = qe_gc->mm_gc.regs;
+ struct qe_pio_regs __iomem *regs = qe_gc->regs;
struct qe_pio_regs *sregs = &qe_gc->saved_regs;
int pin = qe_pin->num;
u32 mask1 = 1 << (QE_PIO_PINS - (pin + 1));
@@ -264,7 +263,6 @@ void qe_pin_set_dedicated(struct qe_pin *qe_pin)
iowrite32be(qe_gc->cpdata, &regs->cpdata);
qe_clrsetbits_be32(&regs->cpodr, mask1, sregs->cpodr & mask1);
-
spin_unlock_irqrestore(&qe_gc->lock, flags);
}
EXPORT_SYMBOL(qe_pin_set_dedicated);
@@ -279,7 +277,7 @@ EXPORT_SYMBOL(qe_pin_set_dedicated);
void qe_pin_set_gpio(struct qe_pin *qe_pin)
{
struct qe_gpio_chip *qe_gc = qe_pin->controller;
- struct qe_pio_regs __iomem *regs = qe_gc->mm_gc.regs;
+ struct qe_pio_regs __iomem *regs = qe_gc->regs;
unsigned long flags;
spin_lock_irqsave(&qe_gc->lock, flags);
@@ -291,45 +289,62 @@ void qe_pin_set_gpio(struct qe_pin *qe_pin)
}
EXPORT_SYMBOL(qe_pin_set_gpio);
-static int __init qe_add_gpiochips(void)
+static int qe_gpio_probe(struct platform_device *ofdev)
{
- struct device_node *np;
-
- for_each_compatible_node(np, NULL, "fsl,mpc8323-qe-pario-bank") {
- int ret;
- struct qe_gpio_chip *qe_gc;
- struct of_mm_gpio_chip *mm_gc;
- struct gpio_chip *gc;
-
- qe_gc = kzalloc(sizeof(*qe_gc), GFP_KERNEL);
- if (!qe_gc) {
- ret = -ENOMEM;
- goto err;
- }
+ struct device *dev = &ofdev->dev;
+ struct device_node *np = dev->of_node;
+ struct qe_gpio_chip *qe_gc;
+ struct gpio_chip *gc;
- spin_lock_init(&qe_gc->lock);
-
- mm_gc = &qe_gc->mm_gc;
- gc = &mm_gc->gc;
-
- mm_gc->save_regs = qe_gpio_save_regs;
- gc->ngpio = QE_PIO_PINS;
- gc->direction_input = qe_gpio_dir_in;
- gc->direction_output = qe_gpio_dir_out;
- gc->get = qe_gpio_get;
- gc->set = qe_gpio_set;
- gc->set_multiple = qe_gpio_set_multiple;
-
- ret = of_mm_gpiochip_add_data(np, mm_gc, qe_gc);
- if (ret)
- goto err;
- continue;
-err:
- pr_err("%pOF: registration failed with status %d\n",
- np, ret);
- kfree(qe_gc);
- /* try others anyway */
- }
- return 0;
+ qe_gc = devm_kzalloc(dev, sizeof(*qe_gc), GFP_KERNEL);
+ if (!qe_gc)
+ return -ENOMEM;
+
+ spin_lock_init(&qe_gc->lock);
+
+ gc = &qe_gc->gc;
+
+ gc->base = -1;
+ gc->ngpio = QE_PIO_PINS;
+ gc->direction_input = qe_gpio_dir_in;
+ gc->direction_output = qe_gpio_dir_out;
+ gc->get = qe_gpio_get;
+ gc->set = qe_gpio_set;
+ gc->set_multiple = qe_gpio_set_multiple;
+ gc->parent = dev;
+ gc->owner = THIS_MODULE;
+
+ gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np);
+ if (!gc->label)
+ return -ENOMEM;
+
+ qe_gc->regs = devm_of_iomap(dev, np, 0, NULL);
+ if (IS_ERR(qe_gc->regs))
+ return PTR_ERR(qe_gc->regs);
+
+ qe_gpio_save_regs(qe_gc);
+
+ return devm_gpiochip_add_data(dev, gc, qe_gc);
+}
+
+static const struct of_device_id qe_gpio_match[] = {
+ {
+ .compatible = "fsl,mpc8323-qe-pario-bank",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, qe_gpio_match);
+
+static struct platform_driver qe_gpio_driver = {
+ .probe = qe_gpio_probe,
+ .driver = {
+ .name = "qe-gpio",
+ .of_match_table = qe_gpio_match,
+ },
+};
+
+static int __init qe_gpio_init(void)
+{
+ return platform_driver_register(&qe_gpio_driver);
}
-arch_initcall(qe_add_gpiochips);
+arch_initcall(qe_gpio_init);
diff --git a/drivers/soc/fsl/qe/qe.c b/drivers/soc/fsl/qe/qe.c
index b3c226eb5292..70b6eddb867b 100644
--- a/drivers/soc/fsl/qe/qe.c
+++ b/drivers/soc/fsl/qe/qe.c
@@ -25,7 +25,8 @@
#include <linux/iopoll.h>
#include <linux/crc32.h>
#include <linux/mod_devicetable.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <soc/fsl/qe/immap_qe.h>
#include <soc/fsl/qe/qe.h>
@@ -429,7 +430,7 @@ static void qe_upload_microcode(const void *base,
/*
* Upload a microcode to the I-RAM at a specific address.
*
- * See Documentation/powerpc/qe_firmware.rst for information on QE microcode
+ * See Documentation/arch/powerpc/qe_firmware.rst for information on QE microcode
* uploading.
*
* Currently, only version 1 is supported, so the 'version' field must be
@@ -524,7 +525,7 @@ int qe_upload_firmware(const struct qe_firmware *firmware)
* saved microcode information and put in the new.
*/
memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
- strlcpy(qe_firmware_info.id, firmware->id, sizeof(qe_firmware_info.id));
+ strscpy(qe_firmware_info.id, firmware->id, sizeof(qe_firmware_info.id));
qe_firmware_info.extended_modes = be64_to_cpu(firmware->extended_modes);
memcpy(qe_firmware_info.vtraps, firmware->vtraps,
sizeof(firmware->vtraps));
@@ -599,7 +600,7 @@ struct qe_firmware_info *qe_get_firmware_info(void)
/* Copy the data into qe_firmware_info*/
sprop = of_get_property(fw, "id", NULL);
if (sprop)
- strlcpy(qe_firmware_info.id, sprop,
+ strscpy(qe_firmware_info.id, sprop,
sizeof(qe_firmware_info.id));
of_property_read_u64(fw, "extended-modes",
diff --git a/drivers/soc/fsl/qe/qe_common.c b/drivers/soc/fsl/qe/qe_common.c
index a0cb8e746879..02c29f5f86d3 100644
--- a/drivers/soc/fsl/qe/qe_common.c
+++ b/drivers/soc/fsl/qe/qe_common.c
@@ -13,10 +13,10 @@
* 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>
-#include <linux/of_device.h>
#include <linux/spinlock.h>
#include <linux/export.h>
#include <linux/of.h>
@@ -142,7 +142,7 @@ static s32 cpm_muram_alloc_common(unsigned long size,
*
* This function returns a non-negative offset into the muram area, or
* a negative errno on failure.
- * Use cpm_dpram_addr() to get the virtual address of the area.
+ * Use cpm_muram_addr() to get the virtual address of the area.
* Use cpm_muram_free() to free the allocation.
*/
s32 cpm_muram_alloc(unsigned long size, unsigned long align)
@@ -188,13 +188,56 @@ 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
* @size: number of bytes to allocate
* This function returns @offset if the area was available, a negative
* errno otherwise.
- * Use cpm_dpram_addr() to get the virtual address of the area.
+ * Use cpm_muram_addr() to get the virtual address of the area.
* Use cpm_muram_free() to free the allocation.
*/
s32 cpm_muram_alloc_fixed(unsigned long offset, unsigned long size)
@@ -213,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/qe_ic.c b/drivers/soc/fsl/qe/qe_ic.c
index bbae3d39c7be..943911053af6 100644
--- a/drivers/soc/fsl/qe/qe_ic.c
+++ b/drivers/soc/fsl/qe/qe_ic.c
@@ -232,11 +232,6 @@ static inline void qe_ic_write(__be32 __iomem *base, unsigned int reg,
iowrite32be(value, base + (reg >> 2));
}
-static inline struct qe_ic *qe_ic_from_irq(unsigned int virq)
-{
- return irq_get_chip_data(virq);
-}
-
static inline struct qe_ic *qe_ic_from_irq_data(struct irq_data *d)
{
return irq_data_get_irq_chip_data(d);
@@ -344,7 +339,7 @@ static unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic)
if (irq == 0)
return 0;
- return irq_linear_revmap(qe_ic->irqhost, irq);
+ return irq_find_mapping(qe_ic->irqhost, irq);
}
/* Return an interrupt vector or 0 if no interrupt is pending. */
@@ -360,7 +355,7 @@ static unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic)
if (irq == 0)
return 0;
- return irq_linear_revmap(qe_ic->irqhost, irq);
+ return irq_find_mapping(qe_ic->irqhost, irq);
}
static void qe_ic_cascade_low(struct irq_desc *desc)
@@ -412,7 +407,6 @@ static int qe_ic_init(struct platform_device *pdev)
void (*high_handler)(struct irq_desc *desc);
struct qe_ic *qe_ic;
struct resource *res;
- struct device_node *node = pdev->dev.of_node;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
@@ -446,8 +440,8 @@ static int qe_ic_init(struct platform_device *pdev)
high_handler = NULL;
}
- qe_ic->irqhost = irq_domain_add_linear(node, NR_QE_IC_INTS,
- &qe_ic_host_ops, qe_ic);
+ qe_ic->irqhost = irq_domain_create_linear(dev_fwnode(&pdev->dev), NR_QE_IC_INTS,
+ &qe_ic_host_ops, qe_ic);
if (qe_ic->irqhost == NULL) {
dev_err(dev, "failed to add irq domain\n");
return -ENODEV;
@@ -455,13 +449,11 @@ static int qe_ic_init(struct platform_device *pdev)
qe_ic_write(qe_ic->regs, QEIC_CICR, 0);
- irq_set_handler_data(qe_ic->virq_low, qe_ic);
- irq_set_chained_handler(qe_ic->virq_low, low_handler);
+ irq_set_chained_handler_and_data(qe_ic->virq_low, low_handler, qe_ic);
- if (high_handler) {
- irq_set_handler_data(qe_ic->virq_high, qe_ic);
- irq_set_chained_handler(qe_ic->virq_high, high_handler);
- }
+ if (high_handler)
+ irq_set_chained_handler_and_data(qe_ic->virq_high,
+ high_handler, qe_ic);
return 0;
}
static const struct of_device_id qe_ic_ids[] = {
diff --git a/drivers/soc/fsl/qe/qe_tdm.c b/drivers/soc/fsl/qe/qe_tdm.c
index 7d7d78d3ee50..a3b691875c8e 100644
--- a/drivers/soc/fsl/qe/qe_tdm.c
+++ b/drivers/soc/fsl/qe/qe_tdm.c
@@ -9,9 +9,7 @@
*/
#include <linux/io.h>
#include <linux/kernel.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
#include <soc/fsl/qe/qe_tdm.h>
static int set_tdm_framer(const char *tdm_framer_type)
diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c
new file mode 100644
index 000000000000..da5ea6d35618
--- /dev/null
+++ b/drivers/soc/fsl/qe/qmc.c
@@ -0,0 +1,2269 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * QMC driver
+ *
+ * Copyright 2022 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+
+#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>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#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 low (32 bits) (GUMR_L in QE) */
+#define SCC_GSMRL 0x00
+#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 high (32 bits) (identical to GUMR_H in QE) */
+#define SCC_GSMRH 0x04
+#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 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) */
+#define QMC_GBL_QMCSTATE 0x04
+/* Maximum receive buffer length (16 bits) */
+#define QMC_GBL_MRBLR 0x06
+/* Tx time-slot assignment table pointer (16 bits) */
+#define QMC_GBL_TX_S_PTR 0x08
+/* Rx pointer (16 bits) */
+#define QMC_GBL_RXPTR 0x0A
+/* Global receive frame threshold (16 bits) */
+#define QMC_GBL_GRFTHR 0x0C
+/* Global receive frame count (16 bits) */
+#define QMC_GBL_GRFCNT 0x0E
+/* Multichannel interrupt base address (32 bits) */
+#define QMC_GBL_INTBASE 0x10
+/* Multichannel interrupt pointer (32 bits) */
+#define QMC_GBL_INTPTR 0x14
+/* Rx time-slot assignment table pointer (16 bits) */
+#define QMC_GBL_RX_S_PTR 0x18
+/* Tx pointer (16 bits) */
+#define QMC_GBL_TXPTR 0x1A
+/* CRC constant (32 bits) */
+#define QMC_GBL_C_MASK32 0x1C
+/* Time slot assignment table Rx (32 x 16 bits) */
+#define QMC_GBL_TSATRX 0x20
+/* Time slot assignment table Tx (32 x 16 bits) */
+#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 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_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
+/* Tx buffer descriptor pointer (16 bits) */
+#define QMC_SPE_TBPTR 0x0C
+/* Zero-insertion state (32 bits) */
+#define QMC_SPE_ZISTATE 0x14
+/* Channel’s interrupt mask flags (16 bits) */
+#define QMC_SPE_INTMSK 0x1C
+/* Rx buffer descriptor base address (16 bits, offset from MCBASE) */
+#define QMC_SPE_RBASE 0x20
+/* HDLC: Maximum frame length register (16 bits) */
+#define QMC_SPE_MFLR 0x22
+/* TRANSPARENT: Transparent maximum receive length (16 bits) */
+#define QMC_SPE_TMRBLR 0x22
+/* Rx internal state (32 bits) */
+#define QMC_SPE_RSTATE 0x24
+/* Rx buffer descriptor pointer (16 bits) */
+#define QMC_SPE_RBPTR 0x2C
+/* Packs 4 bytes to 1 long word before writing to buffer (32 bits) */
+#define QMC_SPE_RPACK 0x30
+/* Zero deletion state (32 bits) */
+#define QMC_SPE_ZDSTATE 0x34
+
+/* Transparent synchronization (16 bits) */
+#define QMC_SPE_TRNSYNC 0x3C
+#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 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 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
+#define QMC_NB_RXBDS 8
+#define QMC_NB_INTS 128
+
+struct qmc_xfer_desc {
+ union {
+ void (*tx_complete)(void *context);
+ void (*rx_complete)(void *context, size_t length, unsigned int flags);
+ };
+ void *context;
+};
+
+struct qmc_chan {
+ struct list_head list;
+ unsigned int id;
+ struct qmc *qmc;
+ void __iomem *s_param;
+ enum qmc_mode mode;
+ spinlock_t ts_lock; /* Protect timeslots */
+ u64 tx_ts_mask_avail;
+ u64 tx_ts_mask;
+ u64 rx_ts_mask_avail;
+ u64 rx_ts_mask;
+ bool is_reverse_data;
+
+ spinlock_t tx_lock; /* Protect Tx related data */
+ cbd_t __iomem *txbds;
+ cbd_t __iomem *txbd_free;
+ cbd_t __iomem *txbd_done;
+ struct qmc_xfer_desc tx_desc[QMC_NB_TXBDS];
+ u64 nb_tx_underrun;
+ bool is_tx_stopped;
+
+ spinlock_t rx_lock; /* Protect Rx related data */
+ cbd_t __iomem *rxbds;
+ cbd_t __iomem *rxbd_free;
+ cbd_t __iomem *rxbd_done;
+ struct qmc_xfer_desc rx_desc[QMC_NB_RXBDS];
+ u64 nb_rx_busy;
+ int rx_pending;
+ bool is_rx_halted;
+ 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;
+ u16 __iomem *int_table;
+ u16 __iomem *int_curr;
+ dma_addr_t int_dma_addr;
+ size_t int_size;
+ bool is_tsa_64rxtx;
+ struct list_head chan_head;
+ 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);
+}
+
+static u16 qmc_read16(void __iomem *addr)
+{
+ return ioread16be(addr);
+}
+
+static void qmc_setbits16(void __iomem *addr, u16 set)
+{
+ qmc_write16(addr, qmc_read16(addr) | set);
+}
+
+static void qmc_clrbits16(void __iomem *addr, u16 clr)
+{
+ qmc_write16(addr, qmc_read16(addr) & ~clr);
+}
+
+static void qmc_clrsetbits16(void __iomem *addr, u16 clr, u16 set)
+{
+ qmc_write16(addr, (qmc_read16(addr) & ~clr) | set);
+}
+
+static void qmc_write32(void __iomem *addr, u32 val)
+{
+ iowrite32be(val, addr);
+}
+
+static u32 qmc_read32(void __iomem *addr)
+{
+ return ioread32be(addr);
+}
+
+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)
+{
+ struct tsa_serial_info tsa_info;
+ unsigned long flags;
+ int ret;
+
+ /* Retrieve info from the TSA related serial */
+ ret = tsa_serial_get_info(chan->qmc->tsa_serial, &tsa_info);
+ if (ret)
+ return ret;
+
+ spin_lock_irqsave(&chan->ts_lock, flags);
+
+ info->mode = chan->mode;
+ info->rx_fs_rate = tsa_info.rx_fs_rate;
+ info->rx_bit_rate = tsa_info.rx_bit_rate;
+ info->nb_tx_ts = hweight64(chan->tx_ts_mask);
+ info->tx_fs_rate = tsa_info.tx_fs_rate;
+ info->tx_bit_rate = tsa_info.tx_bit_rate;
+ info->nb_rx_ts = hweight64(chan->rx_ts_mask);
+
+ spin_unlock_irqrestore(&chan->ts_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(qmc_chan_get_info);
+
+int qmc_chan_get_ts_info(struct qmc_chan *chan, struct qmc_chan_ts_info *ts_info)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->ts_lock, flags);
+
+ ts_info->rx_ts_mask_avail = chan->rx_ts_mask_avail;
+ ts_info->tx_ts_mask_avail = chan->tx_ts_mask_avail;
+ ts_info->rx_ts_mask = chan->rx_ts_mask;
+ ts_info->tx_ts_mask = chan->tx_ts_mask;
+
+ spin_unlock_irqrestore(&chan->ts_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(qmc_chan_get_ts_info);
+
+int qmc_chan_set_ts_info(struct qmc_chan *chan, const struct qmc_chan_ts_info *ts_info)
+{
+ unsigned long flags;
+ int ret;
+
+ /* Only a subset of available timeslots is allowed */
+ if ((ts_info->rx_ts_mask & chan->rx_ts_mask_avail) != ts_info->rx_ts_mask)
+ return -EINVAL;
+ if ((ts_info->tx_ts_mask & chan->tx_ts_mask_avail) != ts_info->tx_ts_mask)
+ return -EINVAL;
+
+ /* In case of common rx/tx table, rx/tx masks must be identical */
+ if (chan->qmc->is_tsa_64rxtx) {
+ if (ts_info->rx_ts_mask != ts_info->tx_ts_mask)
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&chan->ts_lock, flags);
+
+ if ((chan->tx_ts_mask != ts_info->tx_ts_mask && !chan->is_tx_stopped) ||
+ (chan->rx_ts_mask != ts_info->rx_ts_mask && !chan->is_rx_stopped)) {
+ dev_err(chan->qmc->dev, "Channel rx and/or tx not stopped\n");
+ ret = -EBUSY;
+ } else {
+ chan->tx_ts_mask = ts_info->tx_ts_mask;
+ chan->rx_ts_mask = ts_info->rx_ts_mask;
+ ret = 0;
+ }
+ spin_unlock_irqrestore(&chan->ts_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(qmc_chan_set_ts_info);
+
+int qmc_chan_set_param(struct qmc_chan *chan, const struct qmc_chan_param *param)
+{
+ if (param->mode != chan->mode)
+ return -EINVAL;
+
+ switch (param->mode) {
+ case QMC_HDLC:
+ 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,
+ param->hdlc.max_rx_buf_size - 8);
+ qmc_write16(chan->s_param + QMC_SPE_MFLR,
+ param->hdlc.max_rx_frame_size);
+ if (param->hdlc.is_crc32) {
+ qmc_setbits16(chan->s_param + QMC_SPE_CHAMR,
+ QMC_SPE_CHAMR_HDLC_CRC);
+ } else {
+ qmc_clrbits16(chan->s_param + QMC_SPE_CHAMR,
+ QMC_SPE_CHAMR_HDLC_CRC);
+ }
+ break;
+
+ case QMC_TRANSPARENT:
+ qmc_write16(chan->s_param + QMC_SPE_TMRBLR,
+ param->transp.max_rx_buf_size);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(qmc_chan_set_param);
+
+int qmc_chan_write_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
+ void (*complete)(void *context), void *context)
+{
+ struct qmc_xfer_desc *xfer_desc;
+ unsigned long flags;
+ cbd_t __iomem *bd;
+ u16 ctrl;
+ int ret;
+
+ /*
+ * R bit UB bit
+ * 0 0 : The BD is free
+ * 1 1 : The BD is in used, waiting for transfer
+ * 0 1 : The BD is in used, waiting for completion
+ * 1 0 : Should not append
+ */
+
+ spin_lock_irqsave(&chan->tx_lock, flags);
+ bd = chan->txbd_free;
+
+ ctrl = qmc_read16(&bd->cbd_sc);
+ if (ctrl & (QMC_BD_TX_R | QMC_BD_TX_UB)) {
+ if (!(ctrl & (QMC_BD_TX_R | QMC_BD_TX_I)) && bd == chan->txbd_done) {
+ if (ctrl & QMC_BD_TX_W)
+ chan->txbd_done = chan->txbds;
+ else
+ chan->txbd_done++;
+ } else {
+ /* We are full ... */
+ ret = -EBUSY;
+ goto end;
+ }
+ }
+
+ qmc_write16(&bd->cbd_datlen, length);
+ qmc_write32(&bd->cbd_bufaddr, addr);
+
+ xfer_desc = &chan->tx_desc[bd - chan->txbds];
+ xfer_desc->tx_complete = complete;
+ xfer_desc->context = context;
+
+ /* Activate the descriptor */
+ ctrl |= (QMC_BD_TX_R | QMC_BD_TX_UB);
+ if (complete)
+ ctrl |= QMC_BD_TX_I;
+ else
+ ctrl &= ~QMC_BD_TX_I;
+ wmb(); /* Be sure to flush the descriptor before control update */
+ qmc_write16(&bd->cbd_sc, ctrl);
+
+ if (!chan->is_tx_stopped)
+ qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_POL);
+
+ if (ctrl & QMC_BD_TX_W)
+ chan->txbd_free = chan->txbds;
+ else
+ chan->txbd_free++;
+
+ ret = 0;
+
+end:
+ spin_unlock_irqrestore(&chan->tx_lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL(qmc_chan_write_submit);
+
+static void qmc_chan_write_done(struct qmc_chan *chan)
+{
+ struct qmc_xfer_desc *xfer_desc;
+ void (*complete)(void *context);
+ unsigned long flags;
+ void *context;
+ cbd_t __iomem *bd;
+ u16 ctrl;
+
+ /*
+ * R bit UB bit
+ * 0 0 : The BD is free
+ * 1 1 : The BD is in used, waiting for transfer
+ * 0 1 : The BD is in used, waiting for completion
+ * 1 0 : Should not append
+ */
+
+ spin_lock_irqsave(&chan->tx_lock, flags);
+ bd = chan->txbd_done;
+
+ ctrl = qmc_read16(&bd->cbd_sc);
+ while (!(ctrl & QMC_BD_TX_R)) {
+ if (!(ctrl & QMC_BD_TX_UB))
+ goto end;
+
+ xfer_desc = &chan->tx_desc[bd - chan->txbds];
+ complete = xfer_desc->tx_complete;
+ context = xfer_desc->context;
+ xfer_desc->tx_complete = NULL;
+ xfer_desc->context = NULL;
+
+ qmc_write16(&bd->cbd_sc, ctrl & ~QMC_BD_TX_UB);
+
+ if (ctrl & QMC_BD_TX_W)
+ chan->txbd_done = chan->txbds;
+ else
+ chan->txbd_done++;
+
+ if (complete) {
+ spin_unlock_irqrestore(&chan->tx_lock, flags);
+ complete(context);
+ spin_lock_irqsave(&chan->tx_lock, flags);
+ }
+
+ bd = chan->txbd_done;
+ ctrl = qmc_read16(&bd->cbd_sc);
+ }
+
+end:
+ spin_unlock_irqrestore(&chan->tx_lock, flags);
+}
+
+int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
+ void (*complete)(void *context, size_t length, unsigned int flags),
+ void *context)
+{
+ struct qmc_xfer_desc *xfer_desc;
+ unsigned long flags;
+ cbd_t __iomem *bd;
+ u16 ctrl;
+ int ret;
+
+ /*
+ * E bit UB bit
+ * 0 0 : The BD is free
+ * 1 1 : The BD is in used, waiting for transfer
+ * 0 1 : The BD is in used, waiting for completion
+ * 1 0 : Should not append
+ */
+
+ spin_lock_irqsave(&chan->rx_lock, flags);
+ bd = chan->rxbd_free;
+
+ ctrl = qmc_read16(&bd->cbd_sc);
+ if (ctrl & (QMC_BD_RX_E | QMC_BD_RX_UB)) {
+ if (!(ctrl & (QMC_BD_RX_E | QMC_BD_RX_I)) && bd == chan->rxbd_done) {
+ if (ctrl & QMC_BD_RX_W)
+ chan->rxbd_done = chan->rxbds;
+ else
+ chan->rxbd_done++;
+ } else {
+ /* We are full ... */
+ ret = -EBUSY;
+ goto end;
+ }
+ }
+
+ qmc_write16(&bd->cbd_datlen, 0); /* data length is updated by the QMC */
+ qmc_write32(&bd->cbd_bufaddr, addr);
+
+ xfer_desc = &chan->rx_desc[bd - chan->rxbds];
+ xfer_desc->rx_complete = complete;
+ xfer_desc->context = context;
+
+ /* Clear previous status flags */
+ ctrl &= ~(QMC_BD_RX_L | QMC_BD_RX_F | QMC_BD_RX_LG | QMC_BD_RX_NO |
+ QMC_BD_RX_AB | QMC_BD_RX_CR);
+
+ /* Activate the descriptor */
+ ctrl |= (QMC_BD_RX_E | QMC_BD_RX_UB);
+ if (complete)
+ ctrl |= QMC_BD_RX_I;
+ else
+ ctrl &= ~QMC_BD_RX_I;
+ wmb(); /* Be sure to flush data before descriptor activation */
+ qmc_write16(&bd->cbd_sc, ctrl);
+
+ /* Restart receiver if needed */
+ if (chan->is_rx_halted && !chan->is_rx_stopped) {
+ /* Restart receiver */
+ 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++;
+
+ if (ctrl & QMC_BD_RX_W)
+ chan->rxbd_free = chan->rxbds;
+ else
+ chan->rxbd_free++;
+
+ ret = 0;
+end:
+ spin_unlock_irqrestore(&chan->rx_lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL(qmc_chan_read_submit);
+
+static void qmc_chan_read_done(struct qmc_chan *chan)
+{
+ void (*complete)(void *context, size_t size, unsigned int flags);
+ struct qmc_xfer_desc *xfer_desc;
+ unsigned long flags;
+ cbd_t __iomem *bd;
+ void *context;
+ u16 datalen;
+ u16 ctrl;
+
+ /*
+ * E bit UB bit
+ * 0 0 : The BD is free
+ * 1 1 : The BD is in used, waiting for transfer
+ * 0 1 : The BD is in used, waiting for completion
+ * 1 0 : Should not append
+ */
+
+ spin_lock_irqsave(&chan->rx_lock, flags);
+ bd = chan->rxbd_done;
+
+ ctrl = qmc_read16(&bd->cbd_sc);
+ while (!(ctrl & QMC_BD_RX_E)) {
+ if (!(ctrl & QMC_BD_RX_UB))
+ goto end;
+
+ xfer_desc = &chan->rx_desc[bd - chan->rxbds];
+ complete = xfer_desc->rx_complete;
+ context = xfer_desc->context;
+ xfer_desc->rx_complete = NULL;
+ xfer_desc->context = NULL;
+
+ datalen = qmc_read16(&bd->cbd_datlen);
+ qmc_write16(&bd->cbd_sc, ctrl & ~QMC_BD_RX_UB);
+
+ if (ctrl & QMC_BD_RX_W)
+ chan->rxbd_done = chan->rxbds;
+ else
+ chan->rxbd_done++;
+
+ chan->rx_pending--;
+
+ if (complete) {
+ spin_unlock_irqrestore(&chan->rx_lock, flags);
+
+ /*
+ * Avoid conversion between internal hardware flags and
+ * the software API flags.
+ * -> Be sure that the software API flags are consistent
+ * with the hardware flags
+ */
+ BUILD_BUG_ON(QMC_RX_FLAG_HDLC_LAST != QMC_BD_RX_L);
+ BUILD_BUG_ON(QMC_RX_FLAG_HDLC_FIRST != QMC_BD_RX_F);
+ BUILD_BUG_ON(QMC_RX_FLAG_HDLC_OVF != QMC_BD_RX_LG);
+ BUILD_BUG_ON(QMC_RX_FLAG_HDLC_UNA != QMC_BD_RX_NO);
+ BUILD_BUG_ON(QMC_RX_FLAG_HDLC_ABORT != QMC_BD_RX_AB);
+ BUILD_BUG_ON(QMC_RX_FLAG_HDLC_CRC != QMC_BD_RX_CR);
+
+ complete(context, datalen,
+ ctrl & (QMC_BD_RX_L | QMC_BD_RX_F | QMC_BD_RX_LG |
+ QMC_BD_RX_NO | QMC_BD_RX_AB | QMC_BD_RX_CR));
+ spin_lock_irqsave(&chan->rx_lock, flags);
+ }
+
+ bd = chan->rxbd_done;
+ ctrl = qmc_read16(&bd->cbd_sc);
+ }
+
+end:
+ spin_unlock_irqrestore(&chan->rx_lock, flags);
+}
+
+static int qmc_chan_setup_tsa_64rxtx(struct qmc_chan *chan, const struct tsa_serial_info *info,
+ bool enable)
+{
+ unsigned int i;
+ u16 curr;
+ u16 val;
+
+ /*
+ * Use a common Tx/Rx 64 entries table.
+ * Tx and Rx related stuffs must be identical
+ */
+ if (chan->tx_ts_mask != chan->rx_ts_mask) {
+ dev_err(chan->qmc->dev, "chan %u uses different Rx and Tx TS\n", chan->id);
+ return -EINVAL;
+ }
+
+ 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++) {
+ if (!(chan->rx_ts_mask & (((u64)1) << i)))
+ continue;
+
+ curr = qmc_read16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2));
+ if (curr & QMC_TSA_VALID && (curr & ~QMC_TSA_WRAP) != val) {
+ dev_err(chan->qmc->dev, "chan %u TxRx entry %d already used\n",
+ chan->id, i);
+ return -EBUSY;
+ }
+ }
+
+ /* Set entries based on Rx stuff*/
+ for (i = 0; i < info->nb_rx_ts; i++) {
+ if (!(chan->rx_ts_mask & (((u64)1) << i)))
+ continue;
+
+ qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2),
+ (u16)~QMC_TSA_WRAP, enable ? val : 0x0000);
+ }
+
+ return 0;
+}
+
+static int qmc_chan_setup_tsa_32rx(struct qmc_chan *chan, const struct tsa_serial_info *info,
+ bool enable)
+{
+ unsigned int i;
+ u16 curr;
+ u16 val;
+
+ /* Use a Rx 32 entries table */
+
+ 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++) {
+ if (!(chan->rx_ts_mask & (((u64)1) << i)))
+ continue;
+
+ curr = qmc_read16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2));
+ if (curr & QMC_TSA_VALID && (curr & ~QMC_TSA_WRAP) != val) {
+ dev_err(chan->qmc->dev, "chan %u Rx entry %d already used\n",
+ chan->id, i);
+ return -EBUSY;
+ }
+ }
+
+ /* Set entries based on Rx stuff */
+ for (i = 0; i < info->nb_rx_ts; i++) {
+ if (!(chan->rx_ts_mask & (((u64)1) << i)))
+ continue;
+
+ qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2),
+ (u16)~QMC_TSA_WRAP, enable ? val : 0x0000);
+ }
+
+ return 0;
+}
+
+static int qmc_chan_setup_tsa_32tx(struct qmc_chan *chan, const struct tsa_serial_info *info,
+ bool enable)
+{
+ unsigned int i;
+ u16 curr;
+ u16 val;
+
+ /* Use a Tx 32 entries table */
+
+ 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++) {
+ if (!(chan->tx_ts_mask & (((u64)1) << i)))
+ continue;
+
+ curr = qmc_read16(chan->qmc->scc_pram + QMC_GBL_TSATTX + (i * 2));
+ if (curr & QMC_TSA_VALID && (curr & ~QMC_TSA_WRAP) != val) {
+ dev_err(chan->qmc->dev, "chan %u Tx entry %d already used\n",
+ chan->id, i);
+ return -EBUSY;
+ }
+ }
+
+ /* Set entries based on Tx stuff */
+ for (i = 0; i < info->nb_tx_ts; i++) {
+ if (!(chan->tx_ts_mask & (((u64)1) << i)))
+ continue;
+
+ qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATTX + (i * 2),
+ (u16)~QMC_TSA_WRAP, enable ? val : 0x0000);
+ }
+
+ return 0;
+}
+
+static int qmc_chan_setup_tsa_tx(struct qmc_chan *chan, bool enable)
+{
+ struct tsa_serial_info info;
+ int ret;
+
+ /* Retrieve info from the TSA related serial */
+ ret = tsa_serial_get_info(chan->qmc->tsa_serial, &info);
+ if (ret)
+ return ret;
+
+ /* Setup entries */
+ if (chan->qmc->is_tsa_64rxtx)
+ return qmc_chan_setup_tsa_64rxtx(chan, &info, enable);
+
+ return qmc_chan_setup_tsa_32tx(chan, &info, enable);
+}
+
+static int qmc_chan_setup_tsa_rx(struct qmc_chan *chan, bool enable)
+{
+ struct tsa_serial_info info;
+ int ret;
+
+ /* Retrieve info from the TSA related serial */
+ ret = tsa_serial_get_info(chan->qmc->tsa_serial, &info);
+ if (ret)
+ return ret;
+
+ /* Setup entries */
+ if (chan->qmc->is_tsa_64rxtx)
+ return qmc_chan_setup_tsa_64rxtx(chan, &info, enable);
+
+ return qmc_chan_setup_tsa_32rx(chan, &info, enable);
+}
+
+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;
+ int ret;
+
+ spin_lock_irqsave(&chan->rx_lock, flags);
+
+ if (chan->is_rx_stopped) {
+ /* The channel is already stopped -> simply return ok */
+ ret = 0;
+ goto end;
+ }
+
+ /* Send STOP RECEIVE command */
+ 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);
+ goto end;
+ }
+
+ chan->is_rx_stopped = true;
+
+ if (!chan->qmc->is_tsa_64rxtx || chan->is_tx_stopped) {
+ ret = qmc_chan_setup_tsa_rx(chan, false);
+ if (ret) {
+ dev_err(chan->qmc->dev, "chan %u: Disable tsa entries failed (%d)\n",
+ chan->id, ret);
+ goto end;
+ }
+ }
+
+end:
+ spin_unlock_irqrestore(&chan->rx_lock, flags);
+ return ret;
+}
+
+static int qmc_chan_stop_tx(struct qmc_chan *chan)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&chan->tx_lock, flags);
+
+ if (chan->is_tx_stopped) {
+ /* The channel is already stopped -> simply return ok */
+ ret = 0;
+ goto end;
+ }
+
+ /* Send STOP TRANSMIT command */
+ 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);
+ goto end;
+ }
+
+ chan->is_tx_stopped = true;
+
+ if (!chan->qmc->is_tsa_64rxtx || chan->is_rx_stopped) {
+ ret = qmc_chan_setup_tsa_tx(chan, false);
+ if (ret) {
+ dev_err(chan->qmc->dev, "chan %u: Disable tsa entries failed (%d)\n",
+ chan->id, ret);
+ goto end;
+ }
+ }
+
+end:
+ spin_unlock_irqrestore(&chan->tx_lock, flags);
+ return ret;
+}
+
+static int qmc_chan_start_rx(struct qmc_chan *chan);
+
+int qmc_chan_stop(struct qmc_chan *chan, int direction)
+{
+ bool is_rx_rollback_needed = false;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&chan->ts_lock, flags);
+
+ if (direction & QMC_CHAN_READ) {
+ is_rx_rollback_needed = !chan->is_rx_stopped;
+ ret = qmc_chan_stop_rx(chan);
+ if (ret)
+ goto end;
+ }
+
+ if (direction & QMC_CHAN_WRITE) {
+ ret = qmc_chan_stop_tx(chan);
+ if (ret) {
+ /* Restart rx if needed */
+ if (is_rx_rollback_needed)
+ qmc_chan_start_rx(chan);
+ goto end;
+ }
+ }
+
+end:
+ spin_unlock_irqrestore(&chan->ts_lock, flags);
+ return ret;
+}
+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;
+
+ /* Retrieve info from the TSA related serial */
+ ret = tsa_serial_get_info(chan->qmc->tsa_serial, &info);
+ 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;
+
+ /* Find the last Tx TS allocated to the channel */
+ last_tx = fls64(chan->tx_ts_mask);
+
+ trnsync = 0;
+ if (info.nb_rx_ts)
+ trnsync |= QMC_SPE_TRNSYNC_RX((first_rx % info.nb_rx_ts) * 2);
+ if (info.nb_tx_ts)
+ 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,
+ first_rx, info.nb_rx_ts, chan->rx_ts_mask,
+ last_tx, info.nb_tx_ts, chan->tx_ts_mask);
+
+ return 0;
+}
+
+static int qmc_chan_start_rx(struct qmc_chan *chan)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&chan->rx_lock, flags);
+
+ if (!chan->is_rx_stopped) {
+ /* The channel is already started -> simply return ok */
+ ret = 0;
+ goto end;
+ }
+
+ ret = qmc_chan_setup_tsa_rx(chan, true);
+ if (ret) {
+ dev_err(chan->qmc->dev, "chan %u: Enable tsa entries 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 */
+ 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;
+
+end:
+ spin_unlock_irqrestore(&chan->rx_lock, flags);
+ return ret;
+}
+
+static int qmc_chan_start_tx(struct qmc_chan *chan)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&chan->tx_lock, flags);
+
+ if (!chan->is_tx_stopped) {
+ /* The channel is already started -> simply return ok */
+ ret = 0;
+ goto end;
+ }
+
+ ret = qmc_chan_setup_tsa_tx(chan, true);
+ if (ret) {
+ dev_err(chan->qmc->dev, "chan %u: Enable tsa entries 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;
+ }
+ }
+
+ /*
+ * Enable channel transmitter as it could be disabled if
+ * qmc_chan_reset() was called.
+ */
+ qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_ENT);
+
+ /* Set the POL bit in the channel mode register */
+ qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_POL);
+
+ chan->is_tx_stopped = false;
+
+end:
+ spin_unlock_irqrestore(&chan->tx_lock, flags);
+ return ret;
+}
+
+int qmc_chan_start(struct qmc_chan *chan, int direction)
+{
+ bool is_rx_rollback_needed = false;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&chan->ts_lock, flags);
+
+ if (direction & QMC_CHAN_READ) {
+ is_rx_rollback_needed = chan->is_rx_stopped;
+ ret = qmc_chan_start_rx(chan);
+ if (ret)
+ goto end;
+ }
+
+ if (direction & QMC_CHAN_WRITE) {
+ ret = qmc_chan_start_tx(chan);
+ if (ret) {
+ /* Restop rx if needed */
+ if (is_rx_rollback_needed)
+ qmc_chan_stop_rx(chan);
+ goto end;
+ }
+ }
+
+end:
+ spin_unlock_irqrestore(&chan->ts_lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL(qmc_chan_start);
+
+static void qmc_chan_reset_rx(struct qmc_chan *chan)
+{
+ struct qmc_xfer_desc *xfer_desc;
+ unsigned long flags;
+ cbd_t __iomem *bd;
+ u16 ctrl;
+
+ spin_lock_irqsave(&chan->rx_lock, flags);
+ bd = chan->rxbds;
+ do {
+ ctrl = qmc_read16(&bd->cbd_sc);
+ qmc_write16(&bd->cbd_sc, ctrl & ~(QMC_BD_RX_UB | QMC_BD_RX_E));
+
+ xfer_desc = &chan->rx_desc[bd - chan->rxbds];
+ xfer_desc->rx_complete = NULL;
+ xfer_desc->context = NULL;
+
+ bd++;
+ } while (!(ctrl & QMC_BD_RX_W));
+
+ chan->rxbd_free = chan->rxbds;
+ chan->rxbd_done = chan->rxbds;
+ qmc_write16(chan->s_param + QMC_SPE_RBPTR,
+ qmc_read16(chan->s_param + QMC_SPE_RBASE));
+
+ chan->rx_pending = 0;
+
+ spin_unlock_irqrestore(&chan->rx_lock, flags);
+}
+
+static void qmc_chan_reset_tx(struct qmc_chan *chan)
+{
+ struct qmc_xfer_desc *xfer_desc;
+ unsigned long flags;
+ cbd_t __iomem *bd;
+ u16 ctrl;
+
+ spin_lock_irqsave(&chan->tx_lock, flags);
+
+ /* Disable transmitter. It will be re-enable on qmc_chan_start() */
+ qmc_clrbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_ENT);
+
+ bd = chan->txbds;
+ do {
+ ctrl = qmc_read16(&bd->cbd_sc);
+ qmc_write16(&bd->cbd_sc, ctrl & ~(QMC_BD_TX_UB | QMC_BD_TX_R));
+
+ xfer_desc = &chan->tx_desc[bd - chan->txbds];
+ xfer_desc->tx_complete = NULL;
+ xfer_desc->context = NULL;
+
+ bd++;
+ } while (!(ctrl & QMC_BD_TX_W));
+
+ chan->txbd_free = chan->txbds;
+ chan->txbd_done = chan->txbds;
+ qmc_write16(chan->s_param + QMC_SPE_TBPTR,
+ qmc_read16(chan->s_param + QMC_SPE_TBASE));
+
+ /* Reset TSTATE and ZISTATE to their initial value */
+ 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);
+}
+
+int qmc_chan_reset(struct qmc_chan *chan, int direction)
+{
+ if (direction & QMC_CHAN_READ)
+ qmc_chan_reset_rx(chan);
+
+ if (direction & QMC_CHAN_WRITE)
+ qmc_chan_reset_tx(chan);
+
+ return 0;
+}
+EXPORT_SYMBOL(qmc_chan_reset);
+
+static int qmc_check_chans(struct qmc *qmc)
+{
+ struct tsa_serial_info info;
+ struct qmc_chan *chan;
+ u64 tx_ts_assigned_mask;
+ u64 rx_ts_assigned_mask;
+ int ret;
+
+ /* Retrieve info from the TSA related serial */
+ ret = tsa_serial_get_info(qmc->tsa_serial, &info);
+ if (ret)
+ return ret;
+
+ 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;
+ }
+
+ /*
+ * 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 != info.nb_rx_ts) {
+ dev_err(qmc->dev, "Number of TSA Tx/Rx TS assigned are not equal\n");
+ return -EINVAL;
+ }
+ }
+
+ tx_ts_assigned_mask = info.nb_tx_ts == 64 ? U64_MAX : (((u64)1) << info.nb_tx_ts) - 1;
+ rx_ts_assigned_mask = info.nb_rx_ts == 64 ? U64_MAX : (((u64)1) << info.nb_rx_ts) - 1;
+
+ list_for_each_entry(chan, &qmc->chan_head, list) {
+ if (chan->tx_ts_mask_avail > tx_ts_assigned_mask) {
+ dev_err(qmc->dev, "chan %u can use TSA unassigned Tx TS\n", chan->id);
+ return -EINVAL;
+ }
+
+ if (chan->rx_ts_mask_avail > rx_ts_assigned_mask) {
+ dev_err(qmc->dev, "chan %u can use TSA unassigned Rx TS\n", chan->id);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static unsigned int qmc_nb_chans(struct qmc *qmc)
+{
+ unsigned int count = 0;
+ struct qmc_chan *chan;
+
+ list_for_each_entry(chan, &qmc->chan_head, list)
+ count++;
+
+ return count;
+}
+
+static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np)
+{
+ struct device_node *chan_np;
+ struct qmc_chan *chan;
+ const char *mode;
+ u32 chan_id;
+ u64 ts_mask;
+ int ret;
+
+ for_each_available_child_of_node(np, chan_np) {
+ ret = of_property_read_u32(chan_np, "reg", &chan_id);
+ if (ret) {
+ dev_err(qmc->dev, "%pOF: failed to read reg\n", chan_np);
+ of_node_put(chan_np);
+ return ret;
+ }
+ if (chan_id > 63) {
+ dev_err(qmc->dev, "%pOF: Invalid chan_id\n", chan_np);
+ of_node_put(chan_np);
+ return -EINVAL;
+ }
+
+ chan = devm_kzalloc(qmc->dev, sizeof(*chan), GFP_KERNEL);
+ if (!chan) {
+ of_node_put(chan_np);
+ return -ENOMEM;
+ }
+
+ chan->id = chan_id;
+ spin_lock_init(&chan->ts_lock);
+ spin_lock_init(&chan->rx_lock);
+ spin_lock_init(&chan->tx_lock);
+
+ ret = of_property_read_u64(chan_np, "fsl,tx-ts-mask", &ts_mask);
+ if (ret) {
+ dev_err(qmc->dev, "%pOF: failed to read fsl,tx-ts-mask\n",
+ chan_np);
+ of_node_put(chan_np);
+ return ret;
+ }
+ chan->tx_ts_mask_avail = ts_mask;
+ chan->tx_ts_mask = chan->tx_ts_mask_avail;
+
+ ret = of_property_read_u64(chan_np, "fsl,rx-ts-mask", &ts_mask);
+ if (ret) {
+ dev_err(qmc->dev, "%pOF: failed to read fsl,rx-ts-mask\n",
+ chan_np);
+ of_node_put(chan_np);
+ return ret;
+ }
+ chan->rx_ts_mask_avail = ts_mask;
+ chan->rx_ts_mask = chan->rx_ts_mask_avail;
+
+ mode = "transparent";
+ ret = of_property_read_string(chan_np, "fsl,operational-mode", &mode);
+ if (ret && ret != -EINVAL) {
+ dev_err(qmc->dev, "%pOF: failed to read fsl,operational-mode\n",
+ chan_np);
+ of_node_put(chan_np);
+ return ret;
+ }
+ if (!strcmp(mode, "transparent")) {
+ chan->mode = QMC_TRANSPARENT;
+ } else if (!strcmp(mode, "hdlc")) {
+ chan->mode = QMC_HDLC;
+ } else {
+ dev_err(qmc->dev, "%pOF: Invalid fsl,operational-mode (%s)\n",
+ chan_np, mode);
+ of_node_put(chan_np);
+ return -EINVAL;
+ }
+
+ chan->is_reverse_data = of_property_read_bool(chan_np,
+ "fsl,reverse-data");
+
+ list_add_tail(&chan->list, &qmc->chan_head);
+ qmc->chans[chan->id] = chan;
+ }
+
+ return qmc_check_chans(qmc);
+}
+
+static int qmc_init_tsa_64rxtx(struct qmc *qmc, const struct tsa_serial_info *info)
+{
+ unsigned int i;
+ u16 val;
+
+ /*
+ * Use a common Tx/Rx 64 entries table.
+ * Everything was previously checked, Tx and Rx related stuffs are
+ * identical -> Used Rx related stuff to build the table
+ */
+ qmc->is_tsa_64rxtx = true;
+
+ /* Invalidate all entries */
+ for (i = 0; i < 64; i++)
+ qmc_write16(qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), 0x0000);
+
+ /* Set Wrap bit on last entry */
+ qmc_setbits16(qmc->scc_pram + QMC_GBL_TSATRX + ((info->nb_rx_ts - 1) * 2),
+ QMC_TSA_WRAP);
+
+ /* Init pointers to the table */
+ val = qmc->scc_pram_offset + QMC_GBL_TSATRX;
+ qmc_write16(qmc->scc_pram + QMC_GBL_RX_S_PTR, val);
+ qmc_write16(qmc->scc_pram + QMC_GBL_RXPTR, val);
+ qmc_write16(qmc->scc_pram + QMC_GBL_TX_S_PTR, val);
+ qmc_write16(qmc->scc_pram + QMC_GBL_TXPTR, val);
+
+ return 0;
+}
+
+static int qmc_init_tsa_32rx_32tx(struct qmc *qmc, const struct tsa_serial_info *info)
+{
+ unsigned int i;
+ u16 val;
+
+ /*
+ * Use a Tx 32 entries table and a Rx 32 entries table.
+ * Everything was previously checked.
+ */
+ qmc->is_tsa_64rxtx = false;
+
+ /* Invalidate all entries */
+ for (i = 0; i < 32; i++) {
+ qmc_write16(qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), 0x0000);
+ qmc_write16(qmc->scc_pram + QMC_GBL_TSATTX + (i * 2), 0x0000);
+ }
+
+ /* Set Wrap bit on last entries */
+ qmc_setbits16(qmc->scc_pram + QMC_GBL_TSATRX + ((info->nb_rx_ts - 1) * 2),
+ QMC_TSA_WRAP);
+ qmc_setbits16(qmc->scc_pram + QMC_GBL_TSATTX + ((info->nb_tx_ts - 1) * 2),
+ QMC_TSA_WRAP);
+
+ /* Init Rx pointers ...*/
+ val = qmc->scc_pram_offset + QMC_GBL_TSATRX;
+ qmc_write16(qmc->scc_pram + QMC_GBL_RX_S_PTR, val);
+ qmc_write16(qmc->scc_pram + QMC_GBL_RXPTR, val);
+
+ /* ... and Tx pointers */
+ val = qmc->scc_pram_offset + QMC_GBL_TSATTX;
+ qmc_write16(qmc->scc_pram + QMC_GBL_TX_S_PTR, val);
+ qmc_write16(qmc->scc_pram + QMC_GBL_TXPTR, val);
+
+ return 0;
+}
+
+static int qmc_init_tsa(struct qmc *qmc)
+{
+ struct tsa_serial_info info;
+ int ret;
+
+ /* Retrieve info from the TSA related serial */
+ ret = tsa_serial_get_info(qmc->tsa_serial, &info);
+ if (ret)
+ return ret;
+
+ /*
+ * Initialize one common 64 entries table or two 32 entries (one for Tx
+ * and one for Tx) according to assigned TS numbers.
+ */
+ return ((info.nb_tx_ts > 32) || (info.nb_rx_ts > 32)) ?
+ qmc_init_tsa_64rxtx(qmc, &info) :
+ qmc_init_tsa_32rx_32tx(qmc, &info);
+}
+
+static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan)
+{
+ unsigned int i;
+ cbd_t __iomem *bd;
+ int ret;
+ u16 val;
+
+ chan->qmc = qmc;
+
+ /* Set channel specific parameter base address */
+ chan->s_param = qmc->dpram + (chan->id * 64);
+ /* 16 bd per channel (8 rx and 8 tx) */
+ chan->txbds = qmc->bd_table + (chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS));
+ chan->rxbds = qmc->bd_table + (chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS)) + QMC_NB_TXBDS;
+
+ chan->txbd_free = chan->txbds;
+ chan->txbd_done = chan->txbds;
+ chan->rxbd_free = chan->rxbds;
+ chan->rxbd_done = chan->rxbds;
+
+ /* TBASE and TBPTR*/
+ val = chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS) * sizeof(cbd_t);
+ qmc_write16(chan->s_param + QMC_SPE_TBASE, val);
+ qmc_write16(chan->s_param + QMC_SPE_TBPTR, val);
+
+ /* RBASE and RBPTR*/
+ 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, 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, chan->qmc->data->zdstate_transp);
+ qmc_write16(chan->s_param + QMC_SPE_TMRBLR, 60);
+ 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);
+ ret = qmc_setup_chan_trnsync(qmc, chan);
+ if (ret)
+ return ret;
+ } else {
+ 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);
+ }
+
+ /* Do not enable interrupts now. They will be enabled later */
+ qmc_write16(chan->s_param + QMC_SPE_INTMSK, 0x0000);
+
+ /* Init Rx BDs and set Wrap bit on last descriptor */
+ BUILD_BUG_ON(QMC_NB_RXBDS == 0);
+ for (i = 0; i < QMC_NB_RXBDS; i++) {
+ bd = chan->rxbds + i;
+ qmc_write16(&bd->cbd_sc, 0);
+ }
+ bd = chan->rxbds + QMC_NB_RXBDS - 1;
+ qmc_write16(&bd->cbd_sc, QMC_BD_RX_W);
+
+ /* Init Tx BDs and set Wrap bit on last descriptor */
+ BUILD_BUG_ON(QMC_NB_TXBDS == 0);
+ if (chan->mode == QMC_HDLC)
+ val = QMC_BD_TX_L | QMC_BD_TX_TC;
+ else
+ val = 0;
+ for (i = 0; i < QMC_NB_TXBDS; i++) {
+ bd = chan->txbds + i;
+ qmc_write16(&bd->cbd_sc, val);
+ }
+ bd = chan->txbds + QMC_NB_TXBDS - 1;
+ qmc_write16(&bd->cbd_sc, val | QMC_BD_TX_W);
+
+ return 0;
+}
+
+static int qmc_setup_chans(struct qmc *qmc)
+{
+ struct qmc_chan *chan;
+ int ret;
+
+ list_for_each_entry(chan, &qmc->chan_head, list) {
+ ret = qmc_setup_chan(qmc, chan);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int qmc_finalize_chans(struct qmc *qmc)
+{
+ struct qmc_chan *chan;
+ int ret;
+
+ list_for_each_entry(chan, &qmc->chan_head, list) {
+ /* Unmask channel interrupts */
+ if (chan->mode == QMC_HDLC) {
+ qmc_write16(chan->s_param + QMC_SPE_INTMSK,
+ QMC_INT_NID | QMC_INT_IDL | QMC_INT_MRF |
+ QMC_INT_UN | QMC_INT_RXF | QMC_INT_BSY |
+ QMC_INT_TXB | QMC_INT_RXB);
+ } else {
+ qmc_write16(chan->s_param + QMC_SPE_INTMSK,
+ QMC_INT_UN | QMC_INT_BSY |
+ QMC_INT_TXB | QMC_INT_RXB);
+ }
+
+ /* Forced stop the channel */
+ ret = qmc_chan_stop(chan, QMC_CHAN_ALL);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int qmc_setup_ints(struct qmc *qmc)
+{
+ unsigned int i;
+ u16 __iomem *last;
+
+ /* Raz all entries */
+ for (i = 0; i < (qmc->int_size / sizeof(u16)); i++)
+ qmc_write16(qmc->int_table + i, 0x0000);
+
+ /* Set Wrap bit on last entry */
+ if (qmc->int_size >= sizeof(u16)) {
+ last = qmc->int_table + (qmc->int_size / sizeof(u16)) - 1;
+ qmc_write16(last, QMC_INT_W);
+ }
+
+ return 0;
+}
+
+static void qmc_irq_gint(struct qmc *qmc)
+{
+ struct qmc_chan *chan;
+ unsigned int chan_id;
+ unsigned long flags;
+ u16 int_entry;
+
+ int_entry = qmc_read16(qmc->int_curr);
+ while (int_entry & QMC_INT_V) {
+ /* Clear all but the Wrap bit */
+ qmc_write16(qmc->int_curr, int_entry & QMC_INT_W);
+
+ chan_id = QMC_INT_GET_CHANNEL(int_entry);
+ chan = qmc->chans[chan_id];
+ if (!chan) {
+ dev_err(qmc->dev, "interrupt on invalid chan %u\n", chan_id);
+ goto int_next;
+ }
+
+ if (int_entry & QMC_INT_TXB)
+ qmc_chan_write_done(chan);
+
+ if (int_entry & QMC_INT_UN) {
+ dev_info(qmc->dev, "intr chan %u, 0x%04x (UN)\n", chan_id,
+ int_entry);
+ chan->nb_tx_underrun++;
+ }
+
+ if (int_entry & QMC_INT_BSY) {
+ dev_info(qmc->dev, "intr chan %u, 0x%04x (BSY)\n", chan_id,
+ int_entry);
+ chan->nb_rx_busy++;
+ /* Restart the receiver if needed */
+ spin_lock_irqsave(&chan->rx_lock, flags);
+ if (chan->rx_pending && !chan->is_rx_stopped) {
+ 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;
+ }
+ spin_unlock_irqrestore(&chan->rx_lock, flags);
+ }
+
+ if (int_entry & QMC_INT_RXB)
+ qmc_chan_read_done(chan);
+
+int_next:
+ if (int_entry & QMC_INT_W)
+ qmc->int_curr = qmc->int_table;
+ else
+ qmc->int_curr++;
+ int_entry = qmc_read16(qmc->int_curr);
+ }
+}
+
+static irqreturn_t qmc_irq_handler(int irq, void *priv)
+{
+ struct qmc *qmc = (struct qmc *)priv;
+ u16 scce;
+
+ scce = qmc_read16(qmc->scc_regs + SCC_SCCE);
+ qmc_write16(qmc->scc_regs + SCC_SCCE, scce);
+
+ if (unlikely(scce & SCC_SCCE_IQOV))
+ dev_info(qmc->dev, "IRQ queue overflow\n");
+
+ if (unlikely(scce & SCC_SCCE_GUN))
+ dev_err(qmc->dev, "Global transmitter underrun\n");
+
+ if (unlikely(scce & SCC_SCCE_GOV))
+ dev_err(qmc->dev, "Global receiver overrun\n");
+
+ /* normal interrupt */
+ if (likely(scce & SCC_SCCE_GINT))
+ qmc_irq_gint(qmc);
+
+ return IRQ_HANDLED;
+}
+
+static int qmc_qe_soft_qmc_init(struct qmc *qmc, struct device_node *np)
+{
+ struct qe_firmware_info *qe_fw_info;
+ const struct qe_firmware *qe_fw;
+ const struct firmware *fw;
+ const char *filename;
+ int ret;
+
+ 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;
+ }
+
+ 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;
+ qmc->scc_pram_offset = res->start - get_immrbase();
+ qmc->scc_pram = devm_ioremap_resource(qmc->dev, res);
+ if (IS_ERR(qmc->scc_pram))
+ return PTR_ERR(qmc->scc_pram);
+
+ qmc->dpram = devm_platform_ioremap_resource_byname(pdev, "dpram");
+ 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");
+ }
+
+ 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)
+ return ret;
+
+ nb_chans = qmc_nb_chans(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);
+ if (!qmc->bd_table) {
+ dev_err(qmc->dev, "Failed to allocate bd table\n");
+ return -ENOMEM;
+ }
+ memset(qmc->bd_table, 0, qmc->bd_size);
+
+ qmc_write32(qmc->scc_pram + QMC_GBL_MCBASE, qmc->bd_dma_addr);
+
+ /* 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);
+ if (!qmc->int_table) {
+ dev_err(qmc->dev, "Failed to allocate interrupt table\n");
+ return -ENOMEM;
+ }
+ memset(qmc->int_table, 0, qmc->int_size);
+
+ qmc->int_curr = qmc->int_table;
+ qmc_write32(qmc->scc_pram + QMC_GBL_INTBASE, qmc->int_dma_addr);
+ qmc_write32(qmc->scc_pram + QMC_GBL_INTPTR, qmc->int_dma_addr);
+
+ /* Set MRBLR (valid for HDLC only) max MRU + max CRC */
+ qmc_write16(qmc->scc_pram + QMC_GBL_MRBLR, HDLC_MAX_MRU + 4);
+
+ qmc_write16(qmc->scc_pram + QMC_GBL_GRFTHR, 1);
+ qmc_write16(qmc->scc_pram + QMC_GBL_GRFCNT, 1);
+
+ 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)
+ return ret;
+
+ qmc_write16(qmc->scc_pram + QMC_GBL_QMCSTATE, 0x8000);
+
+ ret = qmc_setup_chans(qmc);
+ if (ret)
+ return ret;
+
+ /* Init interrupts table */
+ ret = qmc_setup_ints(qmc);
+ if (ret)
+ return ret;
+
+ /* 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) {
+ ret = irq;
+ goto err_exit_xcc;
+ }
+ ret = devm_request_irq(qmc->dev, irq, qmc_irq_handler, 0, "qmc", qmc);
+ if (ret < 0)
+ 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);
+
+ ret = qmc_finalize_chans(qmc);
+ if (ret < 0)
+ goto err_disable_intr;
+
+ /* Enable transmitter and receiver */
+ qmc_setbits32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+ platform_set_drvdata(pdev, qmc);
+
+ /* Populate channel related devices */
+ ret = devm_of_platform_populate(qmc->dev);
+ if (ret)
+ goto err_disable_txrx;
+
+ return 0;
+
+err_disable_txrx:
+ qmc_setbits32(qmc->scc_regs + SCC_GSMRL, 0);
+
+err_disable_intr:
+ qmc_write16(qmc->scc_regs + SCC_SCCM, 0);
+
+err_exit_xcc:
+ qmc_exit_xcc(qmc);
+ return ret;
+}
+
+static void qmc_remove(struct platform_device *pdev)
+{
+ struct qmc *qmc = platform_get_drvdata(pdev);
+
+ /* Disable transmitter and receiver */
+ qmc_setbits32(qmc->scc_regs + SCC_GSMRL, 0);
+
+ /* Disable interrupts */
+ qmc_write16(qmc->scc_regs + SCC_SCCM, 0);
+
+ /* 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[] = {
+#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);
+
+static struct platform_driver qmc_driver = {
+ .driver = {
+ .name = "fsl-qmc",
+ .of_match_table = of_match_ptr(qmc_id_table),
+ },
+ .probe = qmc_probe,
+ .remove = qmc_remove,
+};
+module_platform_driver(qmc_driver);
+
+static struct qmc_chan *qmc_chan_get_from_qmc(struct device_node *qmc_np, unsigned int chan_index)
+{
+ struct platform_device *pdev;
+ struct qmc_chan *qmc_chan;
+ struct qmc *qmc;
+
+ if (!of_match_node(qmc_driver.driver.of_match_table, qmc_np))
+ return ERR_PTR(-EINVAL);
+
+ pdev = of_find_device_by_node(qmc_np);
+ if (!pdev)
+ return ERR_PTR(-ENODEV);
+
+ qmc = platform_get_drvdata(pdev);
+ if (!qmc) {
+ platform_device_put(pdev);
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+
+ if (chan_index >= ARRAY_SIZE(qmc->chans)) {
+ platform_device_put(pdev);
+ return ERR_PTR(-EINVAL);
+ }
+
+ qmc_chan = qmc->chans[chan_index];
+ if (!qmc_chan) {
+ platform_device_put(pdev);
+ return ERR_PTR(-ENOENT);
+ }
+
+ return qmc_chan;
+}
+
+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, phandles_name, 1, index,
+ &out_args);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ if (out_args.args_count != 1) {
+ of_node_put(out_args.np);
+ return ERR_PTR(-EINVAL);
+ }
+
+ qmc_chan = qmc_chan_get_from_qmc(out_args.np, out_args.args[0]);
+ of_node_put(out_args.np);
+ return qmc_chan;
+}
+EXPORT_SYMBOL(qmc_chan_get_byphandles_index);
+
+struct qmc_chan *qmc_chan_get_bychild(struct device_node *np)
+{
+ struct device_node *qmc_np;
+ u32 chan_index;
+ int ret;
+
+ qmc_np = np->parent;
+ ret = of_property_read_u32(np, "reg", &chan_index);
+ if (ret)
+ return ERR_PTR(-EINVAL);
+
+ return qmc_chan_get_from_qmc(qmc_np, chan_index);
+}
+EXPORT_SYMBOL(qmc_chan_get_bychild);
+
+void qmc_chan_put(struct qmc_chan *chan)
+{
+ put_device(chan->qmc->dev);
+}
+EXPORT_SYMBOL(qmc_chan_put);
+
+static void devm_qmc_chan_release(struct device *dev, void *res)
+{
+ struct qmc_chan **qmc_chan = res;
+
+ qmc_chan_put(*qmc_chan);
+}
+
+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;
+
+ dr = devres_alloc(devm_qmc_chan_release, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return ERR_PTR(-ENOMEM);
+
+ qmc_chan = qmc_chan_get_byphandles_index(np, phandles_name, index);
+ if (!IS_ERR(qmc_chan)) {
+ *dr = qmc_chan;
+ devres_add(dev, dr);
+ } else {
+ devres_free(dr);
+ }
+
+ return qmc_chan;
+}
+EXPORT_SYMBOL(devm_qmc_chan_get_byphandles_index);
+
+struct qmc_chan *devm_qmc_chan_get_bychild(struct device *dev,
+ struct device_node *np)
+{
+ struct qmc_chan *qmc_chan;
+ struct qmc_chan **dr;
+
+ dr = devres_alloc(devm_qmc_chan_release, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return ERR_PTR(-ENOMEM);
+
+ qmc_chan = qmc_chan_get_bychild(np);
+ if (!IS_ERR(qmc_chan)) {
+ *dr = qmc_chan;
+ devres_add(dev, dr);
+ } else {
+ devres_free(dr);
+ }
+
+ return qmc_chan;
+}
+EXPORT_SYMBOL(devm_qmc_chan_get_bychild);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+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
new file mode 100644
index 000000000000..4a88e54d25b9
--- /dev/null
+++ b/drivers/soc/fsl/qe/tsa.c
@@ -0,0 +1,1168 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * TSA driver
+ *
+ * Copyright 2022 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+
+#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>
+#include <linux/of.h>
+#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)
+
+/*
+ * 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_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;
+ void __iomem *entries_next;
+ void __iomem *last_entry;
+};
+
+struct tsa_tdm {
+ bool is_enable;
+ struct clk *l1rclk_clk;
+ struct clk *l1rsync_clk;
+ struct clk *l1tclk_clk;
+ struct clk *l1tsync_clk;
+ u32 simode_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; /* 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;
+ } serials[6];
+};
+
+static inline struct tsa *tsa_serial_get_tsa(struct tsa_serial *tsa_serial)
+{
+ /* The serials table is indexed by the serial id */
+ return container_of(tsa_serial, struct tsa, serials[tsa_serial->id]);
+}
+
+static inline void tsa_write32(void __iomem *addr, u32 val)
+{
+ iowrite32be(val, addr);
+}
+
+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);
+}
+
+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);
+}
+
+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;
+ u32 clear;
+ u32 set;
+
+ switch (tsa_serial->id) {
+ case FSL_CPM_TSA_SCC2:
+ 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_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_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);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&tsa->lock, flags);
+ tsa_clrsetbits32(tsa->si_regs + TSA_CPM1_SICR, clear,
+ connect ? set : 0);
+ spin_unlock_irqrestore(&tsa->lock, flags);
+
+ return 0;
+}
+
+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;
+ int ucc_num;
+ int ret;
+
+ ucc_num = tsa_qe_serial_get_num(tsa_serial);
+ if (ucc_num < 0)
+ return ucc_num;
+
+ spin_lock_irqsave(&tsa->lock, flags);
+ 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)
+{
+ memcpy(info, &tsa_serial->info, sizeof(*info));
+ return 0;
+}
+EXPORT_SYMBOL(tsa_serial_get_info);
+
+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;
+
+ if (tdms == BIT(TSA_TDMA)) {
+ /* Only TDMA */
+ if (is_rx) {
+ /* First half of si_ram */
+ area->entries_start = tsa->si_ram;
+ area->entries_next = area->entries_start + half;
+ area->last_entry = NULL;
+ } else {
+ /* Second half of si_ram */
+ area->entries_start = tsa->si_ram + half;
+ area->entries_next = area->entries_start + half;
+ area->last_entry = NULL;
+ }
+ } else {
+ /* Only TDMB or both TDMs */
+ if (tdm_id == TSA_TDMA) {
+ if (is_rx) {
+ /* First half of first half of si_ram */
+ area->entries_start = tsa->si_ram;
+ area->entries_next = area->entries_start + quarter;
+ area->last_entry = NULL;
+ } else {
+ /* First half of second half of si_ram */
+ area->entries_start = tsa->si_ram + (2 * quarter);
+ area->entries_next = area->entries_start + quarter;
+ area->last_entry = NULL;
+ }
+ } else {
+ if (is_rx) {
+ /* Second half of first half of si_ram */
+ area->entries_start = tsa->si_ram + quarter;
+ area->entries_next = area->entries_start + quarter;
+ area->last_entry = NULL;
+ } else {
+ /* Second half of second half of si_ram */
+ area->entries_start = tsa->si_ram + (3 * quarter);
+ area->entries_next = area->entries_start + quarter;
+ area->last_entry = NULL;
+ }
+ }
+ }
+}
+
+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";
+ case FSL_CPM_TSA_SCC2: return "SCC2";
+ case FSL_CPM_TSA_SCC3: return "SCC3";
+ case FSL_CPM_TSA_SCC4: return "SCC4";
+ case FSL_CPM_TSA_SMC1: return "SMC1";
+ case FSL_CPM_TSA_SMC2: return "SMC2";
+ default:
+ break;
+ }
+ return NULL;
+}
+
+static const char *tsa_qe_serial_id2name(struct tsa *tsa, u32 serial_id)
+{
+ switch (serial_id) {
+ 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 NULL;
+}
+
+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;
+ u32 val;
+ u32 cnt;
+ u32 nb;
+
+ addr = area->last_entry ? area->last_entry + 4 : area->entries_start;
+
+ nb = DIV_ROUND_UP(count, 8);
+ if ((addr + (nb * 4)) > area->entries_next) {
+ dev_err(tsa->dev, "si ram area full\n");
+ return -ENOSPC;
+ }
+
+ if (area->last_entry) {
+ /* Clear last flag */
+ tsa_clrbits32(area->last_entry, TSA_CPM1_SIRAM_ENTRY_LAST);
+ }
+
+ left = count;
+ while (left) {
+ val = TSA_CPM1_SIRAM_ENTRY_BYTE | tsa_cpm1_serial_id2csel(tsa, serial_id);
+
+ if (left > 16) {
+ cnt = 16;
+ } else {
+ cnt = left;
+ val |= TSA_CPM1_SIRAM_ENTRY_LAST;
+ area->last_entry = addr;
+ }
+ val |= TSA_CPM1_SIRAM_ENTRY_CNT(cnt - 1);
+
+ tsa_write32(addr, val);
+ addr += 4;
+ left -= cnt;
+ }
+
+ 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)
+{
+ struct tsa_entries_area area;
+ const char *route_name;
+ u32 serial_id;
+ int len, i;
+ u32 count;
+ const char *serial_name;
+ struct tsa_serial_info *serial_info;
+ struct tsa_tdm *tdm;
+ int ret;
+ u32 ts;
+
+ route_name = is_rx ? "fsl,rx-ts-routes" : "fsl,tx-ts-routes";
+
+ len = of_property_count_u32_elems(tdm_np, route_name);
+ if (len < 0) {
+ dev_err(tsa->dev, "%pOF: failed to read %s\n", tdm_np, route_name);
+ return len;
+ }
+ if (len % 2 != 0) {
+ dev_err(tsa->dev, "%pOF: wrong %s format\n", tdm_np, route_name);
+ return -EINVAL;
+ }
+
+ tsa_init_entries_area(tsa, &area, tdms, tdm_id, is_rx);
+ ts = 0;
+ for (i = 0; i < len; i += 2) {
+ of_property_read_u32_index(tdm_np, route_name, i, &count);
+ of_property_read_u32_index(tdm_np, route_name, i + 1, &serial_id);
+
+ if (serial_id >= ARRAY_SIZE(tsa->serials)) {
+ dev_err(tsa->dev, "%pOF: invalid serial id (%u)\n",
+ tdm_np, serial_id);
+ return -EINVAL;
+ }
+
+ serial_name = tsa_serial_id2name(tsa, serial_id);
+ if (!serial_name) {
+ dev_err(tsa->dev, "%pOF: unsupported serial id (%u)\n",
+ tdm_np, serial_id);
+ return -EINVAL;
+ }
+
+ dev_dbg(tsa->dev, "tdm_id=%u, %s ts %u..%u -> %s\n",
+ tdm_id, route_name, ts, ts + count - 1, serial_name);
+ ts += count;
+
+ ret = tsa_add_entry(tsa, &area, count, serial_id);
+ if (ret)
+ return ret;
+
+ serial_info = &tsa->serials[serial_id].info;
+ tdm = &tsa->tdm[tdm_id];
+ if (is_rx) {
+ serial_info->rx_fs_rate = clk_get_rate(tdm->l1rsync_clk);
+ serial_info->rx_bit_rate = clk_get_rate(tdm->l1rclk_clk);
+ serial_info->nb_rx_ts += count;
+ } else {
+ serial_info->tx_fs_rate = tdm->l1tsync_clk ?
+ clk_get_rate(tdm->l1tsync_clk) :
+ clk_get_rate(tdm->l1rsync_clk);
+ serial_info->tx_bit_rate = tdm->l1tclk_clk ?
+ clk_get_rate(tdm->l1tclk_clk) :
+ clk_get_rate(tdm->l1rclk_clk);
+ serial_info->nb_tx_ts += count;
+ }
+ }
+ return 0;
+}
+
+static inline int tsa_of_parse_tdm_rx_route(struct tsa *tsa,
+ struct device_node *tdm_np,
+ u32 tdms, u32 tdm_id)
+{
+ return tsa_of_parse_tdm_route(tsa, tdm_np, tdms, tdm_id, true);
+}
+
+static inline int tsa_of_parse_tdm_tx_route(struct tsa *tsa,
+ struct device_node *tdm_np,
+ u32 tdms, u32 tdm_id)
+{
+ return tsa_of_parse_tdm_route(tsa, tdm_np, tdms, tdm_id, false);
+}
+
+static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np)
+{
+ struct tsa_tdm *tdm;
+ struct clk *clk;
+ u32 tdm_id, val;
+ int ret;
+ int i;
+
+ tsa->tdms = 0;
+ for (i = 0; i < ARRAY_SIZE(tsa->tdm); i++)
+ tsa->tdm[i].is_enable = false;
+
+ 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);
+ return ret;
+ }
+ switch (tdm_id) {
+ case 0:
+ tsa->tdms |= BIT(TSA_TDMA);
+ break;
+ 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);
+ return -EINVAL;
+ }
+ }
+
+ 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);
+ return ret;
+ }
+
+ tdm = &tsa->tdm[tdm_id];
+ tdm->simode_tdm = TSA_SIMODE_TDM_SDM_NORM;
+
+ val = 0;
+ ret = of_property_read_u32(tdm_np, "fsl,rx-frame-sync-delay-bits",
+ &val);
+ if (ret && ret != -EINVAL) {
+ dev_err(tsa->dev,
+ "%pOF: failed to read fsl,rx-frame-sync-delay-bits\n",
+ tdm_np);
+ return ret;
+ }
+ if (val > 3) {
+ dev_err(tsa->dev,
+ "%pOF: Invalid fsl,rx-frame-sync-delay-bits (%u)\n",
+ tdm_np, val);
+ return -EINVAL;
+ }
+ tdm->simode_tdm |= TSA_SIMODE_TDM_RFSD(val);
+
+ val = 0;
+ ret = of_property_read_u32(tdm_np, "fsl,tx-frame-sync-delay-bits",
+ &val);
+ if (ret && ret != -EINVAL) {
+ dev_err(tsa->dev,
+ "%pOF: failed to read fsl,tx-frame-sync-delay-bits\n",
+ tdm_np);
+ return ret;
+ }
+ if (val > 3) {
+ dev_err(tsa->dev,
+ "%pOF: Invalid fsl,tx-frame-sync-delay-bits (%u)\n",
+ tdm_np, val);
+ return -EINVAL;
+ }
+ tdm->simode_tdm |= TSA_SIMODE_TDM_TFSD(val);
+
+ if (of_property_read_bool(tdm_np, "fsl,common-rxtx-pins"))
+ tdm->simode_tdm |= TSA_SIMODE_TDM_CRT;
+
+ if (of_property_read_bool(tdm_np, "fsl,clock-falling-edge"))
+ tdm->simode_tdm |= TSA_SIMODE_TDM_CE;
+
+ 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, tsa_is_qe(tsa) ? "rsync" : "l1rsync");
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ goto err;
+ }
+ ret = clk_prepare_enable(clk);
+ if (ret) {
+ clk_put(clk);
+ goto err;
+ }
+ tdm->l1rsync_clk = clk;
+
+ clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "rclk" : "l1rclk");
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ goto err;
+ }
+ ret = clk_prepare_enable(clk);
+ if (ret) {
+ clk_put(clk);
+ goto err;
+ }
+ tdm->l1rclk_clk = clk;
+
+ if (!(tdm->simode_tdm & TSA_SIMODE_TDM_CRT)) {
+ clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "tsync" : "l1tsync");
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ goto err;
+ }
+ ret = clk_prepare_enable(clk);
+ if (ret) {
+ clk_put(clk);
+ goto err;
+ }
+ tdm->l1tsync_clk = clk;
+
+ clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "tclk" : "l1tclk");
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ goto err;
+ }
+ ret = clk_prepare_enable(clk);
+ if (ret) {
+ clk_put(clk);
+ 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)
+ goto err;
+
+ ret = tsa_of_parse_tdm_tx_route(tsa, tdm_np, tsa->tdms, tdm_id);
+ if (ret)
+ goto err;
+
+ tdm->is_enable = true;
+ }
+ return 0;
+
+err:
+ 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);
+ }
+ if (tsa->tdm[i].l1rclk_clk) {
+ clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
+ clk_put(tsa->tdm[i].l1rclk_clk);
+ }
+ if (tsa->tdm[i].l1tsync_clk) {
+ clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
+ clk_put(tsa->tdm[i].l1rsync_clk);
+ }
+ if (tsa->tdm[i].l1tclk_clk) {
+ clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
+ clk_put(tsa->tdm[i].l1rclk_clk);
+ }
+ }
+ return ret;
+}
+
+static void tsa_init_si_ram(struct tsa *tsa)
+{
+ resource_size_t i;
+
+ /* Fill all entries as the last one */
+ 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)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *res;
+ struct tsa *tsa;
+ unsigned int i;
+ int ret;
+
+ tsa = devm_kzalloc(&pdev->dev, sizeof(*tsa), GFP_KERNEL);
+ if (!tsa)
+ 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;
+
+ spin_lock_init(&tsa->lock);
+
+ tsa->si_regs = devm_platform_ioremap_resource_byname(pdev, "si_regs");
+ if (IS_ERR(tsa->si_regs))
+ return PTR_ERR(tsa->si_regs);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "si_ram");
+ if (!res) {
+ dev_err(tsa->dev, "si_ram resource missing\n");
+ return -EINVAL;
+ }
+ tsa->si_ram_sz = resource_size(res);
+ tsa->si_ram = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(tsa->si_ram))
+ return PTR_ERR(tsa->si_ram);
+
+ tsa_init_si_ram(tsa);
+
+ ret = tsa_of_parse_tdms(tsa, np);
+ if (ret)
+ return ret;
+
+ ret = tsa_setup(tsa);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, tsa);
+
+ return 0;
+}
+
+static void tsa_remove(struct platform_device *pdev)
+{
+ struct tsa *tsa = platform_get_drvdata(pdev);
+ int 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);
+ }
+ if (tsa->tdm[i].l1rclk_clk) {
+ clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
+ clk_put(tsa->tdm[i].l1rclk_clk);
+ }
+ if (tsa->tdm[i].l1tsync_clk) {
+ clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
+ clk_put(tsa->tdm[i].l1rsync_clk);
+ }
+ if (tsa->tdm[i].l1tclk_clk) {
+ clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
+ clk_put(tsa->tdm[i].l1rclk_clk);
+ }
+ }
+}
+
+static const struct of_device_id tsa_id_table[] = {
+#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);
+
+static struct platform_driver tsa_driver = {
+ .driver = {
+ .name = "fsl-tsa",
+ .of_match_table = of_match_ptr(tsa_id_table),
+ },
+ .probe = tsa_probe,
+ .remove = tsa_remove,
+};
+module_platform_driver(tsa_driver);
+
+struct tsa_serial *tsa_serial_get_byphandle(struct device_node *np,
+ const char *phandle_name)
+{
+ struct of_phandle_args out_args;
+ struct platform_device *pdev;
+ struct tsa_serial *tsa_serial;
+ struct tsa *tsa;
+ int ret;
+
+ ret = of_parse_phandle_with_fixed_args(np, phandle_name, 1, 0, &out_args);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ if (!of_match_node(tsa_driver.driver.of_match_table, out_args.np)) {
+ of_node_put(out_args.np);
+ return ERR_PTR(-EINVAL);
+ }
+
+ pdev = of_find_device_by_node(out_args.np);
+ of_node_put(out_args.np);
+ if (!pdev)
+ return ERR_PTR(-ENODEV);
+
+ tsa = platform_get_drvdata(pdev);
+ if (!tsa) {
+ platform_device_put(pdev);
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+
+ if (out_args.args_count != 1) {
+ platform_device_put(pdev);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (out_args.args[0] >= ARRAY_SIZE(tsa->serials)) {
+ platform_device_put(pdev);
+ return ERR_PTR(-EINVAL);
+ }
+
+ tsa_serial = &tsa->serials[out_args.args[0]];
+
+ /*
+ * Be sure that the serial id matches the phandle arg.
+ * The tsa_serials table is indexed by serial ids. The serial id is set
+ * during the probe() call and needs to be coherent.
+ */
+ if (WARN_ON(tsa_serial->id != out_args.args[0])) {
+ platform_device_put(pdev);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return tsa_serial;
+}
+EXPORT_SYMBOL(tsa_serial_get_byphandle);
+
+void tsa_serial_put(struct tsa_serial *tsa_serial)
+{
+ struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);
+
+ put_device(tsa->dev);
+}
+EXPORT_SYMBOL(tsa_serial_put);
+
+static void devm_tsa_serial_release(struct device *dev, void *res)
+{
+ struct tsa_serial **tsa_serial = res;
+
+ tsa_serial_put(*tsa_serial);
+}
+
+struct tsa_serial *devm_tsa_serial_get_byphandle(struct device *dev,
+ struct device_node *np,
+ const char *phandle_name)
+{
+ struct tsa_serial *tsa_serial;
+ struct tsa_serial **dr;
+
+ dr = devres_alloc(devm_tsa_serial_release, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return ERR_PTR(-ENOMEM);
+
+ tsa_serial = tsa_serial_get_byphandle(np, phandle_name);
+ if (!IS_ERR(tsa_serial)) {
+ *dr = tsa_serial;
+ devres_add(dev, dr);
+ } else {
+ devres_free(dr);
+ }
+
+ return tsa_serial;
+}
+EXPORT_SYMBOL(devm_tsa_serial_get_byphandle);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+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
new file mode 100644
index 000000000000..da137bc0f49b
--- /dev/null
+++ b/drivers/soc/fsl/qe/tsa.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * TSA management
+ *
+ * Copyright 2022 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+#ifndef __SOC_FSL_TSA_H__
+#define __SOC_FSL_TSA_H__
+
+#include <linux/types.h>
+
+struct device_node;
+struct device;
+struct tsa_serial;
+
+struct tsa_serial *tsa_serial_get_byphandle(struct device_node *np,
+ const char *phandle_name);
+void tsa_serial_put(struct tsa_serial *tsa_serial);
+struct tsa_serial *devm_tsa_serial_get_byphandle(struct device *dev,
+ struct device_node *np,
+ const char *phandle_name);
+
+/* Connect and disconnect the TSA serial */
+int tsa_serial_connect(struct tsa_serial *tsa_serial);
+int tsa_serial_disconnect(struct tsa_serial *tsa_serial);
+
+/* Cell information */
+struct tsa_serial_info {
+ unsigned long rx_fs_rate;
+ unsigned long rx_bit_rate;
+ u8 nb_rx_ts;
+ unsigned long tx_fs_rate;
+ unsigned long tx_bit_rate;
+ u8 nb_tx_ts;
+};
+
+/* 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 d87f348427bf..76cb0b6a221c 100644
--- a/drivers/soc/fujitsu/a64fx-diag.c
+++ b/drivers/soc/fujitsu/a64fx-diag.c
@@ -116,7 +116,7 @@ static int a64fx_diag_probe(struct platform_device *pdev)
return 0;
}
-static int a64fx_diag_remove(struct platform_device *pdev)
+static void a64fx_diag_remove(struct platform_device *pdev)
{
struct a64fx_diag_priv *priv = platform_get_drvdata(pdev);
@@ -127,8 +127,6 @@ static int a64fx_diag_remove(struct platform_device *pdev)
free_nmi(priv->irq, NULL);
else
free_irq(priv->irq, NULL);
-
- return 0;
}
static const struct acpi_device_id a64fx_diag_acpi_match[] = {
@@ -149,6 +147,5 @@ static struct platform_driver a64fx_diag_driver = {
module_platform_driver(a64fx_diag_driver);
-MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Hitomi Hasegawa <hasegawa-hitomi@fujitsu.com>");
MODULE_DESCRIPTION("A64FX diag driver");
diff --git a/drivers/soc/hisilicon/Kconfig b/drivers/soc/hisilicon/Kconfig
new file mode 100644
index 000000000000..6d7c244d2e78
--- /dev/null
+++ b/drivers/soc/hisilicon/Kconfig
@@ -0,0 +1,24 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+menu "Hisilicon SoC drivers"
+ depends on ARCH_HISI || COMPILE_TEST
+
+config KUNPENG_HCCS
+ tristate "HCCS driver on Kunpeng SoC"
+ depends on ACPI
+ 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. 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, or reducing system
+ power consumption on Kunpeng SoC.
+
+endmenu
diff --git a/drivers/soc/hisilicon/Makefile b/drivers/soc/hisilicon/Makefile
new file mode 100644
index 000000000000..226e747e70d6
--- /dev/null
+++ b/drivers/soc/hisilicon/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_KUNPENG_HCCS) += kunpeng_hccs.o
diff --git a/drivers/soc/hisilicon/kunpeng_hccs.c b/drivers/soc/hisilicon/kunpeng_hccs.c
new file mode 100644
index 000000000000..006fec47ea10
--- /dev/null
+++ b/drivers/soc/hisilicon/kunpeng_hccs.c
@@ -0,0 +1,1834 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * The Huawei Cache Coherence System (HCCS) is a multi-chip interconnection
+ * bus protocol.
+ *
+ * Copyright (c) 2023 Hisilicon Limited.
+ * Author: Huisong Li <lihuisong@huawei.com>
+ *
+ * HCCS driver for Kunpeng SoC provides the following features:
+ * - Retrieve the following information about each port:
+ * - port type
+ * - lane mode
+ * - enable
+ * - current lane mode
+ * - link finite state machine
+ * - lane mask
+ * - CRC error count
+ *
+ * - Retrieve the following information about all the ports on the chip or
+ * the die:
+ * - 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>
+
+#include "kunpeng_hccs.h"
+
+/*
+ * Arbitrary retries in case the remote processor is slow to respond
+ * to PCC commands
+ */
+#define HCCS_PCC_CMD_WAIT_RETRIES_NUM 500ULL
+#define HCCS_POLL_STATUS_TIME_INTERVAL_US 3
+
+static struct hccs_port_info *kobj_to_port_info(struct kobject *k)
+{
+ return container_of(k, struct hccs_port_info, kobj);
+}
+
+static struct hccs_die_info *kobj_to_die_info(struct kobject *k)
+{
+ return container_of(k, struct hccs_die_info, kobj);
+}
+
+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;
+ int err;
+};
+
+static acpi_status hccs_get_register_cb(struct acpi_resource *ares,
+ void *context)
+{
+ struct acpi_resource_generic_register *reg;
+ struct hccs_register_ctx *ctx = context;
+
+ if (ares->type != ACPI_RESOURCE_TYPE_GENERIC_REGISTER)
+ return AE_OK;
+
+ reg = &ares->data.generic_reg;
+ if (reg->space_id != ACPI_ADR_SPACE_PLATFORM_COMM) {
+ dev_err(ctx->dev, "Bad register resource.\n");
+ ctx->err = -EINVAL;
+ return AE_ERROR;
+ }
+ ctx->chan_id = reg->access_size;
+
+ return AE_OK;
+}
+
+static int hccs_get_pcc_chan_id(struct hccs_dev *hdev)
+{
+ acpi_handle handle = ACPI_HANDLE(hdev->dev);
+ struct hccs_register_ctx ctx = {0};
+ acpi_status status;
+
+ if (!acpi_has_method(handle, METHOD_NAME__CRS)) {
+ dev_err(hdev->dev, "No _CRS method.\n");
+ return -ENODEV;
+ }
+
+ ctx.dev = hdev->dev;
+ status = acpi_walk_resources(handle, METHOD_NAME__CRS,
+ hccs_get_register_cb, &ctx);
+ if (ACPI_FAILURE(status))
+ return ctx.err;
+ hdev->chan_id = ctx.chan_id;
+
+ return 0;
+}
+
+static void hccs_chan_tx_done(struct mbox_client *cl, void *msg, int ret)
+{
+ if (ret < 0)
+ pr_debug("TX did not complete: CMD sent:0x%x, ret:%d\n",
+ *(u8 *)msg, ret);
+ else
+ pr_debug("TX completed. CMD sent:0x%x, ret:%d\n",
+ *(u8 *)msg, ret);
+}
+
+static void hccs_pcc_rx_callback(struct mbox_client *cl, void *mssg)
+{
+ struct hccs_mbox_client_info *cl_info =
+ container_of(cl, struct hccs_mbox_client_info, client);
+
+ complete(&cl_info->done);
+}
+
+static void hccs_unregister_pcc_channel(struct hccs_dev *hdev)
+{
+ pcc_mbox_free_channel(hdev->cl_info.pcc_chan);
+}
+
+static int hccs_register_pcc_channel(struct hccs_dev *hdev)
+{
+ struct hccs_mbox_client_info *cl_info = &hdev->cl_info;
+ struct mbox_client *cl = &cl_info->client;
+ struct pcc_mbox_chan *pcc_chan;
+ struct mbox_chan *mbox_chan;
+ struct device *dev = hdev->dev;
+ int rc;
+
+ cl->dev = dev;
+ cl->tx_block = false;
+ cl->knows_txdone = true;
+ cl->tx_done = hccs_chan_tx_done;
+ cl->rx_callback = hdev->verspec_data->rx_callback;
+ init_completion(&cl_info->done);
+
+ pcc_chan = pcc_mbox_request_channel(cl, hdev->chan_id);
+ if (IS_ERR(pcc_chan)) {
+ dev_err(dev, "PCC channel request failed.\n");
+ rc = -ENODEV;
+ goto out;
+ }
+ cl_info->pcc_chan = pcc_chan;
+ mbox_chan = pcc_chan->mchan;
+
+ /*
+ * pcc_chan->latency is just a nominal value. In reality the remote
+ * processor could be much slower to reply. So add an arbitrary amount
+ * of wait on top of nominal.
+ */
+ cl_info->deadline_us =
+ HCCS_PCC_CMD_WAIT_RETRIES_NUM * pcc_chan->latency;
+ if (!hdev->verspec_data->has_txdone_irq &&
+ mbox_chan->mbox->txdone_irq) {
+ dev_err(dev, "PCC IRQ in PCCT is enabled.\n");
+ rc = -EINVAL;
+ goto err_mbx_channel_free;
+ } else if (hdev->verspec_data->has_txdone_irq &&
+ !mbox_chan->mbox->txdone_irq) {
+ dev_err(dev, "PCC IRQ in PCCT isn't supported.\n");
+ rc = -EINVAL;
+ goto err_mbx_channel_free;
+ }
+
+ if (pcc_chan->shmem_size != HCCS_PCC_SHARE_MEM_BYTES) {
+ dev_err(dev, "Base size (%llu) of PCC communication region must be %d bytes.\n",
+ pcc_chan->shmem_size, HCCS_PCC_SHARE_MEM_BYTES);
+ rc = -EINVAL;
+ goto err_mbx_channel_free;
+ }
+
+ return 0;
+
+err_mbx_channel_free:
+ pcc_mbox_free_channel(cl_info->pcc_chan);
+out:
+ return rc;
+}
+
+static int hccs_wait_cmd_complete_by_poll(struct hccs_dev *hdev)
+{
+ struct hccs_mbox_client_info *cl_info = &hdev->cl_info;
+ struct acpi_pcct_shared_memory __iomem *comm_base =
+ cl_info->pcc_chan->shmem;
+ u16 status;
+ int ret;
+
+ /*
+ * Poll PCC status register every 3us(delay_us) for maximum of
+ * deadline_us(timeout_us) until PCC command complete bit is set(cond)
+ */
+ ret = readw_poll_timeout(&comm_base->status, status,
+ status & PCC_STATUS_CMD_COMPLETE,
+ HCCS_POLL_STATUS_TIME_INTERVAL_US,
+ cl_info->deadline_us);
+ if (unlikely(ret))
+ dev_err(hdev->dev, "poll PCC status failed, ret = %d.\n", ret);
+
+ return ret;
+}
+
+static int hccs_wait_cmd_complete_by_irq(struct hccs_dev *hdev)
+{
+ struct hccs_mbox_client_info *cl_info = &hdev->cl_info;
+
+ if (!wait_for_completion_timeout(&cl_info->done,
+ usecs_to_jiffies(cl_info->deadline_us))) {
+ dev_err(hdev->dev, "PCC command executed timeout!\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static inline void hccs_fill_pcc_shared_mem_region(struct hccs_dev *hdev,
+ u8 cmd,
+ struct hccs_desc *desc,
+ void __iomem *comm_space,
+ u16 space_size)
+{
+ struct acpi_pcct_shared_memory tmp = {
+ .signature = PCC_SIGNATURE | hdev->chan_id,
+ .command = cmd,
+ .status = 0,
+ };
+
+ memcpy_toio(hdev->cl_info.pcc_chan->shmem, (void *)&tmp,
+ sizeof(struct acpi_pcct_shared_memory));
+
+ /* Copy the message to the PCC comm space */
+ memcpy_toio(comm_space, (void *)desc, space_size);
+}
+
+static inline void hccs_fill_ext_pcc_shared_mem_region(struct hccs_dev *hdev,
+ u8 cmd,
+ struct hccs_desc *desc,
+ void __iomem *comm_space,
+ u16 space_size)
+{
+ struct acpi_pcct_ext_pcc_shared_memory tmp = {
+ .signature = PCC_SIGNATURE | hdev->chan_id,
+ .flags = PCC_CMD_COMPLETION_NOTIFY,
+ .length = HCCS_PCC_SHARE_MEM_BYTES,
+ .command = cmd,
+ };
+
+ memcpy_toio(hdev->cl_info.pcc_chan->shmem, (void *)&tmp,
+ sizeof(struct acpi_pcct_ext_pcc_shared_memory));
+
+ /* Copy the message to the PCC comm space */
+ memcpy_toio(comm_space, (void *)desc, space_size);
+}
+
+static int hccs_pcc_cmd_send(struct hccs_dev *hdev, u8 cmd,
+ struct hccs_desc *desc)
+{
+ const struct hccs_verspecific_data *verspec_data = hdev->verspec_data;
+ struct hccs_mbox_client_info *cl_info = &hdev->cl_info;
+ struct mbox_chan *mbox_chan = cl_info->pcc_chan->mchan;
+ struct hccs_fw_inner_head *fw_inner_head;
+ void __iomem *comm_space;
+ u16 space_size;
+ int ret;
+
+ comm_space = cl_info->pcc_chan->shmem + verspec_data->shared_mem_size;
+ space_size = HCCS_PCC_SHARE_MEM_BYTES - verspec_data->shared_mem_size;
+ verspec_data->fill_pcc_shared_mem(hdev, cmd, desc,
+ comm_space, space_size);
+ if (verspec_data->has_txdone_irq)
+ reinit_completion(&cl_info->done);
+
+ /* Ring doorbell */
+ ret = mbox_send_message(mbox_chan, &cmd);
+ if (ret < 0) {
+ dev_err(hdev->dev, "Send PCC mbox message failed, ret = %d.\n",
+ ret);
+ goto end;
+ }
+
+ ret = verspec_data->wait_cmd_complete(hdev);
+ if (ret)
+ goto end;
+
+ /* Copy response data */
+ memcpy_fromio((void *)desc, comm_space, space_size);
+ fw_inner_head = &desc->rsp.fw_inner_head;
+ if (fw_inner_head->retStatus) {
+ dev_err(hdev->dev, "Execute PCC command failed, error code = %u.\n",
+ fw_inner_head->retStatus);
+ ret = -EIO;
+ }
+
+end:
+ if (verspec_data->has_txdone_irq)
+ mbox_chan_txdone(mbox_chan, ret);
+ else
+ mbox_client_txdone(mbox_chan, ret);
+ return ret;
+}
+
+static void hccs_init_req_desc(struct hccs_desc *desc)
+{
+ struct hccs_req_desc *req = &desc->req;
+
+ memset(desc, 0, sizeof(*desc));
+ req->req_head.module_code = HCCS_SERDES_MODULE_CODE;
+}
+
+static int hccs_get_dev_caps(struct hccs_dev *hdev)
+{
+ struct hccs_desc desc;
+ int ret;
+
+ hccs_init_req_desc(&desc);
+ ret = hccs_pcc_cmd_send(hdev, HCCS_GET_DEV_CAP, &desc);
+ if (ret) {
+ dev_err(hdev->dev, "Get device capabilities failed, ret = %d.\n",
+ ret);
+ return ret;
+ }
+ memcpy(&hdev->caps, desc.rsp.data, sizeof(hdev->caps));
+
+ return 0;
+}
+
+static int hccs_query_chip_num_on_platform(struct hccs_dev *hdev)
+{
+ struct hccs_desc desc;
+ int ret;
+
+ hccs_init_req_desc(&desc);
+ ret = hccs_pcc_cmd_send(hdev, HCCS_GET_CHIP_NUM, &desc);
+ if (ret) {
+ dev_err(hdev->dev, "query system chip number failed, ret = %d.\n",
+ ret);
+ return ret;
+ }
+
+ hdev->chip_num = *((u8 *)&desc.rsp.data);
+ if (!hdev->chip_num) {
+ dev_err(hdev->dev, "chip num obtained from firmware is zero.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int hccs_get_chip_info(struct hccs_dev *hdev,
+ struct hccs_chip_info *chip)
+{
+ struct hccs_die_num_req_param *req_param;
+ struct hccs_desc desc;
+ int ret;
+
+ hccs_init_req_desc(&desc);
+ req_param = (struct hccs_die_num_req_param *)desc.req.data;
+ req_param->chip_id = chip->chip_id;
+ ret = hccs_pcc_cmd_send(hdev, HCCS_GET_DIE_NUM, &desc);
+ if (ret)
+ return ret;
+
+ chip->die_num = *((u8 *)&desc.rsp.data);
+
+ return 0;
+}
+
+static int hccs_query_chip_info_on_platform(struct hccs_dev *hdev)
+{
+ struct hccs_chip_info *chip;
+ int ret;
+ u8 idx;
+
+ ret = hccs_query_chip_num_on_platform(hdev);
+ if (ret) {
+ dev_err(hdev->dev, "query chip number on platform failed, ret = %d.\n",
+ ret);
+ return ret;
+ }
+
+ hdev->chips = devm_kzalloc(hdev->dev,
+ hdev->chip_num * sizeof(struct hccs_chip_info),
+ GFP_KERNEL);
+ if (!hdev->chips) {
+ dev_err(hdev->dev, "allocate all chips memory failed.\n");
+ return -ENOMEM;
+ }
+
+ for (idx = 0; idx < hdev->chip_num; idx++) {
+ chip = &hdev->chips[idx];
+ chip->chip_id = idx;
+ ret = hccs_get_chip_info(hdev, chip);
+ if (ret) {
+ dev_err(hdev->dev, "get chip%u info failed, ret = %d.\n",
+ idx, ret);
+ return ret;
+ }
+ chip->hdev = hdev;
+ }
+
+ return 0;
+}
+
+static int hccs_query_die_info_on_chip(struct hccs_dev *hdev, u8 chip_id,
+ u8 die_idx, struct hccs_die_info *die)
+{
+ struct hccs_die_info_req_param *req_param;
+ struct hccs_die_info_rsp_data *rsp_data;
+ struct hccs_desc desc;
+ int ret;
+
+ hccs_init_req_desc(&desc);
+ req_param = (struct hccs_die_info_req_param *)desc.req.data;
+ req_param->chip_id = chip_id;
+ req_param->die_idx = die_idx;
+ ret = hccs_pcc_cmd_send(hdev, HCCS_GET_DIE_INFO, &desc);
+ if (ret)
+ return ret;
+
+ rsp_data = (struct hccs_die_info_rsp_data *)desc.rsp.data;
+ die->die_id = rsp_data->die_id;
+ die->port_num = rsp_data->port_num;
+ die->min_port_id = rsp_data->min_port_id;
+ die->max_port_id = rsp_data->max_port_id;
+ if (die->min_port_id > die->max_port_id) {
+ dev_err(hdev->dev, "min port id(%u) > max port id(%u) on die_idx(%u).\n",
+ die->min_port_id, die->max_port_id, die_idx);
+ return -EINVAL;
+ }
+ if (die->max_port_id > HCCS_DIE_MAX_PORT_ID) {
+ dev_err(hdev->dev, "max port id(%u) on die_idx(%u) is too big.\n",
+ die->max_port_id, die_idx);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+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;
+
+ for (i = 0; i < hdev->chip_num; i++) {
+ chip = &hdev->chips[i];
+ 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);
+ if (!chip->dies) {
+ dev_err(dev, "allocate all dies memory on chip%u failed.\n",
+ i);
+ return -ENOMEM;
+ }
+
+ for (j = 0; j < chip->die_num; j++) {
+ die = &chip->dies[j];
+ ret = hccs_query_die_info_on_chip(hdev, i, j, die);
+ if (ret) {
+ dev_err(dev, "get die idx (%u) info on chip%u failed, ret = %d.\n",
+ j, i, ret);
+ return ret;
+ }
+ die->chip = chip;
+ }
+ }
+
+ return has_die_info ? 0 : -EINVAL;
+}
+
+static int hccs_get_bd_info(struct hccs_dev *hdev, u8 opcode,
+ struct hccs_desc *desc,
+ void *buf, size_t buf_len,
+ struct hccs_rsp_head *rsp_head)
+{
+ struct hccs_rsp_head *head;
+ struct hccs_rsp_desc *rsp;
+ int ret;
+
+ ret = hccs_pcc_cmd_send(hdev, opcode, desc);
+ if (ret)
+ return ret;
+
+ rsp = &desc->rsp;
+ head = &rsp->rsp_head;
+ if (head->data_len > buf_len) {
+ dev_err(hdev->dev,
+ "buffer overflow (buf_len = %zu, data_len = %u)!\n",
+ buf_len, head->data_len);
+ return -ENOMEM;
+ }
+
+ memcpy(buf, rsp->data, head->data_len);
+ *rsp_head = *head;
+
+ return 0;
+}
+
+static int hccs_get_all_port_attr(struct hccs_dev *hdev,
+ struct hccs_die_info *die,
+ struct hccs_port_attr *attrs, u16 size)
+{
+ struct hccs_die_comm_req_param *req_param;
+ struct hccs_req_head *req_head;
+ struct hccs_rsp_head rsp_head;
+ struct hccs_desc desc;
+ size_t left_buf_len;
+ u32 data_len = 0;
+ u8 start_id;
+ u8 *buf;
+ int ret;
+
+ buf = (u8 *)attrs;
+ left_buf_len = sizeof(struct hccs_port_attr) * size;
+ start_id = die->min_port_id;
+ while (start_id <= die->max_port_id) {
+ hccs_init_req_desc(&desc);
+ req_head = &desc.req.req_head;
+ req_head->start_id = start_id;
+ req_param = (struct hccs_die_comm_req_param *)desc.req.data;
+ req_param->chip_id = die->chip->chip_id;
+ req_param->die_id = die->die_id;
+
+ ret = hccs_get_bd_info(hdev, HCCS_GET_DIE_PORT_INFO, &desc,
+ buf + data_len, left_buf_len, &rsp_head);
+ if (ret) {
+ dev_err(hdev->dev,
+ "get the information of port%u on die%u failed, ret = %d.\n",
+ start_id, die->die_id, ret);
+ return ret;
+ }
+
+ data_len += rsp_head.data_len;
+ left_buf_len -= rsp_head.data_len;
+ if (unlikely(rsp_head.next_id <= start_id)) {
+ dev_err(hdev->dev,
+ "next port id (%u) is not greater than last start id (%u) on die%u.\n",
+ rsp_head.next_id, start_id, die->die_id);
+ return -EINVAL;
+ }
+ 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;
+}
+
+static int hccs_get_all_port_info_on_die(struct hccs_dev *hdev,
+ struct hccs_die_info *die)
+{
+ struct hccs_port_attr *attrs;
+ struct hccs_port_info *port;
+ int ret;
+ u8 i;
+
+ attrs = kcalloc(die->port_num, sizeof(struct hccs_port_attr),
+ GFP_KERNEL);
+ if (!attrs)
+ return -ENOMEM;
+
+ ret = hccs_get_all_port_attr(hdev, die, attrs, die->port_num);
+ if (ret)
+ goto out;
+
+ for (i = 0; i < die->port_num; i++) {
+ port = &die->ports[i];
+ port->port_id = attrs[i].port_id;
+ port->port_type = attrs[i].port_type;
+ port->max_lane_num = attrs[i].max_lane_num;
+ port->enable = attrs[i].enable;
+ port->die = die;
+ }
+
+out:
+ kfree(attrs);
+ return ret;
+}
+
+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;
+
+ for (i = 0; i < hdev->chip_num; i++) {
+ chip = &hdev->chips[i];
+ for (j = 0; j < chip->die_num; j++) {
+ die = &chip->dies[j];
+ if (!die->port_num)
+ continue;
+
+ has_port_info = true;
+ die->ports = devm_kzalloc(dev,
+ die->port_num * sizeof(struct hccs_port_info),
+ GFP_KERNEL);
+ if (!die->ports) {
+ dev_err(dev, "allocate ports memory on chip%u/die%u failed.\n",
+ i, die->die_id);
+ return -ENOMEM;
+ }
+
+ ret = hccs_get_all_port_info_on_die(hdev, die);
+ if (ret) {
+ dev_err(dev, "get all port info on chip%u/die%u failed, ret = %d.\n",
+ i, die->die_id, ret);
+ return ret;
+ }
+ }
+ }
+
+ return has_port_info ? 0 : -EINVAL;
+}
+
+static int hccs_get_hw_info(struct hccs_dev *hdev)
+{
+ int ret;
+
+ ret = hccs_query_chip_info_on_platform(hdev);
+ if (ret) {
+ dev_err(hdev->dev, "query chip info on platform failed, ret = %d.\n",
+ ret);
+ return ret;
+ }
+
+ ret = hccs_query_all_die_info_on_platform(hdev);
+ if (ret) {
+ dev_err(hdev->dev, "query all die info on platform failed, ret = %d.\n",
+ ret);
+ return ret;
+ }
+
+ ret = hccs_query_all_port_info_on_platform(hdev);
+ if (ret) {
+ dev_err(hdev->dev, "query all port info on platform failed, ret = %d.\n",
+ ret);
+ return ret;
+ }
+
+ 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)
+{
+ 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_LINK_STATUS, &desc);
+ if (ret) {
+ dev_err(hdev->dev,
+ "get port link status info failed, ret = %d.\n", ret);
+ return ret;
+ }
+
+ *link_status = *((struct hccs_link_status *)desc.rsp.data);
+
+ return 0;
+}
+
+static int hccs_query_port_crc_err_cnt(struct hccs_dev *hdev,
+ const struct hccs_port_info *port,
+ u64 *crc_err_cnt)
+{
+ 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_CRC_ERR_CNT, &desc);
+ if (ret) {
+ dev_err(hdev->dev,
+ "get port crc error count failed, ret = %d.\n", ret);
+ return ret;
+ }
+
+ memcpy(crc_err_cnt, &desc.rsp.data, sizeof(u64));
+
+ return 0;
+}
+
+static int hccs_get_die_all_link_status(struct hccs_dev *hdev,
+ const struct hccs_die_info *die,
+ u8 *all_linked)
+{
+ struct hccs_die_comm_req_param *req_param;
+ struct hccs_desc desc;
+ int ret;
+
+ if (die->port_num == 0) {
+ *all_linked = 1;
+ return 0;
+ }
+
+ hccs_init_req_desc(&desc);
+ req_param = (struct hccs_die_comm_req_param *)desc.req.data;
+ req_param->chip_id = die->chip->chip_id;
+ req_param->die_id = die->die_id;
+ ret = hccs_pcc_cmd_send(hdev, HCCS_GET_DIE_PORTS_LINK_STA, &desc);
+ if (ret) {
+ dev_err(hdev->dev,
+ "get link status of all ports failed on die%u, ret = %d.\n",
+ die->die_id, ret);
+ return ret;
+ }
+
+ *all_linked = *((u8 *)&desc.rsp.data);
+
+ return 0;
+}
+
+static int hccs_get_die_all_port_lane_status(struct hccs_dev *hdev,
+ const struct hccs_die_info *die,
+ u8 *full_lane)
+{
+ struct hccs_die_comm_req_param *req_param;
+ struct hccs_desc desc;
+ int ret;
+
+ if (die->port_num == 0) {
+ *full_lane = 1;
+ return 0;
+ }
+
+ hccs_init_req_desc(&desc);
+ req_param = (struct hccs_die_comm_req_param *)desc.req.data;
+ req_param->chip_id = die->chip->chip_id;
+ req_param->die_id = die->die_id;
+ ret = hccs_pcc_cmd_send(hdev, HCCS_GET_DIE_PORTS_LANE_STA, &desc);
+ if (ret) {
+ dev_err(hdev->dev, "get lane status of all ports failed on die%u, ret = %d.\n",
+ die->die_id, ret);
+ return ret;
+ }
+
+ *full_lane = *((u8 *)&desc.rsp.data);
+
+ return 0;
+}
+
+static int hccs_get_die_total_crc_err_cnt(struct hccs_dev *hdev,
+ const struct hccs_die_info *die,
+ u64 *total_crc_err_cnt)
+{
+ struct hccs_die_comm_req_param *req_param;
+ struct hccs_desc desc;
+ int ret;
+
+ if (die->port_num == 0) {
+ *total_crc_err_cnt = 0;
+ return 0;
+ }
+
+ hccs_init_req_desc(&desc);
+ req_param = (struct hccs_die_comm_req_param *)desc.req.data;
+ req_param->chip_id = die->chip->chip_id;
+ req_param->die_id = die->die_id;
+ ret = hccs_pcc_cmd_send(hdev, HCCS_GET_DIE_PORTS_CRC_ERR_CNT, &desc);
+ if (ret) {
+ dev_err(hdev->dev, "get crc error count sum failed on die%u, ret = %d.\n",
+ die->die_id, ret);
+ return ret;
+ }
+
+ memcpy(total_crc_err_cnt, &desc.rsp.data, sizeof(u64));
+
+ return 0;
+}
+
+static ssize_t hccs_show(struct kobject *k, struct attribute *attr, char *buf)
+{
+ struct kobj_attribute *kobj_attr;
+
+ kobj_attr = container_of(attr, struct kobj_attribute, attr);
+
+ return kobj_attr->show(k, kobj_attr, buf);
+}
+
+static const struct sysfs_ops hccs_comm_ops = {
+ .show = hccs_show,
+};
+
+static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ const struct hccs_port_info *port = kobj_to_port_info(kobj);
+
+ return sysfs_emit(buf, "%s%u\n", HCCS_IP_PREFIX, port->port_type);
+}
+static struct kobj_attribute hccs_type_attr = __ATTR_RO(type);
+
+static ssize_t lane_mode_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ const struct hccs_port_info *port = kobj_to_port_info(kobj);
+
+ return sysfs_emit(buf, "x%u\n", port->max_lane_num);
+}
+static struct kobj_attribute lane_mode_attr = __ATTR_RO(lane_mode);
+
+static ssize_t enable_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ const struct hccs_port_info *port = kobj_to_port_info(kobj);
+
+ return sysfs_emit(buf, "%u\n", port->enable);
+}
+static struct kobj_attribute port_enable_attr = __ATTR_RO(enable);
+
+static ssize_t cur_lane_num_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ const struct hccs_port_info *port = kobj_to_port_info(kobj);
+ struct hccs_dev *hdev = port->die->chip->hdev;
+ struct hccs_link_status link_status = {0};
+ int ret;
+
+ mutex_lock(&hdev->lock);
+ ret = hccs_query_port_link_status(hdev, port, &link_status);
+ mutex_unlock(&hdev->lock);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%u\n", link_status.lane_num);
+}
+static struct kobj_attribute cur_lane_num_attr = __ATTR_RO(cur_lane_num);
+
+static ssize_t link_fsm_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ const struct hccs_port_info *port = kobj_to_port_info(kobj);
+ struct hccs_dev *hdev = port->die->chip->hdev;
+ struct hccs_link_status link_status = {0};
+ const struct {
+ u8 link_fsm;
+ char *str;
+ } link_fsm_map[] = {
+ {HCCS_PORT_RESET, "reset"},
+ {HCCS_PORT_SETUP, "setup"},
+ {HCCS_PORT_CONFIG, "config"},
+ {HCCS_PORT_READY, "link-up"},
+ };
+ const char *link_fsm_str = "unknown";
+ size_t i;
+ int ret;
+
+ mutex_lock(&hdev->lock);
+ ret = hccs_query_port_link_status(hdev, port, &link_status);
+ mutex_unlock(&hdev->lock);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(link_fsm_map); i++) {
+ if (link_fsm_map[i].link_fsm == link_status.link_fsm) {
+ link_fsm_str = link_fsm_map[i].str;
+ break;
+ }
+ }
+
+ return sysfs_emit(buf, "%s\n", link_fsm_str);
+}
+static struct kobj_attribute link_fsm_attr = __ATTR_RO(link_fsm);
+
+static ssize_t lane_mask_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ const struct hccs_port_info *port = kobj_to_port_info(kobj);
+ struct hccs_dev *hdev = port->die->chip->hdev;
+ struct hccs_link_status link_status = {0};
+ int ret;
+
+ mutex_lock(&hdev->lock);
+ ret = hccs_query_port_link_status(hdev, port, &link_status);
+ mutex_unlock(&hdev->lock);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "0x%x\n", link_status.lane_mask);
+}
+static struct kobj_attribute lane_mask_attr = __ATTR_RO(lane_mask);
+
+static ssize_t crc_err_cnt_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ const struct hccs_port_info *port = kobj_to_port_info(kobj);
+ struct hccs_dev *hdev = port->die->chip->hdev;
+ u64 crc_err_cnt;
+ int ret;
+
+ mutex_lock(&hdev->lock);
+ ret = hccs_query_port_crc_err_cnt(hdev, port, &crc_err_cnt);
+ mutex_unlock(&hdev->lock);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%llu\n", crc_err_cnt);
+}
+static struct kobj_attribute crc_err_cnt_attr = __ATTR_RO(crc_err_cnt);
+
+static struct attribute *hccs_port_default_attrs[] = {
+ &hccs_type_attr.attr,
+ &lane_mode_attr.attr,
+ &port_enable_attr.attr,
+ &cur_lane_num_attr.attr,
+ &link_fsm_attr.attr,
+ &lane_mask_attr.attr,
+ &crc_err_cnt_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(hccs_port_default);
+
+static const struct kobj_type hccs_port_type = {
+ .sysfs_ops = &hccs_comm_ops,
+ .default_groups = hccs_port_default_groups,
+};
+
+static ssize_t all_linked_on_die_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ const struct hccs_die_info *die = kobj_to_die_info(kobj);
+ struct hccs_dev *hdev = die->chip->hdev;
+ u8 all_linked;
+ int ret;
+
+ mutex_lock(&hdev->lock);
+ ret = hccs_get_die_all_link_status(hdev, die, &all_linked);
+ mutex_unlock(&hdev->lock);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%u\n", all_linked);
+}
+static struct kobj_attribute all_linked_on_die_attr =
+ __ATTR(all_linked, 0444, all_linked_on_die_show, NULL);
+
+static ssize_t linked_full_lane_on_die_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ const struct hccs_die_info *die = kobj_to_die_info(kobj);
+ struct hccs_dev *hdev = die->chip->hdev;
+ u8 full_lane;
+ int ret;
+
+ mutex_lock(&hdev->lock);
+ ret = hccs_get_die_all_port_lane_status(hdev, die, &full_lane);
+ mutex_unlock(&hdev->lock);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%u\n", full_lane);
+}
+static struct kobj_attribute linked_full_lane_on_die_attr =
+ __ATTR(linked_full_lane, 0444, linked_full_lane_on_die_show, NULL);
+
+static ssize_t crc_err_cnt_sum_on_die_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ const struct hccs_die_info *die = kobj_to_die_info(kobj);
+ struct hccs_dev *hdev = die->chip->hdev;
+ u64 total_crc_err_cnt;
+ int ret;
+
+ mutex_lock(&hdev->lock);
+ ret = hccs_get_die_total_crc_err_cnt(hdev, die, &total_crc_err_cnt);
+ mutex_unlock(&hdev->lock);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%llu\n", total_crc_err_cnt);
+}
+static struct kobj_attribute crc_err_cnt_sum_on_die_attr =
+ __ATTR(crc_err_cnt, 0444, crc_err_cnt_sum_on_die_show, NULL);
+
+static struct attribute *hccs_die_default_attrs[] = {
+ &all_linked_on_die_attr.attr,
+ &linked_full_lane_on_die_attr.attr,
+ &crc_err_cnt_sum_on_die_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(hccs_die_default);
+
+static const struct kobj_type hccs_die_type = {
+ .sysfs_ops = &hccs_comm_ops,
+ .default_groups = hccs_die_default_groups,
+};
+
+static ssize_t all_linked_on_chip_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ const struct hccs_chip_info *chip = kobj_to_chip_info(kobj);
+ struct hccs_dev *hdev = chip->hdev;
+ const struct hccs_die_info *die;
+ u8 all_linked = 1;
+ u8 i, tmp;
+ int ret;
+
+ mutex_lock(&hdev->lock);
+ for (i = 0; i < chip->die_num; i++) {
+ die = &chip->dies[i];
+ ret = hccs_get_die_all_link_status(hdev, die, &tmp);
+ if (ret) {
+ mutex_unlock(&hdev->lock);
+ return ret;
+ }
+ if (tmp != all_linked) {
+ all_linked = 0;
+ break;
+ }
+ }
+ mutex_unlock(&hdev->lock);
+
+ return sysfs_emit(buf, "%u\n", all_linked);
+}
+static struct kobj_attribute all_linked_on_chip_attr =
+ __ATTR(all_linked, 0444, all_linked_on_chip_show, NULL);
+
+static ssize_t linked_full_lane_on_chip_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ const struct hccs_chip_info *chip = kobj_to_chip_info(kobj);
+ struct hccs_dev *hdev = chip->hdev;
+ const struct hccs_die_info *die;
+ u8 full_lane = 1;
+ u8 i, tmp;
+ int ret;
+
+ mutex_lock(&hdev->lock);
+ for (i = 0; i < chip->die_num; i++) {
+ die = &chip->dies[i];
+ ret = hccs_get_die_all_port_lane_status(hdev, die, &tmp);
+ if (ret) {
+ mutex_unlock(&hdev->lock);
+ return ret;
+ }
+ if (tmp != full_lane) {
+ full_lane = 0;
+ break;
+ }
+ }
+ mutex_unlock(&hdev->lock);
+
+ return sysfs_emit(buf, "%u\n", full_lane);
+}
+static struct kobj_attribute linked_full_lane_on_chip_attr =
+ __ATTR(linked_full_lane, 0444, linked_full_lane_on_chip_show, NULL);
+
+static ssize_t crc_err_cnt_sum_on_chip_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ const struct hccs_chip_info *chip = kobj_to_chip_info(kobj);
+ u64 crc_err_cnt, total_crc_err_cnt = 0;
+ struct hccs_dev *hdev = chip->hdev;
+ const struct hccs_die_info *die;
+ int ret;
+ u16 i;
+
+ mutex_lock(&hdev->lock);
+ for (i = 0; i < chip->die_num; i++) {
+ die = &chip->dies[i];
+ ret = hccs_get_die_total_crc_err_cnt(hdev, die, &crc_err_cnt);
+ if (ret) {
+ mutex_unlock(&hdev->lock);
+ return ret;
+ }
+
+ total_crc_err_cnt += crc_err_cnt;
+ }
+ mutex_unlock(&hdev->lock);
+
+ return sysfs_emit(buf, "%llu\n", total_crc_err_cnt);
+}
+static struct kobj_attribute crc_err_cnt_sum_on_chip_attr =
+ __ATTR(crc_err_cnt, 0444, crc_err_cnt_sum_on_chip_show, NULL);
+
+static struct attribute *hccs_chip_default_attrs[] = {
+ &all_linked_on_chip_attr.attr,
+ &linked_full_lane_on_chip_attr.attr,
+ &crc_err_cnt_sum_on_chip_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(hccs_chip_default);
+
+static const struct kobj_type hccs_chip_type = {
+ .sysfs_ops = &hccs_comm_ops,
+ .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",
+ port->port_id, chip->chip_id, die->die_id, ret);
+ return ret;
+ } else if (idle == 0) {
+ dev_info(hdev->dev, "hccs%u on chip%u/die%u is busy.\n",
+ port->port_id, chip->chip_id, die->die_id);
+ 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 decrease 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;
+ u8 i;
+
+ for (i = 0; i < die->port_num; i++) {
+ port = &die->ports[i];
+ if (port->dir_created)
+ kobject_put(&port->kobj);
+ }
+
+ kobject_put(&die->kobj);
+}
+
+static void hccs_remove_chip_dir(struct hccs_chip_info *chip)
+{
+ struct hccs_die_info *die;
+ u8 i;
+
+ for (i = 0; i < chip->die_num; i++) {
+ die = &chip->dies[i];
+ if (die->dir_created)
+ hccs_remove_die_dir(die);
+ }
+
+ kobject_put(&chip->kobj);
+}
+
+static void hccs_remove_topo_dirs(struct hccs_dev *hdev)
+{
+ u8 i;
+
+ 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,
+ struct hccs_die_info *die,
+ struct hccs_port_info *port)
+{
+ int ret;
+
+ ret = kobject_init_and_add(&port->kobj, &hccs_port_type,
+ &die->kobj, "hccs%u", port->port_id);
+ if (ret) {
+ kobject_put(&port->kobj);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int hccs_create_die_dir(struct hccs_dev *hdev,
+ struct hccs_chip_info *chip,
+ struct hccs_die_info *die)
+{
+ struct hccs_port_info *port;
+ int ret;
+ u16 i;
+
+ ret = kobject_init_and_add(&die->kobj, &hccs_die_type,
+ &chip->kobj, "die%u", die->die_id);
+ if (ret) {
+ kobject_put(&die->kobj);
+ return ret;
+ }
+
+ for (i = 0; i < die->port_num; i++) {
+ port = &die->ports[i];
+ ret = hccs_create_hccs_dir(hdev, die, port);
+ if (ret) {
+ dev_err(hdev->dev, "create hccs%u dir failed.\n",
+ port->port_id);
+ goto err;
+ }
+ port->dir_created = true;
+ }
+
+ return 0;
+err:
+ hccs_remove_die_dir(die);
+
+ return ret;
+}
+
+static int hccs_create_chip_dir(struct hccs_dev *hdev,
+ struct hccs_chip_info *chip)
+{
+ struct hccs_die_info *die;
+ int ret;
+ u16 id;
+
+ ret = kobject_init_and_add(&chip->kobj, &hccs_chip_type,
+ &hdev->dev->kobj, "chip%u", chip->chip_id);
+ if (ret) {
+ kobject_put(&chip->kobj);
+ return ret;
+ }
+
+ for (id = 0; id < chip->die_num; id++) {
+ die = &chip->dies[id];
+ ret = hccs_create_die_dir(hdev, chip, die);
+ if (ret)
+ goto err;
+ die->dir_created = true;
+ }
+
+ return 0;
+err:
+ hccs_remove_chip_dir(chip);
+
+ return ret;
+}
+
+static int hccs_create_topo_dirs(struct hccs_dev *hdev)
+{
+ struct hccs_chip_info *chip;
+ u8 id, k;
+ int ret;
+
+ for (id = 0; id < hdev->chip_num; id++) {
+ chip = &hdev->chips[id];
+ ret = hccs_create_chip_dir(hdev, chip);
+ if (ret) {
+ dev_err(hdev->dev, "init chip%u dir failed!\n", id);
+ goto err;
+ }
+ }
+
+ 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++)
+ hccs_remove_chip_dir(&hdev->chips[k]);
+
+ return ret;
+}
+
+static int hccs_probe(struct platform_device *pdev)
+{
+ struct acpi_device *acpi_dev;
+ struct hccs_dev *hdev;
+ int rc;
+
+ if (acpi_disabled) {
+ dev_err(&pdev->dev, "acpi is disabled.\n");
+ return -ENODEV;
+ }
+ acpi_dev = ACPI_COMPANION(&pdev->dev);
+ if (!acpi_dev)
+ return -ENODEV;
+
+ hdev = devm_kzalloc(&pdev->dev, sizeof(*hdev), GFP_KERNEL);
+ if (!hdev)
+ return -ENOMEM;
+ hdev->acpi_dev = acpi_dev;
+ hdev->dev = &pdev->dev;
+ platform_set_drvdata(pdev, hdev);
+
+ /*
+ * Here would never be failure as the driver and device has been matched.
+ */
+ hdev->verspec_data = acpi_device_get_match_data(hdev->dev);
+
+ mutex_init(&hdev->lock);
+ rc = hccs_get_pcc_chan_id(hdev);
+ if (rc)
+ return rc;
+ rc = hccs_register_pcc_channel(hdev);
+ if (rc)
+ return rc;
+
+ rc = hccs_get_dev_caps(hdev);
+ if (rc)
+ goto unregister_pcc_chan;
+
+ rc = hccs_get_hw_info(hdev);
+ 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;
+
+ return 0;
+
+unregister_pcc_chan:
+ hccs_unregister_pcc_channel(hdev);
+
+ return rc;
+}
+
+static void hccs_remove(struct platform_device *pdev)
+{
+ struct hccs_dev *hdev = platform_get_drvdata(pdev);
+
+ hccs_remove_topo_dirs(hdev);
+ hccs_unregister_pcc_channel(hdev);
+}
+
+static const struct hccs_verspecific_data hisi04b1_verspec_data = {
+ .rx_callback = NULL,
+ .wait_cmd_complete = hccs_wait_cmd_complete_by_poll,
+ .fill_pcc_shared_mem = hccs_fill_pcc_shared_mem_region,
+ .shared_mem_size = sizeof(struct acpi_pcct_shared_memory),
+ .has_txdone_irq = false,
+};
+
+static const struct hccs_verspecific_data hisi04b2_verspec_data = {
+ .rx_callback = hccs_pcc_rx_callback,
+ .wait_cmd_complete = hccs_wait_cmd_complete_by_irq,
+ .fill_pcc_shared_mem = hccs_fill_ext_pcc_shared_mem_region,
+ .shared_mem_size = sizeof(struct acpi_pcct_ext_pcc_shared_memory),
+ .has_txdone_irq = true,
+};
+
+static const struct acpi_device_id hccs_acpi_match[] = {
+ { "HISI04B1", (unsigned long)&hisi04b1_verspec_data},
+ { "HISI04B2", (unsigned long)&hisi04b2_verspec_data},
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, hccs_acpi_match);
+
+static struct platform_driver hccs_driver = {
+ .probe = hccs_probe,
+ .remove = hccs_remove,
+ .driver = {
+ .name = "kunpeng_hccs",
+ .acpi_match_table = hccs_acpi_match,
+ },
+};
+
+module_platform_driver(hccs_driver);
+
+MODULE_DESCRIPTION("Kunpeng SoC HCCS driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Huisong Li <lihuisong@huawei.com>");
diff --git a/drivers/soc/hisilicon/kunpeng_hccs.h b/drivers/soc/hisilicon/kunpeng_hccs.h
new file mode 100644
index 000000000000..f0a9a5618d97
--- /dev/null
+++ b/drivers/soc/hisilicon/kunpeng_hccs.h
@@ -0,0 +1,233 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (c) 2023 Hisilicon Limited. */
+
+#ifndef __KUNPENG_HCCS_H__
+#define __KUNPENG_HCCS_H__
+
+/*
+ * |--------------- Chip0 ---------------|---------------- ChipN -------------|
+ * |--------Die0-------|--------DieN-------|--------Die0-------|-------DieN-------|
+ * | 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.
+ */
+#define HCCS_DIE_MAX_PORT_ID 254
+
+struct hccs_port_info {
+ u8 port_id;
+ u8 port_type;
+ u8 max_lane_num;
+ bool enable; /* if the port is enabled */
+ struct kobject kobj;
+ bool dir_created;
+ struct hccs_die_info *die; /* point to the die the port is located */
+};
+
+struct hccs_die_info {
+ u8 die_id;
+ u8 port_num;
+ u8 min_port_id;
+ u8 max_port_id;
+ struct hccs_port_info *ports;
+ struct kobject kobj;
+ bool dir_created;
+ struct hccs_chip_info *chip; /* point to the chip the die is located */
+};
+
+struct hccs_chip_info {
+ u8 chip_id;
+ u8 die_num;
+ struct hccs_die_info *dies;
+ struct kobject kobj;
+ struct hccs_dev *hdev;
+};
+
+struct hccs_mbox_client_info {
+ struct mbox_client client;
+ struct pcc_mbox_chan *pcc_chan;
+ u64 deadline_us;
+ struct completion done;
+};
+
+struct hccs_desc;
+
+struct hccs_verspecific_data {
+ void (*rx_callback)(struct mbox_client *cl, void *mssg);
+ int (*wait_cmd_complete)(struct hccs_dev *hdev);
+ void (*fill_pcc_shared_mem)(struct hccs_dev *hdev,
+ u8 cmd, struct hccs_desc *desc,
+ void __iomem *comm_space,
+ u16 space_size);
+ u16 shared_mem_size;
+ 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;
+};
+
+#define HCCS_SERDES_MODULE_CODE 0x32
+enum hccs_subcmd_type {
+ HCCS_GET_CHIP_NUM = 0x1,
+ HCCS_GET_DIE_NUM,
+ HCCS_GET_DIE_INFO,
+ HCCS_GET_DIE_PORT_INFO,
+ HCCS_GET_DEV_CAP,
+ HCCS_GET_PORT_LINK_STATUS,
+ HCCS_GET_PORT_CRC_ERR_CNT,
+ 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,
+};
+
+struct hccs_die_num_req_param {
+ u8 chip_id;
+};
+
+struct hccs_die_info_req_param {
+ u8 chip_id;
+ u8 die_idx;
+};
+
+struct hccs_die_info_rsp_data {
+ u8 die_id;
+ u8 port_num;
+ u8 min_port_id;
+ u8 max_port_id;
+};
+
+struct hccs_port_attr {
+ u8 port_id;
+ u8 port_type;
+ u8 max_lane_num;
+ u8 enable : 1; /* if the port is enabled */
+ u16 rsv[2];
+};
+
+/*
+ * The common command request for getting the information of all HCCS port on
+ * specified DIE.
+ */
+struct hccs_die_comm_req_param {
+ u8 chip_id;
+ u8 die_id; /* id in hardware */
+};
+
+/* The common command request for getting the information of a specific port */
+struct hccs_port_comm_req_param {
+ u8 chip_id;
+ u8 die_id;
+ 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
+#define HCCS_PORT_READY 4
+struct hccs_link_status {
+ u8 lane_mask; /* indicate which lanes are used. */
+ u8 link_fsm : 3; /* link fsm, 1: reset 2: setup 3: config 4: link-up */
+ u8 lane_num : 5; /* current lane number */
+};
+
+struct hccs_req_head {
+ u8 module_code; /* set to 0x32 for serdes */
+ u8 start_id;
+ u8 rsv[2];
+};
+
+struct hccs_rsp_head {
+ u8 data_len;
+ u8 next_id;
+ u8 rsv[2];
+};
+
+struct hccs_fw_inner_head {
+ u8 retStatus; /* 0: success, other: failure */
+ u8 rsv[7];
+};
+
+#define HCCS_PCC_SHARE_MEM_BYTES 64
+#define HCCS_FW_INNER_HEAD_BYTES 8
+#define HCCS_RSP_HEAD_BYTES 4
+
+#define HCCS_MAX_RSP_DATA_BYTES (HCCS_PCC_SHARE_MEM_BYTES - \
+ HCCS_FW_INNER_HEAD_BYTES - \
+ HCCS_RSP_HEAD_BYTES)
+#define HCCS_MAX_RSP_DATA_SIZE_MAX (HCCS_MAX_RSP_DATA_BYTES / 4)
+
+/*
+ * Note: Actual available size of data field also depands on the PCC header
+ * bytes of the specific type. Driver needs to copy the response data in the
+ * communication space based on the real length.
+ */
+struct hccs_rsp_desc {
+ struct hccs_fw_inner_head fw_inner_head; /* 8 Bytes */
+ struct hccs_rsp_head rsp_head; /* 4 Bytes */
+ u32 data[HCCS_MAX_RSP_DATA_SIZE_MAX];
+};
+
+#define HCCS_REQ_HEAD_BYTES 4
+#define HCCS_MAX_REQ_DATA_BYTES (HCCS_PCC_SHARE_MEM_BYTES - \
+ HCCS_REQ_HEAD_BYTES)
+#define HCCS_MAX_REQ_DATA_SIZE_MAX (HCCS_MAX_REQ_DATA_BYTES / 4)
+
+/*
+ * Note: Actual available size of data field also depands on the PCC header
+ * bytes of the specific type. Driver needs to copy the request data to the
+ * communication space based on the real length.
+ */
+struct hccs_req_desc {
+ struct hccs_req_head req_head; /* 4 Bytes */
+ u32 data[HCCS_MAX_REQ_DATA_SIZE_MAX];
+};
+
+struct hccs_desc {
+ union {
+ struct hccs_req_desc req;
+ struct hccs_rsp_desc rsp;
+ };
+};
+
+#endif /* __KUNPENG_HCCS_H__ */
diff --git a/drivers/soc/imx/Kconfig b/drivers/soc/imx/Kconfig
index 4b906791d6c7..2a90ddd20104 100644
--- a/drivers/soc/imx/Kconfig
+++ b/drivers/soc/imx/Kconfig
@@ -1,16 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only
menu "i.MX SoC drivers"
-config IMX_GPCV2_PM_DOMAINS
- bool "i.MX GPCv2 PM domains"
- depends on ARCH_MXC || (COMPILE_TEST && OF)
- depends on PM
- select PM_GENERIC_DOMAINS
- select REGMAP_MMIO
- default y if SOC_IMX7D
-
config SOC_IMX8M
- bool "i.MX8M SoC family support"
+ tristate "i.MX8M SoC family support"
depends on ARCH_MXC || COMPILE_TEST
default ARCH_MXC && ARM64
select SOC_BUS
diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile
index 7b4099ceafd6..ca6a5fa1618f 100644
--- a/drivers/soc/imx/Makefile
+++ b/drivers/soc/imx/Makefile
@@ -2,10 +2,5 @@
ifeq ($(CONFIG_ARM),y)
obj-$(CONFIG_ARCH_MXC) += soc-imx.o
endif
-obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
-obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o
obj-$(CONFIG_SOC_IMX8M) += soc-imx8m.o
-obj-$(CONFIG_SOC_IMX8M) += imx8m-blk-ctrl.o
-obj-$(CONFIG_SOC_IMX8M) += imx8mp-blk-ctrl.o
-obj-$(CONFIG_SOC_IMX9) += imx93-src.o imx93-pd.o
-obj-$(CONFIG_SOC_IMX9) += imx93-blk-ctrl.o
+obj-$(CONFIG_SOC_IMX9) += imx93-src.o soc-imx9.o
diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c
deleted file mode 100644
index 90a8b2c0676f..000000000000
--- a/drivers/soc/imx/gpc.c
+++ /dev/null
@@ -1,554 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright 2015-2017 Pengutronix, Lucas Stach <kernel@pengutronix.de>
- * Copyright 2011-2013 Freescale Semiconductor, Inc.
- */
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <linux/regmap.h>
-#include <linux/regulator/consumer.h>
-
-#define GPC_CNTR 0x000
-
-#define GPC_PGC_CTRL_OFFS 0x0
-#define GPC_PGC_PUPSCR_OFFS 0x4
-#define GPC_PGC_PDNSCR_OFFS 0x8
-#define GPC_PGC_SW2ISO_SHIFT 0x8
-#define GPC_PGC_SW_SHIFT 0x0
-
-#define GPC_PGC_PCI_PDN 0x200
-#define GPC_PGC_PCI_SR 0x20c
-
-#define GPC_PGC_GPU_PDN 0x260
-#define GPC_PGC_GPU_PUPSCR 0x264
-#define GPC_PGC_GPU_PDNSCR 0x268
-#define GPC_PGC_GPU_SR 0x26c
-
-#define GPC_PGC_DISP_PDN 0x240
-#define GPC_PGC_DISP_SR 0x24c
-
-#define GPU_VPU_PUP_REQ BIT(1)
-#define GPU_VPU_PDN_REQ BIT(0)
-
-#define GPC_CLK_MAX 7
-
-#define PGC_DOMAIN_FLAG_NO_PD BIT(0)
-
-struct imx_pm_domain {
- struct generic_pm_domain base;
- struct regmap *regmap;
- struct regulator *supply;
- struct clk *clk[GPC_CLK_MAX];
- int num_clks;
- unsigned int reg_offs;
- signed char cntr_pdn_bit;
- unsigned int ipg_rate_mhz;
-};
-
-static inline struct imx_pm_domain *
-to_imx_pm_domain(struct generic_pm_domain *genpd)
-{
- return container_of(genpd, struct imx_pm_domain, base);
-}
-
-static int imx6_pm_domain_power_off(struct generic_pm_domain *genpd)
-{
- struct imx_pm_domain *pd = to_imx_pm_domain(genpd);
- int iso, iso2sw;
- u32 val;
-
- /* Read ISO and ISO2SW power down delays */
- regmap_read(pd->regmap, pd->reg_offs + GPC_PGC_PDNSCR_OFFS, &val);
- iso = val & 0x3f;
- iso2sw = (val >> 8) & 0x3f;
-
- /* Gate off domain when powered down */
- regmap_update_bits(pd->regmap, pd->reg_offs + GPC_PGC_CTRL_OFFS,
- 0x1, 0x1);
-
- /* Request GPC to power down domain */
- val = BIT(pd->cntr_pdn_bit);
- regmap_update_bits(pd->regmap, GPC_CNTR, val, val);
-
- /* Wait ISO + ISO2SW IPG clock cycles */
- udelay(DIV_ROUND_UP(iso + iso2sw, pd->ipg_rate_mhz));
-
- if (pd->supply)
- regulator_disable(pd->supply);
-
- return 0;
-}
-
-static int imx6_pm_domain_power_on(struct generic_pm_domain *genpd)
-{
- struct imx_pm_domain *pd = to_imx_pm_domain(genpd);
- int i, ret;
- u32 val, req;
-
- if (pd->supply) {
- ret = regulator_enable(pd->supply);
- if (ret) {
- pr_err("%s: failed to enable regulator: %d\n",
- __func__, ret);
- return ret;
- }
- }
-
- /* Enable reset clocks for all devices in the domain */
- for (i = 0; i < pd->num_clks; i++)
- clk_prepare_enable(pd->clk[i]);
-
- /* Gate off domain when powered down */
- regmap_update_bits(pd->regmap, pd->reg_offs + GPC_PGC_CTRL_OFFS,
- 0x1, 0x1);
-
- /* Request GPC to power up domain */
- req = BIT(pd->cntr_pdn_bit + 1);
- regmap_update_bits(pd->regmap, GPC_CNTR, req, req);
-
- /* Wait for the PGC to handle the request */
- ret = regmap_read_poll_timeout(pd->regmap, GPC_CNTR, val, !(val & req),
- 1, 50);
- if (ret)
- pr_err("powerup request on domain %s timed out\n", genpd->name);
-
- /* Wait for reset to propagate through peripherals */
- usleep_range(5, 10);
-
- /* Disable reset clocks for all devices in the domain */
- for (i = 0; i < pd->num_clks; i++)
- clk_disable_unprepare(pd->clk[i]);
-
- return 0;
-}
-
-static int imx_pgc_get_clocks(struct device *dev, struct imx_pm_domain *domain)
-{
- int i, ret;
-
- for (i = 0; ; i++) {
- struct clk *clk = of_clk_get(dev->of_node, i);
- if (IS_ERR(clk))
- break;
- if (i >= GPC_CLK_MAX) {
- dev_err(dev, "more than %d clocks\n", GPC_CLK_MAX);
- ret = -EINVAL;
- goto clk_err;
- }
- domain->clk[i] = clk;
- }
- domain->num_clks = i;
-
- return 0;
-
-clk_err:
- while (i--)
- clk_put(domain->clk[i]);
-
- return ret;
-}
-
-static void imx_pgc_put_clocks(struct imx_pm_domain *domain)
-{
- int i;
-
- for (i = domain->num_clks - 1; i >= 0; i--)
- clk_put(domain->clk[i]);
-}
-
-static int imx_pgc_parse_dt(struct device *dev, struct imx_pm_domain *domain)
-{
- /* try to get the domain supply regulator */
- domain->supply = devm_regulator_get_optional(dev, "power");
- if (IS_ERR(domain->supply)) {
- if (PTR_ERR(domain->supply) == -ENODEV)
- domain->supply = NULL;
- else
- return PTR_ERR(domain->supply);
- }
-
- /* try to get all clocks needed for reset propagation */
- return imx_pgc_get_clocks(dev, domain);
-}
-
-static int imx_pgc_power_domain_probe(struct platform_device *pdev)
-{
- struct imx_pm_domain *domain = pdev->dev.platform_data;
- struct device *dev = &pdev->dev;
- int ret;
-
- /* if this PD is associated with a DT node try to parse it */
- if (dev->of_node) {
- ret = imx_pgc_parse_dt(dev, domain);
- if (ret)
- return ret;
- }
-
- /* initially power on the domain */
- if (domain->base.power_on)
- domain->base.power_on(&domain->base);
-
- if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) {
- pm_genpd_init(&domain->base, NULL, false);
- ret = of_genpd_add_provider_simple(dev->of_node, &domain->base);
- if (ret)
- goto genpd_err;
- }
-
- device_link_add(dev, dev->parent, DL_FLAG_AUTOREMOVE_CONSUMER);
-
- return 0;
-
-genpd_err:
- pm_genpd_remove(&domain->base);
- imx_pgc_put_clocks(domain);
-
- return ret;
-}
-
-static int imx_pgc_power_domain_remove(struct platform_device *pdev)
-{
- struct imx_pm_domain *domain = pdev->dev.platform_data;
-
- if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) {
- of_genpd_del_provider(pdev->dev.of_node);
- pm_genpd_remove(&domain->base);
- imx_pgc_put_clocks(domain);
- }
-
- return 0;
-}
-
-static const struct platform_device_id imx_pgc_power_domain_id[] = {
- { "imx-pgc-power-domain"},
- { },
-};
-
-static struct platform_driver imx_pgc_power_domain_driver = {
- .driver = {
- .name = "imx-pgc-pd",
- },
- .probe = imx_pgc_power_domain_probe,
- .remove = imx_pgc_power_domain_remove,
- .id_table = imx_pgc_power_domain_id,
-};
-builtin_platform_driver(imx_pgc_power_domain_driver)
-
-#define GPC_PGC_DOMAIN_ARM 0
-#define GPC_PGC_DOMAIN_PU 1
-#define GPC_PGC_DOMAIN_DISPLAY 2
-#define GPC_PGC_DOMAIN_PCI 3
-
-static struct genpd_power_state imx6_pm_domain_pu_state = {
- .power_off_latency_ns = 25000,
- .power_on_latency_ns = 2000000,
-};
-
-static struct imx_pm_domain imx_gpc_domains[] = {
- [GPC_PGC_DOMAIN_ARM] = {
- .base = {
- .name = "ARM",
- .flags = GENPD_FLAG_ALWAYS_ON,
- },
- },
- [GPC_PGC_DOMAIN_PU] = {
- .base = {
- .name = "PU",
- .power_off = imx6_pm_domain_power_off,
- .power_on = imx6_pm_domain_power_on,
- .states = &imx6_pm_domain_pu_state,
- .state_count = 1,
- },
- .reg_offs = 0x260,
- .cntr_pdn_bit = 0,
- },
- [GPC_PGC_DOMAIN_DISPLAY] = {
- .base = {
- .name = "DISPLAY",
- .power_off = imx6_pm_domain_power_off,
- .power_on = imx6_pm_domain_power_on,
- },
- .reg_offs = 0x240,
- .cntr_pdn_bit = 4,
- },
- [GPC_PGC_DOMAIN_PCI] = {
- .base = {
- .name = "PCI",
- .power_off = imx6_pm_domain_power_off,
- .power_on = imx6_pm_domain_power_on,
- },
- .reg_offs = 0x200,
- .cntr_pdn_bit = 6,
- },
-};
-
-struct imx_gpc_dt_data {
- int num_domains;
- bool err009619_present;
- bool err006287_present;
-};
-
-static const struct imx_gpc_dt_data imx6q_dt_data = {
- .num_domains = 2,
- .err009619_present = false,
- .err006287_present = false,
-};
-
-static const struct imx_gpc_dt_data imx6qp_dt_data = {
- .num_domains = 2,
- .err009619_present = true,
- .err006287_present = false,
-};
-
-static const struct imx_gpc_dt_data imx6sl_dt_data = {
- .num_domains = 3,
- .err009619_present = false,
- .err006287_present = true,
-};
-
-static const struct imx_gpc_dt_data imx6sx_dt_data = {
- .num_domains = 4,
- .err009619_present = false,
- .err006287_present = false,
-};
-
-static const struct of_device_id imx_gpc_dt_ids[] = {
- { .compatible = "fsl,imx6q-gpc", .data = &imx6q_dt_data },
- { .compatible = "fsl,imx6qp-gpc", .data = &imx6qp_dt_data },
- { .compatible = "fsl,imx6sl-gpc", .data = &imx6sl_dt_data },
- { .compatible = "fsl,imx6sx-gpc", .data = &imx6sx_dt_data },
- { }
-};
-
-static const struct regmap_range yes_ranges[] = {
- regmap_reg_range(GPC_CNTR, GPC_CNTR),
- regmap_reg_range(GPC_PGC_PCI_PDN, GPC_PGC_PCI_SR),
- regmap_reg_range(GPC_PGC_GPU_PDN, GPC_PGC_GPU_SR),
- regmap_reg_range(GPC_PGC_DISP_PDN, GPC_PGC_DISP_SR),
-};
-
-static const struct regmap_access_table access_table = {
- .yes_ranges = yes_ranges,
- .n_yes_ranges = ARRAY_SIZE(yes_ranges),
-};
-
-static const struct regmap_config imx_gpc_regmap_config = {
- .reg_bits = 32,
- .val_bits = 32,
- .reg_stride = 4,
- .rd_table = &access_table,
- .wr_table = &access_table,
- .max_register = 0x2ac,
- .fast_io = true,
-};
-
-static struct generic_pm_domain *imx_gpc_onecell_domains[] = {
- &imx_gpc_domains[GPC_PGC_DOMAIN_ARM].base,
- &imx_gpc_domains[GPC_PGC_DOMAIN_PU].base,
-};
-
-static struct genpd_onecell_data imx_gpc_onecell_data = {
- .domains = imx_gpc_onecell_domains,
- .num_domains = 2,
-};
-
-static int imx_gpc_old_dt_init(struct device *dev, struct regmap *regmap,
- unsigned int num_domains)
-{
- struct imx_pm_domain *domain;
- int i, ret;
-
- for (i = 0; i < num_domains; i++) {
- domain = &imx_gpc_domains[i];
- domain->regmap = regmap;
- domain->ipg_rate_mhz = 66;
-
- if (i == 1) {
- domain->supply = devm_regulator_get(dev, "pu");
- if (IS_ERR(domain->supply))
- return PTR_ERR(domain->supply);
-
- ret = imx_pgc_get_clocks(dev, domain);
- if (ret)
- goto clk_err;
-
- domain->base.power_on(&domain->base);
- }
- }
-
- for (i = 0; i < num_domains; i++)
- pm_genpd_init(&imx_gpc_domains[i].base, NULL, false);
-
- if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) {
- ret = of_genpd_add_provider_onecell(dev->of_node,
- &imx_gpc_onecell_data);
- if (ret)
- goto genpd_err;
- }
-
- return 0;
-
-genpd_err:
- for (i = 0; i < num_domains; i++)
- pm_genpd_remove(&imx_gpc_domains[i].base);
- imx_pgc_put_clocks(&imx_gpc_domains[GPC_PGC_DOMAIN_PU]);
-clk_err:
- return ret;
-}
-
-static int imx_gpc_probe(struct platform_device *pdev)
-{
- const struct of_device_id *of_id =
- of_match_device(imx_gpc_dt_ids, &pdev->dev);
- const struct imx_gpc_dt_data *of_id_data = of_id->data;
- struct device_node *pgc_node;
- struct regmap *regmap;
- void __iomem *base;
- int ret;
-
- pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc");
-
- /* bail out if DT too old and doesn't provide the necessary info */
- if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells") &&
- !pgc_node)
- return 0;
-
- base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base,
- &imx_gpc_regmap_config);
- if (IS_ERR(regmap)) {
- ret = PTR_ERR(regmap);
- dev_err(&pdev->dev, "failed to init regmap: %d\n",
- ret);
- return ret;
- }
-
- /*
- * Disable PU power down by runtime PM if ERR009619 is present.
- *
- * The PRE clock will be paused for several cycles when turning on the
- * PU domain LDO from power down state. If PRE is in use at that time,
- * the IPU/PRG cannot get the correct display data from the PRE.
- *
- * This is not a concern when the whole system enters suspend state, so
- * it's safe to power down PU in this case.
- */
- if (of_id_data->err009619_present)
- imx_gpc_domains[GPC_PGC_DOMAIN_PU].base.flags |=
- GENPD_FLAG_RPM_ALWAYS_ON;
-
- /* Keep DISP always on if ERR006287 is present */
- if (of_id_data->err006287_present)
- imx_gpc_domains[GPC_PGC_DOMAIN_DISPLAY].base.flags |=
- GENPD_FLAG_ALWAYS_ON;
-
- if (!pgc_node) {
- ret = imx_gpc_old_dt_init(&pdev->dev, regmap,
- of_id_data->num_domains);
- if (ret)
- return ret;
- } else {
- struct imx_pm_domain *domain;
- struct platform_device *pd_pdev;
- struct device_node *np;
- struct clk *ipg_clk;
- unsigned int ipg_rate_mhz;
- int domain_index;
-
- ipg_clk = devm_clk_get(&pdev->dev, "ipg");
- if (IS_ERR(ipg_clk))
- return PTR_ERR(ipg_clk);
- ipg_rate_mhz = clk_get_rate(ipg_clk) / 1000000;
-
- for_each_child_of_node(pgc_node, np) {
- ret = of_property_read_u32(np, "reg", &domain_index);
- if (ret) {
- of_node_put(np);
- return ret;
- }
- if (domain_index >= of_id_data->num_domains)
- continue;
-
- pd_pdev = platform_device_alloc("imx-pgc-power-domain",
- domain_index);
- if (!pd_pdev) {
- of_node_put(np);
- return -ENOMEM;
- }
-
- ret = platform_device_add_data(pd_pdev,
- &imx_gpc_domains[domain_index],
- sizeof(imx_gpc_domains[domain_index]));
- if (ret) {
- platform_device_put(pd_pdev);
- of_node_put(np);
- return ret;
- }
- domain = pd_pdev->dev.platform_data;
- domain->regmap = regmap;
- domain->ipg_rate_mhz = ipg_rate_mhz;
-
- pd_pdev->dev.parent = &pdev->dev;
- pd_pdev->dev.of_node = np;
-
- ret = platform_device_add(pd_pdev);
- if (ret) {
- platform_device_put(pd_pdev);
- of_node_put(np);
- return ret;
- }
- }
- }
-
- return 0;
-}
-
-static int imx_gpc_remove(struct platform_device *pdev)
-{
- struct device_node *pgc_node;
- int ret;
-
- pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc");
-
- /* bail out if DT too old and doesn't provide the necessary info */
- if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells") &&
- !pgc_node)
- return 0;
-
- /*
- * If the old DT binding is used the toplevel driver needs to
- * de-register the power domains
- */
- if (!pgc_node) {
- of_genpd_del_provider(pdev->dev.of_node);
-
- ret = pm_genpd_remove(&imx_gpc_domains[GPC_PGC_DOMAIN_PU].base);
- if (ret)
- return ret;
- imx_pgc_put_clocks(&imx_gpc_domains[GPC_PGC_DOMAIN_PU]);
-
- ret = pm_genpd_remove(&imx_gpc_domains[GPC_PGC_DOMAIN_ARM].base);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static struct platform_driver imx_gpc_driver = {
- .driver = {
- .name = "imx-gpc",
- .of_match_table = imx_gpc_dt_ids,
- },
- .probe = imx_gpc_probe,
- .remove = imx_gpc_remove,
-};
-builtin_platform_driver(imx_gpc_driver)
diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
deleted file mode 100644
index 7a47d14fde44..000000000000
--- a/drivers/soc/imx/gpcv2.c
+++ /dev/null
@@ -1,1550 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright 2017 Impinj, Inc
- * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
- *
- * Based on the code of analogus driver:
- *
- * Copyright 2015-2017 Pengutronix, Lucas Stach <kernel@pengutronix.de>
- */
-
-#include <linux/clk.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <linux/pm_runtime.h>
-#include <linux/regmap.h>
-#include <linux/regulator/consumer.h>
-#include <linux/reset.h>
-#include <linux/sizes.h>
-#include <dt-bindings/power/imx7-power.h>
-#include <dt-bindings/power/imx8mq-power.h>
-#include <dt-bindings/power/imx8mm-power.h>
-#include <dt-bindings/power/imx8mn-power.h>
-#include <dt-bindings/power/imx8mp-power.h>
-
-#define GPC_LPCR_A_CORE_BSC 0x000
-
-#define GPC_PGC_CPU_MAPPING 0x0ec
-#define IMX8MP_GPC_PGC_CPU_MAPPING 0x1cc
-
-#define IMX7_USB_HSIC_PHY_A_CORE_DOMAIN BIT(6)
-#define IMX7_USB_OTG2_PHY_A_CORE_DOMAIN BIT(5)
-#define IMX7_USB_OTG1_PHY_A_CORE_DOMAIN BIT(4)
-#define IMX7_PCIE_PHY_A_CORE_DOMAIN BIT(3)
-#define IMX7_MIPI_PHY_A_CORE_DOMAIN BIT(2)
-
-#define IMX8M_PCIE2_A53_DOMAIN BIT(15)
-#define IMX8M_MIPI_CSI2_A53_DOMAIN BIT(14)
-#define IMX8M_MIPI_CSI1_A53_DOMAIN BIT(13)
-#define IMX8M_DISP_A53_DOMAIN BIT(12)
-#define IMX8M_HDMI_A53_DOMAIN BIT(11)
-#define IMX8M_VPU_A53_DOMAIN BIT(10)
-#define IMX8M_GPU_A53_DOMAIN BIT(9)
-#define IMX8M_DDR2_A53_DOMAIN BIT(8)
-#define IMX8M_DDR1_A53_DOMAIN BIT(7)
-#define IMX8M_OTG2_A53_DOMAIN BIT(5)
-#define IMX8M_OTG1_A53_DOMAIN BIT(4)
-#define IMX8M_PCIE1_A53_DOMAIN BIT(3)
-#define IMX8M_MIPI_A53_DOMAIN BIT(2)
-
-#define IMX8MM_VPUH1_A53_DOMAIN BIT(15)
-#define IMX8MM_VPUG2_A53_DOMAIN BIT(14)
-#define IMX8MM_VPUG1_A53_DOMAIN BIT(13)
-#define IMX8MM_DISPMIX_A53_DOMAIN BIT(12)
-#define IMX8MM_VPUMIX_A53_DOMAIN BIT(10)
-#define IMX8MM_GPUMIX_A53_DOMAIN BIT(9)
-#define IMX8MM_GPU_A53_DOMAIN (BIT(8) | BIT(11))
-#define IMX8MM_DDR1_A53_DOMAIN BIT(7)
-#define IMX8MM_OTG2_A53_DOMAIN BIT(5)
-#define IMX8MM_OTG1_A53_DOMAIN BIT(4)
-#define IMX8MM_PCIE_A53_DOMAIN BIT(3)
-#define IMX8MM_MIPI_A53_DOMAIN BIT(2)
-
-#define IMX8MN_DISPMIX_A53_DOMAIN BIT(12)
-#define IMX8MN_GPUMIX_A53_DOMAIN BIT(9)
-#define IMX8MN_DDR1_A53_DOMAIN BIT(7)
-#define IMX8MN_OTG1_A53_DOMAIN BIT(4)
-#define IMX8MN_MIPI_A53_DOMAIN BIT(2)
-
-#define IMX8MP_MEDIA_ISPDWP_A53_DOMAIN BIT(20)
-#define IMX8MP_HSIOMIX_A53_DOMAIN BIT(19)
-#define IMX8MP_MIPI_PHY2_A53_DOMAIN BIT(18)
-#define IMX8MP_HDMI_PHY_A53_DOMAIN BIT(17)
-#define IMX8MP_HDMIMIX_A53_DOMAIN BIT(16)
-#define IMX8MP_VPU_VC8000E_A53_DOMAIN BIT(15)
-#define IMX8MP_VPU_G2_A53_DOMAIN BIT(14)
-#define IMX8MP_VPU_G1_A53_DOMAIN BIT(13)
-#define IMX8MP_MEDIAMIX_A53_DOMAIN BIT(12)
-#define IMX8MP_GPU3D_A53_DOMAIN BIT(11)
-#define IMX8MP_VPUMIX_A53_DOMAIN BIT(10)
-#define IMX8MP_GPUMIX_A53_DOMAIN BIT(9)
-#define IMX8MP_GPU2D_A53_DOMAIN BIT(8)
-#define IMX8MP_AUDIOMIX_A53_DOMAIN BIT(7)
-#define IMX8MP_MLMIX_A53_DOMAIN BIT(6)
-#define IMX8MP_USB2_PHY_A53_DOMAIN BIT(5)
-#define IMX8MP_USB1_PHY_A53_DOMAIN BIT(4)
-#define IMX8MP_PCIE_PHY_A53_DOMAIN BIT(3)
-#define IMX8MP_MIPI_PHY1_A53_DOMAIN BIT(2)
-
-#define IMX8MP_GPC_PU_PGC_SW_PUP_REQ 0x0d8
-#define IMX8MP_GPC_PU_PGC_SW_PDN_REQ 0x0e4
-
-#define GPC_PU_PGC_SW_PUP_REQ 0x0f8
-#define GPC_PU_PGC_SW_PDN_REQ 0x104
-
-#define IMX7_USB_HSIC_PHY_SW_Pxx_REQ BIT(4)
-#define IMX7_USB_OTG2_PHY_SW_Pxx_REQ BIT(3)
-#define IMX7_USB_OTG1_PHY_SW_Pxx_REQ BIT(2)
-#define IMX7_PCIE_PHY_SW_Pxx_REQ BIT(1)
-#define IMX7_MIPI_PHY_SW_Pxx_REQ BIT(0)
-
-#define IMX8M_PCIE2_SW_Pxx_REQ BIT(13)
-#define IMX8M_MIPI_CSI2_SW_Pxx_REQ BIT(12)
-#define IMX8M_MIPI_CSI1_SW_Pxx_REQ BIT(11)
-#define IMX8M_DISP_SW_Pxx_REQ BIT(10)
-#define IMX8M_HDMI_SW_Pxx_REQ BIT(9)
-#define IMX8M_VPU_SW_Pxx_REQ BIT(8)
-#define IMX8M_GPU_SW_Pxx_REQ BIT(7)
-#define IMX8M_DDR2_SW_Pxx_REQ BIT(6)
-#define IMX8M_DDR1_SW_Pxx_REQ BIT(5)
-#define IMX8M_OTG2_SW_Pxx_REQ BIT(3)
-#define IMX8M_OTG1_SW_Pxx_REQ BIT(2)
-#define IMX8M_PCIE1_SW_Pxx_REQ BIT(1)
-#define IMX8M_MIPI_SW_Pxx_REQ BIT(0)
-
-#define IMX8MM_VPUH1_SW_Pxx_REQ BIT(13)
-#define IMX8MM_VPUG2_SW_Pxx_REQ BIT(12)
-#define IMX8MM_VPUG1_SW_Pxx_REQ BIT(11)
-#define IMX8MM_DISPMIX_SW_Pxx_REQ BIT(10)
-#define IMX8MM_VPUMIX_SW_Pxx_REQ BIT(8)
-#define IMX8MM_GPUMIX_SW_Pxx_REQ BIT(7)
-#define IMX8MM_GPU_SW_Pxx_REQ (BIT(6) | BIT(9))
-#define IMX8MM_DDR1_SW_Pxx_REQ BIT(5)
-#define IMX8MM_OTG2_SW_Pxx_REQ BIT(3)
-#define IMX8MM_OTG1_SW_Pxx_REQ BIT(2)
-#define IMX8MM_PCIE_SW_Pxx_REQ BIT(1)
-#define IMX8MM_MIPI_SW_Pxx_REQ BIT(0)
-
-#define IMX8MN_DISPMIX_SW_Pxx_REQ BIT(10)
-#define IMX8MN_GPUMIX_SW_Pxx_REQ BIT(7)
-#define IMX8MN_DDR1_SW_Pxx_REQ BIT(5)
-#define IMX8MN_OTG1_SW_Pxx_REQ BIT(2)
-#define IMX8MN_MIPI_SW_Pxx_REQ BIT(0)
-
-#define IMX8MP_DDRMIX_Pxx_REQ BIT(19)
-#define IMX8MP_MEDIA_ISP_DWP_Pxx_REQ BIT(18)
-#define IMX8MP_HSIOMIX_Pxx_REQ BIT(17)
-#define IMX8MP_MIPI_PHY2_Pxx_REQ BIT(16)
-#define IMX8MP_HDMI_PHY_Pxx_REQ BIT(15)
-#define IMX8MP_HDMIMIX_Pxx_REQ BIT(14)
-#define IMX8MP_VPU_VC8K_Pxx_REQ BIT(13)
-#define IMX8MP_VPU_G2_Pxx_REQ BIT(12)
-#define IMX8MP_VPU_G1_Pxx_REQ BIT(11)
-#define IMX8MP_MEDIMIX_Pxx_REQ BIT(10)
-#define IMX8MP_GPU_3D_Pxx_REQ BIT(9)
-#define IMX8MP_VPU_MIX_SHARE_LOGIC_Pxx_REQ BIT(8)
-#define IMX8MP_GPU_SHARE_LOGIC_Pxx_REQ BIT(7)
-#define IMX8MP_GPU_2D_Pxx_REQ BIT(6)
-#define IMX8MP_AUDIOMIX_Pxx_REQ BIT(5)
-#define IMX8MP_MLMIX_Pxx_REQ BIT(4)
-#define IMX8MP_USB2_PHY_Pxx_REQ BIT(3)
-#define IMX8MP_USB1_PHY_Pxx_REQ BIT(2)
-#define IMX8MP_PCIE_PHY_SW_Pxx_REQ BIT(1)
-#define IMX8MP_MIPI_PHY1_SW_Pxx_REQ BIT(0)
-
-#define GPC_M4_PU_PDN_FLG 0x1bc
-
-#define IMX8MP_GPC_PU_PWRHSK 0x190
-#define GPC_PU_PWRHSK 0x1fc
-
-#define IMX8M_GPU_HSK_PWRDNACKN BIT(26)
-#define IMX8M_VPU_HSK_PWRDNACKN BIT(25)
-#define IMX8M_DISP_HSK_PWRDNACKN BIT(24)
-#define IMX8M_GPU_HSK_PWRDNREQN BIT(6)
-#define IMX8M_VPU_HSK_PWRDNREQN BIT(5)
-#define IMX8M_DISP_HSK_PWRDNREQN BIT(4)
-
-#define IMX8MM_GPUMIX_HSK_PWRDNACKN BIT(29)
-#define IMX8MM_GPU_HSK_PWRDNACKN (BIT(27) | BIT(28))
-#define IMX8MM_VPUMIX_HSK_PWRDNACKN BIT(26)
-#define IMX8MM_DISPMIX_HSK_PWRDNACKN BIT(25)
-#define IMX8MM_HSIO_HSK_PWRDNACKN (BIT(23) | BIT(24))
-#define IMX8MM_GPUMIX_HSK_PWRDNREQN BIT(11)
-#define IMX8MM_GPU_HSK_PWRDNREQN (BIT(9) | BIT(10))
-#define IMX8MM_VPUMIX_HSK_PWRDNREQN BIT(8)
-#define IMX8MM_DISPMIX_HSK_PWRDNREQN BIT(7)
-#define IMX8MM_HSIO_HSK_PWRDNREQN (BIT(5) | BIT(6))
-
-#define IMX8MN_GPUMIX_HSK_PWRDNACKN (BIT(29) | BIT(27))
-#define IMX8MN_DISPMIX_HSK_PWRDNACKN BIT(25)
-#define IMX8MN_HSIO_HSK_PWRDNACKN BIT(23)
-#define IMX8MN_GPUMIX_HSK_PWRDNREQN (BIT(11) | BIT(9))
-#define IMX8MN_DISPMIX_HSK_PWRDNREQN BIT(7)
-#define IMX8MN_HSIO_HSK_PWRDNREQN BIT(5)
-
-#define IMX8MP_MEDIAMIX_PWRDNACKN BIT(30)
-#define IMX8MP_HDMIMIX_PWRDNACKN BIT(29)
-#define IMX8MP_HSIOMIX_PWRDNACKN BIT(28)
-#define IMX8MP_VPUMIX_PWRDNACKN BIT(26)
-#define IMX8MP_GPUMIX_PWRDNACKN BIT(25)
-#define IMX8MP_MLMIX_PWRDNACKN (BIT(23) | BIT(24))
-#define IMX8MP_AUDIOMIX_PWRDNACKN (BIT(20) | BIT(31))
-#define IMX8MP_MEDIAMIX_PWRDNREQN BIT(14)
-#define IMX8MP_HDMIMIX_PWRDNREQN BIT(13)
-#define IMX8MP_HSIOMIX_PWRDNREQN BIT(12)
-#define IMX8MP_VPUMIX_PWRDNREQN BIT(10)
-#define IMX8MP_GPUMIX_PWRDNREQN BIT(9)
-#define IMX8MP_MLMIX_PWRDNREQN (BIT(7) | BIT(8))
-#define IMX8MP_AUDIOMIX_PWRDNREQN (BIT(4) | BIT(15))
-
-/*
- * The PGC offset values in Reference Manual
- * (Rev. 1, 01/2018 and the older ones) GPC chapter's
- * GPC_PGC memory map are incorrect, below offset
- * values are from design RTL.
- */
-#define IMX7_PGC_MIPI 16
-#define IMX7_PGC_PCIE 17
-#define IMX7_PGC_USB_HSIC 20
-
-#define IMX8M_PGC_MIPI 16
-#define IMX8M_PGC_PCIE1 17
-#define IMX8M_PGC_OTG1 18
-#define IMX8M_PGC_OTG2 19
-#define IMX8M_PGC_DDR1 21
-#define IMX8M_PGC_GPU 23
-#define IMX8M_PGC_VPU 24
-#define IMX8M_PGC_DISP 26
-#define IMX8M_PGC_MIPI_CSI1 27
-#define IMX8M_PGC_MIPI_CSI2 28
-#define IMX8M_PGC_PCIE2 29
-
-#define IMX8MM_PGC_MIPI 16
-#define IMX8MM_PGC_PCIE 17
-#define IMX8MM_PGC_OTG1 18
-#define IMX8MM_PGC_OTG2 19
-#define IMX8MM_PGC_DDR1 21
-#define IMX8MM_PGC_GPU2D 22
-#define IMX8MM_PGC_GPUMIX 23
-#define IMX8MM_PGC_VPUMIX 24
-#define IMX8MM_PGC_GPU3D 25
-#define IMX8MM_PGC_DISPMIX 26
-#define IMX8MM_PGC_VPUG1 27
-#define IMX8MM_PGC_VPUG2 28
-#define IMX8MM_PGC_VPUH1 29
-
-#define IMX8MN_PGC_MIPI 16
-#define IMX8MN_PGC_OTG1 18
-#define IMX8MN_PGC_DDR1 21
-#define IMX8MN_PGC_GPUMIX 23
-#define IMX8MN_PGC_DISPMIX 26
-
-#define IMX8MP_PGC_NOC 9
-#define IMX8MP_PGC_MIPI1 12
-#define IMX8MP_PGC_PCIE 13
-#define IMX8MP_PGC_USB1 14
-#define IMX8MP_PGC_USB2 15
-#define IMX8MP_PGC_MLMIX 16
-#define IMX8MP_PGC_AUDIOMIX 17
-#define IMX8MP_PGC_GPU2D 18
-#define IMX8MP_PGC_GPUMIX 19
-#define IMX8MP_PGC_VPUMIX 20
-#define IMX8MP_PGC_GPU3D 21
-#define IMX8MP_PGC_MEDIAMIX 22
-#define IMX8MP_PGC_VPU_G1 23
-#define IMX8MP_PGC_VPU_G2 24
-#define IMX8MP_PGC_VPU_VC8000E 25
-#define IMX8MP_PGC_HDMIMIX 26
-#define IMX8MP_PGC_HDMI 27
-#define IMX8MP_PGC_MIPI2 28
-#define IMX8MP_PGC_HSIOMIX 29
-#define IMX8MP_PGC_MEDIA_ISP_DWP 30
-#define IMX8MP_PGC_DDRMIX 31
-
-#define GPC_PGC_CTRL(n) (0x800 + (n) * 0x40)
-#define GPC_PGC_SR(n) (GPC_PGC_CTRL(n) + 0xc)
-
-#define GPC_PGC_CTRL_PCR BIT(0)
-
-struct imx_pgc_regs {
- u16 map;
- u16 pup;
- u16 pdn;
- u16 hsk;
-};
-
-struct imx_pgc_domain {
- struct generic_pm_domain genpd;
- struct regmap *regmap;
- const struct imx_pgc_regs *regs;
- struct regulator *regulator;
- struct reset_control *reset;
- struct clk_bulk_data *clks;
- int num_clks;
-
- unsigned long pgc;
-
- const struct {
- u32 pxx;
- u32 map;
- u32 hskreq;
- u32 hskack;
- } bits;
-
- const int voltage;
- const bool keep_clocks;
- struct device *dev;
-
- unsigned int pgc_sw_pup_reg;
- unsigned int pgc_sw_pdn_reg;
-};
-
-struct imx_pgc_domain_data {
- const struct imx_pgc_domain *domains;
- size_t domains_num;
- const struct regmap_access_table *reg_access_table;
- const struct imx_pgc_regs *pgc_regs;
-};
-
-static inline struct imx_pgc_domain *
-to_imx_pgc_domain(struct generic_pm_domain *genpd)
-{
- return container_of(genpd, struct imx_pgc_domain, genpd);
-}
-
-static int imx_pgc_power_up(struct generic_pm_domain *genpd)
-{
- struct imx_pgc_domain *domain = to_imx_pgc_domain(genpd);
- u32 reg_val, pgc;
- int ret;
-
- ret = pm_runtime_get_sync(domain->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(domain->dev);
- return ret;
- }
-
- if (!IS_ERR(domain->regulator)) {
- ret = regulator_enable(domain->regulator);
- if (ret) {
- dev_err(domain->dev,
- "failed to enable regulator: %pe\n",
- ERR_PTR(ret));
- goto out_put_pm;
- }
- }
-
- reset_control_assert(domain->reset);
-
- /* Enable reset clocks for all devices in the domain */
- ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks);
- if (ret) {
- dev_err(domain->dev, "failed to enable reset clocks\n");
- goto out_regulator_disable;
- }
-
- /* delays for reset to propagate */
- udelay(5);
-
- if (domain->bits.pxx) {
- /* request the domain to power up */
- regmap_update_bits(domain->regmap, domain->regs->pup,
- domain->bits.pxx, domain->bits.pxx);
- /*
- * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait
- * for PUP_REQ/PDN_REQ bit to be cleared
- */
- ret = regmap_read_poll_timeout(domain->regmap,
- domain->regs->pup, reg_val,
- !(reg_val & domain->bits.pxx),
- 0, USEC_PER_MSEC);
- if (ret) {
- dev_err(domain->dev, "failed to command PGC\n");
- goto out_clk_disable;
- }
-
- /* disable power control */
- for_each_set_bit(pgc, &domain->pgc, 32) {
- regmap_clear_bits(domain->regmap, GPC_PGC_CTRL(pgc),
- GPC_PGC_CTRL_PCR);
- }
- }
-
- /* delay for reset to propagate */
- udelay(5);
-
- reset_control_deassert(domain->reset);
-
- /* request the ADB400 to power up */
- if (domain->bits.hskreq) {
- regmap_update_bits(domain->regmap, domain->regs->hsk,
- domain->bits.hskreq, domain->bits.hskreq);
-
- /*
- * ret = regmap_read_poll_timeout(domain->regmap, domain->regs->hsk, reg_val,
- * (reg_val & domain->bits.hskack), 0,
- * USEC_PER_MSEC);
- * Technically we need the commented code to wait handshake. But that needs
- * the BLK-CTL module BUS clk-en bit being set.
- *
- * There is a separate BLK-CTL module and we will have such a driver for it,
- * that driver will set the BUS clk-en bit and handshake will be triggered
- * automatically there. Just add a delay and suppose the handshake finish
- * after that.
- */
- }
-
- /* Disable reset clocks for all devices in the domain */
- if (!domain->keep_clocks)
- clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
-
- return 0;
-
-out_clk_disable:
- clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
-out_regulator_disable:
- if (!IS_ERR(domain->regulator))
- regulator_disable(domain->regulator);
-out_put_pm:
- pm_runtime_put(domain->dev);
-
- return ret;
-}
-
-static int imx_pgc_power_down(struct generic_pm_domain *genpd)
-{
- struct imx_pgc_domain *domain = to_imx_pgc_domain(genpd);
- u32 reg_val, pgc;
- int ret;
-
- /* Enable reset clocks for all devices in the domain */
- if (!domain->keep_clocks) {
- ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks);
- if (ret) {
- dev_err(domain->dev, "failed to enable reset clocks\n");
- return ret;
- }
- }
-
- /* request the ADB400 to power down */
- if (domain->bits.hskreq) {
- regmap_clear_bits(domain->regmap, domain->regs->hsk,
- domain->bits.hskreq);
-
- ret = regmap_read_poll_timeout(domain->regmap, domain->regs->hsk,
- reg_val,
- !(reg_val & domain->bits.hskack),
- 0, USEC_PER_MSEC);
- if (ret) {
- dev_err(domain->dev, "failed to power down ADB400\n");
- goto out_clk_disable;
- }
- }
-
- if (domain->bits.pxx) {
- /* enable power control */
- for_each_set_bit(pgc, &domain->pgc, 32) {
- regmap_update_bits(domain->regmap, GPC_PGC_CTRL(pgc),
- GPC_PGC_CTRL_PCR, GPC_PGC_CTRL_PCR);
- }
-
- /* request the domain to power down */
- regmap_update_bits(domain->regmap, domain->regs->pdn,
- domain->bits.pxx, domain->bits.pxx);
- /*
- * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait
- * for PUP_REQ/PDN_REQ bit to be cleared
- */
- ret = regmap_read_poll_timeout(domain->regmap,
- domain->regs->pdn, reg_val,
- !(reg_val & domain->bits.pxx),
- 0, USEC_PER_MSEC);
- if (ret) {
- dev_err(domain->dev, "failed to command PGC\n");
- goto out_clk_disable;
- }
- }
-
- /* Disable reset clocks for all devices in the domain */
- clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
-
- if (!IS_ERR(domain->regulator)) {
- ret = regulator_disable(domain->regulator);
- if (ret) {
- dev_err(domain->dev,
- "failed to disable regulator: %pe\n",
- ERR_PTR(ret));
- return ret;
- }
- }
-
- pm_runtime_put_sync_suspend(domain->dev);
-
- return 0;
-
-out_clk_disable:
- if (!domain->keep_clocks)
- clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
-
- return ret;
-}
-
-static const struct imx_pgc_domain imx7_pgc_domains[] = {
- [IMX7_POWER_DOMAIN_MIPI_PHY] = {
- .genpd = {
- .name = "mipi-phy",
- },
- .bits = {
- .pxx = IMX7_MIPI_PHY_SW_Pxx_REQ,
- .map = IMX7_MIPI_PHY_A_CORE_DOMAIN,
- },
- .voltage = 1000000,
- .pgc = BIT(IMX7_PGC_MIPI),
- },
-
- [IMX7_POWER_DOMAIN_PCIE_PHY] = {
- .genpd = {
- .name = "pcie-phy",
- },
- .bits = {
- .pxx = IMX7_PCIE_PHY_SW_Pxx_REQ,
- .map = IMX7_PCIE_PHY_A_CORE_DOMAIN,
- },
- .voltage = 1000000,
- .pgc = BIT(IMX7_PGC_PCIE),
- },
-
- [IMX7_POWER_DOMAIN_USB_HSIC_PHY] = {
- .genpd = {
- .name = "usb-hsic-phy",
- },
- .bits = {
- .pxx = IMX7_USB_HSIC_PHY_SW_Pxx_REQ,
- .map = IMX7_USB_HSIC_PHY_A_CORE_DOMAIN,
- },
- .voltage = 1200000,
- .pgc = BIT(IMX7_PGC_USB_HSIC),
- },
-};
-
-static const struct regmap_range imx7_yes_ranges[] = {
- regmap_reg_range(GPC_LPCR_A_CORE_BSC,
- GPC_M4_PU_PDN_FLG),
- regmap_reg_range(GPC_PGC_CTRL(IMX7_PGC_MIPI),
- GPC_PGC_SR(IMX7_PGC_MIPI)),
- regmap_reg_range(GPC_PGC_CTRL(IMX7_PGC_PCIE),
- GPC_PGC_SR(IMX7_PGC_PCIE)),
- regmap_reg_range(GPC_PGC_CTRL(IMX7_PGC_USB_HSIC),
- GPC_PGC_SR(IMX7_PGC_USB_HSIC)),
-};
-
-static const struct regmap_access_table imx7_access_table = {
- .yes_ranges = imx7_yes_ranges,
- .n_yes_ranges = ARRAY_SIZE(imx7_yes_ranges),
-};
-
-static const struct imx_pgc_regs imx7_pgc_regs = {
- .map = GPC_PGC_CPU_MAPPING,
- .pup = GPC_PU_PGC_SW_PUP_REQ,
- .pdn = GPC_PU_PGC_SW_PDN_REQ,
- .hsk = GPC_PU_PWRHSK,
-};
-
-static const struct imx_pgc_domain_data imx7_pgc_domain_data = {
- .domains = imx7_pgc_domains,
- .domains_num = ARRAY_SIZE(imx7_pgc_domains),
- .reg_access_table = &imx7_access_table,
- .pgc_regs = &imx7_pgc_regs,
-};
-
-static const struct imx_pgc_domain imx8m_pgc_domains[] = {
- [IMX8M_POWER_DOMAIN_MIPI] = {
- .genpd = {
- .name = "mipi",
- },
- .bits = {
- .pxx = IMX8M_MIPI_SW_Pxx_REQ,
- .map = IMX8M_MIPI_A53_DOMAIN,
- },
- .pgc = BIT(IMX8M_PGC_MIPI),
- },
-
- [IMX8M_POWER_DOMAIN_PCIE1] = {
- .genpd = {
- .name = "pcie1",
- },
- .bits = {
- .pxx = IMX8M_PCIE1_SW_Pxx_REQ,
- .map = IMX8M_PCIE1_A53_DOMAIN,
- },
- .pgc = BIT(IMX8M_PGC_PCIE1),
- },
-
- [IMX8M_POWER_DOMAIN_USB_OTG1] = {
- .genpd = {
- .name = "usb-otg1",
- },
- .bits = {
- .pxx = IMX8M_OTG1_SW_Pxx_REQ,
- .map = IMX8M_OTG1_A53_DOMAIN,
- },
- .pgc = BIT(IMX8M_PGC_OTG1),
- },
-
- [IMX8M_POWER_DOMAIN_USB_OTG2] = {
- .genpd = {
- .name = "usb-otg2",
- },
- .bits = {
- .pxx = IMX8M_OTG2_SW_Pxx_REQ,
- .map = IMX8M_OTG2_A53_DOMAIN,
- },
- .pgc = BIT(IMX8M_PGC_OTG2),
- },
-
- [IMX8M_POWER_DOMAIN_DDR1] = {
- .genpd = {
- .name = "ddr1",
- },
- .bits = {
- .pxx = IMX8M_DDR1_SW_Pxx_REQ,
- .map = IMX8M_DDR2_A53_DOMAIN,
- },
- .pgc = BIT(IMX8M_PGC_DDR1),
- },
-
- [IMX8M_POWER_DOMAIN_GPU] = {
- .genpd = {
- .name = "gpu",
- },
- .bits = {
- .pxx = IMX8M_GPU_SW_Pxx_REQ,
- .map = IMX8M_GPU_A53_DOMAIN,
- .hskreq = IMX8M_GPU_HSK_PWRDNREQN,
- .hskack = IMX8M_GPU_HSK_PWRDNACKN,
- },
- .pgc = BIT(IMX8M_PGC_GPU),
- },
-
- [IMX8M_POWER_DOMAIN_VPU] = {
- .genpd = {
- .name = "vpu",
- },
- .bits = {
- .pxx = IMX8M_VPU_SW_Pxx_REQ,
- .map = IMX8M_VPU_A53_DOMAIN,
- .hskreq = IMX8M_VPU_HSK_PWRDNREQN,
- .hskack = IMX8M_VPU_HSK_PWRDNACKN,
- },
- .pgc = BIT(IMX8M_PGC_VPU),
- .keep_clocks = true,
- },
-
- [IMX8M_POWER_DOMAIN_DISP] = {
- .genpd = {
- .name = "disp",
- },
- .bits = {
- .pxx = IMX8M_DISP_SW_Pxx_REQ,
- .map = IMX8M_DISP_A53_DOMAIN,
- .hskreq = IMX8M_DISP_HSK_PWRDNREQN,
- .hskack = IMX8M_DISP_HSK_PWRDNACKN,
- },
- .pgc = BIT(IMX8M_PGC_DISP),
- },
-
- [IMX8M_POWER_DOMAIN_MIPI_CSI1] = {
- .genpd = {
- .name = "mipi-csi1",
- },
- .bits = {
- .pxx = IMX8M_MIPI_CSI1_SW_Pxx_REQ,
- .map = IMX8M_MIPI_CSI1_A53_DOMAIN,
- },
- .pgc = BIT(IMX8M_PGC_MIPI_CSI1),
- },
-
- [IMX8M_POWER_DOMAIN_MIPI_CSI2] = {
- .genpd = {
- .name = "mipi-csi2",
- },
- .bits = {
- .pxx = IMX8M_MIPI_CSI2_SW_Pxx_REQ,
- .map = IMX8M_MIPI_CSI2_A53_DOMAIN,
- },
- .pgc = BIT(IMX8M_PGC_MIPI_CSI2),
- },
-
- [IMX8M_POWER_DOMAIN_PCIE2] = {
- .genpd = {
- .name = "pcie2",
- },
- .bits = {
- .pxx = IMX8M_PCIE2_SW_Pxx_REQ,
- .map = IMX8M_PCIE2_A53_DOMAIN,
- },
- .pgc = BIT(IMX8M_PGC_PCIE2),
- },
-};
-
-static const struct regmap_range imx8m_yes_ranges[] = {
- regmap_reg_range(GPC_LPCR_A_CORE_BSC,
- GPC_PU_PWRHSK),
- regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_MIPI),
- GPC_PGC_SR(IMX8M_PGC_MIPI)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_PCIE1),
- GPC_PGC_SR(IMX8M_PGC_PCIE1)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_OTG1),
- GPC_PGC_SR(IMX8M_PGC_OTG1)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_OTG2),
- GPC_PGC_SR(IMX8M_PGC_OTG2)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_DDR1),
- GPC_PGC_SR(IMX8M_PGC_DDR1)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_GPU),
- GPC_PGC_SR(IMX8M_PGC_GPU)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_VPU),
- GPC_PGC_SR(IMX8M_PGC_VPU)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_DISP),
- GPC_PGC_SR(IMX8M_PGC_DISP)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_MIPI_CSI1),
- GPC_PGC_SR(IMX8M_PGC_MIPI_CSI1)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_MIPI_CSI2),
- GPC_PGC_SR(IMX8M_PGC_MIPI_CSI2)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_PCIE2),
- GPC_PGC_SR(IMX8M_PGC_PCIE2)),
-};
-
-static const struct regmap_access_table imx8m_access_table = {
- .yes_ranges = imx8m_yes_ranges,
- .n_yes_ranges = ARRAY_SIZE(imx8m_yes_ranges),
-};
-
-static const struct imx_pgc_domain_data imx8m_pgc_domain_data = {
- .domains = imx8m_pgc_domains,
- .domains_num = ARRAY_SIZE(imx8m_pgc_domains),
- .reg_access_table = &imx8m_access_table,
- .pgc_regs = &imx7_pgc_regs,
-};
-
-static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
- [IMX8MM_POWER_DOMAIN_HSIOMIX] = {
- .genpd = {
- .name = "hsiomix",
- },
- .bits = {
- .pxx = 0, /* no power sequence control */
- .map = 0, /* no power sequence control */
- .hskreq = IMX8MM_HSIO_HSK_PWRDNREQN,
- .hskack = IMX8MM_HSIO_HSK_PWRDNACKN,
- },
- .keep_clocks = true,
- },
-
- [IMX8MM_POWER_DOMAIN_PCIE] = {
- .genpd = {
- .name = "pcie",
- },
- .bits = {
- .pxx = IMX8MM_PCIE_SW_Pxx_REQ,
- .map = IMX8MM_PCIE_A53_DOMAIN,
- },
- .pgc = BIT(IMX8MM_PGC_PCIE),
- },
-
- [IMX8MM_POWER_DOMAIN_OTG1] = {
- .genpd = {
- .name = "usb-otg1",
- .flags = GENPD_FLAG_ACTIVE_WAKEUP,
- },
- .bits = {
- .pxx = IMX8MM_OTG1_SW_Pxx_REQ,
- .map = IMX8MM_OTG1_A53_DOMAIN,
- },
- .pgc = BIT(IMX8MM_PGC_OTG1),
- },
-
- [IMX8MM_POWER_DOMAIN_OTG2] = {
- .genpd = {
- .name = "usb-otg2",
- .flags = GENPD_FLAG_ACTIVE_WAKEUP,
- },
- .bits = {
- .pxx = IMX8MM_OTG2_SW_Pxx_REQ,
- .map = IMX8MM_OTG2_A53_DOMAIN,
- },
- .pgc = BIT(IMX8MM_PGC_OTG2),
- },
-
- [IMX8MM_POWER_DOMAIN_GPUMIX] = {
- .genpd = {
- .name = "gpumix",
- },
- .bits = {
- .pxx = IMX8MM_GPUMIX_SW_Pxx_REQ,
- .map = IMX8MM_GPUMIX_A53_DOMAIN,
- .hskreq = IMX8MM_GPUMIX_HSK_PWRDNREQN,
- .hskack = IMX8MM_GPUMIX_HSK_PWRDNACKN,
- },
- .pgc = BIT(IMX8MM_PGC_GPUMIX),
- .keep_clocks = true,
- },
-
- [IMX8MM_POWER_DOMAIN_GPU] = {
- .genpd = {
- .name = "gpu",
- },
- .bits = {
- .pxx = IMX8MM_GPU_SW_Pxx_REQ,
- .map = IMX8MM_GPU_A53_DOMAIN,
- .hskreq = IMX8MM_GPU_HSK_PWRDNREQN,
- .hskack = IMX8MM_GPU_HSK_PWRDNACKN,
- },
- .pgc = BIT(IMX8MM_PGC_GPU2D) | BIT(IMX8MM_PGC_GPU3D),
- },
-
- [IMX8MM_POWER_DOMAIN_VPUMIX] = {
- .genpd = {
- .name = "vpumix",
- },
- .bits = {
- .pxx = IMX8MM_VPUMIX_SW_Pxx_REQ,
- .map = IMX8MM_VPUMIX_A53_DOMAIN,
- .hskreq = IMX8MM_VPUMIX_HSK_PWRDNREQN,
- .hskack = IMX8MM_VPUMIX_HSK_PWRDNACKN,
- },
- .pgc = BIT(IMX8MM_PGC_VPUMIX),
- .keep_clocks = true,
- },
-
- [IMX8MM_POWER_DOMAIN_VPUG1] = {
- .genpd = {
- .name = "vpu-g1",
- },
- .bits = {
- .pxx = IMX8MM_VPUG1_SW_Pxx_REQ,
- .map = IMX8MM_VPUG1_A53_DOMAIN,
- },
- .pgc = BIT(IMX8MM_PGC_VPUG1),
- },
-
- [IMX8MM_POWER_DOMAIN_VPUG2] = {
- .genpd = {
- .name = "vpu-g2",
- },
- .bits = {
- .pxx = IMX8MM_VPUG2_SW_Pxx_REQ,
- .map = IMX8MM_VPUG2_A53_DOMAIN,
- },
- .pgc = BIT(IMX8MM_PGC_VPUG2),
- },
-
- [IMX8MM_POWER_DOMAIN_VPUH1] = {
- .genpd = {
- .name = "vpu-h1",
- },
- .bits = {
- .pxx = IMX8MM_VPUH1_SW_Pxx_REQ,
- .map = IMX8MM_VPUH1_A53_DOMAIN,
- },
- .pgc = BIT(IMX8MM_PGC_VPUH1),
- .keep_clocks = true,
- },
-
- [IMX8MM_POWER_DOMAIN_DISPMIX] = {
- .genpd = {
- .name = "dispmix",
- },
- .bits = {
- .pxx = IMX8MM_DISPMIX_SW_Pxx_REQ,
- .map = IMX8MM_DISPMIX_A53_DOMAIN,
- .hskreq = IMX8MM_DISPMIX_HSK_PWRDNREQN,
- .hskack = IMX8MM_DISPMIX_HSK_PWRDNACKN,
- },
- .pgc = BIT(IMX8MM_PGC_DISPMIX),
- .keep_clocks = true,
- },
-
- [IMX8MM_POWER_DOMAIN_MIPI] = {
- .genpd = {
- .name = "mipi",
- },
- .bits = {
- .pxx = IMX8MM_MIPI_SW_Pxx_REQ,
- .map = IMX8MM_MIPI_A53_DOMAIN,
- },
- .pgc = BIT(IMX8MM_PGC_MIPI),
- },
-};
-
-static const struct regmap_range imx8mm_yes_ranges[] = {
- regmap_reg_range(GPC_LPCR_A_CORE_BSC,
- GPC_PU_PWRHSK),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_MIPI),
- GPC_PGC_SR(IMX8MM_PGC_MIPI)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_PCIE),
- GPC_PGC_SR(IMX8MM_PGC_PCIE)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_OTG1),
- GPC_PGC_SR(IMX8MM_PGC_OTG1)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_OTG2),
- GPC_PGC_SR(IMX8MM_PGC_OTG2)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_DDR1),
- GPC_PGC_SR(IMX8MM_PGC_DDR1)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_GPU2D),
- GPC_PGC_SR(IMX8MM_PGC_GPU2D)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_GPUMIX),
- GPC_PGC_SR(IMX8MM_PGC_GPUMIX)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_VPUMIX),
- GPC_PGC_SR(IMX8MM_PGC_VPUMIX)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_GPU3D),
- GPC_PGC_SR(IMX8MM_PGC_GPU3D)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_DISPMIX),
- GPC_PGC_SR(IMX8MM_PGC_DISPMIX)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_VPUG1),
- GPC_PGC_SR(IMX8MM_PGC_VPUG1)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_VPUG2),
- GPC_PGC_SR(IMX8MM_PGC_VPUG2)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_VPUH1),
- GPC_PGC_SR(IMX8MM_PGC_VPUH1)),
-};
-
-static const struct regmap_access_table imx8mm_access_table = {
- .yes_ranges = imx8mm_yes_ranges,
- .n_yes_ranges = ARRAY_SIZE(imx8mm_yes_ranges),
-};
-
-static const struct imx_pgc_domain_data imx8mm_pgc_domain_data = {
- .domains = imx8mm_pgc_domains,
- .domains_num = ARRAY_SIZE(imx8mm_pgc_domains),
- .reg_access_table = &imx8mm_access_table,
- .pgc_regs = &imx7_pgc_regs,
-};
-
-static const struct imx_pgc_domain imx8mp_pgc_domains[] = {
- [IMX8MP_POWER_DOMAIN_MIPI_PHY1] = {
- .genpd = {
- .name = "mipi-phy1",
- },
- .bits = {
- .pxx = IMX8MP_MIPI_PHY1_SW_Pxx_REQ,
- .map = IMX8MP_MIPI_PHY1_A53_DOMAIN,
- },
- .pgc = BIT(IMX8MP_PGC_MIPI1),
- },
-
- [IMX8MP_POWER_DOMAIN_PCIE_PHY] = {
- .genpd = {
- .name = "pcie-phy1",
- },
- .bits = {
- .pxx = IMX8MP_PCIE_PHY_SW_Pxx_REQ,
- .map = IMX8MP_PCIE_PHY_A53_DOMAIN,
- },
- .pgc = BIT(IMX8MP_PGC_PCIE),
- },
-
- [IMX8MP_POWER_DOMAIN_USB1_PHY] = {
- .genpd = {
- .name = "usb-otg1",
- },
- .bits = {
- .pxx = IMX8MP_USB1_PHY_Pxx_REQ,
- .map = IMX8MP_USB1_PHY_A53_DOMAIN,
- },
- .pgc = BIT(IMX8MP_PGC_USB1),
- },
-
- [IMX8MP_POWER_DOMAIN_USB2_PHY] = {
- .genpd = {
- .name = "usb-otg2",
- },
- .bits = {
- .pxx = IMX8MP_USB2_PHY_Pxx_REQ,
- .map = IMX8MP_USB2_PHY_A53_DOMAIN,
- },
- .pgc = BIT(IMX8MP_PGC_USB2),
- },
-
- [IMX8MP_POWER_DOMAIN_MLMIX] = {
- .genpd = {
- .name = "mlmix",
- },
- .bits = {
- .pxx = IMX8MP_MLMIX_Pxx_REQ,
- .map = IMX8MP_MLMIX_A53_DOMAIN,
- .hskreq = IMX8MP_MLMIX_PWRDNREQN,
- .hskack = IMX8MP_MLMIX_PWRDNACKN,
- },
- .pgc = BIT(IMX8MP_PGC_MLMIX),
- .keep_clocks = true,
- },
-
- [IMX8MP_POWER_DOMAIN_AUDIOMIX] = {
- .genpd = {
- .name = "audiomix",
- },
- .bits = {
- .pxx = IMX8MP_AUDIOMIX_Pxx_REQ,
- .map = IMX8MP_AUDIOMIX_A53_DOMAIN,
- .hskreq = IMX8MP_AUDIOMIX_PWRDNREQN,
- .hskack = IMX8MP_AUDIOMIX_PWRDNACKN,
- },
- .pgc = BIT(IMX8MP_PGC_AUDIOMIX),
- .keep_clocks = true,
- },
-
- [IMX8MP_POWER_DOMAIN_GPU2D] = {
- .genpd = {
- .name = "gpu2d",
- },
- .bits = {
- .pxx = IMX8MP_GPU_2D_Pxx_REQ,
- .map = IMX8MP_GPU2D_A53_DOMAIN,
- },
- .pgc = BIT(IMX8MP_PGC_GPU2D),
- },
-
- [IMX8MP_POWER_DOMAIN_GPUMIX] = {
- .genpd = {
- .name = "gpumix",
- },
- .bits = {
- .pxx = IMX8MP_GPU_SHARE_LOGIC_Pxx_REQ,
- .map = IMX8MP_GPUMIX_A53_DOMAIN,
- .hskreq = IMX8MP_GPUMIX_PWRDNREQN,
- .hskack = IMX8MP_GPUMIX_PWRDNACKN,
- },
- .pgc = BIT(IMX8MP_PGC_GPUMIX),
- .keep_clocks = true,
- },
-
- [IMX8MP_POWER_DOMAIN_VPUMIX] = {
- .genpd = {
- .name = "vpumix",
- },
- .bits = {
- .pxx = IMX8MP_VPU_MIX_SHARE_LOGIC_Pxx_REQ,
- .map = IMX8MP_VPUMIX_A53_DOMAIN,
- .hskreq = IMX8MP_VPUMIX_PWRDNREQN,
- .hskack = IMX8MP_VPUMIX_PWRDNACKN,
- },
- .pgc = BIT(IMX8MP_PGC_VPUMIX),
- .keep_clocks = true,
- },
-
- [IMX8MP_POWER_DOMAIN_GPU3D] = {
- .genpd = {
- .name = "gpu3d",
- },
- .bits = {
- .pxx = IMX8MP_GPU_3D_Pxx_REQ,
- .map = IMX8MP_GPU3D_A53_DOMAIN,
- },
- .pgc = BIT(IMX8MP_PGC_GPU3D),
- },
-
- [IMX8MP_POWER_DOMAIN_MEDIAMIX] = {
- .genpd = {
- .name = "mediamix",
- },
- .bits = {
- .pxx = IMX8MP_MEDIMIX_Pxx_REQ,
- .map = IMX8MP_MEDIAMIX_A53_DOMAIN,
- .hskreq = IMX8MP_MEDIAMIX_PWRDNREQN,
- .hskack = IMX8MP_MEDIAMIX_PWRDNACKN,
- },
- .pgc = BIT(IMX8MP_PGC_MEDIAMIX),
- .keep_clocks = true,
- },
-
- [IMX8MP_POWER_DOMAIN_VPU_G1] = {
- .genpd = {
- .name = "vpu-g1",
- },
- .bits = {
- .pxx = IMX8MP_VPU_G1_Pxx_REQ,
- .map = IMX8MP_VPU_G1_A53_DOMAIN,
- },
- .pgc = BIT(IMX8MP_PGC_VPU_G1),
- },
-
- [IMX8MP_POWER_DOMAIN_VPU_G2] = {
- .genpd = {
- .name = "vpu-g2",
- },
- .bits = {
- .pxx = IMX8MP_VPU_G2_Pxx_REQ,
- .map = IMX8MP_VPU_G2_A53_DOMAIN
- },
- .pgc = BIT(IMX8MP_PGC_VPU_G2),
- },
-
- [IMX8MP_POWER_DOMAIN_VPU_VC8000E] = {
- .genpd = {
- .name = "vpu-h1",
- },
- .bits = {
- .pxx = IMX8MP_VPU_VC8K_Pxx_REQ,
- .map = IMX8MP_VPU_VC8000E_A53_DOMAIN,
- },
- .pgc = BIT(IMX8MP_PGC_VPU_VC8000E),
- },
-
- [IMX8MP_POWER_DOMAIN_HDMIMIX] = {
- .genpd = {
- .name = "hdmimix",
- },
- .bits = {
- .pxx = IMX8MP_HDMIMIX_Pxx_REQ,
- .map = IMX8MP_HDMIMIX_A53_DOMAIN,
- .hskreq = IMX8MP_HDMIMIX_PWRDNREQN,
- .hskack = IMX8MP_HDMIMIX_PWRDNACKN,
- },
- .pgc = BIT(IMX8MP_PGC_HDMIMIX),
- .keep_clocks = true,
- },
-
- [IMX8MP_POWER_DOMAIN_HDMI_PHY] = {
- .genpd = {
- .name = "hdmi-phy",
- },
- .bits = {
- .pxx = IMX8MP_HDMI_PHY_Pxx_REQ,
- .map = IMX8MP_HDMI_PHY_A53_DOMAIN,
- },
- .pgc = BIT(IMX8MP_PGC_HDMI),
- },
-
- [IMX8MP_POWER_DOMAIN_MIPI_PHY2] = {
- .genpd = {
- .name = "mipi-phy2",
- },
- .bits = {
- .pxx = IMX8MP_MIPI_PHY2_Pxx_REQ,
- .map = IMX8MP_MIPI_PHY2_A53_DOMAIN,
- },
- .pgc = BIT(IMX8MP_PGC_MIPI2),
- },
-
- [IMX8MP_POWER_DOMAIN_HSIOMIX] = {
- .genpd = {
- .name = "hsiomix",
- },
- .bits = {
- .pxx = IMX8MP_HSIOMIX_Pxx_REQ,
- .map = IMX8MP_HSIOMIX_A53_DOMAIN,
- .hskreq = IMX8MP_HSIOMIX_PWRDNREQN,
- .hskack = IMX8MP_HSIOMIX_PWRDNACKN,
- },
- .pgc = BIT(IMX8MP_PGC_HSIOMIX),
- .keep_clocks = true,
- },
-
- [IMX8MP_POWER_DOMAIN_MEDIAMIX_ISPDWP] = {
- .genpd = {
- .name = "mediamix-isp-dwp",
- },
- .bits = {
- .pxx = IMX8MP_MEDIA_ISP_DWP_Pxx_REQ,
- .map = IMX8MP_MEDIA_ISPDWP_A53_DOMAIN,
- },
- .pgc = BIT(IMX8MP_PGC_MEDIA_ISP_DWP),
- },
-};
-
-static const struct regmap_range imx8mp_yes_ranges[] = {
- regmap_reg_range(GPC_LPCR_A_CORE_BSC,
- IMX8MP_GPC_PGC_CPU_MAPPING),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_NOC),
- GPC_PGC_SR(IMX8MP_PGC_NOC)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_MIPI1),
- GPC_PGC_SR(IMX8MP_PGC_MIPI1)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_PCIE),
- GPC_PGC_SR(IMX8MP_PGC_PCIE)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_USB1),
- GPC_PGC_SR(IMX8MP_PGC_USB1)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_USB2),
- GPC_PGC_SR(IMX8MP_PGC_USB2)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_MLMIX),
- GPC_PGC_SR(IMX8MP_PGC_MLMIX)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_AUDIOMIX),
- GPC_PGC_SR(IMX8MP_PGC_AUDIOMIX)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_GPU2D),
- GPC_PGC_SR(IMX8MP_PGC_GPU2D)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_GPUMIX),
- GPC_PGC_SR(IMX8MP_PGC_GPUMIX)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_VPUMIX),
- GPC_PGC_SR(IMX8MP_PGC_VPUMIX)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_GPU3D),
- GPC_PGC_SR(IMX8MP_PGC_GPU3D)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_MEDIAMIX),
- GPC_PGC_SR(IMX8MP_PGC_MEDIAMIX)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_VPU_G1),
- GPC_PGC_SR(IMX8MP_PGC_VPU_G1)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_VPU_G2),
- GPC_PGC_SR(IMX8MP_PGC_VPU_G2)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_VPU_VC8000E),
- GPC_PGC_SR(IMX8MP_PGC_VPU_VC8000E)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_HDMIMIX),
- GPC_PGC_SR(IMX8MP_PGC_HDMIMIX)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_HDMI),
- GPC_PGC_SR(IMX8MP_PGC_HDMI)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_MIPI2),
- GPC_PGC_SR(IMX8MP_PGC_MIPI2)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_HSIOMIX),
- GPC_PGC_SR(IMX8MP_PGC_HSIOMIX)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_MEDIA_ISP_DWP),
- GPC_PGC_SR(IMX8MP_PGC_MEDIA_ISP_DWP)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MP_PGC_DDRMIX),
- GPC_PGC_SR(IMX8MP_PGC_DDRMIX)),
-};
-
-static const struct regmap_access_table imx8mp_access_table = {
- .yes_ranges = imx8mp_yes_ranges,
- .n_yes_ranges = ARRAY_SIZE(imx8mp_yes_ranges),
-};
-
-static const struct imx_pgc_regs imx8mp_pgc_regs = {
- .map = IMX8MP_GPC_PGC_CPU_MAPPING,
- .pup = IMX8MP_GPC_PU_PGC_SW_PUP_REQ,
- .pdn = IMX8MP_GPC_PU_PGC_SW_PDN_REQ,
- .hsk = IMX8MP_GPC_PU_PWRHSK,
-};
-static const struct imx_pgc_domain_data imx8mp_pgc_domain_data = {
- .domains = imx8mp_pgc_domains,
- .domains_num = ARRAY_SIZE(imx8mp_pgc_domains),
- .reg_access_table = &imx8mp_access_table,
- .pgc_regs = &imx8mp_pgc_regs,
-};
-
-static const struct imx_pgc_domain imx8mn_pgc_domains[] = {
- [IMX8MN_POWER_DOMAIN_HSIOMIX] = {
- .genpd = {
- .name = "hsiomix",
- },
- .bits = {
- .pxx = 0, /* no power sequence control */
- .map = 0, /* no power sequence control */
- .hskreq = IMX8MN_HSIO_HSK_PWRDNREQN,
- .hskack = IMX8MN_HSIO_HSK_PWRDNACKN,
- },
- .keep_clocks = true,
- },
-
- [IMX8MN_POWER_DOMAIN_OTG1] = {
- .genpd = {
- .name = "usb-otg1",
- .flags = GENPD_FLAG_ACTIVE_WAKEUP,
- },
- .bits = {
- .pxx = IMX8MN_OTG1_SW_Pxx_REQ,
- .map = IMX8MN_OTG1_A53_DOMAIN,
- },
- .pgc = BIT(IMX8MN_PGC_OTG1),
- },
-
- [IMX8MN_POWER_DOMAIN_GPUMIX] = {
- .genpd = {
- .name = "gpumix",
- },
- .bits = {
- .pxx = IMX8MN_GPUMIX_SW_Pxx_REQ,
- .map = IMX8MN_GPUMIX_A53_DOMAIN,
- .hskreq = IMX8MN_GPUMIX_HSK_PWRDNREQN,
- .hskack = IMX8MN_GPUMIX_HSK_PWRDNACKN,
- },
- .pgc = BIT(IMX8MN_PGC_GPUMIX),
- .keep_clocks = true,
- },
-
- [IMX8MN_POWER_DOMAIN_DISPMIX] = {
- .genpd = {
- .name = "dispmix",
- },
- .bits = {
- .pxx = IMX8MN_DISPMIX_SW_Pxx_REQ,
- .map = IMX8MN_DISPMIX_A53_DOMAIN,
- .hskreq = IMX8MN_DISPMIX_HSK_PWRDNREQN,
- .hskack = IMX8MN_DISPMIX_HSK_PWRDNACKN,
- },
- .pgc = BIT(IMX8MN_PGC_DISPMIX),
- .keep_clocks = true,
- },
-
- [IMX8MN_POWER_DOMAIN_MIPI] = {
- .genpd = {
- .name = "mipi",
- },
- .bits = {
- .pxx = IMX8MN_MIPI_SW_Pxx_REQ,
- .map = IMX8MN_MIPI_A53_DOMAIN,
- },
- .pgc = BIT(IMX8MN_PGC_MIPI),
- },
-};
-
-static const struct regmap_range imx8mn_yes_ranges[] = {
- regmap_reg_range(GPC_LPCR_A_CORE_BSC,
- GPC_PU_PWRHSK),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_MIPI),
- GPC_PGC_SR(IMX8MN_PGC_MIPI)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_OTG1),
- GPC_PGC_SR(IMX8MN_PGC_OTG1)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_DDR1),
- GPC_PGC_SR(IMX8MN_PGC_DDR1)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_GPUMIX),
- GPC_PGC_SR(IMX8MN_PGC_GPUMIX)),
- regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_DISPMIX),
- GPC_PGC_SR(IMX8MN_PGC_DISPMIX)),
-};
-
-static const struct regmap_access_table imx8mn_access_table = {
- .yes_ranges = imx8mn_yes_ranges,
- .n_yes_ranges = ARRAY_SIZE(imx8mn_yes_ranges),
-};
-
-static const struct imx_pgc_domain_data imx8mn_pgc_domain_data = {
- .domains = imx8mn_pgc_domains,
- .domains_num = ARRAY_SIZE(imx8mn_pgc_domains),
- .reg_access_table = &imx8mn_access_table,
- .pgc_regs = &imx7_pgc_regs,
-};
-
-static int imx_pgc_domain_probe(struct platform_device *pdev)
-{
- struct imx_pgc_domain *domain = pdev->dev.platform_data;
- int ret;
-
- domain->dev = &pdev->dev;
-
- domain->regulator = devm_regulator_get_optional(domain->dev, "power");
- if (IS_ERR(domain->regulator)) {
- if (PTR_ERR(domain->regulator) != -ENODEV)
- return dev_err_probe(domain->dev, PTR_ERR(domain->regulator),
- "Failed to get domain's regulator\n");
- } else if (domain->voltage) {
- regulator_set_voltage(domain->regulator,
- domain->voltage, domain->voltage);
- }
-
- domain->num_clks = devm_clk_bulk_get_all(domain->dev, &domain->clks);
- if (domain->num_clks < 0)
- return dev_err_probe(domain->dev, domain->num_clks,
- "Failed to get domain's clocks\n");
-
- domain->reset = devm_reset_control_array_get_optional_exclusive(domain->dev);
- if (IS_ERR(domain->reset))
- return dev_err_probe(domain->dev, PTR_ERR(domain->reset),
- "Failed to get domain's resets\n");
-
- pm_runtime_enable(domain->dev);
-
- if (domain->bits.map)
- regmap_update_bits(domain->regmap, domain->regs->map,
- domain->bits.map, domain->bits.map);
-
- ret = pm_genpd_init(&domain->genpd, NULL, true);
- if (ret) {
- dev_err(domain->dev, "Failed to init power domain\n");
- goto out_domain_unmap;
- }
-
- if (IS_ENABLED(CONFIG_LOCKDEP) &&
- of_property_read_bool(domain->dev->of_node, "power-domains"))
- lockdep_set_subclass(&domain->genpd.mlock, 1);
-
- ret = of_genpd_add_provider_simple(domain->dev->of_node,
- &domain->genpd);
- if (ret) {
- dev_err(domain->dev, "Failed to add genpd provider\n");
- goto out_genpd_remove;
- }
-
- return 0;
-
-out_genpd_remove:
- pm_genpd_remove(&domain->genpd);
-out_domain_unmap:
- if (domain->bits.map)
- regmap_update_bits(domain->regmap, domain->regs->map,
- domain->bits.map, 0);
- pm_runtime_disable(domain->dev);
-
- return ret;
-}
-
-static int imx_pgc_domain_remove(struct platform_device *pdev)
-{
- struct imx_pgc_domain *domain = pdev->dev.platform_data;
-
- of_genpd_del_provider(domain->dev->of_node);
- pm_genpd_remove(&domain->genpd);
-
- if (domain->bits.map)
- regmap_update_bits(domain->regmap, domain->regs->map,
- domain->bits.map, 0);
-
- pm_runtime_disable(domain->dev);
-
- return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int imx_pgc_domain_suspend(struct device *dev)
-{
- int ret;
-
- /*
- * This may look strange, but is done so the generic PM_SLEEP code
- * can power down our domain and more importantly power it up again
- * after resume, without tripping over our usage of runtime PM to
- * power up/down the nested domains.
- */
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- pm_runtime_put_noidle(dev);
- return ret;
- }
-
- return 0;
-}
-
-static int imx_pgc_domain_resume(struct device *dev)
-{
- return pm_runtime_put(dev);
-}
-#endif
-
-static const struct dev_pm_ops imx_pgc_domain_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(imx_pgc_domain_suspend, imx_pgc_domain_resume)
-};
-
-static const struct platform_device_id imx_pgc_domain_id[] = {
- { "imx-pgc-domain", },
- { },
-};
-
-static struct platform_driver imx_pgc_domain_driver = {
- .driver = {
- .name = "imx-pgc",
- .pm = &imx_pgc_domain_pm_ops,
- },
- .probe = imx_pgc_domain_probe,
- .remove = imx_pgc_domain_remove,
- .id_table = imx_pgc_domain_id,
-};
-builtin_platform_driver(imx_pgc_domain_driver)
-
-static int imx_gpcv2_probe(struct platform_device *pdev)
-{
- const struct imx_pgc_domain_data *domain_data =
- of_device_get_match_data(&pdev->dev);
-
- struct regmap_config regmap_config = {
- .reg_bits = 32,
- .val_bits = 32,
- .reg_stride = 4,
- .rd_table = domain_data->reg_access_table,
- .wr_table = domain_data->reg_access_table,
- .max_register = SZ_4K,
- };
- struct device *dev = &pdev->dev;
- struct device_node *pgc_np, *np;
- struct regmap *regmap;
- void __iomem *base;
- int ret;
-
- pgc_np = of_get_child_by_name(dev->of_node, "pgc");
- if (!pgc_np) {
- dev_err(dev, "No power domains specified in DT\n");
- return -EINVAL;
- }
-
- base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- regmap = devm_regmap_init_mmio(dev, base, &regmap_config);
- if (IS_ERR(regmap)) {
- ret = PTR_ERR(regmap);
- dev_err(dev, "failed to init regmap (%d)\n", ret);
- return ret;
- }
-
- for_each_child_of_node(pgc_np, np) {
- struct platform_device *pd_pdev;
- struct imx_pgc_domain *domain;
- u32 domain_index;
-
- if (!of_device_is_available(np))
- continue;
-
- ret = of_property_read_u32(np, "reg", &domain_index);
- if (ret) {
- dev_err(dev, "Failed to read 'reg' property\n");
- of_node_put(np);
- return ret;
- }
-
- if (domain_index >= domain_data->domains_num) {
- dev_warn(dev,
- "Domain index %d is out of bounds\n",
- domain_index);
- continue;
- }
-
- pd_pdev = platform_device_alloc("imx-pgc-domain",
- domain_index);
- if (!pd_pdev) {
- dev_err(dev, "Failed to allocate platform device\n");
- of_node_put(np);
- return -ENOMEM;
- }
-
- ret = platform_device_add_data(pd_pdev,
- &domain_data->domains[domain_index],
- sizeof(domain_data->domains[domain_index]));
- if (ret) {
- platform_device_put(pd_pdev);
- of_node_put(np);
- return ret;
- }
-
- domain = pd_pdev->dev.platform_data;
- domain->regmap = regmap;
- domain->regs = domain_data->pgc_regs;
-
- domain->genpd.power_on = imx_pgc_power_up;
- domain->genpd.power_off = imx_pgc_power_down;
-
- pd_pdev->dev.parent = dev;
- pd_pdev->dev.of_node = np;
-
- ret = platform_device_add(pd_pdev);
- if (ret) {
- platform_device_put(pd_pdev);
- of_node_put(np);
- return ret;
- }
- }
-
- return 0;
-}
-
-static const struct of_device_id imx_gpcv2_dt_ids[] = {
- { .compatible = "fsl,imx7d-gpc", .data = &imx7_pgc_domain_data, },
- { .compatible = "fsl,imx8mm-gpc", .data = &imx8mm_pgc_domain_data, },
- { .compatible = "fsl,imx8mn-gpc", .data = &imx8mn_pgc_domain_data, },
- { .compatible = "fsl,imx8mp-gpc", .data = &imx8mp_pgc_domain_data, },
- { .compatible = "fsl,imx8mq-gpc", .data = &imx8m_pgc_domain_data, },
- { }
-};
-
-static struct platform_driver imx_gpc_driver = {
- .driver = {
- .name = "imx-gpcv2",
- .of_match_table = imx_gpcv2_dt_ids,
- },
- .probe = imx_gpcv2_probe,
-};
-builtin_platform_driver(imx_gpc_driver)
diff --git a/drivers/soc/imx/imx8m-blk-ctrl.c b/drivers/soc/imx/imx8m-blk-ctrl.c
deleted file mode 100644
index ddcf6be3d8b4..000000000000
--- a/drivers/soc/imx/imx8m-blk-ctrl.c
+++ /dev/null
@@ -1,878 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-
-/*
- * Copyright 2021 Pengutronix, Lucas Stach <kernel@pengutronix.de>
- */
-
-#include <linux/device.h>
-#include <linux/interconnect.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <linux/pm_runtime.h>
-#include <linux/regmap.h>
-#include <linux/clk.h>
-
-#include <dt-bindings/power/imx8mm-power.h>
-#include <dt-bindings/power/imx8mn-power.h>
-#include <dt-bindings/power/imx8mp-power.h>
-#include <dt-bindings/power/imx8mq-power.h>
-
-#define BLK_SFT_RSTN 0x0
-#define BLK_CLK_EN 0x4
-#define BLK_MIPI_RESET_DIV 0x8 /* Mini/Nano/Plus DISPLAY_BLK_CTRL only */
-
-struct imx8m_blk_ctrl_domain;
-
-struct imx8m_blk_ctrl {
- struct device *dev;
- struct notifier_block power_nb;
- struct device *bus_power_dev;
- struct regmap *regmap;
- struct imx8m_blk_ctrl_domain *domains;
- struct genpd_onecell_data onecell_data;
-};
-
-struct imx8m_blk_ctrl_domain_data {
- const char *name;
- const char * const *clk_names;
- int num_clks;
- const char * const *path_names;
- int num_paths;
- const char *gpc_name;
- u32 rst_mask;
- u32 clk_mask;
-
- /*
- * i.MX8M Mini, Nano and Plus have a third DISPLAY_BLK_CTRL register
- * which is used to control the reset for the MIPI Phy.
- * Since it's only present in certain circumstances,
- * an if-statement should be used before setting and clearing this
- * register.
- */
- u32 mipi_phy_rst_mask;
-};
-
-#define DOMAIN_MAX_CLKS 4
-#define DOMAIN_MAX_PATHS 4
-
-struct imx8m_blk_ctrl_domain {
- struct generic_pm_domain genpd;
- const struct imx8m_blk_ctrl_domain_data *data;
- struct clk_bulk_data clks[DOMAIN_MAX_CLKS];
- struct icc_bulk_data paths[DOMAIN_MAX_PATHS];
- struct device *power_dev;
- struct imx8m_blk_ctrl *bc;
- int num_paths;
-};
-
-struct imx8m_blk_ctrl_data {
- int max_reg;
- notifier_fn_t power_notifier_fn;
- const struct imx8m_blk_ctrl_domain_data *domains;
- int num_domains;
-};
-
-static inline struct imx8m_blk_ctrl_domain *
-to_imx8m_blk_ctrl_domain(struct generic_pm_domain *genpd)
-{
- return container_of(genpd, struct imx8m_blk_ctrl_domain, genpd);
-}
-
-static int imx8m_blk_ctrl_power_on(struct generic_pm_domain *genpd)
-{
- struct imx8m_blk_ctrl_domain *domain = to_imx8m_blk_ctrl_domain(genpd);
- const struct imx8m_blk_ctrl_domain_data *data = domain->data;
- struct imx8m_blk_ctrl *bc = domain->bc;
- int ret;
-
- /* make sure bus domain is awake */
- ret = pm_runtime_get_sync(bc->bus_power_dev);
- if (ret < 0) {
- pm_runtime_put_noidle(bc->bus_power_dev);
- dev_err(bc->dev, "failed to power up bus domain\n");
- return ret;
- }
-
- /* put devices into reset */
- regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask);
- if (data->mipi_phy_rst_mask)
- regmap_clear_bits(bc->regmap, BLK_MIPI_RESET_DIV, data->mipi_phy_rst_mask);
-
- /* enable upstream and blk-ctrl clocks to allow reset to propagate */
- ret = clk_bulk_prepare_enable(data->num_clks, domain->clks);
- if (ret) {
- dev_err(bc->dev, "failed to enable clocks\n");
- goto bus_put;
- }
- regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
-
- /* power up upstream GPC domain */
- ret = pm_runtime_get_sync(domain->power_dev);
- if (ret < 0) {
- dev_err(bc->dev, "failed to power up peripheral domain\n");
- goto clk_disable;
- }
-
- /* wait for reset to propagate */
- udelay(5);
-
- /* release reset */
- regmap_set_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask);
- if (data->mipi_phy_rst_mask)
- regmap_set_bits(bc->regmap, BLK_MIPI_RESET_DIV, data->mipi_phy_rst_mask);
-
- ret = icc_bulk_set_bw(domain->num_paths, domain->paths);
- if (ret)
- dev_err(bc->dev, "failed to set icc bw\n");
-
- /* disable upstream clocks */
- clk_bulk_disable_unprepare(data->num_clks, domain->clks);
-
- return 0;
-
-clk_disable:
- clk_bulk_disable_unprepare(data->num_clks, domain->clks);
-bus_put:
- pm_runtime_put(bc->bus_power_dev);
-
- return ret;
-}
-
-static int imx8m_blk_ctrl_power_off(struct generic_pm_domain *genpd)
-{
- struct imx8m_blk_ctrl_domain *domain = to_imx8m_blk_ctrl_domain(genpd);
- const struct imx8m_blk_ctrl_domain_data *data = domain->data;
- struct imx8m_blk_ctrl *bc = domain->bc;
-
- /* put devices into reset and disable clocks */
- if (data->mipi_phy_rst_mask)
- regmap_clear_bits(bc->regmap, BLK_MIPI_RESET_DIV, data->mipi_phy_rst_mask);
-
- regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask);
- regmap_clear_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
-
- /* power down upstream GPC domain */
- pm_runtime_put(domain->power_dev);
-
- /* allow bus domain to suspend */
- pm_runtime_put(bc->bus_power_dev);
-
- return 0;
-}
-
-static struct lock_class_key blk_ctrl_genpd_lock_class;
-
-static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
-{
- const struct imx8m_blk_ctrl_data *bc_data;
- struct device *dev = &pdev->dev;
- struct imx8m_blk_ctrl *bc;
- void __iomem *base;
- int i, ret;
-
- struct regmap_config regmap_config = {
- .reg_bits = 32,
- .val_bits = 32,
- .reg_stride = 4,
- };
-
- bc = devm_kzalloc(dev, sizeof(*bc), GFP_KERNEL);
- if (!bc)
- return -ENOMEM;
-
- bc->dev = dev;
-
- bc_data = of_device_get_match_data(dev);
-
- base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- regmap_config.max_register = bc_data->max_reg;
- bc->regmap = devm_regmap_init_mmio(dev, base, &regmap_config);
- if (IS_ERR(bc->regmap))
- return dev_err_probe(dev, PTR_ERR(bc->regmap),
- "failed to init regmap\n");
-
- bc->domains = devm_kcalloc(dev, bc_data->num_domains,
- sizeof(struct imx8m_blk_ctrl_domain),
- GFP_KERNEL);
- if (!bc->domains)
- return -ENOMEM;
-
- bc->onecell_data.num_domains = bc_data->num_domains;
- bc->onecell_data.domains =
- devm_kcalloc(dev, bc_data->num_domains,
- sizeof(struct generic_pm_domain *), GFP_KERNEL);
- if (!bc->onecell_data.domains)
- return -ENOMEM;
-
- bc->bus_power_dev = genpd_dev_pm_attach_by_name(dev, "bus");
- if (IS_ERR(bc->bus_power_dev)) {
- if (PTR_ERR(bc->bus_power_dev) == -ENODEV)
- return dev_err_probe(dev, -EPROBE_DEFER,
- "failed to attach power domain \"bus\"\n");
- else
- return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev),
- "failed to attach power domain \"bus\"\n");
- }
-
- for (i = 0; i < bc_data->num_domains; i++) {
- const struct imx8m_blk_ctrl_domain_data *data = &bc_data->domains[i];
- struct imx8m_blk_ctrl_domain *domain = &bc->domains[i];
- int j;
-
- domain->data = data;
- domain->num_paths = data->num_paths;
-
- for (j = 0; j < data->num_clks; j++)
- domain->clks[j].id = data->clk_names[j];
-
- for (j = 0; j < data->num_paths; j++) {
- domain->paths[j].name = data->path_names[j];
- /* Fake value for now, just let ICC could configure NoC mode/priority */
- domain->paths[j].avg_bw = 1;
- domain->paths[j].peak_bw = 1;
- }
-
- ret = devm_of_icc_bulk_get(dev, data->num_paths, domain->paths);
- if (ret) {
- if (ret != -EPROBE_DEFER) {
- dev_warn_once(dev, "Could not get interconnect paths, NoC will stay unconfigured!\n");
- domain->num_paths = 0;
- } else {
- dev_err_probe(dev, ret, "failed to get noc entries\n");
- goto cleanup_pds;
- }
- }
-
- ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
- if (ret) {
- dev_err_probe(dev, ret, "failed to get clock\n");
- goto cleanup_pds;
- }
-
- domain->power_dev =
- dev_pm_domain_attach_by_name(dev, data->gpc_name);
- if (IS_ERR(domain->power_dev)) {
- dev_err_probe(dev, PTR_ERR(domain->power_dev),
- "failed to attach power domain \"%s\"\n",
- data->gpc_name);
- ret = PTR_ERR(domain->power_dev);
- goto cleanup_pds;
- }
-
- domain->genpd.name = data->name;
- domain->genpd.power_on = imx8m_blk_ctrl_power_on;
- domain->genpd.power_off = imx8m_blk_ctrl_power_off;
- domain->bc = bc;
-
- ret = pm_genpd_init(&domain->genpd, NULL, true);
- if (ret) {
- dev_err_probe(dev, ret,
- "failed to init power domain \"%s\"\n",
- data->gpc_name);
- dev_pm_domain_detach(domain->power_dev, true);
- goto cleanup_pds;
- }
-
- /*
- * We use runtime PM to trigger power on/off of the upstream GPC
- * domain, as a strict hierarchical parent/child power domain
- * setup doesn't allow us to meet the sequencing requirements.
- * This means we have nested locking of genpd locks, without the
- * nesting being visible at the genpd level, so we need a
- * separate lock class to make lockdep aware of the fact that
- * this are separate domain locks that can be nested without a
- * self-deadlock.
- */
- lockdep_set_class(&domain->genpd.mlock,
- &blk_ctrl_genpd_lock_class);
-
- bc->onecell_data.domains[i] = &domain->genpd;
- }
-
- ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data);
- if (ret) {
- dev_err_probe(dev, ret, "failed to add power domain provider\n");
- goto cleanup_pds;
- }
-
- bc->power_nb.notifier_call = bc_data->power_notifier_fn;
- ret = dev_pm_genpd_add_notifier(bc->bus_power_dev, &bc->power_nb);
- if (ret) {
- dev_err_probe(dev, ret, "failed to add power notifier\n");
- goto cleanup_provider;
- }
-
- dev_set_drvdata(dev, bc);
-
- return 0;
-
-cleanup_provider:
- of_genpd_del_provider(dev->of_node);
-cleanup_pds:
- for (i--; i >= 0; i--) {
- pm_genpd_remove(&bc->domains[i].genpd);
- dev_pm_domain_detach(bc->domains[i].power_dev, true);
- }
-
- dev_pm_domain_detach(bc->bus_power_dev, true);
-
- return ret;
-}
-
-static int imx8m_blk_ctrl_remove(struct platform_device *pdev)
-{
- struct imx8m_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
- int i;
-
- of_genpd_del_provider(pdev->dev.of_node);
-
- for (i = 0; bc->onecell_data.num_domains; i++) {
- struct imx8m_blk_ctrl_domain *domain = &bc->domains[i];
-
- pm_genpd_remove(&domain->genpd);
- dev_pm_domain_detach(domain->power_dev, true);
- }
-
- dev_pm_genpd_remove_notifier(bc->bus_power_dev);
-
- dev_pm_domain_detach(bc->bus_power_dev, true);
-
- return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int imx8m_blk_ctrl_suspend(struct device *dev)
-{
- struct imx8m_blk_ctrl *bc = dev_get_drvdata(dev);
- int ret, i;
-
- /*
- * This may look strange, but is done so the generic PM_SLEEP code
- * can power down our domains and more importantly power them up again
- * after resume, without tripping over our usage of runtime PM to
- * control the upstream GPC domains. Things happen in the right order
- * in the system suspend/resume paths due to the device parent/child
- * hierarchy.
- */
- ret = pm_runtime_get_sync(bc->bus_power_dev);
- if (ret < 0) {
- pm_runtime_put_noidle(bc->bus_power_dev);
- return ret;
- }
-
- for (i = 0; i < bc->onecell_data.num_domains; i++) {
- struct imx8m_blk_ctrl_domain *domain = &bc->domains[i];
-
- ret = pm_runtime_get_sync(domain->power_dev);
- if (ret < 0) {
- pm_runtime_put_noidle(domain->power_dev);
- goto out_fail;
- }
- }
-
- return 0;
-
-out_fail:
- for (i--; i >= 0; i--)
- pm_runtime_put(bc->domains[i].power_dev);
-
- pm_runtime_put(bc->bus_power_dev);
-
- return ret;
-}
-
-static int imx8m_blk_ctrl_resume(struct device *dev)
-{
- struct imx8m_blk_ctrl *bc = dev_get_drvdata(dev);
- int i;
-
- for (i = 0; i < bc->onecell_data.num_domains; i++)
- pm_runtime_put(bc->domains[i].power_dev);
-
- pm_runtime_put(bc->bus_power_dev);
-
- return 0;
-}
-#endif
-
-static const struct dev_pm_ops imx8m_blk_ctrl_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(imx8m_blk_ctrl_suspend, imx8m_blk_ctrl_resume)
-};
-
-static int imx8mm_vpu_power_notifier(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl,
- power_nb);
-
- if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF)
- return NOTIFY_OK;
-
- /*
- * The ADB in the VPUMIX domain has no separate reset and clock
- * enable bits, but is ungated together with the VPU clocks. To
- * allow the handshake with the GPC to progress we put the VPUs
- * in reset and ungate the clocks.
- */
- regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, BIT(0) | BIT(1) | BIT(2));
- regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(0) | BIT(1) | BIT(2));
-
- if (action == GENPD_NOTIFY_ON) {
- /*
- * On power up we have no software backchannel to the GPC to
- * wait for the ADB handshake to happen, so we just delay for a
- * bit. On power down the GPC driver waits for the handshake.
- */
- udelay(5);
-
- /* set "fuse" bits to enable the VPUs */
- regmap_set_bits(bc->regmap, 0x8, 0xffffffff);
- regmap_set_bits(bc->regmap, 0xc, 0xffffffff);
- regmap_set_bits(bc->regmap, 0x10, 0xffffffff);
- regmap_set_bits(bc->regmap, 0x14, 0xffffffff);
- }
-
- return NOTIFY_OK;
-}
-
-static const struct imx8m_blk_ctrl_domain_data imx8mm_vpu_blk_ctl_domain_data[] = {
- [IMX8MM_VPUBLK_PD_G1] = {
- .name = "vpublk-g1",
- .clk_names = (const char *[]){ "g1", },
- .num_clks = 1,
- .gpc_name = "g1",
- .rst_mask = BIT(1),
- .clk_mask = BIT(1),
- },
- [IMX8MM_VPUBLK_PD_G2] = {
- .name = "vpublk-g2",
- .clk_names = (const char *[]){ "g2", },
- .num_clks = 1,
- .gpc_name = "g2",
- .rst_mask = BIT(0),
- .clk_mask = BIT(0),
- },
- [IMX8MM_VPUBLK_PD_H1] = {
- .name = "vpublk-h1",
- .clk_names = (const char *[]){ "h1", },
- .num_clks = 1,
- .gpc_name = "h1",
- .rst_mask = BIT(2),
- .clk_mask = BIT(2),
- },
-};
-
-static const struct imx8m_blk_ctrl_data imx8mm_vpu_blk_ctl_dev_data = {
- .max_reg = 0x18,
- .power_notifier_fn = imx8mm_vpu_power_notifier,
- .domains = imx8mm_vpu_blk_ctl_domain_data,
- .num_domains = ARRAY_SIZE(imx8mm_vpu_blk_ctl_domain_data),
-};
-
-static const struct imx8m_blk_ctrl_domain_data imx8mp_vpu_blk_ctl_domain_data[] = {
- [IMX8MP_VPUBLK_PD_G1] = {
- .name = "vpublk-g1",
- .clk_names = (const char *[]){ "g1", },
- .num_clks = 1,
- .gpc_name = "g1",
- .rst_mask = BIT(1),
- .clk_mask = BIT(1),
- .path_names = (const char *[]){"g1"},
- .num_paths = 1,
- },
- [IMX8MP_VPUBLK_PD_G2] = {
- .name = "vpublk-g2",
- .clk_names = (const char *[]){ "g2", },
- .num_clks = 1,
- .gpc_name = "g2",
- .rst_mask = BIT(0),
- .clk_mask = BIT(0),
- .path_names = (const char *[]){"g2"},
- .num_paths = 1,
- },
- [IMX8MP_VPUBLK_PD_VC8000E] = {
- .name = "vpublk-vc8000e",
- .clk_names = (const char *[]){ "vc8000e", },
- .num_clks = 1,
- .gpc_name = "vc8000e",
- .rst_mask = BIT(2),
- .clk_mask = BIT(2),
- .path_names = (const char *[]){"vc8000e"},
- .num_paths = 1,
- },
-};
-
-static const struct imx8m_blk_ctrl_data imx8mp_vpu_blk_ctl_dev_data = {
- .max_reg = 0x18,
- .power_notifier_fn = imx8mm_vpu_power_notifier,
- .domains = imx8mp_vpu_blk_ctl_domain_data,
- .num_domains = ARRAY_SIZE(imx8mp_vpu_blk_ctl_domain_data),
-};
-
-static int imx8mm_disp_power_notifier(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl,
- power_nb);
-
- if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF)
- return NOTIFY_OK;
-
- /* Enable bus clock and deassert bus reset */
- regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(12));
- regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(6));
-
- /*
- * On power up we have no software backchannel to the GPC to
- * wait for the ADB handshake to happen, so we just delay for a
- * bit. On power down the GPC driver waits for the handshake.
- */
- if (action == GENPD_NOTIFY_ON)
- udelay(5);
-
-
- return NOTIFY_OK;
-}
-
-static const struct imx8m_blk_ctrl_domain_data imx8mm_disp_blk_ctl_domain_data[] = {
- [IMX8MM_DISPBLK_PD_CSI_BRIDGE] = {
- .name = "dispblk-csi-bridge",
- .clk_names = (const char *[]){ "csi-bridge-axi", "csi-bridge-apb",
- "csi-bridge-core", },
- .num_clks = 3,
- .gpc_name = "csi-bridge",
- .rst_mask = BIT(0) | BIT(1) | BIT(2),
- .clk_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5),
- },
- [IMX8MM_DISPBLK_PD_LCDIF] = {
- .name = "dispblk-lcdif",
- .clk_names = (const char *[]){ "lcdif-axi", "lcdif-apb", "lcdif-pix", },
- .num_clks = 3,
- .gpc_name = "lcdif",
- .clk_mask = BIT(6) | BIT(7),
- },
- [IMX8MM_DISPBLK_PD_MIPI_DSI] = {
- .name = "dispblk-mipi-dsi",
- .clk_names = (const char *[]){ "dsi-pclk", "dsi-ref", },
- .num_clks = 2,
- .gpc_name = "mipi-dsi",
- .rst_mask = BIT(5),
- .clk_mask = BIT(8) | BIT(9),
- .mipi_phy_rst_mask = BIT(17),
- },
- [IMX8MM_DISPBLK_PD_MIPI_CSI] = {
- .name = "dispblk-mipi-csi",
- .clk_names = (const char *[]){ "csi-aclk", "csi-pclk" },
- .num_clks = 2,
- .gpc_name = "mipi-csi",
- .rst_mask = BIT(3) | BIT(4),
- .clk_mask = BIT(10) | BIT(11),
- .mipi_phy_rst_mask = BIT(16),
- },
-};
-
-static const struct imx8m_blk_ctrl_data imx8mm_disp_blk_ctl_dev_data = {
- .max_reg = 0x2c,
- .power_notifier_fn = imx8mm_disp_power_notifier,
- .domains = imx8mm_disp_blk_ctl_domain_data,
- .num_domains = ARRAY_SIZE(imx8mm_disp_blk_ctl_domain_data),
-};
-
-
-static int imx8mn_disp_power_notifier(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl,
- power_nb);
-
- if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF)
- return NOTIFY_OK;
-
- /* Enable bus clock and deassert bus reset */
- regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(8));
- regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(8));
-
- /*
- * On power up we have no software backchannel to the GPC to
- * wait for the ADB handshake to happen, so we just delay for a
- * bit. On power down the GPC driver waits for the handshake.
- */
- if (action == GENPD_NOTIFY_ON)
- udelay(5);
-
-
- return NOTIFY_OK;
-}
-
-static const struct imx8m_blk_ctrl_domain_data imx8mn_disp_blk_ctl_domain_data[] = {
- [IMX8MN_DISPBLK_PD_MIPI_DSI] = {
- .name = "dispblk-mipi-dsi",
- .clk_names = (const char *[]){ "dsi-pclk", "dsi-ref", },
- .num_clks = 2,
- .gpc_name = "mipi-dsi",
- .rst_mask = BIT(0) | BIT(1),
- .clk_mask = BIT(0) | BIT(1),
- .mipi_phy_rst_mask = BIT(17),
- },
- [IMX8MN_DISPBLK_PD_MIPI_CSI] = {
- .name = "dispblk-mipi-csi",
- .clk_names = (const char *[]){ "csi-aclk", "csi-pclk" },
- .num_clks = 2,
- .gpc_name = "mipi-csi",
- .rst_mask = BIT(2) | BIT(3),
- .clk_mask = BIT(2) | BIT(3),
- .mipi_phy_rst_mask = BIT(16),
- },
- [IMX8MN_DISPBLK_PD_LCDIF] = {
- .name = "dispblk-lcdif",
- .clk_names = (const char *[]){ "lcdif-axi", "lcdif-apb", "lcdif-pix", },
- .num_clks = 3,
- .gpc_name = "lcdif",
- .rst_mask = BIT(4) | BIT(5),
- .clk_mask = BIT(4) | BIT(5),
- },
- [IMX8MN_DISPBLK_PD_ISI] = {
- .name = "dispblk-isi",
- .clk_names = (const char *[]){ "disp_axi", "disp_apb", "disp_axi_root",
- "disp_apb_root"},
- .num_clks = 4,
- .gpc_name = "isi",
- .rst_mask = BIT(6) | BIT(7),
- .clk_mask = BIT(6) | BIT(7),
- },
-};
-
-static const struct imx8m_blk_ctrl_data imx8mn_disp_blk_ctl_dev_data = {
- .max_reg = 0x84,
- .power_notifier_fn = imx8mn_disp_power_notifier,
- .domains = imx8mn_disp_blk_ctl_domain_data,
- .num_domains = ARRAY_SIZE(imx8mn_disp_blk_ctl_domain_data),
-};
-
-static int imx8mp_media_power_notifier(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl,
- power_nb);
-
- if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF)
- return NOTIFY_OK;
-
- /* Enable bus clock and deassert bus reset */
- regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(8));
- regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(8));
-
- /*
- * On power up we have no software backchannel to the GPC to
- * wait for the ADB handshake to happen, so we just delay for a
- * bit. On power down the GPC driver waits for the handshake.
- */
- if (action == GENPD_NOTIFY_ON)
- udelay(5);
-
- return NOTIFY_OK;
-}
-
-/*
- * From i.MX 8M Plus Applications Processor Reference Manual, Rev. 1,
- * section 13.2.2, 13.2.3
- * isp-ahb and dwe are not in Figure 13-5. Media BLK_CTRL Clocks
- */
-static const struct imx8m_blk_ctrl_domain_data imx8mp_media_blk_ctl_domain_data[] = {
- [IMX8MP_MEDIABLK_PD_MIPI_DSI_1] = {
- .name = "mediablk-mipi-dsi-1",
- .clk_names = (const char *[]){ "apb", "phy", },
- .num_clks = 2,
- .gpc_name = "mipi-dsi1",
- .rst_mask = BIT(0) | BIT(1),
- .clk_mask = BIT(0) | BIT(1),
- .mipi_phy_rst_mask = BIT(17),
- },
- [IMX8MP_MEDIABLK_PD_MIPI_CSI2_1] = {
- .name = "mediablk-mipi-csi2-1",
- .clk_names = (const char *[]){ "apb", "cam1" },
- .num_clks = 2,
- .gpc_name = "mipi-csi1",
- .rst_mask = BIT(2) | BIT(3),
- .clk_mask = BIT(2) | BIT(3),
- .mipi_phy_rst_mask = BIT(16),
- },
- [IMX8MP_MEDIABLK_PD_LCDIF_1] = {
- .name = "mediablk-lcdif-1",
- .clk_names = (const char *[]){ "disp1", "apb", "axi", },
- .num_clks = 3,
- .gpc_name = "lcdif1",
- .rst_mask = BIT(4) | BIT(5) | BIT(23),
- .clk_mask = BIT(4) | BIT(5) | BIT(23),
- .path_names = (const char *[]){"lcdif-rd", "lcdif-wr"},
- .num_paths = 2,
- },
- [IMX8MP_MEDIABLK_PD_ISI] = {
- .name = "mediablk-isi",
- .clk_names = (const char *[]){ "axi", "apb" },
- .num_clks = 2,
- .gpc_name = "isi",
- .rst_mask = BIT(6) | BIT(7),
- .clk_mask = BIT(6) | BIT(7),
- .path_names = (const char *[]){"isi0", "isi1", "isi2"},
- .num_paths = 3,
- },
- [IMX8MP_MEDIABLK_PD_MIPI_CSI2_2] = {
- .name = "mediablk-mipi-csi2-2",
- .clk_names = (const char *[]){ "apb", "cam2" },
- .num_clks = 2,
- .gpc_name = "mipi-csi2",
- .rst_mask = BIT(9) | BIT(10),
- .clk_mask = BIT(9) | BIT(10),
- .mipi_phy_rst_mask = BIT(30),
- },
- [IMX8MP_MEDIABLK_PD_LCDIF_2] = {
- .name = "mediablk-lcdif-2",
- .clk_names = (const char *[]){ "disp2", "apb", "axi", },
- .num_clks = 3,
- .gpc_name = "lcdif2",
- .rst_mask = BIT(11) | BIT(12) | BIT(24),
- .clk_mask = BIT(11) | BIT(12) | BIT(24),
- .path_names = (const char *[]){"lcdif-rd", "lcdif-wr"},
- .num_paths = 2,
- },
- [IMX8MP_MEDIABLK_PD_ISP] = {
- .name = "mediablk-isp",
- .clk_names = (const char *[]){ "isp", "axi", "apb" },
- .num_clks = 3,
- .gpc_name = "isp",
- .rst_mask = BIT(16) | BIT(17) | BIT(18),
- .clk_mask = BIT(16) | BIT(17) | BIT(18),
- .path_names = (const char *[]){"isp0", "isp1"},
- .num_paths = 2,
- },
- [IMX8MP_MEDIABLK_PD_DWE] = {
- .name = "mediablk-dwe",
- .clk_names = (const char *[]){ "axi", "apb" },
- .num_clks = 2,
- .gpc_name = "dwe",
- .rst_mask = BIT(19) | BIT(20) | BIT(21),
- .clk_mask = BIT(19) | BIT(20) | BIT(21),
- .path_names = (const char *[]){"dwe"},
- .num_paths = 1,
- },
- [IMX8MP_MEDIABLK_PD_MIPI_DSI_2] = {
- .name = "mediablk-mipi-dsi-2",
- .clk_names = (const char *[]){ "phy", },
- .num_clks = 1,
- .gpc_name = "mipi-dsi2",
- .rst_mask = BIT(22),
- .clk_mask = BIT(22),
- .mipi_phy_rst_mask = BIT(29),
- },
-};
-
-static const struct imx8m_blk_ctrl_data imx8mp_media_blk_ctl_dev_data = {
- .max_reg = 0x138,
- .power_notifier_fn = imx8mp_media_power_notifier,
- .domains = imx8mp_media_blk_ctl_domain_data,
- .num_domains = ARRAY_SIZE(imx8mp_media_blk_ctl_domain_data),
-};
-
-static int imx8mq_vpu_power_notifier(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl,
- power_nb);
-
- if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF)
- return NOTIFY_OK;
-
- /*
- * The ADB in the VPUMIX domain has no separate reset and clock
- * enable bits, but is ungated and reset together with the VPUs. The
- * reset and clock enable inputs to the ADB is a logical OR of the
- * VPU bits. In order to set the G2 fuse bits, the G2 clock must
- * also be enabled.
- */
- regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(0) | BIT(1));
- regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(0) | BIT(1));
-
- if (action == GENPD_NOTIFY_ON) {
- /*
- * On power up we have no software backchannel to the GPC to
- * wait for the ADB handshake to happen, so we just delay for a
- * bit. On power down the GPC driver waits for the handshake.
- */
- udelay(5);
-
- /* set "fuse" bits to enable the VPUs */
- regmap_set_bits(bc->regmap, 0x8, 0xffffffff);
- regmap_set_bits(bc->regmap, 0xc, 0xffffffff);
- regmap_set_bits(bc->regmap, 0x10, 0xffffffff);
- }
-
- return NOTIFY_OK;
-}
-
-static const struct imx8m_blk_ctrl_domain_data imx8mq_vpu_blk_ctl_domain_data[] = {
- [IMX8MQ_VPUBLK_PD_G1] = {
- .name = "vpublk-g1",
- .clk_names = (const char *[]){ "g1", },
- .num_clks = 1,
- .gpc_name = "g1",
- .rst_mask = BIT(1),
- .clk_mask = BIT(1),
- },
- [IMX8MQ_VPUBLK_PD_G2] = {
- .name = "vpublk-g2",
- .clk_names = (const char *[]){ "g2", },
- .num_clks = 1,
- .gpc_name = "g2",
- .rst_mask = BIT(0),
- .clk_mask = BIT(0),
- },
-};
-
-static const struct imx8m_blk_ctrl_data imx8mq_vpu_blk_ctl_dev_data = {
- .max_reg = 0x14,
- .power_notifier_fn = imx8mq_vpu_power_notifier,
- .domains = imx8mq_vpu_blk_ctl_domain_data,
- .num_domains = ARRAY_SIZE(imx8mq_vpu_blk_ctl_domain_data),
-};
-
-static const struct of_device_id imx8m_blk_ctrl_of_match[] = {
- {
- .compatible = "fsl,imx8mm-vpu-blk-ctrl",
- .data = &imx8mm_vpu_blk_ctl_dev_data
- }, {
- .compatible = "fsl,imx8mm-disp-blk-ctrl",
- .data = &imx8mm_disp_blk_ctl_dev_data
- }, {
- .compatible = "fsl,imx8mn-disp-blk-ctrl",
- .data = &imx8mn_disp_blk_ctl_dev_data
- }, {
- .compatible = "fsl,imx8mp-media-blk-ctrl",
- .data = &imx8mp_media_blk_ctl_dev_data
- }, {
- .compatible = "fsl,imx8mq-vpu-blk-ctrl",
- .data = &imx8mq_vpu_blk_ctl_dev_data
- }, {
- .compatible = "fsl,imx8mp-vpu-blk-ctrl",
- .data = &imx8mp_vpu_blk_ctl_dev_data
- }, {
- /* Sentinel */
- }
-};
-MODULE_DEVICE_TABLE(of, imx8m_blk_ctrl_of_match);
-
-static struct platform_driver imx8m_blk_ctrl_driver = {
- .probe = imx8m_blk_ctrl_probe,
- .remove = imx8m_blk_ctrl_remove,
- .driver = {
- .name = "imx8m-blk-ctrl",
- .pm = &imx8m_blk_ctrl_pm_ops,
- .of_match_table = imx8m_blk_ctrl_of_match,
- },
-};
-module_platform_driver(imx8m_blk_ctrl_driver);
diff --git a/drivers/soc/imx/imx8mp-blk-ctrl.c b/drivers/soc/imx/imx8mp-blk-ctrl.c
deleted file mode 100644
index 0f13853901df..000000000000
--- a/drivers/soc/imx/imx8mp-blk-ctrl.c
+++ /dev/null
@@ -1,758 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-
-/*
- * Copyright 2022 Pengutronix, Lucas Stach <kernel@pengutronix.de>
- */
-
-#include <linux/clk.h>
-#include <linux/device.h>
-#include <linux/interconnect.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <linux/pm_runtime.h>
-#include <linux/regmap.h>
-
-#include <dt-bindings/power/imx8mp-power.h>
-
-#define GPR_REG0 0x0
-#define PCIE_CLOCK_MODULE_EN BIT(0)
-#define USB_CLOCK_MODULE_EN BIT(1)
-#define PCIE_PHY_APB_RST BIT(4)
-#define PCIE_PHY_INIT_RST BIT(5)
-
-struct imx8mp_blk_ctrl_domain;
-
-struct imx8mp_blk_ctrl {
- struct device *dev;
- struct notifier_block power_nb;
- struct device *bus_power_dev;
- struct regmap *regmap;
- struct imx8mp_blk_ctrl_domain *domains;
- struct genpd_onecell_data onecell_data;
- void (*power_off) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
- void (*power_on) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
-};
-
-struct imx8mp_blk_ctrl_domain_data {
- const char *name;
- const char * const *clk_names;
- int num_clks;
- const char * const *path_names;
- int num_paths;
- const char *gpc_name;
-};
-
-#define DOMAIN_MAX_CLKS 2
-#define DOMAIN_MAX_PATHS 3
-
-struct imx8mp_blk_ctrl_domain {
- struct generic_pm_domain genpd;
- const struct imx8mp_blk_ctrl_domain_data *data;
- struct clk_bulk_data clks[DOMAIN_MAX_CLKS];
- struct icc_bulk_data paths[DOMAIN_MAX_PATHS];
- struct device *power_dev;
- struct imx8mp_blk_ctrl *bc;
- int num_paths;
- int id;
-};
-
-struct imx8mp_blk_ctrl_data {
- int max_reg;
- notifier_fn_t power_notifier_fn;
- void (*power_off) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
- void (*power_on) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
- const struct imx8mp_blk_ctrl_domain_data *domains;
- int num_domains;
-};
-
-static inline struct imx8mp_blk_ctrl_domain *
-to_imx8mp_blk_ctrl_domain(struct generic_pm_domain *genpd)
-{
- return container_of(genpd, struct imx8mp_blk_ctrl_domain, genpd);
-}
-
-static void imx8mp_hsio_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
- struct imx8mp_blk_ctrl_domain *domain)
-{
- switch (domain->id) {
- case IMX8MP_HSIOBLK_PD_USB:
- regmap_set_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN);
- break;
- case IMX8MP_HSIOBLK_PD_PCIE:
- regmap_set_bits(bc->regmap, GPR_REG0, PCIE_CLOCK_MODULE_EN);
- break;
- case IMX8MP_HSIOBLK_PD_PCIE_PHY:
- regmap_set_bits(bc->regmap, GPR_REG0,
- PCIE_PHY_APB_RST | PCIE_PHY_INIT_RST);
- break;
- default:
- break;
- }
-}
-
-static void imx8mp_hsio_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc,
- struct imx8mp_blk_ctrl_domain *domain)
-{
- switch (domain->id) {
- case IMX8MP_HSIOBLK_PD_USB:
- regmap_clear_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN);
- break;
- case IMX8MP_HSIOBLK_PD_PCIE:
- regmap_clear_bits(bc->regmap, GPR_REG0, PCIE_CLOCK_MODULE_EN);
- break;
- case IMX8MP_HSIOBLK_PD_PCIE_PHY:
- regmap_clear_bits(bc->regmap, GPR_REG0,
- PCIE_PHY_APB_RST | PCIE_PHY_INIT_RST);
- break;
- default:
- break;
- }
-}
-
-static int imx8mp_hsio_power_notifier(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct imx8mp_blk_ctrl *bc = container_of(nb, struct imx8mp_blk_ctrl,
- power_nb);
- struct clk_bulk_data *usb_clk = bc->domains[IMX8MP_HSIOBLK_PD_USB].clks;
- int num_clks = bc->domains[IMX8MP_HSIOBLK_PD_USB].data->num_clks;
- int ret;
-
- switch (action) {
- case GENPD_NOTIFY_ON:
- /*
- * enable USB clock for a moment for the power-on ADB handshake
- * to proceed
- */
- ret = clk_bulk_prepare_enable(num_clks, usb_clk);
- if (ret)
- return NOTIFY_BAD;
- regmap_set_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN);
-
- udelay(5);
-
- regmap_clear_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN);
- clk_bulk_disable_unprepare(num_clks, usb_clk);
- break;
- case GENPD_NOTIFY_PRE_OFF:
- /* enable USB clock for the power-down ADB handshake to work */
- ret = clk_bulk_prepare_enable(num_clks, usb_clk);
- if (ret)
- return NOTIFY_BAD;
-
- regmap_set_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN);
- break;
- case GENPD_NOTIFY_OFF:
- clk_bulk_disable_unprepare(num_clks, usb_clk);
- break;
- default:
- break;
- }
-
- return NOTIFY_OK;
-}
-
-static const struct imx8mp_blk_ctrl_domain_data imx8mp_hsio_domain_data[] = {
- [IMX8MP_HSIOBLK_PD_USB] = {
- .name = "hsioblk-usb",
- .clk_names = (const char *[]){ "usb" },
- .num_clks = 1,
- .gpc_name = "usb",
- .path_names = (const char *[]){"usb1", "usb2"},
- .num_paths = 2,
- },
- [IMX8MP_HSIOBLK_PD_USB_PHY1] = {
- .name = "hsioblk-usb-phy1",
- .gpc_name = "usb-phy1",
- },
- [IMX8MP_HSIOBLK_PD_USB_PHY2] = {
- .name = "hsioblk-usb-phy2",
- .gpc_name = "usb-phy2",
- },
- [IMX8MP_HSIOBLK_PD_PCIE] = {
- .name = "hsioblk-pcie",
- .clk_names = (const char *[]){ "pcie" },
- .num_clks = 1,
- .gpc_name = "pcie",
- .path_names = (const char *[]){"noc-pcie", "pcie"},
- .num_paths = 2,
- },
- [IMX8MP_HSIOBLK_PD_PCIE_PHY] = {
- .name = "hsioblk-pcie-phy",
- .gpc_name = "pcie-phy",
- },
-};
-
-static const struct imx8mp_blk_ctrl_data imx8mp_hsio_blk_ctl_dev_data = {
- .max_reg = 0x24,
- .power_on = imx8mp_hsio_blk_ctrl_power_on,
- .power_off = imx8mp_hsio_blk_ctrl_power_off,
- .power_notifier_fn = imx8mp_hsio_power_notifier,
- .domains = imx8mp_hsio_domain_data,
- .num_domains = ARRAY_SIZE(imx8mp_hsio_domain_data),
-};
-
-#define HDMI_RTX_RESET_CTL0 0x20
-#define HDMI_RTX_CLK_CTL0 0x40
-#define HDMI_RTX_CLK_CTL1 0x50
-#define HDMI_RTX_CLK_CTL2 0x60
-#define HDMI_RTX_CLK_CTL3 0x70
-#define HDMI_RTX_CLK_CTL4 0x80
-#define HDMI_TX_CONTROL0 0x200
-
-static void imx8mp_hdmi_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
- struct imx8mp_blk_ctrl_domain *domain)
-{
- switch (domain->id) {
- case IMX8MP_HDMIBLK_PD_IRQSTEER:
- regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(9));
- regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(16));
- break;
- case IMX8MP_HDMIBLK_PD_LCDIF:
- regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
- BIT(16) | BIT(17) | BIT(18) |
- BIT(19) | BIT(20));
- regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(11));
- regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
- BIT(4) | BIT(5) | BIT(6));
- break;
- case IMX8MP_HDMIBLK_PD_PAI:
- regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(17));
- regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(18));
- break;
- case IMX8MP_HDMIBLK_PD_PVI:
- regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(28));
- regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(22));
- break;
- case IMX8MP_HDMIBLK_PD_TRNG:
- regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(27) | BIT(30));
- regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(20));
- break;
- case IMX8MP_HDMIBLK_PD_HDMI_TX:
- regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
- BIT(2) | BIT(4) | BIT(5));
- regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1,
- BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) |
- BIT(18) | BIT(19) | BIT(20) | BIT(21));
- regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
- BIT(7) | BIT(10) | BIT(11));
- regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(1));
- break;
- case IMX8MP_HDMIBLK_PD_HDMI_TX_PHY:
- regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(7));
- regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24));
- regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12));
- regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3));
- break;
- case IMX8MP_HDMIBLK_PD_HDCP:
- regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(11));
- break;
- case IMX8MP_HDMIBLK_PD_HRV:
- regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(3) | BIT(4) | BIT(5));
- regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(15));
- break;
- default:
- break;
- }
-}
-
-static void imx8mp_hdmi_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc,
- struct imx8mp_blk_ctrl_domain *domain)
-{
- switch (domain->id) {
- case IMX8MP_HDMIBLK_PD_IRQSTEER:
- regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(9));
- regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(16));
- break;
- case IMX8MP_HDMIBLK_PD_LCDIF:
- regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
- BIT(4) | BIT(5) | BIT(6));
- regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(11));
- regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
- BIT(16) | BIT(17) | BIT(18) |
- BIT(19) | BIT(20));
- break;
- case IMX8MP_HDMIBLK_PD_PAI:
- regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(18));
- regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(17));
- break;
- case IMX8MP_HDMIBLK_PD_PVI:
- regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(22));
- regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(28));
- break;
- case IMX8MP_HDMIBLK_PD_TRNG:
- regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(20));
- regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(27) | BIT(30));
- break;
- case IMX8MP_HDMIBLK_PD_HDMI_TX:
- regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(1));
- regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
- BIT(7) | BIT(10) | BIT(11));
- regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1,
- BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) |
- BIT(18) | BIT(19) | BIT(20) | BIT(21));
- regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
- BIT(2) | BIT(4) | BIT(5));
- break;
- case IMX8MP_HDMIBLK_PD_HDMI_TX_PHY:
- regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3));
- regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12));
- regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(7));
- regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24));
- break;
- case IMX8MP_HDMIBLK_PD_HDCP:
- regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(11));
- break;
- case IMX8MP_HDMIBLK_PD_HRV:
- regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(15));
- regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(3) | BIT(4) | BIT(5));
- break;
- default:
- break;
- }
-}
-
-static int imx8mp_hdmi_power_notifier(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct imx8mp_blk_ctrl *bc = container_of(nb, struct imx8mp_blk_ctrl,
- power_nb);
-
- if (action != GENPD_NOTIFY_ON)
- return NOTIFY_OK;
-
- /*
- * Contrary to other blk-ctrls the reset and clock don't clear when the
- * power domain is powered down. To ensure the proper reset pulsing,
- * first clear them all to asserted state, then enable the bus clocks
- * and then release the ADB reset.
- */
- regmap_write(bc->regmap, HDMI_RTX_RESET_CTL0, 0x0);
- regmap_write(bc->regmap, HDMI_RTX_CLK_CTL0, 0x0);
- regmap_write(bc->regmap, HDMI_RTX_CLK_CTL1, 0x0);
- regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
- BIT(0) | BIT(1) | BIT(10));
- regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(0));
-
- /*
- * On power up we have no software backchannel to the GPC to
- * wait for the ADB handshake to happen, so we just delay for a
- * bit. On power down the GPC driver waits for the handshake.
- */
- udelay(5);
-
- return NOTIFY_OK;
-}
-
-static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = {
- [IMX8MP_HDMIBLK_PD_IRQSTEER] = {
- .name = "hdmiblk-irqsteer",
- .clk_names = (const char *[]){ "apb" },
- .num_clks = 1,
- .gpc_name = "irqsteer",
- },
- [IMX8MP_HDMIBLK_PD_LCDIF] = {
- .name = "hdmiblk-lcdif",
- .clk_names = (const char *[]){ "axi", "apb" },
- .num_clks = 2,
- .gpc_name = "lcdif",
- .path_names = (const char *[]){"lcdif-hdmi"},
- .num_paths = 1,
- },
- [IMX8MP_HDMIBLK_PD_PAI] = {
- .name = "hdmiblk-pai",
- .clk_names = (const char *[]){ "apb" },
- .num_clks = 1,
- .gpc_name = "pai",
- },
- [IMX8MP_HDMIBLK_PD_PVI] = {
- .name = "hdmiblk-pvi",
- .clk_names = (const char *[]){ "apb" },
- .num_clks = 1,
- .gpc_name = "pvi",
- },
- [IMX8MP_HDMIBLK_PD_TRNG] = {
- .name = "hdmiblk-trng",
- .clk_names = (const char *[]){ "apb" },
- .num_clks = 1,
- .gpc_name = "trng",
- },
- [IMX8MP_HDMIBLK_PD_HDMI_TX] = {
- .name = "hdmiblk-hdmi-tx",
- .clk_names = (const char *[]){ "apb", "ref_266m" },
- .num_clks = 2,
- .gpc_name = "hdmi-tx",
- },
- [IMX8MP_HDMIBLK_PD_HDMI_TX_PHY] = {
- .name = "hdmiblk-hdmi-tx-phy",
- .clk_names = (const char *[]){ "apb", "ref_24m" },
- .num_clks = 2,
- .gpc_name = "hdmi-tx-phy",
- },
- [IMX8MP_HDMIBLK_PD_HRV] = {
- .name = "hdmiblk-hrv",
- .clk_names = (const char *[]){ "axi", "apb" },
- .num_clks = 2,
- .gpc_name = "hrv",
- .path_names = (const char *[]){"hrv"},
- .num_paths = 1,
- },
- [IMX8MP_HDMIBLK_PD_HDCP] = {
- .name = "hdmiblk-hdcp",
- .clk_names = (const char *[]){ "axi", "apb" },
- .num_clks = 2,
- .gpc_name = "hdcp",
- .path_names = (const char *[]){"hdcp"},
- .num_paths = 1,
- },
-};
-
-static const struct imx8mp_blk_ctrl_data imx8mp_hdmi_blk_ctl_dev_data = {
- .max_reg = 0x23c,
- .power_on = imx8mp_hdmi_blk_ctrl_power_on,
- .power_off = imx8mp_hdmi_blk_ctrl_power_off,
- .power_notifier_fn = imx8mp_hdmi_power_notifier,
- .domains = imx8mp_hdmi_domain_data,
- .num_domains = ARRAY_SIZE(imx8mp_hdmi_domain_data),
-};
-
-static int imx8mp_blk_ctrl_power_on(struct generic_pm_domain *genpd)
-{
- struct imx8mp_blk_ctrl_domain *domain = to_imx8mp_blk_ctrl_domain(genpd);
- const struct imx8mp_blk_ctrl_domain_data *data = domain->data;
- struct imx8mp_blk_ctrl *bc = domain->bc;
- int ret;
-
- /* make sure bus domain is awake */
- ret = pm_runtime_resume_and_get(bc->bus_power_dev);
- if (ret < 0) {
- dev_err(bc->dev, "failed to power up bus domain\n");
- return ret;
- }
-
- /* enable upstream clocks */
- ret = clk_bulk_prepare_enable(data->num_clks, domain->clks);
- if (ret) {
- dev_err(bc->dev, "failed to enable clocks\n");
- goto bus_put;
- }
-
- /* domain specific blk-ctrl manipulation */
- bc->power_on(bc, domain);
-
- /* power up upstream GPC domain */
- ret = pm_runtime_resume_and_get(domain->power_dev);
- if (ret < 0) {
- dev_err(bc->dev, "failed to power up peripheral domain\n");
- goto clk_disable;
- }
-
- ret = icc_bulk_set_bw(domain->num_paths, domain->paths);
- if (ret)
- dev_err(bc->dev, "failed to set icc bw\n");
-
- clk_bulk_disable_unprepare(data->num_clks, domain->clks);
-
- return 0;
-
-clk_disable:
- clk_bulk_disable_unprepare(data->num_clks, domain->clks);
-bus_put:
- pm_runtime_put(bc->bus_power_dev);
-
- return ret;
-}
-
-static int imx8mp_blk_ctrl_power_off(struct generic_pm_domain *genpd)
-{
- struct imx8mp_blk_ctrl_domain *domain = to_imx8mp_blk_ctrl_domain(genpd);
- const struct imx8mp_blk_ctrl_domain_data *data = domain->data;
- struct imx8mp_blk_ctrl *bc = domain->bc;
- int ret;
-
- ret = clk_bulk_prepare_enable(data->num_clks, domain->clks);
- if (ret) {
- dev_err(bc->dev, "failed to enable clocks\n");
- return ret;
- }
-
- /* domain specific blk-ctrl manipulation */
- bc->power_off(bc, domain);
-
- clk_bulk_disable_unprepare(data->num_clks, domain->clks);
-
- /* power down upstream GPC domain */
- pm_runtime_put(domain->power_dev);
-
- /* allow bus domain to suspend */
- pm_runtime_put(bc->bus_power_dev);
-
- return 0;
-}
-
-static struct lock_class_key blk_ctrl_genpd_lock_class;
-
-static int imx8mp_blk_ctrl_probe(struct platform_device *pdev)
-{
- const struct imx8mp_blk_ctrl_data *bc_data;
- struct device *dev = &pdev->dev;
- struct imx8mp_blk_ctrl *bc;
- void __iomem *base;
- int num_domains, i, ret;
-
- struct regmap_config regmap_config = {
- .reg_bits = 32,
- .val_bits = 32,
- .reg_stride = 4,
- };
-
- bc = devm_kzalloc(dev, sizeof(*bc), GFP_KERNEL);
- if (!bc)
- return -ENOMEM;
-
- bc->dev = dev;
-
- bc_data = of_device_get_match_data(dev);
- num_domains = bc_data->num_domains;
-
- base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- regmap_config.max_register = bc_data->max_reg;
- bc->regmap = devm_regmap_init_mmio(dev, base, &regmap_config);
- if (IS_ERR(bc->regmap))
- return dev_err_probe(dev, PTR_ERR(bc->regmap),
- "failed to init regmap\n");
-
- bc->domains = devm_kcalloc(dev, num_domains,
- sizeof(struct imx8mp_blk_ctrl_domain),
- GFP_KERNEL);
- if (!bc->domains)
- return -ENOMEM;
-
- bc->onecell_data.num_domains = num_domains;
- bc->onecell_data.domains =
- devm_kcalloc(dev, num_domains,
- sizeof(struct generic_pm_domain *), GFP_KERNEL);
- if (!bc->onecell_data.domains)
- return -ENOMEM;
-
- bc->bus_power_dev = genpd_dev_pm_attach_by_name(dev, "bus");
- if (IS_ERR(bc->bus_power_dev))
- return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev),
- "failed to attach bus power domain\n");
-
- bc->power_off = bc_data->power_off;
- bc->power_on = bc_data->power_on;
-
- for (i = 0; i < num_domains; i++) {
- const struct imx8mp_blk_ctrl_domain_data *data = &bc_data->domains[i];
- struct imx8mp_blk_ctrl_domain *domain = &bc->domains[i];
- int j;
-
- domain->data = data;
- domain->num_paths = data->num_paths;
-
- for (j = 0; j < data->num_clks; j++)
- domain->clks[j].id = data->clk_names[j];
-
- for (j = 0; j < data->num_paths; j++) {
- domain->paths[j].name = data->path_names[j];
- /* Fake value for now, just let ICC could configure NoC mode/priority */
- domain->paths[j].avg_bw = 1;
- domain->paths[j].peak_bw = 1;
- }
-
- ret = devm_of_icc_bulk_get(dev, data->num_paths, domain->paths);
- if (ret) {
- if (ret != -EPROBE_DEFER) {
- dev_warn_once(dev, "Could not get interconnect paths, NoC will stay unconfigured!\n");
- domain->num_paths = 0;
- } else {
- dev_err_probe(dev, ret, "failed to get noc entries\n");
- goto cleanup_pds;
- }
- }
-
- ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
- if (ret) {
- dev_err_probe(dev, ret, "failed to get clock\n");
- goto cleanup_pds;
- }
-
- domain->power_dev =
- dev_pm_domain_attach_by_name(dev, data->gpc_name);
- if (IS_ERR(domain->power_dev)) {
- dev_err_probe(dev, PTR_ERR(domain->power_dev),
- "failed to attach power domain %s\n",
- data->gpc_name);
- ret = PTR_ERR(domain->power_dev);
- goto cleanup_pds;
- }
-
- domain->genpd.name = data->name;
- domain->genpd.power_on = imx8mp_blk_ctrl_power_on;
- domain->genpd.power_off = imx8mp_blk_ctrl_power_off;
- domain->bc = bc;
- domain->id = i;
-
- ret = pm_genpd_init(&domain->genpd, NULL, true);
- if (ret) {
- dev_err_probe(dev, ret, "failed to init power domain\n");
- dev_pm_domain_detach(domain->power_dev, true);
- goto cleanup_pds;
- }
-
- /*
- * We use runtime PM to trigger power on/off of the upstream GPC
- * domain, as a strict hierarchical parent/child power domain
- * setup doesn't allow us to meet the sequencing requirements.
- * This means we have nested locking of genpd locks, without the
- * nesting being visible at the genpd level, so we need a
- * separate lock class to make lockdep aware of the fact that
- * this are separate domain locks that can be nested without a
- * self-deadlock.
- */
- lockdep_set_class(&domain->genpd.mlock,
- &blk_ctrl_genpd_lock_class);
-
- bc->onecell_data.domains[i] = &domain->genpd;
- }
-
- ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data);
- if (ret) {
- dev_err_probe(dev, ret, "failed to add power domain provider\n");
- goto cleanup_pds;
- }
-
- bc->power_nb.notifier_call = bc_data->power_notifier_fn;
- ret = dev_pm_genpd_add_notifier(bc->bus_power_dev, &bc->power_nb);
- if (ret) {
- dev_err_probe(dev, ret, "failed to add power notifier\n");
- goto cleanup_provider;
- }
-
- dev_set_drvdata(dev, bc);
-
- return 0;
-
-cleanup_provider:
- of_genpd_del_provider(dev->of_node);
-cleanup_pds:
- for (i--; i >= 0; i--) {
- pm_genpd_remove(&bc->domains[i].genpd);
- dev_pm_domain_detach(bc->domains[i].power_dev, true);
- }
-
- dev_pm_domain_detach(bc->bus_power_dev, true);
-
- return ret;
-}
-
-static int imx8mp_blk_ctrl_remove(struct platform_device *pdev)
-{
- struct imx8mp_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
- int i;
-
- of_genpd_del_provider(pdev->dev.of_node);
-
- for (i = 0; bc->onecell_data.num_domains; i++) {
- struct imx8mp_blk_ctrl_domain *domain = &bc->domains[i];
-
- pm_genpd_remove(&domain->genpd);
- dev_pm_domain_detach(domain->power_dev, true);
- }
-
- dev_pm_genpd_remove_notifier(bc->bus_power_dev);
-
- dev_pm_domain_detach(bc->bus_power_dev, true);
-
- return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int imx8mp_blk_ctrl_suspend(struct device *dev)
-{
- struct imx8mp_blk_ctrl *bc = dev_get_drvdata(dev);
- int ret, i;
-
- /*
- * This may look strange, but is done so the generic PM_SLEEP code
- * can power down our domains and more importantly power them up again
- * after resume, without tripping over our usage of runtime PM to
- * control the upstream GPC domains. Things happen in the right order
- * in the system suspend/resume paths due to the device parent/child
- * hierarchy.
- */
- ret = pm_runtime_get_sync(bc->bus_power_dev);
- if (ret < 0) {
- pm_runtime_put_noidle(bc->bus_power_dev);
- return ret;
- }
-
- for (i = 0; i < bc->onecell_data.num_domains; i++) {
- struct imx8mp_blk_ctrl_domain *domain = &bc->domains[i];
-
- ret = pm_runtime_get_sync(domain->power_dev);
- if (ret < 0) {
- pm_runtime_put_noidle(domain->power_dev);
- goto out_fail;
- }
- }
-
- return 0;
-
-out_fail:
- for (i--; i >= 0; i--)
- pm_runtime_put(bc->domains[i].power_dev);
-
- pm_runtime_put(bc->bus_power_dev);
-
- return ret;
-}
-
-static int imx8mp_blk_ctrl_resume(struct device *dev)
-{
- struct imx8mp_blk_ctrl *bc = dev_get_drvdata(dev);
- int i;
-
- for (i = 0; i < bc->onecell_data.num_domains; i++)
- pm_runtime_put(bc->domains[i].power_dev);
-
- pm_runtime_put(bc->bus_power_dev);
-
- return 0;
-}
-#endif
-
-static const struct dev_pm_ops imx8mp_blk_ctrl_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(imx8mp_blk_ctrl_suspend,
- imx8mp_blk_ctrl_resume)
-};
-
-static const struct of_device_id imx8mp_blk_ctrl_of_match[] = {
- {
- .compatible = "fsl,imx8mp-hsio-blk-ctrl",
- .data = &imx8mp_hsio_blk_ctl_dev_data,
- }, {
- .compatible = "fsl,imx8mp-hdmi-blk-ctrl",
- .data = &imx8mp_hdmi_blk_ctl_dev_data,
- }, {
- /* Sentinel */
- }
-};
-MODULE_DEVICE_TABLE(of, imx8m_blk_ctrl_of_match);
-
-static struct platform_driver imx8mp_blk_ctrl_driver = {
- .probe = imx8mp_blk_ctrl_probe,
- .remove = imx8mp_blk_ctrl_remove,
- .driver = {
- .name = "imx8mp-blk-ctrl",
- .pm = &imx8mp_blk_ctrl_pm_ops,
- .of_match_table = imx8mp_blk_ctrl_of_match,
- },
-};
-module_platform_driver(imx8mp_blk_ctrl_driver);
diff --git a/drivers/soc/imx/imx93-blk-ctrl.c b/drivers/soc/imx/imx93-blk-ctrl.c
deleted file mode 100644
index 2c600329436c..000000000000
--- a/drivers/soc/imx/imx93-blk-ctrl.c
+++ /dev/null
@@ -1,436 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright 2022 NXP, Peng Fan <peng.fan@nxp.com>
- */
-
-#include <linux/clk.h>
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <linux/pm_runtime.h>
-#include <linux/regmap.h>
-#include <linux/sizes.h>
-
-#include <dt-bindings/power/fsl,imx93-power.h>
-
-#define BLK_SFT_RSTN 0x0
-#define BLK_CLK_EN 0x4
-#define BLK_MAX_CLKS 4
-
-#define DOMAIN_MAX_CLKS 4
-
-#define LCDIF_QOS_REG 0xC
-#define LCDIF_DEFAULT_QOS_OFF 12
-#define LCDIF_CFG_QOS_OFF 8
-
-#define PXP_QOS_REG 0x10
-#define PXP_R_DEFAULT_QOS_OFF 28
-#define PXP_R_CFG_QOS_OFF 24
-#define PXP_W_DEFAULT_QOS_OFF 20
-#define PXP_W_CFG_QOS_OFF 16
-
-#define ISI_CACHE_REG 0x14
-
-#define ISI_QOS_REG 0x1C
-#define ISI_V_DEFAULT_QOS_OFF 28
-#define ISI_V_CFG_QOS_OFF 24
-#define ISI_U_DEFAULT_QOS_OFF 20
-#define ISI_U_CFG_QOS_OFF 16
-#define ISI_Y_R_DEFAULT_QOS_OFF 12
-#define ISI_Y_R_CFG_QOS_OFF 8
-#define ISI_Y_W_DEFAULT_QOS_OFF 4
-#define ISI_Y_W_CFG_QOS_OFF 0
-
-#define PRIO_MASK 0xF
-
-#define PRIO(X) (X)
-
-struct imx93_blk_ctrl_domain;
-
-struct imx93_blk_ctrl {
- struct device *dev;
- struct regmap *regmap;
- int num_clks;
- struct clk_bulk_data clks[BLK_MAX_CLKS];
- struct imx93_blk_ctrl_domain *domains;
- struct genpd_onecell_data onecell_data;
-};
-
-#define DOMAIN_MAX_QOS 4
-
-struct imx93_blk_ctrl_qos {
- u32 reg;
- u32 cfg_off;
- u32 default_prio;
- u32 cfg_prio;
-};
-
-struct imx93_blk_ctrl_domain_data {
- const char *name;
- const char * const *clk_names;
- int num_clks;
- u32 rst_mask;
- u32 clk_mask;
- int num_qos;
- struct imx93_blk_ctrl_qos qos[DOMAIN_MAX_QOS];
-};
-
-struct imx93_blk_ctrl_domain {
- struct generic_pm_domain genpd;
- const struct imx93_blk_ctrl_domain_data *data;
- struct clk_bulk_data clks[DOMAIN_MAX_CLKS];
- struct imx93_blk_ctrl *bc;
-};
-
-struct imx93_blk_ctrl_data {
- const struct imx93_blk_ctrl_domain_data *domains;
- int num_domains;
- const char * const *clk_names;
- int num_clks;
- const struct regmap_access_table *reg_access_table;
-};
-
-static inline struct imx93_blk_ctrl_domain *
-to_imx93_blk_ctrl_domain(struct generic_pm_domain *genpd)
-{
- return container_of(genpd, struct imx93_blk_ctrl_domain, genpd);
-}
-
-static int imx93_blk_ctrl_set_qos(struct imx93_blk_ctrl_domain *domain)
-{
- const struct imx93_blk_ctrl_domain_data *data = domain->data;
- struct imx93_blk_ctrl *bc = domain->bc;
- const struct imx93_blk_ctrl_qos *qos;
- u32 val, mask;
- int i;
-
- for (i = 0; i < data->num_qos; i++) {
- qos = &data->qos[i];
-
- mask = PRIO_MASK << qos->cfg_off;
- mask |= PRIO_MASK << (qos->cfg_off + 4);
- val = qos->cfg_prio << qos->cfg_off;
- val |= qos->default_prio << (qos->cfg_off + 4);
-
- regmap_write_bits(bc->regmap, qos->reg, mask, val);
-
- dev_dbg(bc->dev, "data->qos[i].reg 0x%x 0x%x\n", qos->reg, val);
- }
-
- return 0;
-}
-
-static int imx93_blk_ctrl_power_on(struct generic_pm_domain *genpd)
-{
- struct imx93_blk_ctrl_domain *domain = to_imx93_blk_ctrl_domain(genpd);
- const struct imx93_blk_ctrl_domain_data *data = domain->data;
- struct imx93_blk_ctrl *bc = domain->bc;
- int ret;
-
- ret = clk_bulk_prepare_enable(bc->num_clks, bc->clks);
- if (ret) {
- dev_err(bc->dev, "failed to enable bus clocks\n");
- return ret;
- }
-
- ret = clk_bulk_prepare_enable(data->num_clks, domain->clks);
- if (ret) {
- clk_bulk_disable_unprepare(bc->num_clks, bc->clks);
- dev_err(bc->dev, "failed to enable clocks\n");
- return ret;
- }
-
- ret = pm_runtime_get_sync(bc->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(bc->dev);
- dev_err(bc->dev, "failed to power up domain\n");
- goto disable_clk;
- }
-
- /* ungate clk */
- regmap_clear_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
-
- /* release reset */
- regmap_set_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask);
-
- dev_dbg(bc->dev, "pd_on: name: %s\n", genpd->name);
-
- return imx93_blk_ctrl_set_qos(domain);
-
-disable_clk:
- clk_bulk_disable_unprepare(data->num_clks, domain->clks);
-
- clk_bulk_disable_unprepare(bc->num_clks, bc->clks);
-
- return ret;
-}
-
-static int imx93_blk_ctrl_power_off(struct generic_pm_domain *genpd)
-{
- struct imx93_blk_ctrl_domain *domain = to_imx93_blk_ctrl_domain(genpd);
- const struct imx93_blk_ctrl_domain_data *data = domain->data;
- struct imx93_blk_ctrl *bc = domain->bc;
-
- dev_dbg(bc->dev, "pd_off: name: %s\n", genpd->name);
-
- regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask);
- regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
-
- pm_runtime_put(bc->dev);
-
- clk_bulk_disable_unprepare(data->num_clks, domain->clks);
-
- clk_bulk_disable_unprepare(bc->num_clks, bc->clks);
-
- return 0;
-}
-
-static int imx93_blk_ctrl_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- const struct imx93_blk_ctrl_data *bc_data = of_device_get_match_data(dev);
- struct imx93_blk_ctrl *bc;
- void __iomem *base;
- int i, ret;
-
- struct regmap_config regmap_config = {
- .reg_bits = 32,
- .val_bits = 32,
- .reg_stride = 4,
- .rd_table = bc_data->reg_access_table,
- .wr_table = bc_data->reg_access_table,
- .max_register = SZ_4K,
- };
-
- bc = devm_kzalloc(dev, sizeof(*bc), GFP_KERNEL);
- if (!bc)
- return -ENOMEM;
-
- bc->dev = dev;
-
- base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- bc->regmap = devm_regmap_init_mmio(dev, base, &regmap_config);
- if (IS_ERR(bc->regmap))
- return dev_err_probe(dev, PTR_ERR(bc->regmap),
- "failed to init regmap\n");
-
- bc->domains = devm_kcalloc(dev, bc_data->num_domains,
- sizeof(struct imx93_blk_ctrl_domain),
- GFP_KERNEL);
- if (!bc->domains)
- return -ENOMEM;
-
- bc->onecell_data.num_domains = bc_data->num_domains;
- bc->onecell_data.domains =
- devm_kcalloc(dev, bc_data->num_domains,
- sizeof(struct generic_pm_domain *), GFP_KERNEL);
- if (!bc->onecell_data.domains)
- return -ENOMEM;
-
- for (i = 0; i < bc_data->num_clks; i++)
- bc->clks[i].id = bc_data->clk_names[i];
- bc->num_clks = bc_data->num_clks;
-
- ret = devm_clk_bulk_get(dev, bc->num_clks, bc->clks);
- if (ret) {
- dev_err_probe(dev, ret, "failed to get bus clock\n");
- return ret;
- }
-
- for (i = 0; i < bc_data->num_domains; i++) {
- const struct imx93_blk_ctrl_domain_data *data = &bc_data->domains[i];
- struct imx93_blk_ctrl_domain *domain = &bc->domains[i];
- int j;
-
- domain->data = data;
-
- for (j = 0; j < data->num_clks; j++)
- domain->clks[j].id = data->clk_names[j];
-
- ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
- if (ret) {
- dev_err_probe(dev, ret, "failed to get clock\n");
- goto cleanup_pds;
- }
-
- domain->genpd.name = data->name;
- domain->genpd.power_on = imx93_blk_ctrl_power_on;
- domain->genpd.power_off = imx93_blk_ctrl_power_off;
- domain->bc = bc;
-
- ret = pm_genpd_init(&domain->genpd, NULL, true);
- if (ret) {
- dev_err_probe(dev, ret, "failed to init power domain\n");
- goto cleanup_pds;
- }
-
- bc->onecell_data.domains[i] = &domain->genpd;
- }
-
- pm_runtime_enable(dev);
-
- ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data);
- if (ret) {
- dev_err_probe(dev, ret, "failed to add power domain provider\n");
- goto cleanup_pds;
- }
-
- dev_set_drvdata(dev, bc);
-
- return 0;
-
-cleanup_pds:
- for (i--; i >= 0; i--)
- pm_genpd_remove(&bc->domains[i].genpd);
-
- return ret;
-}
-
-static int imx93_blk_ctrl_remove(struct platform_device *pdev)
-{
- struct imx93_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
- int i;
-
- of_genpd_del_provider(pdev->dev.of_node);
-
- for (i = 0; bc->onecell_data.num_domains; i++) {
- struct imx93_blk_ctrl_domain *domain = &bc->domains[i];
-
- pm_genpd_remove(&domain->genpd);
- }
-
- return 0;
-}
-
-static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] = {
- [IMX93_MEDIABLK_PD_MIPI_DSI] = {
- .name = "mediablk-mipi-dsi",
- .clk_names = (const char *[]){ "dsi" },
- .num_clks = 1,
- .rst_mask = BIT(11) | BIT(12),
- .clk_mask = BIT(11) | BIT(12),
- },
- [IMX93_MEDIABLK_PD_MIPI_CSI] = {
- .name = "mediablk-mipi-csi",
- .clk_names = (const char *[]){ "cam", "csi" },
- .num_clks = 2,
- .rst_mask = BIT(9) | BIT(10),
- .clk_mask = BIT(9) | BIT(10),
- },
- [IMX93_MEDIABLK_PD_PXP] = {
- .name = "mediablk-pxp",
- .clk_names = (const char *[]){ "pxp" },
- .num_clks = 1,
- .rst_mask = BIT(7) | BIT(8),
- .clk_mask = BIT(7) | BIT(8),
- .num_qos = 2,
- .qos = {
- {
- .reg = PXP_QOS_REG,
- .cfg_off = PXP_R_CFG_QOS_OFF,
- .default_prio = PRIO(3),
- .cfg_prio = PRIO(6),
- }, {
- .reg = PXP_QOS_REG,
- .cfg_off = PXP_W_CFG_QOS_OFF,
- .default_prio = PRIO(3),
- .cfg_prio = PRIO(6),
- }
- }
- },
- [IMX93_MEDIABLK_PD_LCDIF] = {
- .name = "mediablk-lcdif",
- .clk_names = (const char *[]){ "disp", "lcdif" },
- .num_clks = 2,
- .rst_mask = BIT(4) | BIT(5) | BIT(6),
- .clk_mask = BIT(4) | BIT(5) | BIT(6),
- .num_qos = 1,
- .qos = {
- {
- .reg = LCDIF_QOS_REG,
- .cfg_off = LCDIF_CFG_QOS_OFF,
- .default_prio = PRIO(3),
- .cfg_prio = PRIO(7),
- }
- }
- },
- [IMX93_MEDIABLK_PD_ISI] = {
- .name = "mediablk-isi",
- .clk_names = (const char *[]){ "isi" },
- .num_clks = 1,
- .rst_mask = BIT(2) | BIT(3),
- .clk_mask = BIT(2) | BIT(3),
- .num_qos = 4,
- .qos = {
- {
- .reg = ISI_QOS_REG,
- .cfg_off = ISI_Y_W_CFG_QOS_OFF,
- .default_prio = PRIO(3),
- .cfg_prio = PRIO(7),
- }, {
- .reg = ISI_QOS_REG,
- .cfg_off = ISI_Y_R_CFG_QOS_OFF,
- .default_prio = PRIO(3),
- .cfg_prio = PRIO(7),
- }, {
- .reg = ISI_QOS_REG,
- .cfg_off = ISI_U_CFG_QOS_OFF,
- .default_prio = PRIO(3),
- .cfg_prio = PRIO(7),
- }, {
- .reg = ISI_QOS_REG,
- .cfg_off = ISI_V_CFG_QOS_OFF,
- .default_prio = PRIO(3),
- .cfg_prio = PRIO(7),
- }
- }
- },
-};
-
-static const struct regmap_range imx93_media_blk_ctl_yes_ranges[] = {
- regmap_reg_range(BLK_SFT_RSTN, BLK_CLK_EN),
- regmap_reg_range(LCDIF_QOS_REG, ISI_CACHE_REG),
- regmap_reg_range(ISI_QOS_REG, ISI_QOS_REG),
-};
-
-static const struct regmap_access_table imx93_media_blk_ctl_access_table = {
- .yes_ranges = imx93_media_blk_ctl_yes_ranges,
- .n_yes_ranges = ARRAY_SIZE(imx93_media_blk_ctl_yes_ranges),
-};
-
-static const struct imx93_blk_ctrl_data imx93_media_blk_ctl_dev_data = {
- .domains = imx93_media_blk_ctl_domain_data,
- .num_domains = ARRAY_SIZE(imx93_media_blk_ctl_domain_data),
- .clk_names = (const char *[]){ "axi", "apb", "nic", },
- .num_clks = 3,
- .reg_access_table = &imx93_media_blk_ctl_access_table,
-};
-
-static const struct of_device_id imx93_blk_ctrl_of_match[] = {
- {
- .compatible = "fsl,imx93-media-blk-ctrl",
- .data = &imx93_media_blk_ctl_dev_data
- }, {
- /* Sentinel */
- }
-};
-MODULE_DEVICE_TABLE(of, imx93_blk_ctrl_of_match);
-
-static struct platform_driver imx93_blk_ctrl_driver = {
- .probe = imx93_blk_ctrl_probe,
- .remove = imx93_blk_ctrl_remove,
- .driver = {
- .name = "imx93-blk-ctrl",
- .of_match_table = imx93_blk_ctrl_of_match,
- },
-};
-module_platform_driver(imx93_blk_ctrl_driver);
-
-MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
-MODULE_DESCRIPTION("i.MX93 BLK CTRL driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/soc/imx/imx93-pd.c b/drivers/soc/imx/imx93-pd.c
deleted file mode 100644
index 4d235c8c4924..000000000000
--- a/drivers/soc/imx/imx93-pd.c
+++ /dev/null
@@ -1,177 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright 2022 NXP
- */
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/of_device.h>
-#include <linux/iopoll.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-
-#define MIX_SLICE_SW_CTRL_OFF 0x20
-#define SLICE_SW_CTRL_PSW_CTRL_OFF_MASK BIT(4)
-#define SLICE_SW_CTRL_PDN_SOFT_MASK BIT(31)
-
-#define MIX_FUNC_STAT_OFF 0xB4
-
-#define FUNC_STAT_PSW_STAT_MASK BIT(0)
-#define FUNC_STAT_RST_STAT_MASK BIT(2)
-#define FUNC_STAT_ISO_STAT_MASK BIT(4)
-
-struct imx93_power_domain {
- struct generic_pm_domain genpd;
- struct device *dev;
- void __iomem *addr;
- struct clk_bulk_data *clks;
- int num_clks;
- bool init_off;
-};
-
-#define to_imx93_pd(_genpd) container_of(_genpd, struct imx93_power_domain, genpd)
-
-static int imx93_pd_on(struct generic_pm_domain *genpd)
-{
- struct imx93_power_domain *domain = to_imx93_pd(genpd);
- void __iomem *addr = domain->addr;
- u32 val;
- int ret;
-
- ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks);
- if (ret) {
- dev_err(domain->dev, "failed to enable clocks for domain: %s\n", genpd->name);
- return ret;
- }
-
- val = readl(addr + MIX_SLICE_SW_CTRL_OFF);
- val &= ~SLICE_SW_CTRL_PDN_SOFT_MASK;
- writel(val, addr + MIX_SLICE_SW_CTRL_OFF);
-
- ret = readl_poll_timeout(addr + MIX_FUNC_STAT_OFF, val,
- !(val & FUNC_STAT_ISO_STAT_MASK), 1, 10000);
- if (ret) {
- dev_err(domain->dev, "pd_on timeout: name: %s, stat: %x\n", genpd->name, val);
- return ret;
- }
-
- return 0;
-}
-
-static int imx93_pd_off(struct generic_pm_domain *genpd)
-{
- struct imx93_power_domain *domain = to_imx93_pd(genpd);
- void __iomem *addr = domain->addr;
- int ret;
- u32 val;
-
- /* Power off MIX */
- val = readl(addr + MIX_SLICE_SW_CTRL_OFF);
- val |= SLICE_SW_CTRL_PDN_SOFT_MASK;
- writel(val, addr + MIX_SLICE_SW_CTRL_OFF);
-
- ret = readl_poll_timeout(addr + MIX_FUNC_STAT_OFF, val,
- val & FUNC_STAT_PSW_STAT_MASK, 1, 1000);
- if (ret) {
- dev_err(domain->dev, "pd_off timeout: name: %s, stat: %x\n", genpd->name, val);
- return ret;
- }
-
- clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
-
- return 0;
-};
-
-static int imx93_pd_remove(struct platform_device *pdev)
-{
- struct imx93_power_domain *domain = platform_get_drvdata(pdev);
- struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
-
- if (!domain->init_off)
- clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
-
- of_genpd_del_provider(np);
- pm_genpd_remove(&domain->genpd);
-
- return 0;
-}
-
-static int imx93_pd_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
- struct imx93_power_domain *domain;
- int ret;
-
- domain = devm_kzalloc(dev, sizeof(*domain), GFP_KERNEL);
- if (!domain)
- return -ENOMEM;
-
- domain->addr = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(domain->addr))
- return PTR_ERR(domain->addr);
-
- domain->num_clks = devm_clk_bulk_get_all(dev, &domain->clks);
- if (domain->num_clks < 0)
- return dev_err_probe(dev, domain->num_clks, "Failed to get domain's clocks\n");
-
- domain->genpd.name = dev_name(dev);
- domain->genpd.power_off = imx93_pd_off;
- domain->genpd.power_on = imx93_pd_on;
- domain->dev = dev;
-
- domain->init_off = readl(domain->addr + MIX_FUNC_STAT_OFF) & FUNC_STAT_ISO_STAT_MASK;
- /* Just to sync the status of hardware */
- if (!domain->init_off) {
- ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks);
- if (ret) {
- dev_err(domain->dev, "failed to enable clocks for domain: %s\n",
- domain->genpd.name);
- return ret;
- }
- }
-
- ret = pm_genpd_init(&domain->genpd, NULL, domain->init_off);
- if (ret)
- goto err_clk_unprepare;
-
- platform_set_drvdata(pdev, domain);
-
- ret = of_genpd_add_provider_simple(np, &domain->genpd);
- if (ret)
- goto err_genpd_remove;
-
- return 0;
-
-err_genpd_remove:
- pm_genpd_remove(&domain->genpd);
-
-err_clk_unprepare:
- if (!domain->init_off)
- clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
-
- return ret;
-}
-
-static const struct of_device_id imx93_pd_ids[] = {
- { .compatible = "fsl,imx93-src-slice" },
- { }
-};
-MODULE_DEVICE_TABLE(of, imx93_pd_ids);
-
-static struct platform_driver imx93_power_domain_driver = {
- .driver = {
- .name = "imx93_power_domain",
- .owner = THIS_MODULE,
- .of_match_table = imx93_pd_ids,
- },
- .probe = imx93_pd_probe,
- .remove = imx93_pd_remove,
-};
-module_platform_driver(imx93_power_domain_driver);
-
-MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
-MODULE_DESCRIPTION("NXP i.MX93 power domain driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/soc/imx/imx93-src.c b/drivers/soc/imx/imx93-src.c
index 4d74921cae0f..f1c2e22d5cbd 100644
--- a/drivers/soc/imx/imx93-src.c
+++ b/drivers/soc/imx/imx93-src.c
@@ -21,7 +21,6 @@ MODULE_DEVICE_TABLE(of, imx93_src_ids);
static struct platform_driver imx93_src_driver = {
.driver = {
.name = "imx93_src",
- .owner = THIS_MODULE,
.of_match_table = imx93_src_ids,
},
.probe = imx93_src_probe,
diff --git a/drivers/soc/imx/soc-imx8m.c b/drivers/soc/imx/soc-imx8m.c
index 32ed9dc88e45..04a1b60f2f2b 100644
--- a/drivers/soc/imx/soc-imx8m.c
+++ b/drivers/soc/imx/soc-imx8m.c
@@ -24,16 +24,22 @@
#define OCOTP_UID_HIGH 0x420
#define IMX8MP_OCOTP_UID_OFFSET 0x10
+#define IMX8MP_OCOTP_UID_HIGH 0xE00
/* Same as ANADIG_DIGPROG_IMX7D */
#define ANADIG_DIGPROG_IMX8MM 0x800
struct imx8_soc_data {
char *name;
- u32 (*soc_revision)(void);
+ const char *ocotp_compatible;
+ int (*soc_revision)(struct platform_device *pdev, u32 *socrev);
+ int (*soc_uid)(struct platform_device *pdev, u64 *socuid);
};
-static u64 soc_uid;
+struct imx8_soc_drvdata {
+ void __iomem *ocotp_base;
+ struct clk *clk;
+};
#ifdef CONFIG_HAVE_ARM_SMCCC
static u32 imx8mq_soc_revision_from_atf(void)
@@ -51,27 +57,24 @@ 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 imx8m_soc_uid(struct platform_device *pdev, u64 *socuid)
{
- struct device_node *np;
- void __iomem *ocotp_base;
- u32 magic;
- u32 rev;
- struct clk *clk;
+ struct imx8_soc_drvdata *drvdata = platform_get_drvdata(pdev);
+ void __iomem *ocotp_base = drvdata->ocotp_base;
- np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-ocotp");
- if (!np)
- return 0;
+ *socuid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH);
+ *socuid <<= 32;
+ *socuid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW);
- ocotp_base = of_iomap(np, 0);
- WARN_ON(!ocotp_base);
- clk = of_clk_get_by_name(np, NULL);
- if (IS_ERR(clk)) {
- WARN_ON(IS_ERR(clk));
- return 0;
- }
+ return 0;
+}
- clk_prepare_enable(clk);
+static int imx8mq_soc_revision(struct platform_device *pdev, u32 *socrev)
+{
+ struct imx8_soc_drvdata *drvdata = platform_get_drvdata(pdev);
+ void __iomem *ocotp_base = drvdata->ocotp_base;
+ u32 magic;
+ u32 rev;
/*
* SOC revision on older imx8mq is not available in fuses so query
@@ -84,81 +87,109 @@ 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);
-
- clk_disable_unprepare(clk);
- clk_put(clk);
- iounmap(ocotp_base);
- of_node_put(np);
+ *socrev = rev;
- return rev;
+ return 0;
}
-static void __init imx8mm_soc_uid(void)
+static int imx8mp_soc_uid(struct platform_device *pdev, u64 *socuid)
{
- void __iomem *ocotp_base;
- struct device_node *np;
- u32 offset = of_machine_is_compatible("fsl,imx8mp") ?
- IMX8MP_OCOTP_UID_OFFSET : 0;
+ struct imx8_soc_drvdata *drvdata = platform_get_drvdata(pdev);
+ void __iomem *ocotp_base = drvdata->ocotp_base;
- np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-ocotp");
- if (!np)
- return;
+ socuid[0] = readl_relaxed(ocotp_base + OCOTP_UID_HIGH + IMX8MP_OCOTP_UID_OFFSET);
+ socuid[0] <<= 32;
+ socuid[0] |= readl_relaxed(ocotp_base + OCOTP_UID_LOW + IMX8MP_OCOTP_UID_OFFSET);
- ocotp_base = of_iomap(np, 0);
- WARN_ON(!ocotp_base);
+ socuid[1] = readl_relaxed(ocotp_base + IMX8MP_OCOTP_UID_HIGH + 0x10);
+ socuid[1] <<= 32;
+ socuid[1] |= readl_relaxed(ocotp_base + IMX8MP_OCOTP_UID_HIGH);
- soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH + offset);
- soc_uid <<= 32;
- soc_uid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW + offset);
-
- iounmap(ocotp_base);
- of_node_put(np);
+ return 0;
}
-static u32 __init imx8mm_soc_revision(void)
+static int imx8mm_soc_revision(struct platform_device *pdev, u32 *socrev)
{
- 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 0;
+}
+
+static int imx8m_soc_prepare(struct platform_device *pdev, const char *ocotp_compatible)
+{
+ struct device_node *np __free(device_node) =
+ of_find_compatible_node(NULL, NULL, ocotp_compatible);
+ struct imx8_soc_drvdata *drvdata = platform_get_drvdata(pdev);
+ int ret = 0;
+
+ if (!np)
+ return -EINVAL;
+
+ drvdata->ocotp_base = of_iomap(np, 0);
+ if (!drvdata->ocotp_base)
+ return -EINVAL;
+
+ drvdata->clk = of_clk_get_by_name(np, NULL);
+ if (IS_ERR(drvdata->clk)) {
+ ret = PTR_ERR(drvdata->clk);
+ goto err_clk;
+ }
+
+ return clk_prepare_enable(drvdata->clk);
+
+err_clk:
+ iounmap(drvdata->ocotp_base);
+ return ret;
+}
+
+static void imx8m_soc_unprepare(struct platform_device *pdev)
+{
+ struct imx8_soc_drvdata *drvdata = platform_get_drvdata(pdev);
- return rev;
+ clk_disable_unprepare(drvdata->clk);
+ clk_put(drvdata->clk);
+ iounmap(drvdata->ocotp_base);
}
static const struct imx8_soc_data imx8mq_soc_data = {
.name = "i.MX8MQ",
+ .ocotp_compatible = "fsl,imx8mq-ocotp",
.soc_revision = imx8mq_soc_revision,
+ .soc_uid = imx8m_soc_uid,
};
static const struct imx8_soc_data imx8mm_soc_data = {
.name = "i.MX8MM",
+ .ocotp_compatible = "fsl,imx8mm-ocotp",
.soc_revision = imx8mm_soc_revision,
+ .soc_uid = imx8m_soc_uid,
};
static const struct imx8_soc_data imx8mn_soc_data = {
.name = "i.MX8MN",
+ .ocotp_compatible = "fsl,imx8mm-ocotp",
.soc_revision = imx8mm_soc_revision,
+ .soc_uid = imx8m_soc_uid,
};
static const struct imx8_soc_data imx8mp_soc_data = {
.name = "i.MX8MP",
+ .ocotp_compatible = "fsl,imx8mm-ocotp",
.soc_revision = imx8mm_soc_revision,
+ .soc_uid = imx8mp_soc_uid,
};
static __maybe_unused const struct of_device_id imx8_soc_match[] = {
@@ -169,76 +200,146 @@ 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 imx8_soc_drvdata *drvdata;
+ 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[2] = {0, 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;
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, drvdata);
+
soc_dev_attr->family = "Freescale i.MX";
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();
+ ret = imx8m_soc_prepare(pdev, data->ocotp_compatible);
+ if (ret)
+ return ret;
+
+ if (data->soc_revision) {
+ ret = data->soc_revision(pdev, &soc_rev);
+ if (ret) {
+ imx8m_soc_unprepare(pdev);
+ return ret;
+ }
+ }
+ if (data->soc_uid) {
+ ret = data->soc_uid(pdev, soc_uid);
+ if (ret) {
+ imx8m_soc_unprepare(pdev);
+ return ret;
+ }
+ }
+ imx8m_soc_unprepare(pdev);
}
- 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;
- }
+ if (soc_uid[1])
+ soc_dev_attr->serial_number = devm_kasprintf(dev, GFP_KERNEL, "%016llX%016llX",
+ soc_uid[1], soc_uid[0]);
+ else
+ soc_dev_attr->serial_number = devm_kasprintf(dev, GFP_KERNEL, "%016llX",
+ soc_uid[0]);
+ 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 58240e320c13..33e2e0366f19 100644
--- a/drivers/soc/ixp4xx/ixp4xx-npe.c
+++ b/drivers/soc/ixp4xx/ixp4xx-npe.c
@@ -519,15 +519,15 @@ int npe_load_firmware(struct npe *npe, const char *name, struct device *dev)
u32 id;
u32 size;
union {
- u32 data[0];
- struct dl_block blocks[0];
+ DECLARE_FLEX_ARRAY(u32, data);
+ DECLARE_FLEX_ARRAY(struct dl_block, blocks);
};
} *image;
struct dl_codeblock {
u32 npe_addr;
u32 size;
- u32 data[0];
+ u32 data[];
} *cb;
int i, j, err, data_size, instr_size, blocks, table_end;
@@ -736,7 +736,7 @@ static int ixp4xx_npe_probe(struct platform_device *pdev)
return 0;
}
-static int ixp4xx_npe_remove(struct platform_device *pdev)
+static void ixp4xx_npe_remove(struct platform_device *pdev)
{
int i;
@@ -744,8 +744,6 @@ static int ixp4xx_npe_remove(struct platform_device *pdev)
if (npe_tab[i].regs) {
npe_reset(&npe_tab[i]);
}
-
- return 0;
}
static const struct of_device_id ixp4xx_npe_of_match[] = {
@@ -766,6 +764,7 @@ static struct platform_driver ixp4xx_npe_driver = {
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 291086bb9313..475e229039e3 100644
--- a/drivers/soc/ixp4xx/ixp4xx-qmgr.c
+++ b/drivers/soc/ixp4xx/ixp4xx-qmgr.c
@@ -442,11 +442,10 @@ static int ixp4xx_qmgr_probe(struct platform_device *pdev)
return 0;
}
-static int ixp4xx_qmgr_remove(struct platform_device *pdev)
+static void ixp4xx_qmgr_remove(struct platform_device *pdev)
{
synchronize_irq(qmgr_irq_1);
synchronize_irq(qmgr_irq_2);
- return 0;
}
static const struct of_device_id ixp4xx_qmgr_of_match[] = {
@@ -466,6 +465,7 @@ static struct platform_driver ixp4xx_qmgr_driver = {
};
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 f75790091d38..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,21 +113,12 @@ static int litex_soc_ctrl_probe(struct platform_device *pdev)
return 0;
}
-static int 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);
- return 0;
-}
-
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 = litex_soc_ctrl_remove,
};
module_platform_driver(litex_soc_ctrl_driver);
diff --git a/drivers/soc/loongson/Kconfig b/drivers/soc/loongson/Kconfig
index 707f56358dc4..368344943a93 100644
--- a/drivers/soc/loongson/Kconfig
+++ b/drivers/soc/loongson/Kconfig
@@ -16,3 +16,14 @@ config LOONGSON2_GUTS
SoCs. Initially only reading SVR and registering soc device are
supported. Other guts accesses, such as reading firmware configuration
by default, should eventually be added into this driver as well.
+
+config LOONGSON2_PM
+ bool "Loongson-2 SoC Power Management Controller Driver"
+ depends on LOONGARCH && OF
+ depends on INPUT=y
+ help
+ The Loongson-2's power management controller was ACPI, supports ACPI
+ S2Idle (Suspend To Idle), ACPI S3 (Suspend To RAM), ACPI S4 (Suspend To
+ Disk), ACPI S5 (Soft Shutdown) and supports multiple wake-up methods
+ (USB, GMAC, PWRBTN, etc.). This driver was to add power management
+ controller support that base on dts for Loongson-2 series SoCs.
diff --git a/drivers/soc/loongson/Makefile b/drivers/soc/loongson/Makefile
index 263c486df638..4118f50f55e2 100644
--- a/drivers/soc/loongson/Makefile
+++ b/drivers/soc/loongson/Makefile
@@ -4,3 +4,4 @@
#
obj-$(CONFIG_LOONGSON2_GUTS) += loongson2_guts.o
+obj-$(CONFIG_LOONGSON2_PM) += loongson2_pm.o
diff --git a/drivers/soc/loongson/loongson2_guts.c b/drivers/soc/loongson/loongson2_guts.c
index bace4bc8e03b..16913c3ef65c 100644
--- a/drivers/soc/loongson/loongson2_guts.c
+++ b/drivers/soc/loongson/loongson2_guts.c
@@ -70,7 +70,7 @@ static const struct loongson2_soc_die_attr *loongson2_soc_die_match(
if (matches->svr == (svr & matches->mask))
return matches;
matches++;
- };
+ }
return NULL;
}
@@ -94,7 +94,6 @@ static int loongson2_guts_probe(struct platform_device *pdev)
{
struct device_node *root, *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
- struct resource *res;
const struct loongson2_soc_die_attr *soc_die;
const char *machine;
u32 svr;
@@ -106,8 +105,7 @@ static int loongson2_guts_probe(struct platform_device *pdev)
guts->little_endian = of_property_read_bool(np, "little-endian");
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- guts->regs = ioremap(res->start, res->end - res->start + 1);
+ guts->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(guts->regs))
return PTR_ERR(guts->regs);
@@ -116,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);
@@ -150,11 +151,9 @@ static int loongson2_guts_probe(struct platform_device *pdev)
return 0;
}
-static int loongson2_guts_remove(struct platform_device *dev)
+static void loongson2_guts_remove(struct platform_device *dev)
{
soc_device_unregister(soc_dev);
-
- return 0;
}
/*
diff --git a/drivers/soc/loongson/loongson2_pm.c b/drivers/soc/loongson/loongson2_pm.c
new file mode 100644
index 000000000000..b8e5e1e3528a
--- /dev/null
+++ b/drivers/soc/loongson/loongson2_pm.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Loongson-2 PM Support
+ *
+ * Copyright (C) 2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/suspend.h>
+#include <linux/interrupt.h>
+#include <linux/of_platform.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/platform_device.h>
+#include <asm/bootinfo.h>
+#include <asm/suspend.h>
+
+#define LOONGSON2_PM1_CNT_REG 0x14
+#define LOONGSON2_PM1_STS_REG 0x0c
+#define LOONGSON2_PM1_ENA_REG 0x10
+#define LOONGSON2_GPE0_STS_REG 0x28
+#define LOONGSON2_GPE0_ENA_REG 0x2c
+
+#define LOONGSON2_PM1_PWRBTN_STS BIT(8)
+#define LOONGSON2_PM1_PCIEXP_WAKE_STS BIT(14)
+#define LOONGSON2_PM1_WAKE_STS BIT(15)
+#define LOONGSON2_PM1_CNT_INT_EN BIT(0)
+#define LOONGSON2_PM1_PWRBTN_EN LOONGSON2_PM1_PWRBTN_STS
+
+static struct loongson2_pm {
+ void __iomem *base;
+ struct input_dev *dev;
+ bool suspended;
+} loongson2_pm;
+
+#define loongson2_pm_readw(reg) readw(loongson2_pm.base + reg)
+#define loongson2_pm_readl(reg) readl(loongson2_pm.base + reg)
+#define loongson2_pm_writew(val, reg) writew(val, loongson2_pm.base + reg)
+#define loongson2_pm_writel(val, reg) writel(val, loongson2_pm.base + reg)
+
+static void loongson2_pm_status_clear(void)
+{
+ u16 value;
+
+ value = loongson2_pm_readw(LOONGSON2_PM1_STS_REG);
+ value |= (LOONGSON2_PM1_PWRBTN_STS | LOONGSON2_PM1_PCIEXP_WAKE_STS |
+ LOONGSON2_PM1_WAKE_STS);
+ loongson2_pm_writew(value, LOONGSON2_PM1_STS_REG);
+ loongson2_pm_writel(loongson2_pm_readl(LOONGSON2_GPE0_STS_REG), LOONGSON2_GPE0_STS_REG);
+}
+
+static void loongson2_pm_irq_enable(void)
+{
+ u16 value;
+
+ value = loongson2_pm_readw(LOONGSON2_PM1_CNT_REG);
+ value |= LOONGSON2_PM1_CNT_INT_EN;
+ loongson2_pm_writew(value, LOONGSON2_PM1_CNT_REG);
+
+ value = loongson2_pm_readw(LOONGSON2_PM1_ENA_REG);
+ value |= LOONGSON2_PM1_PWRBTN_EN;
+ loongson2_pm_writew(value, LOONGSON2_PM1_ENA_REG);
+}
+
+static int loongson2_suspend_enter(suspend_state_t state)
+{
+ loongson2_pm_status_clear();
+ loongarch_common_suspend();
+ loongarch_suspend_enter();
+ loongarch_common_resume();
+ loongson2_pm_irq_enable();
+ pm_set_resume_via_firmware();
+
+ return 0;
+}
+
+static int loongson2_suspend_begin(suspend_state_t state)
+{
+ pm_set_suspend_via_firmware();
+
+ return 0;
+}
+
+static int loongson2_suspend_valid_state(suspend_state_t state)
+{
+ return (state == PM_SUSPEND_MEM);
+}
+
+static const struct platform_suspend_ops loongson2_suspend_ops = {
+ .valid = loongson2_suspend_valid_state,
+ .begin = loongson2_suspend_begin,
+ .enter = loongson2_suspend_enter,
+};
+
+static int loongson2_power_button_init(struct device *dev, int irq)
+{
+ int ret;
+ struct input_dev *button;
+
+ button = input_allocate_device();
+ if (!dev)
+ return -ENOMEM;
+
+ button->name = "Power Button";
+ button->phys = "pm/button/input0";
+ button->id.bustype = BUS_HOST;
+ button->dev.parent = NULL;
+ input_set_capability(button, EV_KEY, KEY_POWER);
+
+ ret = input_register_device(button);
+ if (ret)
+ goto free_dev;
+
+ dev_pm_set_wake_irq(&button->dev, irq);
+ device_set_wakeup_capable(&button->dev, true);
+ device_set_wakeup_enable(&button->dev, true);
+
+ loongson2_pm.dev = button;
+ dev_info(dev, "Power Button: Init successful!\n");
+
+ return 0;
+
+free_dev:
+ input_free_device(button);
+
+ return ret;
+}
+
+static irqreturn_t loongson2_pm_irq_handler(int irq, void *dev_id)
+{
+ u16 status = loongson2_pm_readw(LOONGSON2_PM1_STS_REG);
+
+ if (!loongson2_pm.suspended && (status & LOONGSON2_PM1_PWRBTN_STS)) {
+ pr_info("Power Button pressed...\n");
+ input_report_key(loongson2_pm.dev, KEY_POWER, 1);
+ input_sync(loongson2_pm.dev);
+ input_report_key(loongson2_pm.dev, KEY_POWER, 0);
+ input_sync(loongson2_pm.dev);
+ }
+
+ loongson2_pm_status_clear();
+
+ return IRQ_HANDLED;
+}
+
+static int __maybe_unused loongson2_pm_suspend(struct device *dev)
+{
+ loongson2_pm.suspended = true;
+
+ return 0;
+}
+
+static int __maybe_unused loongson2_pm_resume(struct device *dev)
+{
+ loongson2_pm.suspended = false;
+
+ return 0;
+}
+static SIMPLE_DEV_PM_OPS(loongson2_pm_ops, loongson2_pm_suspend, loongson2_pm_resume);
+
+static int loongson2_pm_probe(struct platform_device *pdev)
+{
+ int irq, retval;
+ u64 suspend_addr;
+ struct device *dev = &pdev->dev;
+
+ loongson2_pm.base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(loongson2_pm.base))
+ return PTR_ERR(loongson2_pm.base);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ if (!device_property_read_u64(dev, "loongson,suspend-address", &suspend_addr))
+ loongson_sysconf.suspend_addr = (u64)phys_to_virt(suspend_addr);
+ else
+ dev_err(dev, "No loongson,suspend-address, could not support S3!\n");
+
+ if (loongson2_power_button_init(dev, irq))
+ return -EINVAL;
+
+ retval = devm_request_irq(&pdev->dev, irq, loongson2_pm_irq_handler,
+ IRQF_SHARED, "pm_irq", &loongson2_pm);
+ if (retval)
+ return retval;
+
+ loongson2_pm_irq_enable();
+ loongson2_pm_status_clear();
+
+ if (loongson_sysconf.suspend_addr)
+ suspend_set_ops(&loongson2_suspend_ops);
+
+ /* Populate children */
+ retval = devm_of_platform_populate(dev);
+ if (retval)
+ dev_err(dev, "Error populating children, reboot and poweroff might not work properly\n");
+
+ return 0;
+}
+
+static const struct of_device_id loongson2_pm_match[] = {
+ { .compatible = "loongson,ls2k0500-pmc", },
+ {},
+};
+
+static struct platform_driver loongson2_pm_driver = {
+ .driver = {
+ .name = "ls2k-pm",
+ .pm = &loongson2_pm_ops,
+ .of_match_table = loongson2_pm_match,
+ },
+ .probe = loongson2_pm_probe,
+};
+module_platform_driver(loongson2_pm_driver);
+
+MODULE_DESCRIPTION("Loongson-2 PM driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
index 40d0cc600cae..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
@@ -44,33 +55,16 @@ config MTK_PMIC_WRAP
on different MediaTek SoCs. The PMIC wrapper is a proprietary
hardware to connect the PMIC.
-config MTK_SCPSYS
- bool "MediaTek SCPSYS Support"
- default ARCH_MEDIATEK
- depends on OF
- select REGMAP
- select MTK_INFRACFG
- select PM_GENERIC_DOMAINS if PM
- help
- Say yes here to add support for the MediaTek SCPSYS power domain
- driver.
-
-config MTK_SCPSYS_PM_DOMAINS
- bool "MediaTek SCPSYS generic power domain"
+config MTK_REGULATOR_COUPLER
+ bool "MediaTek SoC Regulator Coupler" if COMPILE_TEST
default ARCH_MEDIATEK
- depends on PM
- select PM_GENERIC_DOMAINS
- select REGMAP
- help
- Say y here to enable power domain support.
- In order to meet high performance and low power requirements, the System
- Control Processor System (SCPSYS) has several power management related
- tasks in the system.
+ depends on REGULATOR
config MTK_MMSYS
- bool "MediaTek MMSYS Support"
+ tristate "MediaTek MMSYS Support"
default ARCH_MEDIATEK
depends on HAS_IOMEM
+ depends on MTK_CMDQ || MTK_CMDQ=n
help
Say yes here to add support for the MediaTek Multimedia
Subsystem (MMSYS).
@@ -85,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 0e9e703c931a..0665573e3c4b 100644
--- a/drivers/soc/mediatek/Makefile
+++ b/drivers/soc/mediatek/Makefile
@@ -1,10 +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_SCPSYS) += mtk-scpsys.o
-obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.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/mt6795-pm-domains.h b/drivers/soc/mediatek/mt6795-pm-domains.h
deleted file mode 100644
index ef07c9dfdd9b..000000000000
--- a/drivers/soc/mediatek/mt6795-pm-domains.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-
-#ifndef __SOC_MEDIATEK_MT6795_PM_DOMAINS_H
-#define __SOC_MEDIATEK_MT6795_PM_DOMAINS_H
-
-#include "mtk-pm-domains.h"
-#include <dt-bindings/power/mt6795-power.h>
-
-/*
- * MT6795 power domain support
- */
-
-static const struct scpsys_domain_data scpsys_domain_data_mt6795[] = {
- [MT6795_POWER_DOMAIN_VDEC] = {
- .name = "vdec",
- .sta_mask = PWR_STATUS_VDEC,
- .ctl_offs = SPM_VDE_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- },
- [MT6795_POWER_DOMAIN_VENC] = {
- .name = "venc",
- .sta_mask = PWR_STATUS_VENC,
- .ctl_offs = SPM_VEN_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- },
- [MT6795_POWER_DOMAIN_ISP] = {
- .name = "isp",
- .sta_mask = PWR_STATUS_ISP,
- .ctl_offs = SPM_ISP_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(13, 12),
- },
- [MT6795_POWER_DOMAIN_MM] = {
- .name = "mm",
- .sta_mask = PWR_STATUS_DISP,
- .ctl_offs = SPM_DIS_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_UPDATE_TOPAXI(MT8173_TOP_AXI_PROT_EN_MM_M0 |
- MT8173_TOP_AXI_PROT_EN_MM_M1),
- },
- },
- [MT6795_POWER_DOMAIN_MJC] = {
- .name = "mjc",
- .sta_mask = BIT(20),
- .ctl_offs = 0x298,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- },
- [MT6795_POWER_DOMAIN_AUDIO] = {
- .name = "audio",
- .sta_mask = PWR_STATUS_AUDIO,
- .ctl_offs = SPM_AUDIO_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- },
- [MT6795_POWER_DOMAIN_MFG_ASYNC] = {
- .name = "mfg_async",
- .sta_mask = PWR_STATUS_MFG_ASYNC,
- .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = 0,
- },
- [MT6795_POWER_DOMAIN_MFG_2D] = {
- .name = "mfg_2d",
- .sta_mask = PWR_STATUS_MFG_2D,
- .ctl_offs = SPM_MFG_2D_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(13, 12),
- },
- [MT6795_POWER_DOMAIN_MFG] = {
- .name = "mfg",
- .sta_mask = PWR_STATUS_MFG,
- .ctl_offs = SPM_MFG_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(13, 8),
- .sram_pdn_ack_bits = GENMASK(21, 16),
- .bp_infracfg = {
- BUS_PROT_UPDATE_TOPAXI(MT8173_TOP_AXI_PROT_EN_MFG_S |
- MT8173_TOP_AXI_PROT_EN_MFG_M0 |
- MT8173_TOP_AXI_PROT_EN_MFG_M1 |
- MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT),
- },
- },
-};
-
-static const struct scpsys_soc_data mt6795_scpsys_data = {
- .domains_data = scpsys_domain_data_mt6795,
- .num_domains = ARRAY_SIZE(scpsys_domain_data_mt6795),
-};
-
-#endif /* __SOC_MEDIATEK_MT6795_PM_DOMAINS_H */
diff --git a/drivers/soc/mediatek/mt8167-mmsys.h b/drivers/soc/mediatek/mt8167-mmsys.h
index f7a35b3656bb..c468926561b4 100644
--- a/drivers/soc/mediatek/mt8167-mmsys.h
+++ b/drivers/soc/mediatek/mt8167-mmsys.h
@@ -14,22 +14,21 @@
#define MT8167_DSI0_SEL_IN_RDMA0 0x1
static const struct mtk_mmsys_routes mt8167_mmsys_routing_table[] = {
- {
- DDP_COMPONENT_OVL0, DDP_COMPONENT_COLOR0,
- MT8167_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN, OVL0_MOUT_EN_COLOR0,
- }, {
- DDP_COMPONENT_DITHER0, DDP_COMPONENT_RDMA0,
- MT8167_DISP_REG_CONFIG_DISP_DITHER_MOUT_EN, MT8167_DITHER_MOUT_EN_RDMA0
- }, {
- DDP_COMPONENT_OVL0, DDP_COMPONENT_COLOR0,
- MT8167_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN, COLOR0_SEL_IN_OVL0
- }, {
- DDP_COMPONENT_RDMA0, DDP_COMPONENT_DSI0,
- MT8167_DISP_REG_CONFIG_DISP_DSI0_SEL_IN, MT8167_DSI0_SEL_IN_RDMA0
- }, {
- DDP_COMPONENT_RDMA0, DDP_COMPONENT_DSI0,
- MT8167_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN, MT8167_RDMA0_SOUT_DSI0
- },
+ MMSYS_ROUTE(OVL0, COLOR0,
+ MT8167_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN, OVL0_MOUT_EN_COLOR0,
+ OVL0_MOUT_EN_COLOR0),
+ MMSYS_ROUTE(DITHER0, RDMA0,
+ MT8167_DISP_REG_CONFIG_DISP_DITHER_MOUT_EN, MT8167_DITHER_MOUT_EN_RDMA0,
+ MT8167_DITHER_MOUT_EN_RDMA0),
+ MMSYS_ROUTE(OVL0, COLOR0,
+ MT8167_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN, COLOR0_SEL_IN_OVL0,
+ COLOR0_SEL_IN_OVL0),
+ MMSYS_ROUTE(RDMA0, DSI0,
+ MT8167_DISP_REG_CONFIG_DISP_DSI0_SEL_IN, MT8167_DSI0_SEL_IN_RDMA0,
+ MT8167_DSI0_SEL_IN_RDMA0),
+ MMSYS_ROUTE(RDMA0, DSI0,
+ MT8167_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN, MT8167_RDMA0_SOUT_DSI0,
+ MT8167_RDMA0_SOUT_DSI0),
};
#endif /* __SOC_MEDIATEK_MT8167_MMSYS_H */
diff --git a/drivers/soc/mediatek/mt8167-pm-domains.h b/drivers/soc/mediatek/mt8167-pm-domains.h
deleted file mode 100644
index 4d6c32759606..000000000000
--- a/drivers/soc/mediatek/mt8167-pm-domains.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-
-#ifndef __SOC_MEDIATEK_MT8167_PM_DOMAINS_H
-#define __SOC_MEDIATEK_MT8167_PM_DOMAINS_H
-
-#include "mtk-pm-domains.h"
-#include <dt-bindings/power/mt8167-power.h>
-
-#define MT8167_PWR_STATUS_MFG_2D BIT(24)
-#define MT8167_PWR_STATUS_MFG_ASYNC BIT(25)
-
-/*
- * MT8167 power domain support
- */
-
-static const struct scpsys_domain_data scpsys_domain_data_mt8167[] = {
- [MT8167_POWER_DOMAIN_MM] = {
- .name = "mm",
- .sta_mask = PWR_STATUS_DISP,
- .ctl_offs = SPM_DIS_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_UPDATE_TOPAXI(MT8167_TOP_AXI_PROT_EN_MM_EMI |
- MT8167_TOP_AXI_PROT_EN_MCU_MM),
- },
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT8167_POWER_DOMAIN_VDEC] = {
- .name = "vdec",
- .sta_mask = PWR_STATUS_VDEC,
- .ctl_offs = SPM_VDE_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT8167_POWER_DOMAIN_ISP] = {
- .name = "isp",
- .sta_mask = PWR_STATUS_ISP,
- .ctl_offs = SPM_ISP_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(13, 12),
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT8167_POWER_DOMAIN_MFG_ASYNC] = {
- .name = "mfg_async",
- .sta_mask = MT8167_PWR_STATUS_MFG_ASYNC,
- .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = 0,
- .sram_pdn_ack_bits = 0,
- .bp_infracfg = {
- BUS_PROT_UPDATE_TOPAXI(MT8167_TOP_AXI_PROT_EN_MCU_MFG |
- MT8167_TOP_AXI_PROT_EN_MFG_EMI),
- },
- },
- [MT8167_POWER_DOMAIN_MFG_2D] = {
- .name = "mfg_2d",
- .sta_mask = MT8167_PWR_STATUS_MFG_2D,
- .ctl_offs = SPM_MFG_2D_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- },
- [MT8167_POWER_DOMAIN_MFG] = {
- .name = "mfg",
- .sta_mask = PWR_STATUS_MFG,
- .ctl_offs = SPM_MFG_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- },
- [MT8167_POWER_DOMAIN_CONN] = {
- .name = "conn",
- .sta_mask = PWR_STATUS_CONN,
- .ctl_offs = SPM_CONN_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = 0,
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- .bp_infracfg = {
- BUS_PROT_UPDATE_TOPAXI(MT8167_TOP_AXI_PROT_EN_CONN_EMI |
- MT8167_TOP_AXI_PROT_EN_CONN_MCU |
- MT8167_TOP_AXI_PROT_EN_MCU_CONN),
- },
- },
-};
-
-static const struct scpsys_soc_data mt8167_scpsys_data = {
- .domains_data = scpsys_domain_data_mt8167,
- .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8167),
-};
-
-#endif /* __SOC_MEDIATEK_MT8167_PM_DOMAINS_H */
-
diff --git a/drivers/soc/mediatek/mt8173-mmsys.h b/drivers/soc/mediatek/mt8173-mmsys.h
new file mode 100644
index 000000000000..957876d7c166
--- /dev/null
+++ b/drivers/soc/mediatek/mt8173-mmsys.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_MT8173_MMSYS_H
+#define __SOC_MEDIATEK_MT8173_MMSYS_H
+
+#define MT8173_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN 0x040
+#define MT8173_DISP_REG_CONFIG_DISP_OVL1_MOUT_EN 0x044
+#define MT8173_DISP_REG_CONFIG_DISP_OD_MOUT_EN 0x048
+#define MT8173_DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN 0x04c
+#define MT8173_DISP_REG_CONFIG_DISP_UFOE_MOUT_EN 0x050
+#define MT8173_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0x084
+#define MT8173_DISP_REG_CONFIG_DISP_COLOR1_SEL_IN 0x088
+#define MT8173_DISP_REG_CONFIG_DISP_AAL_SEL_IN 0x08c
+#define MT8173_DISP_REG_CONFIG_DISP_UFOE_SEL_IN 0x0a0
+#define MT8173_DISP_REG_CONFIG_DSI0_SEL_IN 0x0a4
+#define MT8173_DISP_REG_CONFIG_DPI_SEL_IN 0x0ac
+#define MT8173_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN 0x0b0
+#define MT8173_DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN 0x0c8
+#define MT8173_DISP_REG_CONFIG_DISP_COLOR0_SOUT_SEL_IN 0x0bc
+
+#define MT8173_AAL_SEL_IN_MERGE BIT(0)
+#define MT8173_COLOR0_SEL_IN_OVL0 BIT(0)
+#define MT8173_COLOR0_SOUT_MERGE BIT(0)
+#define MT8173_DPI0_SEL_IN_MASK GENMASK(1, 0)
+#define MT8173_DPI0_SEL_IN_RDMA1 BIT(0)
+#define MT8173_DSI0_SEL_IN_UFOE BIT(0)
+#define MT8173_GAMMA_MOUT_EN_RDMA1 BIT(0)
+#define MT8173_OD0_MOUT_EN_RDMA0 BIT(0)
+#define MT8173_OVL0_MOUT_EN_COLOR0 BIT(0)
+#define MT8173_OVL1_MOUT_EN_COLOR1 BIT(0)
+#define MT8173_UFOE_MOUT_EN_DSI0 BIT(0)
+#define MT8173_UFOE_SEL_IN_RDMA0 BIT(0)
+#define MT8173_RDMA0_SOUT_COLOR0 BIT(0)
+
+static const struct mtk_mmsys_routes mt8173_mmsys_routing_table[] = {
+ MMSYS_ROUTE(OVL0, COLOR0,
+ MT8173_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN, MT8173_OVL0_MOUT_EN_COLOR0,
+ MT8173_OVL0_MOUT_EN_COLOR0),
+ MMSYS_ROUTE(OD0, RDMA0,
+ MT8173_DISP_REG_CONFIG_DISP_OD_MOUT_EN, MT8173_OD0_MOUT_EN_RDMA0,
+ MT8173_OD0_MOUT_EN_RDMA0),
+ MMSYS_ROUTE(UFOE, DSI0,
+ MT8173_DISP_REG_CONFIG_DISP_UFOE_MOUT_EN, MT8173_UFOE_MOUT_EN_DSI0,
+ MT8173_UFOE_MOUT_EN_DSI0),
+ MMSYS_ROUTE(COLOR0, AAL0,
+ MT8173_DISP_REG_CONFIG_DISP_COLOR0_SOUT_SEL_IN, MT8173_COLOR0_SOUT_MERGE,
+ 0 /* SOUT to AAL */),
+ MMSYS_ROUTE(RDMA0, UFOE,
+ MT8173_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN, MT8173_RDMA0_SOUT_COLOR0,
+ 0 /* SOUT to UFOE */),
+ MMSYS_ROUTE(OVL0, COLOR0,
+ MT8173_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN, MT8173_COLOR0_SEL_IN_OVL0,
+ MT8173_COLOR0_SEL_IN_OVL0),
+ MMSYS_ROUTE(AAL0, COLOR0,
+ MT8173_DISP_REG_CONFIG_DISP_AAL_SEL_IN, MT8173_AAL_SEL_IN_MERGE,
+ 0 /* SEL_IN from COLOR0 */),
+ MMSYS_ROUTE(RDMA0, UFOE,
+ MT8173_DISP_REG_CONFIG_DISP_UFOE_SEL_IN, MT8173_UFOE_SEL_IN_RDMA0,
+ 0 /* SEL_IN from RDMA0 */),
+ MMSYS_ROUTE(UFOE, DSI0,
+ MT8173_DISP_REG_CONFIG_DSI0_SEL_IN, MT8173_DSI0_SEL_IN_UFOE,
+ 0 /* SEL_IN from UFOE */),
+ MMSYS_ROUTE(OVL1, COLOR1,
+ MT8173_DISP_REG_CONFIG_DISP_OVL1_MOUT_EN, MT8173_OVL1_MOUT_EN_COLOR1,
+ MT8173_OVL1_MOUT_EN_COLOR1),
+ MMSYS_ROUTE(GAMMA, RDMA1,
+ MT8173_DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN, MT8173_GAMMA_MOUT_EN_RDMA1,
+ MT8173_GAMMA_MOUT_EN_RDMA1),
+ MMSYS_ROUTE(RDMA1, DPI0,
+ MT8173_DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK,
+ RDMA1_SOUT_DPI0),
+ MMSYS_ROUTE(OVL1, COLOR1,
+ MT8173_DISP_REG_CONFIG_DISP_COLOR1_SEL_IN, COLOR1_SEL_IN_OVL1,
+ COLOR1_SEL_IN_OVL1),
+ MMSYS_ROUTE(RDMA1, DPI0,
+ MT8173_DISP_REG_CONFIG_DPI_SEL_IN, MT8173_DPI0_SEL_IN_MASK,
+ MT8173_DPI0_SEL_IN_RDMA1),
+};
+
+#endif /* __SOC_MEDIATEK_MT8173_MMSYS_H */
diff --git a/drivers/soc/mediatek/mt8173-pm-domains.h b/drivers/soc/mediatek/mt8173-pm-domains.h
deleted file mode 100644
index 1a5dc63b7357..000000000000
--- a/drivers/soc/mediatek/mt8173-pm-domains.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-
-#ifndef __SOC_MEDIATEK_MT8173_PM_DOMAINS_H
-#define __SOC_MEDIATEK_MT8173_PM_DOMAINS_H
-
-#include "mtk-pm-domains.h"
-#include <dt-bindings/power/mt8173-power.h>
-
-/*
- * MT8173 power domain support
- */
-
-static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = {
- [MT8173_POWER_DOMAIN_VDEC] = {
- .name = "vdec",
- .sta_mask = PWR_STATUS_VDEC,
- .ctl_offs = SPM_VDE_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- },
- [MT8173_POWER_DOMAIN_VENC] = {
- .name = "venc",
- .sta_mask = PWR_STATUS_VENC,
- .ctl_offs = SPM_VEN_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- },
- [MT8173_POWER_DOMAIN_ISP] = {
- .name = "isp",
- .sta_mask = PWR_STATUS_ISP,
- .ctl_offs = SPM_ISP_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(13, 12),
- },
- [MT8173_POWER_DOMAIN_MM] = {
- .name = "mm",
- .sta_mask = PWR_STATUS_DISP,
- .ctl_offs = SPM_DIS_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_UPDATE_TOPAXI(MT8173_TOP_AXI_PROT_EN_MM_M0 |
- MT8173_TOP_AXI_PROT_EN_MM_M1),
- },
- },
- [MT8173_POWER_DOMAIN_VENC_LT] = {
- .name = "venc_lt",
- .sta_mask = PWR_STATUS_VENC_LT,
- .ctl_offs = SPM_VEN2_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- },
- [MT8173_POWER_DOMAIN_AUDIO] = {
- .name = "audio",
- .sta_mask = PWR_STATUS_AUDIO,
- .ctl_offs = SPM_AUDIO_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- },
- [MT8173_POWER_DOMAIN_USB] = {
- .name = "usb",
- .sta_mask = PWR_STATUS_USB,
- .ctl_offs = SPM_USB_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT8173_POWER_DOMAIN_MFG_ASYNC] = {
- .name = "mfg_async",
- .sta_mask = PWR_STATUS_MFG_ASYNC,
- .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = 0,
- .caps = MTK_SCPD_DOMAIN_SUPPLY,
- },
- [MT8173_POWER_DOMAIN_MFG_2D] = {
- .name = "mfg_2d",
- .sta_mask = PWR_STATUS_MFG_2D,
- .ctl_offs = SPM_MFG_2D_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(13, 12),
- },
- [MT8173_POWER_DOMAIN_MFG] = {
- .name = "mfg",
- .sta_mask = PWR_STATUS_MFG,
- .ctl_offs = SPM_MFG_PWR_CON,
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
- .sram_pdn_bits = GENMASK(13, 8),
- .sram_pdn_ack_bits = GENMASK(21, 16),
- .bp_infracfg = {
- BUS_PROT_UPDATE_TOPAXI(MT8173_TOP_AXI_PROT_EN_MFG_S |
- MT8173_TOP_AXI_PROT_EN_MFG_M0 |
- MT8173_TOP_AXI_PROT_EN_MFG_M1 |
- MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT),
- },
- },
-};
-
-static const struct scpsys_soc_data mt8173_scpsys_data = {
- .domains_data = scpsys_domain_data_mt8173,
- .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8173),
-};
-
-#endif /* __SOC_MEDIATEK_MT8173_PM_DOMAINS_H */
diff --git a/drivers/soc/mediatek/mt8183-mmsys.h b/drivers/soc/mediatek/mt8183-mmsys.h
index ff6be1703469..123384958c4b 100644
--- a/drivers/soc/mediatek/mt8183-mmsys.h
+++ b/drivers/soc/mediatek/mt8183-mmsys.h
@@ -28,35 +28,27 @@
#define MT8183_MMSYS_SW0_RST_B 0x140
static const struct mtk_mmsys_routes mmsys_mt8183_routing_table[] = {
- {
- DDP_COMPONENT_OVL0, DDP_COMPONENT_OVL_2L0,
- MT8183_DISP_OVL0_MOUT_EN, MT8183_OVL0_MOUT_EN_OVL0_2L,
- MT8183_OVL0_MOUT_EN_OVL0_2L
- }, {
- DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA0,
- MT8183_DISP_OVL0_2L_MOUT_EN, MT8183_OVL0_2L_MOUT_EN_DISP_PATH0,
- MT8183_OVL0_2L_MOUT_EN_DISP_PATH0
- }, {
- DDP_COMPONENT_OVL_2L1, DDP_COMPONENT_RDMA1,
- MT8183_DISP_OVL1_2L_MOUT_EN, MT8183_OVL1_2L_MOUT_EN_RDMA1,
- MT8183_OVL1_2L_MOUT_EN_RDMA1
- }, {
- DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0,
- MT8183_DISP_DITHER0_MOUT_EN, MT8183_DITHER0_MOUT_IN_DSI0,
- MT8183_DITHER0_MOUT_IN_DSI0
- }, {
- DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA0,
- MT8183_DISP_PATH0_SEL_IN, MT8183_DISP_PATH0_SEL_IN_OVL0_2L,
- MT8183_DISP_PATH0_SEL_IN_OVL0_2L
- }, {
- DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
- MT8183_DISP_DPI0_SEL_IN, MT8183_DPI0_SEL_IN_RDMA1,
- MT8183_DPI0_SEL_IN_RDMA1
- }, {
- DDP_COMPONENT_RDMA0, DDP_COMPONENT_COLOR0,
- MT8183_DISP_RDMA0_SOUT_SEL_IN, MT8183_RDMA0_SOUT_COLOR0,
- MT8183_RDMA0_SOUT_COLOR0
- }
+ MMSYS_ROUTE(OVL0, OVL_2L0,
+ MT8183_DISP_OVL0_MOUT_EN, MT8183_OVL0_MOUT_EN_OVL0_2L,
+ MT8183_OVL0_MOUT_EN_OVL0_2L),
+ MMSYS_ROUTE(OVL_2L0, RDMA0,
+ MT8183_DISP_OVL0_2L_MOUT_EN, MT8183_OVL0_2L_MOUT_EN_DISP_PATH0,
+ MT8183_OVL0_2L_MOUT_EN_DISP_PATH0),
+ MMSYS_ROUTE(OVL_2L1, RDMA1,
+ MT8183_DISP_OVL1_2L_MOUT_EN, MT8183_OVL1_2L_MOUT_EN_RDMA1,
+ MT8183_OVL1_2L_MOUT_EN_RDMA1),
+ MMSYS_ROUTE(DITHER0, DSI0,
+ MT8183_DISP_DITHER0_MOUT_EN, MT8183_DITHER0_MOUT_IN_DSI0,
+ MT8183_DITHER0_MOUT_IN_DSI0),
+ MMSYS_ROUTE(OVL_2L0, RDMA0,
+ MT8183_DISP_PATH0_SEL_IN, MT8183_DISP_PATH0_SEL_IN_OVL0_2L,
+ MT8183_DISP_PATH0_SEL_IN_OVL0_2L),
+ MMSYS_ROUTE(RDMA1, DPI0,
+ MT8183_DISP_DPI0_SEL_IN, MT8183_DPI0_SEL_IN_RDMA1,
+ MT8183_DPI0_SEL_IN_RDMA1),
+ MMSYS_ROUTE(RDMA0, COLOR0,
+ MT8183_DISP_RDMA0_SOUT_SEL_IN, MT8183_RDMA0_SOUT_COLOR0,
+ MT8183_RDMA0_SOUT_COLOR0),
};
#endif /* __SOC_MEDIATEK_MT8183_MMSYS_H */
diff --git a/drivers/soc/mediatek/mt8183-pm-domains.h b/drivers/soc/mediatek/mt8183-pm-domains.h
deleted file mode 100644
index 99de67fe5de8..000000000000
--- a/drivers/soc/mediatek/mt8183-pm-domains.h
+++ /dev/null
@@ -1,266 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-
-#ifndef __SOC_MEDIATEK_MT8183_PM_DOMAINS_H
-#define __SOC_MEDIATEK_MT8183_PM_DOMAINS_H
-
-#include "mtk-pm-domains.h"
-#include <dt-bindings/power/mt8183-power.h>
-
-/*
- * MT8183 power domain support
- */
-
-static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
- [MT8183_POWER_DOMAIN_AUDIO] = {
- .name = "audio",
- .sta_mask = PWR_STATUS_AUDIO,
- .ctl_offs = 0x0314,
- .pwr_sta_offs = 0x0180,
- .pwr_sta2nd_offs = 0x0184,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- },
- [MT8183_POWER_DOMAIN_CONN] = {
- .name = "conn",
- .sta_mask = PWR_STATUS_CONN,
- .ctl_offs = 0x032c,
- .pwr_sta_offs = 0x0180,
- .pwr_sta2nd_offs = 0x0184,
- .sram_pdn_bits = 0,
- .sram_pdn_ack_bits = 0,
- .bp_infracfg = {
- BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_CONN, MT8183_TOP_AXI_PROT_EN_SET,
- MT8183_TOP_AXI_PROT_EN_CLR, MT8183_TOP_AXI_PROT_EN_STA1),
- },
- },
- [MT8183_POWER_DOMAIN_MFG_ASYNC] = {
- .name = "mfg_async",
- .sta_mask = PWR_STATUS_MFG_ASYNC,
- .ctl_offs = 0x0334,
- .pwr_sta_offs = 0x0180,
- .pwr_sta2nd_offs = 0x0184,
- .sram_pdn_bits = 0,
- .sram_pdn_ack_bits = 0,
- .caps = MTK_SCPD_DOMAIN_SUPPLY,
- },
- [MT8183_POWER_DOMAIN_MFG] = {
- .name = "mfg",
- .sta_mask = PWR_STATUS_MFG,
- .ctl_offs = 0x0338,
- .pwr_sta_offs = 0x0180,
- .pwr_sta2nd_offs = 0x0184,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .caps = MTK_SCPD_DOMAIN_SUPPLY,
- },
- [MT8183_POWER_DOMAIN_MFG_CORE0] = {
- .name = "mfg_core0",
- .sta_mask = BIT(7),
- .ctl_offs = 0x034c,
- .pwr_sta_offs = 0x0180,
- .pwr_sta2nd_offs = 0x0184,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- },
- [MT8183_POWER_DOMAIN_MFG_CORE1] = {
- .name = "mfg_core1",
- .sta_mask = BIT(20),
- .ctl_offs = 0x0310,
- .pwr_sta_offs = 0x0180,
- .pwr_sta2nd_offs = 0x0184,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- },
- [MT8183_POWER_DOMAIN_MFG_2D] = {
- .name = "mfg_2d",
- .sta_mask = PWR_STATUS_MFG_2D,
- .ctl_offs = 0x0348,
- .pwr_sta_offs = 0x0180,
- .pwr_sta2nd_offs = 0x0184,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_1_MFG, MT8183_TOP_AXI_PROT_EN_1_SET,
- MT8183_TOP_AXI_PROT_EN_1_CLR, MT8183_TOP_AXI_PROT_EN_STA1_1),
- BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MFG, MT8183_TOP_AXI_PROT_EN_SET,
- MT8183_TOP_AXI_PROT_EN_CLR, MT8183_TOP_AXI_PROT_EN_STA1),
- },
- },
- [MT8183_POWER_DOMAIN_DISP] = {
- .name = "disp",
- .sta_mask = PWR_STATUS_DISP,
- .ctl_offs = 0x030c,
- .pwr_sta_offs = 0x0180,
- .pwr_sta2nd_offs = 0x0184,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_1_DISP, MT8183_TOP_AXI_PROT_EN_1_SET,
- MT8183_TOP_AXI_PROT_EN_1_CLR, MT8183_TOP_AXI_PROT_EN_STA1_1),
- BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_DISP, MT8183_TOP_AXI_PROT_EN_SET,
- MT8183_TOP_AXI_PROT_EN_CLR, MT8183_TOP_AXI_PROT_EN_STA1),
- },
- .bp_smi = {
- BUS_PROT_WR(MT8183_SMI_COMMON_SMI_CLAMP_DISP,
- MT8183_SMI_COMMON_CLAMP_EN_SET,
- MT8183_SMI_COMMON_CLAMP_EN_CLR,
- MT8183_SMI_COMMON_CLAMP_EN),
- },
- },
- [MT8183_POWER_DOMAIN_CAM] = {
- .name = "cam",
- .sta_mask = BIT(25),
- .ctl_offs = 0x0344,
- .pwr_sta_offs = 0x0180,
- .pwr_sta2nd_offs = 0x0184,
- .sram_pdn_bits = GENMASK(9, 8),
- .sram_pdn_ack_bits = GENMASK(13, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MM_CAM, MT8183_TOP_AXI_PROT_EN_MM_SET,
- MT8183_TOP_AXI_PROT_EN_MM_CLR, MT8183_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_CAM, MT8183_TOP_AXI_PROT_EN_SET,
- MT8183_TOP_AXI_PROT_EN_CLR, MT8183_TOP_AXI_PROT_EN_STA1),
- BUS_PROT_WR_IGN(MT8183_TOP_AXI_PROT_EN_MM_CAM_2ND,
- MT8183_TOP_AXI_PROT_EN_MM_SET,
- MT8183_TOP_AXI_PROT_EN_MM_CLR,
- MT8183_TOP_AXI_PROT_EN_MM_STA1),
- },
- .bp_smi = {
- BUS_PROT_WR(MT8183_SMI_COMMON_SMI_CLAMP_CAM,
- MT8183_SMI_COMMON_CLAMP_EN_SET,
- MT8183_SMI_COMMON_CLAMP_EN_CLR,
- MT8183_SMI_COMMON_CLAMP_EN),
- },
- },
- [MT8183_POWER_DOMAIN_ISP] = {
- .name = "isp",
- .sta_mask = PWR_STATUS_ISP,
- .ctl_offs = 0x0308,
- .pwr_sta_offs = 0x0180,
- .pwr_sta2nd_offs = 0x0184,
- .sram_pdn_bits = GENMASK(9, 8),
- .sram_pdn_ack_bits = GENMASK(13, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MM_ISP,
- MT8183_TOP_AXI_PROT_EN_MM_SET,
- MT8183_TOP_AXI_PROT_EN_MM_CLR,
- MT8183_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR_IGN(MT8183_TOP_AXI_PROT_EN_MM_ISP_2ND,
- MT8183_TOP_AXI_PROT_EN_MM_SET,
- MT8183_TOP_AXI_PROT_EN_MM_CLR,
- MT8183_TOP_AXI_PROT_EN_MM_STA1),
- },
- .bp_smi = {
- BUS_PROT_WR(MT8183_SMI_COMMON_SMI_CLAMP_ISP,
- MT8183_SMI_COMMON_CLAMP_EN_SET,
- MT8183_SMI_COMMON_CLAMP_EN_CLR,
- MT8183_SMI_COMMON_CLAMP_EN),
- },
- },
- [MT8183_POWER_DOMAIN_VDEC] = {
- .name = "vdec",
- .sta_mask = BIT(31),
- .ctl_offs = 0x0300,
- .pwr_sta_offs = 0x0180,
- .pwr_sta2nd_offs = 0x0184,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_smi = {
- BUS_PROT_WR(MT8183_SMI_COMMON_SMI_CLAMP_VDEC,
- MT8183_SMI_COMMON_CLAMP_EN_SET,
- MT8183_SMI_COMMON_CLAMP_EN_CLR,
- MT8183_SMI_COMMON_CLAMP_EN),
- },
- },
- [MT8183_POWER_DOMAIN_VENC] = {
- .name = "venc",
- .sta_mask = PWR_STATUS_VENC,
- .ctl_offs = 0x0304,
- .pwr_sta_offs = 0x0180,
- .pwr_sta2nd_offs = 0x0184,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- .bp_smi = {
- BUS_PROT_WR(MT8183_SMI_COMMON_SMI_CLAMP_VENC,
- MT8183_SMI_COMMON_CLAMP_EN_SET,
- MT8183_SMI_COMMON_CLAMP_EN_CLR,
- MT8183_SMI_COMMON_CLAMP_EN),
- },
- },
- [MT8183_POWER_DOMAIN_VPU_TOP] = {
- .name = "vpu_top",
- .sta_mask = BIT(26),
- .ctl_offs = 0x0324,
- .pwr_sta_offs = 0x0180,
- .pwr_sta2nd_offs = 0x0184,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MM_VPU_TOP,
- MT8183_TOP_AXI_PROT_EN_MM_SET,
- MT8183_TOP_AXI_PROT_EN_MM_CLR,
- MT8183_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_VPU_TOP,
- MT8183_TOP_AXI_PROT_EN_SET,
- MT8183_TOP_AXI_PROT_EN_CLR,
- MT8183_TOP_AXI_PROT_EN_STA1),
- BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MM_VPU_TOP_2ND,
- MT8183_TOP_AXI_PROT_EN_MM_SET,
- MT8183_TOP_AXI_PROT_EN_MM_CLR,
- MT8183_TOP_AXI_PROT_EN_MM_STA1),
- },
- .bp_smi = {
- BUS_PROT_WR(MT8183_SMI_COMMON_SMI_CLAMP_VPU_TOP,
- MT8183_SMI_COMMON_CLAMP_EN_SET,
- MT8183_SMI_COMMON_CLAMP_EN_CLR,
- MT8183_SMI_COMMON_CLAMP_EN),
- },
- },
- [MT8183_POWER_DOMAIN_VPU_CORE0] = {
- .name = "vpu_core0",
- .sta_mask = BIT(27),
- .ctl_offs = 0x33c,
- .pwr_sta_offs = 0x0180,
- .pwr_sta2nd_offs = 0x0184,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(13, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MCU_VPU_CORE0,
- MT8183_TOP_AXI_PROT_EN_MCU_SET,
- MT8183_TOP_AXI_PROT_EN_MCU_CLR,
- MT8183_TOP_AXI_PROT_EN_MCU_STA1),
- BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MCU_VPU_CORE0_2ND,
- MT8183_TOP_AXI_PROT_EN_MCU_SET,
- MT8183_TOP_AXI_PROT_EN_MCU_CLR,
- MT8183_TOP_AXI_PROT_EN_MCU_STA1),
- },
- .caps = MTK_SCPD_SRAM_ISO,
- },
- [MT8183_POWER_DOMAIN_VPU_CORE1] = {
- .name = "vpu_core1",
- .sta_mask = BIT(28),
- .ctl_offs = 0x0340,
- .pwr_sta_offs = 0x0180,
- .pwr_sta2nd_offs = 0x0184,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(13, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MCU_VPU_CORE1,
- MT8183_TOP_AXI_PROT_EN_MCU_SET,
- MT8183_TOP_AXI_PROT_EN_MCU_CLR,
- MT8183_TOP_AXI_PROT_EN_MCU_STA1),
- BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MCU_VPU_CORE1_2ND,
- MT8183_TOP_AXI_PROT_EN_MCU_SET,
- MT8183_TOP_AXI_PROT_EN_MCU_CLR,
- MT8183_TOP_AXI_PROT_EN_MCU_STA1),
- },
- .caps = MTK_SCPD_SRAM_ISO,
- },
-};
-
-static const struct scpsys_soc_data mt8183_scpsys_data = {
- .domains_data = scpsys_domain_data_mt8183,
- .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8183),
-};
-
-#endif /* __SOC_MEDIATEK_MT8183_PM_DOMAINS_H */
diff --git a/drivers/soc/mediatek/mt8186-mmsys.h b/drivers/soc/mediatek/mt8186-mmsys.h
index 279d4138525b..354664be72bd 100644
--- a/drivers/soc/mediatek/mt8186-mmsys.h
+++ b/drivers/soc/mediatek/mt8186-mmsys.h
@@ -63,61 +63,39 @@
#define MT8186_MMSYS_SW0_RST_B 0x160
static const struct mtk_mmsys_routes mmsys_mt8186_routing_table[] = {
- {
- DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0,
- MT8186_DISP_OVL0_MOUT_EN, MT8186_OVL0_MOUT_EN_MASK,
- MT8186_OVL0_MOUT_TO_RDMA0
- },
- {
- DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0,
- MT8186_DISP_RDMA0_SEL_IN, MT8186_RDMA0_SEL_IN_MASK,
- MT8186_RDMA0_FROM_OVL0
- },
- {
- DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0,
- MT8186_MMSYS_OVL_CON, MT8186_MMSYS_OVL0_CON_MASK,
- MT8186_OVL0_GO_BLEND
- },
- {
- DDP_COMPONENT_RDMA0, DDP_COMPONENT_COLOR0,
- MT8186_DISP_RDMA0_SOUT_SEL, MT8186_RDMA0_SOUT_SEL_MASK,
- MT8186_RDMA0_SOUT_TO_COLOR0
- },
- {
- DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0,
- MT8186_DISP_DITHER0_MOUT_EN, MT8186_DITHER0_MOUT_EN_MASK,
- MT8186_DITHER0_MOUT_TO_DSI0,
- },
- {
- DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0,
- MT8186_DISP_DSI0_SEL_IN, MT8186_DSI0_SEL_IN_MASK,
- MT8186_DSI0_FROM_DITHER0
- },
- {
- DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA1,
- MT8186_DISP_OVL0_2L_MOUT_EN, MT8186_OVL0_2L_MOUT_EN_MASK,
- MT8186_OVL0_2L_MOUT_TO_RDMA1
- },
- {
- DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA1,
- MT8186_DISP_RDMA1_SEL_IN, MT8186_RDMA1_SEL_IN_MASK,
- MT8186_RDMA1_FROM_OVL0_2L
- },
- {
- DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA1,
- MT8186_MMSYS_OVL_CON, MT8186_MMSYS_OVL0_2L_CON_MASK,
- MT8186_OVL0_2L_GO_BLEND
- },
- {
- DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
- MT8186_DISP_RDMA1_MOUT_EN, MT8186_RDMA1_MOUT_EN_MASK,
- MT8186_RDMA1_MOUT_TO_DPI0_SEL
- },
- {
- DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
- MT8186_DISP_DPI0_SEL_IN, MT8186_DPI0_SEL_IN_MASK,
- MT8186_DPI0_FROM_RDMA1
- },
+ MMSYS_ROUTE(OVL0, RDMA0,
+ MT8186_DISP_OVL0_MOUT_EN, MT8186_OVL0_MOUT_EN_MASK,
+ MT8186_OVL0_MOUT_TO_RDMA0),
+ MMSYS_ROUTE(OVL0, RDMA0,
+ MT8186_DISP_RDMA0_SEL_IN, MT8186_RDMA0_SEL_IN_MASK,
+ MT8186_RDMA0_FROM_OVL0),
+ MMSYS_ROUTE(OVL0, RDMA0,
+ MT8186_MMSYS_OVL_CON, MT8186_MMSYS_OVL0_CON_MASK,
+ MT8186_OVL0_GO_BLEND),
+ MMSYS_ROUTE(RDMA0, COLOR0,
+ MT8186_DISP_RDMA0_SOUT_SEL, MT8186_RDMA0_SOUT_SEL_MASK,
+ MT8186_RDMA0_SOUT_TO_COLOR0),
+ MMSYS_ROUTE(DITHER0, DSI0,
+ MT8186_DISP_DITHER0_MOUT_EN, MT8186_DITHER0_MOUT_EN_MASK,
+ MT8186_DITHER0_MOUT_TO_DSI0),
+ MMSYS_ROUTE(DITHER0, DSI0,
+ MT8186_DISP_DSI0_SEL_IN, MT8186_DSI0_SEL_IN_MASK,
+ MT8186_DSI0_FROM_DITHER0),
+ MMSYS_ROUTE(OVL_2L0, RDMA1,
+ MT8186_DISP_OVL0_2L_MOUT_EN, MT8186_OVL0_2L_MOUT_EN_MASK,
+ MT8186_OVL0_2L_MOUT_TO_RDMA1),
+ MMSYS_ROUTE(OVL_2L0, RDMA1,
+ MT8186_DISP_RDMA1_SEL_IN, MT8186_RDMA1_SEL_IN_MASK,
+ MT8186_RDMA1_FROM_OVL0_2L),
+ MMSYS_ROUTE(OVL_2L0, RDMA1,
+ MT8186_MMSYS_OVL_CON, MT8186_MMSYS_OVL0_2L_CON_MASK,
+ MT8186_OVL0_2L_GO_BLEND),
+ MMSYS_ROUTE(RDMA1, DPI0,
+ MT8186_DISP_RDMA1_MOUT_EN, MT8186_RDMA1_MOUT_EN_MASK,
+ MT8186_RDMA1_MOUT_TO_DPI0_SEL),
+ MMSYS_ROUTE(RDMA1, DPI0,
+ MT8186_DISP_DPI0_SEL_IN, MT8186_DPI0_SEL_IN_MASK,
+ MT8186_DPI0_FROM_RDMA1),
};
#endif /* __SOC_MEDIATEK_MT8186_MMSYS_H */
diff --git a/drivers/soc/mediatek/mt8186-pm-domains.h b/drivers/soc/mediatek/mt8186-pm-domains.h
deleted file mode 100644
index 108af61854a3..000000000000
--- a/drivers/soc/mediatek/mt8186-pm-domains.h
+++ /dev/null
@@ -1,344 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (c) 2022 MediaTek Inc.
- * Author: Chun-Jie Chen <chun-jie.chen@mediatek.com>
- */
-
-#ifndef __SOC_MEDIATEK_MT8186_PM_DOMAINS_H
-#define __SOC_MEDIATEK_MT8186_PM_DOMAINS_H
-
-#include "mtk-pm-domains.h"
-#include <dt-bindings/power/mt8186-power.h>
-
-/*
- * MT8186 power domain support
- */
-
-static const struct scpsys_domain_data scpsys_domain_data_mt8186[] = {
- [MT8186_POWER_DOMAIN_MFG0] = {
- .name = "mfg0",
- .sta_mask = BIT(2),
- .ctl_offs = 0x308,
- .pwr_sta_offs = 0x16C,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = BIT(8),
- .sram_pdn_ack_bits = BIT(12),
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_DOMAIN_SUPPLY,
- },
- [MT8186_POWER_DOMAIN_MFG1] = {
- .name = "mfg1",
- .sta_mask = BIT(3),
- .ctl_offs = 0x30c,
- .pwr_sta_offs = 0x16C,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = BIT(8),
- .sram_pdn_ack_bits = BIT(12),
- .bp_infracfg = {
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_MFG1_STEP1,
- MT8186_TOP_AXI_PROT_EN_1_SET,
- MT8186_TOP_AXI_PROT_EN_1_CLR,
- MT8186_TOP_AXI_PROT_EN_1_STA),
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_MFG1_STEP2,
- MT8186_TOP_AXI_PROT_EN_SET,
- MT8186_TOP_AXI_PROT_EN_CLR,
- MT8186_TOP_AXI_PROT_EN_STA),
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_MFG1_STEP3,
- MT8186_TOP_AXI_PROT_EN_SET,
- MT8186_TOP_AXI_PROT_EN_CLR,
- MT8186_TOP_AXI_PROT_EN_STA),
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_MFG1_STEP4,
- MT8186_TOP_AXI_PROT_EN_1_SET,
- MT8186_TOP_AXI_PROT_EN_1_CLR,
- MT8186_TOP_AXI_PROT_EN_1_STA),
- },
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_DOMAIN_SUPPLY,
- },
- [MT8186_POWER_DOMAIN_MFG2] = {
- .name = "mfg2",
- .sta_mask = BIT(4),
- .ctl_offs = 0x310,
- .pwr_sta_offs = 0x16C,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = BIT(8),
- .sram_pdn_ack_bits = BIT(12),
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8186_POWER_DOMAIN_MFG3] = {
- .name = "mfg3",
- .sta_mask = BIT(5),
- .ctl_offs = 0x314,
- .pwr_sta_offs = 0x16C,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = BIT(8),
- .sram_pdn_ack_bits = BIT(12),
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8186_POWER_DOMAIN_SSUSB] = {
- .name = "ssusb",
- .sta_mask = BIT(20),
- .ctl_offs = 0x9F0,
- .pwr_sta_offs = 0x16C,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = BIT(8),
- .sram_pdn_ack_bits = BIT(12),
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT8186_POWER_DOMAIN_SSUSB_P1] = {
- .name = "ssusb_p1",
- .sta_mask = BIT(19),
- .ctl_offs = 0x9F4,
- .pwr_sta_offs = 0x16C,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = BIT(8),
- .sram_pdn_ack_bits = BIT(12),
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT8186_POWER_DOMAIN_DIS] = {
- .name = "dis",
- .sta_mask = BIT(21),
- .ctl_offs = 0x354,
- .pwr_sta_offs = 0x16C,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = BIT(8),
- .sram_pdn_ack_bits = BIT(12),
- .bp_infracfg = {
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_DIS_STEP1,
- MT8186_TOP_AXI_PROT_EN_1_SET,
- MT8186_TOP_AXI_PROT_EN_1_CLR,
- MT8186_TOP_AXI_PROT_EN_1_STA),
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_DIS_STEP2,
- MT8186_TOP_AXI_PROT_EN_SET,
- MT8186_TOP_AXI_PROT_EN_CLR,
- MT8186_TOP_AXI_PROT_EN_STA),
- },
- },
- [MT8186_POWER_DOMAIN_IMG] = {
- .name = "img",
- .sta_mask = BIT(13),
- .ctl_offs = 0x334,
- .pwr_sta_offs = 0x16C,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = BIT(8),
- .sram_pdn_ack_bits = BIT(12),
- .bp_infracfg = {
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_IMG_STEP1,
- MT8186_TOP_AXI_PROT_EN_1_SET,
- MT8186_TOP_AXI_PROT_EN_1_CLR,
- MT8186_TOP_AXI_PROT_EN_1_STA),
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_IMG_STEP2,
- MT8186_TOP_AXI_PROT_EN_1_SET,
- MT8186_TOP_AXI_PROT_EN_1_CLR,
- MT8186_TOP_AXI_PROT_EN_1_STA),
- },
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8186_POWER_DOMAIN_IMG2] = {
- .name = "img2",
- .sta_mask = BIT(14),
- .ctl_offs = 0x338,
- .pwr_sta_offs = 0x16C,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = BIT(8),
- .sram_pdn_ack_bits = BIT(12),
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8186_POWER_DOMAIN_IPE] = {
- .name = "ipe",
- .sta_mask = BIT(15),
- .ctl_offs = 0x33C,
- .pwr_sta_offs = 0x16C,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = BIT(8),
- .sram_pdn_ack_bits = BIT(12),
- .bp_infracfg = {
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_IPE_STEP1,
- MT8186_TOP_AXI_PROT_EN_1_SET,
- MT8186_TOP_AXI_PROT_EN_1_CLR,
- MT8186_TOP_AXI_PROT_EN_1_STA),
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_IPE_STEP2,
- MT8186_TOP_AXI_PROT_EN_1_SET,
- MT8186_TOP_AXI_PROT_EN_1_CLR,
- MT8186_TOP_AXI_PROT_EN_1_STA),
- },
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8186_POWER_DOMAIN_CAM] = {
- .name = "cam",
- .sta_mask = BIT(23),
- .ctl_offs = 0x35C,
- .pwr_sta_offs = 0x16C,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = BIT(8),
- .sram_pdn_ack_bits = BIT(12),
- .bp_infracfg = {
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_CAM_STEP1,
- MT8186_TOP_AXI_PROT_EN_1_SET,
- MT8186_TOP_AXI_PROT_EN_1_CLR,
- MT8186_TOP_AXI_PROT_EN_1_STA),
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_CAM_STEP2,
- MT8186_TOP_AXI_PROT_EN_1_SET,
- MT8186_TOP_AXI_PROT_EN_1_CLR,
- MT8186_TOP_AXI_PROT_EN_1_STA),
- },
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8186_POWER_DOMAIN_CAM_RAWA] = {
- .name = "cam_rawa",
- .sta_mask = BIT(24),
- .ctl_offs = 0x360,
- .pwr_sta_offs = 0x16C,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = BIT(8),
- .sram_pdn_ack_bits = BIT(12),
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8186_POWER_DOMAIN_CAM_RAWB] = {
- .name = "cam_rawb",
- .sta_mask = BIT(25),
- .ctl_offs = 0x364,
- .pwr_sta_offs = 0x16C,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = BIT(8),
- .sram_pdn_ack_bits = BIT(12),
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8186_POWER_DOMAIN_VENC] = {
- .name = "venc",
- .sta_mask = BIT(18),
- .ctl_offs = 0x348,
- .pwr_sta_offs = 0x16C,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = BIT(8),
- .sram_pdn_ack_bits = BIT(12),
- .bp_infracfg = {
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_VENC_STEP1,
- MT8186_TOP_AXI_PROT_EN_1_SET,
- MT8186_TOP_AXI_PROT_EN_1_CLR,
- MT8186_TOP_AXI_PROT_EN_1_STA),
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_VENC_STEP2,
- MT8186_TOP_AXI_PROT_EN_1_SET,
- MT8186_TOP_AXI_PROT_EN_1_CLR,
- MT8186_TOP_AXI_PROT_EN_1_STA),
- },
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8186_POWER_DOMAIN_VDEC] = {
- .name = "vdec",
- .sta_mask = BIT(16),
- .ctl_offs = 0x340,
- .pwr_sta_offs = 0x16C,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = BIT(8),
- .sram_pdn_ack_bits = BIT(12),
- .bp_infracfg = {
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_VDEC_STEP1,
- MT8186_TOP_AXI_PROT_EN_1_SET,
- MT8186_TOP_AXI_PROT_EN_1_CLR,
- MT8186_TOP_AXI_PROT_EN_1_STA),
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_VDEC_STEP2,
- MT8186_TOP_AXI_PROT_EN_1_SET,
- MT8186_TOP_AXI_PROT_EN_1_CLR,
- MT8186_TOP_AXI_PROT_EN_1_STA),
- },
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8186_POWER_DOMAIN_WPE] = {
- .name = "wpe",
- .sta_mask = BIT(0),
- .ctl_offs = 0x3F8,
- .pwr_sta_offs = 0x16C,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = BIT(8),
- .sram_pdn_ack_bits = BIT(12),
- .bp_infracfg = {
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_2_WPE_STEP1,
- MT8186_TOP_AXI_PROT_EN_2_SET,
- MT8186_TOP_AXI_PROT_EN_2_CLR,
- MT8186_TOP_AXI_PROT_EN_2_STA),
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_2_WPE_STEP2,
- MT8186_TOP_AXI_PROT_EN_2_SET,
- MT8186_TOP_AXI_PROT_EN_2_CLR,
- MT8186_TOP_AXI_PROT_EN_2_STA),
- },
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8186_POWER_DOMAIN_CONN_ON] = {
- .name = "conn_on",
- .sta_mask = BIT(1),
- .ctl_offs = 0x304,
- .pwr_sta_offs = 0x16C,
- .pwr_sta2nd_offs = 0x170,
- .bp_infracfg = {
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_CONN_ON_STEP1,
- MT8186_TOP_AXI_PROT_EN_1_SET,
- MT8186_TOP_AXI_PROT_EN_1_CLR,
- MT8186_TOP_AXI_PROT_EN_1_STA),
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_CONN_ON_STEP2,
- MT8186_TOP_AXI_PROT_EN_SET,
- MT8186_TOP_AXI_PROT_EN_CLR,
- MT8186_TOP_AXI_PROT_EN_STA),
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_CONN_ON_STEP3,
- MT8186_TOP_AXI_PROT_EN_SET,
- MT8186_TOP_AXI_PROT_EN_CLR,
- MT8186_TOP_AXI_PROT_EN_STA),
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_CONN_ON_STEP4,
- MT8186_TOP_AXI_PROT_EN_SET,
- MT8186_TOP_AXI_PROT_EN_CLR,
- MT8186_TOP_AXI_PROT_EN_STA),
- },
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT8186_POWER_DOMAIN_CSIRX_TOP] = {
- .name = "csirx_top",
- .sta_mask = BIT(6),
- .ctl_offs = 0x318,
- .pwr_sta_offs = 0x16C,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = BIT(8),
- .sram_pdn_ack_bits = BIT(12),
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8186_POWER_DOMAIN_ADSP_AO] = {
- .name = "adsp_ao",
- .sta_mask = BIT(17),
- .ctl_offs = 0x9FC,
- .pwr_sta_offs = 0x16C,
- .pwr_sta2nd_offs = 0x170,
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8186_POWER_DOMAIN_ADSP_INFRA] = {
- .name = "adsp_infra",
- .sta_mask = BIT(10),
- .ctl_offs = 0x9F8,
- .pwr_sta_offs = 0x16C,
- .pwr_sta2nd_offs = 0x170,
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8186_POWER_DOMAIN_ADSP_TOP] = {
- .name = "adsp_top",
- .sta_mask = BIT(31),
- .ctl_offs = 0x3E4,
- .pwr_sta_offs = 0x16C,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = BIT(8),
- .sram_pdn_ack_bits = BIT(12),
- .bp_infracfg = {
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_3_ADSP_TOP_STEP1,
- MT8186_TOP_AXI_PROT_EN_3_SET,
- MT8186_TOP_AXI_PROT_EN_3_CLR,
- MT8186_TOP_AXI_PROT_EN_3_STA),
- BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_3_ADSP_TOP_STEP2,
- MT8186_TOP_AXI_PROT_EN_3_SET,
- MT8186_TOP_AXI_PROT_EN_3_CLR,
- MT8186_TOP_AXI_PROT_EN_3_STA),
- },
- .caps = MTK_SCPD_SRAM_ISO | MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_ACTIVE_WAKEUP,
- },
-};
-
-static const struct scpsys_soc_data mt8186_scpsys_data = {
- .domains_data = scpsys_domain_data_mt8186,
- .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8186),
-};
-
-#endif /* __SOC_MEDIATEK_MT8186_PM_DOMAINS_H */
diff --git a/drivers/soc/mediatek/mt8188-mmsys.h b/drivers/soc/mediatek/mt8188-mmsys.h
new file mode 100644
index 000000000000..99080afead7e
--- /dev/null
+++ b/drivers/soc/mediatek/mt8188-mmsys.h
@@ -0,0 +1,327 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_MT8188_MMSYS_H
+#define __SOC_MEDIATEK_MT8188_MMSYS_H
+
+#include <linux/soc/mediatek/mtk-mmsys.h>
+#include <dt-bindings/reset/mt8188-resets.h>
+
+#define MT8188_VDO0_SW0_RST_B 0x190
+#define MT8188_VDO0_OVL_MOUT_EN 0xf14
+#define MT8188_MOUT_DISP_OVL0_TO_DISP_RDMA0 BIT(0)
+#define MT8188_MOUT_DISP_OVL0_TO_DISP_WDMA0 BIT(1)
+#define MT8188_MOUT_DISP_OVL0_TO_DISP_OVL1 BIT(2)
+#define MT8188_MOUT_DISP_OVL1_TO_DISP_RDMA1 BIT(4)
+#define MT8188_MOUT_DISP_OVL1_TO_DISP_WDMA1 BIT(5)
+#define MT8188_MOUT_DISP_OVL1_TO_DISP_OVL0 BIT(6)
+
+#define MT8188_VDO0_SEL_IN 0xf34
+#define MT8188_VDO0_SEL_OUT 0xf38
+
+#define MT8188_VDO0_DISP_RDMA_SEL 0xf40
+#define MT8188_SOUT_DISP_RDMA0_TO_MASK GENMASK(2, 0)
+#define MT8188_SOUT_DISP_RDMA0_TO_DISP_COLOR0 (0 << 0)
+#define MT8188_SOUT_DISP_RDMA0_TO_DISP_DSI0 (1 << 0)
+#define MT8188_SOUT_DISP_RDMA0_TO_DISP_DP_INTF0 (5 << 0)
+#define MT8188_SEL_IN_DISP_RDMA0_FROM_MASK GENMASK(8, 8)
+#define MT8188_SEL_IN_DISP_RDMA0_FROM_DISP_OVL0 (0 << 8)
+#define MT8188_SEL_IN_DISP_RDMA0_FROM_DISP_RSZ0 (1 << 8)
+
+
+#define MT8188_VDO0_DSI0_SEL_IN 0xf44
+#define MT8188_SEL_IN_DSI0_FROM_MASK BIT(0)
+#define MT8188_SEL_IN_DSI0_FROM_DSC_WRAP0_OUT (0 << 0)
+#define MT8188_SEL_IN_DSI0_FROM_DISP_DITHER0 (1 << 0)
+
+#define MT8188_VDO0_DP_INTF0_SEL_IN 0xf4C
+#define MT8188_SEL_IN_DP_INTF0_FROM_MASK GENMASK(2, 0)
+#define MT8188_SEL_IN_DP_INTF0_FROM_DSC_WRAP0C1_OUT (0 << 0)
+#define MT8188_SEL_IN_DP_INTF0_FROM_VPP_MERGE (1 << 0)
+#define MT8188_SEL_IN_DP_INTF0_FROM_DISP_DITHER0 (3 << 0)
+
+#define MT8188_VDO0_DISP_DITHER0_SEL_OUT 0xf58
+#define MT8188_SOUT_DISP_DITHER0_TO_MASK GENMASK(2, 0)
+#define MT8188_SOUT_DISP_DITHER0_TO_DSC_WRAP0_IN (0 << 0)
+#define MT8188_SOUT_DISP_DITHER0_TO_DSI0 (1 << 0)
+#define MT8188_SOUT_DISP_DITHER0_TO_VPP_MERGE0 (6 << 0)
+#define MT8188_SOUT_DISP_DITHER0_TO_DP_INTF0 (7 << 0)
+
+#define MT8188_VDO0_VPP_MERGE_SEL 0xf60
+#define MT8188_SEL_IN_VPP_MERGE_FROM_MASK GENMASK(1, 0)
+#define MT8188_SEL_IN_VPP_MERGE_FROM_DSC_WRAP0_OUT (0 << 0)
+#define MT8188_SEL_IN_VPP_MERGE_FROM_DITHER0_OUT (3 << 0)
+
+#define MT8188_SOUT_VPP_MERGE_TO_MASK GENMASK(6, 4)
+#define MT8188_SOUT_VPP_MERGE_TO_DSI1 (0 << 4)
+#define MT8188_SOUT_VPP_MERGE_TO_DP_INTF0 (1 << 4)
+#define MT8188_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0 (2 << 4)
+#define MT8188_SOUT_VPP_MERGE_TO_DISP_WDMA1 (3 << 4)
+#define MT8188_SOUT_VPP_MERGE_TO_DSC_WRAP0_IN (4 << 4)
+#define MT8188_SOUT_VPP_MERGE_TO_DISP_WDMA0 (5 << 4)
+#define MT8188_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN_MASK GENMASK(11, 11)
+#define MT8188_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN (0 << 11)
+
+#define MT8188_VDO0_DSC_WARP_SEL 0xf64
+#define MT8188_SEL_IN_DSC_WRAP0C0_IN_FROM_MASK GENMASK(0, 0)
+#define MT8188_SEL_IN_DSC_WRAP0C0_IN_FROM_DISP_DITHER0 (0 << 0)
+#define MT8188_SEL_IN_DSC_WRAP0C0_IN_FROM_VPP_MERGE (1 << 0)
+#define MT8188_SOUT_DSC_WRAP0_OUT_TO_MASK GENMASK(19, 16)
+#define MT8188_SOUT_DSC_WRAP0_OUT_TO_DSI0 BIT(16)
+#define MT8188_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0 BIT(17)
+#define MT8188_SOUT_DSC_WRAP0_OUT_TO_VPP_MERGE BIT(18)
+#define MT8188_SOUT_DSC_WRAP0_OUT_TO_DISP_WDMA0 BIT(19)
+
+#define MT8188_VDO1_SW0_RST_B 0x1d0
+#define MT8188_VDO1_HDR_TOP_CFG 0xd00
+#define MT8188_VDO1_MIXER_IN1_ALPHA 0xd30
+#define MT8188_VDO1_MIXER_IN1_PAD 0xd40
+#define MT8188_VDO1_MIXER_VSYNC_LEN 0xd5c
+#define MT8188_VDO1_MERGE0_ASYNC_CFG_WD 0xe30
+#define MT8188_VDO1_HDRBE_ASYNC_CFG_WD 0xe70
+#define MT8188_VDO1_VPP_MERGE0_P0_SEL_IN 0xf04
+#define MT8188_VPP_MERGE0_P0_SEL_IN_FROM_MDP_RDMA0 1
+#define MT8188_VDO1_VPP_MERGE0_P1_SEL_IN 0xf08
+#define MT8188_VPP_MERGE0_P1_SEL_IN_FROM_MDP_RDMA1 1
+#define MT8188_VDO1_DISP_DPI1_SEL_IN 0xf10
+#define MT8188_DISP_DPI1_SEL_IN_FROM_VPP_MERGE4_MOUT 0
+#define MT8188_VDO1_DISP_DP_INTF0_SEL_IN 0xf14
+#define MT8188_DISP_DP_INTF0_SEL_IN_FROM_VPP_MERGE4_MOUT 0
+#define MT8188_VDO1_MERGE4_SOUT_SEL 0xf18
+#define MT8188_MERGE4_SOUT_TO_DPI1_SEL BIT(2)
+#define MT8188_MERGE4_SOUT_TO_DP_INTF0_SEL BIT(3)
+#define MT8188_VDO1_MIXER_IN1_SEL_IN 0xf24
+#define MT8188_MIXER_IN1_SEL_IN_FROM_MERGE0_ASYNC_SOUT 1
+#define MT8188_VDO1_MIXER_IN2_SEL_IN 0xf28
+#define MT8188_MIXER_IN2_SEL_IN_FROM_MERGE1_ASYNC_SOUT 1
+#define MT8188_VDO1_MIXER_IN3_SEL_IN 0xf2c
+#define MT8188_MIXER_IN3_SEL_IN_FROM_MERGE2_ASYNC_SOUT 1
+#define MT8188_VDO1_MIXER_IN4_SEL_IN 0xf30
+#define MT8188_MIXER_IN4_SEL_IN_FROM_MERGE3_ASYNC_SOUT 1
+#define MT8188_VDO1_MIXER_OUT_SOUT_SEL 0xf34
+#define MT8188_MIXER_SOUT_TO_MERGE4_ASYNC_SEL 1
+#define MT8188_VDO1_VPP_MERGE1_P0_SEL_IN 0xf3c
+#define MT8188_VPP_MERGE1_P0_SEL_IN_FROM_MDP_RDMA2 1
+#define MT8188_VDO1_MERGE0_ASYNC_SOUT_SEL 0xf40
+#define MT8188_SOUT_TO_MIXER_IN1_SEL 1
+#define MT8188_VDO1_MERGE1_ASYNC_SOUT_SEL 0xf44
+#define MT8188_SOUT_TO_MIXER_IN2_SEL 1
+#define MT8188_VDO1_MERGE2_ASYNC_SOUT_SEL 0xf48
+#define MT8188_SOUT_TO_MIXER_IN3_SEL 1
+#define MT8188_VDO1_MERGE3_ASYNC_SOUT_SEL 0xf4c
+#define MT8188_SOUT_TO_MIXER_IN4_SEL 1
+#define MT8188_VDO1_MERGE4_ASYNC_SEL_IN 0xf50
+#define MT8188_MERGE4_ASYNC_SEL_IN_FROM_MIXER_OUT_SOUT 1
+#define MT8188_VDO1_MIXER_IN1_SOUT_SEL 0xf58
+#define MT8188_MIXER_IN1_SOUT_TO_DISP_MIXER 0
+#define MT8188_VDO1_MIXER_IN2_SOUT_SEL 0xf5c
+#define MT8188_MIXER_IN2_SOUT_TO_DISP_MIXER 0
+#define MT8188_VDO1_MIXER_IN3_SOUT_SEL 0xf60
+#define MT8188_MIXER_IN3_SOUT_TO_DISP_MIXER 0
+#define MT8188_VDO1_MIXER_IN4_SOUT_SEL 0xf64
+#define MT8188_MIXER_IN4_SOUT_TO_DISP_MIXER 0
+#define MT8188_VDO1_MIXER_SOUT_SEL_IN 0xf68
+#define MT8188_MIXER_SOUT_SEL_IN_FROM_DISP_MIXER 0
+
+static const u8 mmsys_mt8188_vdo0_rst_tb[] = {
+ [MT8188_VDO0_RST_DISP_OVL0] = MMSYS_RST_NR(0, 0),
+ [MT8188_VDO0_RST_FAKE_ENG0] = MMSYS_RST_NR(0, 2),
+ [MT8188_VDO0_RST_DISP_CCORR0] = MMSYS_RST_NR(0, 4),
+ [MT8188_VDO0_RST_DISP_MUTEX0] = MMSYS_RST_NR(0, 6),
+ [MT8188_VDO0_RST_DISP_GAMMA0] = MMSYS_RST_NR(0, 8),
+ [MT8188_VDO0_RST_DISP_DITHER0] = MMSYS_RST_NR(0, 10),
+ [MT8188_VDO0_RST_DISP_WDMA0] = MMSYS_RST_NR(0, 17),
+ [MT8188_VDO0_RST_DISP_RDMA0] = MMSYS_RST_NR(0, 19),
+ [MT8188_VDO0_RST_DSI0] = MMSYS_RST_NR(0, 21),
+ [MT8188_VDO0_RST_DSI1] = MMSYS_RST_NR(0, 22),
+ [MT8188_VDO0_RST_DSC_WRAP0] = MMSYS_RST_NR(0, 23),
+ [MT8188_VDO0_RST_VPP_MERGE0] = MMSYS_RST_NR(0, 24),
+ [MT8188_VDO0_RST_DP_INTF0] = MMSYS_RST_NR(0, 25),
+ [MT8188_VDO0_RST_DISP_AAL0] = MMSYS_RST_NR(0, 26),
+ [MT8188_VDO0_RST_INLINEROT0] = MMSYS_RST_NR(0, 27),
+ [MT8188_VDO0_RST_APB_BUS] = MMSYS_RST_NR(0, 28),
+ [MT8188_VDO0_RST_DISP_COLOR0] = MMSYS_RST_NR(0, 29),
+ [MT8188_VDO0_RST_MDP_WROT0] = MMSYS_RST_NR(0, 30),
+ [MT8188_VDO0_RST_DISP_RSZ0] = MMSYS_RST_NR(0, 31),
+};
+
+static const u8 mmsys_mt8188_vdo1_rst_tb[] = {
+ [MT8188_VDO1_RST_SMI_LARB2] = MMSYS_RST_NR(0, 0),
+ [MT8188_VDO1_RST_SMI_LARB3] = MMSYS_RST_NR(0, 1),
+ [MT8188_VDO1_RST_GALS] = MMSYS_RST_NR(0, 2),
+ [MT8188_VDO1_RST_FAKE_ENG0] = MMSYS_RST_NR(0, 3),
+ [MT8188_VDO1_RST_FAKE_ENG1] = MMSYS_RST_NR(0, 4),
+ [MT8188_VDO1_RST_MDP_RDMA0] = MMSYS_RST_NR(0, 5),
+ [MT8188_VDO1_RST_MDP_RDMA1] = MMSYS_RST_NR(0, 6),
+ [MT8188_VDO1_RST_MDP_RDMA2] = MMSYS_RST_NR(0, 7),
+ [MT8188_VDO1_RST_MDP_RDMA3] = MMSYS_RST_NR(0, 8),
+ [MT8188_VDO1_RST_VPP_MERGE0] = MMSYS_RST_NR(0, 9),
+ [MT8188_VDO1_RST_VPP_MERGE1] = MMSYS_RST_NR(0, 10),
+ [MT8188_VDO1_RST_VPP_MERGE2] = MMSYS_RST_NR(0, 11),
+ [MT8188_VDO1_RST_VPP_MERGE3] = MMSYS_RST_NR(1, 0),
+ [MT8188_VDO1_RST_VPP_MERGE4] = MMSYS_RST_NR(1, 1),
+ [MT8188_VDO1_RST_VPP2_TO_VDO1_DL_ASYNC] = MMSYS_RST_NR(1, 2),
+ [MT8188_VDO1_RST_VPP3_TO_VDO1_DL_ASYNC] = MMSYS_RST_NR(1, 3),
+ [MT8188_VDO1_RST_DISP_MUTEX] = MMSYS_RST_NR(1, 4),
+ [MT8188_VDO1_RST_MDP_RDMA4] = MMSYS_RST_NR(1, 5),
+ [MT8188_VDO1_RST_MDP_RDMA5] = MMSYS_RST_NR(1, 6),
+ [MT8188_VDO1_RST_MDP_RDMA6] = MMSYS_RST_NR(1, 7),
+ [MT8188_VDO1_RST_MDP_RDMA7] = MMSYS_RST_NR(1, 8),
+ [MT8188_VDO1_RST_DP_INTF1_MMCK] = MMSYS_RST_NR(1, 9),
+ [MT8188_VDO1_RST_DPI0_MM_CK] = MMSYS_RST_NR(1, 10),
+ [MT8188_VDO1_RST_DPI1_MM_CK] = MMSYS_RST_NR(1, 11),
+ [MT8188_VDO1_RST_MERGE0_DL_ASYNC] = MMSYS_RST_NR(1, 13),
+ [MT8188_VDO1_RST_MERGE1_DL_ASYNC] = MMSYS_RST_NR(1, 14),
+ [MT8188_VDO1_RST_MERGE2_DL_ASYNC] = MMSYS_RST_NR(1, 15),
+ [MT8188_VDO1_RST_MERGE3_DL_ASYNC] = MMSYS_RST_NR(1, 16),
+ [MT8188_VDO1_RST_MERGE4_DL_ASYNC] = MMSYS_RST_NR(1, 17),
+ [MT8188_VDO1_RST_VDO0_DSC_TO_VDO1_DL_ASYNC] = MMSYS_RST_NR(1, 18),
+ [MT8188_VDO1_RST_VDO0_MERGE_TO_VDO1_DL_ASYNC] = MMSYS_RST_NR(1, 19),
+ [MT8188_VDO1_RST_PADDING0] = MMSYS_RST_NR(1, 20),
+ [MT8188_VDO1_RST_PADDING1] = MMSYS_RST_NR(1, 21),
+ [MT8188_VDO1_RST_PADDING2] = MMSYS_RST_NR(1, 22),
+ [MT8188_VDO1_RST_PADDING3] = MMSYS_RST_NR(1, 23),
+ [MT8188_VDO1_RST_PADDING4] = MMSYS_RST_NR(1, 24),
+ [MT8188_VDO1_RST_PADDING5] = MMSYS_RST_NR(1, 25),
+ [MT8188_VDO1_RST_PADDING6] = MMSYS_RST_NR(1, 26),
+ [MT8188_VDO1_RST_PADDING7] = MMSYS_RST_NR(1, 27),
+ [MT8188_VDO1_RST_DISP_RSZ0] = MMSYS_RST_NR(1, 28),
+ [MT8188_VDO1_RST_DISP_RSZ1] = MMSYS_RST_NR(1, 29),
+ [MT8188_VDO1_RST_DISP_RSZ2] = MMSYS_RST_NR(1, 30),
+ [MT8188_VDO1_RST_DISP_RSZ3] = MMSYS_RST_NR(1, 31),
+ [MT8188_VDO1_RST_HDR_VDO_FE0] = MMSYS_RST_NR(2, 0),
+ [MT8188_VDO1_RST_HDR_GFX_FE0] = MMSYS_RST_NR(2, 1),
+ [MT8188_VDO1_RST_HDR_VDO_BE] = MMSYS_RST_NR(2, 2),
+ [MT8188_VDO1_RST_HDR_VDO_FE1] = MMSYS_RST_NR(2, 16),
+ [MT8188_VDO1_RST_HDR_GFX_FE1] = MMSYS_RST_NR(2, 17),
+ [MT8188_VDO1_RST_DISP_MIXER] = MMSYS_RST_NR(2, 18),
+ [MT8188_VDO1_RST_HDR_VDO_FE0_DL_ASYNC] = MMSYS_RST_NR(2, 19),
+ [MT8188_VDO1_RST_HDR_VDO_FE1_DL_ASYNC] = MMSYS_RST_NR(2, 20),
+ [MT8188_VDO1_RST_HDR_GFX_FE0_DL_ASYNC] = MMSYS_RST_NR(2, 21),
+ [MT8188_VDO1_RST_HDR_GFX_FE1_DL_ASYNC] = MMSYS_RST_NR(2, 22),
+ [MT8188_VDO1_RST_HDR_VDO_BE_DL_ASYNC] = MMSYS_RST_NR(2, 23),
+};
+
+static const struct mtk_mmsys_routes mmsys_mt8188_routing_table[] = {
+ MMSYS_ROUTE(OVL0, RDMA0,
+ MT8188_VDO0_OVL_MOUT_EN, MT8188_MOUT_DISP_OVL0_TO_DISP_RDMA0,
+ MT8188_MOUT_DISP_OVL0_TO_DISP_RDMA0),
+ MMSYS_ROUTE(OVL0, WDMA0,
+ MT8188_VDO0_OVL_MOUT_EN, MT8188_MOUT_DISP_OVL0_TO_DISP_WDMA0,
+ MT8188_MOUT_DISP_OVL0_TO_DISP_WDMA0),
+ MMSYS_ROUTE(OVL0, RDMA0,
+ MT8188_VDO0_DISP_RDMA_SEL, MT8188_SEL_IN_DISP_RDMA0_FROM_MASK,
+ MT8188_SEL_IN_DISP_RDMA0_FROM_DISP_OVL0),
+ MMSYS_ROUTE(DITHER0, DSI0,
+ MT8188_VDO0_DSI0_SEL_IN, MT8188_SEL_IN_DSI0_FROM_MASK,
+ MT8188_SEL_IN_DSI0_FROM_DISP_DITHER0),
+ MMSYS_ROUTE(DITHER0, MERGE0,
+ MT8188_VDO0_VPP_MERGE_SEL, MT8188_SEL_IN_VPP_MERGE_FROM_MASK,
+ MT8188_SEL_IN_DP_INTF0_FROM_DISP_DITHER0),
+ MMSYS_ROUTE(DITHER0, DSC0,
+ MT8188_VDO0_DSC_WARP_SEL, MT8188_SEL_IN_DSC_WRAP0C0_IN_FROM_MASK,
+ MT8188_SEL_IN_DSC_WRAP0C0_IN_FROM_DISP_DITHER0),
+ MMSYS_ROUTE(DITHER0, DP_INTF0,
+ MT8188_VDO0_DP_INTF0_SEL_IN, MT8188_SEL_IN_DP_INTF0_FROM_MASK,
+ MT8188_SEL_IN_DP_INTF0_FROM_DISP_DITHER0),
+ MMSYS_ROUTE(DSC0, MERGE0,
+ MT8188_VDO0_VPP_MERGE_SEL, MT8188_SEL_IN_VPP_MERGE_FROM_MASK,
+ MT8188_SEL_IN_VPP_MERGE_FROM_DSC_WRAP0_OUT),
+ MMSYS_ROUTE(MERGE0, DP_INTF0,
+ MT8188_VDO0_DP_INTF0_SEL_IN, MT8188_SEL_IN_DP_INTF0_FROM_MASK,
+ MT8188_SEL_IN_DP_INTF0_FROM_VPP_MERGE),
+ MMSYS_ROUTE(DSC0, DSI0,
+ MT8188_VDO0_DSI0_SEL_IN, MT8188_SEL_IN_DSI0_FROM_MASK,
+ MT8188_SEL_IN_DSI0_FROM_DSC_WRAP0_OUT),
+ MMSYS_ROUTE(RDMA0, COLOR0,
+ MT8188_VDO0_DISP_RDMA_SEL, GENMASK(1, 0),
+ MT8188_SOUT_DISP_RDMA0_TO_DISP_COLOR0),
+ MMSYS_ROUTE(DITHER0, DSC0,
+ MT8188_VDO0_DISP_DITHER0_SEL_OUT, MT8188_SOUT_DISP_DITHER0_TO_MASK,
+ MT8188_SOUT_DISP_DITHER0_TO_DSC_WRAP0_IN),
+ MMSYS_ROUTE(DITHER0, DSI0,
+ MT8188_VDO0_DISP_DITHER0_SEL_OUT, MT8188_SOUT_DISP_DITHER0_TO_MASK,
+ MT8188_SOUT_DISP_DITHER0_TO_DSI0),
+ MMSYS_ROUTE(DITHER0, MERGE0,
+ MT8188_VDO0_DISP_DITHER0_SEL_OUT, MT8188_SOUT_DISP_DITHER0_TO_MASK,
+ MT8188_SOUT_DISP_DITHER0_TO_VPP_MERGE0),
+ MMSYS_ROUTE(DITHER0, DP_INTF0,
+ MT8188_VDO0_DISP_DITHER0_SEL_OUT, MT8188_SOUT_DISP_DITHER0_TO_MASK,
+ MT8188_SOUT_DISP_DITHER0_TO_DP_INTF0),
+ MMSYS_ROUTE(MERGE0, DP_INTF0,
+ MT8188_VDO0_VPP_MERGE_SEL, MT8188_SOUT_VPP_MERGE_TO_MASK,
+ MT8188_SOUT_VPP_MERGE_TO_DP_INTF0),
+ MMSYS_ROUTE(MERGE0, DPI0,
+ MT8188_VDO0_VPP_MERGE_SEL, MT8188_SOUT_VPP_MERGE_TO_MASK,
+ MT8188_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0),
+ MMSYS_ROUTE(MERGE0, WDMA0,
+ MT8188_VDO0_VPP_MERGE_SEL, MT8188_SOUT_VPP_MERGE_TO_MASK,
+ MT8188_SOUT_VPP_MERGE_TO_DISP_WDMA0),
+ MMSYS_ROUTE(MERGE0, DSC0,
+ MT8188_VDO0_VPP_MERGE_SEL, MT8188_SOUT_VPP_MERGE_TO_MASK,
+ MT8188_SOUT_VPP_MERGE_TO_DSC_WRAP0_IN),
+ MMSYS_ROUTE(DSC0, DSI0,
+ MT8188_VDO0_DSC_WARP_SEL, MT8188_SOUT_DSC_WRAP0_OUT_TO_MASK,
+ MT8188_SOUT_DSC_WRAP0_OUT_TO_DSI0),
+ MMSYS_ROUTE(DSC0, MERGE0,
+ MT8188_VDO0_DSC_WARP_SEL, MT8188_SOUT_DSC_WRAP0_OUT_TO_MASK,
+ MT8188_SOUT_DSC_WRAP0_OUT_TO_VPP_MERGE),
+};
+
+static const struct mtk_mmsys_routes mmsys_mt8188_vdo1_routing_table[] = {
+ MMSYS_ROUTE(MDP_RDMA0, MERGE1,
+ MT8188_VDO1_VPP_MERGE0_P0_SEL_IN, GENMASK(0, 0),
+ MT8188_VPP_MERGE0_P0_SEL_IN_FROM_MDP_RDMA0),
+ MMSYS_ROUTE(MDP_RDMA1, MERGE1,
+ MT8188_VDO1_VPP_MERGE0_P1_SEL_IN, GENMASK(0, 0),
+ MT8188_VPP_MERGE0_P1_SEL_IN_FROM_MDP_RDMA1),
+ MMSYS_ROUTE(MDP_RDMA2, MERGE2,
+ MT8188_VDO1_VPP_MERGE1_P0_SEL_IN, GENMASK(0, 0),
+ MT8188_VPP_MERGE1_P0_SEL_IN_FROM_MDP_RDMA2),
+ MMSYS_ROUTE(MERGE1, ETHDR_MIXER,
+ MT8188_VDO1_MERGE0_ASYNC_SOUT_SEL, GENMASK(1, 0),
+ MT8188_SOUT_TO_MIXER_IN1_SEL),
+ MMSYS_ROUTE(MERGE2, ETHDR_MIXER,
+ MT8188_VDO1_MERGE1_ASYNC_SOUT_SEL, GENMASK(1, 0),
+ MT8188_SOUT_TO_MIXER_IN2_SEL),
+ MMSYS_ROUTE(MERGE3, ETHDR_MIXER,
+ MT8188_VDO1_MERGE2_ASYNC_SOUT_SEL, GENMASK(1, 0),
+ MT8188_SOUT_TO_MIXER_IN3_SEL),
+ MMSYS_ROUTE(MERGE4, ETHDR_MIXER,
+ MT8188_VDO1_MERGE3_ASYNC_SOUT_SEL, GENMASK(1, 0),
+ MT8188_SOUT_TO_MIXER_IN4_SEL),
+ MMSYS_ROUTE(ETHDR_MIXER, MERGE5,
+ MT8188_VDO1_MIXER_OUT_SOUT_SEL, GENMASK(0, 0),
+ MT8188_MIXER_SOUT_TO_MERGE4_ASYNC_SEL),
+ MMSYS_ROUTE(MERGE1, ETHDR_MIXER,
+ MT8188_VDO1_MIXER_IN1_SEL_IN, GENMASK(0, 0),
+ MT8188_MIXER_IN1_SEL_IN_FROM_MERGE0_ASYNC_SOUT),
+ MMSYS_ROUTE(MERGE2, ETHDR_MIXER,
+ MT8188_VDO1_MIXER_IN2_SEL_IN, GENMASK(0, 0),
+ MT8188_MIXER_IN2_SEL_IN_FROM_MERGE1_ASYNC_SOUT),
+ MMSYS_ROUTE(MERGE3, ETHDR_MIXER,
+ MT8188_VDO1_MIXER_IN3_SEL_IN, GENMASK(0, 0),
+ MT8188_MIXER_IN3_SEL_IN_FROM_MERGE2_ASYNC_SOUT),
+ MMSYS_ROUTE(MERGE4, ETHDR_MIXER,
+ MT8188_VDO1_MIXER_IN4_SEL_IN, GENMASK(0, 0),
+ MT8188_MIXER_IN4_SEL_IN_FROM_MERGE3_ASYNC_SOUT),
+ MMSYS_ROUTE(ETHDR_MIXER, MERGE5,
+ MT8188_VDO1_MIXER_SOUT_SEL_IN, GENMASK(2, 0),
+ MT8188_MIXER_SOUT_SEL_IN_FROM_DISP_MIXER),
+ MMSYS_ROUTE(ETHDR_MIXER, MERGE5,
+ MT8188_VDO1_MERGE4_ASYNC_SEL_IN, GENMASK(2, 0),
+ MT8188_MERGE4_ASYNC_SEL_IN_FROM_MIXER_OUT_SOUT),
+ MMSYS_ROUTE(MERGE5, DPI1,
+ MT8188_VDO1_DISP_DPI1_SEL_IN, GENMASK(1, 0),
+ MT8188_DISP_DPI1_SEL_IN_FROM_VPP_MERGE4_MOUT),
+ MMSYS_ROUTE(MERGE5, DPI1,
+ MT8188_VDO1_MERGE4_SOUT_SEL, GENMASK(3, 0),
+ MT8188_MERGE4_SOUT_TO_DPI1_SEL),
+ MMSYS_ROUTE(MERGE5, DP_INTF1,
+ MT8188_VDO1_DISP_DP_INTF0_SEL_IN, GENMASK(1, 0),
+ MT8188_DISP_DP_INTF0_SEL_IN_FROM_VPP_MERGE4_MOUT),
+ MMSYS_ROUTE(MERGE5, DP_INTF1,
+ MT8188_VDO1_MERGE4_SOUT_SEL, GENMASK(3, 0),
+ MT8188_MERGE4_SOUT_TO_DP_INTF0_SEL),
+};
+
+#endif /* __SOC_MEDIATEK_MT8188_MMSYS_H */
diff --git a/drivers/soc/mediatek/mt8192-mmsys.h b/drivers/soc/mediatek/mt8192-mmsys.h
index a016d80b4bc1..7cafa2455fd0 100644
--- a/drivers/soc/mediatek/mt8192-mmsys.h
+++ b/drivers/soc/mediatek/mt8192-mmsys.h
@@ -31,47 +31,36 @@
#define MT8192_DSI0_SEL_IN_DITHER0 0x1
static const struct mtk_mmsys_routes mmsys_mt8192_routing_table[] = {
- {
- DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA0,
- MT8192_DISP_OVL0_2L_MOUT_EN, MT8192_OVL0_MOUT_EN_DISP_RDMA0,
- MT8192_OVL0_MOUT_EN_DISP_RDMA0
- }, {
- DDP_COMPONENT_OVL_2L2, DDP_COMPONENT_RDMA4,
- MT8192_DISP_OVL2_2L_MOUT_EN, MT8192_OVL2_2L_MOUT_EN_RDMA4,
- MT8192_OVL2_2L_MOUT_EN_RDMA4
- }, {
- DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0,
- MT8192_DISP_DITHER0_MOUT_EN, MT8192_DITHER0_MOUT_IN_DSI0,
- MT8192_DITHER0_MOUT_IN_DSI0
- }, {
- DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA0,
- MT8192_DISP_RDMA0_SEL_IN, MT8192_RDMA0_SEL_IN_OVL0_2L,
- MT8192_RDMA0_SEL_IN_OVL0_2L
- }, {
- DDP_COMPONENT_CCORR, DDP_COMPONENT_AAL0,
- MT8192_DISP_AAL0_SEL_IN, MT8192_AAL0_SEL_IN_CCORR0,
- MT8192_AAL0_SEL_IN_CCORR0
- }, {
- DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0,
- MT8192_DISP_DSI0_SEL_IN, MT8192_DSI0_SEL_IN_DITHER0,
- MT8192_DSI0_SEL_IN_DITHER0
- }, {
- DDP_COMPONENT_RDMA0, DDP_COMPONENT_COLOR0,
- MT8192_DISP_RDMA0_SOUT_SEL, MT8192_RDMA0_SOUT_COLOR0,
- MT8192_RDMA0_SOUT_COLOR0
- }, {
- DDP_COMPONENT_CCORR, DDP_COMPONENT_AAL0,
- MT8192_DISP_CCORR0_SOUT_SEL, MT8192_CCORR0_SOUT_AAL0,
- MT8192_CCORR0_SOUT_AAL0
- }, {
- DDP_COMPONENT_OVL0, DDP_COMPONENT_OVL_2L0,
- MT8192_MMSYS_OVL_MOUT_EN, MT8192_DISP_OVL0_GO_BG,
- MT8192_DISP_OVL0_GO_BG
- }, {
- DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA0,
- MT8192_MMSYS_OVL_MOUT_EN, MT8192_DISP_OVL0_2L_GO_BLEND,
- MT8192_DISP_OVL0_2L_GO_BLEND
- }
+ MMSYS_ROUTE(OVL_2L0, RDMA0,
+ MT8192_DISP_OVL0_2L_MOUT_EN, MT8192_OVL0_MOUT_EN_DISP_RDMA0,
+ MT8192_OVL0_MOUT_EN_DISP_RDMA0),
+ MMSYS_ROUTE(OVL_2L2, RDMA4,
+ MT8192_DISP_OVL2_2L_MOUT_EN, MT8192_OVL2_2L_MOUT_EN_RDMA4,
+ MT8192_OVL2_2L_MOUT_EN_RDMA4),
+ MMSYS_ROUTE(DITHER0, DSI0,
+ MT8192_DISP_DITHER0_MOUT_EN, MT8192_DITHER0_MOUT_IN_DSI0,
+ MT8192_DITHER0_MOUT_IN_DSI0),
+ MMSYS_ROUTE(OVL_2L0, RDMA0,
+ MT8192_DISP_RDMA0_SEL_IN, MT8192_RDMA0_SEL_IN_OVL0_2L,
+ MT8192_RDMA0_SEL_IN_OVL0_2L),
+ MMSYS_ROUTE(CCORR, AAL0,
+ MT8192_DISP_AAL0_SEL_IN, MT8192_AAL0_SEL_IN_CCORR0,
+ MT8192_AAL0_SEL_IN_CCORR0),
+ MMSYS_ROUTE(DITHER0, DSI0,
+ MT8192_DISP_DSI0_SEL_IN, MT8192_DSI0_SEL_IN_DITHER0,
+ MT8192_DSI0_SEL_IN_DITHER0),
+ MMSYS_ROUTE(RDMA0, COLOR0,
+ MT8192_DISP_RDMA0_SOUT_SEL, MT8192_RDMA0_SOUT_COLOR0,
+ MT8192_RDMA0_SOUT_COLOR0),
+ MMSYS_ROUTE(CCORR, AAL0,
+ MT8192_DISP_CCORR0_SOUT_SEL, MT8192_CCORR0_SOUT_AAL0,
+ MT8192_CCORR0_SOUT_AAL0),
+ MMSYS_ROUTE(OVL0, OVL_2L0,
+ MT8192_MMSYS_OVL_MOUT_EN, MT8192_DISP_OVL0_GO_BG,
+ MT8192_DISP_OVL0_GO_BG),
+ MMSYS_ROUTE(OVL_2L0, RDMA0,
+ MT8192_MMSYS_OVL_MOUT_EN, MT8192_DISP_OVL0_2L_GO_BLEND,
+ MT8192_DISP_OVL0_2L_GO_BLEND),
};
#endif /* __SOC_MEDIATEK_MT8192_MMSYS_H */
diff --git a/drivers/soc/mediatek/mt8192-pm-domains.h b/drivers/soc/mediatek/mt8192-pm-domains.h
deleted file mode 100644
index b97b2051920f..000000000000
--- a/drivers/soc/mediatek/mt8192-pm-domains.h
+++ /dev/null
@@ -1,355 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-
-#ifndef __SOC_MEDIATEK_MT8192_PM_DOMAINS_H
-#define __SOC_MEDIATEK_MT8192_PM_DOMAINS_H
-
-#include "mtk-pm-domains.h"
-#include <dt-bindings/power/mt8192-power.h>
-
-/*
- * MT8192 power domain support
- */
-
-static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
- [MT8192_POWER_DOMAIN_AUDIO] = {
- .name = "audio",
- .sta_mask = BIT(21),
- .ctl_offs = 0x0354,
- .pwr_sta_offs = 0x016c,
- .pwr_sta2nd_offs = 0x0170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_2_AUDIO,
- MT8192_TOP_AXI_PROT_EN_2_SET,
- MT8192_TOP_AXI_PROT_EN_2_CLR,
- MT8192_TOP_AXI_PROT_EN_2_STA1),
- },
- },
- [MT8192_POWER_DOMAIN_CONN] = {
- .name = "conn",
- .sta_mask = PWR_STATUS_CONN,
- .ctl_offs = 0x0304,
- .pwr_sta_offs = 0x016c,
- .pwr_sta2nd_offs = 0x0170,
- .sram_pdn_bits = 0,
- .sram_pdn_ack_bits = 0,
- .bp_infracfg = {
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_CONN,
- MT8192_TOP_AXI_PROT_EN_SET,
- MT8192_TOP_AXI_PROT_EN_CLR,
- MT8192_TOP_AXI_PROT_EN_STA1),
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_CONN_2ND,
- MT8192_TOP_AXI_PROT_EN_SET,
- MT8192_TOP_AXI_PROT_EN_CLR,
- MT8192_TOP_AXI_PROT_EN_STA1),
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_1_CONN,
- MT8192_TOP_AXI_PROT_EN_1_SET,
- MT8192_TOP_AXI_PROT_EN_1_CLR,
- MT8192_TOP_AXI_PROT_EN_1_STA1),
- },
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8192_POWER_DOMAIN_MFG0] = {
- .name = "mfg0",
- .sta_mask = BIT(2),
- .ctl_offs = 0x0308,
- .pwr_sta_offs = 0x016c,
- .pwr_sta2nd_offs = 0x0170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .caps = MTK_SCPD_DOMAIN_SUPPLY,
- },
- [MT8192_POWER_DOMAIN_MFG1] = {
- .name = "mfg1",
- .sta_mask = BIT(3),
- .ctl_offs = 0x030c,
- .pwr_sta_offs = 0x016c,
- .pwr_sta2nd_offs = 0x0170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_1_MFG1,
- MT8192_TOP_AXI_PROT_EN_1_SET,
- MT8192_TOP_AXI_PROT_EN_1_CLR,
- MT8192_TOP_AXI_PROT_EN_1_STA1),
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_2_MFG1,
- MT8192_TOP_AXI_PROT_EN_2_SET,
- MT8192_TOP_AXI_PROT_EN_2_CLR,
- MT8192_TOP_AXI_PROT_EN_2_STA1),
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MFG1,
- MT8192_TOP_AXI_PROT_EN_SET,
- MT8192_TOP_AXI_PROT_EN_CLR,
- MT8192_TOP_AXI_PROT_EN_STA1),
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_2_MFG1_2ND,
- MT8192_TOP_AXI_PROT_EN_2_SET,
- MT8192_TOP_AXI_PROT_EN_2_CLR,
- MT8192_TOP_AXI_PROT_EN_2_STA1),
- },
- .caps = MTK_SCPD_DOMAIN_SUPPLY,
- },
- [MT8192_POWER_DOMAIN_MFG2] = {
- .name = "mfg2",
- .sta_mask = BIT(4),
- .ctl_offs = 0x0310,
- .pwr_sta_offs = 0x016c,
- .pwr_sta2nd_offs = 0x0170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- },
- [MT8192_POWER_DOMAIN_MFG3] = {
- .name = "mfg3",
- .sta_mask = BIT(5),
- .ctl_offs = 0x0314,
- .pwr_sta_offs = 0x016c,
- .pwr_sta2nd_offs = 0x0170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- },
- [MT8192_POWER_DOMAIN_MFG4] = {
- .name = "mfg4",
- .sta_mask = BIT(6),
- .ctl_offs = 0x0318,
- .pwr_sta_offs = 0x016c,
- .pwr_sta2nd_offs = 0x0170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- },
- [MT8192_POWER_DOMAIN_MFG5] = {
- .name = "mfg5",
- .sta_mask = BIT(7),
- .ctl_offs = 0x031c,
- .pwr_sta_offs = 0x016c,
- .pwr_sta2nd_offs = 0x0170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- },
- [MT8192_POWER_DOMAIN_MFG6] = {
- .name = "mfg6",
- .sta_mask = BIT(8),
- .ctl_offs = 0x0320,
- .pwr_sta_offs = 0x016c,
- .pwr_sta2nd_offs = 0x0170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- },
- [MT8192_POWER_DOMAIN_DISP] = {
- .name = "disp",
- .sta_mask = BIT(20),
- .ctl_offs = 0x0350,
- .pwr_sta_offs = 0x016c,
- .pwr_sta2nd_offs = 0x0170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR_IGN(MT8192_TOP_AXI_PROT_EN_MM_DISP,
- MT8192_TOP_AXI_PROT_EN_MM_SET,
- MT8192_TOP_AXI_PROT_EN_MM_CLR,
- MT8192_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR_IGN(MT8192_TOP_AXI_PROT_EN_MM_2_DISP,
- MT8192_TOP_AXI_PROT_EN_MM_2_SET,
- MT8192_TOP_AXI_PROT_EN_MM_2_CLR,
- MT8192_TOP_AXI_PROT_EN_MM_2_STA1),
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_DISP,
- MT8192_TOP_AXI_PROT_EN_SET,
- MT8192_TOP_AXI_PROT_EN_CLR,
- MT8192_TOP_AXI_PROT_EN_STA1),
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_DISP_2ND,
- MT8192_TOP_AXI_PROT_EN_MM_SET,
- MT8192_TOP_AXI_PROT_EN_MM_CLR,
- MT8192_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_2_DISP_2ND,
- MT8192_TOP_AXI_PROT_EN_MM_2_SET,
- MT8192_TOP_AXI_PROT_EN_MM_2_CLR,
- MT8192_TOP_AXI_PROT_EN_MM_2_STA1),
- },
- },
- [MT8192_POWER_DOMAIN_IPE] = {
- .name = "ipe",
- .sta_mask = BIT(14),
- .ctl_offs = 0x0338,
- .pwr_sta_offs = 0x016c,
- .pwr_sta2nd_offs = 0x0170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_IPE,
- MT8192_TOP_AXI_PROT_EN_MM_SET,
- MT8192_TOP_AXI_PROT_EN_MM_CLR,
- MT8192_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_IPE_2ND,
- MT8192_TOP_AXI_PROT_EN_MM_SET,
- MT8192_TOP_AXI_PROT_EN_MM_CLR,
- MT8192_TOP_AXI_PROT_EN_MM_STA1),
- },
- },
- [MT8192_POWER_DOMAIN_ISP] = {
- .name = "isp",
- .sta_mask = BIT(12),
- .ctl_offs = 0x0330,
- .pwr_sta_offs = 0x016c,
- .pwr_sta2nd_offs = 0x0170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_2_ISP,
- MT8192_TOP_AXI_PROT_EN_MM_2_SET,
- MT8192_TOP_AXI_PROT_EN_MM_2_CLR,
- MT8192_TOP_AXI_PROT_EN_MM_2_STA1),
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_2_ISP_2ND,
- MT8192_TOP_AXI_PROT_EN_MM_2_SET,
- MT8192_TOP_AXI_PROT_EN_MM_2_CLR,
- MT8192_TOP_AXI_PROT_EN_MM_2_STA1),
- },
- },
- [MT8192_POWER_DOMAIN_ISP2] = {
- .name = "isp2",
- .sta_mask = BIT(13),
- .ctl_offs = 0x0334,
- .pwr_sta_offs = 0x016c,
- .pwr_sta2nd_offs = 0x0170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_ISP2,
- MT8192_TOP_AXI_PROT_EN_MM_SET,
- MT8192_TOP_AXI_PROT_EN_MM_CLR,
- MT8192_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_ISP2_2ND,
- MT8192_TOP_AXI_PROT_EN_MM_SET,
- MT8192_TOP_AXI_PROT_EN_MM_CLR,
- MT8192_TOP_AXI_PROT_EN_MM_STA1),
- },
- },
- [MT8192_POWER_DOMAIN_MDP] = {
- .name = "mdp",
- .sta_mask = BIT(19),
- .ctl_offs = 0x034c,
- .pwr_sta_offs = 0x016c,
- .pwr_sta2nd_offs = 0x0170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_2_MDP,
- MT8192_TOP_AXI_PROT_EN_MM_2_SET,
- MT8192_TOP_AXI_PROT_EN_MM_2_CLR,
- MT8192_TOP_AXI_PROT_EN_MM_2_STA1),
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_2_MDP_2ND,
- MT8192_TOP_AXI_PROT_EN_MM_2_SET,
- MT8192_TOP_AXI_PROT_EN_MM_2_CLR,
- MT8192_TOP_AXI_PROT_EN_MM_2_STA1),
- },
- },
- [MT8192_POWER_DOMAIN_VENC] = {
- .name = "venc",
- .sta_mask = BIT(17),
- .ctl_offs = 0x0344,
- .pwr_sta_offs = 0x016c,
- .pwr_sta2nd_offs = 0x0170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_VENC,
- MT8192_TOP_AXI_PROT_EN_MM_SET,
- MT8192_TOP_AXI_PROT_EN_MM_CLR,
- MT8192_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_VENC_2ND,
- MT8192_TOP_AXI_PROT_EN_MM_SET,
- MT8192_TOP_AXI_PROT_EN_MM_CLR,
- MT8192_TOP_AXI_PROT_EN_MM_STA1),
- },
- },
- [MT8192_POWER_DOMAIN_VDEC] = {
- .name = "vdec",
- .sta_mask = BIT(15),
- .ctl_offs = 0x033c,
- .pwr_sta_offs = 0x016c,
- .pwr_sta2nd_offs = 0x0170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_VDEC,
- MT8192_TOP_AXI_PROT_EN_MM_SET,
- MT8192_TOP_AXI_PROT_EN_MM_CLR,
- MT8192_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_VDEC_2ND,
- MT8192_TOP_AXI_PROT_EN_MM_SET,
- MT8192_TOP_AXI_PROT_EN_MM_CLR,
- MT8192_TOP_AXI_PROT_EN_MM_STA1),
- },
- },
- [MT8192_POWER_DOMAIN_VDEC2] = {
- .name = "vdec2",
- .sta_mask = BIT(16),
- .ctl_offs = 0x0340,
- .pwr_sta_offs = 0x016c,
- .pwr_sta2nd_offs = 0x0170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- },
- [MT8192_POWER_DOMAIN_CAM] = {
- .name = "cam",
- .sta_mask = BIT(23),
- .ctl_offs = 0x035c,
- .pwr_sta_offs = 0x016c,
- .pwr_sta2nd_offs = 0x0170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_2_CAM,
- MT8192_TOP_AXI_PROT_EN_2_SET,
- MT8192_TOP_AXI_PROT_EN_2_CLR,
- MT8192_TOP_AXI_PROT_EN_2_STA1),
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_CAM,
- MT8192_TOP_AXI_PROT_EN_MM_SET,
- MT8192_TOP_AXI_PROT_EN_MM_CLR,
- MT8192_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_1_CAM,
- MT8192_TOP_AXI_PROT_EN_1_SET,
- MT8192_TOP_AXI_PROT_EN_1_CLR,
- MT8192_TOP_AXI_PROT_EN_1_STA1),
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_CAM_2ND,
- MT8192_TOP_AXI_PROT_EN_MM_SET,
- MT8192_TOP_AXI_PROT_EN_MM_CLR,
- MT8192_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_VDNR_CAM,
- MT8192_TOP_AXI_PROT_EN_VDNR_SET,
- MT8192_TOP_AXI_PROT_EN_VDNR_CLR,
- MT8192_TOP_AXI_PROT_EN_VDNR_STA1),
- },
- },
- [MT8192_POWER_DOMAIN_CAM_RAWA] = {
- .name = "cam_rawa",
- .sta_mask = BIT(24),
- .ctl_offs = 0x0360,
- .pwr_sta_offs = 0x016c,
- .pwr_sta2nd_offs = 0x0170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- },
- [MT8192_POWER_DOMAIN_CAM_RAWB] = {
- .name = "cam_rawb",
- .sta_mask = BIT(25),
- .ctl_offs = 0x0364,
- .pwr_sta_offs = 0x016c,
- .pwr_sta2nd_offs = 0x0170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- },
- [MT8192_POWER_DOMAIN_CAM_RAWC] = {
- .name = "cam_rawc",
- .sta_mask = BIT(26),
- .ctl_offs = 0x0368,
- .pwr_sta_offs = 0x016c,
- .pwr_sta2nd_offs = 0x0170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- },
-};
-
-static const struct scpsys_soc_data mt8192_scpsys_data = {
- .domains_data = scpsys_domain_data_mt8192,
- .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8192),
-};
-
-#endif /* __SOC_MEDIATEK_MT8192_PM_DOMAINS_H */
diff --git a/drivers/soc/mediatek/mt8195-mmsys.h b/drivers/soc/mediatek/mt8195-mmsys.h
index abfe94a30248..f69929a2a4d4 100644
--- a/drivers/soc/mediatek/mt8195-mmsys.h
+++ b/drivers/soc/mediatek/mt8195-mmsys.h
@@ -75,296 +75,363 @@
#define MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0 (2 << 16)
#define MT8195_SOUT_DSC_WRAP1_OUT_TO_VPP_MERGE (3 << 16)
+#define MT8195_VDO1_SW0_RST_B 0x1d0
+#define MT8195_VDO1_MERGE0_ASYNC_CFG_WD 0xe30
+#define MT8195_VDO1_HDRBE_ASYNC_CFG_WD 0xe70
+#define MT8195_VDO1_HDR_TOP_CFG 0xd00
+#define MT8195_VDO1_MIXER_IN1_ALPHA 0xd30
+#define MT8195_VDO1_MIXER_IN1_PAD 0xd40
+
+#define MT8195_VDO1_VPP_MERGE0_P0_SEL_IN 0xf04
+#define MT8195_VPP_MERGE0_P0_SEL_IN_FROM_MDP_RDMA0 1
+
+#define MT8195_VDO1_VPP_MERGE0_P1_SEL_IN 0xf08
+#define MT8195_VPP_MERGE0_P1_SEL_IN_FROM_MDP_RDMA1 1
+
+#define MT8195_VDO1_DISP_DPI1_SEL_IN 0xf10
+#define MT8195_DISP_DPI1_SEL_IN_FROM_VPP_MERGE4_MOUT 0
+
+#define MT8195_VDO1_DISP_DP_INTF0_SEL_IN 0xf14
+#define MT8195_DISP_DP_INTF0_SEL_IN_FROM_VPP_MERGE4_MOUT 0
+
+#define MT8195_VDO1_MERGE4_SOUT_SEL 0xf18
+#define MT8195_MERGE4_SOUT_TO_DPI1_SEL 2
+#define MT8195_MERGE4_SOUT_TO_DP_INTF0_SEL 3
+
+#define MT8195_VDO1_MIXER_IN1_SEL_IN 0xf24
+#define MT8195_MIXER_IN1_SEL_IN_FROM_MERGE0_ASYNC_SOUT 1
+
+#define MT8195_VDO1_MIXER_IN2_SEL_IN 0xf28
+#define MT8195_MIXER_IN2_SEL_IN_FROM_MERGE1_ASYNC_SOUT 1
+
+#define MT8195_VDO1_MIXER_IN3_SEL_IN 0xf2c
+#define MT8195_MIXER_IN3_SEL_IN_FROM_MERGE2_ASYNC_SOUT 1
+
+#define MT8195_VDO1_MIXER_IN4_SEL_IN 0xf30
+#define MT8195_MIXER_IN4_SEL_IN_FROM_MERGE3_ASYNC_SOUT 1
+
+#define MT8195_VDO1_MIXER_OUT_SOUT_SEL 0xf34
+#define MT8195_MIXER_SOUT_TO_MERGE4_ASYNC_SEL 1
+
+#define MT8195_VDO1_VPP_MERGE1_P0_SEL_IN 0xf3c
+#define MT8195_VPP_MERGE1_P0_SEL_IN_FROM_MDP_RDMA2 1
+
+#define MT8195_VDO1_MERGE0_ASYNC_SOUT_SEL 0xf40
+#define MT8195_SOUT_TO_MIXER_IN1_SEL 1
+
+#define MT8195_VDO1_MERGE1_ASYNC_SOUT_SEL 0xf44
+#define MT8195_SOUT_TO_MIXER_IN2_SEL 1
+
+#define MT8195_VDO1_MERGE2_ASYNC_SOUT_SEL 0xf48
+#define MT8195_SOUT_TO_MIXER_IN3_SEL 1
+
+#define MT8195_VDO1_MERGE3_ASYNC_SOUT_SEL 0xf4c
+#define MT8195_SOUT_TO_MIXER_IN4_SEL 1
+
+#define MT8195_VDO1_MERGE4_ASYNC_SEL_IN 0xf50
+#define MT8195_MERGE4_ASYNC_SEL_IN_FROM_MIXER_OUT_SOUT 1
+
+#define MT8195_VDO1_MIXER_IN1_SOUT_SEL 0xf58
+#define MT8195_MIXER_IN1_SOUT_TO_DISP_MIXER 0
+
+#define MT8195_VDO1_MIXER_IN2_SOUT_SEL 0xf5c
+#define MT8195_MIXER_IN2_SOUT_TO_DISP_MIXER 0
+
+#define MT8195_VDO1_MIXER_IN3_SOUT_SEL 0xf60
+#define MT8195_MIXER_IN3_SOUT_TO_DISP_MIXER 0
+
+#define MT8195_VDO1_MIXER_IN4_SOUT_SEL 0xf64
+#define MT8195_MIXER_IN4_SOUT_TO_DISP_MIXER 0
+
+#define MT8195_VDO1_MIXER_SOUT_SEL_IN 0xf68
+#define MT8195_MIXER_SOUT_SEL_IN_FROM_DISP_MIXER 0
+
+/* VPPSYS1 */
+#define MT8195_VPP1_HW_DCM_1ST_DIS0 0x150
+#define MT8195_VPP1_HW_DCM_1ST_DIS1 0x160
+#define MT8195_VPP1_HW_DCM_2ND_DIS0 0x1a0
+#define MT8195_VPP1_HW_DCM_2ND_DIS1 0x1b0
+#define MT8195_SVPP2_BUF_BF_RSZ_SWITCH 0xf48
+#define MT8195_SVPP3_BUF_BF_RSZ_SWITCH 0xf74
+
+/* VPPSYS1 HW DCM client*/
+#define MT8195_SVPP1_MDP_RSZ BIT(25)
+#define MT8195_SVPP2_MDP_RSZ BIT(4)
+#define MT8195_SVPP3_MDP_RSZ BIT(5)
+
static const struct mtk_mmsys_routes mmsys_mt8195_routing_table[] = {
- {
- DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0,
- MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL0_TO_DISP_RDMA0,
- MT8195_MOUT_DISP_OVL0_TO_DISP_RDMA0
- }, {
- DDP_COMPONENT_OVL0, DDP_COMPONENT_WDMA0,
- MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL0_TO_DISP_WDMA0,
- MT8195_MOUT_DISP_OVL0_TO_DISP_WDMA0
- }, {
- DDP_COMPONENT_OVL0, DDP_COMPONENT_OVL1,
- MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL0_TO_DISP_OVL1,
- MT8195_MOUT_DISP_OVL0_TO_DISP_OVL1
- }, {
- DDP_COMPONENT_OVL1, DDP_COMPONENT_RDMA1,
- MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL1_TO_DISP_RDMA1,
- MT8195_MOUT_DISP_OVL1_TO_DISP_RDMA1
- }, {
- DDP_COMPONENT_OVL1, DDP_COMPONENT_WDMA1,
- MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL1_TO_DISP_WDMA1,
- MT8195_MOUT_DISP_OVL1_TO_DISP_WDMA1
- }, {
- DDP_COMPONENT_OVL1, DDP_COMPONENT_OVL0,
- MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL1_TO_DISP_OVL0,
- MT8195_MOUT_DISP_OVL1_TO_DISP_OVL0
- }, {
- DDP_COMPONENT_DSC0, DDP_COMPONENT_MERGE0,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_VPP_MERGE_FROM_MASK,
- MT8195_SEL_IN_VPP_MERGE_FROM_DSC_WRAP0_OUT
- }, {
- DDP_COMPONENT_DITHER1, DDP_COMPONENT_MERGE0,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_VPP_MERGE_FROM_MASK,
- MT8195_SEL_IN_VPP_MERGE_FROM_DISP_DITHER1
- }, {
- DDP_COMPONENT_MERGE5, DDP_COMPONENT_MERGE0,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_VPP_MERGE_FROM_MASK,
- MT8195_SEL_IN_VPP_MERGE_FROM_VDO1_VIRTUAL0
- }, {
- DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSC0,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP0_IN_FROM_MASK,
- MT8195_SEL_IN_DSC_WRAP0_IN_FROM_DISP_DITHER0
- }, {
- DDP_COMPONENT_MERGE0, DDP_COMPONENT_DSC0,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP0_IN_FROM_MASK,
- MT8195_SEL_IN_DSC_WRAP0_IN_FROM_VPP_MERGE
- }, {
- DDP_COMPONENT_DITHER1, DDP_COMPONENT_DSC1,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_IN_FROM_MASK,
- MT8195_SEL_IN_DSC_WRAP1_IN_FROM_DISP_DITHER1
- }, {
- DDP_COMPONENT_MERGE0, DDP_COMPONENT_DSC1,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_IN_FROM_MASK,
- MT8195_SEL_IN_DSC_WRAP1_IN_FROM_VPP_MERGE
- }, {
- DDP_COMPONENT_MERGE0, DDP_COMPONENT_DP_INTF1,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
- MT8195_SEL_IN_SINA_VIRTUAL0_FROM_VPP_MERGE
- }, {
- DDP_COMPONENT_MERGE0, DDP_COMPONENT_DPI0,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
- MT8195_SEL_IN_SINA_VIRTUAL0_FROM_VPP_MERGE
- }, {
- DDP_COMPONENT_MERGE0, DDP_COMPONENT_DPI1,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
- MT8195_SEL_IN_SINA_VIRTUAL0_FROM_VPP_MERGE
- }, {
- DDP_COMPONENT_DSC1, DDP_COMPONENT_DP_INTF1,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
- MT8195_SEL_IN_SINA_VIRTUAL0_FROM_DSC_WRAP1_OUT
- }, {
- DDP_COMPONENT_DSC1, DDP_COMPONENT_DPI0,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
- MT8195_SEL_IN_SINA_VIRTUAL0_FROM_DSC_WRAP1_OUT
- }, {
- DDP_COMPONENT_DSC1, DDP_COMPONENT_DPI1,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
- MT8195_SEL_IN_SINA_VIRTUAL0_FROM_DSC_WRAP1_OUT
- }, {
- DDP_COMPONENT_DSC0, DDP_COMPONENT_DP_INTF1,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINB_VIRTUAL0_FROM_MASK,
- MT8195_SEL_IN_SINB_VIRTUAL0_FROM_DSC_WRAP0_OUT
- }, {
- DDP_COMPONENT_DSC0, DDP_COMPONENT_DPI0,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINB_VIRTUAL0_FROM_MASK,
- MT8195_SEL_IN_SINB_VIRTUAL0_FROM_DSC_WRAP0_OUT
- }, {
- DDP_COMPONENT_DSC0, DDP_COMPONENT_DPI1,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINB_VIRTUAL0_FROM_MASK,
- MT8195_SEL_IN_SINB_VIRTUAL0_FROM_DSC_WRAP0_OUT
- }, {
- DDP_COMPONENT_DSC1, DDP_COMPONENT_DP_INTF0,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DP_INTF0_FROM_MASK,
- MT8195_SEL_IN_DP_INTF0_FROM_DSC_WRAP1_OUT
- }, {
- DDP_COMPONENT_MERGE0, DDP_COMPONENT_DP_INTF0,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DP_INTF0_FROM_MASK,
- MT8195_SEL_IN_DP_INTF0_FROM_VPP_MERGE
- }, {
- DDP_COMPONENT_MERGE5, DDP_COMPONENT_DP_INTF0,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DP_INTF0_FROM_MASK,
- MT8195_SEL_IN_DP_INTF0_FROM_VDO1_VIRTUAL0
- }, {
- DDP_COMPONENT_DSC0, DDP_COMPONENT_DSI0,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI0_FROM_MASK,
- MT8195_SEL_IN_DSI0_FROM_DSC_WRAP0_OUT
- }, {
- DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI0_FROM_MASK,
- MT8195_SEL_IN_DSI0_FROM_DISP_DITHER0
- }, {
- DDP_COMPONENT_DSC1, DDP_COMPONENT_DSI1,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI1_FROM_MASK,
- MT8195_SEL_IN_DSI1_FROM_DSC_WRAP1_OUT
- }, {
- DDP_COMPONENT_MERGE0, DDP_COMPONENT_DSI1,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI1_FROM_MASK,
- MT8195_SEL_IN_DSI1_FROM_VPP_MERGE
- }, {
- DDP_COMPONENT_OVL1, DDP_COMPONENT_WDMA1,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DISP_WDMA1_FROM_MASK,
- MT8195_SEL_IN_DISP_WDMA1_FROM_DISP_OVL1
- }, {
- DDP_COMPONENT_MERGE0, DDP_COMPONENT_WDMA1,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DISP_WDMA1_FROM_MASK,
- MT8195_SEL_IN_DISP_WDMA1_FROM_VPP_MERGE
- }, {
- DDP_COMPONENT_DSC1, DDP_COMPONENT_DSI1,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
- MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN
- }, {
- DDP_COMPONENT_DSC1, DDP_COMPONENT_DP_INTF0,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
- MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN
- }, {
- DDP_COMPONENT_DSC1, DDP_COMPONENT_DP_INTF1,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
- MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN
- }, {
- DDP_COMPONENT_DSC1, DDP_COMPONENT_DPI0,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
- MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN
- }, {
- DDP_COMPONENT_DSC1, DDP_COMPONENT_DPI1,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
- MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN
- }, {
- DDP_COMPONENT_DSC1, DDP_COMPONENT_MERGE0,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
- MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN
- }, {
- DDP_COMPONENT_DITHER1, DDP_COMPONENT_DSI1,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
- MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1
- }, {
- DDP_COMPONENT_DITHER1, DDP_COMPONENT_DP_INTF0,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
- MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1
- }, {
- DDP_COMPONENT_DITHER1, DDP_COMPONENT_DPI0,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
- MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1
- }, {
- DDP_COMPONENT_DITHER1, DDP_COMPONENT_DPI1,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
- MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1
- }, {
- DDP_COMPONENT_OVL0, DDP_COMPONENT_WDMA0,
- MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DISP_WDMA0_FROM_MASK,
- MT8195_SEL_IN_DISP_WDMA0_FROM_DISP_OVL0
- }, {
- DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSC0,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER0_TO_MASK,
- MT8195_SOUT_DISP_DITHER0_TO_DSC_WRAP0_IN
- }, {
- DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER0_TO_MASK,
- MT8195_SOUT_DISP_DITHER0_TO_DSI0
- }, {
- DDP_COMPONENT_DITHER1, DDP_COMPONENT_DSC1,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
- MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_IN
- }, {
- DDP_COMPONENT_DITHER1, DDP_COMPONENT_MERGE0,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
- MT8195_SOUT_DISP_DITHER1_TO_VPP_MERGE
- }, {
- DDP_COMPONENT_DITHER1, DDP_COMPONENT_DSI1,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
- MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT
- }, {
- DDP_COMPONENT_DITHER1, DDP_COMPONENT_DP_INTF0,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
- MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT
- }, {
- DDP_COMPONENT_DITHER1, DDP_COMPONENT_DP_INTF1,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
- MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT
- }, {
- DDP_COMPONENT_DITHER1, DDP_COMPONENT_DPI0,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
- MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT
- }, {
- DDP_COMPONENT_DITHER1, DDP_COMPONENT_DPI1,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
- MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT
- }, {
- DDP_COMPONENT_MERGE5, DDP_COMPONENT_MERGE0,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_VDO1_VIRTUAL0_TO_MASK,
- MT8195_SOUT_VDO1_VIRTUAL0_TO_VPP_MERGE
- }, {
- DDP_COMPONENT_MERGE5, DDP_COMPONENT_DP_INTF0,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_VDO1_VIRTUAL0_TO_MASK,
- MT8195_SOUT_VDO1_VIRTUAL0_TO_DP_INTF0
- }, {
- DDP_COMPONENT_MERGE0, DDP_COMPONENT_DSI1,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
- MT8195_SOUT_VPP_MERGE_TO_DSI1
- }, {
- DDP_COMPONENT_MERGE0, DDP_COMPONENT_DP_INTF0,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
- MT8195_SOUT_VPP_MERGE_TO_DP_INTF0
- }, {
- DDP_COMPONENT_MERGE0, DDP_COMPONENT_DP_INTF1,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
- MT8195_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0
- }, {
- DDP_COMPONENT_MERGE0, DDP_COMPONENT_DPI0,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
- MT8195_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0
- }, {
- DDP_COMPONENT_MERGE0, DDP_COMPONENT_DPI1,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
- MT8195_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0
- }, {
- DDP_COMPONENT_MERGE0, DDP_COMPONENT_WDMA1,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
- MT8195_SOUT_VPP_MERGE_TO_DISP_WDMA1
- }, {
- DDP_COMPONENT_MERGE0, DDP_COMPONENT_DSC0,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
- MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP0_IN
- }, {
- DDP_COMPONENT_MERGE0, DDP_COMPONENT_DSC1,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN_MASK,
- MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN
- }, {
- DDP_COMPONENT_DSC0, DDP_COMPONENT_DSI0,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
- MT8195_SOUT_DSC_WRAP0_OUT_TO_DSI0
- }, {
- DDP_COMPONENT_DSC0, DDP_COMPONENT_DP_INTF1,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
- MT8195_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0
- }, {
- DDP_COMPONENT_DSC0, DDP_COMPONENT_DPI0,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
- MT8195_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0
- }, {
- DDP_COMPONENT_DSC0, DDP_COMPONENT_DPI1,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
- MT8195_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0
- }, {
- DDP_COMPONENT_DSC0, DDP_COMPONENT_MERGE0,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
- MT8195_SOUT_DSC_WRAP0_OUT_TO_VPP_MERGE
- }, {
- DDP_COMPONENT_DSC1, DDP_COMPONENT_DSI1,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
- MT8195_SOUT_DSC_WRAP1_OUT_TO_DSI1
- }, {
- DDP_COMPONENT_DSC1, DDP_COMPONENT_DP_INTF0,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
- MT8195_SOUT_DSC_WRAP1_OUT_TO_DP_INTF0
- }, {
- DDP_COMPONENT_DSC1, DDP_COMPONENT_DP_INTF1,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
- MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0
- }, {
- DDP_COMPONENT_DSC1, DDP_COMPONENT_DPI0,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
- MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0
- }, {
- DDP_COMPONENT_DSC1, DDP_COMPONENT_DPI1,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
- MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0
- }, {
- DDP_COMPONENT_DSC1, DDP_COMPONENT_MERGE0,
- MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
- MT8195_SOUT_DSC_WRAP1_OUT_TO_VPP_MERGE
- }
+ MMSYS_ROUTE(OVL0, RDMA0,
+ MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL0_TO_DISP_RDMA0,
+ MT8195_MOUT_DISP_OVL0_TO_DISP_RDMA0),
+ MMSYS_ROUTE(OVL0, WDMA0,
+ MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL0_TO_DISP_WDMA0,
+ MT8195_MOUT_DISP_OVL0_TO_DISP_WDMA0),
+ MMSYS_ROUTE(OVL0, OVL1,
+ MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL0_TO_DISP_OVL1,
+ MT8195_MOUT_DISP_OVL0_TO_DISP_OVL1),
+ MMSYS_ROUTE(OVL1, RDMA1,
+ MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL1_TO_DISP_RDMA1,
+ MT8195_MOUT_DISP_OVL1_TO_DISP_RDMA1),
+ MMSYS_ROUTE(OVL1, WDMA1,
+ MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL1_TO_DISP_WDMA1,
+ MT8195_MOUT_DISP_OVL1_TO_DISP_WDMA1),
+ MMSYS_ROUTE(OVL1, OVL0,
+ MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL1_TO_DISP_OVL0,
+ MT8195_MOUT_DISP_OVL1_TO_DISP_OVL0),
+ MMSYS_ROUTE(DSC0, MERGE0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_VPP_MERGE_FROM_MASK,
+ MT8195_SEL_IN_VPP_MERGE_FROM_DSC_WRAP0_OUT),
+ MMSYS_ROUTE(DITHER1, MERGE0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_VPP_MERGE_FROM_MASK,
+ MT8195_SEL_IN_VPP_MERGE_FROM_DISP_DITHER1),
+ MMSYS_ROUTE(MERGE5, MERGE0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_VPP_MERGE_FROM_MASK,
+ MT8195_SEL_IN_VPP_MERGE_FROM_VDO1_VIRTUAL0),
+ MMSYS_ROUTE(DITHER0, DSC0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP0_IN_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP0_IN_FROM_DISP_DITHER0),
+ MMSYS_ROUTE(MERGE0, DSC0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP0_IN_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP0_IN_FROM_VPP_MERGE),
+ MMSYS_ROUTE(DITHER1, DSC1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_IN_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_IN_FROM_DISP_DITHER1),
+ MMSYS_ROUTE(MERGE0, DSC1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_IN_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_IN_FROM_VPP_MERGE),
+ MMSYS_ROUTE(MERGE0, DP_INTF1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
+ MT8195_SEL_IN_SINA_VIRTUAL0_FROM_VPP_MERGE),
+ MMSYS_ROUTE(MERGE0, DPI0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
+ MT8195_SEL_IN_SINA_VIRTUAL0_FROM_VPP_MERGE),
+ MMSYS_ROUTE(MERGE0, DPI1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
+ MT8195_SEL_IN_SINA_VIRTUAL0_FROM_VPP_MERGE),
+ MMSYS_ROUTE(DSC1, DP_INTF1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
+ MT8195_SEL_IN_SINA_VIRTUAL0_FROM_DSC_WRAP1_OUT),
+ MMSYS_ROUTE(DSC1, DPI0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
+ MT8195_SEL_IN_SINA_VIRTUAL0_FROM_DSC_WRAP1_OUT),
+ MMSYS_ROUTE(DSC1, DPI1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
+ MT8195_SEL_IN_SINA_VIRTUAL0_FROM_DSC_WRAP1_OUT),
+ MMSYS_ROUTE(DSC0, DP_INTF1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINB_VIRTUAL0_FROM_MASK,
+ MT8195_SEL_IN_SINB_VIRTUAL0_FROM_DSC_WRAP0_OUT),
+ MMSYS_ROUTE(DSC0, DPI0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINB_VIRTUAL0_FROM_MASK,
+ MT8195_SEL_IN_SINB_VIRTUAL0_FROM_DSC_WRAP0_OUT),
+ MMSYS_ROUTE(DSC0, DPI1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINB_VIRTUAL0_FROM_MASK,
+ MT8195_SEL_IN_SINB_VIRTUAL0_FROM_DSC_WRAP0_OUT),
+ MMSYS_ROUTE(DSC1, DP_INTF0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DP_INTF0_FROM_MASK,
+ MT8195_SEL_IN_DP_INTF0_FROM_DSC_WRAP1_OUT),
+ MMSYS_ROUTE(MERGE0, DP_INTF0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DP_INTF0_FROM_MASK,
+ MT8195_SEL_IN_DP_INTF0_FROM_VPP_MERGE),
+ MMSYS_ROUTE(MERGE5, DP_INTF0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DP_INTF0_FROM_MASK,
+ MT8195_SEL_IN_DP_INTF0_FROM_VDO1_VIRTUAL0),
+ MMSYS_ROUTE(DSC0, DSI0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI0_FROM_MASK,
+ MT8195_SEL_IN_DSI0_FROM_DSC_WRAP0_OUT),
+ MMSYS_ROUTE(DITHER0, DSI0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI0_FROM_MASK,
+ MT8195_SEL_IN_DSI0_FROM_DISP_DITHER0),
+ MMSYS_ROUTE(DSC1, DSI1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI1_FROM_MASK,
+ MT8195_SEL_IN_DSI1_FROM_DSC_WRAP1_OUT),
+ MMSYS_ROUTE(MERGE0, DSI1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI1_FROM_MASK,
+ MT8195_SEL_IN_DSI1_FROM_VPP_MERGE),
+ MMSYS_ROUTE(OVL1, WDMA1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DISP_WDMA1_FROM_MASK,
+ MT8195_SEL_IN_DISP_WDMA1_FROM_DISP_OVL1),
+ MMSYS_ROUTE(MERGE0, WDMA1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DISP_WDMA1_FROM_MASK,
+ MT8195_SEL_IN_DISP_WDMA1_FROM_VPP_MERGE),
+ MMSYS_ROUTE(DSC1, DSI1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN),
+ MMSYS_ROUTE(DSC1, DP_INTF0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN),
+ MMSYS_ROUTE(DSC1, DP_INTF1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN),
+ MMSYS_ROUTE(DSC1, DPI0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN),
+ MMSYS_ROUTE(DSC1, DPI1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN),
+ MMSYS_ROUTE(DSC1, MERGE0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN),
+ MMSYS_ROUTE(DITHER1, DSI1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1),
+ MMSYS_ROUTE(DITHER1, DP_INTF0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1),
+ MMSYS_ROUTE(DITHER1, DPI0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1),
+ MMSYS_ROUTE(DITHER1, DPI1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1),
+ MMSYS_ROUTE(OVL0, WDMA0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DISP_WDMA0_FROM_MASK,
+ MT8195_SEL_IN_DISP_WDMA0_FROM_DISP_OVL0),
+ MMSYS_ROUTE(DITHER0, DSC0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER0_TO_MASK,
+ MT8195_SOUT_DISP_DITHER0_TO_DSC_WRAP0_IN),
+ MMSYS_ROUTE(DITHER0, DSI0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER0_TO_MASK,
+ MT8195_SOUT_DISP_DITHER0_TO_DSI0),
+ MMSYS_ROUTE(DITHER1, DSC1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
+ MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_IN),
+ MMSYS_ROUTE(DITHER1, MERGE0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
+ MT8195_SOUT_DISP_DITHER1_TO_VPP_MERGE),
+ MMSYS_ROUTE(DITHER1, DSI1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
+ MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT),
+ MMSYS_ROUTE(DITHER1, DP_INTF0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
+ MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT),
+ MMSYS_ROUTE(DITHER1, DP_INTF1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
+ MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT),
+ MMSYS_ROUTE(DITHER1, DPI0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
+ MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT),
+ MMSYS_ROUTE(DITHER1, DPI1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
+ MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT),
+ MMSYS_ROUTE(MERGE5, MERGE0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_VDO1_VIRTUAL0_TO_MASK,
+ MT8195_SOUT_VDO1_VIRTUAL0_TO_VPP_MERGE),
+ MMSYS_ROUTE(MERGE5, DP_INTF0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_VDO1_VIRTUAL0_TO_MASK,
+ MT8195_SOUT_VDO1_VIRTUAL0_TO_DP_INTF0),
+ MMSYS_ROUTE(MERGE0, DSI1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
+ MT8195_SOUT_VPP_MERGE_TO_DSI1),
+ MMSYS_ROUTE(MERGE0, DP_INTF0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
+ MT8195_SOUT_VPP_MERGE_TO_DP_INTF0),
+ MMSYS_ROUTE(MERGE0, DP_INTF1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
+ MT8195_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0),
+ MMSYS_ROUTE(MERGE0, DPI0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
+ MT8195_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0),
+ MMSYS_ROUTE(MERGE0, DPI1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
+ MT8195_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0),
+ MMSYS_ROUTE(MERGE0, WDMA1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
+ MT8195_SOUT_VPP_MERGE_TO_DISP_WDMA1),
+ MMSYS_ROUTE(MERGE0, DSC0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
+ MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP0_IN),
+ MMSYS_ROUTE(MERGE0, DSC1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN_MASK,
+ MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN),
+ MMSYS_ROUTE(DSC0, DSI0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP0_OUT_TO_DSI0),
+ MMSYS_ROUTE(DSC0, DP_INTF1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0),
+ MMSYS_ROUTE(DSC0, DPI0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0),
+ MMSYS_ROUTE(DSC0, DPI1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0),
+ MMSYS_ROUTE(DSC0, MERGE0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP0_OUT_TO_VPP_MERGE),
+ MMSYS_ROUTE(DSC1, DSI1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP1_OUT_TO_DSI1),
+ MMSYS_ROUTE(DSC1, DP_INTF0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP1_OUT_TO_DP_INTF0),
+ MMSYS_ROUTE(DSC1, DP_INTF1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0),
+ MMSYS_ROUTE(DSC1, DPI0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0),
+ MMSYS_ROUTE(DSC1, DPI1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0),
+ MMSYS_ROUTE(DSC1, MERGE0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP1_OUT_TO_VPP_MERGE),
};
+static const struct mtk_mmsys_routes mmsys_mt8195_vdo1_routing_table[] = {
+ MMSYS_ROUTE(MDP_RDMA0, MERGE1,
+ MT8195_VDO1_VPP_MERGE0_P0_SEL_IN, GENMASK(0, 0),
+ MT8195_VPP_MERGE0_P0_SEL_IN_FROM_MDP_RDMA0),
+ MMSYS_ROUTE(MDP_RDMA1, MERGE1,
+ MT8195_VDO1_VPP_MERGE0_P1_SEL_IN, GENMASK(0, 0),
+ MT8195_VPP_MERGE0_P1_SEL_IN_FROM_MDP_RDMA1),
+ MMSYS_ROUTE(MDP_RDMA2, MERGE2,
+ MT8195_VDO1_VPP_MERGE1_P0_SEL_IN, GENMASK(0, 0),
+ MT8195_VPP_MERGE1_P0_SEL_IN_FROM_MDP_RDMA2),
+ MMSYS_ROUTE(MERGE1, ETHDR_MIXER,
+ MT8195_VDO1_MERGE0_ASYNC_SOUT_SEL, GENMASK(1, 0),
+ MT8195_SOUT_TO_MIXER_IN1_SEL),
+ MMSYS_ROUTE(MERGE2, ETHDR_MIXER,
+ MT8195_VDO1_MERGE1_ASYNC_SOUT_SEL, GENMASK(1, 0),
+ MT8195_SOUT_TO_MIXER_IN2_SEL),
+ MMSYS_ROUTE(MERGE3, ETHDR_MIXER,
+ MT8195_VDO1_MERGE2_ASYNC_SOUT_SEL, GENMASK(1, 0),
+ MT8195_SOUT_TO_MIXER_IN3_SEL),
+ MMSYS_ROUTE(MERGE4, ETHDR_MIXER,
+ MT8195_VDO1_MERGE3_ASYNC_SOUT_SEL, GENMASK(1, 0),
+ MT8195_SOUT_TO_MIXER_IN4_SEL),
+ MMSYS_ROUTE(ETHDR_MIXER, MERGE5,
+ MT8195_VDO1_MIXER_OUT_SOUT_SEL, GENMASK(0, 0),
+ MT8195_MIXER_SOUT_TO_MERGE4_ASYNC_SEL),
+ MMSYS_ROUTE(MERGE1, ETHDR_MIXER,
+ MT8195_VDO1_MIXER_IN1_SEL_IN, GENMASK(0, 0),
+ MT8195_MIXER_IN1_SEL_IN_FROM_MERGE0_ASYNC_SOUT),
+ MMSYS_ROUTE(MERGE2, ETHDR_MIXER,
+ MT8195_VDO1_MIXER_IN2_SEL_IN, GENMASK(0, 0),
+ MT8195_MIXER_IN2_SEL_IN_FROM_MERGE1_ASYNC_SOUT),
+ MMSYS_ROUTE(MERGE3, ETHDR_MIXER,
+ MT8195_VDO1_MIXER_IN3_SEL_IN, GENMASK(0, 0),
+ MT8195_MIXER_IN3_SEL_IN_FROM_MERGE2_ASYNC_SOUT),
+ MMSYS_ROUTE(MERGE4, ETHDR_MIXER,
+ MT8195_VDO1_MIXER_IN4_SEL_IN, GENMASK(0, 0),
+ MT8195_MIXER_IN4_SEL_IN_FROM_MERGE3_ASYNC_SOUT),
+ MMSYS_ROUTE(ETHDR_MIXER, MERGE5,
+ MT8195_VDO1_MIXER_SOUT_SEL_IN, GENMASK(2, 0),
+ MT8195_MIXER_SOUT_SEL_IN_FROM_DISP_MIXER),
+ MMSYS_ROUTE(ETHDR_MIXER, MERGE5,
+ MT8195_VDO1_MERGE4_ASYNC_SEL_IN, GENMASK(2, 0),
+ MT8195_MERGE4_ASYNC_SEL_IN_FROM_MIXER_OUT_SOUT),
+ MMSYS_ROUTE(MERGE5, DPI1,
+ MT8195_VDO1_DISP_DPI1_SEL_IN, GENMASK(1, 0),
+ MT8195_DISP_DPI1_SEL_IN_FROM_VPP_MERGE4_MOUT),
+ MMSYS_ROUTE(MERGE5, DPI1,
+ MT8195_VDO1_MERGE4_SOUT_SEL, GENMASK(1, 0),
+ MT8195_MERGE4_SOUT_TO_DPI1_SEL),
+ MMSYS_ROUTE(MERGE5, DP_INTF1,
+ MT8195_VDO1_DISP_DP_INTF0_SEL_IN, GENMASK(1, 0),
+ MT8195_DISP_DP_INTF0_SEL_IN_FROM_VPP_MERGE4_MOUT),
+ MMSYS_ROUTE(MERGE5, DP_INTF1,
+ MT8195_VDO1_MERGE4_SOUT_SEL, GENMASK(1, 0),
+ MT8195_MERGE4_SOUT_TO_DP_INTF0_SEL),
+};
#endif /* __SOC_MEDIATEK_MT8195_MMSYS_H */
diff --git a/drivers/soc/mediatek/mt8195-pm-domains.h b/drivers/soc/mediatek/mt8195-pm-domains.h
deleted file mode 100644
index d7387ea1b9c9..000000000000
--- a/drivers/soc/mediatek/mt8195-pm-domains.h
+++ /dev/null
@@ -1,613 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (c) 2021 MediaTek Inc.
- * Author: Chun-Jie Chen <chun-jie.chen@mediatek.com>
- */
-
-#ifndef __SOC_MEDIATEK_MT8195_PM_DOMAINS_H
-#define __SOC_MEDIATEK_MT8195_PM_DOMAINS_H
-
-#include "mtk-pm-domains.h"
-#include <dt-bindings/power/mt8195-power.h>
-
-/*
- * MT8195 power domain support
- */
-
-static const struct scpsys_domain_data scpsys_domain_data_mt8195[] = {
- [MT8195_POWER_DOMAIN_PCIE_MAC_P0] = {
- .name = "pcie_mac_p0",
- .sta_mask = BIT(11),
- .ctl_offs = 0x328,
- .pwr_sta_offs = 0x174,
- .pwr_sta2nd_offs = 0x178,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VDNR_PCIE_MAC_P0,
- MT8195_TOP_AXI_PROT_EN_VDNR_SET,
- MT8195_TOP_AXI_PROT_EN_VDNR_CLR,
- MT8195_TOP_AXI_PROT_EN_VDNR_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VDNR_1_PCIE_MAC_P0,
- MT8195_TOP_AXI_PROT_EN_VDNR_1_SET,
- MT8195_TOP_AXI_PROT_EN_VDNR_1_CLR,
- MT8195_TOP_AXI_PROT_EN_VDNR_1_STA1),
- },
- },
- [MT8195_POWER_DOMAIN_PCIE_MAC_P1] = {
- .name = "pcie_mac_p1",
- .sta_mask = BIT(12),
- .ctl_offs = 0x32C,
- .pwr_sta_offs = 0x174,
- .pwr_sta2nd_offs = 0x178,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VDNR_PCIE_MAC_P1,
- MT8195_TOP_AXI_PROT_EN_VDNR_SET,
- MT8195_TOP_AXI_PROT_EN_VDNR_CLR,
- MT8195_TOP_AXI_PROT_EN_VDNR_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VDNR_1_PCIE_MAC_P1,
- MT8195_TOP_AXI_PROT_EN_VDNR_1_SET,
- MT8195_TOP_AXI_PROT_EN_VDNR_1_CLR,
- MT8195_TOP_AXI_PROT_EN_VDNR_1_STA1),
- },
- },
- [MT8195_POWER_DOMAIN_PCIE_PHY] = {
- .name = "pcie_phy",
- .sta_mask = BIT(13),
- .ctl_offs = 0x330,
- .pwr_sta_offs = 0x174,
- .pwr_sta2nd_offs = 0x178,
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT8195_POWER_DOMAIN_SSUSB_PCIE_PHY] = {
- .name = "ssusb_pcie_phy",
- .sta_mask = BIT(14),
- .ctl_offs = 0x334,
- .pwr_sta_offs = 0x174,
- .pwr_sta2nd_offs = 0x178,
- .caps = MTK_SCPD_ACTIVE_WAKEUP | MTK_SCPD_ALWAYS_ON,
- },
- [MT8195_POWER_DOMAIN_CSI_RX_TOP] = {
- .name = "csi_rx_top",
- .sta_mask = BIT(18),
- .ctl_offs = 0x3C4,
- .pwr_sta_offs = 0x174,
- .pwr_sta2nd_offs = 0x178,
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8195_POWER_DOMAIN_ETHER] = {
- .name = "ether",
- .sta_mask = BIT(3),
- .ctl_offs = 0x344,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT8195_POWER_DOMAIN_ADSP] = {
- .name = "adsp",
- .sta_mask = BIT(10),
- .ctl_offs = 0x360,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_2_ADSP,
- MT8195_TOP_AXI_PROT_EN_2_SET,
- MT8195_TOP_AXI_PROT_EN_2_CLR,
- MT8195_TOP_AXI_PROT_EN_2_STA1),
- },
- .caps = MTK_SCPD_SRAM_ISO | MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT8195_POWER_DOMAIN_AUDIO] = {
- .name = "audio",
- .sta_mask = BIT(8),
- .ctl_offs = 0x358,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_2_AUDIO,
- MT8195_TOP_AXI_PROT_EN_2_SET,
- MT8195_TOP_AXI_PROT_EN_2_CLR,
- MT8195_TOP_AXI_PROT_EN_2_STA1),
- },
- },
- [MT8195_POWER_DOMAIN_MFG0] = {
- .name = "mfg0",
- .sta_mask = BIT(1),
- .ctl_offs = 0x300,
- .pwr_sta_offs = 0x174,
- .pwr_sta2nd_offs = 0x178,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_DOMAIN_SUPPLY,
- },
- [MT8195_POWER_DOMAIN_MFG1] = {
- .name = "mfg1",
- .sta_mask = BIT(2),
- .ctl_offs = 0x304,
- .pwr_sta_offs = 0x174,
- .pwr_sta2nd_offs = 0x178,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MFG1,
- MT8195_TOP_AXI_PROT_EN_SET,
- MT8195_TOP_AXI_PROT_EN_CLR,
- MT8195_TOP_AXI_PROT_EN_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_2_MFG1,
- MT8195_TOP_AXI_PROT_EN_2_SET,
- MT8195_TOP_AXI_PROT_EN_2_CLR,
- MT8195_TOP_AXI_PROT_EN_2_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_1_MFG1,
- MT8195_TOP_AXI_PROT_EN_1_SET,
- MT8195_TOP_AXI_PROT_EN_1_CLR,
- MT8195_TOP_AXI_PROT_EN_1_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_2_MFG1_2ND,
- MT8195_TOP_AXI_PROT_EN_2_SET,
- MT8195_TOP_AXI_PROT_EN_2_CLR,
- MT8195_TOP_AXI_PROT_EN_2_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MFG1_2ND,
- MT8195_TOP_AXI_PROT_EN_SET,
- MT8195_TOP_AXI_PROT_EN_CLR,
- MT8195_TOP_AXI_PROT_EN_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_MFG1,
- MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_SET,
- MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR,
- MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA1),
- },
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_DOMAIN_SUPPLY,
- },
- [MT8195_POWER_DOMAIN_MFG2] = {
- .name = "mfg2",
- .sta_mask = BIT(3),
- .ctl_offs = 0x308,
- .pwr_sta_offs = 0x174,
- .pwr_sta2nd_offs = 0x178,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8195_POWER_DOMAIN_MFG3] = {
- .name = "mfg3",
- .sta_mask = BIT(4),
- .ctl_offs = 0x30C,
- .pwr_sta_offs = 0x174,
- .pwr_sta2nd_offs = 0x178,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8195_POWER_DOMAIN_MFG4] = {
- .name = "mfg4",
- .sta_mask = BIT(5),
- .ctl_offs = 0x310,
- .pwr_sta_offs = 0x174,
- .pwr_sta2nd_offs = 0x178,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8195_POWER_DOMAIN_MFG5] = {
- .name = "mfg5",
- .sta_mask = BIT(6),
- .ctl_offs = 0x314,
- .pwr_sta_offs = 0x174,
- .pwr_sta2nd_offs = 0x178,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8195_POWER_DOMAIN_MFG6] = {
- .name = "mfg6",
- .sta_mask = BIT(7),
- .ctl_offs = 0x318,
- .pwr_sta_offs = 0x174,
- .pwr_sta2nd_offs = 0x178,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8195_POWER_DOMAIN_VPPSYS0] = {
- .name = "vppsys0",
- .sta_mask = BIT(11),
- .ctl_offs = 0x364,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VPPSYS0,
- MT8195_TOP_AXI_PROT_EN_SET,
- MT8195_TOP_AXI_PROT_EN_CLR,
- MT8195_TOP_AXI_PROT_EN_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VPPSYS0,
- MT8195_TOP_AXI_PROT_EN_MM_2_SET,
- MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VPPSYS0_2ND,
- MT8195_TOP_AXI_PROT_EN_SET,
- MT8195_TOP_AXI_PROT_EN_CLR,
- MT8195_TOP_AXI_PROT_EN_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VPPSYS0_2ND,
- MT8195_TOP_AXI_PROT_EN_MM_2_SET,
- MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_VPPSYS0,
- MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_SET,
- MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR,
- MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA1),
- },
- },
- [MT8195_POWER_DOMAIN_VDOSYS0] = {
- .name = "vdosys0",
- .sta_mask = BIT(13),
- .ctl_offs = 0x36C,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VDOSYS0,
- MT8195_TOP_AXI_PROT_EN_MM_SET,
- MT8195_TOP_AXI_PROT_EN_MM_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VDOSYS0,
- MT8195_TOP_AXI_PROT_EN_SET,
- MT8195_TOP_AXI_PROT_EN_CLR,
- MT8195_TOP_AXI_PROT_EN_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_VDOSYS0,
- MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_SET,
- MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR,
- MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA1),
- },
- },
- [MT8195_POWER_DOMAIN_VPPSYS1] = {
- .name = "vppsys1",
- .sta_mask = BIT(12),
- .ctl_offs = 0x368,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VPPSYS1,
- MT8195_TOP_AXI_PROT_EN_MM_SET,
- MT8195_TOP_AXI_PROT_EN_MM_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VPPSYS1_2ND,
- MT8195_TOP_AXI_PROT_EN_MM_SET,
- MT8195_TOP_AXI_PROT_EN_MM_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VPPSYS1,
- MT8195_TOP_AXI_PROT_EN_MM_2_SET,
- MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
- },
- },
- [MT8195_POWER_DOMAIN_VDOSYS1] = {
- .name = "vdosys1",
- .sta_mask = BIT(14),
- .ctl_offs = 0x370,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VDOSYS1,
- MT8195_TOP_AXI_PROT_EN_MM_SET,
- MT8195_TOP_AXI_PROT_EN_MM_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VDOSYS1_2ND,
- MT8195_TOP_AXI_PROT_EN_MM_SET,
- MT8195_TOP_AXI_PROT_EN_MM_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VDOSYS1,
- MT8195_TOP_AXI_PROT_EN_MM_2_SET,
- MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
- },
- },
- [MT8195_POWER_DOMAIN_DP_TX] = {
- .name = "dp_tx",
- .sta_mask = BIT(16),
- .ctl_offs = 0x378,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VDNR_1_DP_TX,
- MT8195_TOP_AXI_PROT_EN_VDNR_1_SET,
- MT8195_TOP_AXI_PROT_EN_VDNR_1_CLR,
- MT8195_TOP_AXI_PROT_EN_VDNR_1_STA1),
- },
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8195_POWER_DOMAIN_EPD_TX] = {
- .name = "epd_tx",
- .sta_mask = BIT(17),
- .ctl_offs = 0x37C,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VDNR_1_EPD_TX,
- MT8195_TOP_AXI_PROT_EN_VDNR_1_SET,
- MT8195_TOP_AXI_PROT_EN_VDNR_1_CLR,
- MT8195_TOP_AXI_PROT_EN_VDNR_1_STA1),
- },
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8195_POWER_DOMAIN_HDMI_TX] = {
- .name = "hdmi_tx",
- .sta_mask = BIT(18),
- .ctl_offs = 0x380,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT8195_POWER_DOMAIN_WPESYS] = {
- .name = "wpesys",
- .sta_mask = BIT(15),
- .ctl_offs = 0x374,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_WPESYS,
- MT8195_TOP_AXI_PROT_EN_MM_2_SET,
- MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_WPESYS,
- MT8195_TOP_AXI_PROT_EN_MM_SET,
- MT8195_TOP_AXI_PROT_EN_MM_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_WPESYS_2ND,
- MT8195_TOP_AXI_PROT_EN_MM_2_SET,
- MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
- },
- },
- [MT8195_POWER_DOMAIN_VDEC0] = {
- .name = "vdec0",
- .sta_mask = BIT(20),
- .ctl_offs = 0x388,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VDEC0,
- MT8195_TOP_AXI_PROT_EN_MM_SET,
- MT8195_TOP_AXI_PROT_EN_MM_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VDEC0,
- MT8195_TOP_AXI_PROT_EN_MM_2_SET,
- MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VDEC0_2ND,
- MT8195_TOP_AXI_PROT_EN_MM_SET,
- MT8195_TOP_AXI_PROT_EN_MM_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VDEC0_2ND,
- MT8195_TOP_AXI_PROT_EN_MM_2_SET,
- MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
- },
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8195_POWER_DOMAIN_VDEC1] = {
- .name = "vdec1",
- .sta_mask = BIT(21),
- .ctl_offs = 0x38C,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VDEC1,
- MT8195_TOP_AXI_PROT_EN_MM_SET,
- MT8195_TOP_AXI_PROT_EN_MM_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VDEC1_2ND,
- MT8195_TOP_AXI_PROT_EN_MM_SET,
- MT8195_TOP_AXI_PROT_EN_MM_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_STA1),
- },
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8195_POWER_DOMAIN_VDEC2] = {
- .name = "vdec2",
- .sta_mask = BIT(22),
- .ctl_offs = 0x390,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VDEC2,
- MT8195_TOP_AXI_PROT_EN_MM_2_SET,
- MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VDEC2_2ND,
- MT8195_TOP_AXI_PROT_EN_MM_2_SET,
- MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
- },
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8195_POWER_DOMAIN_VENC] = {
- .name = "venc",
- .sta_mask = BIT(23),
- .ctl_offs = 0x394,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VENC,
- MT8195_TOP_AXI_PROT_EN_MM_SET,
- MT8195_TOP_AXI_PROT_EN_MM_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VENC_2ND,
- MT8195_TOP_AXI_PROT_EN_MM_SET,
- MT8195_TOP_AXI_PROT_EN_MM_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VENC,
- MT8195_TOP_AXI_PROT_EN_MM_2_SET,
- MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
- },
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8195_POWER_DOMAIN_VENC_CORE1] = {
- .name = "venc_core1",
- .sta_mask = BIT(24),
- .ctl_offs = 0x398,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VENC_CORE1,
- MT8195_TOP_AXI_PROT_EN_MM_SET,
- MT8195_TOP_AXI_PROT_EN_MM_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VENC_CORE1,
- MT8195_TOP_AXI_PROT_EN_MM_2_SET,
- MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
- },
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8195_POWER_DOMAIN_IMG] = {
- .name = "img",
- .sta_mask = BIT(29),
- .ctl_offs = 0x3AC,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_IMG,
- MT8195_TOP_AXI_PROT_EN_MM_SET,
- MT8195_TOP_AXI_PROT_EN_MM_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_IMG_2ND,
- MT8195_TOP_AXI_PROT_EN_MM_SET,
- MT8195_TOP_AXI_PROT_EN_MM_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_STA1),
- },
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8195_POWER_DOMAIN_DIP] = {
- .name = "dip",
- .sta_mask = BIT(30),
- .ctl_offs = 0x3B0,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8195_POWER_DOMAIN_IPE] = {
- .name = "ipe",
- .sta_mask = BIT(31),
- .ctl_offs = 0x3B4,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_IPE,
- MT8195_TOP_AXI_PROT_EN_MM_SET,
- MT8195_TOP_AXI_PROT_EN_MM_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_IPE,
- MT8195_TOP_AXI_PROT_EN_MM_2_SET,
- MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
- },
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8195_POWER_DOMAIN_CAM] = {
- .name = "cam",
- .sta_mask = BIT(25),
- .ctl_offs = 0x39C,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .bp_infracfg = {
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_2_CAM,
- MT8195_TOP_AXI_PROT_EN_2_SET,
- MT8195_TOP_AXI_PROT_EN_2_CLR,
- MT8195_TOP_AXI_PROT_EN_2_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_CAM,
- MT8195_TOP_AXI_PROT_EN_MM_SET,
- MT8195_TOP_AXI_PROT_EN_MM_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_1_CAM,
- MT8195_TOP_AXI_PROT_EN_1_SET,
- MT8195_TOP_AXI_PROT_EN_1_CLR,
- MT8195_TOP_AXI_PROT_EN_1_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_CAM_2ND,
- MT8195_TOP_AXI_PROT_EN_MM_SET,
- MT8195_TOP_AXI_PROT_EN_MM_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_STA1),
- BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_CAM,
- MT8195_TOP_AXI_PROT_EN_MM_2_SET,
- MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
- MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
- },
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8195_POWER_DOMAIN_CAM_RAWA] = {
- .name = "cam_rawa",
- .sta_mask = BIT(26),
- .ctl_offs = 0x3A0,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8195_POWER_DOMAIN_CAM_RAWB] = {
- .name = "cam_rawb",
- .sta_mask = BIT(27),
- .ctl_offs = 0x3A4,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
- [MT8195_POWER_DOMAIN_CAM_MRAW] = {
- .name = "cam_mraw",
- .sta_mask = BIT(28),
- .ctl_offs = 0x3A8,
- .pwr_sta_offs = 0x16c,
- .pwr_sta2nd_offs = 0x170,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
- },
-};
-
-static const struct scpsys_soc_data mt8195_scpsys_data = {
- .domains_data = scpsys_domain_data_mt8195,
- .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8195),
-};
-
-#endif /* __SOC_MEDIATEK_MT8195_PM_DOMAINS_H */
diff --git a/drivers/soc/mediatek/mt8365-mmsys.h b/drivers/soc/mediatek/mt8365-mmsys.h
index 7abaf048d91e..533a3fd0923b 100644
--- a/drivers/soc/mediatek/mt8365-mmsys.h
+++ b/drivers/soc/mediatek/mt8365-mmsys.h
@@ -14,8 +14,9 @@
#define MT8365_DISP_REG_CONFIG_DISP_DPI0_SEL_IN 0xfd8
#define MT8365_DISP_REG_CONFIG_DISP_LVDS_SYS_CFG_00 0xfdc
+#define MT8365_DISP_MS_IN_OUT_MASK GENMASK(3, 0)
#define MT8365_RDMA0_SOUT_COLOR0 0x1
-#define MT8365_DITHER_MOUT_EN_DSI0 0x1
+#define MT8365_DITHER_MOUT_EN_DSI0 BIT(0)
#define MT8365_DSI0_SEL_IN_DITHER 0x1
#define MT8365_RDMA0_SEL_IN_OVL0 0x0
#define MT8365_RDMA0_RSZ0_SEL_IN_RDMA0 0x0
@@ -27,56 +28,37 @@
#define MT8365_DPI0_SEL_IN_RDMA1 0x0
static const struct mtk_mmsys_routes mt8365_mmsys_routing_table[] = {
- {
- DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0,
- MT8365_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN,
- MT8365_OVL0_MOUT_PATH0_SEL, MT8365_OVL0_MOUT_PATH0_SEL
- },
- {
- DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0,
- MT8365_DISP_REG_CONFIG_DISP_RDMA0_SEL_IN,
- MT8365_RDMA0_SEL_IN_OVL0, MT8365_RDMA0_SEL_IN_OVL0
- },
- {
- DDP_COMPONENT_RDMA0, DDP_COMPONENT_COLOR0,
- MT8365_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL,
- MT8365_RDMA0_SOUT_COLOR0, MT8365_RDMA0_SOUT_COLOR0
- },
- {
- DDP_COMPONENT_COLOR0, DDP_COMPONENT_CCORR,
- MT8365_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN,
- MT8365_DISP_COLOR_SEL_IN_COLOR0,MT8365_DISP_COLOR_SEL_IN_COLOR0
- },
- {
- DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0,
- MT8365_DISP_REG_CONFIG_DISP_DITHER0_MOUT_EN,
- MT8365_DITHER_MOUT_EN_DSI0, MT8365_DITHER_MOUT_EN_DSI0
- },
- {
- DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0,
- MT8365_DISP_REG_CONFIG_DISP_DSI0_SEL_IN,
- MT8365_DSI0_SEL_IN_DITHER, MT8365_DSI0_SEL_IN_DITHER
- },
- {
- DDP_COMPONENT_RDMA0, DDP_COMPONENT_COLOR0,
- MT8365_DISP_REG_CONFIG_DISP_RDMA0_RSZ0_SEL_IN,
- MT8365_RDMA0_RSZ0_SEL_IN_RDMA0, MT8365_RDMA0_RSZ0_SEL_IN_RDMA0
- },
- {
- DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
- MT8365_DISP_REG_CONFIG_DISP_LVDS_SYS_CFG_00,
- MT8365_LVDS_SYS_CFG_00_SEL_LVDS_PXL_CLK, MT8365_LVDS_SYS_CFG_00_SEL_LVDS_PXL_CLK
- },
- {
- DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
- MT8365_DISP_REG_CONFIG_DISP_DPI0_SEL_IN,
- MT8365_DPI0_SEL_IN_RDMA1, MT8365_DPI0_SEL_IN_RDMA1
- },
- {
- DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
- MT8365_DISP_REG_CONFIG_DISP_RDMA1_SOUT_SEL,
- MT8365_RDMA1_SOUT_DPI0, MT8365_RDMA1_SOUT_DPI0
- },
+ MMSYS_ROUTE(OVL0, RDMA0,
+ MT8365_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN,
+ MT8365_DISP_MS_IN_OUT_MASK, MT8365_OVL0_MOUT_PATH0_SEL),
+ MMSYS_ROUTE(OVL0, RDMA0,
+ MT8365_DISP_REG_CONFIG_DISP_RDMA0_SEL_IN,
+ MT8365_DISP_MS_IN_OUT_MASK, MT8365_RDMA0_SEL_IN_OVL0),
+ MMSYS_ROUTE(RDMA0, COLOR0,
+ MT8365_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL,
+ MT8365_DISP_MS_IN_OUT_MASK, MT8365_RDMA0_SOUT_COLOR0),
+ MMSYS_ROUTE(COLOR0, CCORR,
+ MT8365_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN,
+ MT8365_DISP_MS_IN_OUT_MASK, MT8365_DISP_COLOR_SEL_IN_COLOR0),
+ MMSYS_ROUTE(DITHER0, DSI0,
+ MT8365_DISP_REG_CONFIG_DISP_DITHER0_MOUT_EN,
+ MT8365_DISP_MS_IN_OUT_MASK, MT8365_DITHER_MOUT_EN_DSI0),
+ MMSYS_ROUTE(DITHER0, DSI0,
+ MT8365_DISP_REG_CONFIG_DISP_DSI0_SEL_IN,
+ MT8365_DISP_MS_IN_OUT_MASK, MT8365_DSI0_SEL_IN_DITHER),
+ MMSYS_ROUTE(RDMA0, COLOR0,
+ MT8365_DISP_REG_CONFIG_DISP_RDMA0_RSZ0_SEL_IN,
+ MT8365_DISP_MS_IN_OUT_MASK, MT8365_RDMA0_RSZ0_SEL_IN_RDMA0),
+ MMSYS_ROUTE(RDMA1, DPI0,
+ MT8365_DISP_REG_CONFIG_DISP_LVDS_SYS_CFG_00,
+ MT8365_LVDS_SYS_CFG_00_SEL_LVDS_PXL_CLK,
+ MT8365_LVDS_SYS_CFG_00_SEL_LVDS_PXL_CLK),
+ MMSYS_ROUTE(RDMA1, DPI0,
+ MT8365_DISP_REG_CONFIG_DISP_DPI0_SEL_IN,
+ MT8365_DISP_MS_IN_OUT_MASK, MT8365_DPI0_SEL_IN_RDMA1),
+ MMSYS_ROUTE(RDMA1, DPI0,
+ MT8365_DISP_REG_CONFIG_DISP_RDMA1_SOUT_SEL,
+ MT8365_DISP_MS_IN_OUT_MASK, MT8365_RDMA1_SOUT_DPI0),
};
#endif /* __SOC_MEDIATEK_MT8365_MMSYS_H */
diff --git a/drivers/soc/mediatek/mtk-cmdq-helper.c b/drivers/soc/mediatek/mtk-cmdq-helper.c
index c1837a468267..455221e8de24 100644
--- a/drivers/soc/mediatek/mtk-cmdq-helper.c
+++ b/drivers/soc/mediatek/mtk-cmdq-helper.c
@@ -7,13 +7,18 @@
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/mailbox_controller.h>
+#include <linux/of.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
#define CMDQ_WRITE_ENABLE_MASK BIT(0)
#define CMDQ_POLL_ENABLE_MASK BIT(0)
+/* dedicate the last GPR_R15 to assign the register address to be poll */
+#define CMDQ_POLL_ADDR_GPR (15)
#define CMDQ_EOC_IRQ_EN BIT(0)
+#define CMDQ_IMMEDIATE_VALUE 0
#define CMDQ_REG_TYPE 1
-#define CMDQ_JUMP_RELATIVE 1
+#define CMDQ_JUMP_RELATIVE 0
+#define CMDQ_JUMP_ABSOLUTE 1
struct cmdq_instruction {
union {
@@ -41,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)
{
@@ -54,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);
@@ -104,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,
@@ -127,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);
@@ -175,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);
@@ -191,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);
@@ -228,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);
@@ -243,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);
@@ -266,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);
@@ -280,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);
}
@@ -331,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);
@@ -347,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 fc13334db1b1..f54c966138b5 100644
--- a/drivers/soc/mediatek/mtk-devapc.c
+++ b/drivers/soc/mediatek/mtk-devapc.c
@@ -8,7 +8,7 @@
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
@@ -273,39 +273,39 @@ 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;
-
- ctx->infra_clk = devm_clk_get(&pdev->dev, "devapc-infra-clock");
- if (IS_ERR(ctx->infra_clk))
- return -EINVAL;
+ if (!devapc_irq) {
+ ret = -EINVAL;
+ goto err;
+ }
- if (clk_prepare_enable(ctx->infra_clk))
- return -EINVAL;
+ ctx->infra_clk = devm_clk_get_enabled(&pdev->dev, "devapc-infra-clock");
+ if (IS_ERR(ctx->infra_clk)) {
+ ret = -EINVAL;
+ goto err;
+ }
ret = devm_request_irq(&pdev->dev, devapc_irq, devapc_violation_irq,
IRQF_TRIGGER_NONE, "devapc", ctx);
- if (ret) {
- clk_disable_unprepare(ctx->infra_clk);
- return ret;
- }
+ if (ret)
+ goto err;
platform_set_drvdata(pdev, ctx);
start_devapc(ctx);
return 0;
+
+err:
+ iounmap(ctx->infra_base);
+ return ret;
}
-static int mtk_devapc_remove(struct platform_device *pdev)
+static void mtk_devapc_remove(struct platform_device *pdev)
{
struct mtk_devapc_context *ctx = platform_get_drvdata(pdev);
stop_devapc(ctx);
-
- clk_disable_unprepare(ctx->infra_clk);
-
- return 0;
+ iounmap(ctx->infra_base);
}
static struct platform_driver mtk_devapc_driver = {
diff --git a/drivers/soc/mediatek/mtk-dvfsrc.c b/drivers/soc/mediatek/mtk-dvfsrc.c
new file mode 100644
index 000000000000..41add5636b03
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-dvfsrc.c
@@ -0,0 +1,578 @@
+// 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_bw_constraints dvfsrc_bw_constr_v1 = { 0, 0, 0 };
+static const struct dvfsrc_bw_constraints dvfsrc_bw_constr_v2 = {
+ .max_dram_nom_bw = 255,
+ .max_dram_peak_bw = 255,
+ .max_dram_hrt_bw = 1023,
+};
+
+static const struct dvfsrc_opp dvfsrc_opp_mt6893_lp4[] = {
+ { 0, 0 }, { 1, 0 }, { 2, 0 }, { 3, 0 },
+ { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 },
+ { 0, 2 }, { 1, 2 }, { 2, 2 }, { 3, 2 },
+ { 0, 3 }, { 1, 3 }, { 2, 3 }, { 3, 3 },
+ { 1, 4 }, { 2, 4 }, { 3, 4 }, { 2, 5 },
+ { 3, 5 }, { 3, 6 }, { 4, 6 }, { 4, 7 },
+};
+
+static const struct dvfsrc_opp_desc dvfsrc_opp_mt6893_desc[] = {
+ [0] = {
+ .opps = dvfsrc_opp_mt6893_lp4,
+ .num_opp = ARRAY_SIZE(dvfsrc_opp_mt6893_lp4),
+ }
+};
+
+static const struct dvfsrc_soc_data mt6893_data = {
+ .opps_desc = dvfsrc_opp_mt6893_desc,
+ .regs = dvfsrc_mt8195_regs,
+ .get_target_level = dvfsrc_get_target_level_v2,
+ .get_current_level = dvfsrc_get_current_level_v2,
+ .get_vcore_level = dvfsrc_get_vcore_level_v2,
+ .get_vscp_level = dvfsrc_get_vscp_level_v2,
+ .set_dram_bw = dvfsrc_set_dram_bw_v1,
+ .set_dram_peak_bw = dvfsrc_set_dram_peak_bw_v1,
+ .set_dram_hrt_bw = dvfsrc_set_dram_hrt_bw_v1,
+ .set_vcore_level = dvfsrc_set_vcore_level_v2,
+ .set_vscp_level = dvfsrc_set_vscp_level_v2,
+ .wait_for_opp_level = dvfsrc_wait_for_opp_level_v2,
+ .wait_for_vcore_level = dvfsrc_wait_for_vcore_level_v1,
+ .bw_constraints = &dvfsrc_bw_constr_v2,
+};
+
+static const struct dvfsrc_opp dvfsrc_opp_mt8183_lp4[] = {
+ { 0, 0 }, { 0, 1 }, { 0, 2 }, { 1, 2 },
+};
+
+static const struct dvfsrc_opp dvfsrc_opp_mt8183_lp3[] = {
+ { 0, 0 }, { 0, 1 }, { 1, 1 }, { 1, 2 },
+};
+
+static const struct dvfsrc_opp_desc dvfsrc_opp_mt8183_desc[] = {
+ [0] = {
+ .opps = dvfsrc_opp_mt8183_lp4,
+ .num_opp = ARRAY_SIZE(dvfsrc_opp_mt8183_lp4),
+ },
+ [1] = {
+ .opps = dvfsrc_opp_mt8183_lp3,
+ .num_opp = ARRAY_SIZE(dvfsrc_opp_mt8183_lp3),
+ },
+ [2] = {
+ .opps = dvfsrc_opp_mt8183_lp3,
+ .num_opp = ARRAY_SIZE(dvfsrc_opp_mt8183_lp3),
+ }
+};
+
+static const struct dvfsrc_soc_data mt8183_data = {
+ .opps_desc = dvfsrc_opp_mt8183_desc,
+ .regs = dvfsrc_mt8183_regs,
+ .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_v1,
+};
+
+static const struct dvfsrc_opp dvfsrc_opp_mt8195_lp4[] = {
+ { 0, 0 }, { 1, 0 }, { 2, 0 }, { 3, 0 },
+ { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 },
+ { 0, 2 }, { 1, 2 }, { 2, 2 }, { 3, 2 },
+ { 1, 3 }, { 2, 3 }, { 3, 3 }, { 1, 4 },
+ { 2, 4 }, { 3, 4 }, { 2, 5 }, { 3, 5 },
+ { 3, 6 },
+};
+
+static const struct dvfsrc_opp_desc dvfsrc_opp_mt8195_desc[] = {
+ [0] = {
+ .opps = dvfsrc_opp_mt8195_lp4,
+ .num_opp = ARRAY_SIZE(dvfsrc_opp_mt8195_lp4),
+ }
+};
+
+static const struct dvfsrc_soc_data mt8195_data = {
+ .opps_desc = dvfsrc_opp_mt8195_desc,
+ .regs = dvfsrc_mt8195_regs,
+ .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_v2,
+};
+
+static const struct of_device_id mtk_dvfsrc_of_match[] = {
+ { .compatible = "mediatek,mt6893-dvfsrc", .data = &mt6893_data },
+ { .compatible = "mediatek,mt8183-dvfsrc", .data = &mt8183_data },
+ { .compatible = "mediatek,mt8195-dvfsrc", .data = &mt8195_data },
+ { /* 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 f3431448e843..bb4639ca0b8c 100644
--- a/drivers/soc/mediatek/mtk-mmsys.c
+++ b/drivers/soc/mediatek/mtk-mmsys.c
@@ -7,19 +7,24 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/io.h>
-#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/soc/mediatek/mtk-mmsys.h>
#include "mtk-mmsys.h"
#include "mt8167-mmsys.h"
+#include "mt8173-mmsys.h"
#include "mt8183-mmsys.h"
#include "mt8186-mmsys.h"
+#include "mt8188-mmsys.h"
#include "mt8192-mmsys.h"
#include "mt8195-mmsys.h"
#include "mt8365-mmsys.h"
+#define MMSYS_SW_RESET_PER_REG 32
+
static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = {
.clk_driver = "clk-mt2701-mm",
.routes = mmsys_default_routing_table,
@@ -36,6 +41,14 @@ static const struct mtk_mmsys_driver_data mt6779_mmsys_driver_data = {
.clk_driver = "clk-mt6779-mm",
};
+static const struct mtk_mmsys_driver_data mt6795_mmsys_driver_data = {
+ .clk_driver = "clk-mt6795-mm",
+ .routes = mt8173_mmsys_routing_table,
+ .num_routes = ARRAY_SIZE(mt8173_mmsys_routing_table),
+ .sw0_rst_offset = MT8183_MMSYS_SW0_RST_B,
+ .num_resets = 64,
+};
+
static const struct mtk_mmsys_driver_data mt6797_mmsys_driver_data = {
.clk_driver = "clk-mt6797-mm",
};
@@ -48,9 +61,10 @@ static const struct mtk_mmsys_driver_data mt8167_mmsys_driver_data = {
static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = {
.clk_driver = "clk-mt8173-mm",
- .routes = mmsys_default_routing_table,
- .num_routes = ARRAY_SIZE(mmsys_default_routing_table),
+ .routes = mt8173_mmsys_routing_table,
+ .num_routes = ARRAY_SIZE(mt8173_mmsys_routing_table),
.sw0_rst_offset = MT8183_MMSYS_SW0_RST_B,
+ .num_resets = 64,
};
static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = {
@@ -58,6 +72,7 @@ static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = {
.routes = mmsys_mt8183_routing_table,
.num_routes = ARRAY_SIZE(mmsys_mt8183_routing_table),
.sw0_rst_offset = MT8183_MMSYS_SW0_RST_B,
+ .num_resets = 32,
};
static const struct mtk_mmsys_driver_data mt8186_mmsys_driver_data = {
@@ -65,6 +80,36 @@ static const struct mtk_mmsys_driver_data mt8186_mmsys_driver_data = {
.routes = mmsys_mt8186_routing_table,
.num_routes = ARRAY_SIZE(mmsys_mt8186_routing_table),
.sw0_rst_offset = MT8186_MMSYS_SW0_RST_B,
+ .num_resets = 32,
+};
+
+static const struct mtk_mmsys_driver_data mt8188_vdosys0_driver_data = {
+ .clk_driver = "clk-mt8188-vdo0",
+ .routes = mmsys_mt8188_routing_table,
+ .num_routes = ARRAY_SIZE(mmsys_mt8188_routing_table),
+ .sw0_rst_offset = MT8188_VDO0_SW0_RST_B,
+ .rst_tb = mmsys_mt8188_vdo0_rst_tb,
+ .num_resets = ARRAY_SIZE(mmsys_mt8188_vdo0_rst_tb),
+};
+
+static const struct mtk_mmsys_driver_data mt8188_vdosys1_driver_data = {
+ .clk_driver = "clk-mt8188-vdo1",
+ .routes = mmsys_mt8188_vdo1_routing_table,
+ .num_routes = ARRAY_SIZE(mmsys_mt8188_vdo1_routing_table),
+ .sw0_rst_offset = MT8188_VDO1_SW0_RST_B,
+ .rst_tb = mmsys_mt8188_vdo1_rst_tb,
+ .num_resets = ARRAY_SIZE(mmsys_mt8188_vdo1_rst_tb),
+ .vsync_len = 1,
+};
+
+static const struct mtk_mmsys_driver_data mt8188_vppsys0_driver_data = {
+ .clk_driver = "clk-mt8188-vpp0",
+ .is_vppsys = true,
+};
+
+static const struct mtk_mmsys_driver_data mt8188_vppsys1_driver_data = {
+ .clk_driver = "clk-mt8188-vpp1",
+ .is_vppsys = true,
};
static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = {
@@ -72,6 +117,7 @@ static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = {
.routes = mmsys_mt8192_routing_table,
.num_routes = ARRAY_SIZE(mmsys_mt8192_routing_table),
.sw0_rst_offset = MT8186_MMSYS_SW0_RST_B,
+ .num_resets = 32,
};
static const struct mtk_mmsys_driver_data mt8195_vdosys0_driver_data = {
@@ -80,6 +126,24 @@ static const struct mtk_mmsys_driver_data mt8195_vdosys0_driver_data = {
.num_routes = ARRAY_SIZE(mmsys_mt8195_routing_table),
};
+static const struct mtk_mmsys_driver_data mt8195_vdosys1_driver_data = {
+ .clk_driver = "clk-mt8195-vdo1",
+ .routes = mmsys_mt8195_vdo1_routing_table,
+ .num_routes = ARRAY_SIZE(mmsys_mt8195_vdo1_routing_table),
+ .sw0_rst_offset = MT8195_VDO1_SW0_RST_B,
+ .num_resets = 64,
+};
+
+static const struct mtk_mmsys_driver_data mt8195_vppsys0_driver_data = {
+ .clk_driver = "clk-mt8195-vpp0",
+ .is_vppsys = true,
+};
+
+static const struct mtk_mmsys_driver_data mt8195_vppsys1_driver_data = {
+ .clk_driver = "clk-mt8195-vpp1",
+ .is_vppsys = true,
+};
+
static const struct mtk_mmsys_driver_data mt8365_mmsys_driver_data = {
.clk_driver = "clk-mt8365-mm",
.routes = mt8365_mmsys_routing_table,
@@ -89,26 +153,49 @@ static const struct mtk_mmsys_driver_data mt8365_mmsys_driver_data = {
struct mtk_mmsys {
void __iomem *regs;
const struct mtk_mmsys_driver_data *data;
+ struct platform_device *clks_pdev;
+ struct platform_device *drm_pdev;
spinlock_t lock; /* protects mmsys_sw_rst_b reg */
struct reset_controller_dev rcdev;
+ struct cmdq_client_reg cmdq_base;
};
+static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32 offset, u32 mask, u32 val,
+ struct cmdq_pkt *cmdq_pkt)
+{
+ int ret;
+ u32 tmp;
+
+ if (mmsys->cmdq_base.size && cmdq_pkt) {
+ ret = cmdq_pkt_write_mask(cmdq_pkt, mmsys->cmdq_base.subsys,
+ mmsys->cmdq_base.offset + offset, val,
+ mask);
+ if (ret)
+ pr_debug("CMDQ unavailable: using CPU write\n");
+ else
+ return;
+ }
+ tmp = readl_relaxed(mmsys->regs + offset);
+ tmp = (tmp & ~mask) | (val & mask);
+ writel_relaxed(tmp, mmsys->regs + offset);
+}
+
void mtk_mmsys_ddp_connect(struct device *dev,
enum mtk_ddp_comp_id cur,
enum mtk_ddp_comp_id next)
{
struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
const struct mtk_mmsys_routes *routes = mmsys->data->routes;
- u32 reg;
int i;
for (i = 0; i < mmsys->data->num_routes; i++)
- if (cur == routes[i].from_comp && next == routes[i].to_comp) {
- reg = readl_relaxed(mmsys->regs + routes[i].addr);
- reg &= ~routes[i].mask;
- reg |= routes[i].val;
- writel_relaxed(reg, mmsys->regs + routes[i].addr);
- }
+ if (cur == routes[i].from_comp && next == routes[i].to_comp)
+ mtk_mmsys_update_bits(mmsys, routes[i].addr, routes[i].mask,
+ routes[i].val, NULL);
+
+ if (mmsys->data->vsync_len)
+ mtk_mmsys_update_bits(mmsys, MT8188_VDO1_MIXER_VSYNC_LEN, GENMASK(31, 0),
+ mmsys->data->vsync_len, NULL);
}
EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_connect);
@@ -118,26 +205,52 @@ void mtk_mmsys_ddp_disconnect(struct device *dev,
{
struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
const struct mtk_mmsys_routes *routes = mmsys->data->routes;
- u32 reg;
int i;
for (i = 0; i < mmsys->data->num_routes; i++)
- if (cur == routes[i].from_comp && next == routes[i].to_comp) {
- reg = readl_relaxed(mmsys->regs + routes[i].addr);
- reg &= ~routes[i].mask;
- writel_relaxed(reg, mmsys->regs + routes[i].addr);
- }
+ if (cur == routes[i].from_comp && next == routes[i].to_comp)
+ mtk_mmsys_update_bits(mmsys, routes[i].addr, routes[i].mask, 0, NULL);
}
EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_disconnect);
-static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32 offset, u32 mask, u32 val)
+void mtk_mmsys_merge_async_config(struct device *dev, int idx, int width, int height,
+ struct cmdq_pkt *cmdq_pkt)
{
- u32 tmp;
+ mtk_mmsys_update_bits(dev_get_drvdata(dev), MT8195_VDO1_MERGE0_ASYNC_CFG_WD + 0x10 * idx,
+ ~0, height << 16 | width, cmdq_pkt);
+}
+EXPORT_SYMBOL_GPL(mtk_mmsys_merge_async_config);
- tmp = readl_relaxed(mmsys->regs + offset);
- tmp = (tmp & ~mask) | val;
- writel_relaxed(tmp, mmsys->regs + offset);
+void mtk_mmsys_hdr_config(struct device *dev, int be_width, int be_height,
+ struct cmdq_pkt *cmdq_pkt)
+{
+ mtk_mmsys_update_bits(dev_get_drvdata(dev), MT8195_VDO1_HDRBE_ASYNC_CFG_WD, ~0,
+ be_height << 16 | be_width, cmdq_pkt);
}
+EXPORT_SYMBOL_GPL(mtk_mmsys_hdr_config);
+
+void mtk_mmsys_mixer_in_config(struct device *dev, int idx, bool alpha_sel, u16 alpha,
+ u8 mode, u32 biwidth, struct cmdq_pkt *cmdq_pkt)
+{
+ struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
+
+ mtk_mmsys_update_bits(mmsys, MT8195_VDO1_MIXER_IN1_ALPHA + (idx - 1) * 4, ~0,
+ alpha << 16 | alpha, cmdq_pkt);
+ mtk_mmsys_update_bits(mmsys, MT8195_VDO1_HDR_TOP_CFG, BIT(15 + idx), 0, cmdq_pkt);
+ mtk_mmsys_update_bits(mmsys, MT8195_VDO1_HDR_TOP_CFG, BIT(19 + idx),
+ alpha_sel << (19 + idx), cmdq_pkt);
+ mtk_mmsys_update_bits(mmsys, MT8195_VDO1_MIXER_IN1_PAD + (idx - 1) * 4,
+ GENMASK(31, 16) | GENMASK(1, 0), biwidth << 16 | mode, cmdq_pkt);
+}
+EXPORT_SYMBOL_GPL(mtk_mmsys_mixer_in_config);
+
+void mtk_mmsys_mixer_in_channel_swap(struct device *dev, int idx, bool channel_swap,
+ struct cmdq_pkt *cmdq_pkt)
+{
+ mtk_mmsys_update_bits(dev_get_drvdata(dev), MT8195_VDO1_MIXER_IN1_PAD + (idx - 1) * 4,
+ BIT(4), channel_swap << 4, cmdq_pkt);
+}
+EXPORT_SYMBOL_GPL(mtk_mmsys_mixer_in_channel_swap);
void mtk_mmsys_ddp_dpi_fmt_config(struct device *dev, u32 val)
{
@@ -146,42 +259,96 @@ void mtk_mmsys_ddp_dpi_fmt_config(struct device *dev, u32 val)
switch (val) {
case MTK_DPI_RGB888_SDR_CON:
mtk_mmsys_update_bits(mmsys, MT8186_MMSYS_DPI_OUTPUT_FORMAT,
- MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB888_SDR_CON);
+ MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB888_SDR_CON, NULL);
break;
case MTK_DPI_RGB565_SDR_CON:
mtk_mmsys_update_bits(mmsys, MT8186_MMSYS_DPI_OUTPUT_FORMAT,
- MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB565_SDR_CON);
+ MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB565_SDR_CON, NULL);
break;
case MTK_DPI_RGB565_DDR_CON:
mtk_mmsys_update_bits(mmsys, MT8186_MMSYS_DPI_OUTPUT_FORMAT,
- MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB565_DDR_CON);
+ MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB565_DDR_CON, NULL);
break;
case MTK_DPI_RGB888_DDR_CON:
default:
mtk_mmsys_update_bits(mmsys, MT8186_MMSYS_DPI_OUTPUT_FORMAT,
- MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB888_DDR_CON);
+ MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB888_DDR_CON, NULL);
break;
}
}
EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_dpi_fmt_config);
+void mtk_mmsys_vpp_rsz_merge_config(struct device *dev, u32 id, bool enable,
+ struct cmdq_pkt *cmdq_pkt)
+{
+ u32 reg;
+
+ switch (id) {
+ case 2:
+ reg = MT8195_SVPP2_BUF_BF_RSZ_SWITCH;
+ break;
+ case 3:
+ reg = MT8195_SVPP3_BUF_BF_RSZ_SWITCH;
+ break;
+ default:
+ dev_err(dev, "Invalid id %d\n", id);
+ return;
+ }
+
+ mtk_mmsys_update_bits(dev_get_drvdata(dev), reg, ~0, enable, cmdq_pkt);
+}
+EXPORT_SYMBOL_GPL(mtk_mmsys_vpp_rsz_merge_config);
+
+void mtk_mmsys_vpp_rsz_dcm_config(struct device *dev, bool enable,
+ struct cmdq_pkt *cmdq_pkt)
+{
+ u32 client;
+
+ client = MT8195_SVPP1_MDP_RSZ;
+ mtk_mmsys_update_bits(dev_get_drvdata(dev),
+ MT8195_VPP1_HW_DCM_1ST_DIS0, client,
+ ((enable) ? client : 0), cmdq_pkt);
+ mtk_mmsys_update_bits(dev_get_drvdata(dev),
+ MT8195_VPP1_HW_DCM_2ND_DIS0, client,
+ ((enable) ? client : 0), cmdq_pkt);
+
+ client = MT8195_SVPP2_MDP_RSZ | MT8195_SVPP3_MDP_RSZ;
+ mtk_mmsys_update_bits(dev_get_drvdata(dev),
+ MT8195_VPP1_HW_DCM_1ST_DIS1, client,
+ ((enable) ? client : 0), cmdq_pkt);
+ mtk_mmsys_update_bits(dev_get_drvdata(dev),
+ MT8195_VPP1_HW_DCM_2ND_DIS1, client,
+ ((enable) ? client : 0), cmdq_pkt);
+}
+EXPORT_SYMBOL_GPL(mtk_mmsys_vpp_rsz_dcm_config);
+
static int mtk_mmsys_reset_update(struct reset_controller_dev *rcdev, unsigned long id,
bool assert)
{
struct mtk_mmsys *mmsys = container_of(rcdev, struct mtk_mmsys, rcdev);
unsigned long flags;
+ u32 offset;
u32 reg;
- spin_lock_irqsave(&mmsys->lock, flags);
+ if (mmsys->data->rst_tb) {
+ if (id >= mmsys->data->num_resets) {
+ dev_err(rcdev->dev, "Invalid reset ID: %lu (>=%u)\n",
+ id, mmsys->data->num_resets);
+ return -EINVAL;
+ }
+ id = mmsys->data->rst_tb[id];
+ }
+
+ offset = (id / MMSYS_SW_RESET_PER_REG) * sizeof(u32);
+ id = id % MMSYS_SW_RESET_PER_REG;
+ reg = mmsys->data->sw0_rst_offset + offset;
- reg = readl_relaxed(mmsys->regs + mmsys->data->sw0_rst_offset);
+ spin_lock_irqsave(&mmsys->lock, flags);
if (assert)
- reg &= ~BIT(id);
+ mtk_mmsys_update_bits(mmsys, reg, BIT(id), 0, NULL);
else
- reg |= BIT(id);
-
- writel_relaxed(reg, mmsys->regs + mmsys->data->sw0_rst_offset);
+ mtk_mmsys_update_bits(mmsys, reg, BIT(id), BIT(id), NULL);
spin_unlock_irqrestore(&mmsys->lock, flags);
@@ -236,25 +403,37 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
return ret;
}
- spin_lock_init(&mmsys->lock);
+ mmsys->data = of_device_get_match_data(&pdev->dev);
- mmsys->rcdev.owner = THIS_MODULE;
- mmsys->rcdev.nr_resets = 32;
- mmsys->rcdev.ops = &mtk_mmsys_reset_ops;
- mmsys->rcdev.of_node = pdev->dev.of_node;
- ret = devm_reset_controller_register(&pdev->dev, &mmsys->rcdev);
- if (ret) {
- dev_err(&pdev->dev, "Couldn't register mmsys reset controller: %d\n", ret);
- return ret;
+ if (mmsys->data->num_resets > 0) {
+ spin_lock_init(&mmsys->lock);
+
+ mmsys->rcdev.owner = THIS_MODULE;
+ mmsys->rcdev.nr_resets = mmsys->data->num_resets;
+ mmsys->rcdev.ops = &mtk_mmsys_reset_ops;
+ mmsys->rcdev.of_node = pdev->dev.of_node;
+ ret = devm_reset_controller_register(&pdev->dev, &mmsys->rcdev);
+ if (ret) {
+ dev_err(&pdev->dev, "Couldn't register mmsys reset controller: %d\n", ret);
+ return ret;
+ }
}
- mmsys->data = of_device_get_match_data(&pdev->dev);
+ /* CMDQ is optional */
+ ret = cmdq_dev_get_client_reg(dev, &mmsys->cmdq_base, 0);
+ if (ret)
+ dev_dbg(dev, "No mediatek,gce-client-reg!\n");
+
platform_set_drvdata(pdev, mmsys);
clks = platform_device_register_data(&pdev->dev, mmsys->data->clk_driver,
PLATFORM_DEVID_AUTO, NULL, 0);
if (IS_ERR(clks))
return PTR_ERR(clks);
+ mmsys->clks_pdev = clks;
+
+ if (mmsys->data->is_vppsys)
+ goto out_probe_done;
drm = platform_device_register_data(&pdev->dev, "mediatek-drm",
PLATFORM_DEVID_AUTO, NULL, 0);
@@ -262,61 +441,45 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
platform_device_unregister(clks);
return PTR_ERR(drm);
}
+ mmsys->drm_pdev = drm;
+out_probe_done:
return 0;
}
+static void mtk_mmsys_remove(struct platform_device *pdev)
+{
+ struct mtk_mmsys *mmsys = platform_get_drvdata(pdev);
+
+ platform_device_unregister(mmsys->drm_pdev);
+ platform_device_unregister(mmsys->clks_pdev);
+}
+
static const struct of_device_id of_match_mtk_mmsys[] = {
- {
- .compatible = "mediatek,mt2701-mmsys",
- .data = &mt2701_mmsys_driver_data,
- },
- {
- .compatible = "mediatek,mt2712-mmsys",
- .data = &mt2712_mmsys_driver_data,
- },
- {
- .compatible = "mediatek,mt6779-mmsys",
- .data = &mt6779_mmsys_driver_data,
- },
- {
- .compatible = "mediatek,mt6797-mmsys",
- .data = &mt6797_mmsys_driver_data,
- },
- {
- .compatible = "mediatek,mt8167-mmsys",
- .data = &mt8167_mmsys_driver_data,
- },
- {
- .compatible = "mediatek,mt8173-mmsys",
- .data = &mt8173_mmsys_driver_data,
- },
- {
- .compatible = "mediatek,mt8183-mmsys",
- .data = &mt8183_mmsys_driver_data,
- },
- {
- .compatible = "mediatek,mt8186-mmsys",
- .data = &mt8186_mmsys_driver_data,
- },
- {
- .compatible = "mediatek,mt8192-mmsys",
- .data = &mt8192_mmsys_driver_data,
- },
- { /* deprecated compatible */
- .compatible = "mediatek,mt8195-mmsys",
- .data = &mt8195_vdosys0_driver_data,
- },
- {
- .compatible = "mediatek,mt8195-vdosys0",
- .data = &mt8195_vdosys0_driver_data,
- },
- {
- .compatible = "mediatek,mt8365-mmsys",
- .data = &mt8365_mmsys_driver_data,
- },
- { }
+ { .compatible = "mediatek,mt2701-mmsys", .data = &mt2701_mmsys_driver_data },
+ { .compatible = "mediatek,mt2712-mmsys", .data = &mt2712_mmsys_driver_data },
+ { .compatible = "mediatek,mt6779-mmsys", .data = &mt6779_mmsys_driver_data },
+ { .compatible = "mediatek,mt6795-mmsys", .data = &mt6795_mmsys_driver_data },
+ { .compatible = "mediatek,mt6797-mmsys", .data = &mt6797_mmsys_driver_data },
+ { .compatible = "mediatek,mt8167-mmsys", .data = &mt8167_mmsys_driver_data },
+ { .compatible = "mediatek,mt8173-mmsys", .data = &mt8173_mmsys_driver_data },
+ { .compatible = "mediatek,mt8183-mmsys", .data = &mt8183_mmsys_driver_data },
+ { .compatible = "mediatek,mt8186-mmsys", .data = &mt8186_mmsys_driver_data },
+ { .compatible = "mediatek,mt8188-vdosys0", .data = &mt8188_vdosys0_driver_data },
+ { .compatible = "mediatek,mt8188-vdosys1", .data = &mt8188_vdosys1_driver_data },
+ { .compatible = "mediatek,mt8188-vppsys0", .data = &mt8188_vppsys0_driver_data },
+ { .compatible = "mediatek,mt8188-vppsys1", .data = &mt8188_vppsys1_driver_data },
+ { .compatible = "mediatek,mt8192-mmsys", .data = &mt8192_mmsys_driver_data },
+ /* "mediatek,mt8195-mmsys" compatible is deprecated */
+ { .compatible = "mediatek,mt8195-mmsys", .data = &mt8195_vdosys0_driver_data },
+ { .compatible = "mediatek,mt8195-vdosys0", .data = &mt8195_vdosys0_driver_data },
+ { .compatible = "mediatek,mt8195-vdosys1", .data = &mt8195_vdosys1_driver_data },
+ { .compatible = "mediatek,mt8195-vppsys0", .data = &mt8195_vppsys0_driver_data },
+ { .compatible = "mediatek,mt8195-vppsys1", .data = &mt8195_vppsys1_driver_data },
+ { .compatible = "mediatek,mt8365-mmsys", .data = &mt8365_mmsys_driver_data },
+ { /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, of_match_mtk_mmsys);
static struct platform_driver mtk_mmsys_drv = {
.driver = {
@@ -324,6 +487,10 @@ static struct platform_driver mtk_mmsys_drv = {
.of_match_table = of_match_mtk_mmsys,
},
.probe = mtk_mmsys_probe,
+ .remove = mtk_mmsys_remove,
};
+module_platform_driver(mtk_mmsys_drv);
-builtin_platform_driver(mtk_mmsys_drv);
+MODULE_AUTHOR("Yongqiang Niu <yongqiang.niu@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek SoC MMSYS driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/mediatek/mtk-mmsys.h b/drivers/soc/mediatek/mtk-mmsys.h
index 77f37f8c715b..fe628d5f5198 100644
--- a/drivers/soc/mediatek/mtk-mmsys.h
+++ b/drivers/soc/mediatek/mtk-mmsys.h
@@ -78,6 +78,22 @@
#define DSI_SEL_IN_RDMA 0x1
#define DSI_SEL_IN_MASK 0x1
+#define MMSYS_RST_NR(bank, bit) (((bank) * 32) + (bit))
+
+/*
+ * This macro adds a compile time check to make sure that the in/out
+ * selection bit(s) fit in the register mask, similar to bitfield
+ * macros, but this does not transform the value.
+ */
+#define MMSYS_ROUTE(from, to, reg_addr, reg_mask, selection) \
+ { DDP_COMPONENT_##from, DDP_COMPONENT_##to, reg_addr, reg_mask, \
+ (__BUILD_BUG_ON_ZERO_MSG((reg_mask) == 0, "Invalid mask") + \
+ __BUILD_BUG_ON_ZERO_MSG(~(reg_mask) & (selection), \
+ #selection " does not fit in " \
+ #reg_mask) + \
+ (selection)) \
+ }
+
struct mtk_mmsys_routes {
u32 from_comp;
u32 to_comp;
@@ -86,15 +102,47 @@ struct mtk_mmsys_routes {
u32 val;
};
+/**
+ * struct mtk_mmsys_driver_data - Settings of the mmsys
+ * @clk_driver: Clock driver name that the mmsys is using
+ * (defined in drivers/clk/mediatek/clk-*.c).
+ * @routes: Routing table of the mmsys.
+ * It provides mux settings from one module to another.
+ * @num_routes: Array size of the routes.
+ * @sw0_rst_offset: Register offset for the reset control.
+ * @num_resets: Number of reset bits that are defined
+ * @is_vppsys: Whether the mmsys is VPPSYS (Video Processing Pipe)
+ * or VDOSYS (Video). Only VDOSYS needs to be added to drm driver.
+ * @vsync_len: VSYNC length of the MIXER.
+ * VSYNC is usually triggered by the connector, so its length is a
+ * fixed value when the frame rate is decided, but ETHDR and
+ * MIXER generate their own VSYNC due to hardware design, therefore
+ * MIXER has to sync with ETHDR by adjusting VSYNC length.
+ * On MT8195, there is no such setting so we use the gap between
+ * falling edge and rising edge of SOF (Start of Frame) signal to
+ * do the job, but since MT8188, VSYNC_LEN setting is introduced to
+ * solve the problem and is given 0x40 (ticks) as the default value.
+ * Please notice that this value has to be set to 1 (minimum) if
+ * ETHDR is bypassed, otherwise MIXER could wait too long and causing
+ * underflow.
+ *
+ * Each MMSYS (multi-media system) may have different settings, they may use
+ * different clock sources, mux settings, reset control ...etc., and these
+ * differences are all stored here.
+ */
struct mtk_mmsys_driver_data {
const char *clk_driver;
const struct mtk_mmsys_routes *routes;
const unsigned int num_routes;
const u16 sw0_rst_offset;
+ const u8 *rst_tb;
+ const u32 num_resets;
+ const bool is_vppsys;
+ const u8 vsync_len;
};
/*
- * Routes in mt8173, mt2701, mt2712 are different. That means
+ * Routes in mt2701 and mt2712 are different. That means
* in the same register address, it controls different input/output
* selection for each SoC. But, right now, they use the same table as
* default routes meet their requirements. But we don't have the complete
diff --git a/drivers/soc/mediatek/mtk-mutex.c b/drivers/soc/mediatek/mtk-mutex.c
index c1a33d52038e..38179e8cd98f 100644
--- a/drivers/soc/mediatek/mtk-mutex.c
+++ b/drivers/soc/mediatek/mtk-mutex.c
@@ -6,25 +6,46 @@
#include <linux/clk.h>
#include <linux/iopoll.h>
#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/of_address.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/soc/mediatek/mtk-mmsys.h>
#include <linux/soc/mediatek/mtk-mutex.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
+#define MTK_MUTEX_MAX_HANDLES 10
+
#define MT2701_MUTEX0_MOD0 0x2c
#define MT2701_MUTEX0_SOF0 0x30
+#define MT2701_MUTEX0_MOD1 0x34
+
#define MT8183_MUTEX0_MOD0 0x30
+#define MT8183_MUTEX0_MOD1 0x34
#define MT8183_MUTEX0_SOF0 0x2c
#define DISP_REG_MUTEX_EN(n) (0x20 + 0x20 * (n))
#define DISP_REG_MUTEX(n) (0x24 + 0x20 * (n))
#define DISP_REG_MUTEX_RST(n) (0x28 + 0x20 * (n))
-#define DISP_REG_MUTEX_MOD(mutex_mod_reg, n) (mutex_mod_reg + 0x20 * (n))
+/*
+ * Some SoCs may have multiple MUTEX_MOD registers as more than 32 mods
+ * are present, hence requiring multiple 32-bits registers.
+ *
+ * The mutex_table_mod fully represents that by defining the number of
+ * the mod sequentially, later used as a bit number, which can be more
+ * than 0..31.
+ *
+ * In order to retain compatibility with older SoCs, we perform R/W on
+ * the single 32 bits registers, but this requires us to translate the
+ * mutex ID bit accordingly.
+ */
+#define DISP_REG_MUTEX_MOD(mutex, id, n) ({ \
+ const typeof(mutex) _mutex = (mutex); \
+ u32 _offset = (id) < 32 ? \
+ _mutex->data->mutex_mod_reg : \
+ _mutex->data->mutex_mod1_reg; \
+ _offset + 0x20 * (n); \
+})
#define DISP_REG_MUTEX_SOF(mutex_sof_reg, n) (mutex_sof_reg + 0x20 * (n))
-#define DISP_REG_MUTEX_MOD2(n) (0x34 + 0x20 * (n))
#define INT_MUTEX BIT(1)
@@ -116,6 +137,46 @@
#define MT8173_MUTEX_MOD_DISP_PWM1 24
#define MT8173_MUTEX_MOD_DISP_OD 25
+#define MT8188_MUTEX_MOD_DISP_OVL0 0
+#define MT8188_MUTEX_MOD_DISP_WDMA0 1
+#define MT8188_MUTEX_MOD_DISP_RDMA0 2
+#define MT8188_MUTEX_MOD_DISP_COLOR0 3
+#define MT8188_MUTEX_MOD_DISP_CCORR0 4
+#define MT8188_MUTEX_MOD_DISP_AAL0 5
+#define MT8188_MUTEX_MOD_DISP_GAMMA0 6
+#define MT8188_MUTEX_MOD_DISP_DITHER0 7
+#define MT8188_MUTEX_MOD_DISP_DSI0 8
+#define MT8188_MUTEX_MOD_DISP_DSC_WRAP0_CORE0 9
+#define MT8188_MUTEX_MOD_DISP_VPP_MERGE 20
+#define MT8188_MUTEX_MOD_DISP_DP_INTF0 21
+#define MT8188_MUTEX_MOD_DISP_POSTMASK0 24
+#define MT8188_MUTEX_MOD2_DISP_PWM0 33
+
+#define MT8188_MUTEX_MOD_DISP1_MDP_RDMA0 0
+#define MT8188_MUTEX_MOD_DISP1_MDP_RDMA1 1
+#define MT8188_MUTEX_MOD_DISP1_MDP_RDMA2 2
+#define MT8188_MUTEX_MOD_DISP1_MDP_RDMA3 3
+#define MT8188_MUTEX_MOD_DISP1_MDP_RDMA4 4
+#define MT8188_MUTEX_MOD_DISP1_MDP_RDMA5 5
+#define MT8188_MUTEX_MOD_DISP1_MDP_RDMA6 6
+#define MT8188_MUTEX_MOD_DISP1_MDP_RDMA7 7
+#define MT8188_MUTEX_MOD_DISP1_PADDING0 8
+#define MT8188_MUTEX_MOD_DISP1_PADDING1 9
+#define MT8188_MUTEX_MOD_DISP1_PADDING2 10
+#define MT8188_MUTEX_MOD_DISP1_PADDING3 11
+#define MT8188_MUTEX_MOD_DISP1_PADDING4 12
+#define MT8188_MUTEX_MOD_DISP1_PADDING5 13
+#define MT8188_MUTEX_MOD_DISP1_PADDING6 14
+#define MT8188_MUTEX_MOD_DISP1_PADDING7 15
+#define MT8188_MUTEX_MOD_DISP1_VPP_MERGE0 20
+#define MT8188_MUTEX_MOD_DISP1_VPP_MERGE1 21
+#define MT8188_MUTEX_MOD_DISP1_VPP_MERGE2 22
+#define MT8188_MUTEX_MOD_DISP1_VPP_MERGE3 23
+#define MT8188_MUTEX_MOD_DISP1_VPP_MERGE4 24
+#define MT8188_MUTEX_MOD_DISP1_DISP_MIXER 30
+#define MT8188_MUTEX_MOD_DISP1_DPI1 38
+#define MT8188_MUTEX_MOD_DISP1_DP_INTF1 39
+
#define MT8195_MUTEX_MOD_DISP_OVL0 0
#define MT8195_MUTEX_MOD_DISP_WDMA0 1
#define MT8195_MUTEX_MOD_DISP_RDMA0 2
@@ -130,6 +191,71 @@
#define MT8195_MUTEX_MOD_DISP_DP_INTF0 21
#define MT8195_MUTEX_MOD_DISP_PWM0 27
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA0 0
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA1 1
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA2 2
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA3 3
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA4 4
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA5 5
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA6 6
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA7 7
+#define MT8195_MUTEX_MOD_DISP1_VPP_MERGE0 8
+#define MT8195_MUTEX_MOD_DISP1_VPP_MERGE1 9
+#define MT8195_MUTEX_MOD_DISP1_VPP_MERGE2 10
+#define MT8195_MUTEX_MOD_DISP1_VPP_MERGE3 11
+#define MT8195_MUTEX_MOD_DISP1_VPP_MERGE4 12
+#define MT8195_MUTEX_MOD_DISP1_DISP_MIXER 18
+#define MT8195_MUTEX_MOD_DISP1_DPI0 25
+#define MT8195_MUTEX_MOD_DISP1_DPI1 26
+#define MT8195_MUTEX_MOD_DISP1_DP_INTF0 27
+
+/* VPPSYS0 */
+#define MT8195_MUTEX_MOD_MDP_RDMA0 0
+#define MT8195_MUTEX_MOD_MDP_FG0 1
+#define MT8195_MUTEX_MOD_MDP_STITCH0 2
+#define MT8195_MUTEX_MOD_MDP_HDR0 3
+#define MT8195_MUTEX_MOD_MDP_AAL0 4
+#define MT8195_MUTEX_MOD_MDP_RSZ0 5
+#define MT8195_MUTEX_MOD_MDP_TDSHP0 6
+#define MT8195_MUTEX_MOD_MDP_COLOR0 7
+#define MT8195_MUTEX_MOD_MDP_OVL0 8
+#define MT8195_MUTEX_MOD_MDP_PAD0 9
+#define MT8195_MUTEX_MOD_MDP_TCC0 10
+#define MT8195_MUTEX_MOD_MDP_WROT0 11
+
+/* VPPSYS1 */
+#define MT8195_MUTEX_MOD_MDP_TCC1 3
+#define MT8195_MUTEX_MOD_MDP_RDMA1 4
+#define MT8195_MUTEX_MOD_MDP_RDMA2 5
+#define MT8195_MUTEX_MOD_MDP_RDMA3 6
+#define MT8195_MUTEX_MOD_MDP_FG1 7
+#define MT8195_MUTEX_MOD_MDP_FG2 8
+#define MT8195_MUTEX_MOD_MDP_FG3 9
+#define MT8195_MUTEX_MOD_MDP_HDR1 10
+#define MT8195_MUTEX_MOD_MDP_HDR2 11
+#define MT8195_MUTEX_MOD_MDP_HDR3 12
+#define MT8195_MUTEX_MOD_MDP_AAL1 13
+#define MT8195_MUTEX_MOD_MDP_AAL2 14
+#define MT8195_MUTEX_MOD_MDP_AAL3 15
+#define MT8195_MUTEX_MOD_MDP_RSZ1 16
+#define MT8195_MUTEX_MOD_MDP_RSZ2 17
+#define MT8195_MUTEX_MOD_MDP_RSZ3 18
+#define MT8195_MUTEX_MOD_MDP_TDSHP1 19
+#define MT8195_MUTEX_MOD_MDP_TDSHP2 20
+#define MT8195_MUTEX_MOD_MDP_TDSHP3 21
+#define MT8195_MUTEX_MOD_MDP_MERGE2 22
+#define MT8195_MUTEX_MOD_MDP_MERGE3 23
+#define MT8195_MUTEX_MOD_MDP_COLOR1 24
+#define MT8195_MUTEX_MOD_MDP_COLOR2 25
+#define MT8195_MUTEX_MOD_MDP_COLOR3 26
+#define MT8195_MUTEX_MOD_MDP_OVL1 27
+#define MT8195_MUTEX_MOD_MDP_PAD1 28
+#define MT8195_MUTEX_MOD_MDP_PAD2 29
+#define MT8195_MUTEX_MOD_MDP_PAD3 30
+#define MT8195_MUTEX_MOD_MDP_WROT1 31
+#define MT8195_MUTEX_MOD_MDP_WROT2 32
+#define MT8195_MUTEX_MOD_MDP_WROT3 33
+
#define MT8365_MUTEX_MOD_DISP_OVL0 7
#define MT8365_MUTEX_MOD_DISP_OVL0_2L 8
#define MT8365_MUTEX_MOD_DISP_RDMA0 9
@@ -180,6 +306,10 @@
#define MT8167_MUTEX_SOF_DPI1 3
#define MT8183_MUTEX_SOF_DSI0 1
#define MT8183_MUTEX_SOF_DPI0 2
+#define MT8188_MUTEX_SOF_DSI0 1
+#define MT8188_MUTEX_SOF_DP_INTF0 3
+#define MT8188_MUTEX_SOF_DP_INTF1 4
+#define MT8188_MUTEX_SOF_DPI1 5
#define MT8195_MUTEX_SOF_DSI0 1
#define MT8195_MUTEX_SOF_DSI1 2
#define MT8195_MUTEX_SOF_DP_INTF0 3
@@ -189,6 +319,10 @@
#define MT8183_MUTEX_EOF_DSI0 (MT8183_MUTEX_SOF_DSI0 << 6)
#define MT8183_MUTEX_EOF_DPI0 (MT8183_MUTEX_SOF_DPI0 << 6)
+#define MT8188_MUTEX_EOF_DSI0 (MT8188_MUTEX_SOF_DSI0 << 7)
+#define MT8188_MUTEX_EOF_DP_INTF0 (MT8188_MUTEX_SOF_DP_INTF0 << 7)
+#define MT8188_MUTEX_EOF_DP_INTF1 (MT8188_MUTEX_SOF_DP_INTF1 << 7)
+#define MT8188_MUTEX_EOF_DPI1 (MT8188_MUTEX_SOF_DPI1 << 7)
#define MT8195_MUTEX_EOF_DSI0 (MT8195_MUTEX_SOF_DSI0 << 7)
#define MT8195_MUTEX_EOF_DSI1 (MT8195_MUTEX_SOF_DSI1 << 7)
#define MT8195_MUTEX_EOF_DP_INTF0 (MT8195_MUTEX_SOF_DP_INTF0 << 7)
@@ -197,7 +331,7 @@
#define MT8195_MUTEX_EOF_DPI1 (MT8195_MUTEX_SOF_DPI1 << 7)
struct mtk_mutex {
- int id;
+ u8 id;
bool claimed;
};
@@ -215,11 +349,12 @@ 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_mod1_reg;
+ const u16 mutex_sof_reg;
const bool no_clk;
};
@@ -227,13 +362,13 @@ struct mtk_mutex_ctx {
struct device *dev;
struct clk *clk;
void __iomem *regs;
- struct mtk_mutex mutex[10];
+ struct mtk_mutex mutex[MTK_MUTEX_MAX_HANDLES];
const struct mtk_mutex_data *data;
phys_addr_t addr;
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,
@@ -242,7 +377,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,
@@ -262,7 +397,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,
@@ -277,7 +412,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,
@@ -295,7 +430,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,
@@ -309,7 +444,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,
@@ -320,7 +455,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,
@@ -333,7 +468,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,
@@ -344,7 +479,82 @@ 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 mt8192_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,
+ [DDP_COMPONENT_COLOR0] = MT8188_MUTEX_MOD_DISP_COLOR0,
+ [DDP_COMPONENT_CCORR] = MT8188_MUTEX_MOD_DISP_CCORR0,
+ [DDP_COMPONENT_AAL0] = MT8188_MUTEX_MOD_DISP_AAL0,
+ [DDP_COMPONENT_GAMMA] = MT8188_MUTEX_MOD_DISP_GAMMA0,
+ [DDP_COMPONENT_POSTMASK0] = MT8188_MUTEX_MOD_DISP_POSTMASK0,
+ [DDP_COMPONENT_DITHER0] = MT8188_MUTEX_MOD_DISP_DITHER0,
+ [DDP_COMPONENT_MERGE0] = MT8188_MUTEX_MOD_DISP_VPP_MERGE,
+ [DDP_COMPONENT_DSC0] = MT8188_MUTEX_MOD_DISP_DSC_WRAP0_CORE0,
+ [DDP_COMPONENT_DSI0] = MT8188_MUTEX_MOD_DISP_DSI0,
+ [DDP_COMPONENT_PWM0] = MT8188_MUTEX_MOD2_DISP_PWM0,
+ [DDP_COMPONENT_DP_INTF0] = MT8188_MUTEX_MOD_DISP_DP_INTF0,
+ [DDP_COMPONENT_DP_INTF1] = MT8188_MUTEX_MOD_DISP1_DP_INTF1,
+ [DDP_COMPONENT_DPI1] = MT8188_MUTEX_MOD_DISP1_DPI1,
+ [DDP_COMPONENT_ETHDR_MIXER] = MT8188_MUTEX_MOD_DISP1_DISP_MIXER,
+ [DDP_COMPONENT_MDP_RDMA0] = MT8188_MUTEX_MOD_DISP1_MDP_RDMA0,
+ [DDP_COMPONENT_MDP_RDMA1] = MT8188_MUTEX_MOD_DISP1_MDP_RDMA1,
+ [DDP_COMPONENT_MDP_RDMA2] = MT8188_MUTEX_MOD_DISP1_MDP_RDMA2,
+ [DDP_COMPONENT_MDP_RDMA3] = MT8188_MUTEX_MOD_DISP1_MDP_RDMA3,
+ [DDP_COMPONENT_MDP_RDMA4] = MT8188_MUTEX_MOD_DISP1_MDP_RDMA4,
+ [DDP_COMPONENT_MDP_RDMA5] = MT8188_MUTEX_MOD_DISP1_MDP_RDMA5,
+ [DDP_COMPONENT_MDP_RDMA6] = MT8188_MUTEX_MOD_DISP1_MDP_RDMA6,
+ [DDP_COMPONENT_MDP_RDMA7] = MT8188_MUTEX_MOD_DISP1_MDP_RDMA7,
+ [DDP_COMPONENT_PADDING0] = MT8188_MUTEX_MOD_DISP1_PADDING0,
+ [DDP_COMPONENT_PADDING1] = MT8188_MUTEX_MOD_DISP1_PADDING1,
+ [DDP_COMPONENT_PADDING2] = MT8188_MUTEX_MOD_DISP1_PADDING2,
+ [DDP_COMPONENT_PADDING3] = MT8188_MUTEX_MOD_DISP1_PADDING3,
+ [DDP_COMPONENT_PADDING4] = MT8188_MUTEX_MOD_DISP1_PADDING4,
+ [DDP_COMPONENT_PADDING5] = MT8188_MUTEX_MOD_DISP1_PADDING5,
+ [DDP_COMPONENT_PADDING6] = MT8188_MUTEX_MOD_DISP1_PADDING6,
+ [DDP_COMPONENT_PADDING7] = MT8188_MUTEX_MOD_DISP1_PADDING7,
+ [DDP_COMPONENT_MERGE1] = MT8188_MUTEX_MOD_DISP1_VPP_MERGE0,
+ [DDP_COMPONENT_MERGE2] = MT8188_MUTEX_MOD_DISP1_VPP_MERGE1,
+ [DDP_COMPONENT_MERGE3] = MT8188_MUTEX_MOD_DISP1_VPP_MERGE2,
+ [DDP_COMPONENT_MERGE4] = MT8188_MUTEX_MOD_DISP1_VPP_MERGE3,
+ [DDP_COMPONENT_MERGE5] = MT8188_MUTEX_MOD_DISP1_VPP_MERGE4,
+};
+
+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,
@@ -358,7 +568,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,
@@ -372,9 +582,70 @@ static const unsigned int mt8195_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_DSI0] = MT8195_MUTEX_MOD_DISP_DSI0,
[DDP_COMPONENT_PWM0] = MT8195_MUTEX_MOD_DISP_PWM0,
[DDP_COMPONENT_DP_INTF0] = MT8195_MUTEX_MOD_DISP_DP_INTF0,
+ [DDP_COMPONENT_MDP_RDMA0] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA0,
+ [DDP_COMPONENT_MDP_RDMA1] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA1,
+ [DDP_COMPONENT_MDP_RDMA2] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA2,
+ [DDP_COMPONENT_MDP_RDMA3] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA3,
+ [DDP_COMPONENT_MDP_RDMA4] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA4,
+ [DDP_COMPONENT_MDP_RDMA5] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA5,
+ [DDP_COMPONENT_MDP_RDMA6] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA6,
+ [DDP_COMPONENT_MDP_RDMA7] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA7,
+ [DDP_COMPONENT_MERGE1] = MT8195_MUTEX_MOD_DISP1_VPP_MERGE0,
+ [DDP_COMPONENT_MERGE2] = MT8195_MUTEX_MOD_DISP1_VPP_MERGE1,
+ [DDP_COMPONENT_MERGE3] = MT8195_MUTEX_MOD_DISP1_VPP_MERGE2,
+ [DDP_COMPONENT_MERGE4] = MT8195_MUTEX_MOD_DISP1_VPP_MERGE3,
+ [DDP_COMPONENT_ETHDR_MIXER] = MT8195_MUTEX_MOD_DISP1_DISP_MIXER,
+ [DDP_COMPONENT_MERGE5] = MT8195_MUTEX_MOD_DISP1_VPP_MERGE4,
+ [DDP_COMPONENT_DP_INTF1] = MT8195_MUTEX_MOD_DISP1_DP_INTF0,
+};
+
+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,
+ [MUTEX_MOD_IDX_MDP_RDMA3] = MT8195_MUTEX_MOD_MDP_RDMA3,
+ [MUTEX_MOD_IDX_MDP_STITCH0] = MT8195_MUTEX_MOD_MDP_STITCH0,
+ [MUTEX_MOD_IDX_MDP_FG0] = MT8195_MUTEX_MOD_MDP_FG0,
+ [MUTEX_MOD_IDX_MDP_FG1] = MT8195_MUTEX_MOD_MDP_FG1,
+ [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_HDR1] = MT8195_MUTEX_MOD_MDP_HDR1,
+ [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_AAL1] = MT8195_MUTEX_MOD_MDP_AAL1,
+ [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_RSZ1] = MT8195_MUTEX_MOD_MDP_RSZ1,
+ [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_TDSHP1] = MT8195_MUTEX_MOD_MDP_TDSHP1,
+ [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_COLOR1] = MT8195_MUTEX_MOD_MDP_COLOR1,
+ [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_OVL1] = MT8195_MUTEX_MOD_MDP_OVL1,
+ [MUTEX_MOD_IDX_MDP_PAD0] = MT8195_MUTEX_MOD_MDP_PAD0,
+ [MUTEX_MOD_IDX_MDP_PAD1] = MT8195_MUTEX_MOD_MDP_PAD1,
+ [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_TCC1] = MT8195_MUTEX_MOD_MDP_TCC1,
+ [MUTEX_MOD_IDX_MDP_WROT0] = MT8195_MUTEX_MOD_MDP_WROT0,
+ [MUTEX_MOD_IDX_MDP_WROT1] = MT8195_MUTEX_MOD_MDP_WROT1,
+ [MUTEX_MOD_IDX_MDP_WROT2] = MT8195_MUTEX_MOD_MDP_WROT2,
+ [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,
@@ -390,7 +661,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,
@@ -400,14 +671,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,
@@ -415,13 +686,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,
@@ -435,7 +706,19 @@ 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 mt8195_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,
+ [MUTEX_SOF_DPI1] =
+ MT8188_MUTEX_SOF_DPI1 | MT8188_MUTEX_EOF_DPI1,
+ [MUTEX_SOF_DP_INTF0] =
+ MT8188_MUTEX_SOF_DP_INTF0 | MT8188_MUTEX_EOF_DP_INTF0,
+ [MUTEX_SOF_DP_INTF1] =
+ MT8188_MUTEX_SOF_DP_INTF1 | MT8188_MUTEX_EOF_DP_INTF1,
+};
+
+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,
@@ -451,6 +734,7 @@ static const struct mtk_mutex_data mt2701_mutex_driver_data = {
.mutex_mod = mt2701_mutex_mod,
.mutex_sof = mt2712_mutex_sof,
.mutex_mod_reg = MT2701_MUTEX0_MOD0,
+ .mutex_mod1_reg = MT2701_MUTEX0_MOD1,
.mutex_sof_reg = MT2701_MUTEX0_SOF0,
};
@@ -458,6 +742,7 @@ static const struct mtk_mutex_data mt2712_mutex_driver_data = {
.mutex_mod = mt2712_mutex_mod,
.mutex_sof = mt2712_mutex_sof,
.mutex_mod_reg = MT2701_MUTEX0_MOD0,
+ .mutex_mod1_reg = MT2701_MUTEX0_MOD1,
.mutex_sof_reg = MT2701_MUTEX0_SOF0,
};
@@ -465,6 +750,7 @@ static const struct mtk_mutex_data mt6795_mutex_driver_data = {
.mutex_mod = mt8173_mutex_mod,
.mutex_sof = mt6795_mutex_sof,
.mutex_mod_reg = MT2701_MUTEX0_MOD0,
+ .mutex_mod1_reg = MT2701_MUTEX0_MOD1,
.mutex_sof_reg = MT2701_MUTEX0_SOF0,
};
@@ -472,6 +758,7 @@ static const struct mtk_mutex_data mt8167_mutex_driver_data = {
.mutex_mod = mt8167_mutex_mod,
.mutex_sof = mt8167_mutex_sof,
.mutex_mod_reg = MT2701_MUTEX0_MOD0,
+ .mutex_mod1_reg = MT2701_MUTEX0_MOD1,
.mutex_sof_reg = MT2701_MUTEX0_SOF0,
.no_clk = true,
};
@@ -480,6 +767,7 @@ static const struct mtk_mutex_data mt8173_mutex_driver_data = {
.mutex_mod = mt8173_mutex_mod,
.mutex_sof = mt2712_mutex_sof,
.mutex_mod_reg = MT2701_MUTEX0_MOD0,
+ .mutex_mod1_reg = MT2701_MUTEX0_MOD1,
.mutex_sof_reg = MT2701_MUTEX0_SOF0,
};
@@ -487,6 +775,7 @@ static const struct mtk_mutex_data mt8183_mutex_driver_data = {
.mutex_mod = mt8183_mutex_mod,
.mutex_sof = mt8183_mutex_sof,
.mutex_mod_reg = MT8183_MUTEX0_MOD0,
+ .mutex_mod1_reg = MT8183_MUTEX0_MOD1,
.mutex_sof_reg = MT8183_MUTEX0_SOF0,
.mutex_table_mod = mt8183_mutex_table_mod,
.no_clk = true,
@@ -494,6 +783,7 @@ static const struct mtk_mutex_data mt8183_mutex_driver_data = {
static const struct mtk_mutex_data mt8186_mdp_mutex_driver_data = {
.mutex_mod_reg = MT8183_MUTEX0_MOD0,
+ .mutex_mod1_reg = MT8183_MUTEX0_MOD1,
.mutex_sof_reg = MT8183_MUTEX0_SOF0,
.mutex_table_mod = mt8186_mdp_mutex_table_mod,
};
@@ -502,13 +792,31 @@ static const struct mtk_mutex_data mt8186_mutex_driver_data = {
.mutex_mod = mt8186_mutex_mod,
.mutex_sof = mt8186_mutex_sof,
.mutex_mod_reg = MT8183_MUTEX0_MOD0,
+ .mutex_mod1_reg = MT8183_MUTEX0_MOD1,
.mutex_sof_reg = MT8183_MUTEX0_SOF0,
};
+static const struct mtk_mutex_data mt8188_mutex_driver_data = {
+ .mutex_mod = mt8188_mutex_mod,
+ .mutex_sof = mt8188_mutex_sof,
+ .mutex_mod_reg = MT8183_MUTEX0_MOD0,
+ .mutex_mod1_reg = MT8183_MUTEX0_MOD1,
+ .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_mod1_reg = MT8183_MUTEX0_MOD1,
+ .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,
.mutex_mod_reg = MT8183_MUTEX0_MOD0,
+ .mutex_mod1_reg = MT8183_MUTEX0_MOD1,
.mutex_sof_reg = MT8183_MUTEX0_SOF0,
};
@@ -516,13 +824,23 @@ static const struct mtk_mutex_data mt8195_mutex_driver_data = {
.mutex_mod = mt8195_mutex_mod,
.mutex_sof = mt8195_mutex_sof,
.mutex_mod_reg = MT8183_MUTEX0_MOD0,
+ .mutex_mod1_reg = MT8183_MUTEX0_MOD1,
.mutex_sof_reg = MT8183_MUTEX0_SOF0,
};
+static const struct mtk_mutex_data mt8195_vpp_mutex_driver_data = {
+ .mutex_sof = mt8195_mutex_sof,
+ .mutex_mod_reg = MT8183_MUTEX0_MOD0,
+ .mutex_mod1_reg = MT8183_MUTEX0_MOD1,
+ .mutex_sof_reg = MT8183_MUTEX0_SOF0,
+ .mutex_table_mod = mt8195_mutex_table_mod,
+};
+
static const struct mtk_mutex_data mt8365_mutex_driver_data = {
.mutex_mod = mt8365_mutex_mod,
.mutex_sof = mt8183_mutex_sof,
.mutex_mod_reg = MT8183_MUTEX0_MOD0,
+ .mutex_mod1_reg = MT8183_MUTEX0_MOD1,
.mutex_sof_reg = MT8183_MUTEX0_SOF0,
.no_clk = true,
};
@@ -532,7 +850,7 @@ struct mtk_mutex *mtk_mutex_get(struct device *dev)
struct mtk_mutex_ctx *mtx = dev_get_drvdata(dev);
int i;
- for (i = 0; i < 10; i++)
+ for (i = 0; i < MTK_MUTEX_MAX_HANDLES; i++)
if (!mtx->mutex[i].claimed) {
mtx->mutex[i].claimed = true;
return &mtx->mutex[i];
@@ -575,7 +893,7 @@ void mtk_mutex_add_comp(struct mtk_mutex *mutex,
struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]);
unsigned int reg;
- unsigned int sof_id;
+ unsigned int sof_id, mod_id;
unsigned int offset;
WARN_ON(&mtx->mutex[mutex->id] != mutex);
@@ -602,19 +920,15 @@ void mtk_mutex_add_comp(struct mtk_mutex *mutex,
case DDP_COMPONENT_DP_INTF0:
sof_id = MUTEX_SOF_DP_INTF0;
break;
+ case DDP_COMPONENT_DP_INTF1:
+ sof_id = MUTEX_SOF_DP_INTF1;
+ break;
default:
- if (mtx->data->mutex_mod[id] < 32) {
- offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg,
- mutex->id);
- reg = readl_relaxed(mtx->regs + offset);
- reg |= 1 << mtx->data->mutex_mod[id];
- writel_relaxed(reg, mtx->regs + offset);
- } else {
- offset = DISP_REG_MUTEX_MOD2(mutex->id);
- reg = readl_relaxed(mtx->regs + offset);
- reg |= 1 << (mtx->data->mutex_mod[id] - 32);
- writel_relaxed(reg, mtx->regs + offset);
- }
+ offset = DISP_REG_MUTEX_MOD(mtx, mtx->data->mutex_mod[id], mutex->id);
+ mod_id = mtx->data->mutex_mod[id] % 32;
+ reg = readl_relaxed(mtx->regs + offset);
+ reg |= BIT(mod_id);
+ writel_relaxed(reg, mtx->regs + offset);
return;
}
@@ -630,6 +944,7 @@ void mtk_mutex_remove_comp(struct mtk_mutex *mutex,
struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]);
unsigned int reg;
+ unsigned int mod_id;
unsigned int offset;
WARN_ON(&mtx->mutex[mutex->id] != mutex);
@@ -642,24 +957,18 @@ void mtk_mutex_remove_comp(struct mtk_mutex *mutex,
case DDP_COMPONENT_DPI0:
case DDP_COMPONENT_DPI1:
case DDP_COMPONENT_DP_INTF0:
+ case DDP_COMPONENT_DP_INTF1:
writel_relaxed(MUTEX_SOF_SINGLE_MODE,
mtx->regs +
DISP_REG_MUTEX_SOF(mtx->data->mutex_sof_reg,
mutex->id));
break;
default:
- if (mtx->data->mutex_mod[id] < 32) {
- offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg,
- mutex->id);
- reg = readl_relaxed(mtx->regs + offset);
- reg &= ~(1 << mtx->data->mutex_mod[id]);
- writel_relaxed(reg, mtx->regs + offset);
- } else {
- offset = DISP_REG_MUTEX_MOD2(mutex->id);
- reg = readl_relaxed(mtx->regs + offset);
- reg &= ~(1 << (mtx->data->mutex_mod[id] - 32));
- writel_relaxed(reg, mtx->regs + offset);
- }
+ offset = DISP_REG_MUTEX_MOD(mtx, mtx->data->mutex_mod[id], mutex->id);
+ mod_id = mtx->data->mutex_mod[id] % 32;
+ reg = readl_relaxed(mtx->regs + offset);
+ reg &= ~BIT(mod_id);
+ writel_relaxed(reg, mtx->regs + offset);
break;
}
}
@@ -680,23 +989,18 @@ int mtk_mutex_enable_by_cmdq(struct mtk_mutex *mutex, void *pkt)
{
struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]);
-#if IS_REACHABLE(CONFIG_MTK_CMDQ)
struct cmdq_pkt *cmdq_pkt = (struct cmdq_pkt *)pkt;
WARN_ON(&mtx->mutex[mutex->id] != mutex);
if (!mtx->cmdq_reg.size) {
dev_err(mtx->dev, "mediatek,gce-client-reg hasn't been set");
- return -EINVAL;
+ return -ENODEV;
}
cmdq_pkt_write(cmdq_pkt, mtx->cmdq_reg.subsys,
mtx->addr + DISP_REG_MUTEX_EN(mutex->id), 1);
return 0;
-#else
- dev_err(mtx->dev, "Not support for enable MUTEX by CMDQ");
- return -ENODEV;
-#endif
}
EXPORT_SYMBOL_GPL(mtk_mutex_enable_by_cmdq);
@@ -740,7 +1044,7 @@ int mtk_mutex_write_mod(struct mtk_mutex *mutex,
struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]);
unsigned int reg;
- unsigned int offset;
+ u32 offset, mod_id;
WARN_ON(&mtx->mutex[mutex->id] != mutex);
@@ -750,14 +1054,14 @@ int mtk_mutex_write_mod(struct mtk_mutex *mutex,
return -EINVAL;
}
- offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg,
- mutex->id);
- reg = readl_relaxed(mtx->regs + offset);
+ offset = DISP_REG_MUTEX_MOD(mtx, mtx->data->mutex_table_mod[idx], mutex->id);
+ mod_id = mtx->data->mutex_table_mod[idx] % 32;
+ reg = readl_relaxed(mtx->regs + offset);
if (clear)
- reg &= ~BIT(mtx->data->mutex_table_mod[idx]);
+ reg &= ~BIT(mod_id);
else
- reg |= BIT(mtx->data->mutex_table_mod[idx]);
+ reg |= BIT(mod_id);
writel_relaxed(reg, mtx->regs + offset);
@@ -791,27 +1095,21 @@ static int mtk_mutex_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct mtk_mutex_ctx *mtx;
struct resource *regs;
- int i;
-#if IS_REACHABLE(CONFIG_MTK_CMDQ)
- int ret;
-#endif
+ int i, ret;
mtx = devm_kzalloc(dev, sizeof(*mtx), GFP_KERNEL);
if (!mtx)
return -ENOMEM;
- for (i = 0; i < 10; i++)
+ for (i = 0; i < MTK_MUTEX_MAX_HANDLES; i++)
mtx->mutex[i].id = i;
mtx->data = of_device_get_match_data(dev);
if (!mtx->data->no_clk) {
mtx->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(mtx->clk)) {
- if (PTR_ERR(mtx->clk) != -EPROBE_DEFER)
- dev_err(dev, "Failed to get clock\n");
- return PTR_ERR(mtx->clk);
- }
+ if (IS_ERR(mtx->clk))
+ return dev_err_probe(dev, PTR_ERR(mtx->clk), "Failed to get clock\n");
}
mtx->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &regs);
@@ -821,57 +1119,44 @@ static int mtk_mutex_probe(struct platform_device *pdev)
}
mtx->addr = regs->start;
-#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+ /* CMDQ is optional */
ret = cmdq_dev_get_client_reg(dev, &mtx->cmdq_reg, 0);
if (ret)
dev_dbg(dev, "No mediatek,gce-client-reg!\n");
-#endif
platform_set_drvdata(pdev, mtx);
return 0;
}
-static int mtk_mutex_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
static const struct of_device_id mutex_driver_dt_match[] = {
- { .compatible = "mediatek,mt2701-disp-mutex",
- .data = &mt2701_mutex_driver_data},
- { .compatible = "mediatek,mt2712-disp-mutex",
- .data = &mt2712_mutex_driver_data},
- { .compatible = "mediatek,mt6795-disp-mutex",
- .data = &mt6795_mutex_driver_data},
- { .compatible = "mediatek,mt8167-disp-mutex",
- .data = &mt8167_mutex_driver_data},
- { .compatible = "mediatek,mt8173-disp-mutex",
- .data = &mt8173_mutex_driver_data},
- { .compatible = "mediatek,mt8183-disp-mutex",
- .data = &mt8183_mutex_driver_data},
- { .compatible = "mediatek,mt8186-disp-mutex",
- .data = &mt8186_mutex_driver_data},
- { .compatible = "mediatek,mt8186-mdp3-mutex",
- .data = &mt8186_mdp_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,mt8365-disp-mutex",
- .data = &mt8365_mutex_driver_data},
- {},
+ { .compatible = "mediatek,mt2701-disp-mutex", .data = &mt2701_mutex_driver_data },
+ { .compatible = "mediatek,mt2712-disp-mutex", .data = &mt2712_mutex_driver_data },
+ { .compatible = "mediatek,mt6795-disp-mutex", .data = &mt6795_mutex_driver_data },
+ { .compatible = "mediatek,mt8167-disp-mutex", .data = &mt8167_mutex_driver_data },
+ { .compatible = "mediatek,mt8173-disp-mutex", .data = &mt8173_mutex_driver_data },
+ { .compatible = "mediatek,mt8183-disp-mutex", .data = &mt8183_mutex_driver_data },
+ { .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 },
+ { .compatible = "mediatek,mt8365-disp-mutex", .data = &mt8365_mutex_driver_data },
+ { /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, mutex_driver_dt_match);
static struct platform_driver mtk_mutex_driver = {
.probe = mtk_mutex_probe,
- .remove = mtk_mutex_remove,
.driver = {
.name = "mediatek-mutex",
- .owner = THIS_MODULE,
.of_match_table = mutex_driver_dt_match,
},
};
+module_platform_driver(mtk_mutex_driver);
-builtin_platform_driver(mtk_mutex_driver);
+MODULE_AUTHOR("Yongqiang Niu <yongqiang.niu@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek SoC MUTEX driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/mediatek/mtk-pm-domains.c b/drivers/soc/mediatek/mtk-pm-domains.c
deleted file mode 100644
index 474b272f9b02..000000000000
--- a/drivers/soc/mediatek/mtk-pm-domains.c
+++ /dev/null
@@ -1,675 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2020 Collabora Ltd.
- */
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/mfd/syscon.h>
-#include <linux/of_clk.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <linux/regmap.h>
-#include <linux/regulator/consumer.h>
-#include <linux/soc/mediatek/infracfg.h>
-
-#include "mt6795-pm-domains.h"
-#include "mt8167-pm-domains.h"
-#include "mt8173-pm-domains.h"
-#include "mt8183-pm-domains.h"
-#include "mt8186-pm-domains.h"
-#include "mt8192-pm-domains.h"
-#include "mt8195-pm-domains.h"
-
-#define MTK_POLL_DELAY_US 10
-#define MTK_POLL_TIMEOUT USEC_PER_SEC
-
-#define PWR_RST_B_BIT BIT(0)
-#define PWR_ISO_BIT BIT(1)
-#define PWR_ON_BIT BIT(2)
-#define PWR_ON_2ND_BIT BIT(3)
-#define PWR_CLK_DIS_BIT BIT(4)
-#define PWR_SRAM_CLKISO_BIT BIT(5)
-#define PWR_SRAM_ISOINT_B_BIT BIT(6)
-
-struct scpsys_domain {
- struct generic_pm_domain genpd;
- const struct scpsys_domain_data *data;
- struct scpsys *scpsys;
- int num_clks;
- struct clk_bulk_data *clks;
- int num_subsys_clks;
- struct clk_bulk_data *subsys_clks;
- struct regmap *infracfg;
- struct regmap *smi;
- struct regulator *supply;
-};
-
-struct scpsys {
- struct device *dev;
- struct regmap *base;
- const struct scpsys_soc_data *soc_data;
- struct genpd_onecell_data pd_data;
- struct generic_pm_domain *domains[];
-};
-
-#define to_scpsys_domain(gpd) container_of(gpd, struct scpsys_domain, genpd)
-
-static bool scpsys_domain_is_on(struct scpsys_domain *pd)
-{
- struct scpsys *scpsys = pd->scpsys;
- u32 status, status2;
-
- regmap_read(scpsys->base, pd->data->pwr_sta_offs, &status);
- status &= pd->data->sta_mask;
-
- regmap_read(scpsys->base, pd->data->pwr_sta2nd_offs, &status2);
- status2 &= pd->data->sta_mask;
-
- /* A domain is on when both status bits are set. */
- return status && status2;
-}
-
-static int scpsys_sram_enable(struct scpsys_domain *pd)
-{
- u32 pdn_ack = pd->data->sram_pdn_ack_bits;
- struct scpsys *scpsys = pd->scpsys;
- unsigned int tmp;
- int ret;
-
- regmap_clear_bits(scpsys->base, pd->data->ctl_offs, pd->data->sram_pdn_bits);
-
- /* Either wait until SRAM_PDN_ACK all 1 or 0 */
- ret = regmap_read_poll_timeout(scpsys->base, pd->data->ctl_offs, tmp,
- (tmp & pdn_ack) == 0, MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
- if (ret < 0)
- return ret;
-
- if (MTK_SCPD_CAPS(pd, MTK_SCPD_SRAM_ISO)) {
- regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_SRAM_ISOINT_B_BIT);
- udelay(1);
- regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_SRAM_CLKISO_BIT);
- }
-
- return 0;
-}
-
-static int scpsys_sram_disable(struct scpsys_domain *pd)
-{
- u32 pdn_ack = pd->data->sram_pdn_ack_bits;
- struct scpsys *scpsys = pd->scpsys;
- unsigned int tmp;
-
- if (MTK_SCPD_CAPS(pd, MTK_SCPD_SRAM_ISO)) {
- regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_SRAM_CLKISO_BIT);
- udelay(1);
- regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_SRAM_ISOINT_B_BIT);
- }
-
- regmap_set_bits(scpsys->base, pd->data->ctl_offs, pd->data->sram_pdn_bits);
-
- /* Either wait until SRAM_PDN_ACK all 1 or 0 */
- return regmap_read_poll_timeout(scpsys->base, pd->data->ctl_offs, tmp,
- (tmp & pdn_ack) == pdn_ack, MTK_POLL_DELAY_US,
- MTK_POLL_TIMEOUT);
-}
-
-static int _scpsys_bus_protect_enable(const struct scpsys_bus_prot_data *bpd, struct regmap *regmap)
-{
- int i, ret;
-
- for (i = 0; i < SPM_MAX_BUS_PROT_DATA; i++) {
- u32 val, mask = bpd[i].bus_prot_mask;
-
- if (!mask)
- break;
-
- if (bpd[i].bus_prot_reg_update)
- regmap_set_bits(regmap, bpd[i].bus_prot_set, mask);
- else
- regmap_write(regmap, bpd[i].bus_prot_set, mask);
-
- ret = regmap_read_poll_timeout(regmap, bpd[i].bus_prot_sta,
- val, (val & mask) == mask,
- MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int scpsys_bus_protect_enable(struct scpsys_domain *pd)
-{
- int ret;
-
- ret = _scpsys_bus_protect_enable(pd->data->bp_infracfg, pd->infracfg);
- if (ret)
- return ret;
-
- return _scpsys_bus_protect_enable(pd->data->bp_smi, pd->smi);
-}
-
-static int _scpsys_bus_protect_disable(const struct scpsys_bus_prot_data *bpd,
- struct regmap *regmap)
-{
- int i, ret;
-
- for (i = SPM_MAX_BUS_PROT_DATA - 1; i >= 0; i--) {
- u32 val, mask = bpd[i].bus_prot_mask;
-
- if (!mask)
- continue;
-
- if (bpd[i].bus_prot_reg_update)
- regmap_clear_bits(regmap, bpd[i].bus_prot_clr, mask);
- else
- regmap_write(regmap, bpd[i].bus_prot_clr, mask);
-
- if (bpd[i].ignore_clr_ack)
- continue;
-
- ret = regmap_read_poll_timeout(regmap, bpd[i].bus_prot_sta,
- val, !(val & mask),
- MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int scpsys_bus_protect_disable(struct scpsys_domain *pd)
-{
- int ret;
-
- ret = _scpsys_bus_protect_disable(pd->data->bp_smi, pd->smi);
- if (ret)
- return ret;
-
- return _scpsys_bus_protect_disable(pd->data->bp_infracfg, pd->infracfg);
-}
-
-static int scpsys_regulator_enable(struct regulator *supply)
-{
- return supply ? regulator_enable(supply) : 0;
-}
-
-static int scpsys_regulator_disable(struct regulator *supply)
-{
- return supply ? regulator_disable(supply) : 0;
-}
-
-static int scpsys_power_on(struct generic_pm_domain *genpd)
-{
- struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd);
- struct scpsys *scpsys = pd->scpsys;
- bool tmp;
- int ret;
-
- ret = scpsys_regulator_enable(pd->supply);
- if (ret)
- return ret;
-
- ret = clk_bulk_prepare_enable(pd->num_clks, pd->clks);
- if (ret)
- goto err_reg;
-
- /* subsys power on */
- regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT);
- regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_BIT);
-
- /* wait until PWR_ACK = 1 */
- ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, tmp, MTK_POLL_DELAY_US,
- MTK_POLL_TIMEOUT);
- if (ret < 0)
- goto err_pwr_ack;
-
- regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT);
- regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT);
- regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);
-
- ret = clk_bulk_prepare_enable(pd->num_subsys_clks, pd->subsys_clks);
- if (ret)
- goto err_pwr_ack;
-
- ret = scpsys_sram_enable(pd);
- if (ret < 0)
- goto err_disable_subsys_clks;
-
- ret = scpsys_bus_protect_disable(pd);
- if (ret < 0)
- goto err_disable_sram;
-
- return 0;
-
-err_disable_sram:
- scpsys_sram_disable(pd);
-err_disable_subsys_clks:
- clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
-err_pwr_ack:
- clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
-err_reg:
- scpsys_regulator_disable(pd->supply);
- return ret;
-}
-
-static int scpsys_power_off(struct generic_pm_domain *genpd)
-{
- struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd);
- struct scpsys *scpsys = pd->scpsys;
- bool tmp;
- int ret;
-
- ret = scpsys_bus_protect_enable(pd);
- if (ret < 0)
- return ret;
-
- ret = scpsys_sram_disable(pd);
- if (ret < 0)
- return ret;
-
- clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
-
- /* subsys power off */
- regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT);
- regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT);
- regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);
- regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_BIT);
- regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT);
-
- /* wait until PWR_ACK = 0 */
- ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, !tmp, MTK_POLL_DELAY_US,
- MTK_POLL_TIMEOUT);
- if (ret < 0)
- return ret;
-
- clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
-
- scpsys_regulator_disable(pd->supply);
-
- return 0;
-}
-
-static struct
-generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_node *node)
-{
- const struct scpsys_domain_data *domain_data;
- struct scpsys_domain *pd;
- struct device_node *root_node = scpsys->dev->of_node;
- struct device_node *smi_node;
- struct property *prop;
- const char *clk_name;
- int i, ret, num_clks;
- struct clk *clk;
- int clk_ind = 0;
- u32 id;
-
- ret = of_property_read_u32(node, "reg", &id);
- if (ret) {
- dev_err(scpsys->dev, "%pOF: failed to retrieve domain id from reg: %d\n",
- node, ret);
- return ERR_PTR(-EINVAL);
- }
-
- if (id >= scpsys->soc_data->num_domains) {
- dev_err(scpsys->dev, "%pOF: invalid domain id %d\n", node, id);
- return ERR_PTR(-EINVAL);
- }
-
- domain_data = &scpsys->soc_data->domains_data[id];
- if (domain_data->sta_mask == 0) {
- dev_err(scpsys->dev, "%pOF: undefined domain id %d\n", node, id);
- return ERR_PTR(-EINVAL);
- }
-
- pd = devm_kzalloc(scpsys->dev, sizeof(*pd), GFP_KERNEL);
- if (!pd)
- return ERR_PTR(-ENOMEM);
-
- pd->data = domain_data;
- pd->scpsys = scpsys;
-
- if (MTK_SCPD_CAPS(pd, MTK_SCPD_DOMAIN_SUPPLY)) {
- /*
- * Find regulator in current power domain node.
- * devm_regulator_get() finds regulator in a node and its child
- * node, so set of_node to current power domain node then change
- * back to original node after regulator is found for current
- * power domain node.
- */
- scpsys->dev->of_node = node;
- pd->supply = devm_regulator_get(scpsys->dev, "domain");
- scpsys->dev->of_node = root_node;
- if (IS_ERR(pd->supply)) {
- dev_err_probe(scpsys->dev, PTR_ERR(pd->supply),
- "%pOF: failed to get power supply.\n",
- node);
- return ERR_CAST(pd->supply);
- }
- }
-
- pd->infracfg = syscon_regmap_lookup_by_phandle_optional(node, "mediatek,infracfg");
- if (IS_ERR(pd->infracfg))
- return ERR_CAST(pd->infracfg);
-
- smi_node = of_parse_phandle(node, "mediatek,smi", 0);
- if (smi_node) {
- pd->smi = device_node_to_regmap(smi_node);
- of_node_put(smi_node);
- if (IS_ERR(pd->smi))
- return ERR_CAST(pd->smi);
- }
-
- num_clks = of_clk_get_parent_count(node);
- if (num_clks > 0) {
- /* Calculate number of subsys_clks */
- of_property_for_each_string(node, "clock-names", prop, clk_name) {
- char *subsys;
-
- subsys = strchr(clk_name, '-');
- if (subsys)
- pd->num_subsys_clks++;
- else
- pd->num_clks++;
- }
-
- pd->clks = devm_kcalloc(scpsys->dev, pd->num_clks, sizeof(*pd->clks), GFP_KERNEL);
- if (!pd->clks)
- return ERR_PTR(-ENOMEM);
-
- pd->subsys_clks = devm_kcalloc(scpsys->dev, pd->num_subsys_clks,
- sizeof(*pd->subsys_clks), GFP_KERNEL);
- if (!pd->subsys_clks)
- return ERR_PTR(-ENOMEM);
-
- }
-
- for (i = 0; i < pd->num_clks; i++) {
- clk = of_clk_get(node, i);
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
- dev_err_probe(scpsys->dev, ret,
- "%pOF: failed to get clk at index %d\n", node, i);
- goto err_put_clocks;
- }
-
- pd->clks[clk_ind++].clk = clk;
- }
-
- for (i = 0; i < pd->num_subsys_clks; i++) {
- clk = of_clk_get(node, i + clk_ind);
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
- dev_err_probe(scpsys->dev, ret,
- "%pOF: failed to get clk at index %d\n", node,
- i + clk_ind);
- goto err_put_subsys_clocks;
- }
-
- pd->subsys_clks[i].clk = clk;
- }
-
- /*
- * Initially turn on all domains to make the domains usable
- * with !CONFIG_PM and to get the hardware in sync with the
- * software. The unused domains will be switched off during
- * late_init time.
- */
- if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF)) {
- if (scpsys_domain_is_on(pd))
- dev_warn(scpsys->dev,
- "%pOF: A default off power domain has been ON\n", node);
- } else {
- ret = scpsys_power_on(&pd->genpd);
- if (ret < 0) {
- dev_err(scpsys->dev, "%pOF: failed to power on domain: %d\n", node, ret);
- goto err_put_subsys_clocks;
- }
-
- if (MTK_SCPD_CAPS(pd, MTK_SCPD_ALWAYS_ON))
- pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
- }
-
- if (scpsys->domains[id]) {
- ret = -EINVAL;
- dev_err(scpsys->dev,
- "power domain with id %d already exists, check your device-tree\n", id);
- goto err_put_subsys_clocks;
- }
-
- if (!pd->data->name)
- pd->genpd.name = node->name;
- else
- pd->genpd.name = pd->data->name;
-
- pd->genpd.power_off = scpsys_power_off;
- pd->genpd.power_on = scpsys_power_on;
-
- if (MTK_SCPD_CAPS(pd, MTK_SCPD_ACTIVE_WAKEUP))
- pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
-
- if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF))
- pm_genpd_init(&pd->genpd, NULL, true);
- else
- pm_genpd_init(&pd->genpd, NULL, false);
-
- scpsys->domains[id] = &pd->genpd;
-
- return scpsys->pd_data.domains[id];
-
-err_put_subsys_clocks:
- clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks);
-err_put_clocks:
- clk_bulk_put(pd->num_clks, pd->clks);
- return ERR_PTR(ret);
-}
-
-static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *parent)
-{
- struct generic_pm_domain *child_pd, *parent_pd;
- struct device_node *child;
- int ret;
-
- for_each_child_of_node(parent, child) {
- u32 id;
-
- ret = of_property_read_u32(parent, "reg", &id);
- if (ret) {
- dev_err(scpsys->dev, "%pOF: failed to get parent domain id\n", child);
- goto err_put_node;
- }
-
- if (!scpsys->pd_data.domains[id]) {
- ret = -EINVAL;
- dev_err(scpsys->dev, "power domain with id %d does not exist\n", id);
- goto err_put_node;
- }
-
- parent_pd = scpsys->pd_data.domains[id];
-
- child_pd = scpsys_add_one_domain(scpsys, child);
- if (IS_ERR(child_pd)) {
- ret = PTR_ERR(child_pd);
- dev_err_probe(scpsys->dev, ret, "%pOF: failed to get child domain id\n",
- child);
- goto err_put_node;
- }
-
- ret = pm_genpd_add_subdomain(parent_pd, child_pd);
- if (ret) {
- dev_err(scpsys->dev, "failed to add %s subdomain to parent %s\n",
- child_pd->name, parent_pd->name);
- goto err_put_node;
- } else {
- dev_dbg(scpsys->dev, "%s add subdomain: %s\n", parent_pd->name,
- child_pd->name);
- }
-
- /* recursive call to add all subdomains */
- ret = scpsys_add_subdomain(scpsys, child);
- if (ret)
- goto err_put_node;
- }
-
- return 0;
-
-err_put_node:
- of_node_put(child);
- return ret;
-}
-
-static void scpsys_remove_one_domain(struct scpsys_domain *pd)
-{
- int ret;
-
- if (scpsys_domain_is_on(pd))
- scpsys_power_off(&pd->genpd);
-
- /*
- * We're in the error cleanup already, so we only complain,
- * but won't emit another error on top of the original one.
- */
- ret = pm_genpd_remove(&pd->genpd);
- if (ret < 0)
- dev_err(pd->scpsys->dev,
- "failed to remove domain '%s' : %d - state may be inconsistent\n",
- pd->genpd.name, ret);
-
- clk_bulk_put(pd->num_clks, pd->clks);
- clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks);
-}
-
-static void scpsys_domain_cleanup(struct scpsys *scpsys)
-{
- struct generic_pm_domain *genpd;
- struct scpsys_domain *pd;
- int i;
-
- for (i = scpsys->pd_data.num_domains - 1; i >= 0; i--) {
- genpd = scpsys->pd_data.domains[i];
- if (genpd) {
- pd = to_scpsys_domain(genpd);
- scpsys_remove_one_domain(pd);
- }
- }
-}
-
-static const struct of_device_id scpsys_of_match[] = {
- {
- .compatible = "mediatek,mt6795-power-controller",
- .data = &mt6795_scpsys_data,
- },
- {
- .compatible = "mediatek,mt8167-power-controller",
- .data = &mt8167_scpsys_data,
- },
- {
- .compatible = "mediatek,mt8173-power-controller",
- .data = &mt8173_scpsys_data,
- },
- {
- .compatible = "mediatek,mt8183-power-controller",
- .data = &mt8183_scpsys_data,
- },
- {
- .compatible = "mediatek,mt8186-power-controller",
- .data = &mt8186_scpsys_data,
- },
- {
- .compatible = "mediatek,mt8192-power-controller",
- .data = &mt8192_scpsys_data,
- },
- {
- .compatible = "mediatek,mt8195-power-controller",
- .data = &mt8195_scpsys_data,
- },
- { }
-};
-
-static int scpsys_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
- const struct scpsys_soc_data *soc;
- struct device_node *node;
- struct device *parent;
- struct scpsys *scpsys;
- int ret;
-
- soc = of_device_get_match_data(&pdev->dev);
- if (!soc) {
- dev_err(&pdev->dev, "no power controller data\n");
- return -EINVAL;
- }
-
- scpsys = devm_kzalloc(dev, struct_size(scpsys, domains, soc->num_domains), GFP_KERNEL);
- if (!scpsys)
- return -ENOMEM;
-
- scpsys->dev = dev;
- scpsys->soc_data = soc;
-
- scpsys->pd_data.domains = scpsys->domains;
- scpsys->pd_data.num_domains = soc->num_domains;
-
- parent = dev->parent;
- if (!parent) {
- dev_err(dev, "no parent for syscon devices\n");
- return -ENODEV;
- }
-
- scpsys->base = syscon_node_to_regmap(parent->of_node);
- if (IS_ERR(scpsys->base)) {
- dev_err(dev, "no regmap available\n");
- return PTR_ERR(scpsys->base);
- }
-
- ret = -ENODEV;
- for_each_available_child_of_node(np, node) {
- struct generic_pm_domain *domain;
-
- domain = scpsys_add_one_domain(scpsys, node);
- if (IS_ERR(domain)) {
- ret = PTR_ERR(domain);
- of_node_put(node);
- goto err_cleanup_domains;
- }
-
- ret = scpsys_add_subdomain(scpsys, node);
- if (ret) {
- of_node_put(node);
- goto err_cleanup_domains;
- }
- }
-
- if (ret) {
- dev_dbg(dev, "no power domains present\n");
- return ret;
- }
-
- ret = of_genpd_add_provider_onecell(np, &scpsys->pd_data);
- if (ret) {
- dev_err(dev, "failed to add provider: %d\n", ret);
- goto err_cleanup_domains;
- }
-
- return 0;
-
-err_cleanup_domains:
- scpsys_domain_cleanup(scpsys);
- return ret;
-}
-
-static struct platform_driver scpsys_pm_domain_driver = {
- .probe = scpsys_probe,
- .driver = {
- .name = "mtk-power-controller",
- .suppress_bind_attrs = true,
- .of_match_table = scpsys_of_match,
- },
-};
-builtin_platform_driver(scpsys_pm_domain_driver);
diff --git a/drivers/soc/mediatek/mtk-pm-domains.h b/drivers/soc/mediatek/mtk-pm-domains.h
deleted file mode 100644
index 7d3c0c36316c..000000000000
--- a/drivers/soc/mediatek/mtk-pm-domains.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-
-#ifndef __SOC_MEDIATEK_MTK_PM_DOMAINS_H
-#define __SOC_MEDIATEK_MTK_PM_DOMAINS_H
-
-#define MTK_SCPD_ACTIVE_WAKEUP BIT(0)
-#define MTK_SCPD_FWAIT_SRAM BIT(1)
-#define MTK_SCPD_SRAM_ISO BIT(2)
-#define MTK_SCPD_KEEP_DEFAULT_OFF BIT(3)
-#define MTK_SCPD_DOMAIN_SUPPLY BIT(4)
-/* can't set MTK_SCPD_KEEP_DEFAULT_OFF at the same time */
-#define MTK_SCPD_ALWAYS_ON BIT(5)
-#define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data->caps & (_x))
-
-#define SPM_VDE_PWR_CON 0x0210
-#define SPM_MFG_PWR_CON 0x0214
-#define SPM_VEN_PWR_CON 0x0230
-#define SPM_ISP_PWR_CON 0x0238
-#define SPM_DIS_PWR_CON 0x023c
-#define SPM_CONN_PWR_CON 0x0280
-#define SPM_VEN2_PWR_CON 0x0298
-#define SPM_AUDIO_PWR_CON 0x029c
-#define SPM_MFG_2D_PWR_CON 0x02c0
-#define SPM_MFG_ASYNC_PWR_CON 0x02c4
-#define SPM_USB_PWR_CON 0x02cc
-
-#define SPM_PWR_STATUS 0x060c
-#define SPM_PWR_STATUS_2ND 0x0610
-
-#define PWR_STATUS_CONN BIT(1)
-#define PWR_STATUS_DISP BIT(3)
-#define PWR_STATUS_MFG BIT(4)
-#define PWR_STATUS_ISP BIT(5)
-#define PWR_STATUS_VDEC BIT(7)
-#define PWR_STATUS_VENC_LT BIT(20)
-#define PWR_STATUS_VENC BIT(21)
-#define PWR_STATUS_MFG_2D BIT(22)
-#define PWR_STATUS_MFG_ASYNC BIT(23)
-#define PWR_STATUS_AUDIO BIT(24)
-#define PWR_STATUS_USB BIT(25)
-
-#define SPM_MAX_BUS_PROT_DATA 6
-
-#define _BUS_PROT(_mask, _set, _clr, _sta, _update, _ignore) { \
- .bus_prot_mask = (_mask), \
- .bus_prot_set = _set, \
- .bus_prot_clr = _clr, \
- .bus_prot_sta = _sta, \
- .bus_prot_reg_update = _update, \
- .ignore_clr_ack = _ignore, \
- }
-
-#define BUS_PROT_WR(_mask, _set, _clr, _sta) \
- _BUS_PROT(_mask, _set, _clr, _sta, false, false)
-
-#define BUS_PROT_WR_IGN(_mask, _set, _clr, _sta) \
- _BUS_PROT(_mask, _set, _clr, _sta, false, true)
-
-#define BUS_PROT_UPDATE(_mask, _set, _clr, _sta) \
- _BUS_PROT(_mask, _set, _clr, _sta, true, false)
-
-#define BUS_PROT_UPDATE_TOPAXI(_mask) \
- BUS_PROT_UPDATE(_mask, \
- INFRA_TOPAXI_PROTECTEN, \
- INFRA_TOPAXI_PROTECTEN, \
- INFRA_TOPAXI_PROTECTSTA1)
-
-struct scpsys_bus_prot_data {
- u32 bus_prot_mask;
- u32 bus_prot_set;
- u32 bus_prot_clr;
- u32 bus_prot_sta;
- bool bus_prot_reg_update;
- bool ignore_clr_ack;
-};
-
-/**
- * struct scpsys_domain_data - scp domain data for power on/off flow
- * @name: The name of the power domain.
- * @sta_mask: The mask for power on/off status bit.
- * @ctl_offs: The offset for main power control register.
- * @sram_pdn_bits: The mask for sram power control bits.
- * @sram_pdn_ack_bits: The mask for sram power control acked bits.
- * @caps: The flag for active wake-up action.
- * @bp_infracfg: bus protection for infracfg subsystem
- * @bp_smi: bus protection for smi subsystem
- */
-struct scpsys_domain_data {
- const char *name;
- u32 sta_mask;
- int ctl_offs;
- u32 sram_pdn_bits;
- u32 sram_pdn_ack_bits;
- u8 caps;
- const struct scpsys_bus_prot_data bp_infracfg[SPM_MAX_BUS_PROT_DATA];
- const struct scpsys_bus_prot_data bp_smi[SPM_MAX_BUS_PROT_DATA];
- int pwr_sta_offs;
- int pwr_sta2nd_offs;
-};
-
-struct scpsys_soc_data {
- const struct scpsys_domain_data *domains_data;
- int num_domains;
-};
-
-#endif /* __SOC_MEDIATEK_MTK_PM_DOMAINS_H */
diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
index 15789a03e6c6..0bcd85826375 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -8,7 +8,8 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
@@ -47,6 +48,7 @@
/* macro for device wrapper default value */
#define PWRAP_DEW_READ_TEST_VAL 0x5aa5
+#define PWRAP_DEW_COMP_READ_TEST_VAL 0xa55a
#define PWRAP_DEW_WRITE_TEST_VAL 0xa55a
/* macro for manual command */
@@ -169,6 +171,40 @@ static const u32 mt6323_regs[] = {
[PWRAP_DEW_RDDMY_NO] = 0x01a4,
};
+static const u32 mt6331_regs[] = {
+ [PWRAP_DEW_DIO_EN] = 0x018c,
+ [PWRAP_DEW_READ_TEST] = 0x018e,
+ [PWRAP_DEW_WRITE_TEST] = 0x0190,
+ [PWRAP_DEW_CRC_SWRST] = 0x0192,
+ [PWRAP_DEW_CRC_EN] = 0x0194,
+ [PWRAP_DEW_CRC_VAL] = 0x0196,
+ [PWRAP_DEW_MON_GRP_SEL] = 0x0198,
+ [PWRAP_DEW_CIPHER_KEY_SEL] = 0x019a,
+ [PWRAP_DEW_CIPHER_IV_SEL] = 0x019c,
+ [PWRAP_DEW_CIPHER_EN] = 0x019e,
+ [PWRAP_DEW_CIPHER_RDY] = 0x01a0,
+ [PWRAP_DEW_CIPHER_MODE] = 0x01a2,
+ [PWRAP_DEW_CIPHER_SWRST] = 0x01a4,
+ [PWRAP_DEW_RDDMY_NO] = 0x01a6,
+};
+
+static const u32 mt6332_regs[] = {
+ [PWRAP_DEW_DIO_EN] = 0x80f6,
+ [PWRAP_DEW_READ_TEST] = 0x80f8,
+ [PWRAP_DEW_WRITE_TEST] = 0x80fa,
+ [PWRAP_DEW_CRC_SWRST] = 0x80fc,
+ [PWRAP_DEW_CRC_EN] = 0x80fe,
+ [PWRAP_DEW_CRC_VAL] = 0x8100,
+ [PWRAP_DEW_MON_GRP_SEL] = 0x8102,
+ [PWRAP_DEW_CIPHER_KEY_SEL] = 0x8104,
+ [PWRAP_DEW_CIPHER_IV_SEL] = 0x8106,
+ [PWRAP_DEW_CIPHER_EN] = 0x8108,
+ [PWRAP_DEW_CIPHER_RDY] = 0x810a,
+ [PWRAP_DEW_CIPHER_MODE] = 0x810c,
+ [PWRAP_DEW_CIPHER_SWRST] = 0x810e,
+ [PWRAP_DEW_RDDMY_NO] = 0x8110,
+};
+
static const u32 mt6351_regs[] = {
[PWRAP_DEW_DIO_EN] = 0x02F2,
[PWRAP_DEW_READ_TEST] = 0x02F4,
@@ -447,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,
@@ -533,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,
@@ -565,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,
@@ -604,7 +640,92 @@ static int mt6779_regs[] = {
[PWRAP_WACS2_VLDCLR] = 0xC28,
};
-static int mt6797_regs[] = {
+static const int mt6795_regs[] = {
+ [PWRAP_MUX_SEL] = 0x0,
+ [PWRAP_WRAP_EN] = 0x4,
+ [PWRAP_DIO_EN] = 0x8,
+ [PWRAP_SIDLY] = 0xc,
+ [PWRAP_RDDMY] = 0x10,
+ [PWRAP_SI_CK_CON] = 0x14,
+ [PWRAP_CSHEXT_WRITE] = 0x18,
+ [PWRAP_CSHEXT_READ] = 0x1c,
+ [PWRAP_CSLEXT_START] = 0x20,
+ [PWRAP_CSLEXT_END] = 0x24,
+ [PWRAP_STAUPD_PRD] = 0x28,
+ [PWRAP_STAUPD_GRPEN] = 0x2c,
+ [PWRAP_EINT_STA0_ADR] = 0x30,
+ [PWRAP_EINT_STA1_ADR] = 0x34,
+ [PWRAP_STAUPD_MAN_TRIG] = 0x40,
+ [PWRAP_STAUPD_STA] = 0x44,
+ [PWRAP_WRAP_STA] = 0x48,
+ [PWRAP_HARB_INIT] = 0x4c,
+ [PWRAP_HARB_HPRIO] = 0x50,
+ [PWRAP_HIPRIO_ARB_EN] = 0x54,
+ [PWRAP_HARB_STA0] = 0x58,
+ [PWRAP_HARB_STA1] = 0x5c,
+ [PWRAP_MAN_EN] = 0x60,
+ [PWRAP_MAN_CMD] = 0x64,
+ [PWRAP_MAN_RDATA] = 0x68,
+ [PWRAP_MAN_VLDCLR] = 0x6c,
+ [PWRAP_WACS0_EN] = 0x70,
+ [PWRAP_INIT_DONE0] = 0x74,
+ [PWRAP_WACS0_CMD] = 0x78,
+ [PWRAP_WACS0_RDATA] = 0x7c,
+ [PWRAP_WACS0_VLDCLR] = 0x80,
+ [PWRAP_WACS1_EN] = 0x84,
+ [PWRAP_INIT_DONE1] = 0x88,
+ [PWRAP_WACS1_CMD] = 0x8c,
+ [PWRAP_WACS1_RDATA] = 0x90,
+ [PWRAP_WACS1_VLDCLR] = 0x94,
+ [PWRAP_WACS2_EN] = 0x98,
+ [PWRAP_INIT_DONE2] = 0x9c,
+ [PWRAP_WACS2_CMD] = 0xa0,
+ [PWRAP_WACS2_RDATA] = 0xa4,
+ [PWRAP_WACS2_VLDCLR] = 0xa8,
+ [PWRAP_INT_EN] = 0xac,
+ [PWRAP_INT_FLG_RAW] = 0xb0,
+ [PWRAP_INT_FLG] = 0xb4,
+ [PWRAP_INT_CLR] = 0xb8,
+ [PWRAP_SIG_ADR] = 0xbc,
+ [PWRAP_SIG_MODE] = 0xc0,
+ [PWRAP_SIG_VALUE] = 0xc4,
+ [PWRAP_SIG_ERRVAL] = 0xc8,
+ [PWRAP_CRC_EN] = 0xcc,
+ [PWRAP_TIMER_EN] = 0xd0,
+ [PWRAP_TIMER_STA] = 0xd4,
+ [PWRAP_WDT_UNIT] = 0xd8,
+ [PWRAP_WDT_SRC_EN] = 0xdc,
+ [PWRAP_WDT_FLG] = 0xe0,
+ [PWRAP_DEBUG_INT_SEL] = 0xe4,
+ [PWRAP_DVFS_ADR0] = 0xe8,
+ [PWRAP_DVFS_WDATA0] = 0xec,
+ [PWRAP_DVFS_ADR1] = 0xf0,
+ [PWRAP_DVFS_WDATA1] = 0xf4,
+ [PWRAP_DVFS_ADR2] = 0xf8,
+ [PWRAP_DVFS_WDATA2] = 0xfc,
+ [PWRAP_DVFS_ADR3] = 0x100,
+ [PWRAP_DVFS_WDATA3] = 0x104,
+ [PWRAP_DVFS_ADR4] = 0x108,
+ [PWRAP_DVFS_WDATA4] = 0x10c,
+ [PWRAP_DVFS_ADR5] = 0x110,
+ [PWRAP_DVFS_WDATA5] = 0x114,
+ [PWRAP_DVFS_ADR6] = 0x118,
+ [PWRAP_DVFS_WDATA6] = 0x11c,
+ [PWRAP_DVFS_ADR7] = 0x120,
+ [PWRAP_DVFS_WDATA7] = 0x124,
+ [PWRAP_SPMINF_STA] = 0x128,
+ [PWRAP_CIPHER_KEY_SEL] = 0x12c,
+ [PWRAP_CIPHER_IV_SEL] = 0x130,
+ [PWRAP_CIPHER_EN] = 0x134,
+ [PWRAP_CIPHER_RDY] = 0x138,
+ [PWRAP_CIPHER_MODE] = 0x13c,
+ [PWRAP_CIPHER_SWRST] = 0x140,
+ [PWRAP_DCM_EN] = 0x144,
+ [PWRAP_DCM_DBC_PRD] = 0x148,
+ [PWRAP_EXT_CK] = 0x14c,
+};
+
+static const int mt6797_regs[] = {
[PWRAP_MUX_SEL] = 0x0,
[PWRAP_WRAP_EN] = 0x4,
[PWRAP_DIO_EN] = 0x8,
@@ -637,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,
@@ -648,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,
@@ -760,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,
@@ -833,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,
@@ -915,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,
@@ -966,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,
@@ -983,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,
@@ -1045,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,
@@ -1130,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,
@@ -1181,6 +1302,8 @@ static int mt8186_regs[] = {
enum pmic_type {
PMIC_MT6323,
+ PMIC_MT6331,
+ PMIC_MT6332,
PMIC_MT6351,
PMIC_MT6357,
PMIC_MT6358,
@@ -1193,6 +1316,7 @@ enum pwrap_type {
PWRAP_MT2701,
PWRAP_MT6765,
PWRAP_MT6779,
+ PWRAP_MT6795,
PWRAP_MT6797,
PWRAP_MT6873,
PWRAP_MT7622,
@@ -1218,11 +1342,21 @@ struct pwrap_slv_regops {
int (*pwrap_write)(struct pmic_wrapper *wrp, u32 adr, u32 wdata);
};
+/**
+ * struct pwrap_slv_type - PMIC device wrapper definitions
+ * @dew_regs: Device Wrapper (DeW) register offsets
+ * @type: PMIC Type (model)
+ * @comp_dew_regs: Device Wrapper (DeW) register offsets for companion device
+ * @comp_type: Companion PMIC Type (model)
+ * @regops: Register R/W ops
+ * @caps: Capability flags for the target device
+ */
struct pwrap_slv_type {
const u32 *dew_regs;
enum pmic_type type;
+ const u32 *comp_dew_regs;
+ enum pmic_type comp_type;
const struct pwrap_slv_regops *regops;
- /* Flags indicating the capability for the target slave */
u32 caps;
};
@@ -1232,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;
@@ -1243,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;
@@ -1455,6 +1585,18 @@ static int pwrap_regmap_write(void *context, u32 adr, u32 wdata)
return pwrap_write(context, adr, wdata);
}
+static bool pwrap_pmic_read_test(struct pmic_wrapper *wrp, const u32 *dew_regs,
+ u16 read_test_val)
+{
+ bool is_success;
+ u32 rdata;
+
+ pwrap_read(wrp, dew_regs[PWRAP_DEW_READ_TEST], &rdata);
+ is_success = ((rdata & U16_MAX) == read_test_val);
+
+ return is_success;
+}
+
static int pwrap_reset_spislave(struct pmic_wrapper *wrp)
{
bool tmp;
@@ -1498,18 +1640,18 @@ static int pwrap_reset_spislave(struct pmic_wrapper *wrp)
*/
static int pwrap_init_sidly(struct pmic_wrapper *wrp)
{
- u32 rdata;
u32 i;
u32 pass = 0;
+ bool read_ok;
signed char dly[16] = {
-1, 0, 1, 0, 2, -1, 1, 1, 3, -1, -1, -1, 3, -1, 2, 1
};
for (i = 0; i < 4; i++) {
pwrap_writel(wrp, i, PWRAP_SIDLY);
- pwrap_read(wrp, wrp->slave->dew_regs[PWRAP_DEW_READ_TEST],
- &rdata);
- if (rdata == PWRAP_DEW_READ_TEST_VAL) {
+ read_ok = pwrap_pmic_read_test(wrp, wrp->slave->dew_regs,
+ PWRAP_DEW_READ_TEST_VAL);
+ if (read_ok) {
dev_dbg(wrp->dev, "[Read Test] pass, SIDLY=%x\n", i);
pass |= 1 << i;
}
@@ -1529,11 +1671,13 @@ static int pwrap_init_sidly(struct pmic_wrapper *wrp)
static int pwrap_init_dual_io(struct pmic_wrapper *wrp)
{
int ret;
- bool tmp;
- u32 rdata;
+ bool read_ok, tmp;
+ bool comp_read_ok = true;
/* Enable dual IO mode */
pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_DIO_EN], 1);
+ if (wrp->slave->comp_dew_regs)
+ pwrap_write(wrp, wrp->slave->comp_dew_regs[PWRAP_DEW_DIO_EN], 1);
/* Check IDLE & INIT_DONE in advance */
ret = readx_poll_timeout(pwrap_is_fsm_idle_and_sync_idle, wrp, tmp, tmp,
@@ -1546,12 +1690,15 @@ static int pwrap_init_dual_io(struct pmic_wrapper *wrp)
pwrap_writel(wrp, 1, PWRAP_DIO_EN);
/* Read Test */
- pwrap_read(wrp,
- wrp->slave->dew_regs[PWRAP_DEW_READ_TEST], &rdata);
- if (rdata != PWRAP_DEW_READ_TEST_VAL) {
- dev_err(wrp->dev,
- "Read failed on DIO mode: 0x%04x!=0x%04x\n",
- PWRAP_DEW_READ_TEST_VAL, rdata);
+ read_ok = pwrap_pmic_read_test(wrp, wrp->slave->dew_regs, PWRAP_DEW_READ_TEST_VAL);
+ if (wrp->slave->comp_dew_regs)
+ comp_read_ok = pwrap_pmic_read_test(wrp, wrp->slave->comp_dew_regs,
+ PWRAP_DEW_COMP_READ_TEST_VAL);
+ if (!read_ok || !comp_read_ok) {
+ dev_err(wrp->dev, "Read failed on DIO mode. Main PMIC %s%s\n",
+ !read_ok ? "fail" : "success",
+ wrp->slave->comp_dew_regs && !comp_read_ok ?
+ ", Companion PMIC fail" : "");
return -EFAULT;
}
@@ -1586,6 +1733,20 @@ static void pwrap_init_chip_select_ext(struct pmic_wrapper *wrp, u8 hext_write,
static int pwrap_common_init_reg_clock(struct pmic_wrapper *wrp)
{
switch (wrp->master->type) {
+ case PWRAP_MT6795:
+ if (wrp->slave->type == PMIC_MT6331) {
+ const u32 *dew_regs = wrp->slave->dew_regs;
+
+ pwrap_write(wrp, dew_regs[PWRAP_DEW_RDDMY_NO], 0x8);
+
+ if (wrp->slave->comp_type == PMIC_MT6332) {
+ dew_regs = wrp->slave->comp_dew_regs;
+ pwrap_write(wrp, dew_regs[PWRAP_DEW_RDDMY_NO], 0x8);
+ }
+ }
+ pwrap_writel(wrp, 0x88, PWRAP_RDDMY);
+ pwrap_init_chip_select_ext(wrp, 15, 15, 15, 15);
+ break;
case PWRAP_MT8173:
pwrap_init_chip_select_ext(wrp, 0, 4, 2, 2);
break;
@@ -1626,19 +1787,41 @@ static bool pwrap_is_cipher_ready(struct pmic_wrapper *wrp)
return pwrap_readl(wrp, PWRAP_CIPHER_RDY) & 1;
}
-static bool pwrap_is_pmic_cipher_ready(struct pmic_wrapper *wrp)
+static bool __pwrap_is_pmic_cipher_ready(struct pmic_wrapper *wrp, const u32 *dew_regs)
{
u32 rdata;
int ret;
- ret = pwrap_read(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_RDY],
- &rdata);
+ ret = pwrap_read(wrp, dew_regs[PWRAP_DEW_CIPHER_RDY], &rdata);
if (ret)
return false;
return rdata == 1;
}
+
+static bool pwrap_is_pmic_cipher_ready(struct pmic_wrapper *wrp)
+{
+ bool ret = __pwrap_is_pmic_cipher_ready(wrp, wrp->slave->dew_regs);
+
+ if (!ret)
+ return ret;
+
+ /* If there's any companion, wait for it to be ready too */
+ if (wrp->slave->comp_dew_regs)
+ ret = __pwrap_is_pmic_cipher_ready(wrp, wrp->slave->comp_dew_regs);
+
+ return ret;
+}
+
+static void pwrap_config_cipher(struct pmic_wrapper *wrp, const u32 *dew_regs)
+{
+ pwrap_write(wrp, dew_regs[PWRAP_DEW_CIPHER_SWRST], 0x1);
+ pwrap_write(wrp, dew_regs[PWRAP_DEW_CIPHER_SWRST], 0x0);
+ pwrap_write(wrp, dew_regs[PWRAP_DEW_CIPHER_KEY_SEL], 0x1);
+ pwrap_write(wrp, dew_regs[PWRAP_DEW_CIPHER_IV_SEL], 0x2);
+}
+
static int pwrap_init_cipher(struct pmic_wrapper *wrp)
{
int ret;
@@ -1658,6 +1841,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
case PWRAP_MT2701:
case PWRAP_MT6765:
case PWRAP_MT6779:
+ case PWRAP_MT6795:
case PWRAP_MT6797:
case PWRAP_MT8173:
case PWRAP_MT8186:
@@ -1675,10 +1859,11 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
}
/* Config cipher mode @PMIC */
- pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_SWRST], 0x1);
- pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_SWRST], 0x0);
- pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_KEY_SEL], 0x1);
- pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_IV_SEL], 0x2);
+ pwrap_config_cipher(wrp, wrp->slave->dew_regs);
+
+ /* If there is any companion PMIC, configure cipher mode there too */
+ if (wrp->slave->comp_type > 0)
+ pwrap_config_cipher(wrp, wrp->slave->comp_dew_regs);
switch (wrp->slave->type) {
case PMIC_MT6397:
@@ -1740,6 +1925,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
static int pwrap_init_security(struct pmic_wrapper *wrp)
{
+ u32 crc_val;
int ret;
/* Enable encryption */
@@ -1748,14 +1934,21 @@ static int pwrap_init_security(struct pmic_wrapper *wrp)
return ret;
/* Signature checking - using CRC */
- if (pwrap_write(wrp,
- wrp->slave->dew_regs[PWRAP_DEW_CRC_EN], 0x1))
- return -EFAULT;
+ ret = pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CRC_EN], 0x1);
+ if (ret == 0 && wrp->slave->comp_dew_regs)
+ ret = pwrap_write(wrp, wrp->slave->comp_dew_regs[PWRAP_DEW_CRC_EN], 0x1);
pwrap_writel(wrp, 0x1, PWRAP_CRC_EN);
pwrap_writel(wrp, 0x0, PWRAP_SIG_MODE);
- pwrap_writel(wrp, wrp->slave->dew_regs[PWRAP_DEW_CRC_VAL],
- PWRAP_SIG_ADR);
+
+ /* CRC value */
+ crc_val = wrp->slave->dew_regs[PWRAP_DEW_CRC_VAL];
+ if (wrp->slave->comp_dew_regs)
+ crc_val |= wrp->slave->comp_dew_regs[PWRAP_DEW_CRC_VAL] << 16;
+
+ pwrap_writel(wrp, crc_val, PWRAP_SIG_ADR);
+
+ /* PMIC Wrapper Arbiter priority */
pwrap_writel(wrp,
wrp->master->arb_en_all, PWRAP_HIPRIO_ARB_EN);
@@ -1819,6 +2012,19 @@ static int pwrap_mt2701_init_soc_specific(struct pmic_wrapper *wrp)
return 0;
}
+static int pwrap_mt6795_init_soc_specific(struct pmic_wrapper *wrp)
+{
+ pwrap_writel(wrp, 0xf, PWRAP_STAUPD_GRPEN);
+
+ if (wrp->slave->type == PMIC_MT6331)
+ pwrap_writel(wrp, 0x1b4, PWRAP_EINT_STA0_ADR);
+
+ if (wrp->slave->comp_type == PMIC_MT6332)
+ pwrap_writel(wrp, 0x8112, PWRAP_EINT_STA1_ADR);
+
+ return 0;
+}
+
static int pwrap_mt7622_init_soc_specific(struct pmic_wrapper *wrp)
{
pwrap_writel(wrp, 0, PWRAP_STAUPD_PRD);
@@ -1854,10 +2060,16 @@ static int pwrap_init(struct pmic_wrapper *wrp)
if (wrp->rstc_bridge)
reset_control_reset(wrp->rstc_bridge);
- if (wrp->master->type == PWRAP_MT8173) {
+ switch (wrp->master->type) {
+ case PWRAP_MT6795:
+ fallthrough;
+ case PWRAP_MT8173:
/* Enable DCM */
pwrap_writel(wrp, 3, PWRAP_DCM_EN);
pwrap_writel(wrp, 0, PWRAP_DCM_DBC_PRD);
+ break;
+ default:
+ break;
}
if (HAS_CAP(wrp->slave->caps, PWRAP_SLV_CAP_SPI)) {
@@ -1982,6 +2194,16 @@ static const struct pwrap_slv_type pmic_mt6323 = {
PWRAP_SLV_CAP_SECURITY,
};
+static const struct pwrap_slv_type pmic_mt6331 = {
+ .dew_regs = mt6331_regs,
+ .type = PMIC_MT6331,
+ .comp_dew_regs = mt6332_regs,
+ .comp_type = PMIC_MT6332,
+ .regops = &pwrap_regops16,
+ .caps = PWRAP_SLV_CAP_SPI | PWRAP_SLV_CAP_DUALIO |
+ PWRAP_SLV_CAP_SECURITY,
+};
+
static const struct pwrap_slv_type pmic_mt6351 = {
.dew_regs = mt6351_regs,
.type = PMIC_MT6351,
@@ -2027,6 +2249,7 @@ static const struct pwrap_slv_type pmic_mt6397 = {
static const struct of_device_id of_slave_match_tbl[] = {
{ .compatible = "mediatek,mt6323", .data = &pmic_mt6323 },
+ { .compatible = "mediatek,mt6331", .data = &pmic_mt6331 },
{ .compatible = "mediatek,mt6351", .data = &pmic_mt6351 },
{ .compatible = "mediatek,mt6357", .data = &pmic_mt6357 },
{ .compatible = "mediatek,mt6358", .data = &pmic_mt6358 },
@@ -2079,6 +2302,19 @@ static const struct pmic_wrapper_type pwrap_mt6779 = {
.init_soc_specific = NULL,
};
+static const struct pmic_wrapper_type pwrap_mt6795 = {
+ .regs = mt6795_regs,
+ .type = PWRAP_MT6795,
+ .arb_en_all = 0x3f,
+ .int_en_all = ~(u32)(BIT(31) | BIT(2) | BIT(1)),
+ .int1_en_all = 0,
+ .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
+ .wdt_src = PWRAP_WDT_SRC_MASK_NO_STAUPD,
+ .caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM,
+ .init_reg_clock = pwrap_common_init_reg_clock,
+ .init_soc_specific = pwrap_mt6795_init_soc_specific,
+};
+
static const struct pmic_wrapper_type pwrap_mt6797 = {
.regs = mt6797_regs,
.type = PWRAP_MT6797,
@@ -2157,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 */
@@ -2183,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,
@@ -2195,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,
@@ -2212,6 +2448,7 @@ static const struct of_device_id of_pwrap_match_tbl[] = {
{ .compatible = "mediatek,mt2701-pwrap", .data = &pwrap_mt2701 },
{ .compatible = "mediatek,mt6765-pwrap", .data = &pwrap_mt6765 },
{ .compatible = "mediatek,mt6779-pwrap", .data = &pwrap_mt6779 },
+ { .compatible = "mediatek,mt6795-pwrap", .data = &pwrap_mt6795 },
{ .compatible = "mediatek,mt6797-pwrap", .data = &pwrap_mt6797 },
{ .compatible = "mediatek,mt6873-pwrap", .data = &pwrap_mt6873 },
{ .compatible = "mediatek,mt7622-pwrap", .data = &pwrap_mt7622 },
@@ -2231,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;
@@ -2280,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)) {
@@ -2338,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;
}
}
@@ -2351,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 */
@@ -2381,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
new file mode 100644
index 000000000000..0b6a2884145e
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-regulator-coupler.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Voltage regulators coupler for MediaTek SoCs
+ *
+ * Copyright (C) 2022 Collabora, Ltd.
+ * Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/regulator/coupler.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/suspend.h>
+
+#define to_mediatek_coupler(x) container_of(x, struct mediatek_regulator_coupler, coupler)
+
+struct mediatek_regulator_coupler {
+ struct regulator_coupler coupler;
+ struct regulator_dev *vsram_rdev;
+};
+
+/*
+ * We currently support only couples of not more than two vregs and
+ * modify the vsram voltage only when changing voltage of vgpu.
+ *
+ * This function is limited to the GPU<->SRAM voltages relationships.
+ */
+static int mediatek_regulator_balance_voltage(struct regulator_coupler *coupler,
+ struct regulator_dev *rdev,
+ suspend_state_t state)
+{
+ struct mediatek_regulator_coupler *mrc = to_mediatek_coupler(coupler);
+ int max_spread = rdev->constraints->max_spread[0];
+ int vsram_min_uV = mrc->vsram_rdev->constraints->min_uV;
+ int vsram_max_uV = mrc->vsram_rdev->constraints->max_uV;
+ int vsram_target_min_uV, vsram_target_max_uV;
+ int min_uV = 0;
+ int max_uV = INT_MAX;
+ int ret;
+
+ /*
+ * If the target device is on, setting the SRAM voltage directly
+ * is not supported as it scales through its coupled supply voltage.
+ *
+ * An exception is made in case the use_count is zero: this means
+ * that this is the first time we power up the SRAM regulator, which
+ * implies that the target device has yet to perform initialization
+ * and setting a voltage at that time is harmless.
+ */
+ if (rdev == mrc->vsram_rdev) {
+ if (rdev->use_count == 0)
+ return regulator_do_balance_voltage(rdev, state, true);
+
+ return -EPERM;
+ }
+
+ ret = regulator_check_consumers(rdev, &min_uV, &max_uV, state);
+ if (ret < 0)
+ return ret;
+
+ if (min_uV == 0) {
+ ret = regulator_get_voltage_rdev(rdev);
+ if (ret < 0)
+ return ret;
+ min_uV = ret;
+ }
+
+ ret = regulator_check_voltage(rdev, &min_uV, &max_uV);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * If we're asked to set a voltage less than VSRAM min_uV, set
+ * the minimum allowed voltage on VSRAM, as in this case it is
+ * safe to ignore the max_spread parameter.
+ */
+ vsram_target_min_uV = max(vsram_min_uV, min_uV + max_spread);
+ vsram_target_max_uV = min(vsram_max_uV, vsram_target_min_uV + max_spread);
+
+ /* Make sure we're not out of range */
+ vsram_target_min_uV = min(vsram_target_min_uV, vsram_max_uV);
+
+ pr_debug("Setting voltage %d-%duV on %s (minuV %d)\n",
+ vsram_target_min_uV, vsram_target_max_uV,
+ rdev_get_name(mrc->vsram_rdev), min_uV);
+
+ ret = regulator_set_voltage_rdev(mrc->vsram_rdev, vsram_target_min_uV,
+ vsram_target_max_uV, state);
+ if (ret)
+ return ret;
+
+ /* The sram voltage is now balanced: update the target vreg voltage */
+ return regulator_do_balance_voltage(rdev, state, true);
+}
+
+static int mediatek_regulator_attach(struct regulator_coupler *coupler,
+ struct regulator_dev *rdev)
+{
+ struct mediatek_regulator_coupler *mrc = to_mediatek_coupler(coupler);
+ const char *rdev_name = rdev_get_name(rdev);
+
+ /*
+ * If we're getting a coupling of more than two regulators here and
+ * this means that this is surely not a GPU<->SRAM couple: in that
+ * case, we may want to use another coupler implementation, if any,
+ * or the generic one: the regulator core will keep walking through
+ * the list of couplers when any .attach_regulator() cb returns 1.
+ */
+ if (rdev->coupling_desc.n_coupled > 2)
+ return 1;
+
+ if (strstr(rdev_name, "sram")) {
+ if (mrc->vsram_rdev)
+ return -EINVAL;
+ mrc->vsram_rdev = rdev;
+ } else if (!strstr(rdev_name, "vgpu") && !strstr(rdev_name, "Vgpu")) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static int mediatek_regulator_detach(struct regulator_coupler *coupler,
+ struct regulator_dev *rdev)
+{
+ struct mediatek_regulator_coupler *mrc = to_mediatek_coupler(coupler);
+
+ if (rdev == mrc->vsram_rdev)
+ mrc->vsram_rdev = NULL;
+
+ return 0;
+}
+
+static struct mediatek_regulator_coupler mediatek_coupler = {
+ .coupler = {
+ .attach_regulator = mediatek_regulator_attach,
+ .detach_regulator = mediatek_regulator_detach,
+ .balance_voltage = mediatek_regulator_balance_voltage,
+ },
+};
+
+static int mediatek_regulator_coupler_init(void)
+{
+ if (!of_machine_is_compatible("mediatek,mt8183") &&
+ !of_machine_is_compatible("mediatek,mt8186") &&
+ !of_machine_is_compatible("mediatek,mt8188") &&
+ !of_machine_is_compatible("mediatek,mt8192"))
+ return 0;
+
+ return regulator_coupler_register(&mediatek_coupler.coupler);
+}
+arch_initcall(mediatek_regulator_coupler_init);
+
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_DESCRIPTION("MediaTek Regulator Coupler driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
deleted file mode 100644
index 7a668888111c..000000000000
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ /dev/null
@@ -1,1147 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2015 Pengutronix, Sascha Hauer <kernel@pengutronix.de>
- */
-#include <linux/clk.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/mfd/syscon.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <linux/regulator/consumer.h>
-#include <linux/soc/mediatek/infracfg.h>
-
-#include <dt-bindings/power/mt2701-power.h>
-#include <dt-bindings/power/mt2712-power.h>
-#include <dt-bindings/power/mt6797-power.h>
-#include <dt-bindings/power/mt7622-power.h>
-#include <dt-bindings/power/mt7623a-power.h>
-#include <dt-bindings/power/mt8173-power.h>
-
-#define MTK_POLL_DELAY_US 10
-#define MTK_POLL_TIMEOUT USEC_PER_SEC
-
-#define MTK_SCPD_ACTIVE_WAKEUP BIT(0)
-#define MTK_SCPD_FWAIT_SRAM BIT(1)
-#define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data->caps & (_x))
-
-#define SPM_VDE_PWR_CON 0x0210
-#define SPM_MFG_PWR_CON 0x0214
-#define SPM_VEN_PWR_CON 0x0230
-#define SPM_ISP_PWR_CON 0x0238
-#define SPM_DIS_PWR_CON 0x023c
-#define SPM_CONN_PWR_CON 0x0280
-#define SPM_VEN2_PWR_CON 0x0298
-#define SPM_AUDIO_PWR_CON 0x029c /* MT8173, MT2712 */
-#define SPM_BDP_PWR_CON 0x029c /* MT2701 */
-#define SPM_ETH_PWR_CON 0x02a0
-#define SPM_HIF_PWR_CON 0x02a4
-#define SPM_IFR_MSC_PWR_CON 0x02a8
-#define SPM_MFG_2D_PWR_CON 0x02c0
-#define SPM_MFG_ASYNC_PWR_CON 0x02c4
-#define SPM_USB_PWR_CON 0x02cc
-#define SPM_USB2_PWR_CON 0x02d4 /* MT2712 */
-#define SPM_ETHSYS_PWR_CON 0x02e0 /* MT7622 */
-#define SPM_HIF0_PWR_CON 0x02e4 /* MT7622 */
-#define SPM_HIF1_PWR_CON 0x02e8 /* MT7622 */
-#define SPM_WB_PWR_CON 0x02ec /* MT7622 */
-
-#define SPM_PWR_STATUS 0x060c
-#define SPM_PWR_STATUS_2ND 0x0610
-
-#define PWR_RST_B_BIT BIT(0)
-#define PWR_ISO_BIT BIT(1)
-#define PWR_ON_BIT BIT(2)
-#define PWR_ON_2ND_BIT BIT(3)
-#define PWR_CLK_DIS_BIT BIT(4)
-
-#define PWR_STATUS_CONN BIT(1)
-#define PWR_STATUS_DISP BIT(3)
-#define PWR_STATUS_MFG BIT(4)
-#define PWR_STATUS_ISP BIT(5)
-#define PWR_STATUS_VDEC BIT(7)
-#define PWR_STATUS_BDP BIT(14)
-#define PWR_STATUS_ETH BIT(15)
-#define PWR_STATUS_HIF BIT(16)
-#define PWR_STATUS_IFR_MSC BIT(17)
-#define PWR_STATUS_USB2 BIT(19) /* MT2712 */
-#define PWR_STATUS_VENC_LT BIT(20)
-#define PWR_STATUS_VENC BIT(21)
-#define PWR_STATUS_MFG_2D BIT(22) /* MT8173 */
-#define PWR_STATUS_MFG_ASYNC BIT(23) /* MT8173 */
-#define PWR_STATUS_AUDIO BIT(24) /* MT8173, MT2712 */
-#define PWR_STATUS_USB BIT(25) /* MT8173, MT2712 */
-#define PWR_STATUS_ETHSYS BIT(24) /* MT7622 */
-#define PWR_STATUS_HIF0 BIT(25) /* MT7622 */
-#define PWR_STATUS_HIF1 BIT(26) /* MT7622 */
-#define PWR_STATUS_WB BIT(27) /* MT7622 */
-
-enum clk_id {
- CLK_NONE,
- CLK_MM,
- CLK_MFG,
- CLK_VENC,
- CLK_VENC_LT,
- CLK_ETHIF,
- CLK_VDEC,
- CLK_HIFSEL,
- CLK_JPGDEC,
- CLK_AUDIO,
- CLK_MAX,
-};
-
-static const char * const clk_names[] = {
- NULL,
- "mm",
- "mfg",
- "venc",
- "venc_lt",
- "ethif",
- "vdec",
- "hif_sel",
- "jpgdec",
- "audio",
- NULL,
-};
-
-#define MAX_CLKS 3
-
-/**
- * struct scp_domain_data - scp domain data for power on/off flow
- * @name: The domain name.
- * @sta_mask: The mask for power on/off status bit.
- * @ctl_offs: The offset for main power control register.
- * @sram_pdn_bits: The mask for sram power control bits.
- * @sram_pdn_ack_bits: The mask for sram power control acked bits.
- * @bus_prot_mask: The mask for single step bus protection.
- * @clk_id: The basic clocks required by this power domain.
- * @caps: The flag for active wake-up action.
- */
-struct scp_domain_data {
- const char *name;
- u32 sta_mask;
- int ctl_offs;
- u32 sram_pdn_bits;
- u32 sram_pdn_ack_bits;
- u32 bus_prot_mask;
- enum clk_id clk_id[MAX_CLKS];
- u8 caps;
-};
-
-struct scp;
-
-struct scp_domain {
- struct generic_pm_domain genpd;
- struct scp *scp;
- struct clk *clk[MAX_CLKS];
- const struct scp_domain_data *data;
- struct regulator *supply;
-};
-
-struct scp_ctrl_reg {
- int pwr_sta_offs;
- int pwr_sta2nd_offs;
-};
-
-struct scp {
- struct scp_domain *domains;
- struct genpd_onecell_data pd_data;
- struct device *dev;
- void __iomem *base;
- struct regmap *infracfg;
- struct scp_ctrl_reg ctrl_reg;
- bool bus_prot_reg_update;
-};
-
-struct scp_subdomain {
- int origin;
- int subdomain;
-};
-
-struct scp_soc_data {
- const struct scp_domain_data *domains;
- int num_domains;
- const struct scp_subdomain *subdomains;
- int num_subdomains;
- const struct scp_ctrl_reg regs;
- bool bus_prot_reg_update;
-};
-
-static int scpsys_domain_is_on(struct scp_domain *scpd)
-{
- struct scp *scp = scpd->scp;
-
- u32 status = readl(scp->base + scp->ctrl_reg.pwr_sta_offs) &
- scpd->data->sta_mask;
- u32 status2 = readl(scp->base + scp->ctrl_reg.pwr_sta2nd_offs) &
- scpd->data->sta_mask;
-
- /*
- * A domain is on when both status bits are set. If only one is set
- * return an error. This happens while powering up a domain
- */
-
- if (status && status2)
- return true;
- if (!status && !status2)
- return false;
-
- return -EINVAL;
-}
-
-static int scpsys_regulator_enable(struct scp_domain *scpd)
-{
- if (!scpd->supply)
- return 0;
-
- return regulator_enable(scpd->supply);
-}
-
-static int scpsys_regulator_disable(struct scp_domain *scpd)
-{
- if (!scpd->supply)
- return 0;
-
- return regulator_disable(scpd->supply);
-}
-
-static void scpsys_clk_disable(struct clk *clk[], int max_num)
-{
- int i;
-
- for (i = max_num - 1; i >= 0; i--)
- clk_disable_unprepare(clk[i]);
-}
-
-static int scpsys_clk_enable(struct clk *clk[], int max_num)
-{
- int i, ret = 0;
-
- for (i = 0; i < max_num && clk[i]; i++) {
- ret = clk_prepare_enable(clk[i]);
- if (ret) {
- scpsys_clk_disable(clk, i);
- break;
- }
- }
-
- return ret;
-}
-
-static int scpsys_sram_enable(struct scp_domain *scpd, void __iomem *ctl_addr)
-{
- u32 val;
- u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
- int tmp;
-
- val = readl(ctl_addr);
- val &= ~scpd->data->sram_pdn_bits;
- writel(val, ctl_addr);
-
- /* Either wait until SRAM_PDN_ACK all 0 or have a force wait */
- if (MTK_SCPD_CAPS(scpd, MTK_SCPD_FWAIT_SRAM)) {
- /*
- * Currently, MTK_SCPD_FWAIT_SRAM is necessary only for
- * MT7622_POWER_DOMAIN_WB and thus just a trivial setup
- * is applied here.
- */
- usleep_range(12000, 12100);
- } else {
- /* Either wait until SRAM_PDN_ACK all 1 or 0 */
- int ret = readl_poll_timeout(ctl_addr, tmp,
- (tmp & pdn_ack) == 0,
- MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
- if (ret < 0)
- return ret;
- }
-
- return 0;
-}
-
-static int scpsys_sram_disable(struct scp_domain *scpd, void __iomem *ctl_addr)
-{
- u32 val;
- u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
- int tmp;
-
- val = readl(ctl_addr);
- val |= scpd->data->sram_pdn_bits;
- writel(val, ctl_addr);
-
- /* Either wait until SRAM_PDN_ACK all 1 or 0 */
- return readl_poll_timeout(ctl_addr, tmp,
- (tmp & pdn_ack) == pdn_ack,
- MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
-}
-
-static int scpsys_bus_protect_enable(struct scp_domain *scpd)
-{
- struct scp *scp = scpd->scp;
-
- if (!scpd->data->bus_prot_mask)
- return 0;
-
- return mtk_infracfg_set_bus_protection(scp->infracfg,
- scpd->data->bus_prot_mask,
- scp->bus_prot_reg_update);
-}
-
-static int scpsys_bus_protect_disable(struct scp_domain *scpd)
-{
- struct scp *scp = scpd->scp;
-
- if (!scpd->data->bus_prot_mask)
- return 0;
-
- return mtk_infracfg_clear_bus_protection(scp->infracfg,
- scpd->data->bus_prot_mask,
- scp->bus_prot_reg_update);
-}
-
-static int scpsys_power_on(struct generic_pm_domain *genpd)
-{
- struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
- struct scp *scp = scpd->scp;
- void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs;
- u32 val;
- int ret, tmp;
-
- ret = scpsys_regulator_enable(scpd);
- if (ret < 0)
- return ret;
-
- ret = scpsys_clk_enable(scpd->clk, MAX_CLKS);
- if (ret)
- goto err_clk;
-
- /* subsys power on */
- val = readl(ctl_addr);
- val |= PWR_ON_BIT;
- writel(val, ctl_addr);
- val |= PWR_ON_2ND_BIT;
- writel(val, ctl_addr);
-
- /* wait until PWR_ACK = 1 */
- ret = readx_poll_timeout(scpsys_domain_is_on, scpd, tmp, tmp > 0,
- MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
- if (ret < 0)
- goto err_pwr_ack;
-
- val &= ~PWR_CLK_DIS_BIT;
- writel(val, ctl_addr);
-
- val &= ~PWR_ISO_BIT;
- writel(val, ctl_addr);
-
- val |= PWR_RST_B_BIT;
- writel(val, ctl_addr);
-
- ret = scpsys_sram_enable(scpd, ctl_addr);
- if (ret < 0)
- goto err_pwr_ack;
-
- ret = scpsys_bus_protect_disable(scpd);
- if (ret < 0)
- goto err_pwr_ack;
-
- return 0;
-
-err_pwr_ack:
- scpsys_clk_disable(scpd->clk, MAX_CLKS);
-err_clk:
- scpsys_regulator_disable(scpd);
-
- dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name);
-
- return ret;
-}
-
-static int scpsys_power_off(struct generic_pm_domain *genpd)
-{
- struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
- struct scp *scp = scpd->scp;
- void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs;
- u32 val;
- int ret, tmp;
-
- ret = scpsys_bus_protect_enable(scpd);
- if (ret < 0)
- goto out;
-
- ret = scpsys_sram_disable(scpd, ctl_addr);
- if (ret < 0)
- goto out;
-
- /* subsys power off */
- val = readl(ctl_addr);
- val |= PWR_ISO_BIT;
- writel(val, ctl_addr);
-
- val &= ~PWR_RST_B_BIT;
- writel(val, ctl_addr);
-
- val |= PWR_CLK_DIS_BIT;
- writel(val, ctl_addr);
-
- val &= ~PWR_ON_BIT;
- writel(val, ctl_addr);
-
- val &= ~PWR_ON_2ND_BIT;
- writel(val, ctl_addr);
-
- /* wait until PWR_ACK = 0 */
- ret = readx_poll_timeout(scpsys_domain_is_on, scpd, tmp, tmp == 0,
- MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
- if (ret < 0)
- goto out;
-
- scpsys_clk_disable(scpd->clk, MAX_CLKS);
-
- ret = scpsys_regulator_disable(scpd);
- if (ret < 0)
- goto out;
-
- return 0;
-
-out:
- dev_err(scp->dev, "Failed to power off domain %s\n", genpd->name);
-
- return ret;
-}
-
-static void init_clks(struct platform_device *pdev, struct clk **clk)
-{
- int i;
-
- for (i = CLK_NONE + 1; i < CLK_MAX; i++)
- clk[i] = devm_clk_get(&pdev->dev, clk_names[i]);
-}
-
-static struct scp *init_scp(struct platform_device *pdev,
- const struct scp_domain_data *scp_domain_data, int num,
- const struct scp_ctrl_reg *scp_ctrl_reg,
- bool bus_prot_reg_update)
-{
- struct genpd_onecell_data *pd_data;
- struct resource *res;
- int i, j;
- struct scp *scp;
- struct clk *clk[CLK_MAX];
-
- scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
- if (!scp)
- return ERR_PTR(-ENOMEM);
-
- scp->ctrl_reg.pwr_sta_offs = scp_ctrl_reg->pwr_sta_offs;
- scp->ctrl_reg.pwr_sta2nd_offs = scp_ctrl_reg->pwr_sta2nd_offs;
-
- scp->bus_prot_reg_update = bus_prot_reg_update;
-
- scp->dev = &pdev->dev;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- scp->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(scp->base))
- return ERR_CAST(scp->base);
-
- scp->domains = devm_kcalloc(&pdev->dev,
- num, sizeof(*scp->domains), GFP_KERNEL);
- if (!scp->domains)
- return ERR_PTR(-ENOMEM);
-
- pd_data = &scp->pd_data;
-
- pd_data->domains = devm_kcalloc(&pdev->dev,
- num, sizeof(*pd_data->domains), GFP_KERNEL);
- if (!pd_data->domains)
- return ERR_PTR(-ENOMEM);
-
- scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
- "infracfg");
- if (IS_ERR(scp->infracfg)) {
- dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n",
- PTR_ERR(scp->infracfg));
- return ERR_CAST(scp->infracfg);
- }
-
- for (i = 0; i < num; i++) {
- struct scp_domain *scpd = &scp->domains[i];
- const struct scp_domain_data *data = &scp_domain_data[i];
-
- scpd->supply = devm_regulator_get_optional(&pdev->dev, data->name);
- if (IS_ERR(scpd->supply)) {
- if (PTR_ERR(scpd->supply) == -ENODEV)
- scpd->supply = NULL;
- else
- return ERR_CAST(scpd->supply);
- }
- }
-
- pd_data->num_domains = num;
-
- init_clks(pdev, clk);
-
- for (i = 0; i < num; i++) {
- struct scp_domain *scpd = &scp->domains[i];
- struct generic_pm_domain *genpd = &scpd->genpd;
- const struct scp_domain_data *data = &scp_domain_data[i];
-
- pd_data->domains[i] = genpd;
- scpd->scp = scp;
-
- scpd->data = data;
-
- for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
- struct clk *c = clk[data->clk_id[j]];
-
- if (IS_ERR(c)) {
- dev_err(&pdev->dev, "%s: clk unavailable\n",
- data->name);
- return ERR_CAST(c);
- }
-
- scpd->clk[j] = c;
- }
-
- genpd->name = data->name;
- genpd->power_off = scpsys_power_off;
- genpd->power_on = scpsys_power_on;
- if (MTK_SCPD_CAPS(scpd, MTK_SCPD_ACTIVE_WAKEUP))
- genpd->flags |= GENPD_FLAG_ACTIVE_WAKEUP;
- }
-
- return scp;
-}
-
-static void mtk_register_power_domains(struct platform_device *pdev,
- struct scp *scp, int num)
-{
- struct genpd_onecell_data *pd_data;
- int i, ret;
-
- for (i = 0; i < num; i++) {
- struct scp_domain *scpd = &scp->domains[i];
- struct generic_pm_domain *genpd = &scpd->genpd;
- bool on;
-
- /*
- * Initially turn on all domains to make the domains usable
- * with !CONFIG_PM and to get the hardware in sync with the
- * software. The unused domains will be switched off during
- * late_init time.
- */
- on = !WARN_ON(genpd->power_on(genpd) < 0);
-
- pm_genpd_init(genpd, NULL, !on);
- }
-
- /*
- * We are not allowed to fail here since there is no way to unregister
- * a power domain. Once registered above we have to keep the domains
- * valid.
- */
-
- pd_data = &scp->pd_data;
-
- ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
- if (ret)
- dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
-}
-
-/*
- * MT2701 power domain support
- */
-
-static const struct scp_domain_data scp_domain_data_mt2701[] = {
- [MT2701_POWER_DOMAIN_CONN] = {
- .name = "conn",
- .sta_mask = PWR_STATUS_CONN,
- .ctl_offs = SPM_CONN_PWR_CON,
- .bus_prot_mask = MT2701_TOP_AXI_PROT_EN_CONN_M |
- MT2701_TOP_AXI_PROT_EN_CONN_S,
- .clk_id = {CLK_NONE},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT2701_POWER_DOMAIN_DISP] = {
- .name = "disp",
- .sta_mask = PWR_STATUS_DISP,
- .ctl_offs = SPM_DIS_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .clk_id = {CLK_MM},
- .bus_prot_mask = MT2701_TOP_AXI_PROT_EN_MM_M0,
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT2701_POWER_DOMAIN_MFG] = {
- .name = "mfg",
- .sta_mask = PWR_STATUS_MFG,
- .ctl_offs = SPM_MFG_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .clk_id = {CLK_MFG},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT2701_POWER_DOMAIN_VDEC] = {
- .name = "vdec",
- .sta_mask = PWR_STATUS_VDEC,
- .ctl_offs = SPM_VDE_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .clk_id = {CLK_MM},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT2701_POWER_DOMAIN_ISP] = {
- .name = "isp",
- .sta_mask = PWR_STATUS_ISP,
- .ctl_offs = SPM_ISP_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(13, 12),
- .clk_id = {CLK_MM},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT2701_POWER_DOMAIN_BDP] = {
- .name = "bdp",
- .sta_mask = PWR_STATUS_BDP,
- .ctl_offs = SPM_BDP_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .clk_id = {CLK_NONE},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT2701_POWER_DOMAIN_ETH] = {
- .name = "eth",
- .sta_mask = PWR_STATUS_ETH,
- .ctl_offs = SPM_ETH_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- .clk_id = {CLK_ETHIF},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT2701_POWER_DOMAIN_HIF] = {
- .name = "hif",
- .sta_mask = PWR_STATUS_HIF,
- .ctl_offs = SPM_HIF_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- .clk_id = {CLK_ETHIF},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT2701_POWER_DOMAIN_IFR_MSC] = {
- .name = "ifr_msc",
- .sta_mask = PWR_STATUS_IFR_MSC,
- .ctl_offs = SPM_IFR_MSC_PWR_CON,
- .clk_id = {CLK_NONE},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
-};
-
-/*
- * MT2712 power domain support
- */
-static const struct scp_domain_data scp_domain_data_mt2712[] = {
- [MT2712_POWER_DOMAIN_MM] = {
- .name = "mm",
- .sta_mask = PWR_STATUS_DISP,
- .ctl_offs = SPM_DIS_PWR_CON,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .clk_id = {CLK_MM},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT2712_POWER_DOMAIN_VDEC] = {
- .name = "vdec",
- .sta_mask = PWR_STATUS_VDEC,
- .ctl_offs = SPM_VDE_PWR_CON,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .clk_id = {CLK_MM, CLK_VDEC},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT2712_POWER_DOMAIN_VENC] = {
- .name = "venc",
- .sta_mask = PWR_STATUS_VENC,
- .ctl_offs = SPM_VEN_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- .clk_id = {CLK_MM, CLK_VENC, CLK_JPGDEC},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT2712_POWER_DOMAIN_ISP] = {
- .name = "isp",
- .sta_mask = PWR_STATUS_ISP,
- .ctl_offs = SPM_ISP_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(13, 12),
- .clk_id = {CLK_MM},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT2712_POWER_DOMAIN_AUDIO] = {
- .name = "audio",
- .sta_mask = PWR_STATUS_AUDIO,
- .ctl_offs = SPM_AUDIO_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- .clk_id = {CLK_AUDIO},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT2712_POWER_DOMAIN_USB] = {
- .name = "usb",
- .sta_mask = PWR_STATUS_USB,
- .ctl_offs = SPM_USB_PWR_CON,
- .sram_pdn_bits = GENMASK(10, 8),
- .sram_pdn_ack_bits = GENMASK(14, 12),
- .clk_id = {CLK_NONE},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT2712_POWER_DOMAIN_USB2] = {
- .name = "usb2",
- .sta_mask = PWR_STATUS_USB2,
- .ctl_offs = SPM_USB2_PWR_CON,
- .sram_pdn_bits = GENMASK(10, 8),
- .sram_pdn_ack_bits = GENMASK(14, 12),
- .clk_id = {CLK_NONE},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT2712_POWER_DOMAIN_MFG] = {
- .name = "mfg",
- .sta_mask = PWR_STATUS_MFG,
- .ctl_offs = SPM_MFG_PWR_CON,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(16, 16),
- .clk_id = {CLK_MFG},
- .bus_prot_mask = BIT(14) | BIT(21) | BIT(23),
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT2712_POWER_DOMAIN_MFG_SC1] = {
- .name = "mfg_sc1",
- .sta_mask = BIT(22),
- .ctl_offs = 0x02c0,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(16, 16),
- .clk_id = {CLK_NONE},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT2712_POWER_DOMAIN_MFG_SC2] = {
- .name = "mfg_sc2",
- .sta_mask = BIT(23),
- .ctl_offs = 0x02c4,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(16, 16),
- .clk_id = {CLK_NONE},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT2712_POWER_DOMAIN_MFG_SC3] = {
- .name = "mfg_sc3",
- .sta_mask = BIT(30),
- .ctl_offs = 0x01f8,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(16, 16),
- .clk_id = {CLK_NONE},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
-};
-
-static const struct scp_subdomain scp_subdomain_mt2712[] = {
- {MT2712_POWER_DOMAIN_MM, MT2712_POWER_DOMAIN_VDEC},
- {MT2712_POWER_DOMAIN_MM, MT2712_POWER_DOMAIN_VENC},
- {MT2712_POWER_DOMAIN_MM, MT2712_POWER_DOMAIN_ISP},
- {MT2712_POWER_DOMAIN_MFG, MT2712_POWER_DOMAIN_MFG_SC1},
- {MT2712_POWER_DOMAIN_MFG_SC1, MT2712_POWER_DOMAIN_MFG_SC2},
- {MT2712_POWER_DOMAIN_MFG_SC2, MT2712_POWER_DOMAIN_MFG_SC3},
-};
-
-/*
- * MT6797 power domain support
- */
-
-static const struct scp_domain_data scp_domain_data_mt6797[] = {
- [MT6797_POWER_DOMAIN_VDEC] = {
- .name = "vdec",
- .sta_mask = BIT(7),
- .ctl_offs = 0x300,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .clk_id = {CLK_VDEC},
- },
- [MT6797_POWER_DOMAIN_VENC] = {
- .name = "venc",
- .sta_mask = BIT(21),
- .ctl_offs = 0x304,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- .clk_id = {CLK_NONE},
- },
- [MT6797_POWER_DOMAIN_ISP] = {
- .name = "isp",
- .sta_mask = BIT(5),
- .ctl_offs = 0x308,
- .sram_pdn_bits = GENMASK(9, 8),
- .sram_pdn_ack_bits = GENMASK(13, 12),
- .clk_id = {CLK_NONE},
- },
- [MT6797_POWER_DOMAIN_MM] = {
- .name = "mm",
- .sta_mask = BIT(3),
- .ctl_offs = 0x30C,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .clk_id = {CLK_MM},
- .bus_prot_mask = (BIT(1) | BIT(2)),
- },
- [MT6797_POWER_DOMAIN_AUDIO] = {
- .name = "audio",
- .sta_mask = BIT(24),
- .ctl_offs = 0x314,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- .clk_id = {CLK_NONE},
- },
- [MT6797_POWER_DOMAIN_MFG_ASYNC] = {
- .name = "mfg_async",
- .sta_mask = BIT(13),
- .ctl_offs = 0x334,
- .sram_pdn_bits = 0,
- .sram_pdn_ack_bits = 0,
- .clk_id = {CLK_MFG},
- },
- [MT6797_POWER_DOMAIN_MJC] = {
- .name = "mjc",
- .sta_mask = BIT(20),
- .ctl_offs = 0x310,
- .sram_pdn_bits = GENMASK(8, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .clk_id = {CLK_NONE},
- },
-};
-
-#define SPM_PWR_STATUS_MT6797 0x0180
-#define SPM_PWR_STATUS_2ND_MT6797 0x0184
-
-static const struct scp_subdomain scp_subdomain_mt6797[] = {
- {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_VDEC},
- {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_ISP},
- {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_VENC},
- {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_MJC},
-};
-
-/*
- * MT7622 power domain support
- */
-
-static const struct scp_domain_data scp_domain_data_mt7622[] = {
- [MT7622_POWER_DOMAIN_ETHSYS] = {
- .name = "ethsys",
- .sta_mask = PWR_STATUS_ETHSYS,
- .ctl_offs = SPM_ETHSYS_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- .clk_id = {CLK_NONE},
- .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_ETHSYS,
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT7622_POWER_DOMAIN_HIF0] = {
- .name = "hif0",
- .sta_mask = PWR_STATUS_HIF0,
- .ctl_offs = SPM_HIF0_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- .clk_id = {CLK_HIFSEL},
- .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_HIF0,
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT7622_POWER_DOMAIN_HIF1] = {
- .name = "hif1",
- .sta_mask = PWR_STATUS_HIF1,
- .ctl_offs = SPM_HIF1_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- .clk_id = {CLK_HIFSEL},
- .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_HIF1,
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT7622_POWER_DOMAIN_WB] = {
- .name = "wb",
- .sta_mask = PWR_STATUS_WB,
- .ctl_offs = SPM_WB_PWR_CON,
- .sram_pdn_bits = 0,
- .sram_pdn_ack_bits = 0,
- .clk_id = {CLK_NONE},
- .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_WB,
- .caps = MTK_SCPD_ACTIVE_WAKEUP | MTK_SCPD_FWAIT_SRAM,
- },
-};
-
-/*
- * MT7623A power domain support
- */
-
-static const struct scp_domain_data scp_domain_data_mt7623a[] = {
- [MT7623A_POWER_DOMAIN_CONN] = {
- .name = "conn",
- .sta_mask = PWR_STATUS_CONN,
- .ctl_offs = SPM_CONN_PWR_CON,
- .bus_prot_mask = MT2701_TOP_AXI_PROT_EN_CONN_M |
- MT2701_TOP_AXI_PROT_EN_CONN_S,
- .clk_id = {CLK_NONE},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT7623A_POWER_DOMAIN_ETH] = {
- .name = "eth",
- .sta_mask = PWR_STATUS_ETH,
- .ctl_offs = SPM_ETH_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- .clk_id = {CLK_ETHIF},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT7623A_POWER_DOMAIN_HIF] = {
- .name = "hif",
- .sta_mask = PWR_STATUS_HIF,
- .ctl_offs = SPM_HIF_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- .clk_id = {CLK_ETHIF},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT7623A_POWER_DOMAIN_IFR_MSC] = {
- .name = "ifr_msc",
- .sta_mask = PWR_STATUS_IFR_MSC,
- .ctl_offs = SPM_IFR_MSC_PWR_CON,
- .clk_id = {CLK_NONE},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
-};
-
-/*
- * MT8173 power domain support
- */
-
-static const struct scp_domain_data scp_domain_data_mt8173[] = {
- [MT8173_POWER_DOMAIN_VDEC] = {
- .name = "vdec",
- .sta_mask = PWR_STATUS_VDEC,
- .ctl_offs = SPM_VDE_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .clk_id = {CLK_MM},
- },
- [MT8173_POWER_DOMAIN_VENC] = {
- .name = "venc",
- .sta_mask = PWR_STATUS_VENC,
- .ctl_offs = SPM_VEN_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- .clk_id = {CLK_MM, CLK_VENC},
- },
- [MT8173_POWER_DOMAIN_ISP] = {
- .name = "isp",
- .sta_mask = PWR_STATUS_ISP,
- .ctl_offs = SPM_ISP_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(13, 12),
- .clk_id = {CLK_MM},
- },
- [MT8173_POWER_DOMAIN_MM] = {
- .name = "mm",
- .sta_mask = PWR_STATUS_DISP,
- .ctl_offs = SPM_DIS_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(12, 12),
- .clk_id = {CLK_MM},
- .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
- MT8173_TOP_AXI_PROT_EN_MM_M1,
- },
- [MT8173_POWER_DOMAIN_VENC_LT] = {
- .name = "venc_lt",
- .sta_mask = PWR_STATUS_VENC_LT,
- .ctl_offs = SPM_VEN2_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- .clk_id = {CLK_MM, CLK_VENC_LT},
- },
- [MT8173_POWER_DOMAIN_AUDIO] = {
- .name = "audio",
- .sta_mask = PWR_STATUS_AUDIO,
- .ctl_offs = SPM_AUDIO_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- .clk_id = {CLK_NONE},
- },
- [MT8173_POWER_DOMAIN_USB] = {
- .name = "usb",
- .sta_mask = PWR_STATUS_USB,
- .ctl_offs = SPM_USB_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(15, 12),
- .clk_id = {CLK_NONE},
- .caps = MTK_SCPD_ACTIVE_WAKEUP,
- },
- [MT8173_POWER_DOMAIN_MFG_ASYNC] = {
- .name = "mfg_async",
- .sta_mask = PWR_STATUS_MFG_ASYNC,
- .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = 0,
- .clk_id = {CLK_MFG},
- },
- [MT8173_POWER_DOMAIN_MFG_2D] = {
- .name = "mfg_2d",
- .sta_mask = PWR_STATUS_MFG_2D,
- .ctl_offs = SPM_MFG_2D_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .sram_pdn_ack_bits = GENMASK(13, 12),
- .clk_id = {CLK_NONE},
- },
- [MT8173_POWER_DOMAIN_MFG] = {
- .name = "mfg",
- .sta_mask = PWR_STATUS_MFG,
- .ctl_offs = SPM_MFG_PWR_CON,
- .sram_pdn_bits = GENMASK(13, 8),
- .sram_pdn_ack_bits = GENMASK(21, 16),
- .clk_id = {CLK_NONE},
- .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
- MT8173_TOP_AXI_PROT_EN_MFG_M0 |
- MT8173_TOP_AXI_PROT_EN_MFG_M1 |
- MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
- },
-};
-
-static const struct scp_subdomain scp_subdomain_mt8173[] = {
- {MT8173_POWER_DOMAIN_MFG_ASYNC, MT8173_POWER_DOMAIN_MFG_2D},
- {MT8173_POWER_DOMAIN_MFG_2D, MT8173_POWER_DOMAIN_MFG},
-};
-
-static const struct scp_soc_data mt2701_data = {
- .domains = scp_domain_data_mt2701,
- .num_domains = ARRAY_SIZE(scp_domain_data_mt2701),
- .regs = {
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND
- },
- .bus_prot_reg_update = true,
-};
-
-static const struct scp_soc_data mt2712_data = {
- .domains = scp_domain_data_mt2712,
- .num_domains = ARRAY_SIZE(scp_domain_data_mt2712),
- .subdomains = scp_subdomain_mt2712,
- .num_subdomains = ARRAY_SIZE(scp_subdomain_mt2712),
- .regs = {
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND
- },
- .bus_prot_reg_update = false,
-};
-
-static const struct scp_soc_data mt6797_data = {
- .domains = scp_domain_data_mt6797,
- .num_domains = ARRAY_SIZE(scp_domain_data_mt6797),
- .subdomains = scp_subdomain_mt6797,
- .num_subdomains = ARRAY_SIZE(scp_subdomain_mt6797),
- .regs = {
- .pwr_sta_offs = SPM_PWR_STATUS_MT6797,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND_MT6797
- },
- .bus_prot_reg_update = true,
-};
-
-static const struct scp_soc_data mt7622_data = {
- .domains = scp_domain_data_mt7622,
- .num_domains = ARRAY_SIZE(scp_domain_data_mt7622),
- .regs = {
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND
- },
- .bus_prot_reg_update = true,
-};
-
-static const struct scp_soc_data mt7623a_data = {
- .domains = scp_domain_data_mt7623a,
- .num_domains = ARRAY_SIZE(scp_domain_data_mt7623a),
- .regs = {
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND
- },
- .bus_prot_reg_update = true,
-};
-
-static const struct scp_soc_data mt8173_data = {
- .domains = scp_domain_data_mt8173,
- .num_domains = ARRAY_SIZE(scp_domain_data_mt8173),
- .subdomains = scp_subdomain_mt8173,
- .num_subdomains = ARRAY_SIZE(scp_subdomain_mt8173),
- .regs = {
- .pwr_sta_offs = SPM_PWR_STATUS,
- .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND
- },
- .bus_prot_reg_update = true,
-};
-
-/*
- * scpsys driver init
- */
-
-static const struct of_device_id of_scpsys_match_tbl[] = {
- {
- .compatible = "mediatek,mt2701-scpsys",
- .data = &mt2701_data,
- }, {
- .compatible = "mediatek,mt2712-scpsys",
- .data = &mt2712_data,
- }, {
- .compatible = "mediatek,mt6797-scpsys",
- .data = &mt6797_data,
- }, {
- .compatible = "mediatek,mt7622-scpsys",
- .data = &mt7622_data,
- }, {
- .compatible = "mediatek,mt7623a-scpsys",
- .data = &mt7623a_data,
- }, {
- .compatible = "mediatek,mt8173-scpsys",
- .data = &mt8173_data,
- }, {
- /* sentinel */
- }
-};
-
-static int scpsys_probe(struct platform_device *pdev)
-{
- const struct scp_subdomain *sd;
- const struct scp_soc_data *soc;
- struct scp *scp;
- struct genpd_onecell_data *pd_data;
- int i, ret;
-
- soc = of_device_get_match_data(&pdev->dev);
-
- scp = init_scp(pdev, soc->domains, soc->num_domains, &soc->regs,
- soc->bus_prot_reg_update);
- if (IS_ERR(scp))
- return PTR_ERR(scp);
-
- mtk_register_power_domains(pdev, scp, soc->num_domains);
-
- pd_data = &scp->pd_data;
-
- for (i = 0, sd = soc->subdomains; i < soc->num_subdomains; i++, sd++) {
- ret = pm_genpd_add_subdomain(pd_data->domains[sd->origin],
- pd_data->domains[sd->subdomain]);
- if (ret && IS_ENABLED(CONFIG_PM))
- dev_err(&pdev->dev, "Failed to add subdomain: %d\n",
- ret);
- }
-
- return 0;
-}
-
-static struct platform_driver scpsys_drv = {
- .probe = scpsys_probe,
- .driver = {
- .name = "mtk-scpsys",
- .suppress_bind_attrs = true,
- .owner = THIS_MODULE,
- .of_match_table = of_scpsys_match_tbl,
- },
-};
-builtin_platform_driver(scpsys_drv);
diff --git a/drivers/soc/mediatek/mtk-socinfo.c b/drivers/soc/mediatek/mtk-socinfo.c
new file mode 100644
index 000000000000..978c43e9115a
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-socinfo.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 MediaTek Inc.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/device.h>
+#include <linux/device/bus.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+#include <linux/sys_soc.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#define MTK_SOCINFO_ENTRY(_soc_name, _segment_name, _marketing_name, _cell_data1, _cell_data2) {\
+ .soc_name = _soc_name, \
+ .segment_name = _segment_name, \
+ .marketing_name = _marketing_name, \
+ .cell_data = {_cell_data1, _cell_data2} \
+}
+#define CELL_NOT_USED (0xFFFFFFFF)
+#define MAX_CELLS (2)
+
+struct mtk_socinfo {
+ struct device *dev;
+ struct name_data *name_data;
+ struct socinfo_data *socinfo_data;
+ struct soc_device *soc_dev;
+};
+
+struct socinfo_data {
+ char *soc_name;
+ char *segment_name;
+ char *marketing_name;
+ u32 cell_data[MAX_CELLS];
+};
+
+static const char *cell_names[MAX_CELLS] = {"socinfo-data1", "socinfo-data2"};
+
+static struct socinfo_data socinfo_data_table[] = {
+ MTK_SOCINFO_ENTRY("MT8173", "MT8173V/AC", "MT8173", 0x6CA20004, 0x10000000),
+ MTK_SOCINFO_ENTRY("MT8183", "MT8183V/AZA", "Kompanio 500", 0x00010043, 0x00000840),
+ MTK_SOCINFO_ENTRY("MT8183", "MT8183V/AZA", "Kompanio 500", 0x00010043, 0x00000940),
+ MTK_SOCINFO_ENTRY("MT8186", "MT8186GV/AZA", "Kompanio 520", 0x81861001, CELL_NOT_USED),
+ MTK_SOCINFO_ENTRY("MT8186T", "MT8186TV/AZA", "Kompanio 528", 0x81862001, CELL_NOT_USED),
+ MTK_SOCINFO_ENTRY("MT8188", "MT8188GV/AZA", "Kompanio 838", 0x81880000, 0x00000010),
+ MTK_SOCINFO_ENTRY("MT8188", "MT8188GV/HZA", "Kompanio 838", 0x81880000, 0x00000011),
+ MTK_SOCINFO_ENTRY("MT8189", "MT8189GV/AZA", "Kompanio 540", 0x81890000, 0x00000020),
+ MTK_SOCINFO_ENTRY("MT8189", "MT8189HV/AZA", "Kompanio 540", 0x81890000, 0x00000021),
+ MTK_SOCINFO_ENTRY("MT8192", "MT8192V/AZA", "Kompanio 820", 0x00001100, 0x00040080),
+ MTK_SOCINFO_ENTRY("MT8192T", "MT8192V/ATZA", "Kompanio 828", 0x00000100, 0x000400C0),
+ MTK_SOCINFO_ENTRY("MT8195", "MT8195GV/EZA", "Kompanio 1200", 0x81950300, CELL_NOT_USED),
+ MTK_SOCINFO_ENTRY("MT8195", "MT8195GV/EHZA", "Kompanio 1200", 0x81950304, CELL_NOT_USED),
+ MTK_SOCINFO_ENTRY("MT8195", "MT8195TV/EZA", "Kompanio 1380", 0x81950400, CELL_NOT_USED),
+ MTK_SOCINFO_ENTRY("MT8195", "MT8195TV/EHZA", "Kompanio 1380", 0x81950404, CELL_NOT_USED),
+ MTK_SOCINFO_ENTRY("MT8370", "MT8370AV/AZA", "Genio 510", 0x83700000, 0x00000081),
+ MTK_SOCINFO_ENTRY("MT8390", "MT8390AV/AZA", "Genio 700", 0x83900000, 0x00000080),
+ MTK_SOCINFO_ENTRY("MT8391", "MT8391AV/AZA", "Genio 720", 0x83910000, 0x00000080),
+ MTK_SOCINFO_ENTRY("MT8395", "MT8395AV/ZA", "Genio 1200", 0x83950100, CELL_NOT_USED),
+ MTK_SOCINFO_ENTRY("MT8395", "MT8395AV/ZA", "Genio 1200", 0x83950800, CELL_NOT_USED),
+};
+
+static int mtk_socinfo_create_socinfo_node(struct mtk_socinfo *mtk_socinfop)
+{
+ struct soc_device_attribute *attrs;
+ struct socinfo_data *data = mtk_socinfop->socinfo_data;
+ static const char *soc_manufacturer = "MediaTek";
+
+ attrs = devm_kzalloc(mtk_socinfop->dev, sizeof(*attrs), GFP_KERNEL);
+ if (!attrs)
+ return -ENOMEM;
+
+ if (data->marketing_name != NULL && data->marketing_name[0] != '\0')
+ attrs->family = devm_kasprintf(mtk_socinfop->dev, GFP_KERNEL, "MediaTek %s",
+ data->marketing_name);
+ else
+ attrs->family = soc_manufacturer;
+
+ attrs->soc_id = data->soc_name;
+ /*
+ * The "machine" field will be populated automatically with the model
+ * name from board DTS (if available).
+ **/
+
+ mtk_socinfop->soc_dev = soc_device_register(attrs);
+ if (IS_ERR(mtk_socinfop->soc_dev))
+ return PTR_ERR(mtk_socinfop->soc_dev);
+
+ dev_info(mtk_socinfop->dev, "%s (%s) SoC detected.\n", attrs->family, attrs->soc_id);
+ return 0;
+}
+
+static u32 mtk_socinfo_read_cell(struct device *dev, const char *name)
+{
+ struct nvmem_device *nvmemp;
+ struct device_node *np, *nvmem_node = dev->parent->of_node;
+ u32 offset;
+ u32 cell_val = CELL_NOT_USED;
+
+ /* should never fail since the nvmem driver registers this child */
+ nvmemp = nvmem_device_find(nvmem_node, device_match_of_node);
+ if (IS_ERR(nvmemp))
+ goto out;
+
+ np = of_get_child_by_name(nvmem_node, name);
+ if (!np)
+ goto put_device;
+
+ if (of_property_read_u32_index(np, "reg", 0, &offset))
+ goto put_node;
+
+ nvmem_device_read(nvmemp, offset, sizeof(cell_val), &cell_val);
+
+put_node:
+ of_node_put(np);
+put_device:
+ nvmem_device_put(nvmemp);
+out:
+ return cell_val;
+}
+
+static int mtk_socinfo_get_socinfo_data(struct mtk_socinfo *mtk_socinfop)
+{
+ unsigned int i, j;
+ unsigned int num_cell_data = 0;
+ u32 cell_data[MAX_CELLS] = {0};
+ bool match_socinfo;
+ int match_socinfo_index = -1;
+
+ for (i = 0; i < MAX_CELLS; i++) {
+ cell_data[i] = mtk_socinfo_read_cell(mtk_socinfop->dev, cell_names[i]);
+ if (cell_data[i] != CELL_NOT_USED)
+ num_cell_data++;
+ else
+ break;
+ }
+
+ if (!num_cell_data)
+ return -ENOENT;
+
+ for (i = 0; i < ARRAY_SIZE(socinfo_data_table); i++) {
+ match_socinfo = true;
+ for (j = 0; j < num_cell_data; j++) {
+ if (cell_data[j] != socinfo_data_table[i].cell_data[j]) {
+ match_socinfo = false;
+ break;
+ }
+ }
+ if (match_socinfo) {
+ mtk_socinfop->socinfo_data = &(socinfo_data_table[i]);
+ match_socinfo_index = i;
+ break;
+ }
+ }
+
+ if (match_socinfo_index < 0) {
+ dev_warn(mtk_socinfop->dev,
+ "Unknown MediaTek SoC with ID 0x%08x 0x%08x\n",
+ cell_data[0], cell_data[1]);
+ return -ENOENT;
+ }
+
+ return match_socinfo_index;
+}
+
+static int mtk_socinfo_probe(struct platform_device *pdev)
+{
+ struct mtk_socinfo *mtk_socinfop;
+ int ret;
+
+ mtk_socinfop = devm_kzalloc(&pdev->dev, sizeof(*mtk_socinfop), GFP_KERNEL);
+ if (!mtk_socinfop)
+ return -ENOMEM;
+
+ mtk_socinfop->dev = &pdev->dev;
+
+ ret = mtk_socinfo_get_socinfo_data(mtk_socinfop);
+ if (ret < 0)
+ return dev_err_probe(mtk_socinfop->dev, ret, "Failed to get socinfo data\n");
+
+ ret = mtk_socinfo_create_socinfo_node(mtk_socinfop);
+ if (ret)
+ return dev_err_probe(mtk_socinfop->dev, ret, "Cannot create node\n");
+
+ platform_set_drvdata(pdev, mtk_socinfop);
+ return 0;
+}
+
+static void mtk_socinfo_remove(struct platform_device *pdev)
+{
+ struct mtk_socinfo *mtk_socinfop = platform_get_drvdata(pdev);
+
+ soc_device_unregister(mtk_socinfop->soc_dev);
+}
+
+static struct platform_driver mtk_socinfo = {
+ .probe = mtk_socinfo_probe,
+ .remove = mtk_socinfo_remove,
+ .driver = {
+ .name = "mtk-socinfo",
+ },
+};
+module_platform_driver(mtk_socinfo);
+
+MODULE_AUTHOR("William-TW LIN <william-tw.lin@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek socinfo driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c
index 0469c9dfeb04..f45537546553 100644
--- a/drivers/soc/mediatek/mtk-svs.c
+++ b/drivers/soc/mediatek/mtk-svs.c
@@ -1,12 +1,15 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2022 MediaTek Inc.
+ * Copyright (C) 2022 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
*/
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/completion.h>
+#include <linux/cpu.h>
#include <linux/cpuidle.h>
#include <linux/debugfs.h>
#include <linux/device.h>
@@ -31,16 +34,6 @@
#include <linux/spinlock.h>
#include <linux/thermal.h>
-/* svs bank 1-line software id */
-#define SVSB_CPU_LITTLE BIT(0)
-#define SVSB_CPU_BIG BIT(1)
-#define SVSB_CCI BIT(2)
-#define SVSB_GPU BIT(3)
-
-/* svs bank 2-line type */
-#define SVSB_LOW BIT(8)
-#define SVSB_HIGH BIT(9)
-
/* svs bank mode support */
#define SVSB_MODE_ALL_DISABLE 0
#define SVSB_MODE_INIT01 BIT(1)
@@ -127,6 +120,13 @@
#define SVSB_VOPS_FLD_VOP2_6 GENMASK(23, 16)
#define SVSB_VOPS_FLD_VOP3_7 GENMASK(31, 24)
+/* SVS Thermal Coefficients */
+#define SVSB_TS_COEFF_MT8195 250460
+#define SVSB_TS_COEFF_MT8186 204650
+
+/* Algo helpers */
+#define FUSE_DATA_NOT_VALID U32_MAX
+
/* svs bank related setting */
#define BITS8 8
#define MAX_OPP_ENTRIES 16
@@ -138,6 +138,7 @@
static DEFINE_SPINLOCK(svs_lock);
+#ifdef CONFIG_DEBUG_FS
#define debug_fops_ro(name) \
static int svs_##name##_debug_open(struct inode *inode, \
struct file *filp) \
@@ -170,6 +171,37 @@ static DEFINE_SPINLOCK(svs_lock);
}
#define svs_dentry_data(name) {__stringify(name), &svs_##name##_debug_fops}
+#endif
+
+/**
+ * enum svsb_sw_id - SVS Bank Software ID
+ * @SVSB_SWID_CPU_LITTLE: CPU little cluster Bank
+ * @SVSB_SWID_CPU_BIG: CPU big cluster Bank
+ * @SVSB_SWID_CCI: Cache Coherent Interconnect Bank
+ * @SVSB_SWID_GPU: GPU Bank
+ * @SVSB_SWID_MAX: Total number of Banks
+ */
+enum svsb_sw_id {
+ SVSB_SWID_CPU_LITTLE,
+ SVSB_SWID_CPU_BIG,
+ SVSB_SWID_CCI,
+ SVSB_SWID_GPU,
+ SVSB_SWID_MAX
+};
+
+/**
+ * enum svsb_type - SVS Bank 2-line: Type and Role
+ * @SVSB_TYPE_NONE: One-line type Bank - Global role
+ * @SVSB_TYPE_LOW: Two-line type Bank - Low bank role
+ * @SVSB_TYPE_HIGH: Two-line type Bank - High bank role
+ * @SVSB_TYPE_MAX: Total number of bank types
+ */
+enum svsb_type {
+ SVSB_TYPE_NONE,
+ SVSB_TYPE_LOW,
+ SVSB_TYPE_HIGH,
+ SVSB_TYPE_MAX
+};
/**
* enum svsb_phase - svs bank phase enumeration
@@ -253,155 +285,213 @@ enum svs_reg_index {
};
static const u32 svs_regs_v2[] = {
- [DESCHAR] = 0xc00,
- [TEMPCHAR] = 0xc04,
- [DETCHAR] = 0xc08,
- [AGECHAR] = 0xc0c,
- [DCCONFIG] = 0xc10,
- [AGECONFIG] = 0xc14,
- [FREQPCT30] = 0xc18,
- [FREQPCT74] = 0xc1c,
- [LIMITVALS] = 0xc20,
- [VBOOT] = 0xc24,
- [DETWINDOW] = 0xc28,
- [CONFIG] = 0xc2c,
- [TSCALCS] = 0xc30,
- [RUNCONFIG] = 0xc34,
- [SVSEN] = 0xc38,
- [INIT2VALS] = 0xc3c,
- [DCVALUES] = 0xc40,
- [AGEVALUES] = 0xc44,
- [VOP30] = 0xc48,
- [VOP74] = 0xc4c,
- [TEMP] = 0xc50,
- [INTSTS] = 0xc54,
- [INTSTSRAW] = 0xc58,
- [INTEN] = 0xc5c,
- [CHKINT] = 0xc60,
- [CHKSHIFT] = 0xc64,
- [STATUS] = 0xc68,
- [VDESIGN30] = 0xc6c,
- [VDESIGN74] = 0xc70,
- [DVT30] = 0xc74,
- [DVT74] = 0xc78,
- [AGECOUNT] = 0xc7c,
- [SMSTATE0] = 0xc80,
- [SMSTATE1] = 0xc84,
- [CTL0] = 0xc88,
- [DESDETSEC] = 0xce0,
- [TEMPAGESEC] = 0xce4,
- [CTRLSPARE0] = 0xcf0,
- [CTRLSPARE1] = 0xcf4,
- [CTRLSPARE2] = 0xcf8,
- [CTRLSPARE3] = 0xcfc,
- [CORESEL] = 0xf00,
- [THERMINTST] = 0xf04,
- [INTST] = 0xf08,
- [THSTAGE0ST] = 0xf0c,
- [THSTAGE1ST] = 0xf10,
- [THSTAGE2ST] = 0xf14,
- [THAHBST0] = 0xf18,
- [THAHBST1] = 0xf1c,
- [SPARE0] = 0xf20,
- [SPARE1] = 0xf24,
- [SPARE2] = 0xf28,
- [SPARE3] = 0xf2c,
- [THSLPEVEB] = 0xf30,
+ [DESCHAR] = 0x00,
+ [TEMPCHAR] = 0x04,
+ [DETCHAR] = 0x08,
+ [AGECHAR] = 0x0c,
+ [DCCONFIG] = 0x10,
+ [AGECONFIG] = 0x14,
+ [FREQPCT30] = 0x18,
+ [FREQPCT74] = 0x1c,
+ [LIMITVALS] = 0x20,
+ [VBOOT] = 0x24,
+ [DETWINDOW] = 0x28,
+ [CONFIG] = 0x2c,
+ [TSCALCS] = 0x30,
+ [RUNCONFIG] = 0x34,
+ [SVSEN] = 0x38,
+ [INIT2VALS] = 0x3c,
+ [DCVALUES] = 0x40,
+ [AGEVALUES] = 0x44,
+ [VOP30] = 0x48,
+ [VOP74] = 0x4c,
+ [TEMP] = 0x50,
+ [INTSTS] = 0x54,
+ [INTSTSRAW] = 0x58,
+ [INTEN] = 0x5c,
+ [CHKINT] = 0x60,
+ [CHKSHIFT] = 0x64,
+ [STATUS] = 0x68,
+ [VDESIGN30] = 0x6c,
+ [VDESIGN74] = 0x70,
+ [DVT30] = 0x74,
+ [DVT74] = 0x78,
+ [AGECOUNT] = 0x7c,
+ [SMSTATE0] = 0x80,
+ [SMSTATE1] = 0x84,
+ [CTL0] = 0x88,
+ [DESDETSEC] = 0xe0,
+ [TEMPAGESEC] = 0xe4,
+ [CTRLSPARE0] = 0xf0,
+ [CTRLSPARE1] = 0xf4,
+ [CTRLSPARE2] = 0xf8,
+ [CTRLSPARE3] = 0xfc,
+ [CORESEL] = 0x300,
+ [THERMINTST] = 0x304,
+ [INTST] = 0x308,
+ [THSTAGE0ST] = 0x30c,
+ [THSTAGE1ST] = 0x310,
+ [THSTAGE2ST] = 0x314,
+ [THAHBST0] = 0x318,
+ [THAHBST1] = 0x31c,
+ [SPARE0] = 0x320,
+ [SPARE1] = 0x324,
+ [SPARE2] = 0x328,
+ [SPARE3] = 0x32c,
+ [THSLPEVEB] = 0x330,
+};
+
+static const char * const svs_swid_names[SVSB_SWID_MAX] = {
+ "SVSB_CPU_LITTLE", "SVSB_CPU_BIG", "SVSB_CCI", "SVSB_GPU"
+};
+
+static const char * const svs_type_names[SVSB_TYPE_MAX] = {
+ "", "_LOW", "_HIGH"
+};
+
+enum svs_fusemap_dev {
+ BDEV_BDES,
+ BDEV_MDES,
+ BDEV_MTDES,
+ BDEV_DCBDET,
+ BDEV_DCMDET,
+ BDEV_MAX
+};
+
+enum svs_fusemap_glb {
+ GLB_FT_PGM,
+ GLB_VMIN,
+ GLB_MAX
+};
+
+struct svs_fusemap {
+ s8 index;
+ u8 ofst;
};
/**
* struct svs_platform - svs platform control
- * @name: svs platform name
* @base: svs platform register base
* @dev: svs platform device
* @main_clk: main clock for svs bank
- * @pbank: svs bank pointer needing to be protected by spin_lock section
* @banks: svs banks that svs platform supports
* @rst: svs platform reset control
- * @efuse_parsing: svs platform efuse parsing function pointer
- * @probe: svs platform probe function pointer
* @efuse_max: total number of svs efuse
* @tefuse_max: total number of thermal efuse
* @regs: svs platform registers map
- * @bank_max: total number of svs banks
* @efuse: svs efuse data received from NVMEM framework
* @tefuse: thermal efuse data received from NVMEM framework
+ * @ts_coeff: thermal sensors coefficient
+ * @bank_max: total number of svs banks
*/
struct svs_platform {
- char *name;
void __iomem *base;
struct device *dev;
struct clk *main_clk;
- struct svs_bank *pbank;
struct svs_bank *banks;
struct reset_control *rst;
- bool (*efuse_parsing)(struct svs_platform *svsp);
- int (*probe)(struct svs_platform *svsp);
size_t efuse_max;
size_t tefuse_max;
const u32 *regs;
- u32 bank_max;
u32 *efuse;
u32 *tefuse;
+ u32 ts_coeff;
+ u16 bank_max;
};
struct svs_platform_data {
char *name;
struct svs_bank *banks;
- bool (*efuse_parsing)(struct svs_platform *svsp);
+ bool (*efuse_parsing)(struct svs_platform *svsp, const struct svs_platform_data *pdata);
int (*probe)(struct svs_platform *svsp);
+ const struct svs_fusemap *glb_fuse_map;
const u32 *regs;
- u32 bank_max;
+ u32 ts_coeff;
+ u16 bank_max;
+};
+
+/**
+ * struct svs_bank_pdata - SVS Bank immutable config parameters
+ * @dev_fuse_map: Bank fuse map data
+ * @buck_name: Regulator name
+ * @tzone_name: Thermal zone name
+ * @age_config: Bank age configuration
+ * @ctl0: TS-x selection
+ * @dc_config: Bank dc configuration
+ * @int_st: Bank interrupt identification
+ * @turn_freq_base: Reference frequency for 2-line turn point
+ * @tzone_htemp: Thermal zone high temperature threshold
+ * @tzone_ltemp: Thermal zone low temperature threshold
+ * @volt_step: Bank voltage step
+ * @volt_base: Bank voltage base
+ * @tzone_htemp_voffset: Thermal zone high temperature voltage offset
+ * @tzone_ltemp_voffset: Thermal zone low temperature voltage offset
+ * @chk_shift: Bank chicken shift
+ * @cpu_id: CPU core ID for SVS CPU bank use only
+ * @opp_count: Bank opp count
+ * @vboot: Voltage request for bank init01 only
+ * @vco: Bank VCO value
+ * @sw_id: Bank software identification
+ * @type: SVS Bank Type (1 or 2-line) and Role (high/low)
+ * @set_freq_pct: function pointer to set bank frequency percent table
+ * @get_volts: function pointer to get bank voltages
+ */
+struct svs_bank_pdata {
+ const struct svs_fusemap *dev_fuse_map;
+ char *buck_name;
+ char *tzone_name;
+ u32 age_config;
+ u32 ctl0;
+ u32 dc_config;
+ u32 int_st;
+ u32 turn_freq_base;
+ u32 tzone_htemp;
+ u32 tzone_ltemp;
+ u32 volt_step;
+ u32 volt_base;
+ u16 tzone_htemp_voffset;
+ u16 tzone_ltemp_voffset;
+ u8 chk_shift;
+ u8 cpu_id;
+ u8 opp_count;
+ u8 vboot;
+ u8 vco;
+ u8 sw_id;
+ u8 type;
+
+ /* Callbacks */
+ void (*set_freq_pct)(struct svs_platform *svsp, struct svs_bank *svsb);
+ void (*get_volts)(struct svs_platform *svsp, struct svs_bank *svsb);
};
/**
* struct svs_bank - svs bank representation
+ * @pdata: SVS Bank immutable config parameters
* @dev: bank device
* @opp_dev: device for opp table/buck control
* @init_completion: the timeout completion for bank init
* @buck: regulator used by opp_dev
* @tzd: thermal zone device for getting temperature
* @lock: mutex lock to protect voltage update process
- * @set_freq_pct: function pointer to set bank frequency percent table
- * @get_volts: function pointer to get bank voltages
* @name: bank name
- * @buck_name: regulator name
- * @tzone_name: thermal zone name
* @phase: bank current phase
* @volt_od: bank voltage overdrive
* @reg_data: bank register data in different phase for debug purpose
* @pm_runtime_enabled_count: bank pm runtime enabled count
- * @mode_support: bank mode support.
+ * @mode_support: bank mode support
* @freq_base: reference frequency for bank init
- * @turn_freq_base: refenrece frequency for 2-line turn point
- * @vboot: voltage request for bank init01 only
* @opp_dfreq: default opp frequency table
* @opp_dvolt: default opp voltage table
* @freq_pct: frequency percent table for bank init
* @volt: bank voltage table
- * @volt_step: bank voltage step
- * @volt_base: bank voltage base
* @volt_flags: bank voltage flags
* @vmax: bank voltage maximum
* @vmin: bank voltage minimum
- * @age_config: bank age configuration
* @age_voffset_in: bank age voltage offset
- * @dc_config: bank dc configuration
* @dc_voffset_in: bank dc voltage offset
* @dvt_fixed: bank dvt fixed value
- * @vco: bank VCO value
- * @chk_shift: bank chicken shift
* @core_sel: bank selection
- * @opp_count: bank opp count
- * @int_st: bank interrupt identification
- * @sw_id: bank software identification
- * @cpu_id: cpu core id for SVS CPU bank use only
- * @ctl0: TS-x selection
* @temp: bank temperature
- * @tzone_htemp: thermal zone high temperature threshold
- * @tzone_htemp_voffset: thermal zone high temperature voltage offset
- * @tzone_ltemp: thermal zone low temperature threshold
- * @tzone_ltemp_voffset: thermal zone low temperature voltage offset
* @bts: svs efuse data
* @mts: svs efuse data
* @bdes: svs efuse data
@@ -410,69 +500,49 @@ struct svs_platform_data {
* @dcbdet: svs efuse data
* @dcmdet: svs efuse data
* @turn_pt: 2-line turn point tells which opp_volt calculated by high/low bank
- * @type: bank type to represent it is 2-line (high/low) bank or 1-line bank
+ * @vbin_turn_pt: voltage bin turn point helps know which svsb_volt should be overridden
*
- * Svs bank will generate suitalbe voltages by below general math equation
+ * Svs bank will generate suitable voltages by below general math equation
* and provide these voltages to opp voltage table.
*
* opp_volt[i] = (volt[i] * volt_step) + volt_base;
*/
struct svs_bank {
+ const struct svs_bank_pdata pdata;
struct device *dev;
struct device *opp_dev;
struct completion init_completion;
struct regulator *buck;
struct thermal_zone_device *tzd;
- struct mutex lock; /* lock to protect voltage update process */
- void (*set_freq_pct)(struct svs_platform *svsp);
- void (*get_volts)(struct svs_platform *svsp);
+ struct mutex lock;
+ int pm_runtime_enabled_count;
+ short int volt_od;
char *name;
- char *buck_name;
- char *tzone_name;
enum svsb_phase phase;
- s32 volt_od;
u32 reg_data[SVSB_PHASE_MAX][SVS_REG_MAX];
- u32 pm_runtime_enabled_count;
- u32 mode_support;
- u32 freq_base;
- u32 turn_freq_base;
- u32 vboot;
+ u8 mode_support;
u32 opp_dfreq[MAX_OPP_ENTRIES];
u32 opp_dvolt[MAX_OPP_ENTRIES];
u32 freq_pct[MAX_OPP_ENTRIES];
u32 volt[MAX_OPP_ENTRIES];
- u32 volt_step;
- u32 volt_base;
u32 volt_flags;
- u32 vmax;
- u32 vmin;
- u32 age_config;
- u32 age_voffset_in;
- u32 dc_config;
- u32 dc_voffset_in;
- u32 dvt_fixed;
- u32 vco;
- u32 chk_shift;
+ u32 freq_base;
+ u32 turn_pt;
+ u32 vbin_turn_pt;
u32 core_sel;
- u32 opp_count;
- u32 int_st;
- u32 sw_id;
- u32 cpu_id;
- u32 ctl0;
u32 temp;
- u32 tzone_htemp;
- u32 tzone_htemp_voffset;
- u32 tzone_ltemp;
- u32 tzone_ltemp_voffset;
- u32 bts;
- u32 mts;
- u32 bdes;
- u32 mdes;
- u32 mtdes;
- u32 dcbdet;
- u32 dcmdet;
- u32 turn_pt;
- u32 type;
+ u16 age_voffset_in;
+ u16 dc_voffset_in;
+ u8 dvt_fixed;
+ u8 vmax;
+ u8 vmin;
+ u16 bts;
+ u16 mts;
+ u16 bdes;
+ u16 mdes;
+ u8 mtdes;
+ u8 dcbdet;
+ u8 dcmdet;
};
static u32 percent(u32 numerator, u32 denominator)
@@ -495,10 +565,8 @@ static void svs_writel_relaxed(struct svs_platform *svsp, u32 val,
writel_relaxed(val, svsp->base + svsp->regs[rg_i]);
}
-static void svs_switch_bank(struct svs_platform *svsp)
+static void svs_switch_bank(struct svs_platform *svsp, struct svs_bank *svsb)
{
- struct svs_bank *svsb = svsp->pbank;
-
svs_writel_relaxed(svsp, svsb->core_sel, CORESEL);
}
@@ -516,10 +584,11 @@ static u32 svs_opp_volt_to_bank_volt(u32 opp_u_volt, u32 svsb_volt_step,
static int svs_sync_bank_volts_from_opp(struct svs_bank *svsb)
{
+ const struct svs_bank_pdata *bdata = &svsb->pdata;
struct dev_pm_opp *opp;
u32 i, opp_u_volt;
- for (i = 0; i < svsb->opp_count; i++) {
+ for (i = 0; i < bdata->opp_count; i++) {
opp = dev_pm_opp_find_freq_exact(svsb->opp_dev,
svsb->opp_dfreq[i],
true);
@@ -531,8 +600,8 @@ static int svs_sync_bank_volts_from_opp(struct svs_bank *svsb)
opp_u_volt = dev_pm_opp_get_voltage(opp);
svsb->volt[i] = svs_opp_volt_to_bank_volt(opp_u_volt,
- svsb->volt_step,
- svsb->volt_base);
+ bdata->volt_step,
+ bdata->volt_base);
dev_pm_opp_put(opp);
}
@@ -542,6 +611,7 @@ static int svs_sync_bank_volts_from_opp(struct svs_bank *svsb)
static int svs_adjust_pm_opp_volts(struct svs_bank *svsb)
{
int ret = -EPERM, tzone_temp = 0;
+ const struct svs_bank_pdata *bdata = &svsb->pdata;
u32 i, svsb_volt, opp_volt, temp_voffset = 0, opp_start, opp_stop;
mutex_lock(&svsb->lock);
@@ -550,36 +620,37 @@ static int svs_adjust_pm_opp_volts(struct svs_bank *svsb)
* 2-line bank updates its corresponding opp volts.
* 1-line bank updates all opp volts.
*/
- if (svsb->type == SVSB_HIGH) {
+ if (bdata->type == SVSB_TYPE_HIGH) {
opp_start = 0;
opp_stop = svsb->turn_pt;
- } else if (svsb->type == SVSB_LOW) {
+ } else if (bdata->type == SVSB_TYPE_LOW) {
opp_start = svsb->turn_pt;
- opp_stop = svsb->opp_count;
+ opp_stop = bdata->opp_count;
} else {
opp_start = 0;
- opp_stop = svsb->opp_count;
+ opp_stop = bdata->opp_count;
}
/* Get thermal effect */
- if (svsb->phase == SVSB_PHASE_MON) {
+ if (!IS_ERR_OR_NULL(svsb->tzd)) {
ret = thermal_zone_get_temp(svsb->tzd, &tzone_temp);
if (ret || (svsb->temp > SVSB_TEMP_UPPER_BOUND &&
svsb->temp < SVSB_TEMP_LOWER_BOUND)) {
dev_err(svsb->dev, "%s: %d (0x%x), run default volts\n",
- svsb->tzone_name, ret, svsb->temp);
+ bdata->tzone_name, ret, svsb->temp);
svsb->phase = SVSB_PHASE_ERROR;
}
- if (tzone_temp >= svsb->tzone_htemp)
- temp_voffset += svsb->tzone_htemp_voffset;
- else if (tzone_temp <= svsb->tzone_ltemp)
- temp_voffset += svsb->tzone_ltemp_voffset;
+ if (tzone_temp >= bdata->tzone_htemp)
+ temp_voffset += bdata->tzone_htemp_voffset;
+ else if (tzone_temp <= bdata->tzone_ltemp)
+ temp_voffset += bdata->tzone_ltemp_voffset;
/* 2-line bank update all opp volts when running mon mode */
- if (svsb->type == SVSB_HIGH || svsb->type == SVSB_LOW) {
+ if (svsb->phase == SVSB_PHASE_MON && (bdata->type == SVSB_TYPE_HIGH ||
+ bdata->type == SVSB_TYPE_LOW)) {
opp_start = 0;
- opp_stop = svsb->opp_count;
+ opp_stop = bdata->opp_count;
}
}
@@ -593,16 +664,11 @@ static int svs_adjust_pm_opp_volts(struct svs_bank *svsb)
/* do nothing */
goto unlock_mutex;
case SVSB_PHASE_INIT02:
- svsb_volt = max(svsb->volt[i], svsb->vmin);
- opp_volt = svs_bank_volt_to_opp_volt(svsb_volt,
- svsb->volt_step,
- svsb->volt_base);
- break;
case SVSB_PHASE_MON:
svsb_volt = max(svsb->volt[i] + temp_voffset, svsb->vmin);
opp_volt = svs_bank_volt_to_opp_volt(svsb_volt,
- svsb->volt_step,
- svsb->volt_base);
+ bdata->volt_step,
+ bdata->volt_base);
break;
default:
dev_err(svsb->dev, "unknown phase: %u\n", svsb->phase);
@@ -628,6 +694,25 @@ unlock_mutex:
return ret;
}
+static void svs_bank_disable_and_restore_default_volts(struct svs_platform *svsp,
+ struct svs_bank *svsb)
+{
+ unsigned long flags;
+
+ if (svsb->mode_support == SVSB_MODE_ALL_DISABLE)
+ return;
+
+ spin_lock_irqsave(&svs_lock, flags);
+ svs_switch_bank(svsp, svsb);
+ svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN);
+ svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS);
+ spin_unlock_irqrestore(&svs_lock, flags);
+
+ svsb->phase = SVSB_PHASE_ERROR;
+ svs_adjust_pm_opp_volts(svsb);
+}
+
+#ifdef CONFIG_DEBUG_FS
static int svs_dump_debug_show(struct seq_file *m, void *p)
{
struct svs_platform *svsp = (struct svs_platform *)m->private;
@@ -703,7 +788,6 @@ static ssize_t svs_enable_debug_write(struct file *filp,
{
struct svs_bank *svsb = file_inode(filp)->i_private;
struct svs_platform *svsp = dev_get_drvdata(svsb->dev);
- unsigned long flags;
int enabled, ret;
char *buf = NULL;
@@ -719,16 +803,8 @@ static ssize_t svs_enable_debug_write(struct file *filp,
return ret;
if (!enabled) {
- spin_lock_irqsave(&svs_lock, flags);
- svsp->pbank = svsb;
+ svs_bank_disable_and_restore_default_volts(svsp, svsb);
svsb->mode_support = SVSB_MODE_ALL_DISABLE;
- svs_switch_bank(svsp);
- svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN);
- svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS);
- spin_unlock_irqrestore(&svs_lock, flags);
-
- svsb->phase = SVSB_PHASE_ERROR;
- svs_adjust_pm_opp_volts(svsb);
}
kfree(buf);
@@ -747,13 +823,14 @@ static int svs_status_debug_show(struct seq_file *m, void *v)
ret = thermal_zone_get_temp(svsb->tzd, &tzone_temp);
if (ret)
- seq_printf(m, "%s: temperature ignore, turn_pt = %u\n",
- svsb->name, svsb->turn_pt);
+ seq_printf(m, "%s: temperature ignore, vbin_turn_pt = %u, turn_pt = %u\n",
+ svsb->name, svsb->vbin_turn_pt, svsb->turn_pt);
else
- seq_printf(m, "%s: temperature = %d, turn_pt = %u\n",
- svsb->name, tzone_temp, svsb->turn_pt);
+ seq_printf(m, "%s: temperature = %d, vbin_turn_pt = %u, turn_pt = %u\n",
+ svsb->name, tzone_temp, svsb->vbin_turn_pt,
+ svsb->turn_pt);
- for (i = 0; i < svsb->opp_count; i++) {
+ for (i = 0; i < svsb->pdata.opp_count; i++) {
opp = dev_pm_opp_find_freq_exact(svsb->opp_dev,
svsb->opp_dfreq[i], true);
if (IS_ERR(opp)) {
@@ -843,6 +920,7 @@ static int svs_create_debug_cmds(struct svs_platform *svsp)
return 0;
}
+#endif /* CONFIG_DEBUG_FS */
static u32 interpolate(u32 f0, u32 f1, u32 v0, u32 v1, u32 fx)
{
@@ -857,12 +935,12 @@ static u32 interpolate(u32 f0, u32 f1, u32 v0, u32 v1, u32 fx)
return DIV_ROUND_UP(vx, 100);
}
-static void svs_get_bank_volts_v3(struct svs_platform *svsp)
+static void svs_get_bank_volts_v3(struct svs_platform *svsp, struct svs_bank *svsb)
{
- struct svs_bank *svsb = svsp->pbank;
+ const struct svs_bank_pdata *bdata = &svsb->pdata;
u32 i, j, *vop, vop74, vop30, turn_pt = svsb->turn_pt;
u32 b_sft, shift_byte = 0, opp_start = 0, opp_stop = 0;
- u32 middle_index = (svsb->opp_count / 2);
+ u32 middle_index = (bdata->opp_count / 2);
if (svsb->phase == SVSB_PHASE_MON &&
svsb->volt_flags & SVSB_MON_VOLT_IGNORE)
@@ -873,7 +951,7 @@ static void svs_get_bank_volts_v3(struct svs_platform *svsp)
/* Target is to set svsb->volt[] by algorithm */
if (turn_pt < middle_index) {
- if (svsb->type == SVSB_HIGH) {
+ if (bdata->type == SVSB_TYPE_HIGH) {
/* volt[0] ~ volt[turn_pt - 1] */
for (i = 0; i < turn_pt; i++) {
b_sft = BITS8 * (shift_byte % REG_BYTES);
@@ -882,12 +960,12 @@ static void svs_get_bank_volts_v3(struct svs_platform *svsp)
svsb->volt[i] = (*vop >> b_sft) & GENMASK(7, 0);
shift_byte++;
}
- } else if (svsb->type == SVSB_LOW) {
+ } else if (bdata->type == SVSB_TYPE_LOW) {
/* volt[turn_pt] + volt[j] ~ volt[opp_count - 1] */
- j = svsb->opp_count - 7;
+ j = bdata->opp_count - 7;
svsb->volt[turn_pt] = FIELD_GET(SVSB_VOPS_FLD_VOP0_4, vop30);
shift_byte++;
- for (i = j; i < svsb->opp_count; i++) {
+ for (i = j; i < bdata->opp_count; i++) {
b_sft = BITS8 * (shift_byte % REG_BYTES);
vop = (shift_byte < REG_BYTES) ? &vop30 :
&vop74;
@@ -904,7 +982,7 @@ static void svs_get_bank_volts_v3(struct svs_platform *svsp)
svsb->freq_pct[i]);
}
} else {
- if (svsb->type == SVSB_HIGH) {
+ if (bdata->type == SVSB_TYPE_HIGH) {
/* volt[0] + volt[j] ~ volt[turn_pt - 1] */
j = turn_pt - 7;
svsb->volt[0] = FIELD_GET(SVSB_VOPS_FLD_VOP0_4, vop30);
@@ -924,9 +1002,9 @@ static void svs_get_bank_volts_v3(struct svs_platform *svsp)
svsb->volt[0],
svsb->volt[j],
svsb->freq_pct[i]);
- } else if (svsb->type == SVSB_LOW) {
+ } else if (bdata->type == SVSB_TYPE_LOW) {
/* volt[turn_pt] ~ volt[opp_count - 1] */
- for (i = turn_pt; i < svsb->opp_count; i++) {
+ for (i = turn_pt; i < bdata->opp_count; i++) {
b_sft = BITS8 * (shift_byte % REG_BYTES);
vop = (shift_byte < REG_BYTES) ? &vop30 :
&vop74;
@@ -936,28 +1014,51 @@ static void svs_get_bank_volts_v3(struct svs_platform *svsp)
}
}
- if (svsb->type == SVSB_HIGH) {
+ if (bdata->type == SVSB_TYPE_HIGH) {
opp_start = 0;
opp_stop = svsb->turn_pt;
- } else if (svsb->type == SVSB_LOW) {
+ } else if (bdata->type == SVSB_TYPE_LOW) {
opp_start = svsb->turn_pt;
- opp_stop = svsb->opp_count;
+ opp_stop = bdata->opp_count;
}
for (i = opp_start; i < opp_stop; i++)
if (svsb->volt_flags & SVSB_REMOVE_DVTFIXED_VOLT)
svsb->volt[i] -= svsb->dvt_fixed;
+
+ /* For voltage bin support */
+ if (svsb->opp_dfreq[0] > svsb->freq_base) {
+ svsb->volt[0] = svs_opp_volt_to_bank_volt(svsb->opp_dvolt[0],
+ bdata->volt_step,
+ bdata->volt_base);
+
+ /* Find voltage bin turn point */
+ for (i = 0; i < bdata->opp_count; i++) {
+ if (svsb->opp_dfreq[i] <= svsb->freq_base) {
+ svsb->vbin_turn_pt = i;
+ break;
+ }
+ }
+
+ /* Override svs bank voltages */
+ for (i = 1; i < svsb->vbin_turn_pt; i++)
+ svsb->volt[i] = interpolate(svsb->freq_pct[0],
+ svsb->freq_pct[svsb->vbin_turn_pt],
+ svsb->volt[0],
+ svsb->volt[svsb->vbin_turn_pt],
+ svsb->freq_pct[i]);
+ }
}
-static void svs_set_bank_freq_pct_v3(struct svs_platform *svsp)
+static void svs_set_bank_freq_pct_v3(struct svs_platform *svsp, struct svs_bank *svsb)
{
- struct svs_bank *svsb = svsp->pbank;
+ const struct svs_bank_pdata *bdata = &svsb->pdata;
u32 i, j, *freq_pct, freq_pct74 = 0, freq_pct30 = 0;
u32 b_sft, shift_byte = 0, turn_pt;
- u32 middle_index = (svsb->opp_count / 2);
+ u32 middle_index = (bdata->opp_count / 2);
- for (i = 0; i < svsb->opp_count; i++) {
- if (svsb->opp_dfreq[i] <= svsb->turn_freq_base) {
+ for (i = 0; i < bdata->opp_count; i++) {
+ if (svsb->opp_dfreq[i] <= bdata->turn_freq_base) {
svsb->turn_pt = i;
break;
}
@@ -967,11 +1068,11 @@ static void svs_set_bank_freq_pct_v3(struct svs_platform *svsp)
/* Target is to fill out freq_pct74 / freq_pct30 by algorithm */
if (turn_pt < middle_index) {
- if (svsb->type == SVSB_HIGH) {
+ if (bdata->type == SVSB_TYPE_HIGH) {
/*
* If we don't handle this situation,
- * SVSB_HIGH's FREQPCT74 / FREQPCT30 would keep "0"
- * and this leads SVSB_LOW to work abnormally.
+ * SVSB_TYPE_HIGH's FREQPCT74 / FREQPCT30 would keep "0"
+ * and this leads SVSB_TYPE_LOW to work abnormally.
*/
if (turn_pt == 0)
freq_pct30 = svsb->freq_pct[0];
@@ -984,15 +1085,15 @@ static void svs_set_bank_freq_pct_v3(struct svs_platform *svsp)
*freq_pct |= (svsb->freq_pct[i] << b_sft);
shift_byte++;
}
- } else if (svsb->type == SVSB_LOW) {
+ } else if (bdata->type == SVSB_TYPE_LOW) {
/*
* freq_pct[turn_pt] +
* freq_pct[opp_count - 7] ~ freq_pct[opp_count -1]
*/
freq_pct30 = svsb->freq_pct[turn_pt];
shift_byte++;
- j = svsb->opp_count - 7;
- for (i = j; i < svsb->opp_count; i++) {
+ j = bdata->opp_count - 7;
+ for (i = j; i < bdata->opp_count; i++) {
b_sft = BITS8 * (shift_byte % REG_BYTES);
freq_pct = (shift_byte < REG_BYTES) ?
&freq_pct30 : &freq_pct74;
@@ -1001,7 +1102,7 @@ static void svs_set_bank_freq_pct_v3(struct svs_platform *svsp)
}
}
} else {
- if (svsb->type == SVSB_HIGH) {
+ if (bdata->type == SVSB_TYPE_HIGH) {
/*
* freq_pct[0] +
* freq_pct[turn_pt - 7] ~ freq_pct[turn_pt - 1]
@@ -1016,9 +1117,9 @@ static void svs_set_bank_freq_pct_v3(struct svs_platform *svsp)
*freq_pct |= (svsb->freq_pct[i] << b_sft);
shift_byte++;
}
- } else if (svsb->type == SVSB_LOW) {
+ } else if (bdata->type == SVSB_TYPE_LOW) {
/* freq_pct[turn_pt] ~ freq_pct[opp_count - 1] */
- for (i = turn_pt; i < svsb->opp_count; i++) {
+ for (i = turn_pt; i < bdata->opp_count; i++) {
b_sft = BITS8 * (shift_byte % REG_BYTES);
freq_pct = (shift_byte < REG_BYTES) ?
&freq_pct30 : &freq_pct74;
@@ -1032,9 +1133,9 @@ static void svs_set_bank_freq_pct_v3(struct svs_platform *svsp)
svs_writel_relaxed(svsp, freq_pct30, FREQPCT30);
}
-static void svs_get_bank_volts_v2(struct svs_platform *svsp)
+static void svs_get_bank_volts_v2(struct svs_platform *svsp, struct svs_bank *svsb)
{
- struct svs_bank *svsb = svsp->pbank;
+ const struct svs_bank_pdata *bdata = &svsb->pdata;
u32 temp, i;
temp = svs_readl_relaxed(svsp, VOP74);
@@ -1062,13 +1163,35 @@ static void svs_get_bank_volts_v2(struct svs_platform *svsp)
svsb->volt[14],
svsb->freq_pct[15]);
- for (i = 0; i < svsb->opp_count; i++)
+ for (i = 0; i < bdata->opp_count; i++)
svsb->volt[i] += svsb->volt_od;
+
+ /* For voltage bin support */
+ if (svsb->opp_dfreq[0] > svsb->freq_base) {
+ svsb->volt[0] = svs_opp_volt_to_bank_volt(svsb->opp_dvolt[0],
+ bdata->volt_step,
+ bdata->volt_base);
+
+ /* Find voltage bin turn point */
+ for (i = 0; i < bdata->opp_count; i++) {
+ if (svsb->opp_dfreq[i] <= svsb->freq_base) {
+ svsb->vbin_turn_pt = i;
+ break;
+ }
+ }
+
+ /* Override svs bank voltages */
+ for (i = 1; i < svsb->vbin_turn_pt; i++)
+ svsb->volt[i] = interpolate(svsb->freq_pct[0],
+ svsb->freq_pct[svsb->vbin_turn_pt],
+ svsb->volt[0],
+ svsb->volt[svsb->vbin_turn_pt],
+ svsb->freq_pct[i]);
+ }
}
-static void svs_set_bank_freq_pct_v2(struct svs_platform *svsp)
+static void svs_set_bank_freq_pct_v2(struct svs_platform *svsp, struct svs_bank *svsb)
{
- struct svs_bank *svsb = svsp->pbank;
u32 freqpct74_val, freqpct30_val;
freqpct74_val = FIELD_PREP(SVSB_FREQPCTS_FLD_PCT0_4, svsb->freq_pct[8]) |
@@ -1086,18 +1209,20 @@ static void svs_set_bank_freq_pct_v2(struct svs_platform *svsp)
}
static void svs_set_bank_phase(struct svs_platform *svsp,
+ unsigned int bank_idx,
enum svsb_phase target_phase)
{
- struct svs_bank *svsb = svsp->pbank;
+ struct svs_bank *svsb = &svsp->banks[bank_idx];
+ const struct svs_bank_pdata *bdata = &svsb->pdata;
u32 des_char, temp_char, det_char, limit_vals, init2vals, ts_calcs;
- svs_switch_bank(svsp);
+ svs_switch_bank(svsp, svsb);
des_char = FIELD_PREP(SVSB_DESCHAR_FLD_BDES, svsb->bdes) |
FIELD_PREP(SVSB_DESCHAR_FLD_MDES, svsb->mdes);
svs_writel_relaxed(svsp, des_char, DESCHAR);
- temp_char = FIELD_PREP(SVSB_TEMPCHAR_FLD_VCO, svsb->vco) |
+ temp_char = FIELD_PREP(SVSB_TEMPCHAR_FLD_VCO, bdata->vco) |
FIELD_PREP(SVSB_TEMPCHAR_FLD_MTDES, svsb->mtdes) |
FIELD_PREP(SVSB_TEMPCHAR_FLD_DVT_FIXED, svsb->dvt_fixed);
svs_writel_relaxed(svsp, temp_char, TEMPCHAR);
@@ -1106,11 +1231,11 @@ static void svs_set_bank_phase(struct svs_platform *svsp,
FIELD_PREP(SVSB_DETCHAR_FLD_DCMDET, svsb->dcmdet);
svs_writel_relaxed(svsp, det_char, DETCHAR);
- svs_writel_relaxed(svsp, svsb->dc_config, DCCONFIG);
- svs_writel_relaxed(svsp, svsb->age_config, AGECONFIG);
+ svs_writel_relaxed(svsp, bdata->dc_config, DCCONFIG);
+ svs_writel_relaxed(svsp, bdata->age_config, AGECONFIG);
svs_writel_relaxed(svsp, SVSB_RUNCONFIG_DEFAULT, RUNCONFIG);
- svsb->set_freq_pct(svsp);
+ bdata->set_freq_pct(svsp, svsb);
limit_vals = FIELD_PREP(SVSB_LIMITVALS_FLD_DTLO, SVSB_VAL_DTLO) |
FIELD_PREP(SVSB_LIMITVALS_FLD_DTHI, SVSB_VAL_DTHI) |
@@ -1120,13 +1245,13 @@ static void svs_set_bank_phase(struct svs_platform *svsp,
svs_writel_relaxed(svsp, SVSB_DET_WINDOW, DETWINDOW);
svs_writel_relaxed(svsp, SVSB_DET_MAX, CONFIG);
- svs_writel_relaxed(svsp, svsb->chk_shift, CHKSHIFT);
- svs_writel_relaxed(svsp, svsb->ctl0, CTL0);
+ svs_writel_relaxed(svsp, bdata->chk_shift, CHKSHIFT);
+ svs_writel_relaxed(svsp, bdata->ctl0, CTL0);
svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS);
switch (target_phase) {
case SVSB_PHASE_INIT01:
- svs_writel_relaxed(svsp, svsb->vboot, VBOOT);
+ svs_writel_relaxed(svsp, bdata->vboot, VBOOT);
svs_writel_relaxed(svsp, SVSB_INTEN_INIT0x, INTEN);
svs_writel_relaxed(svsp, SVSB_PTPEN_INIT01, SVSEN);
break;
@@ -1152,18 +1277,20 @@ static void svs_set_bank_phase(struct svs_platform *svsp,
}
static inline void svs_save_bank_register_data(struct svs_platform *svsp,
+ unsigned short bank_idx,
enum svsb_phase phase)
{
- struct svs_bank *svsb = svsp->pbank;
+ struct svs_bank *svsb = &svsp->banks[bank_idx];
enum svs_reg_index rg_i;
for (rg_i = DESCHAR; rg_i < SVS_REG_MAX; rg_i++)
svsb->reg_data[phase][rg_i] = svs_readl_relaxed(svsp, rg_i);
}
-static inline void svs_error_isr_handler(struct svs_platform *svsp)
+static inline void svs_error_isr_handler(struct svs_platform *svsp,
+ unsigned short bank_idx)
{
- struct svs_bank *svsb = svsp->pbank;
+ struct svs_bank *svsb = &svsp->banks[bank_idx];
dev_err(svsb->dev, "%s: CORESEL = 0x%08x\n",
__func__, svs_readl_relaxed(svsp, CORESEL));
@@ -1175,27 +1302,29 @@ static inline void svs_error_isr_handler(struct svs_platform *svsp)
svs_readl_relaxed(svsp, SMSTATE1));
dev_err(svsb->dev, "TEMP = 0x%08x\n", svs_readl_relaxed(svsp, TEMP));
- svs_save_bank_register_data(svsp, SVSB_PHASE_ERROR);
+ svs_save_bank_register_data(svsp, bank_idx, SVSB_PHASE_ERROR);
svsb->phase = SVSB_PHASE_ERROR;
svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN);
svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS);
}
-static inline void svs_init01_isr_handler(struct svs_platform *svsp)
+static inline void svs_init01_isr_handler(struct svs_platform *svsp,
+ unsigned short bank_idx)
{
- struct svs_bank *svsb = svsp->pbank;
+ struct svs_bank *svsb = &svsp->banks[bank_idx];
+ u32 val;
dev_info(svsb->dev, "%s: VDN74~30:0x%08x~0x%08x, DC:0x%08x\n",
__func__, svs_readl_relaxed(svsp, VDESIGN74),
svs_readl_relaxed(svsp, VDESIGN30),
svs_readl_relaxed(svsp, DCVALUES));
- svs_save_bank_register_data(svsp, SVSB_PHASE_INIT01);
+ svs_save_bank_register_data(svsp, bank_idx, SVSB_PHASE_INIT01);
svsb->phase = SVSB_PHASE_INIT01;
- svsb->dc_voffset_in = ~(svs_readl_relaxed(svsp, DCVALUES) &
- GENMASK(15, 0)) + 1;
+ val = ~(svs_readl_relaxed(svsp, DCVALUES) & GENMASK(15, 0)) + 1;
+ svsb->dc_voffset_in = val & GENMASK(15, 0);
if (svsb->volt_flags & SVSB_INIT01_VOLT_IGNORE ||
(svsb->dc_voffset_in & SVSB_DC_SIGNED_BIT &&
svsb->volt_flags & SVSB_INIT01_VOLT_INC_ONLY))
@@ -1209,32 +1338,36 @@ static inline void svs_init01_isr_handler(struct svs_platform *svsp)
svsb->core_sel &= ~SVSB_DET_CLK_EN;
}
-static inline void svs_init02_isr_handler(struct svs_platform *svsp)
+static inline void svs_init02_isr_handler(struct svs_platform *svsp,
+ unsigned short bank_idx)
{
- struct svs_bank *svsb = svsp->pbank;
+ struct svs_bank *svsb = &svsp->banks[bank_idx];
+ const struct svs_bank_pdata *bdata = &svsb->pdata;
dev_info(svsb->dev, "%s: VOP74~30:0x%08x~0x%08x, DC:0x%08x\n",
__func__, svs_readl_relaxed(svsp, VOP74),
svs_readl_relaxed(svsp, VOP30),
svs_readl_relaxed(svsp, DCVALUES));
- svs_save_bank_register_data(svsp, SVSB_PHASE_INIT02);
+ svs_save_bank_register_data(svsp, bank_idx, SVSB_PHASE_INIT02);
svsb->phase = SVSB_PHASE_INIT02;
- svsb->get_volts(svsp);
+ bdata->get_volts(svsp, svsb);
svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN);
svs_writel_relaxed(svsp, SVSB_INTSTS_F0_COMPLETE, INTSTS);
}
-static inline void svs_mon_mode_isr_handler(struct svs_platform *svsp)
+static inline void svs_mon_mode_isr_handler(struct svs_platform *svsp,
+ unsigned short bank_idx)
{
- struct svs_bank *svsb = svsp->pbank;
+ struct svs_bank *svsb = &svsp->banks[bank_idx];
+ const struct svs_bank_pdata *bdata = &svsb->pdata;
- svs_save_bank_register_data(svsp, SVSB_PHASE_MON);
+ svs_save_bank_register_data(svsp, bank_idx, SVSB_PHASE_MON);
svsb->phase = SVSB_PHASE_MON;
- svsb->get_volts(svsp);
+ bdata->get_volts(svsp, svsb);
svsb->temp = svs_readl_relaxed(svsp, TEMP) & GENMASK(7, 0);
svs_writel_relaxed(svsp, SVSB_INTSTS_FLD_MONVOP, INTSTS);
@@ -1243,37 +1376,38 @@ static inline void svs_mon_mode_isr_handler(struct svs_platform *svsp)
static irqreturn_t svs_isr(int irq, void *data)
{
struct svs_platform *svsp = data;
+ const struct svs_bank_pdata *bdata;
struct svs_bank *svsb = NULL;
unsigned long flags;
u32 idx, int_sts, svs_en;
for (idx = 0; idx < svsp->bank_max; idx++) {
svsb = &svsp->banks[idx];
+ bdata = &svsb->pdata;
WARN(!svsb, "%s: svsb(%s) is null", __func__, svsb->name);
spin_lock_irqsave(&svs_lock, flags);
- svsp->pbank = svsb;
/* Find out which svs bank fires interrupt */
- if (svsb->int_st & svs_readl_relaxed(svsp, INTST)) {
+ if (bdata->int_st & svs_readl_relaxed(svsp, INTST)) {
spin_unlock_irqrestore(&svs_lock, flags);
continue;
}
- svs_switch_bank(svsp);
+ svs_switch_bank(svsp, svsb);
int_sts = svs_readl_relaxed(svsp, INTSTS);
svs_en = svs_readl_relaxed(svsp, SVSEN);
if (int_sts == SVSB_INTSTS_F0_COMPLETE &&
svs_en == SVSB_PTPEN_INIT01)
- svs_init01_isr_handler(svsp);
+ svs_init01_isr_handler(svsp, idx);
else if (int_sts == SVSB_INTSTS_F0_COMPLETE &&
svs_en == SVSB_PTPEN_INIT02)
- svs_init02_isr_handler(svsp);
+ svs_init02_isr_handler(svsp, idx);
else if (int_sts & SVSB_INTSTS_FLD_MONVOP)
- svs_mon_mode_isr_handler(svsp);
+ svs_mon_mode_isr_handler(svsp, idx);
else
- svs_error_isr_handler(svsp);
+ svs_error_isr_handler(svsp, idx);
spin_unlock_irqrestore(&svs_lock, flags);
break;
@@ -1288,20 +1422,35 @@ static irqreturn_t svs_isr(int irq, void *data)
return IRQ_HANDLED;
}
+static bool svs_mode_available(struct svs_platform *svsp, u8 mode)
+{
+ int i;
+
+ for (i = 0; i < svsp->bank_max; i++)
+ if (svsp->banks[i].mode_support & mode)
+ return true;
+ return false;
+}
+
static int svs_init01(struct svs_platform *svsp)
{
+ const struct svs_bank_pdata *bdata;
struct svs_bank *svsb;
unsigned long flags, time_left;
bool search_done;
int ret = 0, r;
u32 opp_freq, opp_vboot, buck_volt, idx, i;
+ if (!svs_mode_available(svsp, SVSB_MODE_INIT01))
+ return 0;
+
/* Keep CPUs' core power on for svs_init01 initialization */
cpuidle_pause_and_lock();
/* Svs bank init01 preparation - power enable */
for (idx = 0; idx < svsp->bank_max; idx++) {
svsb = &svsp->banks[idx];
+ bdata = &svsb->pdata;
if (!(svsb->mode_support & SVSB_MODE_INIT01))
continue;
@@ -1309,7 +1458,7 @@ static int svs_init01(struct svs_platform *svsp)
ret = regulator_enable(svsb->buck);
if (ret) {
dev_err(svsb->dev, "%s enable fail: %d\n",
- svsb->buck_name, ret);
+ bdata->buck_name, ret);
goto svs_init01_resume_cpuidle;
}
@@ -1324,7 +1473,7 @@ static int svs_init01(struct svs_platform *svsp)
svsb->pm_runtime_enabled_count++;
}
- ret = pm_runtime_get_sync(svsb->opp_dev);
+ ret = pm_runtime_resume_and_get(svsb->opp_dev);
if (ret < 0) {
dev_err(svsb->dev, "mtcmos on fail: %d\n", ret);
goto svs_init01_resume_cpuidle;
@@ -1339,6 +1488,7 @@ static int svs_init01(struct svs_platform *svsp)
*/
for (idx = 0; idx < svsp->bank_max; idx++) {
svsb = &svsp->banks[idx];
+ bdata = &svsb->pdata;
if (!(svsb->mode_support & SVSB_MODE_INIT01))
continue;
@@ -1348,11 +1498,11 @@ static int svs_init01(struct svs_platform *svsp)
* fix to that freq until svs_init01 is done.
*/
search_done = false;
- opp_vboot = svs_bank_volt_to_opp_volt(svsb->vboot,
- svsb->volt_step,
- svsb->volt_base);
+ opp_vboot = svs_bank_volt_to_opp_volt(bdata->vboot,
+ bdata->volt_step,
+ bdata->volt_base);
- for (i = 0; i < svsb->opp_count; i++) {
+ for (i = 0; i < bdata->opp_count; i++) {
opp_freq = svsb->opp_dfreq[i];
if (!search_done && svsb->opp_dvolt[i] <= opp_vboot) {
ret = dev_pm_opp_adjust_voltage(svsb->opp_dev,
@@ -1384,13 +1534,14 @@ static int svs_init01(struct svs_platform *svsp)
/* Svs bank init01 begins */
for (idx = 0; idx < svsp->bank_max; idx++) {
svsb = &svsp->banks[idx];
+ bdata = &svsb->pdata;
if (!(svsb->mode_support & SVSB_MODE_INIT01))
continue;
- opp_vboot = svs_bank_volt_to_opp_volt(svsb->vboot,
- svsb->volt_step,
- svsb->volt_base);
+ opp_vboot = svs_bank_volt_to_opp_volt(bdata->vboot,
+ bdata->volt_step,
+ bdata->volt_base);
buck_volt = regulator_get_voltage(svsb->buck);
if (buck_volt != opp_vboot) {
@@ -1402,8 +1553,7 @@ static int svs_init01(struct svs_platform *svsp)
}
spin_lock_irqsave(&svs_lock, flags);
- svsp->pbank = svsb;
- svs_set_bank_phase(svsp, SVSB_PHASE_INIT01);
+ svs_set_bank_phase(svsp, idx, SVSB_PHASE_INIT01);
spin_unlock_irqrestore(&svs_lock, flags);
time_left = wait_for_completion_timeout(&svsb->init_completion,
@@ -1418,11 +1568,12 @@ static int svs_init01(struct svs_platform *svsp)
svs_init01_finish:
for (idx = 0; idx < svsp->bank_max; idx++) {
svsb = &svsp->banks[idx];
+ bdata = &svsb->pdata;
if (!(svsb->mode_support & SVSB_MODE_INIT01))
continue;
- for (i = 0; i < svsb->opp_count; i++) {
+ for (i = 0; i < bdata->opp_count; i++) {
r = dev_pm_opp_enable(svsb->opp_dev,
svsb->opp_dfreq[i]);
if (r)
@@ -1448,7 +1599,7 @@ svs_init01_finish:
r = regulator_disable(svsb->buck);
if (r)
dev_err(svsb->dev, "%s disable fail: %d\n",
- svsb->buck_name, r);
+ bdata->buck_name, r);
}
svs_init01_resume_cpuidle:
@@ -1459,10 +1610,15 @@ svs_init01_resume_cpuidle:
static int svs_init02(struct svs_platform *svsp)
{
+ const struct svs_bank_pdata *bdata;
struct svs_bank *svsb;
unsigned long flags, time_left;
+ int ret;
u32 idx;
+ if (!svs_mode_available(svsp, SVSB_MODE_INIT02))
+ return 0;
+
for (idx = 0; idx < svsp->bank_max; idx++) {
svsb = &svsp->banks[idx];
@@ -1471,15 +1627,15 @@ static int svs_init02(struct svs_platform *svsp)
reinit_completion(&svsb->init_completion);
spin_lock_irqsave(&svs_lock, flags);
- svsp->pbank = svsb;
- svs_set_bank_phase(svsp, SVSB_PHASE_INIT02);
+ svs_set_bank_phase(svsp, idx, SVSB_PHASE_INIT02);
spin_unlock_irqrestore(&svs_lock, flags);
time_left = wait_for_completion_timeout(&svsb->init_completion,
msecs_to_jiffies(5000));
if (!time_left) {
dev_err(svsb->dev, "init02 completion timeout\n");
- return -EBUSY;
+ ret = -EBUSY;
+ goto out_of_init02;
}
}
@@ -1490,19 +1646,29 @@ static int svs_init02(struct svs_platform *svsp)
*/
for (idx = 0; idx < svsp->bank_max; idx++) {
svsb = &svsp->banks[idx];
+ bdata = &svsb->pdata;
if (!(svsb->mode_support & SVSB_MODE_INIT02))
continue;
- if (svsb->type == SVSB_HIGH || svsb->type == SVSB_LOW) {
+ if (bdata->type == SVSB_TYPE_HIGH || bdata->type == SVSB_TYPE_LOW) {
if (svs_sync_bank_volts_from_opp(svsb)) {
dev_err(svsb->dev, "sync volt fail\n");
- return -EPERM;
+ ret = -EPERM;
+ goto out_of_init02;
}
}
}
return 0;
+
+out_of_init02:
+ for (idx = 0; idx < svsp->bank_max; idx++) {
+ svsb = &svsp->banks[idx];
+ svs_bank_disable_and_restore_default_volts(svsp, svsb);
+ }
+
+ return ret;
}
static void svs_mon_mode(struct svs_platform *svsp)
@@ -1518,8 +1684,7 @@ static void svs_mon_mode(struct svs_platform *svsp)
continue;
spin_lock_irqsave(&svs_lock, flags);
- svsp->pbank = svsb;
- svs_set_bank_phase(svsp, SVSB_PHASE_MON);
+ svs_set_bank_phase(svsp, idx, SVSB_PHASE_MON);
spin_unlock_irqrestore(&svs_lock, flags);
}
}
@@ -1544,24 +1709,13 @@ static int svs_start(struct svs_platform *svsp)
static int svs_suspend(struct device *dev)
{
struct svs_platform *svsp = dev_get_drvdata(dev);
- struct svs_bank *svsb;
- unsigned long flags;
int ret;
u32 idx;
for (idx = 0; idx < svsp->bank_max; idx++) {
- svsb = &svsp->banks[idx];
+ struct svs_bank *svsb = &svsp->banks[idx];
- /* This might wait for svs_isr() process */
- spin_lock_irqsave(&svs_lock, flags);
- svsp->pbank = svsb;
- svs_switch_bank(svsp);
- svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN);
- svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS);
- spin_unlock_irqrestore(&svs_lock, flags);
-
- svsb->phase = SVSB_PHASE_ERROR;
- svs_adjust_pm_opp_volts(svsb);
+ svs_bank_disable_and_restore_default_volts(svsp, svsb);
}
ret = reset_control_assert(svsp->rst);
@@ -1594,12 +1748,16 @@ static int svs_resume(struct device *dev)
ret = svs_init02(svsp);
if (ret)
- goto out_of_resume;
+ goto svs_resume_reset_assert;
svs_mon_mode(svsp);
return 0;
+svs_resume_reset_assert:
+ dev_err(svsp->dev, "assert reset: %d\n",
+ reset_control_assert(svsp->rst));
+
out_of_resume:
clk_disable_unprepare(svsp->main_clk);
return ret;
@@ -1607,8 +1765,10 @@ out_of_resume:
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;
@@ -1617,35 +1777,23 @@ static int svs_bank_resource_setup(struct svs_platform *svsp)
for (idx = 0; idx < svsp->bank_max; idx++) {
svsb = &svsp->banks[idx];
+ bdata = &svsb->pdata;
- switch (svsb->sw_id) {
- case SVSB_CPU_LITTLE:
- svsb->name = "SVSB_CPU_LITTLE";
- break;
- case SVSB_CPU_BIG:
- svsb->name = "SVSB_CPU_BIG";
- break;
- case SVSB_CCI:
- svsb->name = "SVSB_CCI";
- break;
- case SVSB_GPU:
- if (svsb->type == SVSB_HIGH)
- svsb->name = "SVSB_GPU_HIGH";
- else if (svsb->type == SVSB_LOW)
- svsb->name = "SVSB_GPU_LOW";
- else
- svsb->name = "SVSB_GPU";
- break;
- default:
- dev_err(svsb->dev, "unknown sw_id: %u\n", svsb->sw_id);
+ if (bdata->sw_id >= SVSB_SWID_MAX || bdata->type >= SVSB_TYPE_MAX) {
+ dev_err(svsb->dev, "unknown bank sw_id or type\n");
return -EINVAL;
}
- svsb->dev = devm_kzalloc(svsp->dev, sizeof(*svsb->dev),
- GFP_KERNEL);
+ svsb->dev = devm_kzalloc(svsp->dev, sizeof(*svsb->dev), GFP_KERNEL);
if (!svsb->dev)
return -ENOMEM;
+ svsb->name = devm_kasprintf(svsp->dev, GFP_KERNEL, "%s%s",
+ svs_swid_names[bdata->sw_id],
+ svs_type_names[bdata->type]);
+ if (!svsb->name)
+ return -ENOMEM;
+
ret = dev_set_name(svsb->dev, "%s", svsb->name);
if (ret)
return ret;
@@ -1663,32 +1811,34 @@ static int svs_bank_resource_setup(struct svs_platform *svsp)
if (svsb->mode_support & SVSB_MODE_INIT01) {
svsb->buck = devm_regulator_get_optional(svsb->opp_dev,
- svsb->buck_name);
+ bdata->buck_name);
if (IS_ERR(svsb->buck)) {
dev_err(svsb->dev, "cannot get \"%s-supply\"\n",
- svsb->buck_name);
+ bdata->buck_name);
return PTR_ERR(svsb->buck);
}
}
- if (svsb->mode_support & SVSB_MODE_MON) {
- svsb->tzd = thermal_zone_get_zone_by_name(svsb->tzone_name);
+ if (!IS_ERR_OR_NULL(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",
- svsb->tzone_name);
+ tz_name_buf);
return PTR_ERR(svsb->tzd);
}
}
count = dev_pm_opp_get_opp_count(svsb->opp_dev);
- if (svsb->opp_count != count) {
+ if (bdata->opp_count != count) {
dev_err(svsb->dev,
"opp_count not \"%u\" but get \"%d\"?\n",
- svsb->opp_count, count);
+ bdata->opp_count, count);
return count;
}
- for (i = 0, freq = U32_MAX; i < svsb->opp_count; i++, freq--) {
+ for (i = 0, freq = ULONG_MAX; i < bdata->opp_count; i++, freq--) {
opp = dev_pm_opp_find_freq_floor(svsb->opp_dev, &freq);
if (IS_ERR(opp)) {
dev_err(svsb->dev, "cannot find freq = %ld\n",
@@ -1707,103 +1857,116 @@ static int svs_bank_resource_setup(struct svs_platform *svsp)
return 0;
}
-static int svs_thermal_efuse_get_data(struct svs_platform *svsp)
+static int svs_get_efuse_data(struct svs_platform *svsp,
+ const char *nvmem_cell_name,
+ u32 **svsp_efuse, size_t *svsp_efuse_max)
{
struct nvmem_cell *cell;
- /* Thermal efuse parsing */
- cell = nvmem_cell_get(svsp->dev, "t-calibration-data");
- if (IS_ERR_OR_NULL(cell)) {
- dev_err(svsp->dev, "no \"t-calibration-data\"? %ld\n", PTR_ERR(cell));
+ cell = nvmem_cell_get(svsp->dev, nvmem_cell_name);
+ if (IS_ERR(cell)) {
+ dev_err(svsp->dev, "no \"%s\"? %ld\n",
+ nvmem_cell_name, PTR_ERR(cell));
return PTR_ERR(cell);
}
- svsp->tefuse = nvmem_cell_read(cell, &svsp->tefuse_max);
- if (IS_ERR(svsp->tefuse)) {
- dev_err(svsp->dev, "cannot read thermal efuse: %ld\n",
- PTR_ERR(svsp->tefuse));
+ *svsp_efuse = nvmem_cell_read(cell, svsp_efuse_max);
+ if (IS_ERR(*svsp_efuse)) {
nvmem_cell_put(cell);
- return PTR_ERR(svsp->tefuse);
+ return PTR_ERR(*svsp_efuse);
}
- svsp->tefuse_max /= sizeof(u32);
+ *svsp_efuse_max /= sizeof(u32);
nvmem_cell_put(cell);
return 0;
}
-static bool svs_mt8192_efuse_parsing(struct svs_platform *svsp)
+static u32 svs_get_fuse_val(u32 *fuse_array, const struct svs_fusemap *fmap, u8 nbits)
{
- struct svs_bank *svsb;
- u32 idx, i, vmin, golden_temp;
- int ret;
+ u32 val;
- for (i = 0; i < svsp->efuse_max; i++)
+ if (fmap->index < 0)
+ return FUSE_DATA_NOT_VALID;
+
+ val = fuse_array[fmap->index] >> fmap->ofst;
+ val &= GENMASK(nbits - 1, 0);
+
+ return val;
+}
+
+static bool svs_is_available(struct svs_platform *svsp)
+{
+ int i, num_populated = 0;
+
+ /* If at least two fuse arrays are populated, SVS is calibrated */
+ for (i = 0; i < svsp->efuse_max; i++) {
if (svsp->efuse[i])
- dev_info(svsp->dev, "M_HW_RES%d: 0x%08x\n",
- i, svsp->efuse[i]);
+ num_populated++;
- if (!svsp->efuse[9]) {
- dev_notice(svsp->dev, "svs_efuse[9] = 0x0?\n");
- return false;
+ if (num_populated > 1)
+ return true;
}
- /* Svs efuse parsing */
- vmin = (svsp->efuse[19] >> 4) & GENMASK(1, 0);
+ return false;
+}
- for (idx = 0; idx < svsp->bank_max; idx++) {
- svsb = &svsp->banks[idx];
+static bool svs_common_parse_efuse(struct svs_platform *svsp,
+ const struct svs_platform_data *pdata)
+{
+ const struct svs_fusemap *gfmap = pdata->glb_fuse_map;
+ struct svs_fusemap tfm = { 0, 24 };
+ u32 golden_temp, val;
+ u8 ft_pgm, vmin;
+ int i;
- if (vmin == 0x1)
- svsb->vmin = 0x1e;
+ if (!svs_is_available(svsp))
+ return false;
- if (svsb->type == SVSB_LOW) {
- svsb->mtdes = svsp->efuse[10] & GENMASK(7, 0);
- svsb->bdes = (svsp->efuse[10] >> 16) & GENMASK(7, 0);
- svsb->mdes = (svsp->efuse[10] >> 24) & GENMASK(7, 0);
- svsb->dcbdet = (svsp->efuse[17]) & GENMASK(7, 0);
- svsb->dcmdet = (svsp->efuse[17] >> 8) & GENMASK(7, 0);
- } else if (svsb->type == SVSB_HIGH) {
- svsb->mtdes = svsp->efuse[9] & GENMASK(7, 0);
- svsb->bdes = (svsp->efuse[9] >> 16) & GENMASK(7, 0);
- svsb->mdes = (svsp->efuse[9] >> 24) & GENMASK(7, 0);
- svsb->dcbdet = (svsp->efuse[17] >> 16) & GENMASK(7, 0);
- svsb->dcmdet = (svsp->efuse[17] >> 24) & GENMASK(7, 0);
- }
+ /* Get golden temperature from SVS-Thermal calibration */
+ val = svs_get_fuse_val(svsp->tefuse, &tfm, 8);
- svsb->vmax += svsb->dvt_fixed;
- }
+ /* If golden temp is not programmed, use the default of 50 */
+ golden_temp = val ? val : 50;
- ret = svs_thermal_efuse_get_data(svsp);
- if (ret)
- return false;
+ /* Parse fused SVS calibration */
+ ft_pgm = svs_get_fuse_val(svsp->efuse, &gfmap[GLB_FT_PGM], 8);
+ vmin = svs_get_fuse_val(svsp->efuse, &gfmap[GLB_VMIN], 2);
- for (i = 0; i < svsp->tefuse_max; i++)
- if (svsp->tefuse[i] != 0)
- break;
+ for (i = 0; i < svsp->bank_max; i++) {
+ struct svs_bank *svsb = &svsp->banks[i];
+ const struct svs_bank_pdata *bdata = &svsb->pdata;
+ const struct svs_fusemap *dfmap = bdata->dev_fuse_map;
- if (i == svsp->tefuse_max)
- golden_temp = 50; /* All thermal efuse data are 0 */
- else
- golden_temp = (svsp->tefuse[0] >> 24) & GENMASK(7, 0);
+ if (vmin == 1)
+ svsb->vmin = 0x1e;
- for (idx = 0; idx < svsp->bank_max; idx++) {
- svsb = &svsp->banks[idx];
- svsb->mts = 500;
- svsb->bts = (((500 * golden_temp + 250460) / 1000) - 25) * 4;
+ if (ft_pgm == 0)
+ svsb->volt_flags |= SVSB_INIT01_VOLT_IGNORE;
+
+ svsb->mtdes = svs_get_fuse_val(svsp->efuse, &dfmap[BDEV_MTDES], 8);
+ svsb->bdes = svs_get_fuse_val(svsp->efuse, &dfmap[BDEV_BDES], 8);
+ svsb->mdes = svs_get_fuse_val(svsp->efuse, &dfmap[BDEV_MDES], 8);
+ svsb->dcbdet = svs_get_fuse_val(svsp->efuse, &dfmap[BDEV_DCBDET], 8);
+ svsb->dcmdet = svs_get_fuse_val(svsp->efuse, &dfmap[BDEV_DCMDET], 8);
+ svsb->vmax += svsb->dvt_fixed;
+
+ svsb->mts = (svsp->ts_coeff * 2) / 1000;
+ svsb->bts = (((500 * golden_temp + svsp->ts_coeff) / 1000) - 25) * 4;
}
return true;
}
-static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp)
+static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp,
+ const struct svs_platform_data *pdata)
{
struct svs_bank *svsb;
+ const struct svs_bank_pdata *bdata;
int format[6], x_roomt[6], o_vtsmcu[5], o_vtsabb, tb_roomt = 0;
int adc_ge_t, adc_oe_t, ge, oe, gain, degc_cali, adc_cali_en_t;
int o_slope, o_slope_sign, ts_id;
u32 idx, i, ft_pgm, mts, temp0, temp1, temp2;
- int ret;
for (i = 0; i < svsp->efuse_max; i++)
if (svsp->efuse[i])
@@ -1816,73 +1979,48 @@ static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp)
}
/* Svs efuse parsing */
- ft_pgm = (svsp->efuse[0] >> 4) & GENMASK(3, 0);
+ ft_pgm = svs_get_fuse_val(svsp->efuse, &pdata->glb_fuse_map[GLB_FT_PGM], 4);
for (idx = 0; idx < svsp->bank_max; idx++) {
svsb = &svsp->banks[idx];
+ bdata = &svsb->pdata;
+ const struct svs_fusemap *dfmap = bdata->dev_fuse_map;
if (ft_pgm <= 1)
svsb->volt_flags |= SVSB_INIT01_VOLT_IGNORE;
- switch (svsb->sw_id) {
- case SVSB_CPU_LITTLE:
- svsb->bdes = svsp->efuse[16] & GENMASK(7, 0);
- svsb->mdes = (svsp->efuse[16] >> 8) & GENMASK(7, 0);
- svsb->dcbdet = (svsp->efuse[16] >> 16) & GENMASK(7, 0);
- svsb->dcmdet = (svsp->efuse[16] >> 24) & GENMASK(7, 0);
- svsb->mtdes = (svsp->efuse[17] >> 16) & GENMASK(7, 0);
+ svsb->mtdes = svs_get_fuse_val(svsp->efuse, &dfmap[BDEV_MTDES], 8);
+ svsb->bdes = svs_get_fuse_val(svsp->efuse, &dfmap[BDEV_BDES], 8);
+ svsb->mdes = svs_get_fuse_val(svsp->efuse, &dfmap[BDEV_MDES], 8);
+ svsb->dcbdet = svs_get_fuse_val(svsp->efuse, &dfmap[BDEV_DCBDET], 8);
+ svsb->dcmdet = svs_get_fuse_val(svsp->efuse, &dfmap[BDEV_DCMDET], 8);
+ switch (bdata->sw_id) {
+ case SVSB_SWID_CPU_LITTLE:
+ case SVSB_SWID_CCI:
if (ft_pgm <= 3)
svsb->volt_od += 10;
else
svsb->volt_od += 2;
break;
- case SVSB_CPU_BIG:
- svsb->bdes = svsp->efuse[18] & GENMASK(7, 0);
- svsb->mdes = (svsp->efuse[18] >> 8) & GENMASK(7, 0);
- svsb->dcbdet = (svsp->efuse[18] >> 16) & GENMASK(7, 0);
- svsb->dcmdet = (svsp->efuse[18] >> 24) & GENMASK(7, 0);
- svsb->mtdes = svsp->efuse[17] & GENMASK(7, 0);
-
+ case SVSB_SWID_CPU_BIG:
if (ft_pgm <= 3)
svsb->volt_od += 15;
else
svsb->volt_od += 12;
break;
- case SVSB_CCI:
- svsb->bdes = svsp->efuse[4] & GENMASK(7, 0);
- svsb->mdes = (svsp->efuse[4] >> 8) & GENMASK(7, 0);
- svsb->dcbdet = (svsp->efuse[4] >> 16) & GENMASK(7, 0);
- svsb->dcmdet = (svsp->efuse[4] >> 24) & GENMASK(7, 0);
- svsb->mtdes = (svsp->efuse[5] >> 16) & GENMASK(7, 0);
-
- if (ft_pgm <= 3)
- svsb->volt_od += 10;
- else
- svsb->volt_od += 2;
- break;
- case SVSB_GPU:
- svsb->bdes = svsp->efuse[6] & GENMASK(7, 0);
- svsb->mdes = (svsp->efuse[6] >> 8) & GENMASK(7, 0);
- svsb->dcbdet = (svsp->efuse[6] >> 16) & GENMASK(7, 0);
- svsb->dcmdet = (svsp->efuse[6] >> 24) & GENMASK(7, 0);
- svsb->mtdes = svsp->efuse[5] & GENMASK(7, 0);
-
- if (ft_pgm >= 2) {
+ case SVSB_SWID_GPU:
+ if (ft_pgm != FUSE_DATA_NOT_VALID && ft_pgm >= 2) {
svsb->freq_base = 800000000; /* 800MHz */
svsb->dvt_fixed = 2;
}
break;
default:
- dev_err(svsb->dev, "unknown sw_id: %u\n", svsb->sw_id);
+ dev_err(svsb->dev, "unknown sw_id: %u\n", bdata->sw_id);
return false;
}
}
- ret = svs_thermal_efuse_get_data(svsp);
- if (ret)
- return false;
-
/* Thermal efuse parsing */
adc_ge_t = (svsp->tefuse[1] >> 22) & GENMASK(9, 0);
adc_oe_t = (svsp->tefuse[1] >> 12) & GENMASK(9, 0);
@@ -1899,26 +2037,27 @@ static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp)
o_slope_sign = (svsp->tefuse[0] >> 7) & BIT(0);
ts_id = (svsp->tefuse[1] >> 9) & BIT(0);
- o_slope = (svsp->tefuse[0] >> 26) & GENMASK(5, 0);
-
- if (adc_cali_en_t == 1) {
- if (!ts_id)
- o_slope = 0;
-
- if (adc_ge_t < 265 || adc_ge_t > 758 ||
- adc_oe_t < 265 || adc_oe_t > 758 ||
- o_vtsmcu[0] < -8 || o_vtsmcu[0] > 484 ||
- o_vtsmcu[1] < -8 || o_vtsmcu[1] > 484 ||
- o_vtsmcu[2] < -8 || o_vtsmcu[2] > 484 ||
- o_vtsmcu[3] < -8 || o_vtsmcu[3] > 484 ||
- o_vtsmcu[4] < -8 || o_vtsmcu[4] > 484 ||
- o_vtsabb < -8 || o_vtsabb > 484 ||
- degc_cali < 1 || degc_cali > 63) {
- dev_err(svsp->dev, "bad thermal efuse, no mon mode\n");
- goto remove_mt8183_svsb_mon_mode;
- }
+ if (!ts_id) {
+ o_slope = 1534;
} else {
- dev_err(svsp->dev, "no thermal efuse, no mon mode\n");
+ o_slope = (svsp->tefuse[0] >> 26) & GENMASK(5, 0);
+ if (!o_slope_sign)
+ o_slope = 1534 + o_slope * 10;
+ else
+ o_slope = 1534 - o_slope * 10;
+ }
+
+ if (adc_cali_en_t == 0 ||
+ adc_ge_t < 265 || adc_ge_t > 758 ||
+ adc_oe_t < 265 || adc_oe_t > 758 ||
+ o_vtsmcu[0] < -8 || o_vtsmcu[0] > 484 ||
+ o_vtsmcu[1] < -8 || o_vtsmcu[1] > 484 ||
+ o_vtsmcu[2] < -8 || o_vtsmcu[2] > 484 ||
+ o_vtsmcu[3] < -8 || o_vtsmcu[3] > 484 ||
+ o_vtsmcu[4] < -8 || o_vtsmcu[4] > 484 ||
+ o_vtsabb < -8 || o_vtsabb > 484 ||
+ degc_cali < 1 || degc_cali > 63) {
+ dev_err(svsp->dev, "bad thermal efuse, no mon mode\n");
goto remove_mt8183_svsb_mon_mode;
}
@@ -1937,42 +2076,35 @@ static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp)
x_roomt[i] = (((format[i] * 10000) / 4096) * 10000) / gain;
temp0 = (10000 * 100000 / gain) * 15 / 18;
-
- if (!o_slope_sign)
- mts = (temp0 * 10) / (1534 + o_slope * 10);
- else
- mts = (temp0 * 10) / (1534 - o_slope * 10);
+ mts = (temp0 * 10) / o_slope;
for (idx = 0; idx < svsp->bank_max; idx++) {
svsb = &svsp->banks[idx];
+ bdata = &svsb->pdata;
svsb->mts = mts;
- switch (svsb->sw_id) {
- case SVSB_CPU_LITTLE:
+ switch (bdata->sw_id) {
+ case SVSB_SWID_CPU_LITTLE:
tb_roomt = x_roomt[3];
break;
- case SVSB_CPU_BIG:
+ case SVSB_SWID_CPU_BIG:
tb_roomt = x_roomt[4];
break;
- case SVSB_CCI:
+ case SVSB_SWID_CCI:
tb_roomt = x_roomt[3];
break;
- case SVSB_GPU:
+ case SVSB_SWID_GPU:
tb_roomt = x_roomt[1];
break;
default:
- dev_err(svsb->dev, "unknown sw_id: %u\n", svsb->sw_id);
+ dev_err(svsb->dev, "unknown sw_id: %u\n", bdata->sw_id);
goto remove_mt8183_svsb_mon_mode;
}
temp0 = (degc_cali * 10 / 2);
temp1 = ((10000 * 100000 / 4096 / gain) *
oe + tb_roomt * 10) * 15 / 18;
-
- if (!o_slope_sign)
- temp2 = temp1 * 100 / (1534 + o_slope * 10);
- else
- temp2 = temp1 * 100 / (1534 - o_slope * 10);
+ temp2 = temp1 * 100 / o_slope;
svsb->bts = (temp0 + temp2 - 250) * 4 / 10;
}
@@ -1988,32 +2120,6 @@ remove_mt8183_svsb_mon_mode:
return true;
}
-static bool svs_is_efuse_data_correct(struct svs_platform *svsp)
-{
- struct nvmem_cell *cell;
-
- /* Get svs efuse by nvmem */
- cell = nvmem_cell_get(svsp->dev, "svs-calibration-data");
- if (IS_ERR(cell)) {
- dev_err(svsp->dev, "no \"svs-calibration-data\"? %ld\n",
- PTR_ERR(cell));
- return false;
- }
-
- svsp->efuse = nvmem_cell_read(cell, &svsp->efuse_max);
- if (IS_ERR(svsp->efuse)) {
- dev_err(svsp->dev, "cannot read svs efuse: %ld\n",
- PTR_ERR(svsp->efuse));
- nvmem_cell_put(cell);
- return false;
- }
-
- svsp->efuse_max /= sizeof(u32);
- nvmem_cell_put(cell);
-
- return svsp->efuse_parsing(svsp);
-}
-
static struct device *svs_get_subsys_device(struct svs_platform *svsp,
const char *node_name)
{
@@ -2027,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;
}
@@ -2044,11 +2148,6 @@ static struct device *svs_add_device_link(struct svs_platform *svsp,
struct device *dev;
struct device_link *sup_link;
- if (!node_name) {
- dev_err(svsp->dev, "node name cannot be null\n");
- return ERR_PTR(-EINVAL);
- }
-
dev = svs_get_subsys_device(svsp, node_name);
if (IS_ERR(dev))
return dev;
@@ -2066,34 +2165,63 @@ static struct device *svs_add_device_link(struct svs_platform *svsp,
return dev;
}
+static void svs_put_device(void *_dev)
+{
+ struct device *dev = _dev;
+
+ put_device(dev);
+}
+
static int svs_mt8192_platform_probe(struct svs_platform *svsp)
{
struct device *dev;
- struct svs_bank *svsb;
u32 idx;
+ int ret;
svsp->rst = devm_reset_control_get_optional(svsp->dev, "svs_rst");
if (IS_ERR(svsp->rst))
return dev_err_probe(svsp->dev, PTR_ERR(svsp->rst),
"cannot get svs reset control\n");
- dev = svs_add_device_link(svsp, "lvts");
+ dev = svs_add_device_link(svsp, "thermal-sensor");
if (IS_ERR(dev))
return dev_err_probe(svsp->dev, PTR_ERR(dev),
"failed to get lvts device\n");
+ put_device(dev);
for (idx = 0; idx < svsp->bank_max; idx++) {
- svsb = &svsp->banks[idx];
-
- if (svsb->type == SVSB_HIGH)
- svsb->opp_dev = svs_add_device_link(svsp, "mali");
- else if (svsb->type == SVSB_LOW)
- svsb->opp_dev = svs_get_subsys_device(svsp, "mali");
+ struct svs_bank *svsb = &svsp->banks[idx];
+ const struct svs_bank_pdata *bdata = &svsb->pdata;
+
+ switch (bdata->sw_id) {
+ case SVSB_SWID_CPU_LITTLE:
+ case SVSB_SWID_CPU_BIG:
+ svsb->opp_dev = get_cpu_device(bdata->cpu_id);
+ get_device(svsb->opp_dev);
+ break;
+ case SVSB_SWID_CCI:
+ svsb->opp_dev = svs_add_device_link(svsp, "cci");
+ break;
+ case SVSB_SWID_GPU:
+ if (bdata->type == SVSB_TYPE_LOW)
+ svsb->opp_dev = svs_get_subsys_device(svsp, "gpu");
+ else
+ svsb->opp_dev = svs_add_device_link(svsp, "gpu");
+ break;
+ default:
+ dev_err(svsb->dev, "unknown sw_id: %u\n", bdata->sw_id);
+ return -EINVAL;
+ }
if (IS_ERR(svsb->opp_dev))
return dev_err_probe(svsp->dev, PTR_ERR(svsb->opp_dev),
"failed to get OPP device for bank %d\n",
idx);
+
+ ret = devm_add_action_or_reset(svsp->dev, svs_put_device,
+ svsb->opp_dev);
+ if (ret)
+ return ret;
}
return 0;
@@ -2102,30 +2230,33 @@ static int svs_mt8192_platform_probe(struct svs_platform *svsp)
static int svs_mt8183_platform_probe(struct svs_platform *svsp)
{
struct device *dev;
- struct svs_bank *svsb;
u32 idx;
+ int ret;
- dev = svs_add_device_link(svsp, "thermal");
+ dev = svs_add_device_link(svsp, "thermal-sensor");
if (IS_ERR(dev))
return dev_err_probe(svsp->dev, PTR_ERR(dev),
"failed to get thermal device\n");
+ put_device(dev);
for (idx = 0; idx < svsp->bank_max; idx++) {
- svsb = &svsp->banks[idx];
-
- switch (svsb->sw_id) {
- case SVSB_CPU_LITTLE:
- case SVSB_CPU_BIG:
- svsb->opp_dev = get_cpu_device(svsb->cpu_id);
+ struct svs_bank *svsb = &svsp->banks[idx];
+ const struct svs_bank_pdata *bdata = &svsb->pdata;
+
+ switch (bdata->sw_id) {
+ case SVSB_SWID_CPU_LITTLE:
+ case SVSB_SWID_CPU_BIG:
+ svsb->opp_dev = get_cpu_device(bdata->cpu_id);
+ get_device(svsb->opp_dev);
break;
- case SVSB_CCI:
+ case SVSB_SWID_CCI:
svsb->opp_dev = svs_add_device_link(svsp, "cci");
break;
- case SVSB_GPU:
+ case SVSB_SWID_GPU:
svsb->opp_dev = svs_add_device_link(svsp, "gpu");
break;
default:
- dev_err(svsb->dev, "unknown sw_id: %u\n", svsb->sw_id);
+ dev_err(svsb->dev, "unknown sw_id: %u\n", bdata->sw_id);
return -EINVAL;
}
@@ -2133,177 +2264,554 @@ static int svs_mt8183_platform_probe(struct svs_platform *svsp)
return dev_err_probe(svsp->dev, PTR_ERR(svsb->opp_dev),
"failed to get OPP device for bank %d\n",
idx);
+
+ ret = devm_add_action_or_reset(svsp->dev, svs_put_device,
+ svsb->opp_dev);
+ if (ret)
+ return ret;
}
return 0;
}
+static struct svs_bank svs_mt8195_banks[] = {
+ {
+ .pdata = (const struct svs_bank_pdata) {
+ .sw_id = SVSB_SWID_GPU,
+ .type = SVSB_TYPE_LOW,
+ .set_freq_pct = svs_set_bank_freq_pct_v3,
+ .get_volts = svs_get_bank_volts_v3,
+ .opp_count = MAX_OPP_ENTRIES,
+ .turn_freq_base = 640000000,
+ .volt_step = 6250,
+ .volt_base = 400000,
+ .age_config = 0x555555,
+ .dc_config = 0x1,
+ .vco = 0x18,
+ .chk_shift = 0x87,
+ .int_st = BIT(0),
+ .ctl0 = 0x00540003,
+ .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) {
+ { 10, 16 }, { 10, 24 }, { 10, 0 }, { 8, 0 }, { 8, 8 }
+ }
+ },
+ .mode_support = SVSB_MODE_INIT02,
+ .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT,
+ .freq_base = 640000000,
+ .core_sel = 0x0fff0100,
+ .dvt_fixed = 0x1,
+ .vmax = 0x38,
+ .vmin = 0x14,
+ },
+ {
+ .pdata = (const struct svs_bank_pdata) {
+ .sw_id = SVSB_SWID_GPU,
+ .type = SVSB_TYPE_HIGH,
+ .set_freq_pct = svs_set_bank_freq_pct_v3,
+ .get_volts = svs_get_bank_volts_v3,
+ .tzone_name = "gpu",
+ .opp_count = MAX_OPP_ENTRIES,
+ .turn_freq_base = 640000000,
+ .volt_step = 6250,
+ .volt_base = 400000,
+ .age_config = 0x555555,
+ .dc_config = 0x1,
+ .vco = 0x18,
+ .chk_shift = 0x87,
+ .int_st = BIT(1),
+ .ctl0 = 0x00540003,
+ .tzone_htemp = 85000,
+ .tzone_htemp_voffset = 0,
+ .tzone_ltemp = 25000,
+ .tzone_ltemp_voffset = 7,
+ .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) {
+ { 9, 16 }, { 9, 24 }, { 9, 0 }, { 8, 0 }, { 8, 8 }
+ },
+ },
+ .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT | SVSB_MON_VOLT_IGNORE,
+ .mode_support = SVSB_MODE_INIT02 | SVSB_MODE_MON,
+ .freq_base = 880000000,
+ .core_sel = 0x0fff0101,
+ .dvt_fixed = 0x6,
+ .vmax = 0x38,
+ .vmin = 0x14,
+ },
+};
+
static struct svs_bank svs_mt8192_banks[] = {
{
- .sw_id = SVSB_GPU,
- .type = SVSB_LOW,
- .set_freq_pct = svs_set_bank_freq_pct_v3,
- .get_volts = svs_get_bank_volts_v3,
- .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT,
- .mode_support = SVSB_MODE_INIT02,
- .opp_count = MAX_OPP_ENTRIES,
- .freq_base = 688000000,
- .turn_freq_base = 688000000,
- .volt_step = 6250,
- .volt_base = 400000,
- .vmax = 0x60,
- .vmin = 0x1a,
- .age_config = 0x555555,
- .dc_config = 0x1,
- .dvt_fixed = 0x1,
- .vco = 0x18,
- .chk_shift = 0x87,
- .core_sel = 0x0fff0100,
- .int_st = BIT(0),
- .ctl0 = 0x00540003,
+ .pdata = (const struct svs_bank_pdata) {
+ .sw_id = SVSB_SWID_GPU,
+ .type = SVSB_TYPE_LOW,
+ .set_freq_pct = svs_set_bank_freq_pct_v3,
+ .get_volts = svs_get_bank_volts_v3,
+ .tzone_name = "gpu",
+ .opp_count = MAX_OPP_ENTRIES,
+ .turn_freq_base = 688000000,
+ .volt_step = 6250,
+ .volt_base = 400000,
+ .age_config = 0x555555,
+ .dc_config = 0x1,
+ .vco = 0x18,
+ .chk_shift = 0x87,
+ .int_st = BIT(0),
+ .ctl0 = 0x00540003,
+ .tzone_htemp = 85000,
+ .tzone_htemp_voffset = 0,
+ .tzone_ltemp = 25000,
+ .tzone_ltemp_voffset = 7,
+ .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) {
+ { 10, 16 }, { 10, 24 }, { 10, 0 }, { 17, 0 }, { 17, 8 }
+ }
+ },
+ .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT,
+ .mode_support = SVSB_MODE_INIT02,
+ .freq_base = 688000000,
+ .core_sel = 0x0fff0100,
+ .dvt_fixed = 0x1,
+ .vmax = 0x60,
+ .vmin = 0x1a,
+ },
+ {
+ .pdata = (const struct svs_bank_pdata) {
+ .sw_id = SVSB_SWID_GPU,
+ .type = SVSB_TYPE_HIGH,
+ .set_freq_pct = svs_set_bank_freq_pct_v3,
+ .get_volts = svs_get_bank_volts_v3,
+ .tzone_name = "gpu",
+ .opp_count = MAX_OPP_ENTRIES,
+ .turn_freq_base = 688000000,
+ .volt_step = 6250,
+ .volt_base = 400000,
+ .age_config = 0x555555,
+ .dc_config = 0x1,
+ .vco = 0x18,
+ .chk_shift = 0x87,
+ .int_st = BIT(1),
+ .ctl0 = 0x00540003,
+ .tzone_htemp = 85000,
+ .tzone_htemp_voffset = 0,
+ .tzone_ltemp = 25000,
+ .tzone_ltemp_voffset = 7,
+ .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) {
+ { 9, 16 }, { 9, 24 }, { 17, 0 }, { 17, 16 }, { 17, 24 }
+ }
+ },
+ .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT | SVSB_MON_VOLT_IGNORE,
+ .mode_support = SVSB_MODE_INIT02 | SVSB_MODE_MON,
+ .freq_base = 902000000,
+ .core_sel = 0x0fff0101,
+ .dvt_fixed = 0x6,
+ .vmax = 0x60,
+ .vmin = 0x1a,
+ },
+};
+
+static struct svs_bank svs_mt8188_banks[] = {
+ {
+ .pdata = (const struct svs_bank_pdata) {
+ .sw_id = SVSB_SWID_GPU,
+ .type = SVSB_TYPE_LOW,
+ .set_freq_pct = svs_set_bank_freq_pct_v3,
+ .get_volts = svs_get_bank_volts_v3,
+ .opp_count = MAX_OPP_ENTRIES,
+ .turn_freq_base = 640000000,
+ .volt_step = 6250,
+ .volt_base = 400000,
+ .age_config = 0x555555,
+ .dc_config = 0x555555,
+ .vco = 0x10,
+ .chk_shift = 0x87,
+ .int_st = BIT(0),
+ .ctl0 = 0x00100003,
+ .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) {
+ { 5, 16 }, { 5, 24 }, { 5, 0 }, { 15, 16 }, { 15, 24 }
+ }
+ },
+ .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT,
+ .mode_support = SVSB_MODE_INIT02,
+ .freq_base = 640000000,
+ .core_sel = 0x0fff0000,
+ .dvt_fixed = 0x1,
+ .vmax = 0x38,
+ .vmin = 0x1c,
},
{
- .sw_id = SVSB_GPU,
- .type = SVSB_HIGH,
- .set_freq_pct = svs_set_bank_freq_pct_v3,
- .get_volts = svs_get_bank_volts_v3,
- .tzone_name = "gpu1",
- .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT |
- SVSB_MON_VOLT_IGNORE,
- .mode_support = SVSB_MODE_INIT02 | SVSB_MODE_MON,
- .opp_count = MAX_OPP_ENTRIES,
- .freq_base = 902000000,
- .turn_freq_base = 688000000,
- .volt_step = 6250,
- .volt_base = 400000,
- .vmax = 0x60,
- .vmin = 0x1a,
- .age_config = 0x555555,
- .dc_config = 0x1,
- .dvt_fixed = 0x6,
- .vco = 0x18,
- .chk_shift = 0x87,
- .core_sel = 0x0fff0101,
- .int_st = BIT(1),
- .ctl0 = 0x00540003,
- .tzone_htemp = 85000,
- .tzone_htemp_voffset = 0,
- .tzone_ltemp = 25000,
- .tzone_ltemp_voffset = 7,
+ .pdata = (const struct svs_bank_pdata) {
+ .sw_id = SVSB_SWID_GPU,
+ .type = SVSB_TYPE_HIGH,
+ .set_freq_pct = svs_set_bank_freq_pct_v3,
+ .get_volts = svs_get_bank_volts_v3,
+ .tzone_name = "gpu",
+ .opp_count = MAX_OPP_ENTRIES,
+ .turn_freq_base = 640000000,
+ .volt_step = 6250,
+ .volt_base = 400000,
+ .age_config = 0x555555,
+ .dc_config = 0x555555,
+ .vco = 0x10,
+ .chk_shift = 0x87,
+ .int_st = BIT(1),
+ .ctl0 = 0x00100003,
+ .tzone_htemp = 85000,
+ .tzone_htemp_voffset = 0,
+ .tzone_ltemp = 25000,
+ .tzone_ltemp_voffset = 7,
+ .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) {
+ { 4, 16 }, { 4, 24 }, { 4, 0 }, { 14, 0 }, { 14, 8 }
+ }
+ },
+ .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT | SVSB_MON_VOLT_IGNORE,
+ .mode_support = SVSB_MODE_INIT02 | SVSB_MODE_MON,
+ .freq_base = 880000000,
+ .core_sel = 0x0fff0001,
+ .dvt_fixed = 0x4,
+ .vmax = 0x38,
+ .vmin = 0x1c,
+ },
+};
+
+static struct svs_bank svs_mt8186_banks[] = {
+ {
+ .pdata = (const struct svs_bank_pdata) {
+ .sw_id = SVSB_SWID_CPU_BIG,
+ .type = SVSB_TYPE_LOW,
+ .set_freq_pct = svs_set_bank_freq_pct_v3,
+ .get_volts = svs_get_bank_volts_v3,
+ .cpu_id = 6,
+ .opp_count = MAX_OPP_ENTRIES,
+ .turn_freq_base = 1670000000,
+ .volt_step = 6250,
+ .volt_base = 400000,
+ .age_config = 0x1,
+ .dc_config = 0x1,
+ .vco = 0x10,
+ .chk_shift = 0x87,
+ .int_st = BIT(0),
+ .ctl0 = 0x00540003,
+ .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) {
+ { 3, 16 }, { 3, 24 }, { 3, 0 }, { 14, 16 }, { 14, 24 }
+ }
+ },
+ .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT,
+ .volt_od = 4,
+ .mode_support = SVSB_MODE_INIT02,
+ .freq_base = 1670000000,
+ .core_sel = 0x0fff0100,
+ .dvt_fixed = 0x3,
+ .vmax = 0x59,
+ .vmin = 0x20,
+ },
+ {
+ .pdata = (const struct svs_bank_pdata) {
+ .sw_id = SVSB_SWID_CPU_BIG,
+ .type = SVSB_TYPE_HIGH,
+ .set_freq_pct = svs_set_bank_freq_pct_v3,
+ .get_volts = svs_get_bank_volts_v3,
+ .cpu_id = 6,
+ .tzone_name = "cpu-big",
+ .opp_count = MAX_OPP_ENTRIES,
+ .turn_freq_base = 1670000000,
+ .volt_step = 6250,
+ .volt_base = 400000,
+ .age_config = 0x1,
+ .dc_config = 0x1,
+ .vco = 0x10,
+ .chk_shift = 0x87,
+ .int_st = BIT(1),
+ .ctl0 = 0x00540003,
+ .tzone_htemp = 85000,
+ .tzone_htemp_voffset = 8,
+ .tzone_ltemp = 25000,
+ .tzone_ltemp_voffset = 8,
+ .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) {
+ { 2, 16 }, { 2, 24 }, { 2, 0 }, { 13, 0 }, { 13, 8 }
+ }
+ },
+ .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT | SVSB_MON_VOLT_IGNORE,
+ .volt_od = 4,
+ .mode_support = SVSB_MODE_INIT02 | SVSB_MODE_MON,
+ .freq_base = 2050000000,
+ .core_sel = 0x0fff0101,
+ .dvt_fixed = 0x6,
+ .vmax = 0x73,
+ .vmin = 0x20,
+ },
+ {
+ .pdata = (const struct svs_bank_pdata) {
+ .sw_id = SVSB_SWID_CPU_LITTLE,
+ .set_freq_pct = svs_set_bank_freq_pct_v2,
+ .get_volts = svs_get_bank_volts_v2,
+ .cpu_id = 0,
+ .tzone_name = "cpu-little",
+ .opp_count = MAX_OPP_ENTRIES,
+ .volt_step = 6250,
+ .volt_base = 400000,
+ .age_config = 0x1,
+ .dc_config = 0x1,
+ .vco = 0x10,
+ .chk_shift = 0x87,
+ .int_st = BIT(2),
+ .ctl0 = 0x3210000f,
+ .tzone_htemp = 85000,
+ .tzone_htemp_voffset = 8,
+ .tzone_ltemp = 25000,
+ .tzone_ltemp_voffset = 8,
+ .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) {
+ { 4, 16 }, { 4, 24 }, { 4, 0 }, { 14, 0 }, { 14, 8 }
+ }
+ },
+ .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT | SVSB_MON_VOLT_IGNORE,
+ .volt_od = 3,
+ .mode_support = SVSB_MODE_INIT02 | SVSB_MODE_MON,
+ .freq_base = 2000000000,
+ .core_sel = 0x0fff0102,
+ .dvt_fixed = 0x6,
+ .vmax = 0x65,
+ .vmin = 0x20,
+ },
+ {
+ .pdata = (const struct svs_bank_pdata) {
+ .sw_id = SVSB_SWID_CCI,
+ .set_freq_pct = svs_set_bank_freq_pct_v2,
+ .get_volts = svs_get_bank_volts_v2,
+ .tzone_name = "cci",
+ .opp_count = MAX_OPP_ENTRIES,
+ .volt_step = 6250,
+ .volt_base = 400000,
+ .age_config = 0x1,
+ .dc_config = 0x1,
+ .vco = 0x10,
+ .chk_shift = 0x87,
+ .int_st = BIT(3),
+ .ctl0 = 0x3210000f,
+ .tzone_htemp = 85000,
+ .tzone_htemp_voffset = 8,
+ .tzone_ltemp = 25000,
+ .tzone_ltemp_voffset = 8,
+ .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) {
+ { 5, 16 }, { 5, 24 }, { 5, 0 }, { 15, 16 }, { 15, 24 }
+ }
+ },
+ .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT | SVSB_MON_VOLT_IGNORE,
+ .volt_od = 3,
+ .mode_support = SVSB_MODE_INIT02 | SVSB_MODE_MON,
+ .freq_base = 1400000000,
+ .core_sel = 0x0fff0103,
+ .dvt_fixed = 0x6,
+ .vmax = 0x65,
+ .vmin = 0x20,
+ },
+ {
+ .pdata = (const struct svs_bank_pdata) {
+ .sw_id = SVSB_SWID_GPU,
+ .set_freq_pct = svs_set_bank_freq_pct_v2,
+ .get_volts = svs_get_bank_volts_v2,
+ .tzone_name = "gpu",
+ .opp_count = MAX_OPP_ENTRIES,
+ .volt_step = 6250,
+ .volt_base = 400000,
+ .age_config = 0x555555,
+ .dc_config = 0x1,
+ .vco = 0x10,
+ .chk_shift = 0x87,
+ .int_st = BIT(4),
+ .ctl0 = 0x00100003,
+ .tzone_htemp = 85000,
+ .tzone_htemp_voffset = 8,
+ .tzone_ltemp = 25000,
+ .tzone_ltemp_voffset = 7,
+ .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) {
+ { 6, 16 }, { 6, 24 }, { 6, 0 }, { 15, 8 }, { 15, 0 }
+ }
+ },
+ .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT | SVSB_MON_VOLT_IGNORE,
+ .mode_support = SVSB_MODE_INIT02 | SVSB_MODE_MON,
+ .freq_base = 850000000,
+ .core_sel = 0x0fff0104,
+ .dvt_fixed = 0x4,
+ .vmax = 0x58,
+ .vmin = 0x20,
},
};
static struct svs_bank svs_mt8183_banks[] = {
{
- .sw_id = SVSB_CPU_LITTLE,
- .set_freq_pct = svs_set_bank_freq_pct_v2,
- .get_volts = svs_get_bank_volts_v2,
- .cpu_id = 0,
- .buck_name = "proc",
- .volt_flags = SVSB_INIT01_VOLT_INC_ONLY,
- .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
- .opp_count = MAX_OPP_ENTRIES,
- .freq_base = 1989000000,
- .vboot = 0x30,
- .volt_step = 6250,
- .volt_base = 500000,
- .vmax = 0x64,
- .vmin = 0x18,
- .age_config = 0x555555,
- .dc_config = 0x555555,
- .dvt_fixed = 0x7,
- .vco = 0x10,
- .chk_shift = 0x77,
- .core_sel = 0x8fff0000,
- .int_st = BIT(0),
- .ctl0 = 0x00010001,
+ .pdata = (const struct svs_bank_pdata) {
+ .sw_id = SVSB_SWID_CPU_LITTLE,
+ .set_freq_pct = svs_set_bank_freq_pct_v2,
+ .get_volts = svs_get_bank_volts_v2,
+ .cpu_id = 0,
+ .buck_name = "proc",
+ .opp_count = MAX_OPP_ENTRIES,
+ .vboot = 0x30,
+ .volt_step = 6250,
+ .volt_base = 500000,
+ .age_config = 0x555555,
+ .dc_config = 0x555555,
+ .vco = 0x10,
+ .chk_shift = 0x77,
+ .int_st = BIT(0),
+ .ctl0 = 0x00010001,
+ .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) {
+ { 16, 0 }, { 16, 8 }, { 17, 16 }, { 16, 16 }, { 16, 24 }
+ }
+ },
+ .volt_flags = SVSB_INIT01_VOLT_INC_ONLY,
+ .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
+ .freq_base = 1989000000,
+ .core_sel = 0x8fff0000,
+ .dvt_fixed = 0x7,
+ .vmax = 0x64,
+ .vmin = 0x18,
+
},
{
- .sw_id = SVSB_CPU_BIG,
- .set_freq_pct = svs_set_bank_freq_pct_v2,
- .get_volts = svs_get_bank_volts_v2,
- .cpu_id = 4,
- .buck_name = "proc",
- .volt_flags = SVSB_INIT01_VOLT_INC_ONLY,
- .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
- .opp_count = MAX_OPP_ENTRIES,
- .freq_base = 1989000000,
- .vboot = 0x30,
- .volt_step = 6250,
- .volt_base = 500000,
- .vmax = 0x58,
- .vmin = 0x10,
- .age_config = 0x555555,
- .dc_config = 0x555555,
- .dvt_fixed = 0x7,
- .vco = 0x10,
- .chk_shift = 0x77,
- .core_sel = 0x8fff0001,
- .int_st = BIT(1),
- .ctl0 = 0x00000001,
+ .pdata = (const struct svs_bank_pdata) {
+ .sw_id = SVSB_SWID_CPU_BIG,
+ .set_freq_pct = svs_set_bank_freq_pct_v2,
+ .get_volts = svs_get_bank_volts_v2,
+ .cpu_id = 4,
+ .buck_name = "proc",
+ .opp_count = MAX_OPP_ENTRIES,
+ .vboot = 0x30,
+ .volt_step = 6250,
+ .volt_base = 500000,
+ .age_config = 0x555555,
+ .dc_config = 0x555555,
+ .vco = 0x10,
+ .chk_shift = 0x77,
+ .int_st = BIT(1),
+ .ctl0 = 0x00000001,
+ .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) {
+ { 18, 0 }, { 18, 8 }, { 17, 0 }, { 18, 16 }, { 18, 24 }
+ }
+ },
+ .volt_flags = SVSB_INIT01_VOLT_INC_ONLY,
+ .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
+ .freq_base = 1989000000,
+ .core_sel = 0x8fff0001,
+ .dvt_fixed = 0x7,
+ .vmax = 0x58,
+ .vmin = 0x10,
+
},
{
- .sw_id = SVSB_CCI,
- .set_freq_pct = svs_set_bank_freq_pct_v2,
- .get_volts = svs_get_bank_volts_v2,
- .buck_name = "proc",
- .volt_flags = SVSB_INIT01_VOLT_INC_ONLY,
- .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
- .opp_count = MAX_OPP_ENTRIES,
- .freq_base = 1196000000,
- .vboot = 0x30,
- .volt_step = 6250,
- .volt_base = 500000,
- .vmax = 0x64,
- .vmin = 0x18,
- .age_config = 0x555555,
- .dc_config = 0x555555,
- .dvt_fixed = 0x7,
- .vco = 0x10,
- .chk_shift = 0x77,
- .core_sel = 0x8fff0002,
- .int_st = BIT(2),
- .ctl0 = 0x00100003,
+ .pdata = (const struct svs_bank_pdata) {
+ .sw_id = SVSB_SWID_CCI,
+ .set_freq_pct = svs_set_bank_freq_pct_v2,
+ .get_volts = svs_get_bank_volts_v2,
+ .buck_name = "proc",
+ .opp_count = MAX_OPP_ENTRIES,
+ .vboot = 0x30,
+ .volt_step = 6250,
+ .volt_base = 500000,
+ .age_config = 0x555555,
+ .dc_config = 0x555555,
+ .vco = 0x10,
+ .chk_shift = 0x77,
+ .int_st = BIT(2),
+ .ctl0 = 0x00100003,
+ .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) {
+ { 4, 0 }, { 4, 8 }, { 5, 16 }, { 4, 16 }, { 4, 24 }
+ }
+ },
+ .volt_flags = SVSB_INIT01_VOLT_INC_ONLY,
+ .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
+ .freq_base = 1196000000,
+ .core_sel = 0x8fff0002,
+ .dvt_fixed = 0x7,
+ .vmax = 0x64,
+ .vmin = 0x18,
},
{
- .sw_id = SVSB_GPU,
- .set_freq_pct = svs_set_bank_freq_pct_v2,
- .get_volts = svs_get_bank_volts_v2,
- .buck_name = "mali",
- .tzone_name = "tzts2",
- .volt_flags = SVSB_INIT01_PD_REQ |
- SVSB_INIT01_VOLT_INC_ONLY,
- .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02 |
- SVSB_MODE_MON,
- .opp_count = MAX_OPP_ENTRIES,
- .freq_base = 900000000,
- .vboot = 0x30,
- .volt_step = 6250,
- .volt_base = 500000,
- .vmax = 0x40,
- .vmin = 0x14,
- .age_config = 0x555555,
- .dc_config = 0x555555,
- .dvt_fixed = 0x3,
- .vco = 0x10,
- .chk_shift = 0x77,
- .core_sel = 0x8fff0003,
- .int_st = BIT(3),
- .ctl0 = 0x00050001,
- .tzone_htemp = 85000,
- .tzone_htemp_voffset = 0,
- .tzone_ltemp = 25000,
- .tzone_ltemp_voffset = 3,
+ .pdata = (const struct svs_bank_pdata) {
+ .sw_id = SVSB_SWID_GPU,
+ .set_freq_pct = svs_set_bank_freq_pct_v2,
+ .get_volts = svs_get_bank_volts_v2,
+ .buck_name = "mali",
+ .tzone_name = "gpu",
+ .opp_count = MAX_OPP_ENTRIES,
+ .vboot = 0x30,
+ .volt_step = 6250,
+ .volt_base = 500000,
+ .age_config = 0x555555,
+ .dc_config = 0x555555,
+ .vco = 0x10,
+ .chk_shift = 0x77,
+ .int_st = BIT(3),
+ .ctl0 = 0x00050001,
+ .tzone_htemp = 85000,
+ .tzone_htemp_voffset = 0,
+ .tzone_ltemp = 25000,
+ .tzone_ltemp_voffset = 3,
+ .dev_fuse_map = (const struct svs_fusemap[BDEV_MAX]) {
+ { 6, 0 }, { 6, 8 }, { 5, 0 }, { 6, 16 }, { 6, 24 }
+ }
+ },
+ .volt_flags = SVSB_INIT01_PD_REQ | SVSB_INIT01_VOLT_INC_ONLY,
+ .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02 | SVSB_MODE_MON,
+ .freq_base = 900000000,
+ .core_sel = 0x8fff0003,
+ .dvt_fixed = 0x3,
+ .vmax = 0x40,
+ .vmin = 0x14,
},
};
+static const struct svs_platform_data svs_mt8195_platform_data = {
+ .name = "mt8195-svs",
+ .banks = svs_mt8195_banks,
+ .efuse_parsing = svs_common_parse_efuse,
+ .probe = svs_mt8192_platform_probe,
+ .regs = svs_regs_v2,
+ .bank_max = ARRAY_SIZE(svs_mt8195_banks),
+ .ts_coeff = SVSB_TS_COEFF_MT8195,
+ .glb_fuse_map = (const struct svs_fusemap[GLB_MAX]) {
+ { 0, 0 }, { 19, 4 }
+ }
+};
+
static const struct svs_platform_data svs_mt8192_platform_data = {
.name = "mt8192-svs",
.banks = svs_mt8192_banks,
- .efuse_parsing = svs_mt8192_efuse_parsing,
+ .efuse_parsing = svs_common_parse_efuse,
.probe = svs_mt8192_platform_probe,
.regs = svs_regs_v2,
.bank_max = ARRAY_SIZE(svs_mt8192_banks),
+ .ts_coeff = SVSB_TS_COEFF_MT8195,
+ .glb_fuse_map = (const struct svs_fusemap[GLB_MAX]) {
+ /* FT_PGM not present */
+ { -1, 0 }, { 19, 4 }
+ }
+};
+
+static const struct svs_platform_data svs_mt8188_platform_data = {
+ .name = "mt8188-svs",
+ .banks = svs_mt8188_banks,
+ .efuse_parsing = svs_common_parse_efuse,
+ .probe = svs_mt8192_platform_probe,
+ .regs = svs_regs_v2,
+ .bank_max = ARRAY_SIZE(svs_mt8188_banks),
+ .ts_coeff = SVSB_TS_COEFF_MT8195,
+ .glb_fuse_map = (const struct svs_fusemap[GLB_MAX]) {
+ /* FT_PGM and VMIN not present */
+ { -1, 0 }, { -1, 0 }
+ }
+};
+
+static const struct svs_platform_data svs_mt8186_platform_data = {
+ .name = "mt8186-svs",
+ .banks = svs_mt8186_banks,
+ .efuse_parsing = svs_common_parse_efuse,
+ .probe = svs_mt8192_platform_probe,
+ .regs = svs_regs_v2,
+ .bank_max = ARRAY_SIZE(svs_mt8186_banks),
+ .ts_coeff = SVSB_TS_COEFF_MT8186,
+ .glb_fuse_map = (const struct svs_fusemap[GLB_MAX]) {
+ /* FT_PGM and VMIN not present */
+ { -1, 0 }, { -1, 0 }
+ }
};
static const struct svs_platform_data svs_mt8183_platform_data = {
@@ -2313,133 +2821,123 @@ static const struct svs_platform_data svs_mt8183_platform_data = {
.probe = svs_mt8183_platform_probe,
.regs = svs_regs_v2,
.bank_max = ARRAY_SIZE(svs_mt8183_banks),
+ .glb_fuse_map = (const struct svs_fusemap[GLB_MAX]) {
+ /* VMIN not present */
+ { 0, 4 }, { -1, 0 }
+ }
};
static const struct of_device_id svs_of_match[] = {
- {
- .compatible = "mediatek,mt8192-svs",
- .data = &svs_mt8192_platform_data,
- }, {
- .compatible = "mediatek,mt8183-svs",
- .data = &svs_mt8183_platform_data,
- }, {
- /* Sentinel */
- },
+ { .compatible = "mediatek,mt8195-svs", .data = &svs_mt8195_platform_data },
+ { .compatible = "mediatek,mt8192-svs", .data = &svs_mt8192_platform_data },
+ { .compatible = "mediatek,mt8188-svs", .data = &svs_mt8188_platform_data },
+ { .compatible = "mediatek,mt8186-svs", .data = &svs_mt8186_platform_data },
+ { .compatible = "mediatek,mt8183-svs", .data = &svs_mt8183_platform_data },
+ { /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, svs_of_match);
-static struct svs_platform *svs_platform_probe(struct platform_device *pdev)
+static int svs_probe(struct platform_device *pdev)
{
struct svs_platform *svsp;
const struct svs_platform_data *svsp_data;
- int ret;
+ int ret, svsp_irq;
svsp_data = of_device_get_match_data(&pdev->dev);
- if (!svsp_data) {
- dev_err(&pdev->dev, "no svs platform data?\n");
- return ERR_PTR(-EPERM);
- }
svsp = devm_kzalloc(&pdev->dev, sizeof(*svsp), GFP_KERNEL);
if (!svsp)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
svsp->dev = &pdev->dev;
- svsp->name = svsp_data->name;
svsp->banks = svsp_data->banks;
- svsp->efuse_parsing = svsp_data->efuse_parsing;
- svsp->probe = svsp_data->probe;
svsp->regs = svsp_data->regs;
svsp->bank_max = svsp_data->bank_max;
+ svsp->ts_coeff = svsp_data->ts_coeff;
- ret = svsp->probe(svsp);
+ ret = svsp_data->probe(svsp);
if (ret)
- return ERR_PTR(ret);
-
- return svsp;
-}
+ return ret;
-static int svs_probe(struct platform_device *pdev)
-{
- struct svs_platform *svsp;
- int svsp_irq, ret;
+ ret = svs_get_efuse_data(svsp, "svs-calibration-data",
+ &svsp->efuse, &svsp->efuse_max);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Cannot read SVS calibration\n");
- svsp = svs_platform_probe(pdev);
- if (IS_ERR(svsp))
- return PTR_ERR(svsp);
+ ret = svs_get_efuse_data(svsp, "t-calibration-data",
+ &svsp->tefuse, &svsp->tefuse_max);
+ if (ret) {
+ dev_err_probe(&pdev->dev, ret, "Cannot read SVS-Thermal calibration\n");
+ goto svs_probe_free_efuse;
+ }
- if (!svs_is_efuse_data_correct(svsp)) {
- dev_notice(svsp->dev, "efuse data isn't correct\n");
- ret = -EPERM;
- goto svs_probe_free_resource;
+ if (!svsp_data->efuse_parsing(svsp, svsp_data)) {
+ ret = dev_err_probe(svsp->dev, -EINVAL, "efuse data parsing failed\n");
+ goto svs_probe_free_tefuse;
}
ret = svs_bank_resource_setup(svsp);
if (ret) {
- dev_err(svsp->dev, "svs bank resource setup fail: %d\n", ret);
- goto svs_probe_free_resource;
+ dev_err_probe(svsp->dev, ret, "svs bank resource setup fail\n");
+ goto svs_probe_free_tefuse;
}
svsp_irq = platform_get_irq(pdev, 0);
if (svsp_irq < 0) {
ret = svsp_irq;
- goto svs_probe_free_resource;
- }
-
- ret = devm_request_threaded_irq(svsp->dev, svsp_irq, NULL, svs_isr,
- IRQF_ONESHOT, svsp->name, svsp);
- if (ret) {
- dev_err(svsp->dev, "register irq(%d) failed: %d\n",
- svsp_irq, ret);
- goto svs_probe_free_resource;
+ goto svs_probe_free_tefuse;
}
svsp->main_clk = devm_clk_get(svsp->dev, "main");
if (IS_ERR(svsp->main_clk)) {
- dev_err(svsp->dev, "failed to get clock: %ld\n",
- PTR_ERR(svsp->main_clk));
- ret = PTR_ERR(svsp->main_clk);
- goto svs_probe_free_resource;
+ ret = dev_err_probe(svsp->dev, PTR_ERR(svsp->main_clk),
+ "failed to get clock\n");
+ goto svs_probe_free_tefuse;
}
ret = clk_prepare_enable(svsp->main_clk);
if (ret) {
- dev_err(svsp->dev, "cannot enable main clk: %d\n", ret);
- goto svs_probe_free_resource;
+ dev_err_probe(svsp->dev, ret, "cannot enable main clk\n");
+ goto svs_probe_free_tefuse;
}
svsp->base = of_iomap(svsp->dev->of_node, 0);
if (IS_ERR_OR_NULL(svsp->base)) {
- dev_err(svsp->dev, "cannot find svs register base\n");
- ret = -EINVAL;
+ ret = dev_err_probe(svsp->dev, -EINVAL, "cannot find svs register base\n");
goto svs_probe_clk_disable;
}
+ ret = devm_request_threaded_irq(svsp->dev, svsp_irq, NULL, svs_isr,
+ IRQF_ONESHOT, svsp_data->name, svsp);
+ if (ret) {
+ dev_err_probe(svsp->dev, ret, "register irq(%d) failed\n", svsp_irq);
+ goto svs_probe_iounmap;
+ }
+
ret = svs_start(svsp);
if (ret) {
- dev_err(svsp->dev, "svs start fail: %d\n", ret);
+ dev_err_probe(svsp->dev, ret, "svs start fail\n");
goto svs_probe_iounmap;
}
+#ifdef CONFIG_DEBUG_FS
ret = svs_create_debug_cmds(svsp);
if (ret) {
- dev_err(svsp->dev, "svs create debug cmds fail: %d\n", ret);
+ dev_err_probe(svsp->dev, ret, "svs create debug cmds fail\n");
goto svs_probe_iounmap;
}
+#endif
return 0;
svs_probe_iounmap:
iounmap(svsp->base);
-
svs_probe_clk_disable:
clk_disable_unprepare(svsp->main_clk);
-
-svs_probe_free_resource:
- if (!IS_ERR_OR_NULL(svsp->efuse))
- kfree(svsp->efuse);
- if (!IS_ERR_OR_NULL(svsp->tefuse))
- kfree(svsp->tefuse);
-
+svs_probe_free_tefuse:
+ kfree(svsp->tefuse);
+svs_probe_free_efuse:
+ kfree(svsp->efuse);
return ret;
}
@@ -2457,5 +2955,6 @@ static struct platform_driver svs_driver = {
module_platform_driver(svs_driver);
MODULE_AUTHOR("Roger Lu <roger.lu@mediatek.com>");
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
MODULE_DESCRIPTION("MediaTek SVS driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/soc/microchip/Kconfig b/drivers/soc/microchip/Kconfig
index eb656b33156b..bcf554602561 100644
--- a/drivers/soc/microchip/Kconfig
+++ b/drivers/soc/microchip/Kconfig
@@ -1,6 +1,7 @@
config POLARFIRE_SOC_SYS_CTRL
- tristate "POLARFIRE_SOC_SYS_CTRL"
+ tristate "Microchip PolarFire SoC (MPFS) system controller support"
depends on POLARFIRE_SOC_MAILBOX
+ depends on MTD
help
This driver adds support for the PolarFire SoC (MPFS) system controller.
@@ -8,3 +9,15 @@ config POLARFIRE_SOC_SYS_CTRL
module will be called mpfs_system_controller.
If unsure, say N.
+
+config POLARFIRE_SOC_SYSCONS
+ bool "PolarFire SoC (MPFS) syscon drivers"
+ default y
+ depends on ARCH_MICROCHIP
+ select MFD_CORE
+ help
+ These drivers add support for the syscons on PolarFire SoC (MPFS).
+ Without these drivers core parts of the kernel such as clocks
+ and resets will not function correctly.
+
+ If unsure, and on a PolarFire SoC, say y.
diff --git a/drivers/soc/microchip/Makefile b/drivers/soc/microchip/Makefile
index 14489919fe4b..1a3a1594b089 100644
--- a/drivers/soc/microchip/Makefile
+++ b/drivers/soc/microchip/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_POLARFIRE_SOC_SYS_CTRL) += mpfs-sys-controller.o
+obj-$(CONFIG_POLARFIRE_SOC_SYSCONS) += mpfs-control-scb.o mpfs-mss-top-sysreg.o
diff --git a/drivers/soc/microchip/mpfs-control-scb.c b/drivers/soc/microchip/mpfs-control-scb.c
new file mode 100644
index 000000000000..f0b84b1f49cb
--- /dev/null
+++ b/drivers/soc/microchip/mpfs-control-scb.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/array_size.h>
+#include <linux/of.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/syscon.h>
+#include <linux/platform_device.h>
+
+static const struct mfd_cell mpfs_control_scb_devs[] = {
+ MFD_CELL_NAME("mpfs-tvs"),
+};
+
+static int mpfs_control_scb_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ return mfd_add_devices(dev, PLATFORM_DEVID_NONE, mpfs_control_scb_devs,
+ ARRAY_SIZE(mpfs_control_scb_devs), NULL, 0, NULL);
+}
+
+static const struct of_device_id mpfs_control_scb_of_match[] = {
+ { .compatible = "microchip,mpfs-control-scb", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mpfs_control_scb_of_match);
+
+static struct platform_driver mpfs_control_scb_driver = {
+ .driver = {
+ .name = "mpfs-control-scb",
+ .of_match_table = mpfs_control_scb_of_match,
+ },
+ .probe = mpfs_control_scb_probe,
+};
+module_platform_driver(mpfs_control_scb_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");
+MODULE_DESCRIPTION("PolarFire SoC control scb driver");
diff --git a/drivers/soc/microchip/mpfs-mss-top-sysreg.c b/drivers/soc/microchip/mpfs-mss-top-sysreg.c
new file mode 100644
index 000000000000..b2244e44ff0f
--- /dev/null
+++ b/drivers/soc/microchip/mpfs-mss-top-sysreg.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/array_size.h>
+#include <linux/of.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+static const struct mfd_cell mpfs_mss_top_sysreg_devs[] = {
+ MFD_CELL_NAME("mpfs-reset"),
+};
+
+static int mpfs_mss_top_sysreg_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ ret = mfd_add_devices(dev, PLATFORM_DEVID_NONE, mpfs_mss_top_sysreg_devs,
+ ARRAY_SIZE(mpfs_mss_top_sysreg_devs) , NULL, 0, NULL);
+ if (ret)
+ return ret;
+
+ return devm_of_platform_populate(dev);
+}
+
+static const struct of_device_id mpfs_mss_top_sysreg_of_match[] = {
+ { .compatible = "microchip,mpfs-mss-top-sysreg", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mpfs_mss_top_sysreg_of_match);
+
+static struct platform_driver mpfs_mss_top_sysreg_driver = {
+ .driver = {
+ .name = "mpfs-mss-top-sysreg",
+ .of_match_table = mpfs_mss_top_sysreg_of_match,
+ },
+ .probe = mpfs_mss_top_sysreg_probe,
+};
+module_platform_driver(mpfs_mss_top_sysreg_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");
+MODULE_DESCRIPTION("PolarFire SoC mss top sysreg driver");
diff --git a/drivers/soc/microchip/mpfs-sys-controller.c b/drivers/soc/microchip/mpfs-sys-controller.c
index 6e20207b5756..30bc45d17d34 100644
--- a/drivers/soc/microchip/mpfs-sys-controller.c
+++ b/drivers/soc/microchip/mpfs-sys-controller.c
@@ -11,52 +11,76 @@
#include <linux/slab.h>
#include <linux/kref.h>
#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/mtd/mtd.h>
+#include <linux/spi/spi.h>
#include <linux/interrupt.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
#include <linux/mailbox_client.h>
#include <linux/platform_device.h>
#include <soc/microchip/mpfs.h>
+/*
+ * This timeout must be long, as some services (example: image authentication)
+ * take significant time to complete
+ */
+#define MPFS_SYS_CTRL_TIMEOUT_MS 30000
+
static DEFINE_MUTEX(transaction_lock);
struct mpfs_sys_controller {
struct mbox_client client;
struct mbox_chan *chan;
struct completion c;
+ struct mtd_info *flash;
struct kref consumers;
};
int mpfs_blocking_transaction(struct mpfs_sys_controller *sys_controller, struct mpfs_mss_msg *msg)
{
- int ret, err;
+ unsigned long timeout = msecs_to_jiffies(MPFS_SYS_CTRL_TIMEOUT_MS);
+ int ret;
- err = mutex_lock_interruptible(&transaction_lock);
- if (err)
- return err;
+ ret = mutex_lock_interruptible(&transaction_lock);
+ if (ret)
+ return ret;
reinit_completion(&sys_controller->c);
ret = mbox_send_message(sys_controller->chan, msg);
- if (ret >= 0) {
- if (wait_for_completion_timeout(&sys_controller->c, HZ)) {
- ret = 0;
- } else {
- ret = -ETIMEDOUT;
- dev_warn(sys_controller->client.dev,
- "MPFS sys controller transaction timeout\n");
- }
+ if (ret < 0) {
+ dev_warn(sys_controller->client.dev, "MPFS sys controller service timeout\n");
+ goto out;
+ }
+
+ /*
+ * Unfortunately, the system controller will only deliver an interrupt
+ * if a service succeeds. mbox_send_message() will block until the busy
+ * flag is gone. If the busy flag is gone but no interrupt has arrived
+ * to trigger the rx callback then the service can be deemed to have
+ * failed.
+ * The caller can then interrogate msg::response::resp_status to
+ * determine the cause of the failure.
+ * mbox_send_message() returns positive integers in the success path, so
+ * ret needs to be cleared if we do get an interrupt.
+ */
+ if (!wait_for_completion_timeout(&sys_controller->c, timeout)) {
+ ret = -EBADMSG;
+ dev_warn(sys_controller->client.dev,
+ "MPFS sys controller service failed with status: %d\n",
+ msg->response->resp_status);
} else {
- dev_err(sys_controller->client.dev,
- "mpfs sys controller transaction returned %d\n", ret);
+ ret = 0;
}
+out:
mutex_unlock(&transaction_lock);
return ret;
}
EXPORT_SYMBOL(mpfs_blocking_transaction);
-static void rx_callback(struct mbox_client *client, void *msg)
+static void mpfs_sys_controller_rx_callback(struct mbox_client *client, void *msg)
{
struct mpfs_sys_controller *sys_controller =
container_of(client, struct mpfs_sys_controller, client);
@@ -66,8 +90,8 @@ static void rx_callback(struct mbox_client *client, void *msg)
static void mpfs_sys_controller_delete(struct kref *kref)
{
- struct mpfs_sys_controller *sys_controller = container_of(kref, struct mpfs_sys_controller,
- consumers);
+ struct mpfs_sys_controller *sys_controller =
+ container_of(kref, struct mpfs_sys_controller, consumers);
mbox_free_channel(sys_controller->chan);
kfree(sys_controller);
@@ -80,6 +104,12 @@ static void mpfs_sys_controller_put(void *data)
kref_put(&sys_controller->consumers, mpfs_sys_controller_delete);
}
+struct mtd_info *mpfs_sys_controller_get_flash(struct mpfs_sys_controller *mpfs_client)
+{
+ return mpfs_client->flash;
+}
+EXPORT_SYMBOL(mpfs_sys_controller_get_flash);
+
static struct platform_device subdevs[] = {
{
.name = "mpfs-rng",
@@ -88,22 +118,38 @@ static struct platform_device subdevs[] = {
{
.name = "mpfs-generic-service",
.id = -1,
- }
+ },
+ {
+ .name = "mpfs-auto-update",
+ .id = -1,
+ },
};
static int mpfs_sys_controller_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mpfs_sys_controller *sys_controller;
+ struct device_node *np;
int i, ret;
sys_controller = kzalloc(sizeof(*sys_controller), GFP_KERNEL);
if (!sys_controller)
return -ENOMEM;
+ np = of_parse_phandle(dev->of_node, "microchip,bitstream-flash", 0);
+ if (!np)
+ goto no_flash;
+
+ sys_controller->flash = of_get_mtd_device_by_node(np);
+ of_node_put(np);
+ if (IS_ERR(sys_controller->flash))
+ return dev_err_probe(dev, PTR_ERR(sys_controller->flash), "Failed to get flash\n");
+
+no_flash:
sys_controller->client.dev = dev;
- sys_controller->client.rx_callback = rx_callback;
+ sys_controller->client.rx_callback = mpfs_sys_controller_rx_callback;
sys_controller->client.tx_block = 1U;
+ sys_controller->client.tx_tout = msecs_to_jiffies(MPFS_SYS_CTRL_TIMEOUT_MS);
sys_controller->chan = mbox_request_channel(&sys_controller->client, 0);
if (IS_ERR(sys_controller->chan)) {
@@ -118,7 +164,6 @@ static int mpfs_sys_controller_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, sys_controller);
- dev_info(&pdev->dev, "Registered MPFS system controller\n");
for (i = 0; i < ARRAY_SIZE(subdevs); i++) {
subdevs[i].dev.parent = dev;
@@ -126,16 +171,16 @@ static int mpfs_sys_controller_probe(struct platform_device *pdev)
dev_warn(dev, "Error registering sub device %s\n", subdevs[i].name);
}
+ dev_info(&pdev->dev, "Registered MPFS system controller\n");
+
return 0;
}
-static int mpfs_sys_controller_remove(struct platform_device *pdev)
+static void mpfs_sys_controller_remove(struct platform_device *pdev)
{
struct mpfs_sys_controller *sys_controller = platform_get_drvdata(pdev);
mpfs_sys_controller_put(sys_controller);
-
- return 0;
}
static const struct of_device_id mpfs_sys_controller_of_match[] = {
diff --git a/drivers/soc/nuvoton/Kconfig b/drivers/soc/nuvoton/Kconfig
new file mode 100644
index 000000000000..df46182088ec
--- /dev/null
+++ b/drivers/soc/nuvoton/Kconfig
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+menuconfig WPCM450_SOC
+ tristate "Nuvoton WPCM450 SoC driver"
+ default y if ARCH_WPCM450
+ select SOC_BUS
+ help
+ Say Y here to compile the SoC information driver for Nuvoton
+ WPCM450 SoCs.
+
+ This driver provides information such as the SoC model and
+ revision.
diff --git a/drivers/soc/nuvoton/Makefile b/drivers/soc/nuvoton/Makefile
new file mode 100644
index 000000000000..e30317b4e829
--- /dev/null
+++ b/drivers/soc/nuvoton/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_WPCM450_SOC) += wpcm450-soc.o
diff --git a/drivers/soc/nuvoton/wpcm450-soc.c b/drivers/soc/nuvoton/wpcm450-soc.c
new file mode 100644
index 000000000000..c5e0d11c383b
--- /dev/null
+++ b/drivers/soc/nuvoton/wpcm450-soc.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Nuvoton WPCM450 SoC Identification
+ *
+ * Copyright (C) 2022 Jonathan Neuschäfer
+ */
+
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/sys_soc.h>
+
+#define GCR_PDID 0
+#define PDID_CHIP(x) ((x) & 0x00ffffff)
+#define CHIP_WPCM450 0x926450
+#define PDID_REV(x) ((x) >> 24)
+
+struct revision {
+ u8 number;
+ const char *name;
+};
+
+static const struct revision revisions[] __initconst = {
+ { 0x00, "Z1" },
+ { 0x03, "Z2" },
+ { 0x04, "Z21" },
+ { 0x08, "A1" },
+ { 0x09, "A2" },
+ { 0x0a, "A3" },
+ {}
+};
+
+static const char * __init get_revision(unsigned int rev)
+{
+ int i;
+
+ for (i = 0; revisions[i].name; i++)
+ if (revisions[i].number == rev)
+ return revisions[i].name;
+ return NULL;
+}
+
+static struct soc_device_attribute *wpcm450_attr;
+static struct soc_device *wpcm450_soc;
+
+static int __init wpcm450_soc_init(void)
+{
+ struct soc_device_attribute *attr;
+ struct soc_device *soc;
+ const char *revision;
+ struct regmap *gcr;
+ u32 pdid;
+ int ret;
+
+ if (!of_machine_is_compatible("nuvoton,wpcm450"))
+ return 0;
+
+ gcr = syscon_regmap_lookup_by_compatible("nuvoton,wpcm450-gcr");
+ if (IS_ERR(gcr))
+ return PTR_ERR(gcr);
+ ret = regmap_read(gcr, GCR_PDID, &pdid);
+ if (ret)
+ return ret;
+
+ if (PDID_CHIP(pdid) != CHIP_WPCM450) {
+ pr_warn("Unknown chip ID in GCR.PDID: 0x%06x\n", PDID_CHIP(pdid));
+ return -ENODEV;
+ }
+
+ revision = get_revision(PDID_REV(pdid));
+ if (!revision) {
+ pr_warn("Unknown chip revision in GCR.PDID: 0x%02x\n", PDID_REV(pdid));
+ return -ENODEV;
+ }
+
+ attr = kzalloc(sizeof(*attr), GFP_KERNEL);
+ if (!attr)
+ return -ENOMEM;
+
+ attr->family = "Nuvoton NPCM";
+ attr->soc_id = "WPCM450";
+ attr->revision = revision;
+ soc = soc_device_register(attr);
+ if (IS_ERR(soc)) {
+ kfree(attr);
+ pr_warn("Could not register SoC device\n");
+ return PTR_ERR(soc);
+ }
+
+ wpcm450_soc = soc;
+ wpcm450_attr = attr;
+ return 0;
+}
+module_init(wpcm450_soc_init);
+
+static void __exit wpcm450_soc_exit(void)
+{
+ if (wpcm450_soc) {
+ soc_device_unregister(wpcm450_soc);
+ wpcm450_soc = NULL;
+ kfree(wpcm450_attr);
+ }
+}
+module_exit(wpcm450_soc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jonathan Neuschäfer");
+MODULE_DESCRIPTION("Nuvoton WPCM450 SoC Identification driver");
diff --git a/drivers/soc/pxa/ssp.c b/drivers/soc/pxa/ssp.c
index bd029e838241..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>
@@ -152,11 +152,11 @@ static int pxa_ssp_probe(struct platform_device *pdev)
if (dev->of_node) {
const struct of_device_id *id =
of_match_device(of_match_ptr(pxa_ssp_of_ids), dev);
- ssp->type = (int) id->data;
+ ssp->type = (uintptr_t) id->data;
} else {
const struct platform_device_id *id =
platform_get_device_id(pdev);
- ssp->type = (int) id->driver_data;
+ ssp->type = id->driver_data;
/* PXA2xx/3xx SSP ports starts from 1 and the internal pdev->id
* starts from 0, do a translation here
@@ -176,15 +176,13 @@ static int pxa_ssp_probe(struct platform_device *pdev)
return 0;
}
-static int pxa_ssp_remove(struct platform_device *pdev)
+static void pxa_ssp_remove(struct platform_device *pdev)
{
struct ssp_device *ssp = platform_get_drvdata(pdev);
mutex_lock(&ssp_lock);
list_del(&ssp->node);
mutex_unlock(&ssp_lock);
-
- return 0;
}
static const struct platform_device_id ssp_id_table[] = {
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index ae504c43d9e7..2caadbbcf830 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -26,22 +26,6 @@ config QCOM_COMMAND_DB
resource on a RPM-hardened platform must use this database to get
SoC specific identifier and information for the shared resources.
-config QCOM_CPR
- tristate "QCOM Core Power Reduction (CPR) support"
- depends on ARCH_QCOM && HAS_IOMEM
- select PM_OPP
- select REGMAP
- help
- Say Y here to enable support for the CPR hardware found on Qualcomm
- SoCs like QCS404.
-
- This driver populates CPU OPPs tables and makes adjustments to the
- tables based on feedback from the CPR hardware. If you want to do
- CPUfrequency scaling say Y here.
-
- To compile this driver as a module, choose M here: the module will
- be called qcom-cpr
-
config QCOM_GENI_SE
tristate "QCOM GENI Serial Engine Driver"
depends on ARCH_QCOM || COMPILE_TEST
@@ -72,7 +56,7 @@ config QCOM_LLCC
config QCOM_KRYO_L2_ACCESSORS
bool
- depends on ARCH_QCOM && ARM64 || COMPILE_TEST
+ depends on (ARCH_QCOM || COMPILE_TEST) && ARM64
config QCOM_MDT_LOADER
tristate
@@ -88,17 +72,74 @@ 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
+ depends on EVENT_TRACING
+ help
+ The Qualcomm PMIC PDCharger ULOG driver provides access to logs of
+ the ADSP firmware PDCharger module in charge of Battery and Power
+ Delivery on modern systems.
+
+ Say yes here to support PDCharger ULOG event tracing on modern
+ Qualcomm platforms.
+
+config QCOM_PMIC_GLINK
+ tristate "Qualcomm PMIC GLINK driver"
+ depends on RPMSG
+ depends on TYPEC
+ depends on DRM
+ depends on NET
+ depends on OF
+ select AUXILIARY_BUS
+ select QCOM_PDR_HELPERS
+ select DRM_AUX_HPD_BRIDGE
+ help
+ The Qualcomm PMIC GLINK driver provides access, over GLINK, to the
+ USB and battery firmware running on one of the coprocessors in
+ several modern Qualcomm platforms.
+
+ Say yes here to support USB-C and battery status on modern Qualcomm
+ platforms.
config QCOM_QMI_HELPERS
tristate
depends on NET
+config QCOM_RAMP_CTRL
+ tristate "Qualcomm Ramp Controller driver"
+ depends on ARCH_QCOM || COMPILE_TEST
+ help
+ The Ramp Controller is used to program the sequence ID for pulse
+ swallowing, enable sequence and link sequence IDs for the CPU
+ cores on some Qualcomm SoCs.
+ Say y here to enable support for the ramp controller.
+
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
@@ -108,6 +149,17 @@ config QCOM_RMTFS_MEM
Say y here if you intend to boot the modem remoteproc.
+config QCOM_RPM_MASTER_STATS
+ tristate "Qualcomm RPM Master stats"
+ depends on ARCH_QCOM || COMPILE_TEST
+ help
+ The RPM Master sleep stats driver provides detailed per-subsystem
+ sleep/wake data, read from the RPM message RAM. It can be used to
+ assess whether all the low-power modes available are entered as
+ expected or to check which part of the SoC prevents it from sleeping.
+
+ Say y here if you intend to debug or monitor platform sleep.
+
config QCOM_RPMH
tristate "Qualcomm RPM-Hardened (RPMH) Communication"
depends on ARCH_QCOM || COMPILE_TEST
@@ -119,27 +171,6 @@ config QCOM_RPMH
of hardware components aggregate requests for these resources and
help apply the aggregated state on the resource.
-config QCOM_RPMHPD
- tristate "Qualcomm RPMh Power domain driver"
- depends on QCOM_RPMH && QCOM_COMMAND_DB
- help
- QCOM RPMh Power domain driver to support power-domains with
- performance states. The driver communicates a performance state
- value to RPMh which then translates it into corresponding voltage
- for the voltage rail.
-
-config QCOM_RPMPD
- tristate "Qualcomm RPM Power domain driver"
- depends on PM && OF
- depends on QCOM_SMD_RPM
- select PM_GENERIC_DOMAINS
- select PM_GENERIC_DOMAINS_OF
- help
- QCOM RPM Power domain driver to support power-domains with
- performance states. The driver communicates a performance state
- value to RPM which then translates it into corresponding voltage
- for the voltage rail.
-
config QCOM_SMEM
tristate "Qualcomm Shared Memory Manager (SMEM)"
depends on ARCH_QCOM || COMPILE_TEST
@@ -153,6 +184,7 @@ config QCOM_SMD_RPM
tristate "Qualcomm Resource Power Manager (RPM) over SMD"
depends on ARCH_QCOM || COMPILE_TEST
depends on RPMSG
+ depends on RPMSG_QCOM_SMD || RPMSG_QCOM_SMD=n
help
If you say yes to this option, support will be included for the
Resource Power Manager system found in the Qualcomm 8974 based
@@ -179,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
@@ -207,6 +240,7 @@ config QCOM_STATS
tristate "Qualcomm Technologies, Inc. (QTI) Sleep stats driver"
depends on (ARCH_QCOM && DEBUG_FS) || COMPILE_TEST
depends on QCOM_SMEM
+ depends on QCOM_AOSS_QMP || QCOM_AOSS_QMP=n
help
Qualcomm Technologies, Inc. (QTI) Sleep stats driver to read
the shared memory exported by the remote processor related to
@@ -248,4 +282,25 @@ config QCOM_ICC_BWMON
the fixed bandwidth votes from cpufreq (CPU nodes) thus achieve high
memory throughput even with lower CPU frequencies.
+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
+
+config QCOM_UBWC_CONFIG
+ tristate
+ help
+ Most Qualcomm SoCs feature a number of Universal Bandwidth Compression
+ (UBWC) engines across various IP blocks, which need to be initialized
+ with coherent configuration data. This module functions as a single
+ source of truth for that information.
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index d66604aff2b0..b7f1d2a57367 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -1,22 +1,31 @@
# 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_CPR) += cpr.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
+CFLAGS_pmic_pdcharger_ulog.o := -I$(src)
obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o
qmi_helpers-y += qmi_encdec.o qmi_interface.o
+obj-$(CONFIG_QCOM_RAMP_CTRL) += ramp_controller.o
obj-$(CONFIG_QCOM_RMTFS_MEM) += rmtfs_mem.o
+obj-$(CONFIG_QCOM_RPM_MASTER_STATS) += rpm_master_stats.o
obj-$(CONFIG_QCOM_RPMH) += qcom_rpmh.o
qcom_rpmh-y += rpmh-rsc.o
qcom_rpmh-y += rpmh.o
-obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.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
@@ -25,7 +34,9 @@ obj-$(CONFIG_QCOM_STATS) += qcom_stats.o
obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
obj-$(CONFIG_QCOM_APR) += apr.o
obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o
-obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o
-obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o
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
+obj-$(CONFIG_QCOM_UBWC_CONFIG) += ubwc_config.o
diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c
index d51abb462ae5..a956c407ce03 100644
--- a/drivers/soc/qcom/apr.c
+++ b/drivers/soc/qcom/apr.c
@@ -41,7 +41,7 @@ struct packet_router {
struct apr_rx_buf {
struct list_head node;
int len;
- uint8_t buf[];
+ uint8_t buf[] __counted_by(len);
};
/**
@@ -171,7 +171,7 @@ static int apr_callback(struct rpmsg_device *rpdev, void *buf,
return -EINVAL;
}
- abuf = kzalloc(sizeof(*abuf) + len, GFP_ATOMIC);
+ abuf = kzalloc(struct_size(abuf, buf, len), GFP_ATOMIC);
if (!abuf)
return -ENOMEM;
@@ -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 */
@@ -387,9 +387,9 @@ static void apr_device_remove(struct device *dev)
spin_unlock(&apr->svcs_lock);
}
-static int apr_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int apr_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct apr_device *adev = to_apr_device(dev);
+ const struct apr_device *adev = to_apr_device(dev);
int ret;
ret = of_device_uevent_modalias(dev, env);
@@ -399,7 +399,7 @@ static int apr_uevent(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 33856abd560c..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
@@ -133,7 +139,7 @@ int cmd_db_ready(void)
return 0;
}
-EXPORT_SYMBOL(cmd_db_ready);
+EXPORT_SYMBOL_GPL(cmd_db_ready);
static int cmd_db_get_header(const char *id, const struct entry_header **eh,
const struct rsc_hdr **rh)
@@ -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];
@@ -193,7 +194,7 @@ u32 cmd_db_read_addr(const char *id)
return ret < 0 ? 0 : le32_to_cpu(ent->addr);
}
-EXPORT_SYMBOL(cmd_db_read_addr);
+EXPORT_SYMBOL_GPL(cmd_db_read_addr);
/**
* cmd_db_read_aux_data() - Query command db for aux data.
@@ -218,7 +219,31 @@ const void *cmd_db_read_aux_data(const char *id, size_t *len)
return rsc_offset(rsc_hdr, ent);
}
-EXPORT_SYMBOL(cmd_db_read_aux_data);
+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
@@ -240,7 +265,7 @@ enum cmd_db_hw_type cmd_db_read_slave_id(const char *id)
addr = le32_to_cpu(ent->addr);
return (addr >> SLAVE_ID_SHIFT) & SLAVE_ID_MASK;
}
-EXPORT_SYMBOL(cmd_db_read_slave_id);
+EXPORT_SYMBOL_GPL(cmd_db_read_slave_id);
#ifdef CONFIG_DEBUG_FS
static int cmd_db_debugfs_dump(struct seq_file *seq, void *p)
@@ -284,7 +309,7 @@ static int cmd_db_debugfs_dump(struct seq_file *seq, void *p)
ent = rsc_to_entry_header(rsc);
for (j = 0; j < le16_to_cpu(rsc->cnt); j++, ent++) {
seq_printf(seq, "0x%05x: %*pEp", le32_to_cpu(ent->addr),
- (int)sizeof(ent->id), ent->id);
+ (int)strnlen(ent->id, sizeof(ent->id)), ent->id);
len = le16_to_cpu(ent->len);
if (len) {
@@ -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/cpr.c b/drivers/soc/qcom/cpr.c
deleted file mode 100644
index 144ea68e0920..000000000000
--- a/drivers/soc/qcom/cpr.c
+++ /dev/null
@@ -1,1757 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
- * Copyright (c) 2019, Linaro Limited
- */
-
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/debugfs.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/bitops.h>
-#include <linux/slab.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <linux/pm_opp.h>
-#include <linux/interrupt.h>
-#include <linux/regmap.h>
-#include <linux/mfd/syscon.h>
-#include <linux/regulator/consumer.h>
-#include <linux/clk.h>
-#include <linux/nvmem-consumer.h>
-
-/* Register Offsets for RB-CPR and Bit Definitions */
-
-/* RBCPR Version Register */
-#define REG_RBCPR_VERSION 0
-#define RBCPR_VER_2 0x02
-#define FLAGS_IGNORE_1ST_IRQ_STATUS BIT(0)
-
-/* RBCPR Gate Count and Target Registers */
-#define REG_RBCPR_GCNT_TARGET(n) (0x60 + 4 * (n))
-
-#define RBCPR_GCNT_TARGET_TARGET_SHIFT 0
-#define RBCPR_GCNT_TARGET_TARGET_MASK GENMASK(11, 0)
-#define RBCPR_GCNT_TARGET_GCNT_SHIFT 12
-#define RBCPR_GCNT_TARGET_GCNT_MASK GENMASK(9, 0)
-
-/* RBCPR Timer Control */
-#define REG_RBCPR_TIMER_INTERVAL 0x44
-#define REG_RBIF_TIMER_ADJUST 0x4c
-
-#define RBIF_TIMER_ADJ_CONS_UP_MASK GENMASK(3, 0)
-#define RBIF_TIMER_ADJ_CONS_UP_SHIFT 0
-#define RBIF_TIMER_ADJ_CONS_DOWN_MASK GENMASK(3, 0)
-#define RBIF_TIMER_ADJ_CONS_DOWN_SHIFT 4
-#define RBIF_TIMER_ADJ_CLAMP_INT_MASK GENMASK(7, 0)
-#define RBIF_TIMER_ADJ_CLAMP_INT_SHIFT 8
-
-/* RBCPR Config Register */
-#define REG_RBIF_LIMIT 0x48
-#define RBIF_LIMIT_CEILING_MASK GENMASK(5, 0)
-#define RBIF_LIMIT_CEILING_SHIFT 6
-#define RBIF_LIMIT_FLOOR_BITS 6
-#define RBIF_LIMIT_FLOOR_MASK GENMASK(5, 0)
-
-#define RBIF_LIMIT_CEILING_DEFAULT RBIF_LIMIT_CEILING_MASK
-#define RBIF_LIMIT_FLOOR_DEFAULT 0
-
-#define REG_RBIF_SW_VLEVEL 0x94
-#define RBIF_SW_VLEVEL_DEFAULT 0x20
-
-#define REG_RBCPR_STEP_QUOT 0x80
-#define RBCPR_STEP_QUOT_STEPQUOT_MASK GENMASK(7, 0)
-#define RBCPR_STEP_QUOT_IDLE_CLK_MASK GENMASK(3, 0)
-#define RBCPR_STEP_QUOT_IDLE_CLK_SHIFT 8
-
-/* RBCPR Control Register */
-#define REG_RBCPR_CTL 0x90
-
-#define RBCPR_CTL_LOOP_EN BIT(0)
-#define RBCPR_CTL_TIMER_EN BIT(3)
-#define RBCPR_CTL_SW_AUTO_CONT_ACK_EN BIT(5)
-#define RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN BIT(6)
-#define RBCPR_CTL_COUNT_MODE BIT(10)
-#define RBCPR_CTL_UP_THRESHOLD_MASK GENMASK(3, 0)
-#define RBCPR_CTL_UP_THRESHOLD_SHIFT 24
-#define RBCPR_CTL_DN_THRESHOLD_MASK GENMASK(3, 0)
-#define RBCPR_CTL_DN_THRESHOLD_SHIFT 28
-
-/* RBCPR Ack/Nack Response */
-#define REG_RBIF_CONT_ACK_CMD 0x98
-#define REG_RBIF_CONT_NACK_CMD 0x9c
-
-/* RBCPR Result status Register */
-#define REG_RBCPR_RESULT_0 0xa0
-
-#define RBCPR_RESULT0_BUSY_SHIFT 19
-#define RBCPR_RESULT0_BUSY_MASK BIT(RBCPR_RESULT0_BUSY_SHIFT)
-#define RBCPR_RESULT0_ERROR_LT0_SHIFT 18
-#define RBCPR_RESULT0_ERROR_SHIFT 6
-#define RBCPR_RESULT0_ERROR_MASK GENMASK(11, 0)
-#define RBCPR_RESULT0_ERROR_STEPS_SHIFT 2
-#define RBCPR_RESULT0_ERROR_STEPS_MASK GENMASK(3, 0)
-#define RBCPR_RESULT0_STEP_UP_SHIFT 1
-
-/* RBCPR Interrupt Control Register */
-#define REG_RBIF_IRQ_EN(n) (0x100 + 4 * (n))
-#define REG_RBIF_IRQ_CLEAR 0x110
-#define REG_RBIF_IRQ_STATUS 0x114
-
-#define CPR_INT_DONE BIT(0)
-#define CPR_INT_MIN BIT(1)
-#define CPR_INT_DOWN BIT(2)
-#define CPR_INT_MID BIT(3)
-#define CPR_INT_UP BIT(4)
-#define CPR_INT_MAX BIT(5)
-#define CPR_INT_CLAMP BIT(6)
-#define CPR_INT_ALL (CPR_INT_DONE | CPR_INT_MIN | CPR_INT_DOWN | \
- CPR_INT_MID | CPR_INT_UP | CPR_INT_MAX | CPR_INT_CLAMP)
-#define CPR_INT_DEFAULT (CPR_INT_UP | CPR_INT_DOWN)
-
-#define CPR_NUM_RING_OSC 8
-
-/* CPR eFuse parameters */
-#define CPR_FUSE_TARGET_QUOT_BITS_MASK GENMASK(11, 0)
-
-#define CPR_FUSE_MIN_QUOT_DIFF 50
-
-#define FUSE_REVISION_UNKNOWN (-1)
-
-enum voltage_change_dir {
- NO_CHANGE,
- DOWN,
- UP,
-};
-
-struct cpr_fuse {
- char *ring_osc;
- char *init_voltage;
- char *quotient;
- char *quotient_offset;
-};
-
-struct fuse_corner_data {
- int ref_uV;
- int max_uV;
- int min_uV;
- int max_volt_scale;
- int max_quot_scale;
- /* fuse quot */
- int quot_offset;
- int quot_scale;
- int quot_adjust;
- /* fuse quot_offset */
- int quot_offset_scale;
- int quot_offset_adjust;
-};
-
-struct cpr_fuses {
- int init_voltage_step;
- int init_voltage_width;
- struct fuse_corner_data *fuse_corner_data;
-};
-
-struct corner_data {
- unsigned int fuse_corner;
- unsigned long freq;
-};
-
-struct cpr_desc {
- unsigned int num_fuse_corners;
- int min_diff_quot;
- int *step_quot;
-
- unsigned int timer_delay_us;
- unsigned int timer_cons_up;
- unsigned int timer_cons_down;
- unsigned int up_threshold;
- unsigned int down_threshold;
- unsigned int idle_clocks;
- unsigned int gcnt_us;
- unsigned int vdd_apc_step_up_limit;
- unsigned int vdd_apc_step_down_limit;
- unsigned int clamp_timer_interval;
-
- struct cpr_fuses cpr_fuses;
- bool reduce_to_fuse_uV;
- bool reduce_to_corner_uV;
-};
-
-struct acc_desc {
- unsigned int enable_reg;
- u32 enable_mask;
-
- struct reg_sequence *config;
- struct reg_sequence *settings;
- int num_regs_per_fuse;
-};
-
-struct cpr_acc_desc {
- const struct cpr_desc *cpr_desc;
- const struct acc_desc *acc_desc;
-};
-
-struct fuse_corner {
- int min_uV;
- int max_uV;
- int uV;
- int quot;
- int step_quot;
- const struct reg_sequence *accs;
- int num_accs;
- unsigned long max_freq;
- u8 ring_osc_idx;
-};
-
-struct corner {
- int min_uV;
- int max_uV;
- int uV;
- int last_uV;
- int quot_adjust;
- u32 save_ctl;
- u32 save_irq;
- unsigned long freq;
- struct fuse_corner *fuse_corner;
-};
-
-struct cpr_drv {
- unsigned int num_corners;
- unsigned int ref_clk_khz;
-
- struct generic_pm_domain pd;
- struct device *dev;
- struct device *attached_cpu_dev;
- struct mutex lock;
- void __iomem *base;
- struct corner *corner;
- struct regulator *vdd_apc;
- struct clk *cpu_clk;
- struct regmap *tcsr;
- bool loop_disabled;
- u32 gcnt;
- unsigned long flags;
-
- struct fuse_corner *fuse_corners;
- struct corner *corners;
-
- const struct cpr_desc *desc;
- const struct acc_desc *acc_desc;
- const struct cpr_fuse *cpr_fuses;
-
- struct dentry *debugfs;
-};
-
-static bool cpr_is_allowed(struct cpr_drv *drv)
-{
- return !drv->loop_disabled;
-}
-
-static void cpr_write(struct cpr_drv *drv, u32 offset, u32 value)
-{
- writel_relaxed(value, drv->base + offset);
-}
-
-static u32 cpr_read(struct cpr_drv *drv, u32 offset)
-{
- return readl_relaxed(drv->base + offset);
-}
-
-static void
-cpr_masked_write(struct cpr_drv *drv, u32 offset, u32 mask, u32 value)
-{
- u32 val;
-
- val = readl_relaxed(drv->base + offset);
- val &= ~mask;
- val |= value & mask;
- writel_relaxed(val, drv->base + offset);
-}
-
-static void cpr_irq_clr(struct cpr_drv *drv)
-{
- cpr_write(drv, REG_RBIF_IRQ_CLEAR, CPR_INT_ALL);
-}
-
-static void cpr_irq_clr_nack(struct cpr_drv *drv)
-{
- cpr_irq_clr(drv);
- cpr_write(drv, REG_RBIF_CONT_NACK_CMD, 1);
-}
-
-static void cpr_irq_clr_ack(struct cpr_drv *drv)
-{
- cpr_irq_clr(drv);
- cpr_write(drv, REG_RBIF_CONT_ACK_CMD, 1);
-}
-
-static void cpr_irq_set(struct cpr_drv *drv, u32 int_bits)
-{
- cpr_write(drv, REG_RBIF_IRQ_EN(0), int_bits);
-}
-
-static void cpr_ctl_modify(struct cpr_drv *drv, u32 mask, u32 value)
-{
- cpr_masked_write(drv, REG_RBCPR_CTL, mask, value);
-}
-
-static void cpr_ctl_enable(struct cpr_drv *drv, struct corner *corner)
-{
- u32 val, mask;
- const struct cpr_desc *desc = drv->desc;
-
- /* Program Consecutive Up & Down */
- val = desc->timer_cons_down << RBIF_TIMER_ADJ_CONS_DOWN_SHIFT;
- val |= desc->timer_cons_up << RBIF_TIMER_ADJ_CONS_UP_SHIFT;
- mask = RBIF_TIMER_ADJ_CONS_UP_MASK | RBIF_TIMER_ADJ_CONS_DOWN_MASK;
- cpr_masked_write(drv, REG_RBIF_TIMER_ADJUST, mask, val);
- cpr_masked_write(drv, REG_RBCPR_CTL,
- RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN |
- RBCPR_CTL_SW_AUTO_CONT_ACK_EN,
- corner->save_ctl);
- cpr_irq_set(drv, corner->save_irq);
-
- if (cpr_is_allowed(drv) && corner->max_uV > corner->min_uV)
- val = RBCPR_CTL_LOOP_EN;
- else
- val = 0;
- cpr_ctl_modify(drv, RBCPR_CTL_LOOP_EN, val);
-}
-
-static void cpr_ctl_disable(struct cpr_drv *drv)
-{
- cpr_irq_set(drv, 0);
- cpr_ctl_modify(drv, RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN |
- RBCPR_CTL_SW_AUTO_CONT_ACK_EN, 0);
- cpr_masked_write(drv, REG_RBIF_TIMER_ADJUST,
- RBIF_TIMER_ADJ_CONS_UP_MASK |
- RBIF_TIMER_ADJ_CONS_DOWN_MASK, 0);
- cpr_irq_clr(drv);
- cpr_write(drv, REG_RBIF_CONT_ACK_CMD, 1);
- cpr_write(drv, REG_RBIF_CONT_NACK_CMD, 1);
- cpr_ctl_modify(drv, RBCPR_CTL_LOOP_EN, 0);
-}
-
-static bool cpr_ctl_is_enabled(struct cpr_drv *drv)
-{
- u32 reg_val;
-
- reg_val = cpr_read(drv, REG_RBCPR_CTL);
- return reg_val & RBCPR_CTL_LOOP_EN;
-}
-
-static bool cpr_ctl_is_busy(struct cpr_drv *drv)
-{
- u32 reg_val;
-
- reg_val = cpr_read(drv, REG_RBCPR_RESULT_0);
- return reg_val & RBCPR_RESULT0_BUSY_MASK;
-}
-
-static void cpr_corner_save(struct cpr_drv *drv, struct corner *corner)
-{
- corner->save_ctl = cpr_read(drv, REG_RBCPR_CTL);
- corner->save_irq = cpr_read(drv, REG_RBIF_IRQ_EN(0));
-}
-
-static void cpr_corner_restore(struct cpr_drv *drv, struct corner *corner)
-{
- u32 gcnt, ctl, irq, ro_sel, step_quot;
- struct fuse_corner *fuse = corner->fuse_corner;
- const struct cpr_desc *desc = drv->desc;
- int i;
-
- ro_sel = fuse->ring_osc_idx;
- gcnt = drv->gcnt;
- gcnt |= fuse->quot - corner->quot_adjust;
-
- /* Program the step quotient and idle clocks */
- step_quot = desc->idle_clocks << RBCPR_STEP_QUOT_IDLE_CLK_SHIFT;
- step_quot |= fuse->step_quot & RBCPR_STEP_QUOT_STEPQUOT_MASK;
- cpr_write(drv, REG_RBCPR_STEP_QUOT, step_quot);
-
- /* Clear the target quotient value and gate count of all ROs */
- for (i = 0; i < CPR_NUM_RING_OSC; i++)
- cpr_write(drv, REG_RBCPR_GCNT_TARGET(i), 0);
-
- cpr_write(drv, REG_RBCPR_GCNT_TARGET(ro_sel), gcnt);
- ctl = corner->save_ctl;
- cpr_write(drv, REG_RBCPR_CTL, ctl);
- irq = corner->save_irq;
- cpr_irq_set(drv, irq);
- dev_dbg(drv->dev, "gcnt = %#08x, ctl = %#08x, irq = %#08x\n", gcnt,
- ctl, irq);
-}
-
-static void cpr_set_acc(struct regmap *tcsr, struct fuse_corner *f,
- struct fuse_corner *end)
-{
- if (f == end)
- return;
-
- if (f < end) {
- for (f += 1; f <= end; f++)
- regmap_multi_reg_write(tcsr, f->accs, f->num_accs);
- } else {
- for (f -= 1; f >= end; f--)
- regmap_multi_reg_write(tcsr, f->accs, f->num_accs);
- }
-}
-
-static int cpr_pre_voltage(struct cpr_drv *drv,
- struct fuse_corner *fuse_corner,
- enum voltage_change_dir dir)
-{
- struct fuse_corner *prev_fuse_corner = drv->corner->fuse_corner;
-
- if (drv->tcsr && dir == DOWN)
- cpr_set_acc(drv->tcsr, prev_fuse_corner, fuse_corner);
-
- return 0;
-}
-
-static int cpr_post_voltage(struct cpr_drv *drv,
- struct fuse_corner *fuse_corner,
- enum voltage_change_dir dir)
-{
- struct fuse_corner *prev_fuse_corner = drv->corner->fuse_corner;
-
- if (drv->tcsr && dir == UP)
- cpr_set_acc(drv->tcsr, prev_fuse_corner, fuse_corner);
-
- return 0;
-}
-
-static int cpr_scale_voltage(struct cpr_drv *drv, struct corner *corner,
- int new_uV, enum voltage_change_dir dir)
-{
- int ret;
- struct fuse_corner *fuse_corner = corner->fuse_corner;
-
- ret = cpr_pre_voltage(drv, fuse_corner, dir);
- if (ret)
- return ret;
-
- ret = regulator_set_voltage(drv->vdd_apc, new_uV, new_uV);
- if (ret) {
- dev_err_ratelimited(drv->dev, "failed to set apc voltage %d\n",
- new_uV);
- return ret;
- }
-
- ret = cpr_post_voltage(drv, fuse_corner, dir);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static unsigned int cpr_get_cur_perf_state(struct cpr_drv *drv)
-{
- return drv->corner ? drv->corner - drv->corners + 1 : 0;
-}
-
-static int cpr_scale(struct cpr_drv *drv, enum voltage_change_dir dir)
-{
- u32 val, error_steps, reg_mask;
- int last_uV, new_uV, step_uV, ret;
- struct corner *corner;
- const struct cpr_desc *desc = drv->desc;
-
- if (dir != UP && dir != DOWN)
- return 0;
-
- step_uV = regulator_get_linear_step(drv->vdd_apc);
- if (!step_uV)
- return -EINVAL;
-
- corner = drv->corner;
-
- val = cpr_read(drv, REG_RBCPR_RESULT_0);
-
- error_steps = val >> RBCPR_RESULT0_ERROR_STEPS_SHIFT;
- error_steps &= RBCPR_RESULT0_ERROR_STEPS_MASK;
- last_uV = corner->last_uV;
-
- if (dir == UP) {
- if (desc->clamp_timer_interval &&
- error_steps < desc->up_threshold) {
- /*
- * Handle the case where another measurement started
- * after the interrupt was triggered due to a core
- * exiting from power collapse.
- */
- error_steps = max(desc->up_threshold,
- desc->vdd_apc_step_up_limit);
- }
-
- if (last_uV >= corner->max_uV) {
- cpr_irq_clr_nack(drv);
-
- /* Maximize the UP threshold */
- reg_mask = RBCPR_CTL_UP_THRESHOLD_MASK;
- reg_mask <<= RBCPR_CTL_UP_THRESHOLD_SHIFT;
- val = reg_mask;
- cpr_ctl_modify(drv, reg_mask, val);
-
- /* Disable UP interrupt */
- cpr_irq_set(drv, CPR_INT_DEFAULT & ~CPR_INT_UP);
-
- return 0;
- }
-
- if (error_steps > desc->vdd_apc_step_up_limit)
- error_steps = desc->vdd_apc_step_up_limit;
-
- /* Calculate new voltage */
- new_uV = last_uV + error_steps * step_uV;
- new_uV = min(new_uV, corner->max_uV);
-
- dev_dbg(drv->dev,
- "UP: -> new_uV: %d last_uV: %d perf state: %u\n",
- new_uV, last_uV, cpr_get_cur_perf_state(drv));
- } else {
- if (desc->clamp_timer_interval &&
- error_steps < desc->down_threshold) {
- /*
- * Handle the case where another measurement started
- * after the interrupt was triggered due to a core
- * exiting from power collapse.
- */
- error_steps = max(desc->down_threshold,
- desc->vdd_apc_step_down_limit);
- }
-
- if (last_uV <= corner->min_uV) {
- cpr_irq_clr_nack(drv);
-
- /* Enable auto nack down */
- reg_mask = RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
- val = RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
-
- cpr_ctl_modify(drv, reg_mask, val);
-
- /* Disable DOWN interrupt */
- cpr_irq_set(drv, CPR_INT_DEFAULT & ~CPR_INT_DOWN);
-
- return 0;
- }
-
- if (error_steps > desc->vdd_apc_step_down_limit)
- error_steps = desc->vdd_apc_step_down_limit;
-
- /* Calculate new voltage */
- new_uV = last_uV - error_steps * step_uV;
- new_uV = max(new_uV, corner->min_uV);
-
- dev_dbg(drv->dev,
- "DOWN: -> new_uV: %d last_uV: %d perf state: %u\n",
- new_uV, last_uV, cpr_get_cur_perf_state(drv));
- }
-
- ret = cpr_scale_voltage(drv, corner, new_uV, dir);
- if (ret) {
- cpr_irq_clr_nack(drv);
- return ret;
- }
- drv->corner->last_uV = new_uV;
-
- if (dir == UP) {
- /* Disable auto nack down */
- reg_mask = RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
- val = 0;
- } else {
- /* Restore default threshold for UP */
- reg_mask = RBCPR_CTL_UP_THRESHOLD_MASK;
- reg_mask <<= RBCPR_CTL_UP_THRESHOLD_SHIFT;
- val = desc->up_threshold;
- val <<= RBCPR_CTL_UP_THRESHOLD_SHIFT;
- }
-
- cpr_ctl_modify(drv, reg_mask, val);
-
- /* Re-enable default interrupts */
- cpr_irq_set(drv, CPR_INT_DEFAULT);
-
- /* Ack */
- cpr_irq_clr_ack(drv);
-
- return 0;
-}
-
-static irqreturn_t cpr_irq_handler(int irq, void *dev)
-{
- struct cpr_drv *drv = dev;
- const struct cpr_desc *desc = drv->desc;
- irqreturn_t ret = IRQ_HANDLED;
- u32 val;
-
- mutex_lock(&drv->lock);
-
- val = cpr_read(drv, REG_RBIF_IRQ_STATUS);
- if (drv->flags & FLAGS_IGNORE_1ST_IRQ_STATUS)
- val = cpr_read(drv, REG_RBIF_IRQ_STATUS);
-
- dev_dbg(drv->dev, "IRQ_STATUS = %#02x\n", val);
-
- if (!cpr_ctl_is_enabled(drv)) {
- dev_dbg(drv->dev, "CPR is disabled\n");
- ret = IRQ_NONE;
- } else if (cpr_ctl_is_busy(drv) && !desc->clamp_timer_interval) {
- dev_dbg(drv->dev, "CPR measurement is not ready\n");
- } else if (!cpr_is_allowed(drv)) {
- val = cpr_read(drv, REG_RBCPR_CTL);
- dev_err_ratelimited(drv->dev,
- "Interrupt broken? RBCPR_CTL = %#02x\n",
- val);
- ret = IRQ_NONE;
- } else {
- /*
- * Following sequence of handling is as per each IRQ's
- * priority
- */
- if (val & CPR_INT_UP) {
- cpr_scale(drv, UP);
- } else if (val & CPR_INT_DOWN) {
- cpr_scale(drv, DOWN);
- } else if (val & CPR_INT_MIN) {
- cpr_irq_clr_nack(drv);
- } else if (val & CPR_INT_MAX) {
- cpr_irq_clr_nack(drv);
- } else if (val & CPR_INT_MID) {
- /* RBCPR_CTL_SW_AUTO_CONT_ACK_EN is enabled */
- dev_dbg(drv->dev, "IRQ occurred for Mid Flag\n");
- } else {
- dev_dbg(drv->dev,
- "IRQ occurred for unknown flag (%#08x)\n", val);
- }
-
- /* Save register values for the corner */
- cpr_corner_save(drv, drv->corner);
- }
-
- mutex_unlock(&drv->lock);
-
- return ret;
-}
-
-static int cpr_enable(struct cpr_drv *drv)
-{
- int ret;
-
- ret = regulator_enable(drv->vdd_apc);
- if (ret)
- return ret;
-
- mutex_lock(&drv->lock);
-
- if (cpr_is_allowed(drv) && drv->corner) {
- cpr_irq_clr(drv);
- cpr_corner_restore(drv, drv->corner);
- cpr_ctl_enable(drv, drv->corner);
- }
-
- mutex_unlock(&drv->lock);
-
- return 0;
-}
-
-static int cpr_disable(struct cpr_drv *drv)
-{
- mutex_lock(&drv->lock);
-
- if (cpr_is_allowed(drv)) {
- cpr_ctl_disable(drv);
- cpr_irq_clr(drv);
- }
-
- mutex_unlock(&drv->lock);
-
- return regulator_disable(drv->vdd_apc);
-}
-
-static int cpr_config(struct cpr_drv *drv)
-{
- int i;
- u32 val, gcnt;
- struct corner *corner;
- const struct cpr_desc *desc = drv->desc;
-
- /* Disable interrupt and CPR */
- cpr_write(drv, REG_RBIF_IRQ_EN(0), 0);
- cpr_write(drv, REG_RBCPR_CTL, 0);
-
- /* Program the default HW ceiling, floor and vlevel */
- val = (RBIF_LIMIT_CEILING_DEFAULT & RBIF_LIMIT_CEILING_MASK)
- << RBIF_LIMIT_CEILING_SHIFT;
- val |= RBIF_LIMIT_FLOOR_DEFAULT & RBIF_LIMIT_FLOOR_MASK;
- cpr_write(drv, REG_RBIF_LIMIT, val);
- cpr_write(drv, REG_RBIF_SW_VLEVEL, RBIF_SW_VLEVEL_DEFAULT);
-
- /*
- * Clear the target quotient value and gate count of all
- * ring oscillators
- */
- for (i = 0; i < CPR_NUM_RING_OSC; i++)
- cpr_write(drv, REG_RBCPR_GCNT_TARGET(i), 0);
-
- /* Init and save gcnt */
- gcnt = (drv->ref_clk_khz * desc->gcnt_us) / 1000;
- gcnt = gcnt & RBCPR_GCNT_TARGET_GCNT_MASK;
- gcnt <<= RBCPR_GCNT_TARGET_GCNT_SHIFT;
- drv->gcnt = gcnt;
-
- /* Program the delay count for the timer */
- val = (drv->ref_clk_khz * desc->timer_delay_us) / 1000;
- cpr_write(drv, REG_RBCPR_TIMER_INTERVAL, val);
- dev_dbg(drv->dev, "Timer count: %#0x (for %d us)\n", val,
- desc->timer_delay_us);
-
- /* Program Consecutive Up & Down */
- val = desc->timer_cons_down << RBIF_TIMER_ADJ_CONS_DOWN_SHIFT;
- val |= desc->timer_cons_up << RBIF_TIMER_ADJ_CONS_UP_SHIFT;
- val |= desc->clamp_timer_interval << RBIF_TIMER_ADJ_CLAMP_INT_SHIFT;
- cpr_write(drv, REG_RBIF_TIMER_ADJUST, val);
-
- /* Program the control register */
- val = desc->up_threshold << RBCPR_CTL_UP_THRESHOLD_SHIFT;
- val |= desc->down_threshold << RBCPR_CTL_DN_THRESHOLD_SHIFT;
- val |= RBCPR_CTL_TIMER_EN | RBCPR_CTL_COUNT_MODE;
- val |= RBCPR_CTL_SW_AUTO_CONT_ACK_EN;
- cpr_write(drv, REG_RBCPR_CTL, val);
-
- for (i = 0; i < drv->num_corners; i++) {
- corner = &drv->corners[i];
- corner->save_ctl = val;
- corner->save_irq = CPR_INT_DEFAULT;
- }
-
- cpr_irq_set(drv, CPR_INT_DEFAULT);
-
- val = cpr_read(drv, REG_RBCPR_VERSION);
- if (val <= RBCPR_VER_2)
- drv->flags |= FLAGS_IGNORE_1ST_IRQ_STATUS;
-
- return 0;
-}
-
-static int cpr_set_performance_state(struct generic_pm_domain *domain,
- unsigned int state)
-{
- struct cpr_drv *drv = container_of(domain, struct cpr_drv, pd);
- struct corner *corner, *end;
- enum voltage_change_dir dir;
- int ret = 0, new_uV;
-
- mutex_lock(&drv->lock);
-
- dev_dbg(drv->dev, "%s: setting perf state: %u (prev state: %u)\n",
- __func__, state, cpr_get_cur_perf_state(drv));
-
- /*
- * Determine new corner we're going to.
- * Remove one since lowest performance state is 1.
- */
- corner = drv->corners + state - 1;
- end = &drv->corners[drv->num_corners - 1];
- if (corner > end || corner < drv->corners) {
- ret = -EINVAL;
- goto unlock;
- }
-
- /* Determine direction */
- if (drv->corner > corner)
- dir = DOWN;
- else if (drv->corner < corner)
- dir = UP;
- else
- dir = NO_CHANGE;
-
- if (cpr_is_allowed(drv))
- new_uV = corner->last_uV;
- else
- new_uV = corner->uV;
-
- if (cpr_is_allowed(drv))
- cpr_ctl_disable(drv);
-
- ret = cpr_scale_voltage(drv, corner, new_uV, dir);
- if (ret)
- goto unlock;
-
- if (cpr_is_allowed(drv)) {
- cpr_irq_clr(drv);
- if (drv->corner != corner)
- cpr_corner_restore(drv, corner);
- cpr_ctl_enable(drv, corner);
- }
-
- drv->corner = corner;
-
-unlock:
- mutex_unlock(&drv->lock);
-
- return ret;
-}
-
-static int
-cpr_populate_ring_osc_idx(struct cpr_drv *drv)
-{
- struct fuse_corner *fuse = drv->fuse_corners;
- struct fuse_corner *end = fuse + drv->desc->num_fuse_corners;
- const struct cpr_fuse *fuses = drv->cpr_fuses;
- u32 data;
- int ret;
-
- for (; fuse < end; fuse++, fuses++) {
- ret = nvmem_cell_read_variable_le_u32(drv->dev, fuses->ring_osc, &data);
- if (ret)
- return ret;
- fuse->ring_osc_idx = data;
- }
-
- return 0;
-}
-
-static int cpr_read_fuse_uV(const struct cpr_desc *desc,
- const struct fuse_corner_data *fdata,
- const char *init_v_efuse,
- int step_volt,
- struct cpr_drv *drv)
-{
- int step_size_uV, steps, uV;
- u32 bits = 0;
- int ret;
-
- ret = nvmem_cell_read_variable_le_u32(drv->dev, init_v_efuse, &bits);
- if (ret)
- return ret;
-
- steps = bits & ~BIT(desc->cpr_fuses.init_voltage_width - 1);
- /* Not two's complement.. instead highest bit is sign bit */
- if (bits & BIT(desc->cpr_fuses.init_voltage_width - 1))
- steps = -steps;
-
- step_size_uV = desc->cpr_fuses.init_voltage_step;
-
- uV = fdata->ref_uV + steps * step_size_uV;
- return DIV_ROUND_UP(uV, step_volt) * step_volt;
-}
-
-static int cpr_fuse_corner_init(struct cpr_drv *drv)
-{
- const struct cpr_desc *desc = drv->desc;
- const struct cpr_fuse *fuses = drv->cpr_fuses;
- const struct acc_desc *acc_desc = drv->acc_desc;
- int i;
- unsigned int step_volt;
- struct fuse_corner_data *fdata;
- struct fuse_corner *fuse, *end;
- int uV;
- const struct reg_sequence *accs;
- int ret;
-
- accs = acc_desc->settings;
-
- step_volt = regulator_get_linear_step(drv->vdd_apc);
- if (!step_volt)
- return -EINVAL;
-
- /* Populate fuse_corner members */
- fuse = drv->fuse_corners;
- end = &fuse[desc->num_fuse_corners - 1];
- fdata = desc->cpr_fuses.fuse_corner_data;
-
- for (i = 0; fuse <= end; fuse++, fuses++, i++, fdata++) {
- /*
- * Update SoC voltages: platforms might choose a different
- * regulators than the one used to characterize the algorithms
- * (ie, init_voltage_step).
- */
- fdata->min_uV = roundup(fdata->min_uV, step_volt);
- fdata->max_uV = roundup(fdata->max_uV, step_volt);
-
- /* Populate uV */
- uV = cpr_read_fuse_uV(desc, fdata, fuses->init_voltage,
- step_volt, drv);
- if (uV < 0)
- return uV;
-
- fuse->min_uV = fdata->min_uV;
- fuse->max_uV = fdata->max_uV;
- fuse->uV = clamp(uV, fuse->min_uV, fuse->max_uV);
-
- if (fuse == end) {
- /*
- * Allow the highest fuse corner's PVS voltage to
- * define the ceiling voltage for that corner in order
- * to support SoC's in which variable ceiling values
- * are required.
- */
- end->max_uV = max(end->max_uV, end->uV);
- }
-
- /* Populate target quotient by scaling */
- ret = nvmem_cell_read_variable_le_u32(drv->dev, fuses->quotient, &fuse->quot);
- if (ret)
- return ret;
-
- fuse->quot *= fdata->quot_scale;
- fuse->quot += fdata->quot_offset;
- fuse->quot += fdata->quot_adjust;
- fuse->step_quot = desc->step_quot[fuse->ring_osc_idx];
-
- /* Populate acc settings */
- fuse->accs = accs;
- fuse->num_accs = acc_desc->num_regs_per_fuse;
- accs += acc_desc->num_regs_per_fuse;
- }
-
- /*
- * Restrict all fuse corner PVS voltages based upon per corner
- * ceiling and floor voltages.
- */
- for (fuse = drv->fuse_corners, i = 0; fuse <= end; fuse++, i++) {
- if (fuse->uV > fuse->max_uV)
- fuse->uV = fuse->max_uV;
- else if (fuse->uV < fuse->min_uV)
- fuse->uV = fuse->min_uV;
-
- ret = regulator_is_supported_voltage(drv->vdd_apc,
- fuse->min_uV,
- fuse->min_uV);
- if (!ret) {
- dev_err(drv->dev,
- "min uV: %d (fuse corner: %d) not supported by regulator\n",
- fuse->min_uV, i);
- return -EINVAL;
- }
-
- ret = regulator_is_supported_voltage(drv->vdd_apc,
- fuse->max_uV,
- fuse->max_uV);
- if (!ret) {
- dev_err(drv->dev,
- "max uV: %d (fuse corner: %d) not supported by regulator\n",
- fuse->max_uV, i);
- return -EINVAL;
- }
-
- dev_dbg(drv->dev,
- "fuse corner %d: [%d %d %d] RO%hhu quot %d squot %d\n",
- i, fuse->min_uV, fuse->uV, fuse->max_uV,
- fuse->ring_osc_idx, fuse->quot, fuse->step_quot);
- }
-
- return 0;
-}
-
-static int cpr_calculate_scaling(const char *quot_offset,
- struct cpr_drv *drv,
- const struct fuse_corner_data *fdata,
- const struct corner *corner)
-{
- u32 quot_diff = 0;
- unsigned long freq_diff;
- int scaling;
- const struct fuse_corner *fuse, *prev_fuse;
- int ret;
-
- fuse = corner->fuse_corner;
- prev_fuse = fuse - 1;
-
- if (quot_offset) {
- ret = nvmem_cell_read_variable_le_u32(drv->dev, quot_offset, &quot_diff);
- if (ret)
- return ret;
-
- quot_diff *= fdata->quot_offset_scale;
- quot_diff += fdata->quot_offset_adjust;
- } else {
- quot_diff = fuse->quot - prev_fuse->quot;
- }
-
- freq_diff = fuse->max_freq - prev_fuse->max_freq;
- freq_diff /= 1000000; /* Convert to MHz */
- scaling = 1000 * quot_diff / freq_diff;
- return min(scaling, fdata->max_quot_scale);
-}
-
-static int cpr_interpolate(const struct corner *corner, int step_volt,
- const struct fuse_corner_data *fdata)
-{
- unsigned long f_high, f_low, f_diff;
- int uV_high, uV_low, uV;
- u64 temp, temp_limit;
- const struct fuse_corner *fuse, *prev_fuse;
-
- fuse = corner->fuse_corner;
- prev_fuse = fuse - 1;
-
- f_high = fuse->max_freq;
- f_low = prev_fuse->max_freq;
- uV_high = fuse->uV;
- uV_low = prev_fuse->uV;
- f_diff = fuse->max_freq - corner->freq;
-
- /*
- * Don't interpolate in the wrong direction. This could happen
- * if the adjusted fuse voltage overlaps with the previous fuse's
- * adjusted voltage.
- */
- if (f_high <= f_low || uV_high <= uV_low || f_high <= corner->freq)
- return corner->uV;
-
- temp = f_diff * (uV_high - uV_low);
- temp = div64_ul(temp, f_high - f_low);
-
- /*
- * max_volt_scale has units of uV/MHz while freq values
- * have units of Hz. Divide by 1000000 to convert to.
- */
- temp_limit = f_diff * fdata->max_volt_scale;
- do_div(temp_limit, 1000000);
-
- uV = uV_high - min(temp, temp_limit);
- return roundup(uV, step_volt);
-}
-
-static unsigned int cpr_get_fuse_corner(struct dev_pm_opp *opp)
-{
- struct device_node *np;
- unsigned int fuse_corner = 0;
-
- np = dev_pm_opp_get_of_node(opp);
- if (of_property_read_u32(np, "qcom,opp-fuse-level", &fuse_corner))
- pr_err("%s: missing 'qcom,opp-fuse-level' property\n",
- __func__);
-
- of_node_put(np);
-
- return fuse_corner;
-}
-
-static unsigned long cpr_get_opp_hz_for_req(struct dev_pm_opp *ref,
- struct device *cpu_dev)
-{
- u64 rate = 0;
- struct device_node *ref_np;
- struct device_node *desc_np;
- struct device_node *child_np = NULL;
- struct device_node *child_req_np = NULL;
-
- desc_np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
- if (!desc_np)
- return 0;
-
- ref_np = dev_pm_opp_get_of_node(ref);
- if (!ref_np)
- goto out_ref;
-
- do {
- of_node_put(child_req_np);
- child_np = of_get_next_available_child(desc_np, child_np);
- child_req_np = of_parse_phandle(child_np, "required-opps", 0);
- } while (child_np && child_req_np != ref_np);
-
- if (child_np && child_req_np == ref_np)
- of_property_read_u64(child_np, "opp-hz", &rate);
-
- of_node_put(child_req_np);
- of_node_put(child_np);
- of_node_put(ref_np);
-out_ref:
- of_node_put(desc_np);
-
- return (unsigned long) rate;
-}
-
-static int cpr_corner_init(struct cpr_drv *drv)
-{
- const struct cpr_desc *desc = drv->desc;
- const struct cpr_fuse *fuses = drv->cpr_fuses;
- int i, level, scaling = 0;
- unsigned int fnum, fc;
- const char *quot_offset;
- struct fuse_corner *fuse, *prev_fuse;
- struct corner *corner, *end;
- struct corner_data *cdata;
- const struct fuse_corner_data *fdata;
- bool apply_scaling;
- unsigned long freq_diff, freq_diff_mhz;
- unsigned long freq;
- int step_volt = regulator_get_linear_step(drv->vdd_apc);
- struct dev_pm_opp *opp;
-
- if (!step_volt)
- return -EINVAL;
-
- corner = drv->corners;
- end = &corner[drv->num_corners - 1];
-
- cdata = devm_kcalloc(drv->dev, drv->num_corners,
- sizeof(struct corner_data),
- GFP_KERNEL);
- if (!cdata)
- return -ENOMEM;
-
- /*
- * Store maximum frequency for each fuse corner based on the frequency
- * plan
- */
- for (level = 1; level <= drv->num_corners; level++) {
- opp = dev_pm_opp_find_level_exact(&drv->pd.dev, level);
- if (IS_ERR(opp))
- return -EINVAL;
- fc = cpr_get_fuse_corner(opp);
- if (!fc) {
- dev_pm_opp_put(opp);
- return -EINVAL;
- }
- fnum = fc - 1;
- freq = cpr_get_opp_hz_for_req(opp, drv->attached_cpu_dev);
- if (!freq) {
- dev_pm_opp_put(opp);
- return -EINVAL;
- }
- cdata[level - 1].fuse_corner = fnum;
- cdata[level - 1].freq = freq;
-
- fuse = &drv->fuse_corners[fnum];
- dev_dbg(drv->dev, "freq: %lu level: %u fuse level: %u\n",
- freq, dev_pm_opp_get_level(opp) - 1, fnum);
- if (freq > fuse->max_freq)
- fuse->max_freq = freq;
- dev_pm_opp_put(opp);
- }
-
- /*
- * Get the quotient adjustment scaling factor, according to:
- *
- * scaling = min(1000 * (QUOT(corner_N) - QUOT(corner_N-1))
- * / (freq(corner_N) - freq(corner_N-1)), max_factor)
- *
- * QUOT(corner_N): quotient read from fuse for fuse corner N
- * QUOT(corner_N-1): quotient read from fuse for fuse corner (N - 1)
- * freq(corner_N): max frequency in MHz supported by fuse corner N
- * freq(corner_N-1): max frequency in MHz supported by fuse corner
- * (N - 1)
- *
- * Then walk through the corners mapped to each fuse corner
- * and calculate the quotient adjustment for each one using the
- * following formula:
- *
- * quot_adjust = (freq_max - freq_corner) * scaling / 1000
- *
- * freq_max: max frequency in MHz supported by the fuse corner
- * freq_corner: frequency in MHz corresponding to the corner
- * scaling: calculated from above equation
- *
- *
- * + +
- * | v |
- * q | f c o | f c
- * u | c l | c
- * o | f t | f
- * t | c a | c
- * | c f g | c f
- * | e |
- * +--------------- +----------------
- * 0 1 2 3 4 5 6 0 1 2 3 4 5 6
- * corner corner
- *
- * c = corner
- * f = fuse corner
- *
- */
- for (apply_scaling = false, i = 0; corner <= end; corner++, i++) {
- fnum = cdata[i].fuse_corner;
- fdata = &desc->cpr_fuses.fuse_corner_data[fnum];
- quot_offset = fuses[fnum].quotient_offset;
- fuse = &drv->fuse_corners[fnum];
- if (fnum)
- prev_fuse = &drv->fuse_corners[fnum - 1];
- else
- prev_fuse = NULL;
-
- corner->fuse_corner = fuse;
- corner->freq = cdata[i].freq;
- corner->uV = fuse->uV;
-
- if (prev_fuse && cdata[i - 1].freq == prev_fuse->max_freq) {
- scaling = cpr_calculate_scaling(quot_offset, drv,
- fdata, corner);
- if (scaling < 0)
- return scaling;
-
- apply_scaling = true;
- } else if (corner->freq == fuse->max_freq) {
- /* This is a fuse corner; don't scale anything */
- apply_scaling = false;
- }
-
- if (apply_scaling) {
- freq_diff = fuse->max_freq - corner->freq;
- freq_diff_mhz = freq_diff / 1000000;
- corner->quot_adjust = scaling * freq_diff_mhz / 1000;
-
- corner->uV = cpr_interpolate(corner, step_volt, fdata);
- }
-
- corner->max_uV = fuse->max_uV;
- corner->min_uV = fuse->min_uV;
- corner->uV = clamp(corner->uV, corner->min_uV, corner->max_uV);
- corner->last_uV = corner->uV;
-
- /* Reduce the ceiling voltage if needed */
- if (desc->reduce_to_corner_uV && corner->uV < corner->max_uV)
- corner->max_uV = corner->uV;
- else if (desc->reduce_to_fuse_uV && fuse->uV < corner->max_uV)
- corner->max_uV = max(corner->min_uV, fuse->uV);
-
- dev_dbg(drv->dev, "corner %d: [%d %d %d] quot %d\n", i,
- corner->min_uV, corner->uV, corner->max_uV,
- fuse->quot - corner->quot_adjust);
- }
-
- return 0;
-}
-
-static const struct cpr_fuse *cpr_get_fuses(struct cpr_drv *drv)
-{
- const struct cpr_desc *desc = drv->desc;
- struct cpr_fuse *fuses;
- int i;
-
- fuses = devm_kcalloc(drv->dev, desc->num_fuse_corners,
- sizeof(struct cpr_fuse),
- GFP_KERNEL);
- if (!fuses)
- return ERR_PTR(-ENOMEM);
-
- for (i = 0; i < desc->num_fuse_corners; i++) {
- char tbuf[32];
-
- snprintf(tbuf, 32, "cpr_ring_osc%d", i + 1);
- fuses[i].ring_osc = devm_kstrdup(drv->dev, tbuf, GFP_KERNEL);
- if (!fuses[i].ring_osc)
- return ERR_PTR(-ENOMEM);
-
- snprintf(tbuf, 32, "cpr_init_voltage%d", i + 1);
- fuses[i].init_voltage = devm_kstrdup(drv->dev, tbuf,
- GFP_KERNEL);
- if (!fuses[i].init_voltage)
- return ERR_PTR(-ENOMEM);
-
- snprintf(tbuf, 32, "cpr_quotient%d", i + 1);
- fuses[i].quotient = devm_kstrdup(drv->dev, tbuf, GFP_KERNEL);
- if (!fuses[i].quotient)
- return ERR_PTR(-ENOMEM);
-
- snprintf(tbuf, 32, "cpr_quotient_offset%d", i + 1);
- fuses[i].quotient_offset = devm_kstrdup(drv->dev, tbuf,
- GFP_KERNEL);
- if (!fuses[i].quotient_offset)
- return ERR_PTR(-ENOMEM);
- }
-
- return fuses;
-}
-
-static void cpr_set_loop_allowed(struct cpr_drv *drv)
-{
- drv->loop_disabled = false;
-}
-
-static int cpr_init_parameters(struct cpr_drv *drv)
-{
- const struct cpr_desc *desc = drv->desc;
- struct clk *clk;
-
- clk = clk_get(drv->dev, "ref");
- if (IS_ERR(clk))
- return PTR_ERR(clk);
-
- drv->ref_clk_khz = clk_get_rate(clk) / 1000;
- clk_put(clk);
-
- if (desc->timer_cons_up > RBIF_TIMER_ADJ_CONS_UP_MASK ||
- desc->timer_cons_down > RBIF_TIMER_ADJ_CONS_DOWN_MASK ||
- desc->up_threshold > RBCPR_CTL_UP_THRESHOLD_MASK ||
- desc->down_threshold > RBCPR_CTL_DN_THRESHOLD_MASK ||
- desc->idle_clocks > RBCPR_STEP_QUOT_IDLE_CLK_MASK ||
- desc->clamp_timer_interval > RBIF_TIMER_ADJ_CLAMP_INT_MASK)
- return -EINVAL;
-
- dev_dbg(drv->dev, "up threshold = %u, down threshold = %u\n",
- desc->up_threshold, desc->down_threshold);
-
- return 0;
-}
-
-static int cpr_find_initial_corner(struct cpr_drv *drv)
-{
- unsigned long rate;
- const struct corner *end;
- struct corner *iter;
- unsigned int i = 0;
-
- if (!drv->cpu_clk) {
- dev_err(drv->dev, "cannot get rate from NULL clk\n");
- return -EINVAL;
- }
-
- end = &drv->corners[drv->num_corners - 1];
- rate = clk_get_rate(drv->cpu_clk);
-
- /*
- * Some bootloaders set a CPU clock frequency that is not defined
- * in the OPP table. When running at an unlisted frequency,
- * cpufreq_online() will change to the OPP which has the lowest
- * frequency, at or above the unlisted frequency.
- * Since cpufreq_online() always "rounds up" in the case of an
- * unlisted frequency, this function always "rounds down" in case
- * of an unlisted frequency. That way, when cpufreq_online()
- * triggers the first ever call to cpr_set_performance_state(),
- * it will correctly determine the direction as UP.
- */
- for (iter = drv->corners; iter <= end; iter++) {
- if (iter->freq > rate)
- break;
- i++;
- if (iter->freq == rate) {
- drv->corner = iter;
- break;
- }
- if (iter->freq < rate)
- drv->corner = iter;
- }
-
- if (!drv->corner) {
- dev_err(drv->dev, "boot up corner not found\n");
- return -EINVAL;
- }
-
- dev_dbg(drv->dev, "boot up perf state: %u\n", i);
-
- return 0;
-}
-
-static const struct cpr_desc qcs404_cpr_desc = {
- .num_fuse_corners = 3,
- .min_diff_quot = CPR_FUSE_MIN_QUOT_DIFF,
- .step_quot = (int []){ 25, 25, 25, },
- .timer_delay_us = 5000,
- .timer_cons_up = 0,
- .timer_cons_down = 2,
- .up_threshold = 1,
- .down_threshold = 3,
- .idle_clocks = 15,
- .gcnt_us = 1,
- .vdd_apc_step_up_limit = 1,
- .vdd_apc_step_down_limit = 1,
- .cpr_fuses = {
- .init_voltage_step = 8000,
- .init_voltage_width = 6,
- .fuse_corner_data = (struct fuse_corner_data[]){
- /* fuse corner 0 */
- {
- .ref_uV = 1224000,
- .max_uV = 1224000,
- .min_uV = 1048000,
- .max_volt_scale = 0,
- .max_quot_scale = 0,
- .quot_offset = 0,
- .quot_scale = 1,
- .quot_adjust = 0,
- .quot_offset_scale = 5,
- .quot_offset_adjust = 0,
- },
- /* fuse corner 1 */
- {
- .ref_uV = 1288000,
- .max_uV = 1288000,
- .min_uV = 1048000,
- .max_volt_scale = 2000,
- .max_quot_scale = 1400,
- .quot_offset = 0,
- .quot_scale = 1,
- .quot_adjust = -20,
- .quot_offset_scale = 5,
- .quot_offset_adjust = 0,
- },
- /* fuse corner 2 */
- {
- .ref_uV = 1352000,
- .max_uV = 1384000,
- .min_uV = 1088000,
- .max_volt_scale = 2000,
- .max_quot_scale = 1400,
- .quot_offset = 0,
- .quot_scale = 1,
- .quot_adjust = 0,
- .quot_offset_scale = 5,
- .quot_offset_adjust = 0,
- },
- },
- },
-};
-
-static const struct acc_desc qcs404_acc_desc = {
- .settings = (struct reg_sequence[]){
- { 0xb120, 0x1041040 },
- { 0xb124, 0x41 },
- { 0xb120, 0x0 },
- { 0xb124, 0x0 },
- { 0xb120, 0x0 },
- { 0xb124, 0x0 },
- },
- .config = (struct reg_sequence[]){
- { 0xb138, 0xff },
- { 0xb130, 0x5555 },
- },
- .num_regs_per_fuse = 2,
-};
-
-static const struct cpr_acc_desc qcs404_cpr_acc_desc = {
- .cpr_desc = &qcs404_cpr_desc,
- .acc_desc = &qcs404_acc_desc,
-};
-
-static unsigned int cpr_get_performance_state(struct generic_pm_domain *genpd,
- struct dev_pm_opp *opp)
-{
- return dev_pm_opp_get_level(opp);
-}
-
-static int cpr_power_off(struct generic_pm_domain *domain)
-{
- struct cpr_drv *drv = container_of(domain, struct cpr_drv, pd);
-
- return cpr_disable(drv);
-}
-
-static int cpr_power_on(struct generic_pm_domain *domain)
-{
- struct cpr_drv *drv = container_of(domain, struct cpr_drv, pd);
-
- return cpr_enable(drv);
-}
-
-static int cpr_pd_attach_dev(struct generic_pm_domain *domain,
- struct device *dev)
-{
- struct cpr_drv *drv = container_of(domain, struct cpr_drv, pd);
- const struct acc_desc *acc_desc = drv->acc_desc;
- int ret = 0;
-
- mutex_lock(&drv->lock);
-
- dev_dbg(drv->dev, "attach callback for: %s\n", dev_name(dev));
-
- /*
- * This driver only supports scaling voltage for a CPU cluster
- * where all CPUs in the cluster share a single regulator.
- * Therefore, save the struct device pointer only for the first
- * CPU device that gets attached. There is no need to do any
- * additional initialization when further CPUs get attached.
- */
- if (drv->attached_cpu_dev)
- goto unlock;
-
- /*
- * cpr_scale_voltage() requires the direction (if we are changing
- * to a higher or lower OPP). The first time
- * cpr_set_performance_state() is called, there is no previous
- * performance state defined. Therefore, we call
- * cpr_find_initial_corner() that gets the CPU clock frequency
- * set by the bootloader, so that we can determine the direction
- * the first time cpr_set_performance_state() is called.
- */
- drv->cpu_clk = devm_clk_get(dev, NULL);
- if (IS_ERR(drv->cpu_clk)) {
- ret = PTR_ERR(drv->cpu_clk);
- if (ret != -EPROBE_DEFER)
- dev_err(drv->dev, "could not get cpu clk: %d\n", ret);
- goto unlock;
- }
- drv->attached_cpu_dev = dev;
-
- dev_dbg(drv->dev, "using cpu clk from: %s\n",
- dev_name(drv->attached_cpu_dev));
-
- /*
- * Everything related to (virtual) corners has to be initialized
- * here, when attaching to the power domain, since we need to know
- * the maximum frequency for each fuse corner, and this is only
- * available after the cpufreq driver has attached to us.
- * The reason for this is that we need to know the highest
- * frequency associated with each fuse corner.
- */
- ret = dev_pm_opp_get_opp_count(&drv->pd.dev);
- if (ret < 0) {
- dev_err(drv->dev, "could not get OPP count\n");
- goto unlock;
- }
- drv->num_corners = ret;
-
- if (drv->num_corners < 2) {
- dev_err(drv->dev, "need at least 2 OPPs to use CPR\n");
- ret = -EINVAL;
- goto unlock;
- }
-
- drv->corners = devm_kcalloc(drv->dev, drv->num_corners,
- sizeof(*drv->corners),
- GFP_KERNEL);
- if (!drv->corners) {
- ret = -ENOMEM;
- goto unlock;
- }
-
- ret = cpr_corner_init(drv);
- if (ret)
- goto unlock;
-
- cpr_set_loop_allowed(drv);
-
- ret = cpr_init_parameters(drv);
- if (ret)
- goto unlock;
-
- /* Configure CPR HW but keep it disabled */
- ret = cpr_config(drv);
- if (ret)
- goto unlock;
-
- ret = cpr_find_initial_corner(drv);
- if (ret)
- goto unlock;
-
- if (acc_desc->config)
- regmap_multi_reg_write(drv->tcsr, acc_desc->config,
- acc_desc->num_regs_per_fuse);
-
- /* Enable ACC if required */
- if (acc_desc->enable_mask)
- regmap_update_bits(drv->tcsr, acc_desc->enable_reg,
- acc_desc->enable_mask,
- acc_desc->enable_mask);
-
- dev_info(drv->dev, "driver initialized with %u OPPs\n",
- drv->num_corners);
-
-unlock:
- mutex_unlock(&drv->lock);
-
- return ret;
-}
-
-static int cpr_debug_info_show(struct seq_file *s, void *unused)
-{
- u32 gcnt, ro_sel, ctl, irq_status, reg, error_steps;
- u32 step_dn, step_up, error, error_lt0, busy;
- struct cpr_drv *drv = s->private;
- struct fuse_corner *fuse_corner;
- struct corner *corner;
-
- corner = drv->corner;
- fuse_corner = corner->fuse_corner;
-
- seq_printf(s, "corner, current_volt = %d uV\n",
- corner->last_uV);
-
- ro_sel = fuse_corner->ring_osc_idx;
- gcnt = cpr_read(drv, REG_RBCPR_GCNT_TARGET(ro_sel));
- seq_printf(s, "rbcpr_gcnt_target (%u) = %#02X\n", ro_sel, gcnt);
-
- ctl = cpr_read(drv, REG_RBCPR_CTL);
- seq_printf(s, "rbcpr_ctl = %#02X\n", ctl);
-
- irq_status = cpr_read(drv, REG_RBIF_IRQ_STATUS);
- seq_printf(s, "rbcpr_irq_status = %#02X\n", irq_status);
-
- reg = cpr_read(drv, REG_RBCPR_RESULT_0);
- seq_printf(s, "rbcpr_result_0 = %#02X\n", reg);
-
- step_dn = reg & 0x01;
- step_up = (reg >> RBCPR_RESULT0_STEP_UP_SHIFT) & 0x01;
- seq_printf(s, " [step_dn = %u", step_dn);
-
- seq_printf(s, ", step_up = %u", step_up);
-
- error_steps = (reg >> RBCPR_RESULT0_ERROR_STEPS_SHIFT)
- & RBCPR_RESULT0_ERROR_STEPS_MASK;
- seq_printf(s, ", error_steps = %u", error_steps);
-
- error = (reg >> RBCPR_RESULT0_ERROR_SHIFT) & RBCPR_RESULT0_ERROR_MASK;
- seq_printf(s, ", error = %u", error);
-
- error_lt0 = (reg >> RBCPR_RESULT0_ERROR_LT0_SHIFT) & 0x01;
- seq_printf(s, ", error_lt_0 = %u", error_lt0);
-
- busy = (reg >> RBCPR_RESULT0_BUSY_SHIFT) & 0x01;
- seq_printf(s, ", busy = %u]\n", busy);
-
- return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(cpr_debug_info);
-
-static void cpr_debugfs_init(struct cpr_drv *drv)
-{
- drv->debugfs = debugfs_create_dir("qcom_cpr", NULL);
-
- debugfs_create_file("debug_info", 0444, drv->debugfs,
- drv, &cpr_debug_info_fops);
-}
-
-static int cpr_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct cpr_drv *drv;
- int irq, ret;
- const struct cpr_acc_desc *data;
- struct device_node *np;
- u32 cpr_rev = FUSE_REVISION_UNKNOWN;
-
- data = of_device_get_match_data(dev);
- if (!data || !data->cpr_desc || !data->acc_desc)
- return -EINVAL;
-
- drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
- if (!drv)
- return -ENOMEM;
- drv->dev = dev;
- drv->desc = data->cpr_desc;
- drv->acc_desc = data->acc_desc;
-
- drv->fuse_corners = devm_kcalloc(dev, drv->desc->num_fuse_corners,
- sizeof(*drv->fuse_corners),
- GFP_KERNEL);
- if (!drv->fuse_corners)
- return -ENOMEM;
-
- np = of_parse_phandle(dev->of_node, "acc-syscon", 0);
- if (!np)
- return -ENODEV;
-
- drv->tcsr = syscon_node_to_regmap(np);
- of_node_put(np);
- if (IS_ERR(drv->tcsr))
- return PTR_ERR(drv->tcsr);
-
- drv->base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(drv->base))
- return PTR_ERR(drv->base);
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return -EINVAL;
-
- drv->vdd_apc = devm_regulator_get(dev, "vdd-apc");
- if (IS_ERR(drv->vdd_apc))
- return PTR_ERR(drv->vdd_apc);
-
- /*
- * Initialize fuse corners, since it simply depends
- * on data in efuses.
- * Everything related to (virtual) corners has to be
- * initialized after attaching to the power domain,
- * since it depends on the CPU's OPP table.
- */
- ret = nvmem_cell_read_variable_le_u32(dev, "cpr_fuse_revision", &cpr_rev);
- if (ret)
- return ret;
-
- drv->cpr_fuses = cpr_get_fuses(drv);
- if (IS_ERR(drv->cpr_fuses))
- return PTR_ERR(drv->cpr_fuses);
-
- ret = cpr_populate_ring_osc_idx(drv);
- if (ret)
- return ret;
-
- ret = cpr_fuse_corner_init(drv);
- if (ret)
- return ret;
-
- mutex_init(&drv->lock);
-
- ret = devm_request_threaded_irq(dev, irq, NULL,
- cpr_irq_handler,
- IRQF_ONESHOT | IRQF_TRIGGER_RISING,
- "cpr", drv);
- if (ret)
- return ret;
-
- drv->pd.name = devm_kstrdup_const(dev, dev->of_node->full_name,
- GFP_KERNEL);
- if (!drv->pd.name)
- return -EINVAL;
-
- drv->pd.power_off = cpr_power_off;
- drv->pd.power_on = cpr_power_on;
- drv->pd.set_performance_state = cpr_set_performance_state;
- drv->pd.opp_to_performance_state = cpr_get_performance_state;
- drv->pd.attach_dev = cpr_pd_attach_dev;
-
- ret = pm_genpd_init(&drv->pd, NULL, true);
- if (ret)
- return ret;
-
- ret = of_genpd_add_provider_simple(dev->of_node, &drv->pd);
- if (ret)
- goto err_remove_genpd;
-
- platform_set_drvdata(pdev, drv);
- cpr_debugfs_init(drv);
-
- return 0;
-
-err_remove_genpd:
- pm_genpd_remove(&drv->pd);
- return ret;
-}
-
-static int cpr_remove(struct platform_device *pdev)
-{
- struct cpr_drv *drv = platform_get_drvdata(pdev);
-
- if (cpr_is_allowed(drv)) {
- cpr_ctl_disable(drv);
- cpr_irq_set(drv, 0);
- }
-
- of_genpd_del_provider(pdev->dev.of_node);
- pm_genpd_remove(&drv->pd);
-
- debugfs_remove_recursive(drv->debugfs);
-
- return 0;
-}
-
-static const struct of_device_id cpr_match_table[] = {
- { .compatible = "qcom,qcs404-cpr", .data = &qcs404_cpr_acc_desc },
- { }
-};
-MODULE_DEVICE_TABLE(of, cpr_match_table);
-
-static struct platform_driver cpr_driver = {
- .probe = cpr_probe,
- .remove = cpr_remove,
- .driver = {
- .name = "qcom-cpr",
- .of_match_table = cpr_match_table,
- },
-};
-module_platform_driver(cpr_driver);
-
-MODULE_DESCRIPTION("Core Power Reduction (CPR) driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/icc-bwmon.c b/drivers/soc/qcom/icc-bwmon.c
index d07be3700db6..597f9025e422 100644
--- a/drivers/soc/qcom/icc-bwmon.c
+++ b/drivers/soc/qcom/icc-bwmon.c
@@ -12,11 +12,13 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#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
@@ -34,14 +36,27 @@
/* Internal sampling clock frequency */
#define HW_TIMER_HZ 19200000
-#define BWMON_V4_GLOBAL_IRQ_CLEAR 0x008
-#define BWMON_V4_GLOBAL_IRQ_ENABLE 0x00c
+#define BWMON_V4_GLOBAL_IRQ_CLEAR 0x108
+#define BWMON_V4_GLOBAL_IRQ_ENABLE 0x10c
/*
* All values here and further are matching regmap fields, so without absolute
* register offsets.
*/
#define BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE BIT(0)
+/*
+ * Starting with SDM845, the BWMON4 register space has changed a bit:
+ * the global registers were jammed into the beginning of the monitor region.
+ * To keep the proper offsets, one would have to map <GLOBAL_BASE 0x200> and
+ * <GLOBAL_BASE+0x100 0x300>, which is straight up wrong.
+ * To facilitate for that, while allowing the older, arguably more proper
+ * implementations to work, offset the global registers by -0x100 to avoid
+ * having to map half of the global registers twice.
+ */
+#define BWMON_V4_845_OFFSET 0x100
+#define BWMON_V4_GLOBAL_IRQ_CLEAR_845 (BWMON_V4_GLOBAL_IRQ_CLEAR - BWMON_V4_845_OFFSET)
+#define BWMON_V4_GLOBAL_IRQ_ENABLE_845 (BWMON_V4_GLOBAL_IRQ_ENABLE - BWMON_V4_845_OFFSET)
+
#define BWMON_V4_IRQ_STATUS 0x100
#define BWMON_V4_IRQ_CLEAR 0x108
@@ -118,9 +133,13 @@
#define BWMON_NEEDS_FORCE_CLEAR BIT(1)
enum bwmon_fields {
+ /* Global region fields, keep them at the top */
F_GLOBAL_IRQ_CLEAR,
F_GLOBAL_IRQ_ENABLE,
- F_IRQ_STATUS,
+ F_NUM_GLOBAL_FIELDS,
+
+ /* Monitor region fields */
+ F_IRQ_STATUS = F_NUM_GLOBAL_FIELDS,
F_IRQ_CLEAR,
F_IRQ_ENABLE,
F_ENABLE,
@@ -148,15 +167,15 @@ enum bwmon_fields {
struct icc_bwmon_data {
unsigned int sample_ms;
unsigned int count_unit_kb; /* kbytes */
- unsigned int default_highbw_kbps;
- unsigned int default_medbw_kbps;
- unsigned int default_lowbw_kbps;
u8 zone1_thres_count;
u8 zone3_thres_count;
unsigned int quirks;
const struct regmap_config *regmap_cfg;
const struct reg_field *regmap_fields;
+
+ const struct regmap_config *global_regmap_cfg;
+ const struct reg_field *global_regmap_fields;
};
struct icc_bwmon {
@@ -164,8 +183,8 @@ struct icc_bwmon {
const struct icc_bwmon_data *data;
int irq;
- struct regmap *regmap;
struct regmap_field *regs[F_NUM_FIELDS];
+ struct regmap_field *global_regs[F_NUM_GLOBAL_FIELDS];
unsigned int max_bw_kbps;
unsigned int min_bw_kbps;
@@ -175,8 +194,8 @@ struct icc_bwmon {
/* BWMON v4 */
static const struct reg_field msm8998_bwmon_reg_fields[] = {
- [F_GLOBAL_IRQ_CLEAR] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_CLEAR, 0, 0),
- [F_GLOBAL_IRQ_ENABLE] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_ENABLE, 0, 0),
+ [F_GLOBAL_IRQ_CLEAR] = {},
+ [F_GLOBAL_IRQ_ENABLE] = {},
[F_IRQ_STATUS] = REG_FIELD(BWMON_V4_IRQ_STATUS, 4, 7),
[F_IRQ_CLEAR] = REG_FIELD(BWMON_V4_IRQ_CLEAR, 4, 7),
[F_IRQ_ENABLE] = REG_FIELD(BWMON_V4_IRQ_ENABLE, 4, 7),
@@ -202,7 +221,6 @@ static const struct reg_field msm8998_bwmon_reg_fields[] = {
};
static const struct regmap_range msm8998_bwmon_reg_noread_ranges[] = {
- regmap_reg_range(BWMON_V4_GLOBAL_IRQ_CLEAR, BWMON_V4_GLOBAL_IRQ_CLEAR),
regmap_reg_range(BWMON_V4_IRQ_CLEAR, BWMON_V4_IRQ_CLEAR),
regmap_reg_range(BWMON_V4_CLEAR, BWMON_V4_CLEAR),
};
@@ -222,16 +240,33 @@ static const struct regmap_access_table msm8998_bwmon_reg_volatile_table = {
.n_yes_ranges = ARRAY_SIZE(msm8998_bwmon_reg_volatile_ranges),
};
+static const struct reg_field msm8998_bwmon_global_reg_fields[] = {
+ [F_GLOBAL_IRQ_CLEAR] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_CLEAR, 0, 0),
+ [F_GLOBAL_IRQ_ENABLE] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_ENABLE, 0, 0),
+};
+
+static const struct regmap_range msm8998_bwmon_global_reg_noread_ranges[] = {
+ regmap_reg_range(BWMON_V4_GLOBAL_IRQ_CLEAR, BWMON_V4_GLOBAL_IRQ_CLEAR),
+};
+
+static const struct regmap_access_table msm8998_bwmon_global_reg_read_table = {
+ .no_ranges = msm8998_bwmon_global_reg_noread_ranges,
+ .n_no_ranges = ARRAY_SIZE(msm8998_bwmon_global_reg_noread_ranges),
+};
+
/*
* Fill the cache for non-readable registers only as rest does not really
* matter and can be read from the device.
*/
static const struct reg_default msm8998_bwmon_reg_defaults[] = {
- { BWMON_V4_GLOBAL_IRQ_CLEAR, 0x0 },
{ BWMON_V4_IRQ_CLEAR, 0x0 },
{ BWMON_V4_CLEAR, 0x0 },
};
+static const struct reg_default msm8998_bwmon_global_reg_defaults[] = {
+ { BWMON_V4_GLOBAL_IRQ_CLEAR, 0x0 },
+};
+
static const struct regmap_config msm8998_bwmon_regmap_cfg = {
.reg_bits = 32,
.reg_stride = 4,
@@ -249,7 +284,94 @@ 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 = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ /*
+ * No concurrent access expected - driver has one interrupt handler,
+ * regmap is not shared, no driver or user-space API.
+ */
+ .disable_locking = true,
+ .rd_table = &msm8998_bwmon_global_reg_read_table,
+ .reg_defaults = msm8998_bwmon_global_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(msm8998_bwmon_global_reg_defaults),
+ /*
+ * Cache is necessary for using regmap fields with non-readable
+ * registers.
+ */
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static const struct reg_field sdm845_cpu_bwmon_reg_fields[] = {
+ [F_GLOBAL_IRQ_CLEAR] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_CLEAR_845, 0, 0),
+ [F_GLOBAL_IRQ_ENABLE] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_ENABLE_845, 0, 0),
+ [F_IRQ_STATUS] = REG_FIELD(BWMON_V4_IRQ_STATUS, 4, 7),
+ [F_IRQ_CLEAR] = REG_FIELD(BWMON_V4_IRQ_CLEAR, 4, 7),
+ [F_IRQ_ENABLE] = REG_FIELD(BWMON_V4_IRQ_ENABLE, 4, 7),
+ /* F_ENABLE covers entire register to disable other features */
+ [F_ENABLE] = REG_FIELD(BWMON_V4_ENABLE, 0, 31),
+ [F_CLEAR] = REG_FIELD(BWMON_V4_CLEAR, 0, 1),
+ [F_SAMPLE_WINDOW] = REG_FIELD(BWMON_V4_SAMPLE_WINDOW, 0, 23),
+ [F_THRESHOLD_HIGH] = REG_FIELD(BWMON_V4_THRESHOLD_HIGH, 0, 11),
+ [F_THRESHOLD_MED] = REG_FIELD(BWMON_V4_THRESHOLD_MED, 0, 11),
+ [F_THRESHOLD_LOW] = REG_FIELD(BWMON_V4_THRESHOLD_LOW, 0, 11),
+ [F_ZONE_ACTIONS_ZONE0] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 0, 7),
+ [F_ZONE_ACTIONS_ZONE1] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 8, 15),
+ [F_ZONE_ACTIONS_ZONE2] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 16, 23),
+ [F_ZONE_ACTIONS_ZONE3] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 24, 31),
+ [F_THRESHOLD_COUNT_ZONE0] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 0, 7),
+ [F_THRESHOLD_COUNT_ZONE1] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 8, 15),
+ [F_THRESHOLD_COUNT_ZONE2] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 16, 23),
+ [F_THRESHOLD_COUNT_ZONE3] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 24, 31),
+ [F_ZONE0_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(0), 0, 11),
+ [F_ZONE1_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(1), 0, 11),
+ [F_ZONE2_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(2), 0, 11),
+ [F_ZONE3_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(3), 0, 11),
+};
+
+static const struct regmap_range sdm845_cpu_bwmon_reg_noread_ranges[] = {
+ regmap_reg_range(BWMON_V4_GLOBAL_IRQ_CLEAR_845, BWMON_V4_GLOBAL_IRQ_CLEAR_845),
+ regmap_reg_range(BWMON_V4_IRQ_CLEAR, BWMON_V4_IRQ_CLEAR),
+ regmap_reg_range(BWMON_V4_CLEAR, BWMON_V4_CLEAR),
+};
+
+static const struct regmap_access_table sdm845_cpu_bwmon_reg_read_table = {
+ .no_ranges = sdm845_cpu_bwmon_reg_noread_ranges,
+ .n_no_ranges = ARRAY_SIZE(sdm845_cpu_bwmon_reg_noread_ranges),
+};
+
+/*
+ * Fill the cache for non-readable registers only as rest does not really
+ * matter and can be read from the device.
+ */
+static const struct reg_default sdm845_cpu_bwmon_reg_defaults[] = {
+ { BWMON_V4_GLOBAL_IRQ_CLEAR_845, 0x0 },
+ { BWMON_V4_IRQ_CLEAR, 0x0 },
+ { BWMON_V4_CLEAR, 0x0 },
+};
+
+static const struct regmap_config sdm845_cpu_bwmon_regmap_cfg = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ /*
+ * No concurrent access expected - driver has one interrupt handler,
+ * regmap is not shared, no driver or user-space API.
+ */
+ .disable_locking = true,
+ .rd_table = &sdm845_cpu_bwmon_reg_read_table,
+ .volatile_table = &msm8998_bwmon_reg_volatile_table,
+ .reg_defaults = sdm845_cpu_bwmon_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(sdm845_cpu_bwmon_reg_defaults),
+ /*
+ * Cache is necessary for using regmap fields with non-readable
+ * registers.
+ */
+ .cache_type = REGCACHE_MAPLE,
};
/* BWMON v5 */
@@ -326,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)
@@ -350,6 +472,13 @@ static void bwmon_clear_counters(struct icc_bwmon *bwmon, bool clear_all)
static void bwmon_clear_irq(struct icc_bwmon *bwmon)
{
+ struct regmap_field *global_irq_clr;
+
+ if (bwmon->data->global_regmap_fields)
+ global_irq_clr = bwmon->global_regs[F_GLOBAL_IRQ_CLEAR];
+ else
+ global_irq_clr = bwmon->regs[F_GLOBAL_IRQ_CLEAR];
+
/*
* Clear zone and global interrupts. The order and barriers are
* important. Quoting downstream Qualcomm msm-4.9 tree:
@@ -370,15 +499,22 @@ static void bwmon_clear_irq(struct icc_bwmon *bwmon)
if (bwmon->data->quirks & BWMON_NEEDS_FORCE_CLEAR)
regmap_field_force_write(bwmon->regs[F_IRQ_CLEAR], 0);
if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ)
- regmap_field_force_write(bwmon->regs[F_GLOBAL_IRQ_CLEAR],
+ regmap_field_force_write(global_irq_clr,
BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE);
}
static void bwmon_disable(struct icc_bwmon *bwmon)
{
+ struct regmap_field *global_irq_en;
+
+ if (bwmon->data->global_regmap_fields)
+ global_irq_en = bwmon->global_regs[F_GLOBAL_IRQ_ENABLE];
+ else
+ global_irq_en = bwmon->regs[F_GLOBAL_IRQ_ENABLE];
+
/* Disable interrupts. Strict ordering, see bwmon_clear_irq(). */
if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ)
- regmap_field_write(bwmon->regs[F_GLOBAL_IRQ_ENABLE], 0x0);
+ regmap_field_write(global_irq_en, 0x0);
regmap_field_write(bwmon->regs[F_IRQ_ENABLE], 0x0);
/*
@@ -390,10 +526,18 @@ static void bwmon_disable(struct icc_bwmon *bwmon)
static void bwmon_enable(struct icc_bwmon *bwmon, unsigned int irq_enable)
{
+ struct regmap_field *global_irq_en;
+
+ if (bwmon->data->global_regmap_fields)
+ global_irq_en = bwmon->global_regs[F_GLOBAL_IRQ_ENABLE];
+ else
+ global_irq_en = bwmon->regs[F_GLOBAL_IRQ_ENABLE];
+
/* Enable interrupts */
if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ)
- regmap_field_write(bwmon->regs[F_GLOBAL_IRQ_ENABLE],
+ regmap_field_write(global_irq_en,
BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE);
+
regmap_field_write(bwmon->regs[F_IRQ_ENABLE], irq_enable);
/* Enable bwmon */
@@ -419,20 +563,21 @@ static void bwmon_set_threshold(struct icc_bwmon *bwmon,
static void bwmon_start(struct icc_bwmon *bwmon)
{
const struct icc_bwmon_data *data = bwmon->data;
+ u32 bw_low = 0;
int window;
+ /* No need to check for errors, as this must have succeeded before. */
+ dev_pm_opp_put(dev_pm_opp_find_bw_ceil(bwmon->dev, &bw_low, 0));
+
bwmon_clear_counters(bwmon, true);
window = mult_frac(bwmon->data->sample_ms, HW_TIMER_HZ, MSEC_PER_SEC);
/* Maximum sampling window: 0xffffff for v4 and 0xfffff for v5 */
regmap_field_write(bwmon->regs[F_SAMPLE_WINDOW], window);
- bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_HIGH],
- data->default_highbw_kbps);
- bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_MED],
- data->default_medbw_kbps);
- bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_LOW],
- data->default_lowbw_kbps);
+ bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_HIGH], bw_low);
+ bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_MED], bw_low);
+ bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_LOW], 0);
regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE0],
BWMON_THRESHOLD_COUNT_ZONE0_DEFAULT);
@@ -502,14 +647,18 @@ 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)
target_opp = dev_pm_opp_find_bw_floor(bwmon->dev, &bw_kbps, 0);
+ if (IS_ERR(target_opp))
+ return IRQ_HANDLED;
+
bwmon->target_kbps = bw_kbps;
bw_kbps--;
@@ -536,6 +685,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;
@@ -556,7 +706,9 @@ static int bwmon_init_regmap(struct platform_device *pdev,
struct device *dev = &pdev->dev;
void __iomem *base;
struct regmap *map;
+ int ret;
+ /* Map the monitor base */
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return dev_err_probe(dev, PTR_ERR(base),
@@ -567,12 +719,35 @@ static int bwmon_init_regmap(struct platform_device *pdev,
return dev_err_probe(dev, PTR_ERR(map),
"failed to initialize regmap\n");
+ BUILD_BUG_ON(ARRAY_SIZE(msm8998_bwmon_global_reg_fields) != F_NUM_GLOBAL_FIELDS);
BUILD_BUG_ON(ARRAY_SIZE(msm8998_bwmon_reg_fields) != F_NUM_FIELDS);
+ BUILD_BUG_ON(ARRAY_SIZE(sdm845_cpu_bwmon_reg_fields) != F_NUM_FIELDS);
BUILD_BUG_ON(ARRAY_SIZE(sdm845_llcc_bwmon_reg_fields) != F_NUM_FIELDS);
- return devm_regmap_field_bulk_alloc(dev, map, bwmon->regs,
+ ret = devm_regmap_field_bulk_alloc(dev, map, bwmon->regs,
bwmon->data->regmap_fields,
F_NUM_FIELDS);
+ if (ret)
+ return ret;
+
+ if (bwmon->data->global_regmap_cfg) {
+ /* Map the global base, if separate */
+ base = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(base))
+ return dev_err_probe(dev, PTR_ERR(base),
+ "failed to map bwmon global registers\n");
+
+ map = devm_regmap_init_mmio(dev, base, bwmon->data->global_regmap_cfg);
+ if (IS_ERR(map))
+ return dev_err_probe(dev, PTR_ERR(map),
+ "failed to initialize global regmap\n");
+
+ ret = devm_regmap_field_bulk_alloc(dev, map, bwmon->global_regs,
+ bwmon->data->global_regmap_fields,
+ F_NUM_GLOBAL_FIELDS);
+ }
+
+ return ret;
}
static int bwmon_probe(struct platform_device *pdev)
@@ -603,19 +778,26 @@ static int bwmon_probe(struct platform_device *pdev)
bwmon->max_bw_kbps = UINT_MAX;
opp = dev_pm_opp_find_bw_floor(dev, &bwmon->max_bw_kbps, 0);
if (IS_ERR(opp))
- return dev_err_probe(dev, ret, "failed to find max peak bandwidth\n");
+ 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, ret, "failed to find min peak bandwidth\n");
+ 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");
@@ -625,34 +807,39 @@ static int bwmon_probe(struct platform_device *pdev)
return 0;
}
-static int bwmon_remove(struct platform_device *pdev)
+static void bwmon_remove(struct platform_device *pdev)
{
struct icc_bwmon *bwmon = platform_get_drvdata(pdev);
bwmon_disable(bwmon);
-
- return 0;
+ free_irq(bwmon->irq, bwmon);
}
static const struct icc_bwmon_data msm8998_bwmon_data = {
.sample_ms = 4,
- .count_unit_kb = 64,
- .default_highbw_kbps = 4800 * 1024, /* 4.8 GBps */
- .default_medbw_kbps = 512 * 1024, /* 512 MBps */
- .default_lowbw_kbps = 0,
+ .count_unit_kb = 1024,
.zone1_thres_count = 16,
.zone3_thres_count = 1,
.quirks = BWMON_HAS_GLOBAL_IRQ,
.regmap_fields = msm8998_bwmon_reg_fields,
.regmap_cfg = &msm8998_bwmon_regmap_cfg,
+ .global_regmap_fields = msm8998_bwmon_global_reg_fields,
+ .global_regmap_cfg = &msm8998_bwmon_global_regmap_cfg,
+};
+
+static const struct icc_bwmon_data sdm845_cpu_bwmon_data = {
+ .sample_ms = 4,
+ .count_unit_kb = 64,
+ .zone1_thres_count = 16,
+ .zone3_thres_count = 1,
+ .quirks = BWMON_HAS_GLOBAL_IRQ,
+ .regmap_fields = sdm845_cpu_bwmon_reg_fields,
+ .regmap_cfg = &sdm845_cpu_bwmon_regmap_cfg,
};
static const struct icc_bwmon_data sdm845_llcc_bwmon_data = {
.sample_ms = 4,
.count_unit_kb = 1024,
- .default_highbw_kbps = 800 * 1024, /* 800 MBps */
- .default_medbw_kbps = 256 * 1024, /* 256 MBps */
- .default_lowbw_kbps = 0,
.zone1_thres_count = 16,
.zone3_thres_count = 1,
.regmap_fields = sdm845_llcc_bwmon_reg_fields,
@@ -662,9 +849,6 @@ static const struct icc_bwmon_data sdm845_llcc_bwmon_data = {
static const struct icc_bwmon_data sc7280_llcc_bwmon_data = {
.sample_ms = 4,
.count_unit_kb = 64,
- .default_highbw_kbps = 800 * 1024, /* 800 MBps */
- .default_medbw_kbps = 256 * 1024, /* 256 MBps */
- .default_lowbw_kbps = 0,
.zone1_thres_count = 16,
.zone3_thres_count = 1,
.quirks = BWMON_NEEDS_FORCE_CLEAR,
@@ -673,16 +857,18 @@ static const struct icc_bwmon_data sc7280_llcc_bwmon_data = {
};
static const struct of_device_id bwmon_of_match[] = {
- {
- .compatible = "qcom,msm8998-bwmon",
- .data = &msm8998_bwmon_data
- }, {
- .compatible = "qcom,sdm845-llcc-bwmon",
- .data = &sdm845_llcc_bwmon_data
- }, {
- .compatible = "qcom,sc7280-llcc-bwmon",
- .data = &sc7280_llcc_bwmon_data
- },
+ /* BWMONv4, separate monitor and global register spaces */
+ { .compatible = "qcom,msm8998-bwmon", .data = &msm8998_bwmon_data },
+ /* BWMONv4, unified register space */
+ { .compatible = "qcom,sdm845-bwmon", .data = &sdm845_cpu_bwmon_data },
+ /* BWMONv5 */
+ { .compatible = "qcom,sdm845-llcc-bwmon", .data = &sdm845_llcc_bwmon_data },
+ { .compatible = "qcom,sc7280-llcc-bwmon", .data = &sc7280_llcc_bwmon_data },
+
+ /* Compatibles kept for legacy reasons */
+ { .compatible = "qcom,sc7280-cpu-bwmon", .data = &sdm845_cpu_bwmon_data },
+ { .compatible = "qcom,sc8280xp-cpu-bwmon", .data = &sdm845_cpu_bwmon_data },
+ { .compatible = "qcom,sm8550-cpu-bwmon", .data = &sdm845_cpu_bwmon_data },
{}
};
MODULE_DEVICE_TABLE(of, bwmon_of_match);
diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c
new file mode 100644
index 000000000000..b203bc685cad
--- /dev/null
+++ b/drivers/soc/qcom/ice.c
@@ -0,0 +1,754 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Qualcomm ICE (Inline Crypto Engine) support.
+ *
+ * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019, Google LLC
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/iopoll.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+#include <linux/firmware/qcom/qcom_scm.h>
+
+#include <soc/qcom/ice.h>
+
+#define AES_256_XTS_KEY_SIZE 64 /* for raw keys only */
+
+#define QCOM_ICE_HWKM_V1 1 /* HWKM version 1 */
+#define QCOM_ICE_HWKM_V2 2 /* HWKM version 2 */
+
+#define QCOM_ICE_HWKM_MAX_WRAPPED_KEY_SIZE 100 /* Maximum HWKM wrapped key size */
+
+/*
+ * Wrapped key size depends upon HWKM version:
+ * HWKM version 1 supports 68 bytes
+ * HWKM version 2 supports 100 bytes
+ */
+#define QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(v) ((v) == QCOM_ICE_HWKM_V1 ? 68 : 100)
+
+/* QCOM ICE registers */
+
+#define QCOM_ICE_REG_CONTROL 0x0000
+#define QCOM_ICE_LEGACY_MODE_ENABLED BIT(0)
+
+#define QCOM_ICE_REG_VERSION 0x0008
+
+#define QCOM_ICE_REG_FUSE_SETTING 0x0010
+#define QCOM_ICE_FUSE_SETTING_MASK BIT(0)
+#define QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK BIT(1)
+#define QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK BIT(2)
+
+#define QCOM_ICE_REG_BIST_STATUS 0x0070
+#define QCOM_ICE_BIST_STATUS_MASK GENMASK(31, 28)
+
+#define QCOM_ICE_REG_ADVANCED_CONTROL 0x1000
+
+#define QCOM_ICE_REG_CRYPTOCFG_BASE 0x4040
+#define QCOM_ICE_REG_CRYPTOCFG_SIZE 0x80
+#define QCOM_ICE_REG_CRYPTOCFG(slot) (QCOM_ICE_REG_CRYPTOCFG_BASE + \
+ QCOM_ICE_REG_CRYPTOCFG_SIZE * (slot))
+union crypto_cfg {
+ __le32 regval;
+ struct {
+ u8 dusize;
+ u8 capidx;
+ u8 reserved;
+#define QCOM_ICE_HWKM_CFG_ENABLE_VAL BIT(7)
+ u8 cfge;
+ };
+};
+
+/* QCOM ICE HWKM (Hardware Key Manager) registers */
+
+#define HWKM_OFFSET 0x8000
+
+#define QCOM_ICE_REG_HWKM_TZ_KM_CTL (HWKM_OFFSET + 0x1000)
+#define QCOM_ICE_HWKM_DISABLE_CRC_CHECKS_VAL (BIT(1) | BIT(2))
+/* In HWKM v1 the ICE legacy mode is controlled from HWKM register space */
+#define QCOM_ICE_HWKM_ICE_LEGACY_MODE_ENABLED BIT(5)
+
+#define QCOM_ICE_REG_HWKM_TZ_KM_STATUS (HWKM_OFFSET + 0x1004)
+#define QCOM_ICE_HWKM_KT_CLEAR_DONE BIT(0)
+#define QCOM_ICE_HWKM_BOOT_CMD_LIST0_DONE BIT(1)
+#define QCOM_ICE_HWKM_BOOT_CMD_LIST1_DONE BIT(2)
+#define QCOM_ICE_HWKM_CRYPTO_BIST_DONE(v) (((v) == QCOM_ICE_HWKM_V1) ? BIT(14) : BIT(7))
+#define QCOM_ICE_HWKM_BIST_DONE(v) (((v) == QCOM_ICE_HWKM_V1) ? BIT(16) : BIT(9))
+
+#define QCOM_ICE_REG_HWKM_BANK0_BANKN_IRQ_STATUS (HWKM_OFFSET + 0x2008)
+#define QCOM_ICE_HWKM_RSP_FIFO_CLEAR_VAL BIT(3)
+
+#define QCOM_ICE_REG_HWKM_BANK0_BBAC_0 (HWKM_OFFSET + 0x5000)
+#define QCOM_ICE_REG_HWKM_BANK0_BBAC_1 (HWKM_OFFSET + 0x5004)
+#define QCOM_ICE_REG_HWKM_BANK0_BBAC_2 (HWKM_OFFSET + 0x5008)
+#define QCOM_ICE_REG_HWKM_BANK0_BBAC_3 (HWKM_OFFSET + 0x500C)
+#define QCOM_ICE_REG_HWKM_BANK0_BBAC_4 (HWKM_OFFSET + 0x5010)
+
+#define qcom_ice_writel(engine, val, reg) \
+ writel((val), (engine)->base + (reg))
+
+#define qcom_ice_readl(engine, reg) \
+ readl((engine)->base + (reg))
+
+static bool qcom_ice_use_wrapped_keys;
+module_param_named(use_wrapped_keys, qcom_ice_use_wrapped_keys, bool, 0660);
+MODULE_PARM_DESC(use_wrapped_keys,
+ "Support wrapped keys instead of raw keys, if available on the platform");
+
+struct qcom_ice {
+ struct device *dev;
+ void __iomem *base;
+
+ struct clk *core_clk;
+ bool use_hwkm;
+ bool hwkm_init_complete;
+ u8 hwkm_version;
+};
+
+static bool qcom_ice_check_supported(struct qcom_ice *ice)
+{
+ u32 regval = qcom_ice_readl(ice, QCOM_ICE_REG_VERSION);
+ struct device *dev = ice->dev;
+ int major = FIELD_GET(GENMASK(31, 24), regval);
+ int minor = FIELD_GET(GENMASK(23, 16), regval);
+ int step = FIELD_GET(GENMASK(15, 0), regval);
+
+ /* For now this driver only supports ICE version 3 and 4. */
+ if (major != 3 && major != 4) {
+ dev_warn(dev, "Unsupported ICE version: v%d.%d.%d\n",
+ major, minor, step);
+ return false;
+ }
+
+ /* HWKM version v2 is present from ICE 3.2.1 onwards while version v1
+ * is present only in ICE 3.2.0. Earlier ICE version don't have HWKM.
+ */
+ if (major > 3 ||
+ (major == 3 && (minor >= 3 || (minor == 2 && step >= 1))))
+ ice->hwkm_version = QCOM_ICE_HWKM_V2;
+ else if ((major == 3) && (minor == 2))
+ ice->hwkm_version = QCOM_ICE_HWKM_V1;
+ else
+ ice->hwkm_version = 0;
+
+ dev_info(dev, "Found QC Inline Crypto Engine (ICE) v%d.%d.%d\n",
+ major, minor, step);
+
+ if (ice->hwkm_version)
+ dev_info(dev, "QC Hardware Key Manager (HWKM) version v%d\n",
+ ice->hwkm_version);
+
+ /* If fuses are blown, ICE might not work in the standard way. */
+ regval = qcom_ice_readl(ice, QCOM_ICE_REG_FUSE_SETTING);
+ if (regval & (QCOM_ICE_FUSE_SETTING_MASK |
+ QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK |
+ QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK)) {
+ dev_warn(dev, "Fuses are blown; ICE is unusable!\n");
+ return false;
+ }
+
+ /*
+ * Check for HWKM support and decide whether to use it or not. ICE
+ * v3.2.1 and later have HWKM v2. ICE v3.2.0 has HWKM v1. Earlier ICE
+ * versions don't have HWKM at all. However, for HWKM to be fully
+ * usable by Linux, the TrustZone software also needs to support certain
+ * SCM calls including the ones to generate and prepare keys. Support
+ * for these SCM calls is present for SoCs with HWKM v2 and is being
+ * added for SoCs with HWKM v1 as well but not every SoC with HWKM v1
+ * currently supports this. So, this driver checks for the SCM call
+ * support before it decides to use HWKM.
+ *
+ * Also, since HWKM and legacy mode are mutually exclusive, and
+ * ICE-capable storage driver(s) need to know early on whether to
+ * advertise support for raw keys or wrapped keys, HWKM cannot be used
+ * unconditionally. A module parameter is used to opt into using it.
+ */
+ if (ice->hwkm_version && qcom_scm_has_wrapped_key_support()) {
+ if (qcom_ice_use_wrapped_keys) {
+ dev_info(dev, "Using HWKM. Supporting wrapped keys only.\n");
+ ice->use_hwkm = true;
+ } else {
+ dev_info(dev, "Not using HWKM. Supporting raw keys only.\n");
+ }
+ } else if (qcom_ice_use_wrapped_keys) {
+ dev_warn(dev, "A supported HWKM is not present. Ignoring qcom_ice.use_wrapped_keys=1.\n");
+ } else {
+ dev_info(dev, "A supported HWKM is not present. Supporting raw keys only.\n");
+ }
+ return true;
+}
+
+static void qcom_ice_low_power_mode_enable(struct qcom_ice *ice)
+{
+ u32 regval;
+
+ regval = qcom_ice_readl(ice, QCOM_ICE_REG_ADVANCED_CONTROL);
+
+ /* Enable low power mode sequence */
+ regval |= 0x7000;
+ qcom_ice_writel(ice, regval, QCOM_ICE_REG_ADVANCED_CONTROL);
+}
+
+static void qcom_ice_optimization_enable(struct qcom_ice *ice)
+{
+ u32 regval;
+
+ /* ICE Optimizations Enable Sequence */
+ regval = qcom_ice_readl(ice, QCOM_ICE_REG_ADVANCED_CONTROL);
+ regval |= 0xd807100;
+ /* ICE HPG requires delay before writing */
+ udelay(5);
+ qcom_ice_writel(ice, regval, QCOM_ICE_REG_ADVANCED_CONTROL);
+ udelay(5);
+}
+
+/*
+ * Wait until the ICE BIST (built-in self-test) has completed.
+ *
+ * This may be necessary before ICE can be used.
+ * Note that we don't really care whether the BIST passed or failed;
+ * we really just want to make sure that it isn't still running. This is
+ * because (a) the BIST is a FIPS compliance thing that never fails in
+ * practice, (b) ICE is documented to reject crypto requests if the BIST
+ * fails, so we needn't do it in software too, and (c) properly testing
+ * storage encryption requires testing the full storage stack anyway,
+ * and not relying on hardware-level self-tests.
+ */
+static int qcom_ice_wait_bist_status(struct qcom_ice *ice)
+{
+ u32 regval;
+ int err;
+
+ err = readl_poll_timeout(ice->base + QCOM_ICE_REG_BIST_STATUS,
+ regval, !(regval & QCOM_ICE_BIST_STATUS_MASK),
+ 50, 5000);
+ if (err) {
+ dev_err(ice->dev, "Timed out waiting for ICE self-test to complete\n");
+ return err;
+ }
+
+ if (ice->use_hwkm &&
+ qcom_ice_readl(ice, QCOM_ICE_REG_HWKM_TZ_KM_STATUS) !=
+ (QCOM_ICE_HWKM_KT_CLEAR_DONE |
+ QCOM_ICE_HWKM_BOOT_CMD_LIST0_DONE |
+ QCOM_ICE_HWKM_BOOT_CMD_LIST1_DONE |
+ QCOM_ICE_HWKM_CRYPTO_BIST_DONE(ice->hwkm_version) |
+ QCOM_ICE_HWKM_BIST_DONE(ice->hwkm_version))) {
+ dev_err(ice->dev, "HWKM self-test error!\n");
+ /*
+ * Too late to revoke use_hwkm here, as it was already
+ * propagated up the stack into the crypto capabilities.
+ */
+ }
+ return 0;
+}
+
+static void qcom_ice_hwkm_init(struct qcom_ice *ice)
+{
+ u32 regval;
+
+ if (!ice->use_hwkm)
+ return;
+
+ BUILD_BUG_ON(QCOM_ICE_HWKM_MAX_WRAPPED_KEY_SIZE >
+ BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE);
+ /*
+ * When ICE is in HWKM mode, it only supports wrapped keys.
+ * When ICE is in legacy mode, it only supports raw keys.
+ *
+ * Put ICE in HWKM mode. ICE defaults to legacy mode.
+ */
+ if (ice->hwkm_version == QCOM_ICE_HWKM_V2) {
+ regval = qcom_ice_readl(ice, QCOM_ICE_REG_CONTROL);
+ regval &= ~QCOM_ICE_LEGACY_MODE_ENABLED;
+ qcom_ice_writel(ice, regval, QCOM_ICE_REG_CONTROL);
+ } else if (ice->hwkm_version == QCOM_ICE_HWKM_V1) {
+ regval = qcom_ice_readl(ice, QCOM_ICE_REG_HWKM_TZ_KM_CTL);
+ regval &= ~QCOM_ICE_HWKM_ICE_LEGACY_MODE_ENABLED;
+ qcom_ice_writel(ice, regval, QCOM_ICE_REG_HWKM_TZ_KM_CTL);
+ }
+
+ /* Disable CRC checks. This HWKM feature is not used. */
+ qcom_ice_writel(ice, QCOM_ICE_HWKM_DISABLE_CRC_CHECKS_VAL,
+ QCOM_ICE_REG_HWKM_TZ_KM_CTL);
+
+ /*
+ * Allow the HWKM slave to read and write the keyslots in the ICE HWKM
+ * slave. Without this, TrustZone cannot program keys into ICE.
+ */
+ qcom_ice_writel(ice, GENMASK(31, 0), QCOM_ICE_REG_HWKM_BANK0_BBAC_0);
+ qcom_ice_writel(ice, GENMASK(31, 0), QCOM_ICE_REG_HWKM_BANK0_BBAC_1);
+ qcom_ice_writel(ice, GENMASK(31, 0), QCOM_ICE_REG_HWKM_BANK0_BBAC_2);
+ qcom_ice_writel(ice, GENMASK(31, 0), QCOM_ICE_REG_HWKM_BANK0_BBAC_3);
+ qcom_ice_writel(ice, GENMASK(31, 0), QCOM_ICE_REG_HWKM_BANK0_BBAC_4);
+
+ /* Clear the HWKM response FIFO. */
+ qcom_ice_writel(ice, QCOM_ICE_HWKM_RSP_FIFO_CLEAR_VAL,
+ QCOM_ICE_REG_HWKM_BANK0_BANKN_IRQ_STATUS);
+ ice->hwkm_init_complete = true;
+}
+
+int qcom_ice_enable(struct qcom_ice *ice)
+{
+ qcom_ice_low_power_mode_enable(ice);
+ qcom_ice_optimization_enable(ice);
+ qcom_ice_hwkm_init(ice);
+ return qcom_ice_wait_bist_status(ice);
+}
+EXPORT_SYMBOL_GPL(qcom_ice_enable);
+
+int qcom_ice_resume(struct qcom_ice *ice)
+{
+ struct device *dev = ice->dev;
+ int err;
+
+ err = clk_prepare_enable(ice->core_clk);
+ if (err) {
+ dev_err(dev, "failed to enable core clock (%d)\n",
+ err);
+ return err;
+ }
+ qcom_ice_hwkm_init(ice);
+ return qcom_ice_wait_bist_status(ice);
+}
+EXPORT_SYMBOL_GPL(qcom_ice_resume);
+
+int qcom_ice_suspend(struct qcom_ice *ice)
+{
+ clk_disable_unprepare(ice->core_clk);
+ ice->hwkm_init_complete = false;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_ice_suspend);
+
+static unsigned int translate_hwkm_slot(struct qcom_ice *ice, unsigned int slot)
+{
+ return ice->hwkm_version == QCOM_ICE_HWKM_V1 ? slot : slot * 2;
+}
+
+static int qcom_ice_program_wrapped_key(struct qcom_ice *ice, unsigned int slot,
+ const struct blk_crypto_key *bkey)
+{
+ struct device *dev = ice->dev;
+ union crypto_cfg cfg = {
+ .dusize = bkey->crypto_cfg.data_unit_size / 512,
+ .capidx = QCOM_SCM_ICE_CIPHER_AES_256_XTS,
+ .cfge = QCOM_ICE_HWKM_CFG_ENABLE_VAL,
+ };
+ int err;
+
+ if (!ice->use_hwkm) {
+ dev_err_ratelimited(dev, "Got wrapped key when not using HWKM\n");
+ return -EINVAL;
+ }
+ if (!ice->hwkm_init_complete) {
+ dev_err_ratelimited(dev, "HWKM not yet initialized\n");
+ return -EINVAL;
+ }
+
+ /* Clear CFGE before programming the key. */
+ qcom_ice_writel(ice, 0x0, QCOM_ICE_REG_CRYPTOCFG(slot));
+
+ /* Call into TrustZone to program the wrapped key using HWKM. */
+ err = qcom_scm_ice_set_key(translate_hwkm_slot(ice, slot), bkey->bytes,
+ bkey->size, cfg.capidx, cfg.dusize);
+ if (err) {
+ dev_err_ratelimited(dev,
+ "qcom_scm_ice_set_key failed; err=%d, slot=%u\n",
+ err, slot);
+ return err;
+ }
+
+ /* Set CFGE after programming the key. */
+ qcom_ice_writel(ice, le32_to_cpu(cfg.regval),
+ QCOM_ICE_REG_CRYPTOCFG(slot));
+ return 0;
+}
+
+int qcom_ice_program_key(struct qcom_ice *ice, unsigned int slot,
+ const struct blk_crypto_key *blk_key)
+{
+ struct device *dev = ice->dev;
+ union {
+ u8 bytes[AES_256_XTS_KEY_SIZE];
+ u32 words[AES_256_XTS_KEY_SIZE / sizeof(u32)];
+ } key;
+ int i;
+ int err;
+
+ /* Only AES-256-XTS has been tested so far. */
+ if (blk_key->crypto_cfg.crypto_mode !=
+ BLK_ENCRYPTION_MODE_AES_256_XTS) {
+ dev_err_ratelimited(dev, "Unsupported crypto mode: %d\n",
+ blk_key->crypto_cfg.crypto_mode);
+ return -EINVAL;
+ }
+
+ if (blk_key->crypto_cfg.key_type == BLK_CRYPTO_KEY_TYPE_HW_WRAPPED)
+ return qcom_ice_program_wrapped_key(ice, slot, blk_key);
+
+ if (ice->use_hwkm) {
+ dev_err_ratelimited(dev, "Got raw key when using HWKM\n");
+ return -EINVAL;
+ }
+
+ if (blk_key->size != AES_256_XTS_KEY_SIZE) {
+ dev_err_ratelimited(dev, "Incorrect key size\n");
+ return -EINVAL;
+ }
+ memcpy(key.bytes, blk_key->bytes, AES_256_XTS_KEY_SIZE);
+
+ /* The SCM call requires that the key words are encoded in big endian */
+ for (i = 0; i < ARRAY_SIZE(key.words); i++)
+ __cpu_to_be32s(&key.words[i]);
+
+ err = qcom_scm_ice_set_key(slot, key.bytes, AES_256_XTS_KEY_SIZE,
+ QCOM_SCM_ICE_CIPHER_AES_256_XTS,
+ blk_key->crypto_cfg.data_unit_size / 512);
+
+ memzero_explicit(&key, sizeof(key));
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(qcom_ice_program_key);
+
+int qcom_ice_evict_key(struct qcom_ice *ice, int slot)
+{
+ if (ice->hwkm_init_complete)
+ slot = translate_hwkm_slot(ice, slot);
+ return qcom_scm_ice_invalidate_key(slot);
+}
+EXPORT_SYMBOL_GPL(qcom_ice_evict_key);
+
+/**
+ * qcom_ice_get_supported_key_type() - Get the supported key type
+ * @ice: ICE driver data
+ *
+ * Return: the blk-crypto key type that the ICE driver is configured to use.
+ * This is the key type that ICE-capable storage drivers should advertise as
+ * supported in the crypto capabilities of any disks they register.
+ */
+enum blk_crypto_key_type qcom_ice_get_supported_key_type(struct qcom_ice *ice)
+{
+ if (ice->use_hwkm)
+ return BLK_CRYPTO_KEY_TYPE_HW_WRAPPED;
+ return BLK_CRYPTO_KEY_TYPE_RAW;
+}
+EXPORT_SYMBOL_GPL(qcom_ice_get_supported_key_type);
+
+/**
+ * qcom_ice_derive_sw_secret() - Derive software secret from wrapped key
+ * @ice: ICE driver data
+ * @eph_key: an ephemerally-wrapped key
+ * @eph_key_size: size of @eph_key in bytes
+ * @sw_secret: output buffer for the software secret
+ *
+ * Use HWKM to derive the "software secret" from a hardware-wrapped key that is
+ * given in ephemerally-wrapped form.
+ *
+ * Return: 0 on success; -EBADMSG if the given ephemerally-wrapped key is
+ * invalid; or another -errno value.
+ */
+int qcom_ice_derive_sw_secret(struct qcom_ice *ice,
+ const u8 *eph_key, size_t eph_key_size,
+ u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE])
+{
+ int err = qcom_scm_derive_sw_secret(eph_key, eph_key_size,
+ sw_secret,
+ BLK_CRYPTO_SW_SECRET_SIZE);
+ if (err == -EIO || err == -EINVAL)
+ err = -EBADMSG; /* probably invalid key */
+ return err;
+}
+EXPORT_SYMBOL_GPL(qcom_ice_derive_sw_secret);
+
+/**
+ * qcom_ice_generate_key() - Generate a wrapped key for inline encryption
+ * @ice: ICE driver data
+ * @lt_key: output buffer for the long-term wrapped key
+ *
+ * Use HWKM to generate a new key and return it as a long-term wrapped key.
+ *
+ * Return: the size of the resulting wrapped key on success; -errno on failure.
+ */
+int qcom_ice_generate_key(struct qcom_ice *ice,
+ u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE])
+{
+ int err;
+
+ err = qcom_scm_generate_ice_key(lt_key,
+ QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(ice->hwkm_version));
+ if (err)
+ return err;
+
+ return QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(ice->hwkm_version);
+}
+EXPORT_SYMBOL_GPL(qcom_ice_generate_key);
+
+/**
+ * qcom_ice_prepare_key() - Prepare a wrapped key for inline encryption
+ * @ice: ICE driver data
+ * @lt_key: a long-term wrapped key
+ * @lt_key_size: size of @lt_key in bytes
+ * @eph_key: output buffer for the ephemerally-wrapped key
+ *
+ * Use HWKM to re-wrap a long-term wrapped key with the per-boot ephemeral key.
+ *
+ * Return: the size of the resulting wrapped key on success; -EBADMSG if the
+ * given long-term wrapped key is invalid; or another -errno value.
+ */
+int qcom_ice_prepare_key(struct qcom_ice *ice,
+ const u8 *lt_key, size_t lt_key_size,
+ u8 eph_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE])
+{
+ int err;
+
+ err = qcom_scm_prepare_ice_key(lt_key, lt_key_size,
+ eph_key, QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(ice->hwkm_version));
+ if (err == -EIO || err == -EINVAL)
+ err = -EBADMSG; /* probably invalid key */
+ if (err)
+ return err;
+
+ return QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(ice->hwkm_version);
+}
+EXPORT_SYMBOL_GPL(qcom_ice_prepare_key);
+
+/**
+ * qcom_ice_import_key() - Import a raw key for inline encryption
+ * @ice: ICE driver data
+ * @raw_key: the raw key to import
+ * @raw_key_size: size of @raw_key in bytes
+ * @lt_key: output buffer for the long-term wrapped key
+ *
+ * Use HWKM to import a raw key and return it as a long-term wrapped key.
+ *
+ * Return: the size of the resulting wrapped key on success; -errno on failure.
+ */
+int qcom_ice_import_key(struct qcom_ice *ice,
+ const u8 *raw_key, size_t raw_key_size,
+ u8 lt_key[BLK_CRYPTO_MAX_HW_WRAPPED_KEY_SIZE])
+{
+ int err;
+
+ err = qcom_scm_import_ice_key(raw_key, raw_key_size,
+ lt_key, QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(ice->hwkm_version));
+ if (err)
+ return err;
+
+ return QCOM_ICE_HWKM_WRAPPED_KEY_SIZE(ice->hwkm_version);
+}
+EXPORT_SYMBOL_GPL(qcom_ice_import_key);
+
+static struct qcom_ice *qcom_ice_create(struct device *dev,
+ void __iomem *base)
+{
+ struct qcom_ice *engine;
+
+ if (!qcom_scm_is_available())
+ return ERR_PTR(-EPROBE_DEFER);
+
+ if (!qcom_scm_ice_available()) {
+ dev_warn(dev, "ICE SCM interface not found\n");
+ return NULL;
+ }
+
+ engine = devm_kzalloc(dev, sizeof(*engine), GFP_KERNEL);
+ if (!engine)
+ return ERR_PTR(-ENOMEM);
+
+ engine->dev = dev;
+ engine->base = base;
+
+ /*
+ * Legacy DT binding uses different clk names for each consumer,
+ * so lets try those first. If none of those are a match, it means
+ * the we only have one clock and it is part of the dedicated DT node.
+ * Also, enable the clock before we check what HW version the driver
+ * supports.
+ */
+ engine->core_clk = devm_clk_get_optional_enabled(dev, "ice_core_clk");
+ if (!engine->core_clk)
+ engine->core_clk = devm_clk_get_optional_enabled(dev, "ice");
+ if (!engine->core_clk)
+ engine->core_clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(engine->core_clk))
+ return ERR_CAST(engine->core_clk);
+
+ if (!qcom_ice_check_supported(engine))
+ return ERR_PTR(-EOPNOTSUPP);
+
+ dev_dbg(dev, "Registered Qualcomm Inline Crypto Engine\n");
+
+ return engine;
+}
+
+/**
+ * of_qcom_ice_get() - get an ICE instance from a DT node
+ * @dev: device pointer for the consumer device
+ *
+ * This function will provide an ICE instance either by creating one for the
+ * consumer device if its DT node provides the 'ice' reg range and the 'ice'
+ * clock (for legacy DT style). On the other hand, if consumer provides a
+ * phandle via 'qcom,ice' property to an ICE DT, the ICE instance will already
+ * be created and so this function will return that instead.
+ *
+ * Return: ICE pointer on success, NULL if there is no ICE data provided by the
+ * consumer or ERR_PTR() on error.
+ */
+static struct qcom_ice *of_qcom_ice_get(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct qcom_ice *ice;
+ struct resource *res;
+ void __iomem *base;
+ struct device_link *link;
+
+ if (!dev || !dev->of_node)
+ return ERR_PTR(-ENODEV);
+
+ /*
+ * In order to support legacy style devicetree bindings, we need
+ * to create the ICE instance using the consumer device and the reg
+ * range called 'ice' it provides.
+ */
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ice");
+ if (res) {
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return ERR_CAST(base);
+
+ /* create ICE instance using consumer dev */
+ return qcom_ice_create(&pdev->dev, base);
+ }
+
+ /*
+ * If the consumer node does not provider an 'ice' reg range
+ * (legacy DT binding), then it must at least provide a phandle
+ * to the ICE devicetree node, otherwise ICE is not supported.
+ */
+ 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);
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+
+ ice = platform_get_drvdata(pdev);
+ if (!ice) {
+ dev_err(dev, "Cannot get ice instance from %s\n",
+ dev_name(&pdev->dev));
+ platform_device_put(pdev);
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+
+ 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));
+ platform_device_put(pdev);
+ ice = ERR_PTR(-EINVAL);
+ }
+
+ return ice;
+}
+
+static void qcom_ice_put(const struct qcom_ice *ice)
+{
+ struct platform_device *pdev = to_platform_device(ice->dev);
+
+ if (!platform_get_resource_byname(pdev, IORESOURCE_MEM, "ice"))
+ platform_device_put(pdev);
+}
+
+static void devm_of_qcom_ice_put(struct device *dev, void *res)
+{
+ qcom_ice_put(*(struct qcom_ice **)res);
+}
+
+/**
+ * devm_of_qcom_ice_get() - Devres managed helper to get an ICE instance from
+ * a DT node.
+ * @dev: device pointer for the consumer device.
+ *
+ * This function will provide an ICE instance either by creating one for the
+ * consumer device if its DT node provides the 'ice' reg range and the 'ice'
+ * clock (for legacy DT style). On the other hand, if consumer provides a
+ * phandle via 'qcom,ice' property to an ICE DT, the ICE instance will already
+ * be created and so this function will return that instead.
+ *
+ * Return: ICE pointer on success, NULL if there is no ICE data provided by the
+ * consumer or ERR_PTR() on error.
+ */
+struct qcom_ice *devm_of_qcom_ice_get(struct device *dev)
+{
+ struct qcom_ice *ice, **dr;
+
+ dr = devres_alloc(devm_of_qcom_ice_put, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return ERR_PTR(-ENOMEM);
+
+ ice = of_qcom_ice_get(dev);
+ if (!IS_ERR_OR_NULL(ice)) {
+ *dr = ice;
+ devres_add(dev, dr);
+ } else {
+ devres_free(dr);
+ }
+
+ return ice;
+}
+EXPORT_SYMBOL_GPL(devm_of_qcom_ice_get);
+
+static int qcom_ice_probe(struct platform_device *pdev)
+{
+ struct qcom_ice *engine;
+ void __iomem *base;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base)) {
+ dev_warn(&pdev->dev, "ICE registers not found\n");
+ return PTR_ERR(base);
+ }
+
+ engine = qcom_ice_create(&pdev->dev, base);
+ if (IS_ERR(engine))
+ return PTR_ERR(engine);
+
+ platform_set_drvdata(pdev, engine);
+
+ return 0;
+}
+
+static const struct of_device_id qcom_ice_of_match_table[] = {
+ { .compatible = "qcom,inline-crypto-engine" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, qcom_ice_of_match_table);
+
+static struct platform_driver qcom_ice_driver = {
+ .probe = qcom_ice_probe,
+ .driver = {
+ .name = "qcom-ice",
+ .of_match_table = qcom_ice_of_match_table,
+ },
+};
+
+module_platform_driver(qcom_ice_driver);
+
+MODULE_DESCRIPTION("Qualcomm Inline Crypto Engine driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/qcom/kryo-l2-accessors.c b/drivers/soc/qcom/kryo-l2-accessors.c
index 7886af4fd726..50cd710c5e82 100644
--- a/drivers/soc/qcom/kryo-l2-accessors.c
+++ b/drivers/soc/qcom/kryo-l2-accessors.c
@@ -32,7 +32,7 @@ void kryo_l2_set_indirect_reg(u64 reg, u64 val)
isb();
raw_spin_unlock_irqrestore(&l2_access_lock, flags);
}
-EXPORT_SYMBOL(kryo_l2_set_indirect_reg);
+EXPORT_SYMBOL_GPL(kryo_l2_set_indirect_reg);
/**
* kryo_l2_get_indirect_reg() - read an L2 register value
@@ -54,4 +54,4 @@ u64 kryo_l2_get_indirect_reg(u64 reg)
return val;
}
-EXPORT_SYMBOL(kryo_l2_get_indirect_reg);
+EXPORT_SYMBOL_GPL(kryo_l2_get_indirect_reg);
diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c
index 23ce2f78c4ed..13e174267294 100644
--- a/drivers/soc/qcom/llcc-qcom.c
+++ b/drivers/soc/qcom/llcc-qcom.c
@@ -7,13 +7,14 @@
#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>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/nvmem-consumer.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/sizes.h>
#include <linux/slab.h>
@@ -26,14 +27,19 @@
#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 ATTR2_PROBE_TARGET_WAYS_MASK BIT(4)
+#define ATTR2_FIXED_SIZE_MASK BIT(8)
+#define ATTR2_PRIORITY_MASK GENMASK(14, 12)
+#define ATTR2_PARENT_SCID_MASK GENMASK(21, 16)
+#define ATTR2_IN_A_GROUP_MASK BIT(24)
#define LLCC_STATUS_READ_DELAY 100
#define CACHE_LINE_SIZE_SHIFT 6
@@ -47,7 +53,11 @@
#define LLCC_TRP_STATUSn(n) (4 + n * SZ_4K)
#define LLCC_TRP_ATTR0_CFGn(n) (0x21000 + SZ_8 * n)
#define LLCC_TRP_ATTR1_CFGn(n) (0x21004 + SZ_8 * n)
-#define LLCC_TRP_ATTR2_CFGn(n) (0x21100 + SZ_8 * n)
+#define LLCC_TRP_ATTR2_CFGn(n) (0x21100 + SZ_4 * n)
+#define LLCC_V6_TRP_ATTR0_CFGn(n) (cfg->reg_offset[LLCC_TRP_ATTR0_CFG] + SZ_64 * (n))
+#define LLCC_V6_TRP_ATTR1_CFGn(n) (cfg->reg_offset[LLCC_TRP_ATTR1_CFG] + SZ_64 * (n))
+#define LLCC_V6_TRP_ATTR2_CFGn(n) (cfg->reg_offset[LLCC_TRP_ATTR2_CFG] + SZ_64 * (n))
+#define LLCC_V6_TRP_ATTR3_CFGn(n) (cfg->reg_offset[LLCC_TRP_ATTR3_CFG] + SZ_64 * (n))
#define LLCC_TRP_SCID_DIS_CAP_ALLOC 0x21f00
#define LLCC_TRP_PCB_ACT 0x21f04
@@ -62,11 +72,10 @@
#define LLCC_TRP_WRSC_CACHEABLE_EN 0x21f2c
#define LLCC_TRP_ALGO_CFG8 0x21f30
-#define BANK_OFFSET_STRIDE 0x80000
-
#define LLCC_VERSION_2_0_0_0 0x02000000
#define LLCC_VERSION_2_1_0_0 0x02010000
#define LLCC_VERSION_4_1_0_0 0x04010000
+#define LLCC_VERSION_6_0_0_0 0X06000000
/**
* struct llcc_slice_config - Data associated with the llcc slice
@@ -94,6 +103,20 @@
* @write_scid_en: Bit enables write cache support for a given scid.
* @write_scid_cacheable_en: Enables write cache cacheable support for a
* given scid (not supported on v2 or older hardware).
+ * @stale_en: Bit enables stale.
+ * @stale_cap_en: Bit enables stale only if current scid is over-cap.
+ * @mru_uncap_en: Roll-over on reserved cache ways if current scid is
+ * under-cap.
+ * @mru_rollover: Roll-over on reserved cache ways.
+ * @alloc_oneway_en: Allways allocate one way on over-cap even if there's no
+ * same-scid lines for replacement.
+ * @ovcap_en: Once current scid is over-capacity, allocate other over-cap SCID.
+ * @ovcap_prio: Once current scid is over-capacity, allocate other low priority
+ * over-cap scid. Depends on corresponding bit being set in
+ * ovcap_en.
+ * @vict_prio: When current scid is under-capacity, allocate over other
+ * lower-than victim priority-line threshold scid.
+ * @parent_slice_id: For grouped slices, specifies the slice id of the parent.
*/
struct llcc_slice_config {
u32 usecase_id;
@@ -118,236 +141,3612 @@ struct llcc_slice_config {
bool ovcap_en;
bool ovcap_prio;
bool vict_prio;
+ u32 parent_slice_id;
};
struct qcom_llcc_config {
const struct llcc_slice_config *sct_data;
- int size;
- bool need_llcc_cfg;
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 skip_llcc_cfg;
+ bool no_edac;
+ bool irq_configured;
+ bool no_broadcast_register;
+};
+
+struct qcom_sct_config {
+ const struct qcom_llcc_config *llcc_config;
+ int num_config;
};
enum llcc_reg_offset {
LLCC_COMMON_HW_INFO,
LLCC_COMMON_STATUS0,
+ LLCC_TRP_ATTR0_CFG,
+ LLCC_TRP_ATTR1_CFG,
+ LLCC_TRP_ATTR2_CFG,
+ LLCC_TRP_ATTR3_CFG,
+ LLCC_TRP_SID_DIS_CAP_ALLOC,
+ LLCC_TRP_ALGO_STALE_EN,
+ LLCC_TRP_ALGO_STALE_CAP_EN,
+ LLCC_TRP_ALGO_MRU0,
+ LLCC_TRP_ALGO_MRU1,
+ LLCC_TRP_ALGO_ALLOC0,
+ LLCC_TRP_ALGO_ALLOC1,
+ LLCC_TRP_ALGO_ALLOC2,
+ LLCC_TRP_ALGO_ALLOC3,
+ LLCC_TRP_WRS_EN,
+ LLCC_TRP_WRS_CACHEABLE_EN,
+};
+
+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 kaanapali_data[] = {
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 5120,
+ .priority = 1,
+ .bonus_ways = 0xffffffff,
+ .activate_on_init = true,
+ .write_scid_en = true,
+ .stale_en = true,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_VIDSC0,
+ .slice_id = 2,
+ .max_cap = 512,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_AUDIO,
+ .slice_id = 35,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_MDMHPGRW,
+ .slice_id = 25,
+ .max_cap = 1024,
+ .priority = 5,
+ .bonus_ways = 0xffffffff,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_CMPT,
+ .slice_id = 34,
+ .max_cap = 4096,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 9,
+ .max_cap = 5632,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .write_scid_cacheable_en = true,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_MMUHWT,
+ .slice_id = 18,
+ .max_cap = 768,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .activate_on_init = true,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_DISP,
+ .slice_id = 16,
+ .max_cap = 7168,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .cache_mode = 2,
+ .stale_en = true,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_MDMHPFX,
+ .slice_id = 24,
+ .max_cap = 1024,
+ .priority = 5,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_MDMPNG,
+ .slice_id = 27,
+ .max_cap = 256,
+ .priority = 5,
+ .bonus_ways = 0xfffff,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_CVP,
+ .slice_id = 8,
+ .max_cap = 800,
+ .priority = 5,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .mru_uncap_en = true,
+ .ovcap_en = true,
+ .vict_prio = true,
+ .parent_slice_id = 33,
+ }, {
+ .usecase_id = LLCC_MODPE,
+ .slice_id = 29,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xf0000000,
+ .mru_uncap_en = true,
+ .alloc_oneway_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_WRCACHE,
+ .slice_id = 31,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .activate_on_init = true,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_CVPFW,
+ .slice_id = 19,
+ .max_cap = 512,
+ .priority = 5,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ .parent_slice_id = 33,
+ }, {
+ .usecase_id = LLCC_CPUMTE,
+ .slice_id = 7,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_CMPTHCP,
+ .slice_id = 15,
+ .max_cap = 256,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_LCPDARE,
+ .slice_id = 30,
+ .max_cap = 128,
+ .priority = 5,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .activate_on_init = true,
+ .mru_uncap_en = 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 = 0xffffffff,
+ .cache_mode = 2,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_ISLAND1,
+ .slice_id = 12,
+ .max_cap = 7936,
+ .priority = 7,
+ .fixed_size = true,
+ .bonus_ways = 0x7fffffff,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_DISP_WB,
+ .slice_id = 23,
+ .max_cap = 512,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_VIDVSP,
+ .slice_id = 4,
+ .max_cap = 256,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_VIDDEC,
+ .slice_id = 5,
+ .max_cap = 512,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .cache_mode = 2,
+ .mru_uncap_en = true,
+ .ovcap_en = true,
+ .vict_prio = true,
+ .parent_slice_id = 33,
+ }, {
+ .usecase_id = LLCC_CAMOFE,
+ .slice_id = 33,
+ .max_cap = 6144,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .stale_en = true,
+ .mru_uncap_en = true,
+ .ovcap_en = true,
+ .vict_prio = true,
+ .parent_slice_id = 33,
+ }, {
+ .usecase_id = LLCC_CAMRTIP,
+ .slice_id = 13,
+ .max_cap = 6144,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .stale_en = true,
+ .mru_uncap_en = true,
+ .ovcap_en = true,
+ .vict_prio = true,
+ .parent_slice_id = 33,
+ }, {
+ .usecase_id = LLCC_CAMRTRF,
+ .slice_id = 10,
+ .max_cap = 3584,
+ .priority = 3,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .stale_en = true,
+ .mru_uncap_en = true,
+ .ovcap_en = true,
+ .vict_prio = true,
+ .parent_slice_id = 33,
+ }, {
+ .usecase_id = LLCC_CAMSRTRF,
+ .slice_id = 21,
+ .max_cap = 6144,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .stale_en = true,
+ .mru_uncap_en = true,
+ .ovcap_en = true,
+ .vict_prio = true,
+ .parent_slice_id = 33,
+ }, {
+ .usecase_id = LLCC_VIDEO_APV,
+ .slice_id = 6,
+ .max_cap = 768,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_COMPUTE1,
+ .slice_id = 22,
+ .max_cap = 4096,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_CPUSS_OPP,
+ .slice_id = 32,
+ .max_cap = 0,
+ .priority = 0,
+ .fixed_size = true,
+ .bonus_ways = 0,
+ .activate_on_init = true,
+ .write_scid_en = true,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_CPUSSMPAM,
+ .slice_id = 17,
+ .max_cap = 2048,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .activate_on_init = true,
+ .write_scid_en = true,
+ .stale_en = true,
+ .mru_uncap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_CAM_IPE_STROV,
+ .slice_id = 14,
+ .max_cap = 400,
+ .priority = 5,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .mru_uncap_en = true,
+ .ovcap_en = true,
+ .vict_prio = true,
+ .parent_slice_id = 33,
+ }, {
+ .usecase_id = LLCC_CAM_OFE_STROV,
+ .slice_id = 20,
+ .max_cap = 400,
+ .priority = 5,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .mru_uncap_en = true,
+ .ovcap_en = true,
+ .vict_prio = true,
+ .parent_slice_id = 33,
+ }, {
+ .usecase_id = LLCC_CPUSS_HEU,
+ .slice_id = 28,
+ .max_cap = 0,
+ .priority = 0,
+ .fixed_size = true,
+ .bonus_ways = 0,
+ .mru_uncap_en = true,
+ .ovcap_en = true,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_MDM_PNG_FIXED,
+ .slice_id = 26,
+ .max_cap = 256,
+ .priority = 5,
+ .fixed_size = true,
+ .bonus_ways = 0xff000000,
+ .activate_on_init = true,
+ .write_scid_en = true,
+ .mru_uncap_en = true,
+ .vict_prio = 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_DRE, 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, 32, 512, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
- { LLCC_CPUSS1, 33, 2048, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
- { LLCC_CPUHWT, 36, 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[] = {
+ {
+ .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[] = {
+ {
+ .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 sm8750_data[] = {
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 5120,
+ .priority = 1,
+ .bonus_ways = 0xffffffff,
+ .activate_on_init = true,
+ .write_scid_en = true,
+ }, {
+ .usecase_id = LLCC_MDMHPFX,
+ .slice_id = 24,
+ .max_cap = 1024,
+ .priority = 5,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_VIDSC0,
+ .slice_id = 2,
+ .max_cap = 512,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_AUDIO,
+ .slice_id = 35,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_MDMHPGRW,
+ .slice_id = 25,
+ .max_cap = 1024,
+ .priority = 5,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_MODHW,
+ .slice_id = 26,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_CMPT,
+ .slice_id = 34,
+ .max_cap = 4096,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 9,
+ .max_cap = 5632,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .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 = 0xffffffff,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_DISP,
+ .slice_id = 16,
+ .max_cap = 7168,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .cache_mode = 2,
+ .stale_en = true,
+ }, {
+ .usecase_id = LLCC_VIDFW,
+ .slice_id = 17,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_CAMFW,
+ .slice_id = 20,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_MDMPNG,
+ .slice_id = 27,
+ .max_cap = 256,
+ .priority = 5,
+ .fixed_size = true,
+ .bonus_ways = 0xf0000000,
+ }, {
+ .usecase_id = LLCC_AUDHW,
+ .slice_id = 22,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_CVP,
+ .slice_id = 8,
+ .max_cap = 800,
+ .priority = 5,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_MODPE,
+ .slice_id = 29,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xf0000000,
+ .alloc_oneway_en = true,
+ }, {
+ .usecase_id = LLCC_WRCACHE,
+ .slice_id = 31,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_CVPFW,
+ .slice_id = 19,
+ .max_cap = 64,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_CMPTHCP,
+ .slice_id = 15,
+ .max_cap = 256,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_LCPDARE,
+ .slice_id = 30,
+ .max_cap = 128,
+ .priority = 5,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .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 = 0xffffffff,
+ .cache_mode = 2,
+ }, {
+ .usecase_id = LLCC_ISLAND1,
+ .slice_id = 12,
+ .max_cap = 7936,
+ .priority = 7,
+ .fixed_size = true,
+ .bonus_ways = 0x7fffffff,
+ }, {
+ .usecase_id = LLCC_DISP_WB,
+ .slice_id = 23,
+ .max_cap = 512,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_VIDVSP,
+ .slice_id = 4,
+ .max_cap = 256,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_VIDDEC,
+ .slice_id = 5,
+ .max_cap = 6144,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .cache_mode = 2,
+ .ovcap_prio = true,
+ .parent_slice_id = 33,
+ }, {
+ .usecase_id = LLCC_CAMOFE,
+ .slice_id = 33,
+ .max_cap = 6144,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .stale_en = true,
+ .ovcap_prio = true,
+ .parent_slice_id = 33,
+ }, {
+ .usecase_id = LLCC_CAMRTIP,
+ .slice_id = 13,
+ .max_cap = 1024,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .stale_en = true,
+ .ovcap_prio = true,
+ .parent_slice_id = 33,
+ }, {
+ .usecase_id = LLCC_CAMSRTIP,
+ .slice_id = 14,
+ .max_cap = 6144,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .stale_en = true,
+ .ovcap_prio = true,
+ .parent_slice_id = 33,
+ }, {
+ .usecase_id = LLCC_CAMRTRF,
+ .slice_id = 7,
+ .max_cap = 3584,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .stale_en = true,
+ .ovcap_prio = true,
+ .parent_slice_id = 33,
+ }, {
+ .usecase_id = LLCC_CAMSRTRF,
+ .slice_id = 21,
+ .max_cap = 6144,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .stale_en = true,
+ .ovcap_prio = true,
+ .parent_slice_id = 33,
+ }, {
+ .usecase_id = LLCC_CPUSSMPAM,
+ .slice_id = 6,
+ .max_cap = 2048,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .activate_on_init = true,
+ .write_scid_en = true,
+ },
+};
+
+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[] = {
+ {
+ .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[] = {
+ {
+ .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[] = {
+ {
+ .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[] = {
+ {
+ .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 = {
@@ -404,6 +3803,33 @@ static const struct llcc_edac_reg_offset llcc_v2_1_edac_reg_offset = {
.drp_ecc_db_err_syn0 = 0x52120,
};
+static const struct llcc_edac_reg_offset llcc_v6_edac_reg_offset = {
+ .trp_ecc_error_status0 = 0x47448,
+ .trp_ecc_error_status1 = 0x47450,
+ .trp_ecc_sb_err_syn0 = 0x47490,
+ .trp_ecc_db_err_syn0 = 0x474d0,
+ .trp_ecc_error_cntr_clear = 0x47444,
+ .trp_interrupt_0_status = 0x47600,
+ .trp_interrupt_0_clear = 0x47604,
+ .trp_interrupt_0_enable = 0x47608,
+
+ /* LLCC Common registers */
+ .cmn_status0 = 0x6400c,
+ .cmn_interrupt_0_enable = 0x6401c,
+ .cmn_interrupt_2_enable = 0x6403c,
+
+ /* LLCC DRP registers */
+ .drp_ecc_error_cfg = 0x80000,
+ .drp_ecc_error_cntr_clear = 0x80004,
+ .drp_interrupt_status = 0x80020,
+ .drp_interrupt_clear = 0x80028,
+ .drp_interrupt_enable = 0x8002c,
+ .drp_ecc_error_status0 = 0x820f4,
+ .drp_ecc_error_status1 = 0x820f8,
+ .drp_ecc_sb_err_syn0 = 0x820fc,
+ .drp_ecc_db_err_syn0 = 0x82120,
+};
+
/* LLCC register offset starting from v1.0.0 */
static const u32 llcc_v1_reg_offset[] = {
[LLCC_COMMON_HW_INFO] = 0x00030000,
@@ -416,92 +3842,375 @@ static const u32 llcc_v2_1_reg_offset[] = {
[LLCC_COMMON_STATUS0] = 0x0003400c,
};
-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,
+/* LLCC register offset starting from v6.0.0 */
+static const u32 llcc_v6_reg_offset[] = {
+ [LLCC_COMMON_HW_INFO] = 0x00064000,
+ [LLCC_COMMON_STATUS0] = 0x0006400c,
+ [LLCC_TRP_ATTR0_CFG] = 0x00041000,
+ [LLCC_TRP_ATTR1_CFG] = 0x00041008,
+ [LLCC_TRP_ATTR2_CFG] = 0x00041010,
+ [LLCC_TRP_ATTR3_CFG] = 0x00041014,
+ [LLCC_TRP_SID_DIS_CAP_ALLOC] = 0x00042000,
+ [LLCC_TRP_ALGO_STALE_EN] = 0x00042008,
+ [LLCC_TRP_ALGO_STALE_CAP_EN] = 0x00042010,
+ [LLCC_TRP_ALGO_MRU0] = 0x00042018,
+ [LLCC_TRP_ALGO_MRU1] = 0x00042020,
+ [LLCC_TRP_ALGO_ALLOC0] = 0x00042028,
+ [LLCC_TRP_ALGO_ALLOC1] = 0x00042030,
+ [LLCC_TRP_ALGO_ALLOC2] = 0x00042038,
+ [LLCC_TRP_ALGO_ALLOC3] = 0x00042040,
+ [LLCC_TRP_WRS_EN] = 0x00042080,
+ [LLCC_TRP_WRS_CACHEABLE_EN] = 0x00042088,
+};
+
+static const struct qcom_llcc_config kaanapali_cfg[] = {
+ {
+ .sct_data = kaanapali_data,
+ .size = ARRAY_SIZE(kaanapali_data),
+ .reg_offset = llcc_v6_reg_offset,
+ .edac_reg_offset = &llcc_v6_edac_reg_offset,
+ },
+};
+
+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),
+ .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),
+ .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),
+ .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),
+ .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),
+ .reg_offset = llcc_v1_reg_offset,
+ .edac_reg_offset = &llcc_v1_edac_reg_offset,
+ },
+};
+
+static const struct qcom_llcc_config sc7280_cfg[] = {
+ {
+ .sct_data = sc7280_data,
+ .size = ARRAY_SIZE(sc7280_data),
+ .reg_offset = llcc_v1_reg_offset,
+ .edac_reg_offset = &llcc_v1_edac_reg_offset,
+ },
+};
+
+static const struct qcom_llcc_config sc8180x_cfg[] = {
+ {
+ .sct_data = sc8180x_data,
+ .size = ARRAY_SIZE(sc8180x_data),
+ .reg_offset = llcc_v1_reg_offset,
+ .edac_reg_offset = &llcc_v1_edac_reg_offset,
+ },
+};
+
+static const struct qcom_llcc_config sc8280xp_cfg[] = {
+ {
+ .sct_data = sc8280xp_data,
+ .size = ARRAY_SIZE(sc8280xp_data),
+ .reg_offset = llcc_v1_reg_offset,
+ .edac_reg_offset = &llcc_v1_edac_reg_offset,
+ },
+};
+
+static const struct qcom_llcc_config sdm845_cfg[] = {
+ {
+ .sct_data = sdm845_data,
+ .size = ARRAY_SIZE(sdm845_data),
+ .skip_llcc_cfg = true,
+ .reg_offset = llcc_v1_reg_offset,
+ .edac_reg_offset = &llcc_v1_edac_reg_offset,
+ .no_edac = true,
+ },
+};
+
+static const struct qcom_llcc_config sm6350_cfg[] = {
+ {
+ .sct_data = sm6350_data,
+ .size = ARRAY_SIZE(sm6350_data),
+ .reg_offset = llcc_v1_reg_offset,
+ .edac_reg_offset = &llcc_v1_edac_reg_offset,
+ },
+};
+
+static const struct qcom_llcc_config sm7150_cfg[] = {
+ {
+ .sct_data = sm7150_data,
+ .size = ARRAY_SIZE(sm7150_data),
+ .reg_offset = llcc_v1_reg_offset,
+ .edac_reg_offset = &llcc_v1_edac_reg_offset,
+ },
+};
+
+static const struct qcom_llcc_config sm8150_cfg[] = {
+ {
+ .sct_data = sm8150_data,
+ .size = ARRAY_SIZE(sm8150_data),
+ .reg_offset = llcc_v1_reg_offset,
+ .edac_reg_offset = &llcc_v1_edac_reg_offset,
+ },
+};
+
+static const struct qcom_llcc_config sm8250_cfg[] = {
+ {
+ .sct_data = sm8250_data,
+ .size = ARRAY_SIZE(sm8250_data),
+ .reg_offset = llcc_v1_reg_offset,
+ .edac_reg_offset = &llcc_v1_edac_reg_offset,
+ },
+};
+
+static const struct qcom_llcc_config sm8350_cfg[] = {
+ {
+ .sct_data = sm8350_data,
+ .size = ARRAY_SIZE(sm8350_data),
+ .reg_offset = llcc_v1_reg_offset,
+ .edac_reg_offset = &llcc_v1_edac_reg_offset,
+ },
+};
+
+static const struct qcom_llcc_config sm8450_cfg[] = {
+ {
+ .sct_data = sm8450_data,
+ .size = ARRAY_SIZE(sm8450_data),
+ .reg_offset = llcc_v2_1_reg_offset,
+ .edac_reg_offset = &llcc_v2_1_edac_reg_offset,
+ },
+};
+
+static const struct qcom_llcc_config sm8550_cfg[] = {
+ {
+ .sct_data = sm8550_data,
+ .size = ARRAY_SIZE(sm8550_data),
+ .reg_offset = llcc_v2_1_reg_offset,
+ .edac_reg_offset = &llcc_v2_1_edac_reg_offset,
+ },
+};
+
+static const struct qcom_llcc_config sm8650_cfg[] = {
+ {
+ .sct_data = sm8650_data,
+ .size = ARRAY_SIZE(sm8650_data),
+ .reg_offset = llcc_v2_1_reg_offset,
+ .edac_reg_offset = &llcc_v2_1_edac_reg_offset,
+ },
+};
+
+static const struct qcom_llcc_config sm8750_cfg[] = {
+ {
+ .sct_data = sm8750_data,
+ .size = ARRAY_SIZE(sm8750_data),
+ .skip_llcc_cfg = false,
+ .reg_offset = llcc_v6_reg_offset,
+ .edac_reg_offset = &llcc_v6_edac_reg_offset,
+ },
+};
+
+static const struct qcom_llcc_config x1e80100_cfg[] = {
+ {
+ .sct_data = x1e80100_data,
+ .size = ARRAY_SIZE(x1e80100_data),
+ .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 kaanapali_cfgs = {
+ .llcc_config = kaanapali_cfg,
+ .num_config = ARRAY_SIZE(kaanapali_cfg),
+};
+
+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),
+};
+
+static const struct qcom_sct_config sc7280_cfgs = {
+ .llcc_config = sc7280_cfg,
+ .num_config = ARRAY_SIZE(sc7280_cfg),
+};
+
+static const struct qcom_sct_config sc8180x_cfgs = {
+ .llcc_config = sc8180x_cfg,
+ .num_config = ARRAY_SIZE(sc8180x_cfg),
+};
+
+static const struct qcom_sct_config sc8280xp_cfgs = {
+ .llcc_config = sc8280xp_cfg,
+ .num_config = ARRAY_SIZE(sc8280xp_cfg),
+};
+
+static const struct qcom_sct_config sdm845_cfgs = {
+ .llcc_config = sdm845_cfg,
+ .num_config = ARRAY_SIZE(sdm845_cfg),
};
-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,
+static const struct qcom_sct_config sm6350_cfgs = {
+ .llcc_config = sm6350_cfg,
+ .num_config = ARRAY_SIZE(sm6350_cfg),
};
-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,
+static const struct qcom_sct_config sm7150_cfgs = {
+ .llcc_config = sm7150_cfg,
+ .num_config = ARRAY_SIZE(sm7150_cfg),
};
-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,
+static const struct qcom_sct_config sm8150_cfgs = {
+ .llcc_config = sm8150_cfg,
+ .num_config = ARRAY_SIZE(sm8150_cfg),
};
-static const struct qcom_llcc_config sdm845_cfg = {
- .sct_data = sdm845_data,
- .size = ARRAY_SIZE(sdm845_data),
- .need_llcc_cfg = false,
- .reg_offset = llcc_v1_reg_offset,
- .edac_reg_offset = &llcc_v1_edac_reg_offset,
+static const struct qcom_sct_config sm8250_cfgs = {
+ .llcc_config = sm8250_cfg,
+ .num_config = ARRAY_SIZE(sm8250_cfg),
};
-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,
+static const struct qcom_sct_config sm8350_cfgs = {
+ .llcc_config = sm8350_cfg,
+ .num_config = ARRAY_SIZE(sm8350_cfg),
};
-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,
+static const struct qcom_sct_config sm8450_cfgs = {
+ .llcc_config = sm8450_cfg,
+ .num_config = ARRAY_SIZE(sm8450_cfg),
};
-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,
+static const struct qcom_sct_config sm8550_cfgs = {
+ .llcc_config = sm8550_cfg,
+ .num_config = ARRAY_SIZE(sm8550_cfg),
};
-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,
+static const struct qcom_sct_config sm8650_cfgs = {
+ .llcc_config = sm8650_cfg,
+ .num_config = ARRAY_SIZE(sm8650_cfg),
};
-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,
+static const struct qcom_sct_config sm8750_cfgs = {
+ .llcc_config = sm8750_cfg,
+ .num_config = ARRAY_SIZE(sm8750_cfg),
};
-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,
+static const struct qcom_sct_config x1e80100_cfgs = {
+ .llcc_config = x1e80100_cfg,
+ .num_config = ARRAY_SIZE(x1e80100_cfg),
};
static struct llcc_drv_data *drv_data = (void *) -EPROBE_DEFER;
@@ -544,7 +4253,7 @@ struct llcc_slice_desc *llcc_slice_getd(u32 uid)
EXPORT_SYMBOL_GPL(llcc_slice_getd);
/**
- * llcc_slice_putd - llcc slice descritpor
+ * llcc_slice_putd - llcc slice descriptor
* @desc: Pointer to llcc slice descriptor
*/
void llcc_slice_putd(struct llcc_slice_desc *desc)
@@ -557,6 +4266,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;
@@ -585,7 +4295,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)
@@ -595,6 +4306,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,
@@ -737,7 +4450,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);
@@ -766,19 +4482,20 @@ 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;
- ret = regmap_write(drv_data->bcast_regmap,
- LLCC_TRP_SCID_DIS_CAP_ALLOC, disable_cap_alloc);
+ ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_SCID_DIS_CAP_ALLOC,
+ BIT(config->slice_id), disable_cap_alloc);
if (ret)
return ret;
if (drv_data->version < LLCC_VERSION_4_1_0_0) {
retain_pc = config->retain_on_pc << config->slice_id;
- ret = regmap_write(drv_data->bcast_regmap,
- LLCC_TRP_PCB_ACT, retain_pc);
+ ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_PCB_ACT,
+ BIT(config->slice_id), retain_pc);
if (ret)
return ret;
}
@@ -871,6 +4588,139 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
return ret;
}
+static int _qcom_llcc_cfg_program_v6(const struct llcc_slice_config *config,
+ const struct qcom_llcc_config *cfg)
+{
+ u32 stale_en, stale_cap_en, mru_uncap_en, mru_rollover;
+ u32 alloc_oneway_en, ovcap_en, ovcap_prio, vict_prio;
+ u32 attr0_cfg, attr1_cfg, attr2_cfg, attr3_cfg;
+ u32 attr0_val, attr1_val, attr2_val, attr3_val;
+ u32 slice_offset, reg_offset;
+ struct llcc_slice_desc *desc;
+ u32 wren, wr_cache_en;
+ int ret;
+
+ attr0_cfg = LLCC_V6_TRP_ATTR0_CFGn(config->slice_id);
+ attr1_cfg = LLCC_V6_TRP_ATTR1_CFGn(config->slice_id);
+ attr2_cfg = LLCC_V6_TRP_ATTR2_CFGn(config->slice_id);
+ attr3_cfg = LLCC_V6_TRP_ATTR3_CFGn(config->slice_id);
+
+ attr0_val = config->res_ways;
+ attr1_val = config->bonus_ways;
+ attr2_val = config->cache_mode;
+ attr2_val |= FIELD_PREP(ATTR2_PROBE_TARGET_WAYS_MASK, config->probe_target_ways);
+ attr2_val |= FIELD_PREP(ATTR2_FIXED_SIZE_MASK, config->fixed_size);
+ attr2_val |= FIELD_PREP(ATTR2_PRIORITY_MASK, config->priority);
+
+ if (config->parent_slice_id && config->fixed_size) {
+ attr2_val |= FIELD_PREP(ATTR2_PARENT_SCID_MASK, config->parent_slice_id);
+ attr2_val |= ATTR2_IN_A_GROUP_MASK;
+ }
+
+ attr3_val = MAX_CAP_TO_BYTES(config->max_cap);
+ attr3_val /= drv_data->num_banks;
+ attr3_val >>= CACHE_LINE_SIZE_SHIFT;
+
+ ret = regmap_write(drv_data->bcast_regmap, attr0_cfg, attr0_val);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(drv_data->bcast_regmap, attr1_cfg, attr1_val);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(drv_data->bcast_regmap, attr2_cfg, attr2_val);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(drv_data->bcast_regmap, attr3_cfg, attr3_val);
+ if (ret)
+ return ret;
+
+ slice_offset = config->slice_id % 32;
+ reg_offset = (config->slice_id / 32) * 4;
+
+ wren = config->write_scid_en << slice_offset;
+ ret = regmap_update_bits(drv_data->bcast_regmap,
+ cfg->reg_offset[LLCC_TRP_WRS_EN] + reg_offset,
+ BIT(slice_offset), wren);
+ if (ret)
+ return ret;
+
+ wr_cache_en = config->write_scid_cacheable_en << slice_offset;
+ ret = regmap_update_bits(drv_data->bcast_regmap,
+ cfg->reg_offset[LLCC_TRP_WRS_CACHEABLE_EN] + reg_offset,
+ BIT(slice_offset), wr_cache_en);
+ if (ret)
+ return ret;
+
+ stale_en = config->stale_en << slice_offset;
+ ret = regmap_update_bits(drv_data->bcast_regmap,
+ cfg->reg_offset[LLCC_TRP_ALGO_STALE_EN] + reg_offset,
+ BIT(slice_offset), stale_en);
+ if (ret)
+ return ret;
+
+ stale_cap_en = config->stale_cap_en << slice_offset;
+ ret = regmap_update_bits(drv_data->bcast_regmap,
+ cfg->reg_offset[LLCC_TRP_ALGO_STALE_CAP_EN] + reg_offset,
+ BIT(slice_offset), stale_cap_en);
+ if (ret)
+ return ret;
+
+ mru_uncap_en = config->mru_uncap_en << slice_offset;
+ ret = regmap_update_bits(drv_data->bcast_regmap,
+ cfg->reg_offset[LLCC_TRP_ALGO_MRU0] + reg_offset,
+ BIT(slice_offset), mru_uncap_en);
+ if (ret)
+ return ret;
+
+ mru_rollover = config->mru_rollover << slice_offset;
+ ret = regmap_update_bits(drv_data->bcast_regmap,
+ cfg->reg_offset[LLCC_TRP_ALGO_MRU1] + reg_offset,
+ BIT(slice_offset), mru_rollover);
+ if (ret)
+ return ret;
+
+ alloc_oneway_en = config->alloc_oneway_en << slice_offset;
+ ret = regmap_update_bits(drv_data->bcast_regmap,
+ cfg->reg_offset[LLCC_TRP_ALGO_ALLOC0] + reg_offset,
+ BIT(slice_offset), alloc_oneway_en);
+ if (ret)
+ return ret;
+
+ ovcap_en = config->ovcap_en << slice_offset;
+ ret = regmap_update_bits(drv_data->bcast_regmap,
+ cfg->reg_offset[LLCC_TRP_ALGO_ALLOC1] + reg_offset,
+ BIT(slice_offset), ovcap_en);
+ if (ret)
+ return ret;
+
+ ovcap_prio = config->ovcap_prio << slice_offset;
+ ret = regmap_update_bits(drv_data->bcast_regmap,
+ cfg->reg_offset[LLCC_TRP_ALGO_ALLOC2] + reg_offset,
+ BIT(slice_offset), ovcap_prio);
+ if (ret)
+ return ret;
+
+ vict_prio = config->vict_prio << slice_offset;
+ ret = regmap_update_bits(drv_data->bcast_regmap,
+ cfg->reg_offset[LLCC_TRP_ALGO_ALLOC3] + reg_offset,
+ BIT(slice_offset), vict_prio);
+ if (ret)
+ return ret;
+
+ if (config->activate_on_init) {
+ desc = llcc_slice_getd(config->usecase_id);
+ if (PTR_ERR_OR_ZERO(desc))
+ return -EINVAL;
+
+ ret = llcc_slice_activate(desc);
+ }
+
+ return ret;
+}
+
static int qcom_llcc_cfg_program(struct platform_device *pdev,
const struct qcom_llcc_config *cfg)
{
@@ -882,34 +4732,58 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev,
sz = drv_data->cfg_size;
llcc_table = drv_data->cfg;
- for (i = 0; i < sz; i++) {
- ret = _qcom_llcc_cfg_program(&llcc_table[i], cfg);
- if (ret)
- return ret;
+ if (drv_data->version >= LLCC_VERSION_6_0_0_0) {
+ for (i = 0; i < sz; i++) {
+ ret = _qcom_llcc_cfg_program_v6(&llcc_table[i], cfg);
+ if (ret)
+ return ret;
+ }
+ } else {
+ for (i = 0; i < sz; i++) {
+ ret = _qcom_llcc_cfg_program(&llcc_table[i], cfg);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static int qcom_llcc_get_cfg_index(struct platform_device *pdev, u8 *cfg_index, int num_config)
+{
+ int ret;
+
+ ret = nvmem_cell_read_u8(&pdev->dev, "multi-chan-ddr", cfg_index);
+ if (ret == -ENOENT || ret == -EOPNOTSUPP) {
+ if (num_config > 1)
+ return -EINVAL;
+ *cfg_index = 0;
+ return 0;
}
+ if (!ret && *cfg_index >= num_config)
+ ret = -EINVAL;
+
return ret;
}
-static int qcom_llcc_remove(struct platform_device *pdev)
+static void qcom_llcc_remove(struct platform_device *pdev)
{
/* Set the global pointer to a error code to avoid referencing it */
drv_data = ERR_PTR(-ENODEV);
- return 0;
}
-static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev,
- const char *name)
+static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev, u8 index,
+ const char *name)
{
void __iomem *base;
struct regmap_config llcc_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
- .fast_io = true,
};
- base = devm_platform_ioremap_resource_byname(pdev, name);
+ base = devm_platform_ioremap_resource(pdev, index);
if (IS_ERR(base))
return ERR_CAST(base);
@@ -923,10 +4797,16 @@ static int qcom_llcc_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
int ret, i;
struct platform_device *llcc_edac;
+ const struct qcom_sct_config *cfgs;
const struct qcom_llcc_config *cfg;
const struct llcc_slice_config *llcc_cfg;
u32 sz;
+ u8 cfg_index;
u32 version;
+ struct regmap *regmap;
+
+ if (!IS_ERR(drv_data))
+ return -EBUSY;
drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL);
if (!drv_data) {
@@ -934,20 +4814,64 @@ static int qcom_llcc_probe(struct platform_device *pdev)
goto err;
}
- drv_data->regmap = qcom_llcc_init_mmio(pdev, "llcc_base");
- if (IS_ERR(drv_data->regmap)) {
- ret = PTR_ERR(drv_data->regmap);
+ /* Initialize the first LLCC bank regmap */
+ regmap = qcom_llcc_init_mmio(pdev, 0, "llcc0_base");
+ if (IS_ERR(regmap)) {
+ ret = PTR_ERR(regmap);
goto err;
}
- drv_data->bcast_regmap =
- qcom_llcc_init_mmio(pdev, "llcc_broadcast_base");
- if (IS_ERR(drv_data->bcast_regmap)) {
- ret = PTR_ERR(drv_data->bcast_regmap);
+ cfgs = of_device_get_match_data(&pdev->dev);
+ if (!cfgs) {
+ ret = -EINVAL;
+ goto err;
+ }
+ ret = qcom_llcc_get_cfg_index(pdev, &cfg_index, cfgs->num_config);
+ if (ret)
+ goto err;
+ cfg = &cfgs->llcc_config[cfg_index];
+
+ 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;
+ }
+
+ drv_data->num_banks = num_banks;
+
+ drv_data->regmaps = devm_kcalloc(dev, num_banks, sizeof(*drv_data->regmaps), GFP_KERNEL);
+ if (!drv_data->regmaps) {
+ ret = -ENOMEM;
goto err;
}
- cfg = of_device_get_match_data(&pdev->dev);
+ drv_data->regmaps[0] = regmap;
+
+ /* Initialize rest of LLCC bank regmaps */
+ for (i = 1; i < num_banks; 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]);
+ goto err;
+ }
+ }
+
+ drv_data->bcast_regmap = qcom_llcc_init_mmio(pdev, i, "llcc_broadcast_base");
+ if (IS_ERR(drv_data->bcast_regmap)) {
+ 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 */
ret = regmap_read(drv_data->bcast_regmap, cfg->reg_offset[LLCC_COMMON_HW_INFO],
@@ -957,14 +4881,17 @@ static int qcom_llcc_probe(struct platform_device *pdev)
drv_data->version = version;
- ret = regmap_read(drv_data->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;
- drv_data->num_banks = num_banks;
+ /* 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;
@@ -973,16 +4900,6 @@ static int qcom_llcc_probe(struct platform_device *pdev)
if (llcc_cfg[i].slice_id > drv_data->max_slices)
drv_data->max_slices = llcc_cfg[i].slice_id;
- drv_data->offsets = devm_kcalloc(dev, num_banks, sizeof(u32),
- GFP_KERNEL);
- if (!drv_data->offsets) {
- ret = -ENOMEM;
- goto err;
- }
-
- for (i = 0; i < num_banks; i++)
- drv_data->offsets[i] = i * BANK_OFFSET_STRIDE;
-
drv_data->bitmap = devm_bitmap_zalloc(dev, drv_data->max_slices,
GFP_KERNEL);
if (!drv_data->bitmap) {
@@ -993,6 +4910,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);
@@ -1001,7 +4919,14 @@ static int qcom_llcc_probe(struct platform_device *pdev)
goto err;
drv_data->ecc_irq = platform_get_irq_optional(pdev, 0);
- if (drv_data->ecc_irq >= 0) {
+
+ /*
+ * On some platforms, the access to EDAC registers will be locked by
+ * the bootloader. So probing the EDAC driver will result in a crash.
+ * Hence, disable the creation of EDAC platform device for the
+ * problematic platforms.
+ */
+ if (!cfg->no_edac) {
llcc_edac = platform_device_register_data(&pdev->dev,
"qcom_llcc_edac", -1, drv_data,
sizeof(*drv_data));
@@ -1016,17 +4941,29 @@ err:
}
static const struct of_device_id qcom_llcc_of_match[] = {
- { .compatible = "qcom,sc7180-llcc", .data = &sc7180_cfg },
- { .compatible = "qcom,sc7280-llcc", .data = &sc7280_cfg },
- { .compatible = "qcom,sc8180x-llcc", .data = &sc8180x_cfg },
- { .compatible = "qcom,sc8280xp-llcc", .data = &sc8280xp_cfg },
- { .compatible = "qcom,sdm845-llcc", .data = &sdm845_cfg },
- { .compatible = "qcom,sm6350-llcc", .data = &sm6350_cfg },
- { .compatible = "qcom,sm8150-llcc", .data = &sm8150_cfg },
- { .compatible = "qcom,sm8250-llcc", .data = &sm8250_cfg },
- { .compatible = "qcom,sm8350-llcc", .data = &sm8350_cfg },
- { .compatible = "qcom,sm8450-llcc", .data = &sm8450_cfg },
- { .compatible = "qcom,sm8550-llcc", .data = &sm8550_cfg },
+ { .compatible = "qcom,ipq5424-llcc", .data = &ipq5424_cfgs},
+ { .compatible = "qcom,kaanapali-llcc", .data = &kaanapali_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 },
+ { .compatible = "qcom,sc8280xp-llcc", .data = &sc8280xp_cfgs },
+ { .compatible = "qcom,sdm845-llcc", .data = &sdm845_cfgs },
+ { .compatible = "qcom,sm6350-llcc", .data = &sm6350_cfgs },
+ { .compatible = "qcom,sm7150-llcc", .data = &sm7150_cfgs },
+ { .compatible = "qcom,sm8150-llcc", .data = &sm8150_cfgs },
+ { .compatible = "qcom,sm8250-llcc", .data = &sm8250_cfgs },
+ { .compatible = "qcom,sm8350-llcc", .data = &sm8350_cfgs },
+ { .compatible = "qcom,sm8450-llcc", .data = &sm8450_cfgs },
+ { .compatible = "qcom,sm8550-llcc", .data = &sm8550_cfgs },
+ { .compatible = "qcom,sm8650-llcc", .data = &sm8650_cfgs },
+ { .compatible = "qcom,sm8750-llcc", .data = &sm8750_cfgs },
+ { .compatible = "qcom,x1e80100-llcc", .data = &x1e80100_cfgs },
{ }
};
MODULE_DEVICE_TABLE(of, qcom_llcc_of_match);
diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c
index 3f11554df2f3..c239107cb930 100644
--- a/drivers/soc/qcom/mdt_loader.c
+++ b/drivers/soc/qcom/mdt_loader.c
@@ -7,17 +7,51 @@
* 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>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/soc/qcom/mdt_loader.h>
-static bool mdt_phdr_valid(const struct elf32_phdr *phdr)
+static bool mdt_header_valid(const struct firmware *fw)
+{
+ const struct elf32_hdr *ehdr;
+ size_t phend;
+ size_t shend;
+
+ if (fw->size < sizeof(*ehdr))
+ return false;
+
+ ehdr = (struct elf32_hdr *)fw->data;
+
+ if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG))
+ return false;
+
+ if (ehdr->e_phentsize != sizeof(struct elf32_phdr))
+ return false;
+
+ phend = size_add(size_mul(sizeof(struct elf32_phdr), ehdr->e_phnum), ehdr->e_phoff);
+ if (phend > fw->size)
+ return false;
+
+ if (ehdr->e_shentsize || ehdr->e_shnum) {
+ if (ehdr->e_shentsize != sizeof(struct elf32_shdr))
+ return false;
+
+ shend = size_add(size_mul(sizeof(struct elf32_shdr), ehdr->e_shnum), ehdr->e_shoff);
+ if (shend > fw->size)
+ return false;
+ }
+
+ return true;
+}
+
+static bool mdt_phdr_loadable(const struct elf32_phdr *phdr)
{
if (phdr->p_type != PT_LOAD)
return false;
@@ -37,13 +71,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 +85,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 +96,6 @@ static ssize_t mdt_load_split_segment(void *ptr, const struct elf32_phdr *phdrs,
}
release_firmware(seg_fw);
- kfree(seg_name);
return ret;
}
@@ -84,13 +115,16 @@ ssize_t qcom_mdt_get_size(const struct firmware *fw)
phys_addr_t max_addr = 0;
int i;
+ if (!mdt_header_valid(fw))
+ return -EINVAL;
+
ehdr = (struct elf32_hdr *)fw->data;
- phdrs = (struct elf32_phdr *)(ehdr + 1);
+ phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff);
for (i = 0; i < ehdr->e_phnum; i++) {
phdr = &phdrs[i];
- if (!mdt_phdr_valid(phdr))
+ if (!mdt_phdr_loadable(phdr))
continue;
if (phdr->p_paddr < min_addr)
@@ -136,8 +170,11 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len,
ssize_t ret;
void *data;
+ if (!mdt_header_valid(fw))
+ return ERR_PTR(-EINVAL);
+
ehdr = (struct elf32_hdr *)fw->data;
- phdrs = (struct elf32_phdr *)(ehdr + 1);
+ phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff);
if (ehdr->e_phnum < 2)
return ERR_PTR(-EINVAL);
@@ -210,20 +247,27 @@ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
const struct elf32_hdr *ehdr;
phys_addr_t min_addr = PHYS_ADDR_MAX;
phys_addr_t max_addr = 0;
+ bool relocate = false;
size_t metadata_len;
void *metadata;
int ret;
int i;
+ if (!mdt_header_valid(fw))
+ return -EINVAL;
+
ehdr = (struct elf32_hdr *)fw->data;
- phdrs = (struct elf32_phdr *)(ehdr + 1);
+ phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff);
for (i = 0; i < ehdr->e_phnum; i++) {
phdr = &phdrs[i];
- if (!mdt_phdr_valid(phdr))
+ if (!mdt_phdr_loadable(phdr))
continue;
+ if (phdr->p_flags & QCOM_MDT_RELOCATABLE)
+ relocate = true;
+
if (phdr->p_paddr < min_addr)
min_addr = phdr->p_paddr;
@@ -246,11 +290,13 @@ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
goto out;
}
- ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr);
- if (ret) {
- /* Unable to set up relocation */
- dev_err(dev, "error %d setting up firmware %s\n", ret, fw_name);
- goto out;
+ if (relocate) {
+ ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr);
+ if (ret) {
+ /* Unable to set up relocation */
+ dev_err(dev, "error %d setting up firmware %s\n", ret, fw_name);
+ goto out;
+ }
}
out:
@@ -258,10 +304,50 @@ out:
}
EXPORT_SYMBOL_GPL(qcom_mdt_pas_init);
-static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
- const char *fw_name, int pas_id, void *mem_region,
- phys_addr_t mem_phys, size_t mem_size,
- phys_addr_t *reloc_base, bool pas_init)
+static bool qcom_mdt_bins_are_split(const struct firmware *fw)
+{
+ const struct elf32_phdr *phdrs;
+ const struct elf32_hdr *ehdr;
+ uint64_t seg_start, seg_end;
+ int i;
+
+ ehdr = (struct elf32_hdr *)fw->data;
+ phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff);
+
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ /*
+ * The size of the MDT file is not padded to include any
+ * zero-sized segments at the end. Ignore these, as they should
+ * not affect the decision about image being split or not.
+ */
+ if (!phdrs[i].p_filesz)
+ continue;
+
+ seg_start = phdrs[i].p_offset;
+ seg_end = phdrs[i].p_offset + phdrs[i].p_filesz;
+ if (seg_start > fw->size || seg_end > fw->size)
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * qcom_mdt_load_no_init() - load the firmware which header is loaded as fw
+ * @dev: device handle to associate resources with
+ * @fw: firmware object for the mdt file
+ * @fw_name: name of the firmware, for construction of segment file names
+ * @mem_region: allocated memory region to load firmware into
+ * @mem_phys: physical address of allocated memory region
+ * @mem_size: size of the allocated memory region
+ * @reloc_base: adjusted physical address after relocation
+ *
+ * Returns 0 on success, negative errno otherwise.
+ */
+int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw,
+ const char *fw_name, void *mem_region,
+ phys_addr_t mem_phys, size_t mem_size,
+ phys_addr_t *reloc_base)
{
const struct elf32_phdr *phdrs;
const struct elf32_phdr *phdr;
@@ -270,6 +356,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
phys_addr_t min_addr = PHYS_ADDR_MAX;
ssize_t offset;
bool relocate = false;
+ bool is_split;
void *ptr;
int ret = 0;
int i;
@@ -277,13 +364,17 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
if (!fw || !mem_region || !mem_phys || !mem_size)
return -EINVAL;
+ if (!mdt_header_valid(fw))
+ return -EINVAL;
+
+ is_split = qcom_mdt_bins_are_split(fw);
ehdr = (struct elf32_hdr *)fw->data;
- phdrs = (struct elf32_phdr *)(ehdr + 1);
+ phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff);
for (i = 0; i < ehdr->e_phnum; i++) {
phdr = &phdrs[i];
- if (!mdt_phdr_valid(phdr))
+ if (!mdt_phdr_loadable(phdr))
continue;
if (phdr->p_flags & QCOM_MDT_RELOCATABLE)
@@ -310,7 +401,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
for (i = 0; i < ehdr->e_phnum; i++) {
phdr = &phdrs[i];
- if (!mdt_phdr_valid(phdr))
+ if (!mdt_phdr_loadable(phdr))
continue;
offset = phdr->p_paddr - mem_reloc;
@@ -330,8 +421,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
ptr = mem_region + offset;
- if (phdr->p_filesz && phdr->p_offset < fw->size &&
- phdr->p_offset + phdr->p_filesz <= fw->size) {
+ if (phdr->p_filesz && !is_split) {
/* Firmware is large enough to be non-split */
if (phdr->p_offset + phdr->p_filesz > fw->size) {
dev_err(dev, "file %s segment %d would be truncated\n",
@@ -357,12 +447,13 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
return ret;
}
+EXPORT_SYMBOL_GPL(qcom_mdt_load_no_init);
/**
* qcom_mdt_load() - load the firmware which header is loaded as fw
* @dev: device handle to associate resources with
* @fw: firmware object for the mdt file
- * @firmware: name of the firmware, for construction of segment file names
+ * @fw_name: name of the firmware, for construction of segment file names
* @pas_id: PAS identifier
* @mem_region: allocated memory region to load firmware into
* @mem_phys: physical address of allocated memory region
@@ -372,43 +463,20 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
* Returns 0 on success, negative errno otherwise.
*/
int qcom_mdt_load(struct device *dev, const struct firmware *fw,
- const char *firmware, int pas_id, void *mem_region,
+ const char *fw_name, int pas_id, void *mem_region,
phys_addr_t mem_phys, size_t mem_size,
phys_addr_t *reloc_base)
{
int ret;
- ret = qcom_mdt_pas_init(dev, fw, firmware, pas_id, mem_phys, NULL);
+ ret = qcom_mdt_pas_init(dev, fw, fw_name, pas_id, mem_phys, NULL);
if (ret)
return ret;
- return __qcom_mdt_load(dev, fw, firmware, pas_id, mem_region, mem_phys,
- mem_size, reloc_base, true);
+ return qcom_mdt_load_no_init(dev, fw, fw_name, mem_region, mem_phys,
+ mem_size, reloc_base);
}
EXPORT_SYMBOL_GPL(qcom_mdt_load);
-/**
- * qcom_mdt_load_no_init() - load the firmware which header is loaded as fw
- * @dev: device handle to associate resources with
- * @fw: firmware object for the mdt file
- * @firmware: name of the firmware, for construction of segment file names
- * @pas_id: PAS identifier
- * @mem_region: allocated memory region to load firmware into
- * @mem_phys: physical address of allocated memory region
- * @mem_size: size of the allocated memory region
- * @reloc_base: adjusted physical address after relocation
- *
- * Returns 0 on success, negative errno otherwise.
- */
-int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw,
- const char *firmware, int pas_id,
- void *mem_region, phys_addr_t mem_phys,
- size_t mem_size, phys_addr_t *reloc_base)
-{
- return __qcom_mdt_load(dev, fw, firmware, pas_id, mem_region, mem_phys,
- mem_size, reloc_base, false);
-}
-EXPORT_SYMBOL_GPL(qcom_mdt_load_no_init);
-
MODULE_DESCRIPTION("Firmware parser for Qualcomm MDT format");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c
index c92d26b73e6f..71130a2f62e9 100644
--- a/drivers/soc/qcom/ocmem.c
+++ b/drivers/soc/qcom/ocmem.c
@@ -10,13 +10,15 @@
*/
#include <linux/bitfield.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
#include <linux/platform_device.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/types.h>
@@ -54,6 +56,8 @@ struct ocmem {
const struct ocmem_config *config;
struct resource *memory;
void __iomem *mmio;
+ struct clk *core_clk;
+ struct clk *iface_clk;
unsigned int num_ports;
unsigned int num_macros;
bool interleaved;
@@ -76,8 +80,12 @@ struct ocmem {
#define OCMEM_REG_GFX_MPU_START 0x00001004
#define OCMEM_REG_GFX_MPU_END 0x00001008
-#define OCMEM_HW_PROFILE_NUM_PORTS(val) FIELD_PREP(0x0000000f, (val))
-#define OCMEM_HW_PROFILE_NUM_MACROS(val) FIELD_PREP(0x00003f00, (val))
+#define OCMEM_HW_VERSION_MAJOR(val) FIELD_GET(GENMASK(31, 28), val)
+#define OCMEM_HW_VERSION_MINOR(val) FIELD_GET(GENMASK(27, 16), val)
+#define OCMEM_HW_VERSION_STEP(val) FIELD_GET(GENMASK(15, 0), val)
+
+#define OCMEM_HW_PROFILE_NUM_PORTS(val) FIELD_GET(0x0000000f, (val))
+#define OCMEM_HW_PROFILE_NUM_MACROS(val) FIELD_GET(0x00003f00, (val))
#define OCMEM_HW_PROFILE_LAST_REGN_HALFSIZE 0x00010000
#define OCMEM_HW_PROFILE_INTERLEAVING 0x00020000
@@ -91,16 +99,6 @@ struct ocmem {
#define OCMEM_PSGSC_CTL_MACRO2_MODE(val) FIELD_PREP(0x00000700, (val))
#define OCMEM_PSGSC_CTL_MACRO3_MODE(val) FIELD_PREP(0x00007000, (val))
-#define OCMEM_CLK_CORE_IDX 0
-static struct clk_bulk_data ocmem_clks[] = {
- {
- .id = "core",
- },
- {
- .id = "iface",
- },
-};
-
static inline void ocmem_write(struct ocmem *ocmem, u32 reg, u32 data)
{
writel(data, ocmem->mmio + reg);
@@ -188,38 +186,34 @@ 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);
+ put_device(&pdev->dev);
if (!ocmem) {
dev_err(dev, "Cannot get ocmem\n");
- put_device(&pdev->dev);
return ERR_PTR(-ENODEV);
}
return ocmem;
}
-EXPORT_SYMBOL(of_get_ocmem);
+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... */
@@ -232,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;
@@ -250,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);
@@ -261,16 +255,14 @@ 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);
return ERR_PTR(ret);
}
-EXPORT_SYMBOL(ocmem_allocate);
+EXPORT_SYMBOL_GPL(ocmem_allocate);
void ocmem_free(struct ocmem *ocmem, enum ocmem_client client,
struct ocmem_buf *buf)
@@ -297,7 +289,7 @@ void ocmem_free(struct ocmem *ocmem, enum ocmem_client client,
clear_bit_unlock(BIT(client), &ocmem->active_allocations);
}
-EXPORT_SYMBOL(ocmem_free);
+EXPORT_SYMBOL_GPL(ocmem_free);
static int ocmem_dev_probe(struct platform_device *pdev)
{
@@ -316,19 +308,20 @@ static int ocmem_dev_probe(struct platform_device *pdev)
ocmem->dev = dev;
ocmem->config = device_get_match_data(dev);
- ret = devm_clk_bulk_get(dev, ARRAY_SIZE(ocmem_clks), ocmem_clks);
- if (ret) {
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "Unable to get clocks\n");
+ ocmem->core_clk = devm_clk_get(dev, "core");
+ if (IS_ERR(ocmem->core_clk))
+ return dev_err_probe(dev, PTR_ERR(ocmem->core_clk),
+ "Unable to get core clock\n");
- return ret;
- }
+ ocmem->iface_clk = devm_clk_get_optional(dev, "iface");
+ if (IS_ERR(ocmem->iface_clk))
+ return dev_err_probe(dev, PTR_ERR(ocmem->iface_clk),
+ "Unable to get iface clock\n");
ocmem->mmio = devm_platform_ioremap_resource_byname(pdev, "ctrl");
- if (IS_ERR(ocmem->mmio)) {
- dev_err(&pdev->dev, "Failed to ioremap ocmem_ctrl resource\n");
- return PTR_ERR(ocmem->mmio);
- }
+ if (IS_ERR(ocmem->mmio))
+ return dev_err_probe(&pdev->dev, PTR_ERR(ocmem->mmio),
+ "Failed to ioremap ocmem_ctrl resource\n");
ocmem->memory = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"mem");
@@ -338,23 +331,33 @@ static int ocmem_dev_probe(struct platform_device *pdev)
}
/* The core clock is synchronous with graphics */
- WARN_ON(clk_set_rate(ocmem_clks[OCMEM_CLK_CORE_IDX].clk, 1000) < 0);
+ WARN_ON(clk_set_rate(ocmem->core_clk, 1000) < 0);
+
+ ret = clk_prepare_enable(ocmem->core_clk);
+ if (ret)
+ return dev_err_probe(ocmem->dev, ret, "Failed to enable core clock\n");
- ret = clk_bulk_prepare_enable(ARRAY_SIZE(ocmem_clks), ocmem_clks);
+ ret = clk_prepare_enable(ocmem->iface_clk);
if (ret) {
- dev_info(ocmem->dev, "Failed to enable clocks\n");
- return ret;
+ clk_disable_unprepare(ocmem->core_clk);
+ return dev_err_probe(ocmem->dev, ret, "Failed to enable iface clock\n");
}
if (qcom_scm_restore_sec_cfg_available()) {
dev_dbg(dev, "configuring scm\n");
ret = qcom_scm_restore_sec_cfg(QCOM_SCM_OCMEM_DEV_ID, 0);
if (ret) {
- dev_err(dev, "Could not enable secure configuration\n");
+ dev_err_probe(dev, ret, "Could not enable secure configuration\n");
goto err_clk_disable;
}
}
+ reg = ocmem_read(ocmem, OCMEM_REG_HW_VERSION);
+ dev_dbg(dev, "OCMEM hardware version: %lu.%lu.%lu\n",
+ OCMEM_HW_VERSION_MAJOR(reg),
+ OCMEM_HW_VERSION_MINOR(reg),
+ OCMEM_HW_VERSION_STEP(reg));
+
reg = ocmem_read(ocmem, OCMEM_REG_HW_PROFILE);
ocmem->num_ports = OCMEM_HW_PROFILE_NUM_PORTS(reg);
ocmem->num_macros = OCMEM_HW_PROFILE_NUM_MACROS(reg);
@@ -403,23 +406,31 @@ static int ocmem_dev_probe(struct platform_device *pdev)
return 0;
err_clk_disable:
- clk_bulk_disable_unprepare(ARRAY_SIZE(ocmem_clks), ocmem_clks);
+ clk_disable_unprepare(ocmem->core_clk);
+ clk_disable_unprepare(ocmem->iface_clk);
return ret;
}
-static int ocmem_dev_remove(struct platform_device *pdev)
+static void ocmem_dev_remove(struct platform_device *pdev)
{
- clk_bulk_disable_unprepare(ARRAY_SIZE(ocmem_clks), ocmem_clks);
+ struct ocmem *ocmem = platform_get_drvdata(pdev);
- return 0;
+ clk_disable_unprepare(ocmem->core_clk);
+ clk_disable_unprepare(ocmem->iface_clk);
}
+static const struct ocmem_config ocmem_8226_config = {
+ .num_regions = 1,
+ .macro_size = SZ_128K,
+};
+
static const struct ocmem_config ocmem_8974_config = {
.num_regions = 3,
.macro_size = SZ_128K,
};
static const struct of_device_id ocmem_of_match[] = {
+ { .compatible = "qcom,msm8226-ocmem", .data = &ocmem_8226_config },
{ .compatible = "qcom,msm8974-ocmem", .data = &ocmem_8974_config },
{ }
};
diff --git a/drivers/soc/qcom/pdr_interface.c b/drivers/soc/qcom/pdr_interface.c
index 0034af927b48..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,12 +543,9 @@ 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(pdr_add_lookup);
+EXPORT_SYMBOL_GPL(pdr_add_lookup);
/**
* pdr_restart_pd() - restart PD
@@ -634,7 +625,7 @@ int pdr_restart_pd(struct pdr_handle *pdr, struct pdr_service *pds)
return 0;
}
-EXPORT_SYMBOL(pdr_restart_pd);
+EXPORT_SYMBOL_GPL(pdr_restart_pd);
/**
* pdr_handle_alloc() - initialize the PDR client handle
@@ -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,12 +698,10 @@ destroy_indack:
destroy_workqueue(pdr->indack_wq);
destroy_notifier:
destroy_workqueue(pdr->notifier_wq);
-free_pdr_handle:
- kfree(pdr);
return ERR_PTR(ret);
}
-EXPORT_SYMBOL(pdr_handle_alloc);
+EXPORT_SYMBOL_GPL(pdr_handle_alloc);
/**
* pdr_handle_release() - release the PDR client handle
@@ -749,7 +735,7 @@ void pdr_handle_release(struct pdr_handle *pdr)
kfree(pdr);
}
-EXPORT_SYMBOL(pdr_handle_release);
+EXPORT_SYMBOL_GPL(pdr_handle_release);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Qualcomm Protection Domain Restart helpers");
diff --git a/drivers/soc/qcom/pdr_internal.h b/drivers/soc/qcom/pdr_internal.h
index 03c282b7f17e..039508c1bbf7 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,59 @@ 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_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
new file mode 100644
index 000000000000..627f96ca322e
--- /dev/null
+++ b/drivers/soc/qcom/pmic_glink.c
@@ -0,0 +1,431 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ * 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>
+#include <linux/rpmsg.h>
+#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,
+ PMIC_GLINK_CLIENT_ALTMODE,
+ PMIC_GLINK_CLIENT_UCSI,
+};
+
+struct pmic_glink {
+ struct device *dev;
+ struct pdr_handle *pdr;
+
+ struct rpmsg_endpoint *ept;
+
+ unsigned long client_mask;
+
+ struct auxiliary_device altmode_aux;
+ struct auxiliary_device ps_aux;
+ struct auxiliary_device ucsi_aux;
+
+ /* serializing client_state and pdr_state updates */
+ struct mutex state_lock;
+ unsigned int client_state;
+ unsigned int pdr_state;
+ bool pdr_available;
+
+ /* serializing clients list updates */
+ spinlock_t client_lock;
+ struct list_head clients;
+};
+
+static struct pmic_glink *__pmic_glink;
+static DEFINE_MUTEX(__pmic_glink_lock);
+
+struct pmic_glink_client {
+ struct list_head node;
+
+ struct pmic_glink *pg;
+ unsigned int id;
+
+ void (*cb)(const void *data, size_t len, void *priv);
+ void (*pdr_notify)(void *priv, int state);
+ void *priv;
+};
+
+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;
+
+ spin_lock_irqsave(&pg->client_lock, flags);
+ list_del(&client->node);
+ spin_unlock_irqrestore(&pg->client_lock, flags);
+}
+
+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);
+
+ client = devres_alloc(_devm_pmic_glink_release_client, sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return ERR_PTR(-ENOMEM);
+
+ client->pg = pg;
+ client->id = id;
+ client->cb = cb;
+ client->pdr_notify = pdr;
+ client->priv = priv;
+ INIT_LIST_HEAD(&client->node);
+
+ devres_add(dev, client);
+
+ return 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;
+
+ 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);
+
+static int pmic_glink_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
+ int len, void *priv, u32 addr)
+{
+ 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");
+ return 0;
+ }
+
+ 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;
+}
+
+static void pmic_glink_aux_release(struct device *dev)
+{
+ of_node_put(dev->of_node);
+}
+
+static int pmic_glink_add_aux_device(struct pmic_glink *pg,
+ struct auxiliary_device *aux,
+ const char *name)
+{
+ struct device *parent = pg->dev;
+ int ret;
+
+ aux->name = name;
+ aux->dev.parent = parent;
+ aux->dev.release = pmic_glink_aux_release;
+ device_set_of_node_from_dev(&aux->dev, parent);
+ ret = auxiliary_device_init(aux);
+ if (ret) {
+ of_node_put(aux->dev.of_node);
+ return ret;
+ }
+
+ ret = auxiliary_device_add(aux);
+ if (ret)
+ auxiliary_device_uninit(aux);
+
+ return ret;
+}
+
+static void pmic_glink_del_aux_device(struct pmic_glink *pg,
+ struct auxiliary_device *aux)
+{
+ auxiliary_device_delete(aux);
+ auxiliary_device_uninit(aux);
+}
+
+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_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;
+ }
+}
+
+static void pmic_glink_pdr_callback(int state, char *svc_path, void *priv)
+{
+ struct pmic_glink *pg = priv;
+
+ guard(mutex)(&pg->state_lock);
+ pg->pdr_state = state;
+
+ pmic_glink_state_notify_clients(pg);
+}
+
+static int pmic_glink_rpmsg_probe(struct rpmsg_device *rpdev)
+{
+ struct pmic_glink *pg;
+
+ 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);
+ pg->pdr_available = rpdev->id.driver_data;
+
+ guard(mutex)(&pg->state_lock);
+ pg->ept = rpdev->ept;
+ if (!pg->pdr_available)
+ pg->pdr_state = SERVREG_SERVICE_STATE_UP;
+ pmic_glink_state_notify_clients(pg);
+
+ return 0;
+}
+
+static void pmic_glink_rpmsg_remove(struct rpmsg_device *rpdev)
+{
+ struct pmic_glink *pg;
+
+ guard(mutex)(&__pmic_glink_lock);
+ pg = __pmic_glink;
+ if (!pg)
+ return;
+
+ guard(mutex)(&pg->state_lock);
+ pg->ept = NULL;
+ if (!pg->pdr_available)
+ pg->pdr_state = SERVREG_SERVICE_STATE_DOWN;
+ pmic_glink_state_notify_clients(pg);
+}
+
+static const struct rpmsg_device_id pmic_glink_rpmsg_id_match[] = {
+ {.name = "PMIC_RTR_ADSP_APPS", .driver_data = true },
+ {.name = "PMIC_RTR_SOCCP_APPS", .driver_data = false },
+ {}
+};
+
+static struct rpmsg_driver pmic_glink_rpmsg_driver = {
+ .probe = pmic_glink_rpmsg_probe,
+ .remove = pmic_glink_rpmsg_remove,
+ .callback = pmic_glink_rpmsg_callback,
+ .id_table = pmic_glink_rpmsg_id_match,
+ .drv = {
+ .name = "qcom_pmic_glink_rpmsg",
+ },
+};
+
+static int pmic_glink_probe(struct platform_device *pdev)
+{
+ const unsigned long *match_data;
+ struct pdr_service *service;
+ struct pmic_glink *pg;
+ int ret;
+
+ pg = devm_kzalloc(&pdev->dev, sizeof(*pg), GFP_KERNEL);
+ if (!pg)
+ return -ENOMEM;
+
+ dev_set_drvdata(&pdev->dev, pg);
+
+ pg->dev = &pdev->dev;
+
+ INIT_LIST_HEAD(&pg->clients);
+ spin_lock_init(&pg->client_lock);
+ mutex_init(&pg->state_lock);
+
+ match_data = (unsigned long *)of_device_get_match_data(&pdev->dev);
+ if (!match_data)
+ return -EINVAL;
+
+ pg->client_mask = *match_data;
+
+ pg->pdr = pdr_handle_alloc(pmic_glink_pdr_callback, pg);
+ if (IS_ERR(pg->pdr)) {
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(pg->pdr),
+ "failed to initialize pdr\n");
+ return ret;
+ }
+
+ if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) {
+ ret = pmic_glink_add_aux_device(pg, &pg->ucsi_aux, "ucsi");
+ if (ret)
+ goto out_release_pdr_handle;
+ }
+ if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) {
+ ret = pmic_glink_add_aux_device(pg, &pg->altmode_aux, "altmode");
+ if (ret)
+ goto out_release_ucsi_aux;
+ }
+ if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) {
+ ret = pmic_glink_add_aux_device(pg, &pg->ps_aux, "power-supply");
+ if (ret)
+ goto out_release_altmode_aux;
+ }
+
+ service = pdr_add_lookup(pg->pdr, "tms/servreg", "msm/adsp/charger_pd");
+ if (IS_ERR(service)) {
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(service),
+ "failed adding pdr lookup for charger_pd\n");
+ goto out_release_aux_devices;
+ }
+
+ mutex_lock(&__pmic_glink_lock);
+ __pmic_glink = pg;
+ mutex_unlock(&__pmic_glink_lock);
+
+ return 0;
+
+out_release_aux_devices:
+ if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT))
+ pmic_glink_del_aux_device(pg, &pg->ps_aux);
+out_release_altmode_aux:
+ if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE))
+ pmic_glink_del_aux_device(pg, &pg->altmode_aux);
+out_release_ucsi_aux:
+ if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI))
+ pmic_glink_del_aux_device(pg, &pg->ucsi_aux);
+out_release_pdr_handle:
+ pdr_handle_release(pg->pdr);
+
+ return ret;
+}
+
+static void pmic_glink_remove(struct platform_device *pdev)
+{
+ struct pmic_glink *pg = dev_get_drvdata(&pdev->dev);
+
+ pdr_handle_release(pg->pdr);
+
+ if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT))
+ pmic_glink_del_aux_device(pg, &pg->ps_aux);
+ if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE))
+ pmic_glink_del_aux_device(pg, &pg->altmode_aux);
+ if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI))
+ pmic_glink_del_aux_device(pg, &pg->ucsi_aux);
+
+ guard(mutex)(&__pmic_glink_lock);
+ __pmic_glink = NULL;
+}
+
+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,pmic-glink", .data = &pmic_glink_sm8450_client_mask },
+ {}
+};
+MODULE_DEVICE_TABLE(of, pmic_glink_of_match);
+
+static struct platform_driver pmic_glink_driver = {
+ .probe = pmic_glink_probe,
+ .remove = pmic_glink_remove,
+ .driver = {
+ .name = "qcom_pmic_glink",
+ .of_match_table = pmic_glink_of_match,
+ },
+};
+
+static int pmic_glink_init(void)
+{
+ 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;
+}
+module_init(pmic_glink_init);
+
+static void pmic_glink_exit(void)
+{
+ unregister_rpmsg_driver(&pmic_glink_rpmsg_driver);
+ platform_driver_unregister(&pmic_glink_driver);
+}
+module_exit(pmic_glink_exit);
+
+MODULE_DESCRIPTION("Qualcomm PMIC GLINK driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/qcom/pmic_glink_altmode.c b/drivers/soc/qcom/pmic_glink_altmode.c
new file mode 100644
index 000000000000..7f11acd33323
--- /dev/null
+++ b/drivers/soc/qcom/pmic_glink_altmode.c
@@ -0,0 +1,558 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Linaro Ltd
+ */
+#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>
+#include <linux/mutex.h>
+#include <linux/property.h>
+#include <linux/soc/qcom/pdr.h>
+#include <drm/bridge/aux-bridge.h>
+
+#include <linux/usb/typec_altmode.h>
+#include <linux/usb/typec_dp.h>
+#include <linux/usb/typec_mux.h>
+#include <linux/usb/typec_retimer.h>
+
+#include <linux/soc/qcom/pmic_glink.h>
+
+#define PMIC_GLINK_MAX_PORTS 3
+
+#define USBC_SC8180X_NOTIFY_IND 0x13
+#define USBC_CMD_WRITE_REQ 0x15
+#define USBC_NOTIFY_IND 0x16
+
+#define ALTMODE_PAN_EN 0x10
+#define ALTMODE_PAN_ACK 0x11
+
+struct usbc_write_req {
+ struct pmic_glink_hdr hdr;
+ __le32 cmd;
+ __le32 arg;
+ __le32 reserved;
+};
+
+#define NOTIFY_PAYLOAD_SIZE 16
+struct usbc_notify {
+ struct pmic_glink_hdr hdr;
+ char payload[NOTIFY_PAYLOAD_SIZE];
+ u32 reserved;
+};
+
+struct usbc_sc8180x_notify {
+ struct pmic_glink_hdr hdr;
+ __le32 notification;
+ __le32 reserved[2];
+};
+
+enum pmic_glink_altmode_pin_assignment {
+ DPAM_HPD_OUT,
+ DPAM_HPD_A,
+ DPAM_HPD_B,
+ DPAM_HPD_C,
+ DPAM_HPD_D,
+ DPAM_HPD_E,
+ DPAM_HPD_F,
+};
+
+struct pmic_glink_altmode;
+
+#define work_to_altmode_port(w) container_of((w), struct pmic_glink_altmode_port, work)
+
+struct pmic_glink_altmode_port {
+ struct pmic_glink_altmode *altmode;
+ unsigned int index;
+
+ struct typec_switch *typec_switch;
+ struct typec_mux *typec_mux;
+ struct typec_mux_state state;
+ struct typec_retimer *typec_retimer;
+ struct typec_retimer_state retimer_state;
+ struct typec_altmode dp_alt;
+
+ struct work_struct work;
+
+ struct auxiliary_device *bridge;
+
+ enum typec_orientation orientation;
+ u16 svid;
+ u8 dp_data;
+ u8 mode;
+ u8 hpd_state;
+ u8 hpd_irq;
+};
+
+#define work_to_altmode(w) container_of((w), struct pmic_glink_altmode, enable_work)
+
+struct pmic_glink_altmode {
+ struct device *dev;
+
+ unsigned int owner_id;
+
+ /* To synchronize WRITE_REQ acks */
+ struct mutex lock;
+
+ struct completion pan_ack;
+ struct pmic_glink_client *client;
+
+ struct work_struct enable_work;
+
+ struct pmic_glink_altmode_port ports[PMIC_GLINK_MAX_PORTS];
+};
+
+static int pmic_glink_altmode_request(struct pmic_glink_altmode *altmode, u32 cmd, u32 arg)
+{
+ struct usbc_write_req req = {};
+ unsigned long left;
+ int ret;
+
+ /*
+ * The USBC_CMD_WRITE_REQ ack doesn't identify the request, so wait for
+ * one ack at a time.
+ */
+ guard(mutex)(&altmode->lock);
+
+ req.hdr.owner = cpu_to_le32(altmode->owner_id);
+ req.hdr.type = cpu_to_le32(PMIC_GLINK_REQ_RESP);
+ req.hdr.opcode = cpu_to_le32(USBC_CMD_WRITE_REQ);
+ req.cmd = cpu_to_le32(cmd);
+ req.arg = cpu_to_le32(arg);
+
+ 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);
+ 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);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static void pmic_glink_altmode_enable_dp(struct pmic_glink_altmode *altmode,
+ struct pmic_glink_altmode_port *port,
+ u8 mode, bool hpd_state,
+ bool hpd_irq)
+{
+ struct typec_displayport_data dp_data = {};
+ int ret;
+
+ dp_data.status = DP_STATUS_ENABLED;
+ if (hpd_state)
+ dp_data.status |= DP_STATUS_HPD_STATE;
+ if (hpd_irq)
+ dp_data.status |= DP_STATUS_IRQ_HPD;
+ dp_data.conf = DP_CONF_SET_PIN_ASSIGN(mode);
+
+ port->state.alt = &port->dp_alt;
+ port->state.data = &dp_data;
+ port->state.mode = TYPEC_MODAL_STATE(mode);
+
+ ret = typec_mux_set(port->typec_mux, &port->state);
+ if (ret)
+ dev_err(altmode->dev, "failed to switch mux to DP: %d\n", ret);
+
+ port->retimer_state.alt = &port->dp_alt;
+ port->retimer_state.data = &dp_data;
+ port->retimer_state.mode = TYPEC_MODAL_STATE(mode);
+
+ ret = typec_retimer_set(port->typec_retimer, &port->retimer_state);
+ if (ret)
+ dev_err(altmode->dev, "failed to setup retimer to DP: %d\n", ret);
+}
+
+static void pmic_glink_altmode_enable_usb(struct pmic_glink_altmode *altmode,
+ struct pmic_glink_altmode_port *port)
+{
+ int ret;
+
+ port->state.alt = NULL;
+ port->state.data = NULL;
+ port->state.mode = TYPEC_STATE_USB;
+
+ ret = typec_mux_set(port->typec_mux, &port->state);
+ if (ret)
+ dev_err(altmode->dev, "failed to switch mux to USB: %d\n", ret);
+
+ port->retimer_state.alt = NULL;
+ port->retimer_state.data = NULL;
+ port->retimer_state.mode = TYPEC_STATE_USB;
+
+ ret = typec_retimer_set(port->typec_retimer, &port->retimer_state);
+ if (ret)
+ dev_err(altmode->dev, "failed to setup retimer to USB: %d\n", ret);
+}
+
+static void pmic_glink_altmode_safe(struct pmic_glink_altmode *altmode,
+ struct pmic_glink_altmode_port *port)
+{
+ int ret;
+
+ port->state.alt = NULL;
+ port->state.data = NULL;
+ port->state.mode = TYPEC_STATE_SAFE;
+
+ ret = typec_mux_set(port->typec_mux, &port->state);
+ if (ret)
+ dev_err(altmode->dev, "failed to switch mux to safe mode: %d\n", ret);
+
+ port->retimer_state.alt = NULL;
+ port->retimer_state.data = NULL;
+ port->retimer_state.mode = TYPEC_STATE_SAFE;
+
+ ret = typec_retimer_set(port->typec_retimer, &port->retimer_state);
+ if (ret)
+ dev_err(altmode->dev, "failed to setup retimer to USB: %d\n", ret);
+}
+
+static void pmic_glink_altmode_worker(struct work_struct *work)
+{
+ struct pmic_glink_altmode_port *alt_port = work_to_altmode_port(work);
+ struct pmic_glink_altmode *altmode = alt_port->altmode;
+ enum drm_connector_status conn_status;
+
+ typec_switch_set(alt_port->typec_switch, alt_port->orientation);
+
+ if (alt_port->svid == USB_TYPEC_DP_SID) {
+ if (alt_port->mode == 0xff) {
+ pmic_glink_altmode_safe(altmode, alt_port);
+ } else {
+ pmic_glink_altmode_enable_dp(altmode, alt_port,
+ alt_port->mode,
+ alt_port->hpd_state,
+ alt_port->hpd_irq);
+ }
+
+ if (alt_port->hpd_state)
+ conn_status = connector_status_connected;
+ else
+ conn_status = connector_status_disconnected;
+
+ drm_aux_hpd_bridge_notify(&alt_port->bridge->dev, conn_status);
+ } else {
+ pmic_glink_altmode_enable_usb(altmode, alt_port);
+ }
+
+ pmic_glink_altmode_request(altmode, ALTMODE_PAN_ACK, alt_port->index);
+}
+
+static enum typec_orientation pmic_glink_altmode_orientation(unsigned int orientation)
+{
+ if (orientation == 0)
+ return TYPEC_ORIENTATION_NORMAL;
+ else if (orientation == 1)
+ return TYPEC_ORIENTATION_REVERSE;
+ else
+ return TYPEC_ORIENTATION_NONE;
+}
+
+#define SC8180X_PORT_MASK 0x000000ff
+#define SC8180X_ORIENTATION_MASK 0x0000ff00
+#define SC8180X_MUX_MASK 0x00ff0000
+#define SC8180X_MODE_MASK 0x3f000000
+#define SC8180X_HPD_STATE_MASK 0x40000000
+#define SC8180X_HPD_IRQ_MASK 0x80000000
+
+static void pmic_glink_altmode_sc8180xp_notify(struct pmic_glink_altmode *altmode,
+ const void *data, size_t len)
+{
+ struct pmic_glink_altmode_port *alt_port;
+ const struct usbc_sc8180x_notify *msg;
+ u32 notification;
+ u8 orientation;
+ u8 hpd_state;
+ u8 hpd_irq;
+ u16 svid;
+ u8 port;
+ u8 mode;
+ u8 mux;
+
+ if (len != sizeof(*msg)) {
+ dev_warn(altmode->dev, "invalid length of USBC_NOTIFY indication: %zd\n", len);
+ return;
+ }
+
+ msg = data;
+ notification = le32_to_cpu(msg->notification);
+ port = FIELD_GET(SC8180X_PORT_MASK, notification);
+ orientation = FIELD_GET(SC8180X_ORIENTATION_MASK, notification);
+ mux = FIELD_GET(SC8180X_MUX_MASK, notification);
+ mode = FIELD_GET(SC8180X_MODE_MASK, notification);
+ hpd_state = FIELD_GET(SC8180X_HPD_STATE_MASK, notification);
+ hpd_irq = FIELD_GET(SC8180X_HPD_IRQ_MASK, notification);
+
+ svid = mux == 2 ? USB_TYPEC_DP_SID : 0;
+
+ if (port >= ARRAY_SIZE(altmode->ports) || !altmode->ports[port].altmode) {
+ dev_dbg(altmode->dev, "notification on undefined port %d\n", port);
+ return;
+ }
+
+ alt_port = &altmode->ports[port];
+ alt_port->orientation = pmic_glink_altmode_orientation(orientation);
+ alt_port->svid = svid;
+ alt_port->mode = mode;
+ alt_port->hpd_state = hpd_state;
+ alt_port->hpd_irq = hpd_irq;
+ schedule_work(&alt_port->work);
+}
+
+#define SC8280XP_DPAM_MASK 0x3f
+#define SC8280XP_HPD_STATE_MASK BIT(6)
+#define SC8280XP_HPD_IRQ_MASK BIT(7)
+
+static void pmic_glink_altmode_sc8280xp_notify(struct pmic_glink_altmode *altmode,
+ u16 svid, const void *data, size_t len)
+{
+ struct pmic_glink_altmode_port *alt_port;
+ const struct usbc_notify *notify;
+ u8 orientation;
+ u8 hpd_state;
+ u8 hpd_irq;
+ u8 mode;
+ u8 port;
+
+ if (len != sizeof(*notify)) {
+ dev_warn(altmode->dev, "invalid length USBC_NOTIFY_IND: %zd\n",
+ len);
+ return;
+ }
+
+ notify = data;
+
+ port = notify->payload[0];
+ orientation = notify->payload[1];
+ mode = FIELD_GET(SC8280XP_DPAM_MASK, notify->payload[8]) - DPAM_HPD_A;
+ hpd_state = FIELD_GET(SC8280XP_HPD_STATE_MASK, notify->payload[8]);
+ hpd_irq = FIELD_GET(SC8280XP_HPD_IRQ_MASK, notify->payload[8]);
+
+ if (port >= ARRAY_SIZE(altmode->ports) || !altmode->ports[port].altmode) {
+ dev_dbg(altmode->dev, "notification on undefined port %d\n", port);
+ return;
+ }
+
+ alt_port = &altmode->ports[port];
+ alt_port->orientation = pmic_glink_altmode_orientation(orientation);
+ alt_port->svid = svid;
+ alt_port->mode = mode;
+ alt_port->hpd_state = hpd_state;
+ alt_port->hpd_irq = hpd_irq;
+ schedule_work(&alt_port->work);
+}
+
+static void pmic_glink_altmode_callback(const void *data, size_t len, void *priv)
+{
+ struct pmic_glink_altmode *altmode = priv;
+ const struct pmic_glink_hdr *hdr = data;
+ u16 opcode;
+ u16 svid;
+
+ opcode = le32_to_cpu(hdr->opcode) & 0xff;
+ svid = le32_to_cpu(hdr->opcode) >> 16;
+
+ switch (opcode) {
+ case USBC_CMD_WRITE_REQ:
+ complete(&altmode->pan_ack);
+ break;
+ case USBC_NOTIFY_IND:
+ pmic_glink_altmode_sc8280xp_notify(altmode, svid, data, len);
+ break;
+ case USBC_SC8180X_NOTIFY_IND:
+ pmic_glink_altmode_sc8180xp_notify(altmode, data, len);
+ break;
+ }
+}
+
+static void pmic_glink_altmode_put_retimer(void *data)
+{
+ typec_retimer_put(data);
+}
+
+static void pmic_glink_altmode_put_mux(void *data)
+{
+ typec_mux_put(data);
+}
+
+static void pmic_glink_altmode_put_switch(void *data)
+{
+ typec_switch_put(data);
+}
+
+static void pmic_glink_altmode_enable_worker(struct work_struct *work)
+{
+ struct pmic_glink_altmode *altmode = work_to_altmode(work);
+ int ret;
+
+ ret = pmic_glink_altmode_request(altmode, ALTMODE_PAN_EN, 0);
+ if (ret)
+ dev_err(altmode->dev, "failed to request altmode notifications: %d\n", ret);
+}
+
+static void pmic_glink_altmode_pdr_notify(void *priv, int state)
+{
+ struct pmic_glink_altmode *altmode = priv;
+
+ if (state == SERVREG_SERVICE_STATE_UP)
+ schedule_work(&altmode->enable_work);
+}
+
+static const struct of_device_id pmic_glink_altmode_of_quirks[] = {
+ { .compatible = "qcom,sc8180x-pmic-glink", .data = (void *)PMIC_GLINK_OWNER_USBC },
+ {}
+};
+
+static int pmic_glink_altmode_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
+{
+ struct pmic_glink_altmode_port *alt_port;
+ struct pmic_glink_altmode *altmode;
+ const struct of_device_id *match;
+ struct fwnode_handle *fwnode;
+ struct device *dev = &adev->dev;
+ u32 port;
+ int ret;
+
+ altmode = devm_kzalloc(dev, sizeof(*altmode), GFP_KERNEL);
+ if (!altmode)
+ return -ENOMEM;
+
+ altmode->dev = dev;
+
+ match = of_match_device(pmic_glink_altmode_of_quirks, dev->parent);
+ if (match)
+ altmode->owner_id = (unsigned long)match->data;
+ else
+ altmode->owner_id = PMIC_GLINK_OWNER_USBC_PAN;
+
+ INIT_WORK(&altmode->enable_work, pmic_glink_altmode_enable_worker);
+ init_completion(&altmode->pan_ack);
+ mutex_init(&altmode->lock);
+
+ device_for_each_child_node(dev, fwnode) {
+ ret = fwnode_property_read_u32(fwnode, "reg", &port);
+ if (ret < 0) {
+ dev_err(dev, "missing reg property of %pOFn\n", fwnode);
+ fwnode_handle_put(fwnode);
+ return ret;
+ }
+
+ if (port >= ARRAY_SIZE(altmode->ports)) {
+ dev_warn(dev, "invalid connector number, ignoring\n");
+ continue;
+ }
+
+ if (altmode->ports[port].altmode) {
+ dev_err(dev, "multiple connector definition for port %u\n", port);
+ fwnode_handle_put(fwnode);
+ return -EINVAL;
+ }
+
+ alt_port = &altmode->ports[port];
+ alt_port->altmode = altmode;
+ alt_port->index = port;
+ INIT_WORK(&alt_port->work, pmic_glink_altmode_worker);
+
+ alt_port->bridge = devm_drm_dp_hpd_bridge_alloc(dev, to_of_node(fwnode));
+ if (IS_ERR(alt_port->bridge)) {
+ fwnode_handle_put(fwnode);
+ return PTR_ERR(alt_port->bridge);
+ }
+
+ alt_port->dp_alt.svid = USB_TYPEC_DP_SID;
+ alt_port->dp_alt.mode = USB_TYPEC_DP_MODE;
+ alt_port->dp_alt.active = 1;
+
+ alt_port->typec_mux = fwnode_typec_mux_get(fwnode);
+ if (IS_ERR(alt_port->typec_mux)) {
+ fwnode_handle_put(fwnode);
+ return dev_err_probe(dev, PTR_ERR(alt_port->typec_mux),
+ "failed to acquire mode-switch for port: %d\n",
+ port);
+ }
+
+ ret = devm_add_action_or_reset(dev, pmic_glink_altmode_put_mux,
+ alt_port->typec_mux);
+ if (ret) {
+ fwnode_handle_put(fwnode);
+ return ret;
+ }
+
+ alt_port->typec_retimer = fwnode_typec_retimer_get(fwnode);
+ if (IS_ERR(alt_port->typec_retimer)) {
+ fwnode_handle_put(fwnode);
+ return dev_err_probe(dev, PTR_ERR(alt_port->typec_retimer),
+ "failed to acquire retimer-switch for port: %d\n",
+ port);
+ }
+
+ ret = devm_add_action_or_reset(dev, pmic_glink_altmode_put_retimer,
+ alt_port->typec_retimer);
+ if (ret) {
+ fwnode_handle_put(fwnode);
+ return ret;
+ }
+
+ alt_port->typec_switch = fwnode_typec_switch_get(fwnode);
+ if (IS_ERR(alt_port->typec_switch)) {
+ fwnode_handle_put(fwnode);
+ return dev_err_probe(dev, PTR_ERR(alt_port->typec_switch),
+ "failed to acquire orientation-switch for port: %d\n",
+ port);
+ }
+
+ ret = devm_add_action_or_reset(dev, pmic_glink_altmode_put_switch,
+ alt_port->typec_switch);
+ if (ret) {
+ fwnode_handle_put(fwnode);
+ return ret;
+ }
+ }
+
+ for (port = 0; port < ARRAY_SIZE(altmode->ports); port++) {
+ alt_port = &altmode->ports[port];
+ if (!alt_port->bridge)
+ continue;
+
+ ret = devm_drm_dp_hpd_bridge_add(dev, alt_port->bridge);
+ if (ret)
+ return ret;
+ }
+
+ 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[] = {
+ { .name = "pmic_glink.altmode", },
+ {},
+};
+MODULE_DEVICE_TABLE(auxiliary, pmic_glink_altmode_id_table);
+
+static struct auxiliary_driver pmic_glink_altmode_driver = {
+ .name = "pmic_glink_altmode",
+ .probe = pmic_glink_altmode_probe,
+ .id_table = pmic_glink_altmode_id_table,
+};
+
+module_auxiliary_driver(pmic_glink_altmode_driver);
+
+MODULE_DESCRIPTION("Qualcomm PMIC GLINK Altmode driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/qcom/pmic_pdcharger_ulog.c b/drivers/soc/qcom/pmic_pdcharger_ulog.c
new file mode 100644
index 000000000000..39f412bbf2c1
--- /dev/null
+++ b/drivers/soc/qcom/pmic_pdcharger_ulog.c
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019-2022, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023, Linaro Ltd
+ */
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rpmsg.h>
+#include <linux/slab.h>
+#include <linux/soc/qcom/pdr.h>
+#include <linux/debugfs.h>
+
+#define CREATE_TRACE_POINTS
+#include "pmic_pdcharger_ulog.h"
+
+#define MSG_OWNER_CHG_ULOG 32778
+#define MSG_TYPE_REQ_RESP 1
+
+#define GET_CHG_ULOG_REQ 0x18
+#define SET_CHG_ULOG_PROP_REQ 0x19
+
+#define LOG_DEFAULT_TIME_MS 1000
+
+#define MAX_ULOG_SIZE 8192
+
+struct pmic_pdcharger_ulog_hdr {
+ __le32 owner;
+ __le32 type;
+ __le32 opcode;
+};
+
+struct pmic_pdcharger_ulog {
+ struct rpmsg_device *rpdev;
+ struct delayed_work ulog_work;
+};
+
+struct get_ulog_req_msg {
+ struct pmic_pdcharger_ulog_hdr hdr;
+ u32 log_size;
+};
+
+struct get_ulog_resp_msg {
+ struct pmic_pdcharger_ulog_hdr hdr;
+ u8 buf[MAX_ULOG_SIZE];
+};
+
+static int pmic_pdcharger_ulog_write_async(struct pmic_pdcharger_ulog *pg, void *data, size_t len)
+{
+ return rpmsg_send(pg->rpdev->ept, data, len);
+}
+
+static int pmic_pdcharger_ulog_request(struct pmic_pdcharger_ulog *pg)
+{
+ struct get_ulog_req_msg req_msg = {
+ .hdr = {
+ .owner = cpu_to_le32(MSG_OWNER_CHG_ULOG),
+ .type = cpu_to_le32(MSG_TYPE_REQ_RESP),
+ .opcode = cpu_to_le32(GET_CHG_ULOG_REQ)
+ },
+ .log_size = MAX_ULOG_SIZE
+ };
+
+ return pmic_pdcharger_ulog_write_async(pg, &req_msg, sizeof(req_msg));
+}
+
+static void pmic_pdcharger_ulog_work(struct work_struct *work)
+{
+ struct pmic_pdcharger_ulog *pg = container_of(work, struct pmic_pdcharger_ulog,
+ ulog_work.work);
+ int rc;
+
+ rc = pmic_pdcharger_ulog_request(pg);
+ if (rc) {
+ dev_err(&pg->rpdev->dev, "Error requesting ulog, rc=%d\n", rc);
+ return;
+ }
+}
+
+static void pmic_pdcharger_ulog_handle_message(struct pmic_pdcharger_ulog *pg,
+ struct get_ulog_resp_msg *resp_msg,
+ size_t len)
+{
+ char *token, *buf = resp_msg->buf;
+
+ if (len != sizeof(*resp_msg)) {
+ dev_err(&pg->rpdev->dev, "Expected data length: %zu, received: %zu\n",
+ sizeof(*resp_msg), len);
+ return;
+ }
+
+ buf[MAX_ULOG_SIZE - 1] = '\0';
+
+ do {
+ token = strsep((char **)&buf, "\n");
+ if (token && strlen(token))
+ trace_pmic_pdcharger_ulog_msg(token);
+ } while (token);
+}
+
+static int pmic_pdcharger_ulog_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
+ int len, void *priv, u32 addr)
+{
+ struct pmic_pdcharger_ulog *pg = dev_get_drvdata(&rpdev->dev);
+ struct pmic_pdcharger_ulog_hdr *hdr = data;
+ u32 opcode;
+
+ opcode = le32_to_cpu(hdr->opcode);
+
+ switch (opcode) {
+ case GET_CHG_ULOG_REQ:
+ schedule_delayed_work(&pg->ulog_work, msecs_to_jiffies(LOG_DEFAULT_TIME_MS));
+ pmic_pdcharger_ulog_handle_message(pg, data, len);
+ break;
+ default:
+ dev_err(&pg->rpdev->dev, "Unknown opcode %u\n", opcode);
+ break;
+ }
+
+ return 0;
+}
+
+static int pmic_pdcharger_ulog_rpmsg_probe(struct rpmsg_device *rpdev)
+{
+ struct pmic_pdcharger_ulog *pg;
+ struct device *dev = &rpdev->dev;
+
+ pg = devm_kzalloc(dev, sizeof(*pg), GFP_KERNEL);
+ if (!pg)
+ return -ENOMEM;
+
+ pg->rpdev = rpdev;
+ INIT_DELAYED_WORK(&pg->ulog_work, pmic_pdcharger_ulog_work);
+
+ dev_set_drvdata(dev, pg);
+
+ pmic_pdcharger_ulog_request(pg);
+
+ return 0;
+}
+
+static void pmic_pdcharger_ulog_rpmsg_remove(struct rpmsg_device *rpdev)
+{
+ struct pmic_pdcharger_ulog *pg = dev_get_drvdata(&rpdev->dev);
+
+ cancel_delayed_work_sync(&pg->ulog_work);
+}
+
+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,
+ .remove = pmic_pdcharger_ulog_rpmsg_remove,
+ .callback = pmic_pdcharger_ulog_rpmsg_callback,
+ .id_table = pmic_pdcharger_ulog_rpmsg_id_match,
+ .drv = {
+ .name = "qcom_pmic_pdcharger_ulog_rpmsg",
+ },
+};
+
+module_rpmsg_driver(pmic_pdcharger_ulog_rpmsg_driver);
+MODULE_DESCRIPTION("Qualcomm PMIC ChargerPD ULOG driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/qcom/pmic_pdcharger_ulog.h b/drivers/soc/qcom/pmic_pdcharger_ulog.h
new file mode 100644
index 000000000000..1cfa58f0e34c
--- /dev/null
+++ b/drivers/soc/qcom/pmic_pdcharger_ulog.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2023, Linaro Ltd
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM pmic_pdcharger_ulog
+
+#if !defined(_TRACE_PMIC_PDCHARGER_ULOG_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_PMIC_PDCHARGER_ULOG_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(pmic_pdcharger_ulog_msg,
+ TP_PROTO(char *msg),
+ TP_ARGS(msg),
+ TP_STRUCT__entry(
+ __string(msg, msg)
+ ),
+ TP_fast_assign(
+ __assign_str(msg);
+ ),
+ TP_printk("%s", __get_str(msg))
+);
+
+#endif /* _TRACE_PMIC_PDCHARGER_ULOG_H */
+
+/* This part must be outside protection */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE pmic_pdcharger_ulog
+
+#include <trace/define_trace.h>
diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c
index f0475b93ca73..cd1779b6a91a 100644
--- a/drivers/soc/qcom/qcom-geni-se.c
+++ b/drivers/soc/qcom/qcom-geni-se.c
@@ -1,11 +1,16 @@
// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
/* Disable MMIO tracing to prevent excessive logging of unwanted MMIO traces */
#define __DISABLE_TRACE_MMIO__
#include <linux/acpi.h>
+#include <linux/bitfield.h>
#include <linux/clk.h>
+#include <linux/firmware.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
@@ -14,7 +19,7 @@
#include <linux/of_platform.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
-#include <linux/qcom-geni-se.h>
+#include <linux/soc/qcom/geni-se.h>
/**
* DOC: Overview
@@ -89,7 +94,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;
@@ -111,22 +115,94 @@ struct geni_se_desc {
static const char * const icc_path_names[] = {"qup-core", "qup-config",
"qup-memory"};
-#define QUP_HW_VER_REG 0x4
+static const char * const protocol_name[] = { "None", "SPI", "UART", "I2C", "I3C", "SPI SLAVE" };
+
+/**
+ * struct se_fw_hdr - Serial Engine firmware configuration header
+ *
+ * This structure defines the SE firmware header, which together with the
+ * firmware payload is stored in individual ELF segments.
+ *
+ * @magic: Set to 'SEFW'.
+ * @version: Structure version number.
+ * @core_version: QUPV3 hardware version.
+ * @serial_protocol: Encoded in GENI_FW_REVISION.
+ * @fw_version: Firmware version, from GENI_FW_REVISION.
+ * @cfg_version: Configuration version, from GENI_INIT_CFG_REVISION.
+ * @fw_size_in_items: Number of 32-bit words in GENI_FW_RAM.
+ * @fw_offset: Byte offset to GENI_FW_RAM array.
+ * @cfg_size_in_items: Number of GENI_FW_CFG index/value pairs.
+ * @cfg_idx_offset: Byte offset to GENI_FW_CFG index array.
+ * @cfg_val_offset: Byte offset to GENI_FW_CFG values array.
+ */
+struct se_fw_hdr {
+ __le32 magic;
+ __le32 version;
+ __le32 core_version;
+ __le16 serial_protocol;
+ __le16 fw_version;
+ __le16 cfg_version;
+ __le16 fw_size_in_items;
+ __le16 fw_offset;
+ __le16 cfg_size_in_items;
+ __le16 cfg_idx_offset;
+ __le16 cfg_val_offset;
+};
+
+/*Magic numbers*/
+#define SE_MAGIC_NUM 0x57464553
+
+#define MAX_GENI_CFG_RAMn_CNT 455
+
+#define MI_PBT_NON_PAGED_SEGMENT 0x0
+#define MI_PBT_HASH_SEGMENT 0x2
+#define MI_PBT_NOTUSED_SEGMENT 0x3
+#define MI_PBT_SHARED_SEGMENT 0x4
+
+#define MI_PBT_FLAG_PAGE_MODE BIT(20)
+#define MI_PBT_FLAG_SEGMENT_TYPE GENMASK(26, 24)
+#define MI_PBT_FLAG_ACCESS_TYPE GENMASK(23, 21)
+
+#define MI_PBT_PAGE_MODE_VALUE(x) FIELD_GET(MI_PBT_FLAG_PAGE_MODE, x)
+
+#define MI_PBT_SEGMENT_TYPE_VALUE(x) FIELD_GET(MI_PBT_FLAG_SEGMENT_TYPE, x)
+
+#define MI_PBT_ACCESS_TYPE_VALUE(x) FIELD_GET(MI_PBT_FLAG_ACCESS_TYPE, x)
+
+#define M_COMMON_GENI_M_IRQ_EN (GENMASK(6, 1) | \
+ M_IO_DATA_DEASSERT_EN | \
+ M_IO_DATA_ASSERT_EN | M_RX_FIFO_RD_ERR_EN | \
+ M_RX_FIFO_WR_ERR_EN | M_TX_FIFO_RD_ERR_EN | \
+ M_TX_FIFO_WR_ERR_EN)
+
+/* Common QUPV3 registers */
+#define QUPV3_HW_VER_REG 0x4
+#define QUPV3_SE_AHB_M_CFG 0x118
+#define QUPV3_COMMON_CFG 0x120
+#define QUPV3_COMMON_CGC_CTRL 0x21c
+
+/* QUPV3_COMMON_CFG fields */
+#define FAST_SWITCH_TO_HIGH_DISABLE BIT(0)
+
+/* QUPV3_SE_AHB_M_CFG fields */
+#define AHB_M_CLK_CGC_ON BIT(0)
+
+/* QUPV3_COMMON_CGC_CTRL fields */
+#define COMMON_CSR_SLV_CLK_CGC_ON BIT(0)
/* Common SE registers */
-#define GENI_INIT_CFG_REVISION 0x0
-#define GENI_S_INIT_CFG_REVISION 0x4
-#define GENI_OUTPUT_CTRL 0x24
-#define GENI_CGC_CTRL 0x28
-#define GENI_CLK_CTRL_RO 0x60
-#define GENI_FW_S_REVISION_RO 0x6c
+#define SE_GENI_INIT_CFG_REVISION 0x0
+#define SE_GENI_S_INIT_CFG_REVISION 0x4
+#define SE_GENI_CGC_CTRL 0x28
+#define SE_GENI_CLK_CTRL_RO 0x60
+#define SE_GENI_FW_S_REVISION_RO 0x6c
+#define SE_GENI_CFG_REG0 0x100
#define SE_GENI_BYTE_GRAN 0x254
#define SE_GENI_TX_PACKING_CFG0 0x260
#define SE_GENI_TX_PACKING_CFG1 0x264
#define SE_GENI_RX_PACKING_CFG0 0x284
#define SE_GENI_RX_PACKING_CFG1 0x288
-#define SE_GENI_M_GP_LENGTH 0x910
-#define SE_GENI_S_GP_LENGTH 0x914
+#define SE_GENI_S_IRQ_ENABLE 0x644
#define SE_DMA_TX_PTR_L 0xc30
#define SE_DMA_TX_PTR_H 0xc34
#define SE_DMA_TX_ATTR 0xc38
@@ -143,12 +219,20 @@ static const char * const icc_path_names[] = {"qup-core", "qup-config",
#define SE_DMA_RX_IRQ_EN 0xd48
#define SE_DMA_RX_IRQ_EN_SET 0xd4c
#define SE_DMA_RX_IRQ_EN_CLR 0xd50
-#define SE_DMA_RX_LEN_IN 0xd54
#define SE_DMA_RX_MAX_BURST 0xd5c
#define SE_DMA_RX_FLUSH 0xd60
#define SE_GSI_EVENT_EN 0xe18
#define SE_IRQ_EN 0xe1c
#define SE_DMA_GENERAL_CFG 0xe30
+#define SE_GENI_FW_REVISION 0x1000
+#define SE_GENI_S_FW_REVISION 0x1004
+#define SE_GENI_CFG_RAMN 0x1010
+#define SE_GENI_CLK_CTRL 0x2000
+#define SE_DMA_IF_EN 0x2004
+#define SE_FIFO_IF_DISABLE 0x2008
+
+/* GENI_FW_REVISION_RO fields */
+#define FW_REV_VERSION_MSK GENMASK(7, 0)
/* GENI_OUTPUT_CTRL fields */
#define DEFAULT_IO_OUTPUT_CTRL_MSK GENMASK(6, 0)
@@ -180,13 +264,22 @@ static const char * const icc_path_names[] = {"qup-core", "qup-config",
/* SE_DMA_GENERAL_CFG */
#define DMA_RX_CLK_CGC_ON BIT(0)
#define DMA_TX_CLK_CGC_ON BIT(1)
-#define DMA_AHB_SLV_CFG_ON BIT(2)
+#define DMA_AHB_SLV_CLK_CGC_ON BIT(2)
#define AHB_SEC_SLV_CLK_CGC_ON BIT(3)
#define DUMMY_RX_NON_BUFFERABLE BIT(4)
#define RX_DMA_ZERO_PADDING_EN BIT(5)
#define RX_DMA_IRQ_DELAY_MSK GENMASK(8, 6)
#define RX_DMA_IRQ_DELAY_SHFT 6
+/* GENI_CLK_CTRL fields */
+#define SER_CLK_SEL BIT(0)
+
+/* GENI_DMA_IF_EN fields */
+#define DMA_IF_EN BIT(0)
+
+#define geni_setbits32(_addr, _v) writel(readl(_addr) | (_v), _addr)
+#define geni_clrbits32(_addr, _v) writel(readl(_addr) & ~(_v), _addr)
+
/**
* geni_se_get_qup_hw_version() - Read the QUP wrapper Hardware version
* @se: Pointer to the corresponding serial engine.
@@ -197,9 +290,9 @@ u32 geni_se_get_qup_hw_version(struct geni_se *se)
{
struct geni_wrapper *wrapper = se->wrapper;
- return readl_relaxed(wrapper->base + QUP_HW_VER_REG);
+ return readl_relaxed(wrapper->base + QUPV3_HW_VER_REG);
}
-EXPORT_SYMBOL(geni_se_get_qup_hw_version);
+EXPORT_SYMBOL_GPL(geni_se_get_qup_hw_version);
static void geni_se_io_set_mode(void __iomem *base)
{
@@ -221,12 +314,12 @@ static void geni_se_io_init(void __iomem *base)
{
u32 val;
- val = readl_relaxed(base + GENI_CGC_CTRL);
+ val = readl_relaxed(base + SE_GENI_CGC_CTRL);
val |= DEFAULT_CGC_EN;
- writel_relaxed(val, base + GENI_CGC_CTRL);
+ writel_relaxed(val, base + SE_GENI_CGC_CTRL);
val = readl_relaxed(base + SE_DMA_GENERAL_CFG);
- val |= AHB_SEC_SLV_CLK_CGC_ON | DMA_AHB_SLV_CFG_ON;
+ val |= AHB_SEC_SLV_CLK_CGC_ON | DMA_AHB_SLV_CLK_CGC_ON;
val |= DMA_TX_CLK_CGC_ON | DMA_RX_CLK_CGC_ON;
writel_relaxed(val, base + SE_DMA_GENERAL_CFG);
@@ -272,7 +365,7 @@ void geni_se_init(struct geni_se *se, u32 rx_wm, u32 rx_rfr)
val |= S_COMMON_GENI_S_IRQ_EN;
writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN);
}
-EXPORT_SYMBOL(geni_se_init);
+EXPORT_SYMBOL_GPL(geni_se_init);
static void geni_se_select_fifo_mode(struct geni_se *se)
{
@@ -281,27 +374,14 @@ static void geni_se_select_fifo_mode(struct geni_se *se)
geni_se_irq_clear(se);
- /*
- * The RX path for the UART is asynchronous and so needs more
- * complex logic for enabling / disabling its interrupts.
- *
- * Specific notes:
- * - The done and TX-related interrupts are managed manually.
- * - We don't RX from the main sequencer (we use the secondary) so
- * we don't need the RX-related interrupts enabled in the main
- * sequencer for UART.
- */
+ /* UART driver manages enabling / disabling interrupts internally */
if (proto != GENI_SE_UART) {
+ /* Non-UART use only primary sequencer so dont bother about S_IRQ */
val_old = val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN);
val |= M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN;
val |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN;
if (val != val_old)
writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN);
-
- val_old = val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN);
- val |= S_CMD_DONE_EN;
- if (val != val_old)
- writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN);
}
val_old = val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
@@ -317,17 +397,14 @@ static void geni_se_select_dma_mode(struct geni_se *se)
geni_se_irq_clear(se);
+ /* UART driver manages enabling / disabling interrupts internally */
if (proto != GENI_SE_UART) {
+ /* Non-UART use only primary sequencer so dont bother about S_IRQ */
val_old = val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN);
val &= ~(M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN);
val &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN);
if (val != val_old)
writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN);
-
- val_old = val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN);
- val &= ~S_CMD_DONE_EN;
- if (val != val_old)
- writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN);
}
val_old = val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
@@ -344,10 +421,6 @@ static void geni_se_select_gpi_mode(struct geni_se *se)
writel(0, se->base + SE_IRQ_EN);
- val = readl(se->base + SE_GENI_S_IRQ_EN);
- val &= ~S_CMD_DONE_EN;
- writel(val, se->base + SE_GENI_S_IRQ_EN);
-
val = readl(se->base + SE_GENI_M_IRQ_EN);
val &= ~(M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN |
M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN);
@@ -384,7 +457,7 @@ void geni_se_select_mode(struct geni_se *se, enum geni_se_xfer_mode mode)
break;
}
}
-EXPORT_SYMBOL(geni_se_select_mode);
+EXPORT_SYMBOL_GPL(geni_se_select_mode);
/**
* DOC: Overview
@@ -501,7 +574,7 @@ void geni_se_config_packing(struct geni_se *se, int bpw, int pack_words,
if (pack_words || bpw == 32)
writel_relaxed(bpw / 16, se->base + SE_GENI_BYTE_GRAN);
}
-EXPORT_SYMBOL(geni_se_config_packing);
+EXPORT_SYMBOL_GPL(geni_se_config_packing);
static void geni_se_clks_off(struct geni_se *se)
{
@@ -532,7 +605,7 @@ int geni_se_resources_off(struct geni_se *se)
geni_se_clks_off(se);
return 0;
}
-EXPORT_SYMBOL(geni_se_resources_off);
+EXPORT_SYMBOL_GPL(geni_se_resources_off);
static int geni_se_clks_on(struct geni_se *se)
{
@@ -573,7 +646,7 @@ int geni_se_resources_on(struct geni_se *se)
return ret;
}
-EXPORT_SYMBOL(geni_se_resources_on);
+EXPORT_SYMBOL_GPL(geni_se_resources_on);
/**
* geni_se_clk_tbl_get() - Get the clock table to program DFS
@@ -606,7 +679,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;
}
@@ -614,7 +688,7 @@ int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl)
*tbl = se->clk_perf_tbl;
return se->num_clk_levels;
}
-EXPORT_SYMBOL(geni_se_clk_tbl_get);
+EXPORT_SYMBOL_GPL(geni_se_clk_tbl_get);
/**
* geni_se_clk_freq_match() - Get the matching or closest SE clock frequency
@@ -676,12 +750,39 @@ int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq,
return 0;
}
-EXPORT_SYMBOL(geni_se_clk_freq_match);
+EXPORT_SYMBOL_GPL(geni_se_clk_freq_match);
+
+#define GENI_SE_DMA_DONE_EN BIT(0)
+#define GENI_SE_DMA_EOT_EN BIT(1)
+#define GENI_SE_DMA_AHB_ERR_EN BIT(2)
+#define GENI_SE_DMA_RESET_DONE_EN BIT(3)
+#define GENI_SE_DMA_FLUSH_DONE BIT(4)
-#define GENI_SE_DMA_DONE_EN BIT(0)
-#define GENI_SE_DMA_EOT_EN BIT(1)
-#define GENI_SE_DMA_AHB_ERR_EN BIT(2)
#define GENI_SE_DMA_EOT_BUF BIT(0)
+
+/**
+ * geni_se_tx_init_dma() - Initiate TX DMA transfer on the serial engine
+ * @se: Pointer to the concerned serial engine.
+ * @iova: Mapped DMA address.
+ * @len: Length of the TX buffer.
+ *
+ * This function is used to initiate DMA TX transfer.
+ */
+void geni_se_tx_init_dma(struct geni_se *se, dma_addr_t iova, size_t len)
+{
+ u32 val;
+
+ val = GENI_SE_DMA_DONE_EN;
+ val |= GENI_SE_DMA_EOT_EN;
+ val |= GENI_SE_DMA_AHB_ERR_EN;
+ writel_relaxed(val, se->base + SE_DMA_TX_IRQ_EN_SET);
+ writel_relaxed(lower_32_bits(iova), se->base + SE_DMA_TX_PTR_L);
+ writel_relaxed(upper_32_bits(iova), se->base + SE_DMA_TX_PTR_H);
+ writel_relaxed(GENI_SE_DMA_EOT_BUF, se->base + SE_DMA_TX_ATTR);
+ writel(len, se->base + SE_DMA_TX_LEN);
+}
+EXPORT_SYMBOL_GPL(geni_se_tx_init_dma);
+
/**
* geni_se_tx_dma_prep() - Prepare the serial engine for TX DMA transfer
* @se: Pointer to the concerned serial engine.
@@ -697,7 +798,6 @@ int geni_se_tx_dma_prep(struct geni_se *se, void *buf, size_t len,
dma_addr_t *iova)
{
struct geni_wrapper *wrapper = se->wrapper;
- u32 val;
if (!wrapper)
return -EINVAL;
@@ -706,17 +806,34 @@ int geni_se_tx_dma_prep(struct geni_se *se, void *buf, size_t len,
if (dma_mapping_error(wrapper->dev, *iova))
return -EIO;
+ geni_se_tx_init_dma(se, *iova, len);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(geni_se_tx_dma_prep);
+
+/**
+ * geni_se_rx_init_dma() - Initiate RX DMA transfer on the serial engine
+ * @se: Pointer to the concerned serial engine.
+ * @iova: Mapped DMA address.
+ * @len: Length of the RX buffer.
+ *
+ * This function is used to initiate DMA RX transfer.
+ */
+void geni_se_rx_init_dma(struct geni_se *se, dma_addr_t iova, size_t len)
+{
+ u32 val;
+
val = GENI_SE_DMA_DONE_EN;
val |= GENI_SE_DMA_EOT_EN;
val |= GENI_SE_DMA_AHB_ERR_EN;
- writel_relaxed(val, se->base + SE_DMA_TX_IRQ_EN_SET);
- writel_relaxed(lower_32_bits(*iova), se->base + SE_DMA_TX_PTR_L);
- writel_relaxed(upper_32_bits(*iova), se->base + SE_DMA_TX_PTR_H);
- writel_relaxed(GENI_SE_DMA_EOT_BUF, se->base + SE_DMA_TX_ATTR);
- writel(len, se->base + SE_DMA_TX_LEN);
- return 0;
+ writel_relaxed(val, se->base + SE_DMA_RX_IRQ_EN_SET);
+ writel_relaxed(lower_32_bits(iova), se->base + SE_DMA_RX_PTR_L);
+ writel_relaxed(upper_32_bits(iova), se->base + SE_DMA_RX_PTR_H);
+ /* RX does not have EOT buffer type bit. So just reset RX_ATTR */
+ writel_relaxed(0, se->base + SE_DMA_RX_ATTR);
+ writel(len, se->base + SE_DMA_RX_LEN);
}
-EXPORT_SYMBOL(geni_se_tx_dma_prep);
+EXPORT_SYMBOL_GPL(geni_se_rx_init_dma);
/**
* geni_se_rx_dma_prep() - Prepare the serial engine for RX DMA transfer
@@ -733,7 +850,6 @@ int geni_se_rx_dma_prep(struct geni_se *se, void *buf, size_t len,
dma_addr_t *iova)
{
struct geni_wrapper *wrapper = se->wrapper;
- u32 val;
if (!wrapper)
return -EINVAL;
@@ -742,18 +858,10 @@ int geni_se_rx_dma_prep(struct geni_se *se, void *buf, size_t len,
if (dma_mapping_error(wrapper->dev, *iova))
return -EIO;
- val = GENI_SE_DMA_DONE_EN;
- val |= GENI_SE_DMA_EOT_EN;
- val |= GENI_SE_DMA_AHB_ERR_EN;
- writel_relaxed(val, se->base + SE_DMA_RX_IRQ_EN_SET);
- writel_relaxed(lower_32_bits(*iova), se->base + SE_DMA_RX_PTR_L);
- writel_relaxed(upper_32_bits(*iova), se->base + SE_DMA_RX_PTR_H);
- /* RX does not have EOT buffer type bit. So just reset RX_ATTR */
- writel_relaxed(0, se->base + SE_DMA_RX_ATTR);
- writel(len, se->base + SE_DMA_RX_LEN);
+ geni_se_rx_init_dma(se, *iova, len);
return 0;
}
-EXPORT_SYMBOL(geni_se_rx_dma_prep);
+EXPORT_SYMBOL_GPL(geni_se_rx_dma_prep);
/**
* geni_se_tx_dma_unprep() - Unprepare the serial engine after TX DMA transfer
@@ -770,7 +878,7 @@ void geni_se_tx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len)
if (!dma_mapping_error(wrapper->dev, iova))
dma_unmap_single(wrapper->dev, iova, len, DMA_TO_DEVICE);
}
-EXPORT_SYMBOL(geni_se_tx_dma_unprep);
+EXPORT_SYMBOL_GPL(geni_se_tx_dma_unprep);
/**
* geni_se_rx_dma_unprep() - Unprepare the serial engine after RX DMA transfer
@@ -787,7 +895,7 @@ void geni_se_rx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len)
if (!dma_mapping_error(wrapper->dev, iova))
dma_unmap_single(wrapper->dev, iova, len, DMA_FROM_DEVICE);
}
-EXPORT_SYMBOL(geni_se_rx_dma_unprep);
+EXPORT_SYMBOL_GPL(geni_se_rx_dma_unprep);
int geni_icc_get(struct geni_se *se, const char *icc_ddr)
{
@@ -816,7 +924,7 @@ err:
return err;
}
-EXPORT_SYMBOL(geni_icc_get);
+EXPORT_SYMBOL_GPL(geni_icc_get);
int geni_icc_set_bw(struct geni_se *se)
{
@@ -834,7 +942,7 @@ int geni_icc_set_bw(struct geni_se *se)
return 0;
}
-EXPORT_SYMBOL(geni_icc_set_bw);
+EXPORT_SYMBOL_GPL(geni_icc_set_bw);
void geni_icc_set_tag(struct geni_se *se, u32 tag)
{
@@ -843,7 +951,7 @@ void geni_icc_set_tag(struct geni_se *se, u32 tag)
for (i = 0; i < ARRAY_SIZE(se->icc_paths); i++)
icc_set_tag(se->icc_paths[i].path, tag);
}
-EXPORT_SYMBOL(geni_icc_set_tag);
+EXPORT_SYMBOL_GPL(geni_icc_set_tag);
/* To do: Replace this by icc_bulk_enable once it's implemented in ICC core */
int geni_icc_enable(struct geni_se *se)
@@ -861,7 +969,7 @@ int geni_icc_enable(struct geni_se *se)
return 0;
}
-EXPORT_SYMBOL(geni_icc_enable);
+EXPORT_SYMBOL_GPL(geni_icc_enable);
int geni_icc_disable(struct geni_se *se)
{
@@ -878,12 +986,384 @@ int geni_icc_disable(struct geni_se *se)
return 0;
}
-EXPORT_SYMBOL(geni_icc_disable);
+EXPORT_SYMBOL_GPL(geni_icc_disable);
+
+/**
+ * geni_find_protocol_fw() - Locate and validate SE firmware for a protocol.
+ * @dev: Pointer to the device structure.
+ * @fw: Pointer to the firmware image.
+ * @protocol: Expected serial engine protocol type.
+ *
+ * Identifies the appropriate firmware image or configuration required for a
+ * specific communication protocol instance running on a Qualcomm GENI
+ * controller.
+ *
+ * Return: pointer to a valid 'struct se_fw_hdr' if found, or NULL otherwise.
+ */
+static struct se_fw_hdr *geni_find_protocol_fw(struct device *dev, const struct firmware *fw,
+ enum geni_se_protocol_type protocol)
+{
+ const struct elf32_hdr *ehdr;
+ const struct elf32_phdr *phdrs;
+ const struct elf32_phdr *phdr;
+ struct se_fw_hdr *sefw;
+ u32 fw_end, cfg_idx_end, cfg_val_end;
+ u16 fw_size;
+ int i;
+
+ if (!fw || fw->size < sizeof(struct elf32_hdr))
+ return NULL;
+
+ ehdr = (const struct elf32_hdr *)fw->data;
+ phdrs = (const struct elf32_phdr *)(fw->data + ehdr->e_phoff);
+
+ /*
+ * The firmware is expected to have at least two program headers (segments).
+ * One for metadata and the other for the actual protocol-specific firmware.
+ */
+ if (ehdr->e_phnum < 2) {
+ dev_err(dev, "Invalid firmware: less than 2 program headers\n");
+ return NULL;
+ }
+
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ phdr = &phdrs[i];
+
+ if (fw->size < phdr->p_offset + phdr->p_filesz) {
+ dev_err(dev, "Firmware size (%zu) < expected offset (%u) + size (%u)\n",
+ fw->size, phdr->p_offset, phdr->p_filesz);
+ return NULL;
+ }
+
+ if (phdr->p_type != PT_LOAD || !phdr->p_memsz)
+ continue;
+
+ if (MI_PBT_PAGE_MODE_VALUE(phdr->p_flags) != MI_PBT_NON_PAGED_SEGMENT ||
+ MI_PBT_SEGMENT_TYPE_VALUE(phdr->p_flags) == MI_PBT_HASH_SEGMENT ||
+ MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) == MI_PBT_NOTUSED_SEGMENT ||
+ MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) == MI_PBT_SHARED_SEGMENT)
+ continue;
+
+ if (phdr->p_filesz < sizeof(struct se_fw_hdr))
+ continue;
+
+ sefw = (struct se_fw_hdr *)(fw->data + phdr->p_offset);
+ fw_size = le16_to_cpu(sefw->fw_size_in_items);
+ fw_end = le16_to_cpu(sefw->fw_offset) + fw_size * sizeof(u32);
+ cfg_idx_end = le16_to_cpu(sefw->cfg_idx_offset) +
+ le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u8);
+ cfg_val_end = le16_to_cpu(sefw->cfg_val_offset) +
+ le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u32);
+
+ if (le32_to_cpu(sefw->magic) != SE_MAGIC_NUM || le32_to_cpu(sefw->version) != 1)
+ continue;
+
+ if (le32_to_cpu(sefw->serial_protocol) != protocol)
+ continue;
+
+ if (fw_size % 2 != 0) {
+ fw_size++;
+ sefw->fw_size_in_items = cpu_to_le16(fw_size);
+ }
+
+ if (fw_size >= MAX_GENI_CFG_RAMn_CNT) {
+ dev_err(dev,
+ "Firmware size (%u) exceeds max allowed RAMn count (%u)\n",
+ fw_size, MAX_GENI_CFG_RAMn_CNT);
+ continue;
+ }
+
+ if (fw_end > phdr->p_filesz || cfg_idx_end > phdr->p_filesz ||
+ cfg_val_end > phdr->p_filesz) {
+ dev_err(dev, "Truncated or corrupt SE FW segment found at index %d\n", i);
+ continue;
+ }
+
+ return sefw;
+ }
+
+ dev_err(dev, "Failed to get %s protocol firmware\n", protocol_name[protocol]);
+ return NULL;
+}
+
+/**
+ * geni_configure_xfer_mode() - Set the transfer mode.
+ * @se: Pointer to the concerned serial engine.
+ * @mode: SE data transfer mode.
+ *
+ * Set the transfer mode to either FIFO or DMA according to the mode specified
+ * by the protocol driver.
+ *
+ * Return: 0 if successful, otherwise return an error value.
+ */
+static int geni_configure_xfer_mode(struct geni_se *se, enum geni_se_xfer_mode mode)
+{
+ /* Configure SE FIFO, DMA or GSI mode. */
+ switch (mode) {
+ case GENI_GPI_DMA:
+ geni_setbits32(se->base + SE_GENI_DMA_MODE_EN, GENI_DMA_MODE_EN);
+ writel(0x0, se->base + SE_IRQ_EN);
+ writel(DMA_RX_EVENT_EN | DMA_TX_EVENT_EN | GENI_M_EVENT_EN | GENI_S_EVENT_EN,
+ se->base + SE_GSI_EVENT_EN);
+ break;
+
+ case GENI_SE_FIFO:
+ geni_clrbits32(se->base + SE_GENI_DMA_MODE_EN, GENI_DMA_MODE_EN);
+ writel(DMA_RX_IRQ_EN | DMA_TX_IRQ_EN | GENI_M_IRQ_EN | GENI_S_IRQ_EN,
+ se->base + SE_IRQ_EN);
+ writel(0x0, se->base + SE_GSI_EVENT_EN);
+ break;
+
+ case GENI_SE_DMA:
+ geni_setbits32(se->base + SE_GENI_DMA_MODE_EN, GENI_DMA_MODE_EN);
+ writel(DMA_RX_IRQ_EN | DMA_TX_IRQ_EN | GENI_M_IRQ_EN | GENI_S_IRQ_EN,
+ se->base + SE_IRQ_EN);
+ writel(0x0, se->base + SE_GSI_EVENT_EN);
+ break;
+
+ default:
+ dev_err(se->dev, "Invalid geni-se transfer mode: %d\n", mode);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * geni_enable_interrupts() - Enable interrupts.
+ * @se: Pointer to the concerned serial engine.
+ *
+ * Enable the required interrupts during the firmware load process.
+ */
+static void geni_enable_interrupts(struct geni_se *se)
+{
+ u32 val;
+
+ /* Enable required interrupts. */
+ writel(M_COMMON_GENI_M_IRQ_EN, se->base + SE_GENI_M_IRQ_EN);
+
+ val = S_CMD_OVERRUN_EN | S_ILLEGAL_CMD_EN | S_CMD_CANCEL_EN | S_CMD_ABORT_EN |
+ S_GP_IRQ_0_EN | S_GP_IRQ_1_EN | S_GP_IRQ_2_EN | S_GP_IRQ_3_EN |
+ S_RX_FIFO_WR_ERR_EN | S_RX_FIFO_RD_ERR_EN;
+ writel(val, se->base + SE_GENI_S_IRQ_ENABLE);
+
+ /* DMA mode configuration. */
+ val = GENI_SE_DMA_RESET_DONE_EN | GENI_SE_DMA_AHB_ERR_EN | GENI_SE_DMA_DONE_EN;
+ writel(val, se->base + SE_DMA_TX_IRQ_EN_SET);
+ val = GENI_SE_DMA_FLUSH_DONE | GENI_SE_DMA_RESET_DONE_EN | GENI_SE_DMA_AHB_ERR_EN |
+ GENI_SE_DMA_DONE_EN;
+ writel(val, se->base + SE_DMA_RX_IRQ_EN_SET);
+}
+
+/**
+ * geni_write_fw_revision() - Write the firmware revision.
+ * @se: Pointer to the concerned serial engine.
+ * @serial_protocol: serial protocol type.
+ * @fw_version: QUP firmware version.
+ *
+ * Write the firmware revision and protocol into the respective register.
+ */
+static void geni_write_fw_revision(struct geni_se *se, u16 serial_protocol, u16 fw_version)
+{
+ u32 reg;
+
+ reg = FIELD_PREP(FW_REV_PROTOCOL_MSK, serial_protocol);
+ reg |= FIELD_PREP(FW_REV_VERSION_MSK, fw_version);
+
+ writel(reg, se->base + SE_GENI_FW_REVISION);
+ writel(reg, se->base + SE_GENI_S_FW_REVISION);
+}
+
+/**
+ * geni_load_se_fw() - Load Serial Engine specific firmware.
+ * @se: Pointer to the concerned serial engine.
+ * @fw: Pointer to the firmware structure.
+ * @mode: SE data transfer mode.
+ * @protocol: Protocol type to be used with the SE (e.g., UART, SPI, I2C).
+ *
+ * Load the protocol firmware into the IRAM of the Serial Engine.
+ *
+ * Return: 0 if successful, otherwise return an error value.
+ */
+static int geni_load_se_fw(struct geni_se *se, const struct firmware *fw,
+ enum geni_se_xfer_mode mode, enum geni_se_protocol_type protocol)
+{
+ const u32 *fw_data, *cfg_val_arr;
+ const u8 *cfg_idx_arr;
+ u32 i, reg_value;
+ int ret;
+ struct se_fw_hdr *hdr;
+
+ hdr = geni_find_protocol_fw(se->dev, fw, protocol);
+ if (!hdr)
+ return -EINVAL;
+
+ fw_data = (const u32 *)((u8 *)hdr + le16_to_cpu(hdr->fw_offset));
+ cfg_idx_arr = (const u8 *)hdr + le16_to_cpu(hdr->cfg_idx_offset);
+ cfg_val_arr = (const u32 *)((u8 *)hdr + le16_to_cpu(hdr->cfg_val_offset));
+
+ ret = geni_icc_set_bw(se);
+ if (ret)
+ return ret;
+
+ ret = geni_icc_enable(se);
+ if (ret)
+ return ret;
+
+ ret = geni_se_resources_on(se);
+ if (ret)
+ goto out_icc_disable;
+
+ /*
+ * Disable high-priority interrupts until all currently executing
+ * low-priority interrupts have been fully handled.
+ */
+ geni_setbits32(se->wrapper->base + QUPV3_COMMON_CFG, FAST_SWITCH_TO_HIGH_DISABLE);
+
+ /* Set AHB_M_CLK_CGC_ON to indicate hardware controls se-wrapper cgc clock. */
+ geni_setbits32(se->wrapper->base + QUPV3_SE_AHB_M_CFG, AHB_M_CLK_CGC_ON);
+
+ /* Let hardware to control common cgc. */
+ geni_setbits32(se->wrapper->base + QUPV3_COMMON_CGC_CTRL, COMMON_CSR_SLV_CLK_CGC_ON);
+
+ /*
+ * Setting individual bits in GENI_OUTPUT_CTRL activates corresponding output lines,
+ * allowing the hardware to drive data as configured.
+ */
+ writel(0x0, se->base + GENI_OUTPUT_CTRL);
+
+ /* Set SCLK and HCLK to program RAM */
+ geni_setbits32(se->base + SE_GENI_CGC_CTRL, PROG_RAM_SCLK_OFF | PROG_RAM_HCLK_OFF);
+ writel(0x0, se->base + SE_GENI_CLK_CTRL);
+ geni_clrbits32(se->base + SE_GENI_CGC_CTRL, PROG_RAM_SCLK_OFF | PROG_RAM_HCLK_OFF);
+
+ /* Enable required clocks for DMA CSR, TX and RX. */
+ reg_value = AHB_SEC_SLV_CLK_CGC_ON | DMA_AHB_SLV_CLK_CGC_ON |
+ DMA_TX_CLK_CGC_ON | DMA_RX_CLK_CGC_ON;
+ geni_setbits32(se->base + SE_DMA_GENERAL_CFG, reg_value);
+
+ /* Let hardware control CGC by default. */
+ writel(DEFAULT_CGC_EN, se->base + SE_GENI_CGC_CTRL);
+
+ /* Set version of the configuration register part of firmware. */
+ writel(le16_to_cpu(hdr->cfg_version), se->base + SE_GENI_INIT_CFG_REVISION);
+ writel(le16_to_cpu(hdr->cfg_version), se->base + SE_GENI_S_INIT_CFG_REVISION);
+
+ /* Configure GENI primitive table. */
+ for (i = 0; i < le16_to_cpu(hdr->cfg_size_in_items); i++)
+ writel(cfg_val_arr[i],
+ se->base + SE_GENI_CFG_REG0 + (cfg_idx_arr[i] * sizeof(u32)));
+
+ /* Configure condition for assertion of RX_RFR_WATERMARK condition. */
+ reg_value = geni_se_get_rx_fifo_depth(se);
+ writel(reg_value - 2, se->base + SE_GENI_RX_RFR_WATERMARK_REG);
+
+ /* Let hardware control CGC */
+ geni_setbits32(se->base + GENI_OUTPUT_CTRL, DEFAULT_IO_OUTPUT_CTRL_MSK);
+
+ ret = geni_configure_xfer_mode(se, mode);
+ if (ret)
+ goto out_resources_off;
+
+ geni_enable_interrupts(se);
+
+ geni_write_fw_revision(se, le16_to_cpu(hdr->serial_protocol), le16_to_cpu(hdr->fw_version));
+
+ /* Program RAM address space. */
+ memcpy_toio(se->base + SE_GENI_CFG_RAMN, fw_data,
+ le16_to_cpu(hdr->fw_size_in_items) * sizeof(u32));
+
+ /* Put default values on GENI's output pads. */
+ writel_relaxed(0x1, se->base + GENI_FORCE_DEFAULT_REG);
+
+ /* Toggle SCLK/HCLK from high to low to finalize RAM programming and apply config. */
+ geni_setbits32(se->base + SE_GENI_CGC_CTRL, PROG_RAM_SCLK_OFF | PROG_RAM_HCLK_OFF);
+ geni_setbits32(se->base + SE_GENI_CLK_CTRL, SER_CLK_SEL);
+ geni_clrbits32(se->base + SE_GENI_CGC_CTRL, PROG_RAM_SCLK_OFF | PROG_RAM_HCLK_OFF);
+
+ /* Serial engine DMA interface is enabled. */
+ geni_setbits32(se->base + SE_DMA_IF_EN, DMA_IF_EN);
+
+ /* Enable or disable FIFO interface of the serial engine. */
+ if (mode == GENI_SE_FIFO)
+ geni_clrbits32(se->base + SE_FIFO_IF_DISABLE, FIFO_IF_DISABLE);
+ else
+ geni_setbits32(se->base + SE_FIFO_IF_DISABLE, FIFO_IF_DISABLE);
+
+out_resources_off:
+ geni_se_resources_off(se);
+
+out_icc_disable:
+ geni_icc_disable(se);
+ return ret;
+}
+
+/**
+ * geni_load_se_firmware() - Load firmware for SE based on protocol
+ * @se: Pointer to the concerned serial engine.
+ * @protocol: Protocol type to be used with the SE (e.g., UART, SPI, I2C).
+ *
+ * Retrieves the firmware name from device properties and sets the transfer mode
+ * (FIFO or GSI DMA) based on device tree configuration. Enforces FIFO mode for
+ * UART protocol due to lack of GSI DMA support. Requests the firmware and loads
+ * it into the SE.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int geni_load_se_firmware(struct geni_se *se, enum geni_se_protocol_type protocol)
+{
+ const char *fw_name;
+ const struct firmware *fw;
+ enum geni_se_xfer_mode mode = GENI_SE_FIFO;
+ int ret;
+
+ if (protocol >= ARRAY_SIZE(protocol_name)) {
+ dev_err(se->dev, "Invalid geni-se protocol: %d", protocol);
+ return -EINVAL;
+ }
+
+ ret = device_property_read_string(se->wrapper->dev, "firmware-name", &fw_name);
+ if (ret) {
+ dev_err(se->dev, "Failed to read firmware-name property: %d\n", ret);
+ return -EINVAL;
+ }
+
+ if (of_property_read_bool(se->dev->of_node, "qcom,enable-gsi-dma"))
+ mode = GENI_GPI_DMA;
+
+ /* GSI mode is not supported by the UART driver; therefore, setting FIFO mode */
+ if (protocol == GENI_SE_UART)
+ mode = GENI_SE_FIFO;
+
+ ret = request_firmware(&fw, fw_name, se->dev);
+ if (ret) {
+ if (ret == -ENOENT)
+ return -EPROBE_DEFER;
+
+ dev_err(se->dev, "Failed to request firmware '%s' for protocol %d: ret: %d\n",
+ fw_name, protocol, ret);
+ return ret;
+ }
+
+ ret = geni_load_se_fw(se, fw, mode, protocol);
+ release_firmware(fw);
+
+ if (ret) {
+ dev_err(se->dev, "Failed to load SE firmware for protocol %d: ret: %d\n",
+ protocol, ret);
+ return ret;
+ }
+
+ dev_dbg(se->dev, "Firmware load for %s protocol is successful for xfer mode: %d\n",
+ protocol_name[protocol], mode);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(geni_load_se_firmware);
static int geni_se_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct geni_wrapper *wrapper;
+ const struct geni_se_desc *desc;
int ret;
wrapper = devm_kzalloc(dev, sizeof(*wrapper), GFP_KERNEL);
@@ -895,13 +1375,10 @@ static int geni_se_probe(struct platform_device *pdev)
if (IS_ERR(wrapper->base))
return PTR_ERR(wrapper->base);
- if (!has_acpi_companion(&pdev->dev)) {
- const struct geni_se_desc *desc;
- int i;
+ desc = device_get_match_data(&pdev->dev);
- desc = device_get_match_data(&pdev->dev);
- if (!desc)
- return -EINVAL;
+ if (!has_acpi_companion(&pdev->dev) && desc->num_clks) {
+ int i;
wrapper->num_clks = min_t(unsigned int, desc->num_clks, MAX_CLKS);
@@ -942,6 +1419,8 @@ static const struct geni_se_desc qup_desc = {
.num_clks = ARRAY_SIZE(qup_clks),
};
+static const struct geni_se_desc sa8255p_qup_desc = {};
+
static const char * const i2c_master_hub_clks[] = {
"s-ahb",
};
@@ -954,6 +1433,7 @@ static const struct geni_se_desc i2c_master_hub_desc = {
static const struct of_device_id geni_se_dt_match[] = {
{ .compatible = "qcom,geni-se-qup", .data = &qup_desc },
{ .compatible = "qcom,geni-se-i2c-master-hub", .data = &i2c_master_hub_desc },
+ { .compatible = "qcom,sa8255p-geni-se-qup", .data = &sa8255p_qup_desc },
{}
};
MODULE_DEVICE_TABLE(of, geni_se_dt_match);
diff --git a/drivers/soc/qcom/qcom-pbs.c b/drivers/soc/qcom/qcom-pbs.c
new file mode 100644
index 000000000000..06b4a596e275
--- /dev/null
+++ b/drivers/soc/qcom/qcom-pbs.c
@@ -0,0 +1,228 @@
+// 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);
+ }
+
+ platform_device_put(pdev);
+
+ 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 18c856056475..a543ab9bee6c 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>
@@ -11,8 +12,12 @@
#include <linux/platform_device.h>
#include <linux/thermal.h>
#include <linux/slab.h>
+#include <linux/string_choices.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 +49,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 +72,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 +91,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)
@@ -205,37 +216,44 @@ static bool qmp_message_empty(struct qmp *qmp)
/**
* qmp_send() - send a message to the AOSS
* @qmp: qmp context
- * @data: message to be sent
- * @len: length of the message
+ * @fmt: format string for message to be sent
+ * @...: arguments for the format string
*
- * Transmit @data to AOSS and wait for the AOSS to acknowledge the message.
- * @len must be a multiple of 4 and not longer than the mailbox size. Access is
- * synchronized by this implementation.
+ * Transmit message to AOSS and wait for the AOSS to acknowledge the message.
+ * data must not be longer than the mailbox size. Access is synchronized by
+ * this implementation.
*
* Return: 0 on success, negative errno on failure
*/
-int qmp_send(struct qmp *qmp, const void *data, size_t len)
+int __printf(2, 3) qmp_send(struct qmp *qmp, const char *fmt, ...)
{
+ char buf[QMP_MSG_LEN];
long time_left;
+ va_list args;
+ int len;
int ret;
- if (WARN_ON(IS_ERR_OR_NULL(qmp) || !data))
+ if (WARN_ON(IS_ERR_OR_NULL(qmp) || !fmt))
return -EINVAL;
- if (WARN_ON(len + sizeof(u32) > qmp->size))
- return -EINVAL;
+ memset(buf, 0, sizeof(buf));
+ va_start(args, fmt);
+ len = vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
- if (WARN_ON(len % sizeof(u32)))
+ if (WARN_ON(len >= sizeof(buf)))
return -EINVAL;
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),
- data, len / sizeof(u32));
- writel(len, qmp->msgram + qmp->offset);
+ buf, sizeof(buf) / sizeof(u32));
+ writel(sizeof(buf), qmp->msgram + qmp->offset);
- /* Read back len to confirm data written in message RAM */
+ /* Read back length to confirm data written in message RAM */
readl(qmp->msgram + qmp->offset);
qmp_kick(qmp);
@@ -251,26 +269,28 @@ int qmp_send(struct qmp *qmp, const void *data, size_t len)
ret = 0;
}
+ trace_aoss_send_done(buf, ret);
+
mutex_unlock(&qmp->tx_lock);
return ret;
}
-EXPORT_SYMBOL(qmp_send);
+EXPORT_SYMBOL_GPL(qmp_send);
static int qmp_qdss_clk_prepare(struct clk_hw *hw)
{
- static const char buf[QMP_MSG_LEN] = "{class: clock, res: qdss, val: 1}";
+ static const char *buf = "{class: clock, res: qdss, val: 1}";
struct qmp *qmp = container_of(hw, struct qmp, qdss_clk);
- return qmp_send(qmp, buf, sizeof(buf));
+ return qmp_send(qmp, buf);
}
static void qmp_qdss_clk_unprepare(struct clk_hw *hw)
{
- static const char buf[QMP_MSG_LEN] = "{class: clock, res: qdss, val: 0}";
+ static const char *buf = "{class: clock, res: qdss, val: 0}";
struct qmp *qmp = container_of(hw, struct qmp, qdss_clk);
- qmp_send(qmp, buf, sizeof(buf));
+ qmp_send(qmp, buf);
}
static const struct clk_ops qmp_qdss_clk_ops = {
@@ -329,7 +349,6 @@ static int qmp_cdev_set_cur_state(struct thermal_cooling_device *cdev,
unsigned long state)
{
struct qmp_cooling_device *qmp_cdev = cdev->devdata;
- char buf[QMP_MSG_LEN] = {};
bool cdev_state;
int ret;
@@ -339,13 +358,8 @@ static int qmp_cdev_set_cur_state(struct thermal_cooling_device *cdev,
if (qmp_cdev->state == state)
return 0;
- snprintf(buf, sizeof(buf),
- "{class: volt_flr, event:zero_temp, res:%s, value:%s}",
- qmp_cdev->name,
- cdev_state ? "on" : "off");
-
- ret = qmp_send(qmp_cdev->qmp, buf, sizeof(buf));
-
+ ret = qmp_send(qmp_cdev->qmp, "{class: volt_flr, event:zero_temp, res:%s, value:%s}",
+ qmp_cdev->name, str_on_off(cdev_state));
if (!ret)
qmp_cdev->state = cdev_state;
@@ -381,7 +395,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;
@@ -394,15 +408,13 @@ static int qmp_cooling_devices_register(struct qmp *qmp)
if (!qmp->cooling_devs)
return -ENOMEM;
- for_each_available_child_of_node(np, child) {
- if (!of_find_property(child, "#cooling-cells", NULL))
+ 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)
@@ -459,7 +471,7 @@ struct qmp *qmp_get(struct device *dev)
}
return qmp;
}
-EXPORT_SYMBOL(qmp_get);
+EXPORT_SYMBOL_GPL(qmp_get);
/**
* qmp_put() - release a qmp handle
@@ -474,7 +486,92 @@ void qmp_put(struct qmp *qmp)
if (!IS_ERR_OR_NULL(qmp))
put_device(qmp->dev);
}
-EXPORT_SYMBOL(qmp_put);
+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)
{
@@ -524,6 +621,8 @@ static int qmp_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, qmp);
+ qmp_debugfs_create(qmp);
+
return 0;
err_close_qmp:
@@ -534,17 +633,17 @@ err_free_mbox:
return ret;
}
-static int qmp_remove(struct platform_device *pdev)
+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);
qmp_close(qmp);
mbox_free_channel(qmp->mbox_chan);
-
- return 0;
}
static const struct of_device_id qmp_dt_match[] = {
@@ -566,7 +665,7 @@ static struct platform_driver qmp_driver = {
.suppress_bind_attrs = true,
},
.probe = qmp_probe,
- .remove = 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 290bdefbf28a..a25d1de592f0 100644
--- a/drivers/soc/qcom/qcom_gsbi.c
+++ b/drivers/soc/qcom/qcom_gsbi.c
@@ -114,7 +114,7 @@ struct gsbi_info {
struct regmap *tcsr;
};
-static const struct of_device_id tcsr_dt_match[] = {
+static const struct of_device_id tcsr_dt_match[] __maybe_unused = {
{ .compatible = "qcom,tcsr-ipq8064", .data = &config_ipq8064},
{ .compatible = "qcom,tcsr-apq8064", .data = &config_apq8064},
{ .compatible = "qcom,tcsr-msm8960", .data = &config_msm8960},
@@ -129,7 +129,7 @@ static int gsbi_probe(struct platform_device *pdev)
const struct of_device_id *match;
void __iomem *base;
struct gsbi_info *gsbi;
- int i, ret;
+ int i;
u32 mask, gsbi_num;
const struct crci_config *config = NULL;
@@ -178,12 +178,10 @@ static int gsbi_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "GSBI port protocol: %d crci: %d\n",
gsbi->mode, gsbi->crci);
- gsbi->hclk = devm_clk_get(&pdev->dev, "iface");
+ gsbi->hclk = devm_clk_get_enabled(&pdev->dev, "iface");
if (IS_ERR(gsbi->hclk))
return PTR_ERR(gsbi->hclk);
- clk_prepare_enable(gsbi->hclk);
-
writel_relaxed((gsbi->mode << GSBI_PROTOCOL_SHIFT) | gsbi->crci,
base + GSBI_CTRL_REG);
@@ -211,19 +209,7 @@ static int gsbi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, gsbi);
- ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
- if (ret)
- clk_disable_unprepare(gsbi->hclk);
- return ret;
-}
-
-static int gsbi_remove(struct platform_device *pdev)
-{
- struct gsbi_info *gsbi = platform_get_drvdata(pdev);
-
- clk_disable_unprepare(gsbi->hclk);
-
- return 0;
+ return of_platform_populate(node, NULL, NULL, &pdev->dev);
}
static const struct of_device_id gsbi_dt_match[] = {
@@ -239,7 +225,6 @@ static struct platform_driver gsbi_driver = {
.of_match_table = gsbi_dt_match,
},
.probe = gsbi_probe,
- .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..1bcbe69688d2
--- /dev/null
+++ b/drivers/soc/qcom/qcom_pd_mapper.c
@@ -0,0 +1,731 @@
+// 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 *kaanapali_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd,
+ &adsp_sensor_pd,
+ &cdsp_root_pd,
+ &mpss_root_pd_gps,
+ 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,
+};
+
+/* Unlike SDM660, SDM630/636 lack CDSP */
+static const struct qcom_pdm_domain_data *sdm630_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd,
+ &adsp_sensor_pd,
+ &mpss_root_pd,
+ &mpss_wlan_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 *sm7150_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 *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,kaanapali", .data = kaanapali_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,sdm630", .data = sdm630_domains, },
+ { .compatible = "qcom,sdm636", .data = sdm630_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,sm7150", .data = sm7150_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,sm8750", .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..ca98932140d8
--- /dev/null
+++ b/drivers/soc/qcom/qcom_pdr_msg.c
@@ -0,0 +1,352 @@
+// 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"
+
+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),
+ },
+ {}
+};
+
+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 6228af057120..2e380faf9080 100644
--- a/drivers/soc/qcom/qcom_stats.c
+++ b/drivers/soc/qcom/qcom_stats.c
@@ -1,8 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2025, Qualcomm Innovation Center, Inc. All rights reserved.
*/
+#include <linux/bitfield.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/io.h>
@@ -11,6 +13,7 @@
#include <linux/platform_device.h>
#include <linux/seq_file.h>
+#include <linux/soc/qcom/qcom_aoss.h>
#include <linux/soc/qcom/smem.h>
#include <clocksource/arm_arch_timer.h>
@@ -24,6 +27,19 @@
#define ACCUMULATED_OFFSET 0x18
#define CLIENT_VOTES_OFFSET 0x20
+#define DDR_STATS_MAGIC_KEY 0xA1157A75
+#define DDR_STATS_MAX_NUM_MODES 20
+#define DDR_STATS_MAGIC_KEY_ADDR 0x0
+#define DDR_STATS_NUM_MODES_ADDR 0x4
+#define DDR_STATS_ENTRY_START_ADDR 0x8
+
+#define DDR_STATS_CP_IDX(data) FIELD_GET(GENMASK(4, 0), data)
+#define DDR_STATS_LPM_NAME(data) FIELD_GET(GENMASK(7, 0), data)
+#define DDR_STATS_TYPE(data) FIELD_GET(GENMASK(15, 8), data)
+#define DDR_STATS_FREQ(data) FIELD_GET(GENMASK(31, 16), data)
+
+static struct qmp *qcom_stats_qmp;
+
struct subsystem_data {
const char *name;
u32 smem_item;
@@ -35,21 +51,32 @@ 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 {
size_t stats_offset;
+ size_t ddr_stats_offset;
size_t num_records;
bool appended_stats_avail;
bool dynamic_offset;
bool subsystem_stats_in_smem;
};
+struct ddr_stats_entry {
+ u32 name;
+ u32 count;
+ u64 duration;
+};
+
struct stats_data {
bool appended_stats_avail;
void __iomem *base;
@@ -92,7 +119,7 @@ static int qcom_subsystem_sleep_stats_show(struct seq_file *s, void *unused)
/* Items are allocated lazily, so lookup pointer each time */
stat = qcom_smem_get(subsystem->pid, subsystem->smem_item, NULL);
if (IS_ERR(stat))
- return -EIO;
+ return 0;
qcom_print_stats(s, stat);
@@ -118,8 +145,101 @@ static int qcom_soc_sleep_stats_show(struct seq_file *s, void *unused)
return 0;
}
+static void qcom_ddr_stats_print(struct seq_file *s, struct ddr_stats_entry *data)
+{
+ u32 cp_idx;
+
+ /*
+ * DDR statistic have two different types of details encoded.
+ * (1) DDR LPM Stats
+ * (2) DDR Frequency Stats
+ *
+ * The name field have details like which type of DDR stat (bits 8:15)
+ * along with other details as explained below
+ *
+ * In case of DDR LPM stat, name field will be encoded as,
+ * Bits - Meaning
+ * 0:7 - DDR LPM name, can be of 0xd4, 0xd3, 0x11 and 0xd0.
+ * 8:15 - 0x0 (indicates its a LPM stat)
+ * 16:31 - Unused
+ *
+ * In case of DDR FREQ stats, name field will be encoded as,
+ * Bits - Meaning
+ * 0:4 - DDR Clock plan index (CP IDX)
+ * 5:7 - Unused
+ * 8:15 - 0x1 (indicates its Freq stat)
+ * 16:31 - Frequency value in Mhz
+ */
+ switch (DDR_STATS_TYPE(data->name)) {
+ case 0:
+ seq_printf(s, "DDR LPM Stat Name:0x%lx\tcount:%u\tDuration (ticks):%llu\n",
+ DDR_STATS_LPM_NAME(data->name), data->count, data->duration);
+ break;
+ case 1:
+ if (!data->count || !DDR_STATS_FREQ(data->name))
+ return;
+
+ cp_idx = DDR_STATS_CP_IDX(data->name);
+ seq_printf(s, "DDR Freq %luMhz:\tCP IDX:%u\tcount:%u\tDuration (ticks):%llu\n",
+ DDR_STATS_FREQ(data->name), cp_idx, data->count, data->duration);
+ break;
+ }
+}
+
+static int qcom_ddr_stats_show(struct seq_file *s, void *d)
+{
+ struct ddr_stats_entry data[DDR_STATS_MAX_NUM_MODES];
+ void __iomem *reg = (void __iomem *)s->private;
+ u32 entry_count;
+ int i, ret;
+
+ entry_count = readl_relaxed(reg + DDR_STATS_NUM_MODES_ADDR);
+ if (entry_count > DDR_STATS_MAX_NUM_MODES)
+ return -EINVAL;
+
+ if (qcom_stats_qmp) {
+ /*
+ * Recent SoCs (SM8450 onwards) do not have duration field
+ * populated from boot up onwards for both DDR LPM Stats
+ * and DDR Frequency Stats.
+ *
+ * Send QMP message to Always on processor which will
+ * populate duration field into MSG RAM area.
+ *
+ * Sent every time to read latest data.
+ */
+ ret = qmp_send(qcom_stats_qmp, "{class: ddr, action: freqsync}");
+ if (ret)
+ return ret;
+ }
+
+ reg += DDR_STATS_ENTRY_START_ADDR;
+ memcpy_fromio(data, reg, sizeof(struct ddr_stats_entry) * entry_count);
+
+ for (i = 0; i < entry_count; i++)
+ qcom_ddr_stats_print(s, &data[i]);
+
+ return 0;
+}
+
DEFINE_SHOW_ATTRIBUTE(qcom_soc_sleep_stats);
DEFINE_SHOW_ATTRIBUTE(qcom_subsystem_sleep_stats);
+DEFINE_SHOW_ATTRIBUTE(qcom_ddr_stats);
+
+static void qcom_create_ddr_stat_files(struct dentry *root, void __iomem *reg,
+ const struct stats_config *config)
+{
+ u32 key;
+
+ if (!config->ddr_stats_offset)
+ return;
+
+ key = readl_relaxed(reg + config->ddr_stats_offset + DDR_STATS_MAGIC_KEY_ADDR);
+ if (key == DDR_STATS_MAGIC_KEY)
+ debugfs_create_file("ddr_stats", 0400, root,
+ (__force void *)reg + config->ddr_stats_offset,
+ &qcom_ddr_stats_fops);
+}
static void qcom_create_soc_sleep_stat_files(struct dentry *root, void __iomem *reg,
struct stats_data *d,
@@ -170,20 +290,14 @@ static void qcom_create_soc_sleep_stat_files(struct dentry *root, void __iomem *
static void qcom_create_subsystem_stat_files(struct dentry *root,
const struct stats_config *config)
{
- const struct sleep_stats *stat;
int i;
if (!config->subsystem_stats_in_smem)
return;
- for (i = 0; i < ARRAY_SIZE(subsystems); i++) {
- stat = qcom_smem_get(subsystems[i].pid, subsystems[i].smem_item, NULL);
- if (IS_ERR(stat))
- continue;
-
+ for (i = 0; i < ARRAY_SIZE(subsystems); i++)
debugfs_create_file(subsystems[i].name, 0400, root, (void *)&subsystems[i],
&qcom_subsystem_sleep_stats_fops);
- }
}
static int qcom_stats_probe(struct platform_device *pdev)
@@ -209,11 +323,27 @@ static int qcom_stats_probe(struct platform_device *pdev)
for (i = 0; i < config->num_records; i++)
d[i].appended_stats_avail = config->appended_stats_avail;
+ /*
+ * QMP is used for DDR stats syncing to MSG RAM for recent SoCs (SM8450 onwards).
+ * The prior SoCs do not need QMP handle as the required stats are already present
+ * in MSG RAM, provided the DDR_STATS_MAGIC_KEY matches.
+ */
+ qcom_stats_qmp = qmp_get(&pdev->dev);
+ if (IS_ERR(qcom_stats_qmp)) {
+ /* We ignore error if QMP is not defined/needed */
+ if (!of_property_present(pdev->dev.of_node, "qcom,qmp"))
+ qcom_stats_qmp = NULL;
+ else if (PTR_ERR(qcom_stats_qmp) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ else
+ return PTR_ERR(qcom_stats_qmp);
+ }
root = debugfs_create_dir("qcom_stats", NULL);
qcom_create_subsystem_stat_files(root, config);
qcom_create_soc_sleep_stat_files(root, reg, d, config);
+ qcom_create_ddr_stat_files(root, reg, config);
platform_set_drvdata(pdev, root);
@@ -222,13 +352,11 @@ static int qcom_stats_probe(struct platform_device *pdev)
return 0;
}
-static int qcom_stats_remove(struct platform_device *pdev)
+static void qcom_stats_remove(struct platform_device *pdev)
{
struct dentry *root = platform_get_drvdata(pdev);
debugfs_remove_recursive(root);
-
- return 0;
}
static const struct stats_config rpm_data = {
@@ -258,6 +386,7 @@ static const struct stats_config rpmh_data_sdm845 = {
static const struct stats_config rpmh_data = {
.stats_offset = 0x48,
+ .ddr_stats_offset = 0xb8,
.num_records = 3,
.appended_stats_avail = false,
.dynamic_offset = false,
diff --git a/drivers/soc/qcom/qmi_encdec.c b/drivers/soc/qcom/qmi_encdec.c
index b7158e3c3a0b..7660a960fb45 100644
--- a/drivers/soc/qcom/qmi_encdec.c
+++ b/drivers/soc/qcom/qmi_encdec.c
@@ -304,6 +304,8 @@ static int qmi_encode(const struct qmi_elem_info *ei_array, void *out_buf,
const void *buf_src;
int encode_tlv = 0;
int rc;
+ u8 val8;
+ u16 val16;
if (!ei_array)
return 0;
@@ -338,7 +340,6 @@ static int qmi_encode(const struct qmi_elem_info *ei_array, void *out_buf,
break;
case QMI_DATA_LEN:
- memcpy(&data_len_value, buf_src, temp_ei->elem_size);
data_len_sz = temp_ei->elem_size == sizeof(u8) ?
sizeof(u8) : sizeof(u16);
/* Check to avoid out of range buffer access */
@@ -348,8 +349,17 @@ static int qmi_encode(const struct qmi_elem_info *ei_array, void *out_buf,
__func__);
return -ETOOSMALL;
}
- rc = qmi_encode_basic_elem(buf_dst, &data_len_value,
- 1, data_len_sz);
+ if (data_len_sz == sizeof(u8)) {
+ val8 = *(u8 *)buf_src;
+ data_len_value = (u32)val8;
+ rc = qmi_encode_basic_elem(buf_dst, &val8,
+ 1, data_len_sz);
+ } else {
+ val16 = *(u16 *)buf_src;
+ data_len_value = (u32)le16_to_cpu(val16);
+ rc = qmi_encode_basic_elem(buf_dst, &val16,
+ 1, data_len_sz);
+ }
UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
encoded_bytes, tlv_len,
encode_tlv, rc);
@@ -523,19 +533,28 @@ static int qmi_decode_string_elem(const struct qmi_elem_info *ei_array,
u32 string_len = 0;
u32 string_len_sz = 0;
const struct qmi_elem_info *temp_ei = ei_array;
+ u8 val8;
+ u16 val16;
if (dec_level == 1) {
string_len = tlv_len;
} else {
string_len_sz = temp_ei->elem_len <= U8_MAX ?
sizeof(u8) : sizeof(u16);
- rc = qmi_decode_basic_elem(&string_len, buf_src,
- 1, string_len_sz);
+ if (string_len_sz == sizeof(u8)) {
+ rc = qmi_decode_basic_elem(&val8, buf_src,
+ 1, string_len_sz);
+ string_len = (u32)val8;
+ } else {
+ rc = qmi_decode_basic_elem(&val16, buf_src,
+ 1, string_len_sz);
+ string_len = (u32)val16;
+ }
decoded_bytes += rc;
}
- if (string_len > temp_ei->elem_len) {
- pr_err("%s: String len %d > Max Len %d\n",
+ if (string_len >= temp_ei->elem_len) {
+ pr_err("%s: String len %d >= Max Len %d\n",
__func__, string_len, temp_ei->elem_len);
return -ETOOSMALL;
} else if (string_len > tlv_len) {
@@ -604,6 +623,9 @@ static int qmi_decode(const struct qmi_elem_info *ei_array, void *out_c_struct,
u32 decoded_bytes = 0;
const void *buf_src = in_buf;
int rc;
+ u8 val8;
+ u16 val16;
+ u32 val32;
while (decoded_bytes < in_buf_len) {
if (dec_level >= 2 && temp_ei->data_type == QMI_EOTI)
@@ -642,9 +664,17 @@ static int qmi_decode(const struct qmi_elem_info *ei_array, void *out_c_struct,
if (temp_ei->data_type == QMI_DATA_LEN) {
data_len_sz = temp_ei->elem_size == sizeof(u8) ?
sizeof(u8) : sizeof(u16);
- rc = qmi_decode_basic_elem(&data_len_value, buf_src,
- 1, data_len_sz);
- memcpy(buf_dst, &data_len_value, sizeof(u32));
+ if (data_len_sz == sizeof(u8)) {
+ rc = qmi_decode_basic_elem(&val8, buf_src,
+ 1, data_len_sz);
+ data_len_value = (u32)val8;
+ } else {
+ rc = qmi_decode_basic_elem(&val16, buf_src,
+ 1, data_len_sz);
+ data_len_value = (u32)val16;
+ }
+ val32 = cpu_to_le32(data_len_value);
+ memcpy(buf_dst, &val32, sizeof(u32));
temp_ei = temp_ei + 1;
buf_dst = out_c_struct + temp_ei->offset;
tlv_len -= data_len_sz;
@@ -746,15 +776,15 @@ void *qmi_encode_message(int type, unsigned int msg_id, size_t *len,
hdr = msg;
hdr->type = type;
- hdr->txn_id = txn_id;
- hdr->msg_id = msg_id;
- hdr->msg_len = msglen;
+ hdr->txn_id = cpu_to_le16(txn_id);
+ hdr->msg_id = cpu_to_le16(msg_id);
+ hdr->msg_len = cpu_to_le16(msglen);
*len = sizeof(*hdr) + msglen;
return msg;
}
-EXPORT_SYMBOL(qmi_encode_message);
+EXPORT_SYMBOL_GPL(qmi_encode_message);
/**
* qmi_decode_message() - Decode QMI encoded message to C structure
@@ -778,7 +808,7 @@ int qmi_decode_message(const void *buf, size_t len,
return qmi_decode(ei, c_struct, buf + sizeof(struct qmi_header),
len - sizeof(struct qmi_header), 1);
}
-EXPORT_SYMBOL(qmi_decode_message);
+EXPORT_SYMBOL_GPL(qmi_decode_message);
/* Common header in all QMI responses */
const struct qmi_elem_info qmi_response_type_v01_ei[] = {
@@ -810,7 +840,7 @@ const struct qmi_elem_info qmi_response_type_v01_ei[] = {
.ei_array = NULL,
},
};
-EXPORT_SYMBOL(qmi_response_type_v01_ei);
+EXPORT_SYMBOL_GPL(qmi_response_type_v01_ei);
MODULE_DESCRIPTION("QMI encoder/decoder helper");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c
index 57052726299d..6500f863aae5 100644
--- a/drivers/soc/qcom/qmi_interface.c
+++ b/drivers/soc/qcom/qmi_interface.c
@@ -12,6 +12,7 @@
#include <linux/string.h>
#include <net/sock.h>
#include <linux/workqueue.h>
+#include <trace/events/sock.h>
#include <linux/soc/qcom/qmi.h>
static struct socket *qmi_sock_create(struct qmi_handle *qmi,
@@ -194,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
@@ -222,7 +223,7 @@ int qmi_add_lookup(struct qmi_handle *qmi, unsigned int service,
return 0;
}
-EXPORT_SYMBOL(qmi_add_lookup);
+EXPORT_SYMBOL_GPL(qmi_add_lookup);
static void qmi_send_new_server(struct qmi_handle *qmi, struct qmi_service *svc)
{
@@ -286,7 +287,7 @@ int qmi_add_server(struct qmi_handle *qmi, unsigned int service,
return 0;
}
-EXPORT_SYMBOL(qmi_add_server);
+EXPORT_SYMBOL_GPL(qmi_add_server);
/**
* qmi_txn_init() - allocate transaction id within the given QMI handle
@@ -327,7 +328,7 @@ int qmi_txn_init(struct qmi_handle *qmi, struct qmi_txn *txn,
return ret;
}
-EXPORT_SYMBOL(qmi_txn_init);
+EXPORT_SYMBOL_GPL(qmi_txn_init);
/**
* qmi_txn_wait() - wait for a response on a transaction
@@ -358,7 +359,7 @@ int qmi_txn_wait(struct qmi_txn *txn, unsigned long timeout)
else
return txn->result;
}
-EXPORT_SYMBOL(qmi_txn_wait);
+EXPORT_SYMBOL_GPL(qmi_txn_wait);
/**
* qmi_txn_cancel() - cancel an ongoing transaction
@@ -374,7 +375,7 @@ void qmi_txn_cancel(struct qmi_txn *txn)
mutex_unlock(&txn->lock);
mutex_unlock(&qmi->txn_lock);
}
-EXPORT_SYMBOL(qmi_txn_cancel);
+EXPORT_SYMBOL_GPL(qmi_txn_cancel);
/**
* qmi_invoke_handler() - find and invoke a handler for a message
@@ -399,7 +400,7 @@ static void qmi_invoke_handler(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
for (handler = qmi->handlers; handler->fn; handler++) {
if (handler->type == hdr->type &&
- handler->msg_id == hdr->msg_id)
+ handler->msg_id == le16_to_cpu(hdr->msg_id))
break;
}
@@ -487,7 +488,7 @@ static void qmi_handle_message(struct qmi_handle *qmi,
/* If this is a response, find the matching transaction handle */
if (hdr->type == QMI_RESPONSE) {
mutex_lock(&qmi->txn_lock);
- txn = idr_find(&qmi->txns, hdr->txn_id);
+ txn = idr_find(&qmi->txns, le16_to_cpu(hdr->txn_id));
/* Ignore unexpected responses */
if (!txn) {
@@ -513,7 +514,7 @@ static void qmi_handle_message(struct qmi_handle *qmi,
} else {
/* Create a txn based on the txn_id of the incoming message */
memset(&tmp_txn, 0, sizeof(tmp_txn));
- tmp_txn.id = hdr->txn_id;
+ tmp_txn.id = le16_to_cpu(hdr->txn_id);
qmi_invoke_handler(qmi, sq, &tmp_txn, buf, len);
}
@@ -569,6 +570,8 @@ static void qmi_data_ready(struct sock *sk)
{
struct qmi_handle *qmi = sk->sk_user_data;
+ trace_sk_data_ready(sk);
+
/*
* This will be NULL if we receive data while being in
* qmi_handle_release()
@@ -647,7 +650,7 @@ int qmi_handle_init(struct qmi_handle *qmi, size_t recv_buf_size,
if (!qmi->recv_buf)
return -ENOMEM;
- qmi->wq = alloc_workqueue("qmi_msg_handler", WQ_UNBOUND, 1);
+ qmi->wq = alloc_ordered_workqueue("qmi_msg_handler", 0);
if (!qmi->wq) {
ret = -ENOMEM;
goto err_free_recv_buf;
@@ -673,7 +676,7 @@ err_free_recv_buf:
return ret;
}
-EXPORT_SYMBOL(qmi_handle_init);
+EXPORT_SYMBOL_GPL(qmi_handle_init);
/**
* qmi_handle_release() - release the QMI client handle
@@ -714,7 +717,7 @@ void qmi_handle_release(struct qmi_handle *qmi)
kfree(svc);
}
}
-EXPORT_SYMBOL(qmi_handle_release);
+EXPORT_SYMBOL_GPL(qmi_handle_release);
/**
* qmi_send_message() - send a QMI message
@@ -793,7 +796,7 @@ ssize_t qmi_send_request(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
return qmi_send_message(qmi, sq, txn, QMI_REQUEST, msg_id, len, ei,
c_struct);
}
-EXPORT_SYMBOL(qmi_send_request);
+EXPORT_SYMBOL_GPL(qmi_send_request);
/**
* qmi_send_response() - send a response QMI message
@@ -814,7 +817,7 @@ ssize_t qmi_send_response(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
return qmi_send_message(qmi, sq, txn, QMI_RESPONSE, msg_id, len, ei,
c_struct);
}
-EXPORT_SYMBOL(qmi_send_response);
+EXPORT_SYMBOL_GPL(qmi_send_response);
/**
* qmi_send_indication() - send an indication QMI message
@@ -848,4 +851,4 @@ ssize_t qmi_send_indication(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
return rval;
}
-EXPORT_SYMBOL(qmi_send_indication);
+EXPORT_SYMBOL_GPL(qmi_send_indication);
diff --git a/drivers/soc/qcom/ramp_controller.c b/drivers/soc/qcom/ramp_controller.c
new file mode 100644
index 000000000000..15782bed2925
--- /dev/null
+++ b/drivers/soc/qcom/ramp_controller.c
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Qualcomm Ramp Controller driver
+ * Copyright (c) 2022, AngeloGioacchino Del Regno
+ * <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#define RC_UPDATE_EN BIT(0)
+#define RC_ROOT_EN BIT(1)
+
+#define RC_REG_CFG_UPDATE 0x60
+#define RC_CFG_UPDATE_EN BIT(8)
+#define RC_CFG_ACK GENMASK(31, 16)
+
+#define RC_DCVS_CFG_SID 2
+#define RC_LINK_SID 3
+#define RC_LMH_SID 6
+#define RC_DFS_SID 14
+
+#define RC_UPDATE_TIMEOUT_US 500
+
+/**
+ * struct qcom_ramp_controller_desc - SoC specific parameters
+ * @cfg_dfs_sid: Dynamic Frequency Scaling SID configuration
+ * @cfg_link_sid: Link SID configuration
+ * @cfg_lmh_sid: Limits Management hardware SID configuration
+ * @cfg_ramp_en: Ramp Controller enable sequence
+ * @cfg_ramp_dis: Ramp Controller disable sequence
+ * @cmd_reg: Command register offset
+ * @num_dfs_sids: Number of DFS SIDs (max 8)
+ * @num_link_sids: Number of Link SIDs (max 3)
+ * @num_lmh_sids: Number of LMh SIDs (max 8)
+ * @num_ramp_en: Number of entries in enable sequence
+ * @num_ramp_dis: Number of entries in disable sequence
+ */
+struct qcom_ramp_controller_desc {
+ const struct reg_sequence *cfg_dfs_sid;
+ const struct reg_sequence *cfg_link_sid;
+ const struct reg_sequence *cfg_lmh_sid;
+ const struct reg_sequence *cfg_ramp_en;
+ const struct reg_sequence *cfg_ramp_dis;
+ u8 cmd_reg;
+ u8 num_dfs_sids;
+ u8 num_link_sids;
+ u8 num_lmh_sids;
+ u8 num_ramp_en;
+ u8 num_ramp_dis;
+};
+
+/**
+ * struct qcom_ramp_controller - Main driver structure
+ * @regmap: Regmap handle
+ * @desc: SoC specific parameters
+ */
+struct qcom_ramp_controller {
+ struct regmap *regmap;
+ const struct qcom_ramp_controller_desc *desc;
+};
+
+/**
+ * rc_wait_for_update() - Wait for Ramp Controller root update
+ * @qrc: Main driver structure
+ *
+ * Return: Zero for success or negative number for failure
+ */
+static int rc_wait_for_update(struct qcom_ramp_controller *qrc)
+{
+ const struct qcom_ramp_controller_desc *d = qrc->desc;
+ struct regmap *r = qrc->regmap;
+ u32 val;
+ int ret;
+
+ ret = regmap_set_bits(r, d->cmd_reg, RC_ROOT_EN);
+ if (ret)
+ return ret;
+
+ return regmap_read_poll_timeout(r, d->cmd_reg, val, !(val & RC_UPDATE_EN),
+ 1, RC_UPDATE_TIMEOUT_US);
+}
+
+/**
+ * rc_set_cfg_update() - Ramp Controller configuration update
+ * @qrc: Main driver structure
+ * @ce: Configuration entry to update
+ *
+ * Return: Zero for success or negative number for failure
+ */
+static int rc_set_cfg_update(struct qcom_ramp_controller *qrc, u8 ce)
+{
+ const struct qcom_ramp_controller_desc *d = qrc->desc;
+ struct regmap *r = qrc->regmap;
+ u32 ack, val;
+ int ret;
+
+ /* The ack bit is between bits 16-31 of RC_REG_CFG_UPDATE */
+ ack = FIELD_PREP(RC_CFG_ACK, BIT(ce));
+
+ /* Write the configuration type first... */
+ ret = regmap_set_bits(r, d->cmd_reg + RC_REG_CFG_UPDATE, ce);
+ if (ret)
+ return ret;
+
+ /* ...and after that, enable the update bit to sync the changes */
+ ret = regmap_set_bits(r, d->cmd_reg + RC_REG_CFG_UPDATE, RC_CFG_UPDATE_EN);
+ if (ret)
+ return ret;
+
+ /* Wait for the changes to go through */
+ ret = regmap_read_poll_timeout(r, d->cmd_reg + RC_REG_CFG_UPDATE, val,
+ val & ack, 1, RC_UPDATE_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ /*
+ * Configuration update success! The CFG_UPDATE register will not be
+ * cleared automatically upon applying the configuration, so we have
+ * to do that manually in order to leave the ramp controller in a
+ * predictable and clean state.
+ */
+ ret = regmap_write(r, d->cmd_reg + RC_REG_CFG_UPDATE, 0);
+ if (ret)
+ return ret;
+
+ /* Wait for the update bit cleared ack */
+ return regmap_read_poll_timeout(r, d->cmd_reg + RC_REG_CFG_UPDATE,
+ val, !(val & RC_CFG_ACK), 1,
+ RC_UPDATE_TIMEOUT_US);
+}
+
+/**
+ * rc_write_cfg - Send configuration sequence
+ * @qrc: Main driver structure
+ * @seq: Register sequence to send before asking for update
+ * @ce: Configuration SID
+ * @nsids: Total number of SIDs
+ *
+ * Returns: Zero for success or negative number for error
+ */
+static int rc_write_cfg(struct qcom_ramp_controller *qrc,
+ const struct reg_sequence *seq,
+ u16 ce, u8 nsids)
+{
+ int ret;
+ u8 i;
+
+ /* Check if, and wait until the ramp controller is ready */
+ ret = rc_wait_for_update(qrc);
+ if (ret)
+ return ret;
+
+ /* Write the sequence */
+ ret = regmap_multi_reg_write(qrc->regmap, seq, nsids);
+ if (ret)
+ return ret;
+
+ /* Pull the trigger: do config update starting from the last sid */
+ for (i = 0; i < nsids; i++) {
+ ret = rc_set_cfg_update(qrc, (u8)ce - i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * rc_ramp_ctrl_enable() - Enable Ramp up/down Control
+ * @qrc: Main driver structure
+ *
+ * Return: Zero for success or negative number for error
+ */
+static int rc_ramp_ctrl_enable(struct qcom_ramp_controller *qrc)
+{
+ const struct qcom_ramp_controller_desc *d = qrc->desc;
+ int i, ret;
+
+ for (i = 0; i < d->num_ramp_en; i++) {
+ ret = rc_write_cfg(qrc, &d->cfg_ramp_en[i], RC_DCVS_CFG_SID, 1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * qcom_ramp_controller_start() - Initialize and start the ramp controller
+ * @qrc: Main driver structure
+ *
+ * The Ramp Controller needs to be initialized by programming the relevant
+ * registers with SoC-specific configuration: once programming is done,
+ * the hardware will take care of the rest (no further handling required).
+ *
+ * Return: Zero for success or negative number for error
+ */
+static int qcom_ramp_controller_start(struct qcom_ramp_controller *qrc)
+{
+ const struct qcom_ramp_controller_desc *d = qrc->desc;
+ int ret;
+
+ /* Program LMH, DFS, Link SIDs */
+ ret = rc_write_cfg(qrc, d->cfg_lmh_sid, RC_LMH_SID, d->num_lmh_sids);
+ if (ret)
+ return ret;
+
+ ret = rc_write_cfg(qrc, d->cfg_dfs_sid, RC_DFS_SID, d->num_dfs_sids);
+ if (ret)
+ return ret;
+
+ ret = rc_write_cfg(qrc, d->cfg_link_sid, RC_LINK_SID, d->num_link_sids);
+ if (ret)
+ return ret;
+
+ /* Everything is ready! Enable the ramp up/down control */
+ return rc_ramp_ctrl_enable(qrc);
+}
+
+static const struct regmap_config qrc_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x68,
+};
+
+static const struct reg_sequence msm8976_cfg_dfs_sid[] = {
+ { 0x10, 0xfefebff7 },
+ { 0x14, 0xfdff7fef },
+ { 0x18, 0xfbffdefb },
+ { 0x1c, 0xb69b5555 },
+ { 0x20, 0x24929249 },
+ { 0x24, 0x49241112 },
+ { 0x28, 0x11112111 },
+ { 0x2c, 0x8102 }
+};
+
+static const struct reg_sequence msm8976_cfg_link_sid[] = {
+ { 0x40, 0xfc987 }
+};
+
+static const struct reg_sequence msm8976_cfg_lmh_sid[] = {
+ { 0x30, 0x77706db },
+ { 0x34, 0x5550249 },
+ { 0x38, 0x111 }
+};
+
+static const struct reg_sequence msm8976_cfg_ramp_en[] = {
+ { 0x50, 0x800 }, /* pre_en */
+ { 0x50, 0xc00 }, /* en */
+ { 0x50, 0x400 } /* post_en */
+};
+
+static const struct reg_sequence msm8976_cfg_ramp_dis[] = {
+ { 0x50, 0x0 }
+};
+
+static const struct qcom_ramp_controller_desc msm8976_rc_cfg = {
+ .cfg_dfs_sid = msm8976_cfg_dfs_sid,
+ .num_dfs_sids = ARRAY_SIZE(msm8976_cfg_dfs_sid),
+
+ .cfg_link_sid = msm8976_cfg_link_sid,
+ .num_link_sids = ARRAY_SIZE(msm8976_cfg_link_sid),
+
+ .cfg_lmh_sid = msm8976_cfg_lmh_sid,
+ .num_lmh_sids = ARRAY_SIZE(msm8976_cfg_lmh_sid),
+
+ .cfg_ramp_en = msm8976_cfg_ramp_en,
+ .num_ramp_en = ARRAY_SIZE(msm8976_cfg_ramp_en),
+
+ .cfg_ramp_dis = msm8976_cfg_ramp_dis,
+ .num_ramp_dis = ARRAY_SIZE(msm8976_cfg_ramp_dis),
+
+ .cmd_reg = 0x0,
+};
+
+static int qcom_ramp_controller_probe(struct platform_device *pdev)
+{
+ struct qcom_ramp_controller *qrc;
+ void __iomem *base;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ qrc = devm_kmalloc(&pdev->dev, sizeof(*qrc), GFP_KERNEL);
+ if (!qrc)
+ return -ENOMEM;
+
+ qrc->desc = device_get_match_data(&pdev->dev);
+ if (!qrc->desc)
+ return -EINVAL;
+
+ qrc->regmap = devm_regmap_init_mmio(&pdev->dev, base, &qrc_regmap_config);
+ if (IS_ERR(qrc->regmap))
+ return PTR_ERR(qrc->regmap);
+
+ platform_set_drvdata(pdev, qrc);
+
+ return qcom_ramp_controller_start(qrc);
+}
+
+static void qcom_ramp_controller_remove(struct platform_device *pdev)
+{
+ struct qcom_ramp_controller *qrc = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = rc_write_cfg(qrc, qrc->desc->cfg_ramp_dis,
+ RC_DCVS_CFG_SID, qrc->desc->num_ramp_dis);
+ if (ret)
+ dev_err(&pdev->dev, "Failed to send disable sequence\n");
+}
+
+static const struct of_device_id qcom_ramp_controller_match_table[] = {
+ { .compatible = "qcom,msm8976-ramp-controller", .data = &msm8976_rc_cfg },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, qcom_ramp_controller_match_table);
+
+static struct platform_driver qcom_ramp_controller_driver = {
+ .driver = {
+ .name = "qcom-ramp-controller",
+ .of_match_table = qcom_ramp_controller_match_table,
+ .suppress_bind_attrs = true,
+ },
+ .probe = qcom_ramp_controller_probe,
+ .remove = qcom_ramp_controller_remove,
+};
+
+static int __init qcom_ramp_controller_init(void)
+{
+ return platform_driver_register(&qcom_ramp_controller_driver);
+}
+arch_initcall(qcom_ramp_controller_init);
+
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_DESCRIPTION("Qualcomm Ramp Controller driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/qcom/rmtfs_mem.c b/drivers/soc/qcom/rmtfs_mem.c
index 0feaae357821..1b32469f2789 100644
--- a/drivers/soc/qcom/rmtfs_mem.c
+++ b/drivers/soc/qcom/rmtfs_mem.c
@@ -14,9 +14,10 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#define QCOM_RMTFS_MEM_DEV_MAX (MINORMASK + 1)
+#define NUM_MAX_VMIDS 2
static dev_t qcom_rmtfs_mem_major;
@@ -30,7 +31,7 @@ struct qcom_rmtfs_mem {
unsigned int client_id;
- unsigned int perms;
+ u64 perms;
};
static ssize_t qcom_rmtfs_mem_show(struct device *dev,
@@ -124,8 +125,7 @@ static int qcom_rmtfs_mem_release(struct inode *inode, struct file *filp)
return 0;
}
-static struct class rmtfs_class = {
- .owner = THIS_MODULE,
+static const struct class rmtfs_class = {
.name = "rmtfs",
};
@@ -171,12 +171,13 @@ static void qcom_rmtfs_mem_release_device(struct device *dev)
static int qcom_rmtfs_mem_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
- struct qcom_scm_vmperm perms[2];
+ struct qcom_scm_vmperm perms[NUM_MAX_VMIDS + 1];
struct reserved_mem *rmem;
struct qcom_rmtfs_mem *rmtfs_mem;
u32 client_id;
- u32 vmid;
- int ret;
+ u32 vmid[NUM_MAX_VMIDS];
+ int num_vmids;
+ int ret, i;
rmem = of_reserved_mem_lookup(node);
if (!rmem) {
@@ -199,6 +200,15 @@ static int qcom_rmtfs_mem_probe(struct platform_device *pdev)
rmtfs_mem->client_id = client_id;
rmtfs_mem->size = rmem->size;
+ /*
+ * If requested, discard the first and last 4k block in order to ensure
+ * that the rmtfs region isn't adjacent to other protected regions.
+ */
+ if (of_property_read_bool(node, "qcom,use-guard-pages")) {
+ rmtfs_mem->addr += SZ_4K;
+ rmtfs_mem->size -= 2 * SZ_4K;
+ }
+
device_initialize(&rmtfs_mem->dev);
rmtfs_mem->dev.parent = &pdev->dev;
rmtfs_mem->dev.groups = qcom_rmtfs_mem_groups;
@@ -226,7 +236,22 @@ static int qcom_rmtfs_mem_probe(struct platform_device *pdev)
goto put_device;
}
- ret = of_property_read_u32(node, "qcom,vmid", &vmid);
+ num_vmids = of_property_count_u32_elems(node, "qcom,vmid");
+ if (num_vmids == -EINVAL) {
+ /* qcom,vmid is optional */
+ num_vmids = 0;
+ } else if (num_vmids < 0) {
+ dev_err(&pdev->dev, "failed to count qcom,vmid elements: %d\n", num_vmids);
+ ret = num_vmids;
+ goto remove_cdev;
+ } else if (num_vmids > NUM_MAX_VMIDS) {
+ dev_warn(&pdev->dev,
+ "too many VMIDs (%d) specified! Only mapping first %d entries\n",
+ num_vmids, NUM_MAX_VMIDS);
+ num_vmids = NUM_MAX_VMIDS;
+ }
+
+ ret = of_property_read_u32_array(node, "qcom,vmid", vmid, num_vmids);
if (ret < 0 && ret != -EINVAL) {
dev_err(&pdev->dev, "failed to parse qcom,vmid\n");
goto remove_cdev;
@@ -238,12 +263,15 @@ static int qcom_rmtfs_mem_probe(struct platform_device *pdev)
perms[0].vmid = QCOM_SCM_VMID_HLOS;
perms[0].perm = QCOM_SCM_PERM_RW;
- perms[1].vmid = vmid;
- perms[1].perm = QCOM_SCM_PERM_RW;
+
+ for (i = 0; i < num_vmids; i++) {
+ perms[i + 1].vmid = vmid[i];
+ perms[i + 1].perm = QCOM_SCM_PERM_RW;
+ }
rmtfs_mem->perms = BIT(QCOM_SCM_VMID_HLOS);
ret = qcom_scm_assign_mem(rmtfs_mem->addr, rmtfs_mem->size,
- &rmtfs_mem->perms, perms, 2);
+ &rmtfs_mem->perms, perms, num_vmids + 1);
if (ret < 0) {
dev_err(&pdev->dev, "assign memory failed\n");
goto remove_cdev;
@@ -262,7 +290,7 @@ put_device:
return ret;
}
-static int qcom_rmtfs_mem_remove(struct platform_device *pdev)
+static void qcom_rmtfs_mem_remove(struct platform_device *pdev)
{
struct qcom_rmtfs_mem *rmtfs_mem = dev_get_drvdata(&pdev->dev);
struct qcom_scm_vmperm perm;
@@ -277,8 +305,6 @@ static int qcom_rmtfs_mem_remove(struct platform_device *pdev)
cdev_device_del(&rmtfs_mem->cdev, &rmtfs_mem->dev);
put_device(&rmtfs_mem->dev);
-
- return 0;
}
static const struct of_device_id qcom_rmtfs_mem_of_match[] = {
diff --git a/drivers/soc/qcom/rpm-proc.c b/drivers/soc/qcom/rpm-proc.c
new file mode 100644
index 000000000000..2466d0400c2e
--- /dev/null
+++ b/drivers/soc/qcom/rpm-proc.c
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2021-2023, Stephan Gerhold <stephan@gerhold.net> */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/rpmsg/qcom_smd.h>
+
+static int rpm_proc_probe(struct platform_device *pdev)
+{
+ struct qcom_smd_edge *edge = NULL;
+ struct device *dev = &pdev->dev;
+ struct device_node *edge_node;
+ int ret;
+
+ edge_node = of_get_child_by_name(dev->of_node, "smd-edge");
+ if (edge_node) {
+ edge = qcom_smd_register_edge(dev, edge_node);
+ of_node_put(edge_node);
+ if (IS_ERR(edge))
+ return dev_err_probe(dev, PTR_ERR(edge),
+ "Failed to register smd-edge\n");
+ }
+
+ ret = devm_of_platform_populate(dev);
+ if (ret) {
+ dev_err(dev, "Failed to populate child devices: %d\n", ret);
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, edge);
+ return 0;
+err:
+ if (edge)
+ qcom_smd_unregister_edge(edge);
+ return ret;
+}
+
+static void rpm_proc_remove(struct platform_device *pdev)
+{
+ struct qcom_smd_edge *edge = platform_get_drvdata(pdev);
+
+ if (edge)
+ qcom_smd_unregister_edge(edge);
+}
+
+static const struct of_device_id rpm_proc_of_match[] = {
+ { .compatible = "qcom,rpm-proc", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rpm_proc_of_match);
+
+static struct platform_driver rpm_proc_driver = {
+ .probe = rpm_proc_probe,
+ .remove = rpm_proc_remove,
+ .driver = {
+ .name = "qcom-rpm-proc",
+ .of_match_table = rpm_proc_of_match,
+ },
+};
+
+static int __init rpm_proc_init(void)
+{
+ return platform_driver_register(&rpm_proc_driver);
+}
+arch_initcall(rpm_proc_init);
+
+static void __exit rpm_proc_exit(void)
+{
+ platform_driver_unregister(&rpm_proc_driver);
+}
+module_exit(rpm_proc_exit);
+
+MODULE_DESCRIPTION("Qualcomm RPM processor/subsystem driver");
+MODULE_AUTHOR("Stephan Gerhold <stephan@gerhold.net>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/qcom/rpm_master_stats.c b/drivers/soc/qcom/rpm_master_stats.c
new file mode 100644
index 000000000000..c7788337e164
--- /dev/null
+++ b/drivers/soc/qcom/rpm_master_stats.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023, Linaro Limited
+ *
+ * This driver supports what is known as "Master Stats v2" in Qualcomm
+ * downstream kernel terms, which seems to be the only version which has
+ * ever shipped, all the way from 2013 to 2023.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+
+struct master_stats_data {
+ void __iomem *base;
+ const char *label;
+};
+
+struct rpm_master_stats {
+ u32 active_cores;
+ u32 num_shutdowns;
+ u64 shutdown_req;
+ u64 wakeup_idx;
+ u64 bringup_req;
+ u64 bringup_ack;
+ u32 wakeup_reason; /* 0 = "rude wakeup", 1 = scheduled wakeup */
+ u32 last_sleep_trans_dur;
+ u32 last_wake_trans_dur;
+
+ /* Per-subsystem (*not necessarily* SoC-wide) XO shutdown stats */
+ u32 xo_count;
+ u64 xo_last_enter;
+ u64 last_exit;
+ u64 xo_total_dur;
+} __packed;
+
+static int master_stats_show(struct seq_file *s, void *unused)
+{
+ struct master_stats_data *data = s->private;
+ struct rpm_master_stats stat;
+
+ memcpy_fromio(&stat, data->base, sizeof(stat));
+
+ seq_printf(s, "%s:\n", data->label);
+
+ seq_printf(s, "\tLast shutdown @ %llu\n", stat.shutdown_req);
+ seq_printf(s, "\tLast bringup req @ %llu\n", stat.bringup_req);
+ seq_printf(s, "\tLast bringup ack @ %llu\n", stat.bringup_ack);
+ seq_printf(s, "\tLast wakeup idx: %llu\n", stat.wakeup_idx);
+ seq_printf(s, "\tLast XO shutdown enter @ %llu\n", stat.xo_last_enter);
+ seq_printf(s, "\tLast XO shutdown exit @ %llu\n", stat.last_exit);
+ seq_printf(s, "\tXO total duration: %llu\n", stat.xo_total_dur);
+ seq_printf(s, "\tLast sleep transition duration: %u\n", stat.last_sleep_trans_dur);
+ seq_printf(s, "\tLast wake transition duration: %u\n", stat.last_wake_trans_dur);
+ seq_printf(s, "\tXO shutdown count: %u\n", stat.xo_count);
+ seq_printf(s, "\tWakeup reason: 0x%x\n", stat.wakeup_reason);
+ seq_printf(s, "\tShutdown count: %u\n", stat.num_shutdowns);
+ seq_printf(s, "\tActive cores bitmask: 0x%x\n", stat.active_cores);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(master_stats);
+
+static int master_stats_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct master_stats_data *data;
+ struct device_node *msgram_np;
+ struct dentry *dent, *root;
+ struct resource res;
+ int count, i, ret;
+
+ count = of_property_count_strings(dev->of_node, "qcom,master-names");
+ if (count < 0)
+ return count;
+
+ data = devm_kcalloc(dev, count, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ root = debugfs_create_dir("qcom_rpm_master_stats", NULL);
+ platform_set_drvdata(pdev, root);
+
+ for (i = 0; i < count; i++) {
+ msgram_np = of_parse_phandle(dev->of_node, "qcom,rpm-msg-ram", i);
+ if (!msgram_np) {
+ debugfs_remove_recursive(root);
+ return dev_err_probe(dev, -ENODEV,
+ "Couldn't parse MSG RAM phandle idx %d", i);
+ }
+
+ /*
+ * Purposefully skip devm_platform helpers as we're using a
+ * shared resource.
+ */
+ ret = of_address_to_resource(msgram_np, 0, &res);
+ of_node_put(msgram_np);
+ if (ret < 0) {
+ debugfs_remove_recursive(root);
+ return ret;
+ }
+
+ data[i].base = devm_ioremap(dev, res.start, resource_size(&res));
+ if (!data[i].base) {
+ debugfs_remove_recursive(root);
+ return dev_err_probe(dev, -EINVAL,
+ "Could not map the MSG RAM slice idx %d!\n", i);
+ }
+
+ ret = of_property_read_string_index(dev->of_node, "qcom,master-names", i,
+ &data[i].label);
+ if (ret < 0) {
+ debugfs_remove_recursive(root);
+ return dev_err_probe(dev, ret,
+ "Could not read name idx %d!\n", i);
+ }
+
+ /*
+ * Generally it's not advised to fail on debugfs errors, but this
+ * driver's only job is exposing data therein.
+ */
+ dent = debugfs_create_file(data[i].label, 0444, root,
+ &data[i], &master_stats_fops);
+ if (IS_ERR(dent)) {
+ debugfs_remove_recursive(root);
+ return dev_err_probe(dev, PTR_ERR(dent),
+ "Failed to create debugfs file %s!\n", data[i].label);
+ }
+ }
+
+ device_set_pm_not_required(dev);
+
+ return 0;
+}
+
+static void master_stats_remove(struct platform_device *pdev)
+{
+ struct dentry *root = platform_get_drvdata(pdev);
+
+ debugfs_remove_recursive(root);
+}
+
+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 = master_stats_remove,
+ .driver = {
+ .name = "qcom_rpm_master_stats",
+ .of_match_table = rpm_master_table,
+ },
+};
+module_platform_driver(master_stats_driver);
+
+MODULE_DESCRIPTION("Qualcomm RPM Master Statistics driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index 0f8b2249f889..c6f7d5c9c493 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
@@ -452,13 +453,10 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
trace_rpmh_tx_done(drv, i, req);
- /*
- * If wake tcs was re-purposed for sending active
- * votes, clear AMC trigger & enable modes and
+ /* Clear AMC trigger & enable modes and
* disable interrupt for this TCS
*/
- if (!drv->tcs[ACTIVE_TCS].num_tcs)
- __tcs_set_trigger(drv, i, false);
+ __tcs_set_trigger(drv, i, false);
skip:
/* Reclaim the TCS */
write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], i, 0);
@@ -516,7 +514,7 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id,
write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_MSGID], tcs_id, j, msgid);
write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], tcs_id, j, cmd->addr);
write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_DATA], tcs_id, j, cmd->data);
- trace_rpmh_send_msg(drv, tcs_id, j, msgid, cmd);
+ trace_rpmh_send_msg(drv, tcs_id, msg->state, j, msgid, cmd);
}
cmd_enable |= read_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id);
@@ -557,7 +555,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 +643,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 +668,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 +1042,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)
@@ -1073,7 +1069,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
drv->ver.minor = rsc_id & (MINOR_VER_MASK << MINOR_VER_SHIFT);
drv->ver.minor >>= MINOR_VER_SHIFT;
- if (drv->ver.major == 3 && drv->ver.minor == 0)
+ if (drv->ver.major >= 3)
drv->regs = rpmh_rsc_reg_offset_ver_3_0;
else
drv->regs = rpmh_rsc_reg_offset_ver_2_7;
@@ -1154,7 +1150,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 08e09642d7f5..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 */
@@ -239,7 +238,7 @@ int rpmh_write_async(const struct device *dev, enum rpmh_state state,
return __rpmh_write(dev, state, rpm_msg);
}
-EXPORT_SYMBOL(rpmh_write_async);
+EXPORT_SYMBOL_GPL(rpmh_write_async);
/**
* rpmh_write: Write a set of RPMH commands and block until response
@@ -270,7 +269,7 @@ int rpmh_write(const struct device *dev, enum rpmh_state state,
WARN_ON(!ret);
return (ret > 0) ? 0 : -ETIMEDOUT;
}
-EXPORT_SYMBOL(rpmh_write);
+EXPORT_SYMBOL_GPL(rpmh_write);
static void cache_batch(struct rpmh_ctrlr *ctrlr, struct batch_cache_req *req)
{
@@ -395,7 +394,7 @@ exit:
return ret;
}
-EXPORT_SYMBOL(rpmh_write_batch);
+EXPORT_SYMBOL_GPL(rpmh_write_batch);
static int is_req_valid(struct cache_req *req)
{
@@ -500,4 +499,4 @@ void rpmh_invalidate(const struct device *dev)
ctrlr->dirty = true;
spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
}
-EXPORT_SYMBOL(rpmh_invalidate);
+EXPORT_SYMBOL_GPL(rpmh_invalidate);
diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c
deleted file mode 100644
index 4c2d2c296790..000000000000
--- a/drivers/soc/qcom/rpmhpd.c
+++ /dev/null
@@ -1,820 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.*/
-
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/pm_domain.h>
-#include <linux/slab.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/pm_opp.h>
-#include <soc/qcom/cmd-db.h>
-#include <soc/qcom/rpmh.h>
-#include <dt-bindings/power/qcom-rpmpd.h>
-
-#define domain_to_rpmhpd(domain) container_of(domain, struct rpmhpd, pd)
-
-#define RPMH_ARC_MAX_LEVELS 16
-
-/**
- * struct rpmhpd - top level RPMh power domain resource data structure
- * @dev: rpmh power domain controller device
- * @pd: generic_pm_domain corresponding to the power domain
- * @parent: generic_pm_domain corresponding to the parent's power domain
- * @peer: A peer power domain in case Active only Voting is
- * supported
- * @active_only: True if it represents an Active only peer
- * @corner: current corner
- * @active_corner: current active corner
- * @enable_corner: lowest non-zero corner
- * @level: An array of level (vlvl) to corner (hlvl) mappings
- * derived from cmd-db
- * @level_count: Number of levels supported by the power domain. max
- * being 16 (0 - 15)
- * @enabled: true if the power domain is enabled
- * @res_name: Resource name used for cmd-db lookup
- * @addr: Resource address as looped up using resource name from
- * cmd-db
- * @state_synced: Indicator that sync_state has been invoked for the rpmhpd resource
- */
-struct rpmhpd {
- struct device *dev;
- struct generic_pm_domain pd;
- struct generic_pm_domain *parent;
- struct rpmhpd *peer;
- const bool active_only;
- unsigned int corner;
- unsigned int active_corner;
- unsigned int enable_corner;
- u32 level[RPMH_ARC_MAX_LEVELS];
- size_t level_count;
- bool enabled;
- const char *res_name;
- u32 addr;
- bool state_synced;
-};
-
-struct rpmhpd_desc {
- struct rpmhpd **rpmhpds;
- size_t num_pds;
-};
-
-static DEFINE_MUTEX(rpmhpd_lock);
-
-/* RPMH powerdomains */
-
-static struct rpmhpd cx_ao;
-static struct rpmhpd mx;
-static struct rpmhpd mx_ao;
-static struct rpmhpd cx = {
- .pd = { .name = "cx", },
- .peer = &cx_ao,
- .res_name = "cx.lvl",
-};
-
-static struct rpmhpd cx_ao = {
- .pd = { .name = "cx_ao", },
- .active_only = true,
- .peer = &cx,
- .res_name = "cx.lvl",
-};
-
-static struct rpmhpd cx_ao_w_mx_parent;
-static struct rpmhpd cx_w_mx_parent = {
- .pd = { .name = "cx", },
- .peer = &cx_ao_w_mx_parent,
- .parent = &mx.pd,
- .res_name = "cx.lvl",
-};
-
-static struct rpmhpd cx_ao_w_mx_parent = {
- .pd = { .name = "cx_ao", },
- .active_only = true,
- .peer = &cx_w_mx_parent,
- .parent = &mx_ao.pd,
- .res_name = "cx.lvl",
-};
-
-static struct rpmhpd ebi = {
- .pd = { .name = "ebi", },
- .res_name = "ebi.lvl",
-};
-
-static struct rpmhpd gfx = {
- .pd = { .name = "gfx", },
- .res_name = "gfx.lvl",
-};
-
-static struct rpmhpd lcx = {
- .pd = { .name = "lcx", },
- .res_name = "lcx.lvl",
-};
-
-static struct rpmhpd lmx = {
- .pd = { .name = "lmx", },
- .res_name = "lmx.lvl",
-};
-
-static struct rpmhpd mmcx_ao;
-static struct rpmhpd mmcx = {
- .pd = { .name = "mmcx", },
- .peer = &mmcx_ao,
- .res_name = "mmcx.lvl",
-};
-
-static struct rpmhpd mmcx_ao = {
- .pd = { .name = "mmcx_ao", },
- .active_only = true,
- .peer = &mmcx,
- .res_name = "mmcx.lvl",
-};
-
-static struct rpmhpd mmcx_ao_w_cx_parent;
-static struct rpmhpd mmcx_w_cx_parent = {
- .pd = { .name = "mmcx", },
- .peer = &mmcx_ao_w_cx_parent,
- .parent = &cx.pd,
- .res_name = "mmcx.lvl",
-};
-
-static struct rpmhpd mmcx_ao_w_cx_parent = {
- .pd = { .name = "mmcx_ao", },
- .active_only = true,
- .peer = &mmcx_w_cx_parent,
- .parent = &cx_ao.pd,
- .res_name = "mmcx.lvl",
-};
-
-static struct rpmhpd mss = {
- .pd = { .name = "mss", },
- .res_name = "mss.lvl",
-};
-
-static struct rpmhpd mx_ao;
-static struct rpmhpd mx = {
- .pd = { .name = "mx", },
- .peer = &mx_ao,
- .res_name = "mx.lvl",
-};
-
-static struct rpmhpd mx_ao = {
- .pd = { .name = "mx_ao", },
- .active_only = true,
- .peer = &mx,
- .res_name = "mx.lvl",
-};
-
-static struct rpmhpd mxc_ao;
-static struct rpmhpd mxc = {
- .pd = { .name = "mxc", },
- .peer = &mxc_ao,
- .res_name = "mxc.lvl",
-};
-
-static struct rpmhpd mxc_ao = {
- .pd = { .name = "mxc_ao", },
- .active_only = true,
- .peer = &mxc,
- .res_name = "mxc.lvl",
-};
-
-static struct rpmhpd nsp = {
- .pd = { .name = "nsp", },
- .res_name = "nsp.lvl",
-};
-
-static struct rpmhpd qphy = {
- .pd = { .name = "qphy", },
- .res_name = "qphy.lvl",
-};
-
-/* SA8540P RPMH powerdomains */
-static struct rpmhpd *sa8540p_rpmhpds[] = {
- [SC8280XP_CX] = &cx,
- [SC8280XP_CX_AO] = &cx_ao,
- [SC8280XP_EBI] = &ebi,
- [SC8280XP_GFX] = &gfx,
- [SC8280XP_LCX] = &lcx,
- [SC8280XP_LMX] = &lmx,
- [SC8280XP_MMCX] = &mmcx,
- [SC8280XP_MMCX_AO] = &mmcx_ao,
- [SC8280XP_MX] = &mx,
- [SC8280XP_MX_AO] = &mx_ao,
- [SC8280XP_NSP] = &nsp,
-};
-
-static const struct rpmhpd_desc sa8540p_desc = {
- .rpmhpds = sa8540p_rpmhpds,
- .num_pds = ARRAY_SIZE(sa8540p_rpmhpds),
-};
-
-/* SDM670 RPMH powerdomains */
-static struct rpmhpd *sdm670_rpmhpds[] = {
- [SDM670_CX] = &cx_w_mx_parent,
- [SDM670_CX_AO] = &cx_ao_w_mx_parent,
- [SDM670_GFX] = &gfx,
- [SDM670_LCX] = &lcx,
- [SDM670_LMX] = &lmx,
- [SDM670_MSS] = &mss,
- [SDM670_MX] = &mx,
- [SDM670_MX_AO] = &mx_ao,
-};
-
-static const struct rpmhpd_desc sdm670_desc = {
- .rpmhpds = sdm670_rpmhpds,
- .num_pds = ARRAY_SIZE(sdm670_rpmhpds),
-};
-
-/* SDM845 RPMH powerdomains */
-static struct rpmhpd *sdm845_rpmhpds[] = {
- [SDM845_CX] = &cx_w_mx_parent,
- [SDM845_CX_AO] = &cx_ao_w_mx_parent,
- [SDM845_EBI] = &ebi,
- [SDM845_GFX] = &gfx,
- [SDM845_LCX] = &lcx,
- [SDM845_LMX] = &lmx,
- [SDM845_MSS] = &mss,
- [SDM845_MX] = &mx,
- [SDM845_MX_AO] = &mx_ao,
-};
-
-static const struct rpmhpd_desc sdm845_desc = {
- .rpmhpds = sdm845_rpmhpds,
- .num_pds = ARRAY_SIZE(sdm845_rpmhpds),
-};
-
-/* SDX55 RPMH powerdomains */
-static struct rpmhpd *sdx55_rpmhpds[] = {
- [SDX55_CX] = &cx_w_mx_parent,
- [SDX55_MSS] = &mss,
- [SDX55_MX] = &mx,
-};
-
-static const struct rpmhpd_desc sdx55_desc = {
- .rpmhpds = sdx55_rpmhpds,
- .num_pds = ARRAY_SIZE(sdx55_rpmhpds),
-};
-
-/* SDX65 RPMH powerdomains */
-static struct rpmhpd *sdx65_rpmhpds[] = {
- [SDX65_CX] = &cx_w_mx_parent,
- [SDX65_CX_AO] = &cx_ao_w_mx_parent,
- [SDX65_MSS] = &mss,
- [SDX65_MX] = &mx,
- [SDX65_MX_AO] = &mx_ao,
- [SDX65_MXC] = &mxc,
-};
-
-static const struct rpmhpd_desc sdx65_desc = {
- .rpmhpds = sdx65_rpmhpds,
- .num_pds = ARRAY_SIZE(sdx65_rpmhpds),
-};
-
-/* SM6350 RPMH powerdomains */
-static struct rpmhpd *sm6350_rpmhpds[] = {
- [SM6350_CX] = &cx_w_mx_parent,
- [SM6350_GFX] = &gfx,
- [SM6350_LCX] = &lcx,
- [SM6350_LMX] = &lmx,
- [SM6350_MSS] = &mss,
- [SM6350_MX] = &mx,
-};
-
-static const struct rpmhpd_desc sm6350_desc = {
- .rpmhpds = sm6350_rpmhpds,
- .num_pds = ARRAY_SIZE(sm6350_rpmhpds),
-};
-
-/* SM8150 RPMH powerdomains */
-static struct rpmhpd *sm8150_rpmhpds[] = {
- [SM8150_CX] = &cx_w_mx_parent,
- [SM8150_CX_AO] = &cx_ao_w_mx_parent,
- [SM8150_EBI] = &ebi,
- [SM8150_GFX] = &gfx,
- [SM8150_LCX] = &lcx,
- [SM8150_LMX] = &lmx,
- [SM8150_MMCX] = &mmcx,
- [SM8150_MMCX_AO] = &mmcx_ao,
- [SM8150_MSS] = &mss,
- [SM8150_MX] = &mx,
- [SM8150_MX_AO] = &mx_ao,
-};
-
-static const struct rpmhpd_desc sm8150_desc = {
- .rpmhpds = sm8150_rpmhpds,
- .num_pds = ARRAY_SIZE(sm8150_rpmhpds),
-};
-
-/* SM8250 RPMH powerdomains */
-static struct rpmhpd *sm8250_rpmhpds[] = {
- [SM8250_CX] = &cx_w_mx_parent,
- [SM8250_CX_AO] = &cx_ao_w_mx_parent,
- [SM8250_EBI] = &ebi,
- [SM8250_GFX] = &gfx,
- [SM8250_LCX] = &lcx,
- [SM8250_LMX] = &lmx,
- [SM8250_MMCX] = &mmcx,
- [SM8250_MMCX_AO] = &mmcx_ao,
- [SM8250_MX] = &mx,
- [SM8250_MX_AO] = &mx_ao,
-};
-
-static const struct rpmhpd_desc sm8250_desc = {
- .rpmhpds = sm8250_rpmhpds,
- .num_pds = ARRAY_SIZE(sm8250_rpmhpds),
-};
-
-/* SM8350 Power domains */
-static struct rpmhpd *sm8350_rpmhpds[] = {
- [SM8350_CX] = &cx_w_mx_parent,
- [SM8350_CX_AO] = &cx_ao_w_mx_parent,
- [SM8350_EBI] = &ebi,
- [SM8350_GFX] = &gfx,
- [SM8350_LCX] = &lcx,
- [SM8350_LMX] = &lmx,
- [SM8350_MMCX] = &mmcx,
- [SM8350_MMCX_AO] = &mmcx_ao,
- [SM8350_MSS] = &mss,
- [SM8350_MX] = &mx,
- [SM8350_MX_AO] = &mx_ao,
- [SM8350_MXC] = &mxc,
- [SM8350_MXC_AO] = &mxc_ao,
-};
-
-static const struct rpmhpd_desc sm8350_desc = {
- .rpmhpds = sm8350_rpmhpds,
- .num_pds = ARRAY_SIZE(sm8350_rpmhpds),
-};
-
-/* SM8450 RPMH powerdomains */
-static struct rpmhpd *sm8450_rpmhpds[] = {
- [SM8450_CX] = &cx,
- [SM8450_CX_AO] = &cx_ao,
- [SM8450_EBI] = &ebi,
- [SM8450_GFX] = &gfx,
- [SM8450_LCX] = &lcx,
- [SM8450_LMX] = &lmx,
- [SM8450_MMCX] = &mmcx_w_cx_parent,
- [SM8450_MMCX_AO] = &mmcx_ao_w_cx_parent,
- [SM8450_MSS] = &mss,
- [SM8450_MX] = &mx,
- [SM8450_MX_AO] = &mx_ao,
- [SM8450_MXC] = &mxc,
- [SM8450_MXC_AO] = &mxc_ao,
-};
-
-static const struct rpmhpd_desc sm8450_desc = {
- .rpmhpds = sm8450_rpmhpds,
- .num_pds = ARRAY_SIZE(sm8450_rpmhpds),
-};
-
-/* SM8550 RPMH powerdomains */
-static struct rpmhpd *sm8550_rpmhpds[] = {
- [SM8550_CX] = &cx,
- [SM8550_CX_AO] = &cx_ao,
- [SM8550_EBI] = &ebi,
- [SM8550_GFX] = &gfx,
- [SM8550_LCX] = &lcx,
- [SM8550_LMX] = &lmx,
- [SM8550_MMCX] = &mmcx_w_cx_parent,
- [SM8550_MMCX_AO] = &mmcx_ao_w_cx_parent,
- [SM8550_MSS] = &mss,
- [SM8550_MX] = &mx,
- [SM8550_MX_AO] = &mx_ao,
- [SM8550_MXC] = &mxc,
- [SM8550_MXC_AO] = &mxc_ao,
- [SM8550_NSP] = &nsp,
-};
-
-static const struct rpmhpd_desc sm8550_desc = {
- .rpmhpds = sm8550_rpmhpds,
- .num_pds = ARRAY_SIZE(sm8550_rpmhpds),
-};
-
-/* QDU1000/QRU1000 RPMH powerdomains */
-static struct rpmhpd *qdu1000_rpmhpds[] = {
- [QDU1000_CX] = &cx,
- [QDU1000_EBI] = &ebi,
- [QDU1000_MSS] = &mss,
- [QDU1000_MX] = &mx,
-};
-
-static const struct rpmhpd_desc qdu1000_desc = {
- .rpmhpds = qdu1000_rpmhpds,
- .num_pds = ARRAY_SIZE(qdu1000_rpmhpds),
-};
-
-/* SC7180 RPMH powerdomains */
-static struct rpmhpd *sc7180_rpmhpds[] = {
- [SC7180_CX] = &cx_w_mx_parent,
- [SC7180_CX_AO] = &cx_ao_w_mx_parent,
- [SC7180_GFX] = &gfx,
- [SC7180_LCX] = &lcx,
- [SC7180_LMX] = &lmx,
- [SC7180_MSS] = &mss,
- [SC7180_MX] = &mx,
- [SC7180_MX_AO] = &mx_ao,
-};
-
-static const struct rpmhpd_desc sc7180_desc = {
- .rpmhpds = sc7180_rpmhpds,
- .num_pds = ARRAY_SIZE(sc7180_rpmhpds),
-};
-
-/* SC7280 RPMH powerdomains */
-static struct rpmhpd *sc7280_rpmhpds[] = {
- [SC7280_CX] = &cx,
- [SC7280_CX_AO] = &cx_ao,
- [SC7280_EBI] = &ebi,
- [SC7280_GFX] = &gfx,
- [SC7280_LCX] = &lcx,
- [SC7280_LMX] = &lmx,
- [SC7280_MSS] = &mss,
- [SC7280_MX] = &mx,
- [SC7280_MX_AO] = &mx_ao,
-};
-
-static const struct rpmhpd_desc sc7280_desc = {
- .rpmhpds = sc7280_rpmhpds,
- .num_pds = ARRAY_SIZE(sc7280_rpmhpds),
-};
-
-/* SC8180x RPMH powerdomains */
-static struct rpmhpd *sc8180x_rpmhpds[] = {
- [SC8180X_CX] = &cx_w_mx_parent,
- [SC8180X_CX_AO] = &cx_ao_w_mx_parent,
- [SC8180X_EBI] = &ebi,
- [SC8180X_GFX] = &gfx,
- [SC8180X_LCX] = &lcx,
- [SC8180X_LMX] = &lmx,
- [SC8180X_MMCX] = &mmcx,
- [SC8180X_MMCX_AO] = &mmcx_ao,
- [SC8180X_MSS] = &mss,
- [SC8180X_MX] = &mx,
- [SC8180X_MX_AO] = &mx_ao,
-};
-
-static const struct rpmhpd_desc sc8180x_desc = {
- .rpmhpds = sc8180x_rpmhpds,
- .num_pds = ARRAY_SIZE(sc8180x_rpmhpds),
-};
-
-/* SC8280xp RPMH powerdomains */
-static struct rpmhpd *sc8280xp_rpmhpds[] = {
- [SC8280XP_CX] = &cx,
- [SC8280XP_CX_AO] = &cx_ao,
- [SC8280XP_EBI] = &ebi,
- [SC8280XP_GFX] = &gfx,
- [SC8280XP_LCX] = &lcx,
- [SC8280XP_LMX] = &lmx,
- [SC8280XP_MMCX] = &mmcx,
- [SC8280XP_MMCX_AO] = &mmcx_ao,
- [SC8280XP_MX] = &mx,
- [SC8280XP_MX_AO] = &mx_ao,
- [SC8280XP_NSP] = &nsp,
- [SC8280XP_QPHY] = &qphy,
-};
-
-static const struct rpmhpd_desc sc8280xp_desc = {
- .rpmhpds = sc8280xp_rpmhpds,
- .num_pds = ARRAY_SIZE(sc8280xp_rpmhpds),
-};
-
-static const struct of_device_id rpmhpd_match_table[] = {
- { .compatible = "qcom,qdu1000-rpmhpd", .data = &qdu1000_desc },
- { .compatible = "qcom,sa8540p-rpmhpd", .data = &sa8540p_desc },
- { .compatible = "qcom,sc7180-rpmhpd", .data = &sc7180_desc },
- { .compatible = "qcom,sc7280-rpmhpd", .data = &sc7280_desc },
- { .compatible = "qcom,sc8180x-rpmhpd", .data = &sc8180x_desc },
- { .compatible = "qcom,sc8280xp-rpmhpd", .data = &sc8280xp_desc },
- { .compatible = "qcom,sdm670-rpmhpd", .data = &sdm670_desc },
- { .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc },
- { .compatible = "qcom,sdx55-rpmhpd", .data = &sdx55_desc},
- { .compatible = "qcom,sdx65-rpmhpd", .data = &sdx65_desc},
- { .compatible = "qcom,sm6350-rpmhpd", .data = &sm6350_desc },
- { .compatible = "qcom,sm8150-rpmhpd", .data = &sm8150_desc },
- { .compatible = "qcom,sm8250-rpmhpd", .data = &sm8250_desc },
- { .compatible = "qcom,sm8350-rpmhpd", .data = &sm8350_desc },
- { .compatible = "qcom,sm8450-rpmhpd", .data = &sm8450_desc },
- { .compatible = "qcom,sm8550-rpmhpd", .data = &sm8550_desc },
- { }
-};
-MODULE_DEVICE_TABLE(of, rpmhpd_match_table);
-
-static int rpmhpd_send_corner(struct rpmhpd *pd, int state,
- unsigned int corner, bool sync)
-{
- struct tcs_cmd cmd = {
- .addr = pd->addr,
- .data = corner,
- };
-
- /*
- * Wait for an ack only when we are increasing the
- * perf state of the power domain
- */
- if (sync)
- return rpmh_write(pd->dev, state, &cmd, 1);
- else
- return rpmh_write_async(pd->dev, state, &cmd, 1);
-}
-
-static void to_active_sleep(struct rpmhpd *pd, unsigned int corner,
- unsigned int *active, unsigned int *sleep)
-{
- *active = corner;
-
- if (pd->active_only)
- *sleep = 0;
- else
- *sleep = *active;
-}
-
-/*
- * This function is used to aggregate the votes across the active only
- * resources and its peers. The aggregated votes are sent to RPMh as
- * ACTIVE_ONLY votes (which take effect immediately), as WAKE_ONLY votes
- * (applied by RPMh on system wakeup) and as SLEEP votes (applied by RPMh
- * on system sleep).
- * We send ACTIVE_ONLY votes for resources without any peers. For others,
- * which have an active only peer, all 3 votes are sent.
- */
-static int rpmhpd_aggregate_corner(struct rpmhpd *pd, unsigned int corner)
-{
- int ret;
- struct rpmhpd *peer = pd->peer;
- unsigned int active_corner, sleep_corner;
- unsigned int this_active_corner = 0, this_sleep_corner = 0;
- unsigned int peer_active_corner = 0, peer_sleep_corner = 0;
-
- if (pd->state_synced) {
- to_active_sleep(pd, corner, &this_active_corner, &this_sleep_corner);
- } else {
- /* Clamp to highest corner if sync_state hasn't happened */
- this_active_corner = pd->level_count - 1;
- this_sleep_corner = pd->level_count - 1;
- }
-
- if (peer && peer->enabled)
- to_active_sleep(peer, peer->corner, &peer_active_corner,
- &peer_sleep_corner);
-
- active_corner = max(this_active_corner, peer_active_corner);
-
- ret = rpmhpd_send_corner(pd, RPMH_ACTIVE_ONLY_STATE, active_corner,
- active_corner > pd->active_corner);
- if (ret)
- return ret;
-
- pd->active_corner = active_corner;
-
- if (peer) {
- peer->active_corner = active_corner;
-
- ret = rpmhpd_send_corner(pd, RPMH_WAKE_ONLY_STATE,
- active_corner, false);
- if (ret)
- return ret;
-
- sleep_corner = max(this_sleep_corner, peer_sleep_corner);
-
- return rpmhpd_send_corner(pd, RPMH_SLEEP_STATE, sleep_corner,
- false);
- }
-
- return ret;
-}
-
-static int rpmhpd_power_on(struct generic_pm_domain *domain)
-{
- struct rpmhpd *pd = domain_to_rpmhpd(domain);
- unsigned int corner;
- int ret;
-
- mutex_lock(&rpmhpd_lock);
-
- corner = max(pd->corner, pd->enable_corner);
- ret = rpmhpd_aggregate_corner(pd, corner);
- if (!ret)
- pd->enabled = true;
-
- mutex_unlock(&rpmhpd_lock);
-
- return ret;
-}
-
-static int rpmhpd_power_off(struct generic_pm_domain *domain)
-{
- struct rpmhpd *pd = domain_to_rpmhpd(domain);
- int ret;
-
- mutex_lock(&rpmhpd_lock);
-
- ret = rpmhpd_aggregate_corner(pd, 0);
- if (!ret)
- pd->enabled = false;
-
- mutex_unlock(&rpmhpd_lock);
-
- return ret;
-}
-
-static int rpmhpd_set_performance_state(struct generic_pm_domain *domain,
- unsigned int level)
-{
- struct rpmhpd *pd = domain_to_rpmhpd(domain);
- int ret = 0, i;
-
- mutex_lock(&rpmhpd_lock);
-
- for (i = 0; i < pd->level_count; i++)
- if (level <= pd->level[i])
- break;
-
- /*
- * If the level requested is more than that supported by the
- * max corner, just set it to max anyway.
- */
- if (i == pd->level_count)
- i--;
-
- if (pd->enabled) {
- /* Ensure that the domain isn't turn off */
- if (i < pd->enable_corner)
- i = pd->enable_corner;
-
- ret = rpmhpd_aggregate_corner(pd, i);
- if (ret)
- goto out;
- }
-
- pd->corner = i;
-out:
- mutex_unlock(&rpmhpd_lock);
-
- return ret;
-}
-
-static unsigned int rpmhpd_get_performance_state(struct generic_pm_domain *genpd,
- struct dev_pm_opp *opp)
-{
- return dev_pm_opp_get_level(opp);
-}
-
-static int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd)
-{
- int i;
- const u16 *buf;
-
- buf = cmd_db_read_aux_data(rpmhpd->res_name, &rpmhpd->level_count);
- if (IS_ERR(buf))
- return PTR_ERR(buf);
-
- /* 2 bytes used for each command DB aux data entry */
- rpmhpd->level_count >>= 1;
-
- if (rpmhpd->level_count > RPMH_ARC_MAX_LEVELS)
- return -EINVAL;
-
- for (i = 0; i < rpmhpd->level_count; i++) {
- rpmhpd->level[i] = buf[i];
-
- /* Remember the first corner with non-zero level */
- if (!rpmhpd->level[rpmhpd->enable_corner] && rpmhpd->level[i])
- rpmhpd->enable_corner = i;
-
- /*
- * The AUX data may be zero padded. These 0 valued entries at
- * the end of the map must be ignored.
- */
- if (i > 0 && rpmhpd->level[i] == 0) {
- rpmhpd->level_count = i;
- break;
- }
- pr_debug("%s: ARC hlvl=%2d --> vlvl=%4u\n", rpmhpd->res_name, i,
- rpmhpd->level[i]);
- }
-
- return 0;
-}
-
-static int rpmhpd_probe(struct platform_device *pdev)
-{
- int i, ret;
- size_t num_pds;
- struct device *dev = &pdev->dev;
- struct genpd_onecell_data *data;
- struct rpmhpd **rpmhpds;
- const struct rpmhpd_desc *desc;
-
- desc = of_device_get_match_data(dev);
- if (!desc)
- return -EINVAL;
-
- rpmhpds = desc->rpmhpds;
- num_pds = desc->num_pds;
-
- data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- data->domains = devm_kcalloc(dev, num_pds, sizeof(*data->domains),
- GFP_KERNEL);
- if (!data->domains)
- return -ENOMEM;
-
- data->num_domains = num_pds;
-
- for (i = 0; i < num_pds; i++) {
- if (!rpmhpds[i])
- continue;
-
- rpmhpds[i]->dev = dev;
- rpmhpds[i]->addr = cmd_db_read_addr(rpmhpds[i]->res_name);
- if (!rpmhpds[i]->addr) {
- dev_err(dev, "Could not find RPMh address for resource %s\n",
- rpmhpds[i]->res_name);
- return -ENODEV;
- }
-
- ret = cmd_db_read_slave_id(rpmhpds[i]->res_name);
- if (ret != CMD_DB_HW_ARC) {
- dev_err(dev, "RPMh slave ID mismatch\n");
- return -EINVAL;
- }
-
- ret = rpmhpd_update_level_mapping(rpmhpds[i]);
- if (ret)
- return ret;
-
- rpmhpds[i]->pd.power_off = rpmhpd_power_off;
- rpmhpds[i]->pd.power_on = rpmhpd_power_on;
- rpmhpds[i]->pd.set_performance_state = rpmhpd_set_performance_state;
- rpmhpds[i]->pd.opp_to_performance_state = rpmhpd_get_performance_state;
- pm_genpd_init(&rpmhpds[i]->pd, NULL, true);
-
- data->domains[i] = &rpmhpds[i]->pd;
- }
-
- /* Add subdomains */
- for (i = 0; i < num_pds; i++) {
- if (!rpmhpds[i])
- continue;
- if (rpmhpds[i]->parent)
- pm_genpd_add_subdomain(rpmhpds[i]->parent,
- &rpmhpds[i]->pd);
- }
-
- return of_genpd_add_provider_onecell(pdev->dev.of_node, data);
-}
-
-static void rpmhpd_sync_state(struct device *dev)
-{
- const struct rpmhpd_desc *desc = of_device_get_match_data(dev);
- struct rpmhpd **rpmhpds = desc->rpmhpds;
- unsigned int corner;
- struct rpmhpd *pd;
- unsigned int i;
- int ret;
-
- mutex_lock(&rpmhpd_lock);
- for (i = 0; i < desc->num_pds; i++) {
- pd = rpmhpds[i];
- if (!pd)
- continue;
-
- pd->state_synced = true;
- if (pd->enabled)
- corner = max(pd->corner, pd->enable_corner);
- else
- corner = 0;
-
- ret = rpmhpd_aggregate_corner(pd, corner);
- if (ret)
- dev_err(dev, "failed to sync %s\n", pd->res_name);
- }
- mutex_unlock(&rpmhpd_lock);
-}
-
-static struct platform_driver rpmhpd_driver = {
- .driver = {
- .name = "qcom-rpmhpd",
- .of_match_table = rpmhpd_match_table,
- .suppress_bind_attrs = true,
- .sync_state = rpmhpd_sync_state,
- },
- .probe = rpmhpd_probe,
-};
-
-static int __init rpmhpd_init(void)
-{
- return platform_driver_register(&rpmhpd_driver);
-}
-core_initcall(rpmhpd_init);
-
-MODULE_DESCRIPTION("Qualcomm Technologies, Inc. RPMh Power Domain Driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c
deleted file mode 100644
index f0db6a10cf4e..000000000000
--- a/drivers/soc/qcom/rpmpd.c
+++ /dev/null
@@ -1,713 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */
-
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/pm_domain.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/pm_opp.h>
-#include <linux/soc/qcom/smd-rpm.h>
-
-#include <dt-bindings/power/qcom-rpmpd.h>
-
-#define domain_to_rpmpd(domain) container_of(domain, struct rpmpd, pd)
-
-/* Resource types:
- * RPMPD_X is X encoded as a little-endian, lower-case, ASCII string */
-#define RPMPD_SMPA 0x61706d73
-#define RPMPD_LDOA 0x616f646c
-#define RPMPD_SMPB 0x62706d73
-#define RPMPD_LDOB 0x626f646c
-#define RPMPD_RWCX 0x78637772
-#define RPMPD_RWMX 0x786d7772
-#define RPMPD_RWLC 0x636c7772
-#define RPMPD_RWLM 0x6d6c7772
-#define RPMPD_RWSC 0x63737772
-#define RPMPD_RWSM 0x6d737772
-#define RPMPD_RWGX 0x78677772
-
-/* Operation Keys */
-#define KEY_CORNER 0x6e726f63 /* corn */
-#define KEY_ENABLE 0x6e657773 /* swen */
-#define KEY_FLOOR_CORNER 0x636676 /* vfc */
-#define KEY_FLOOR_LEVEL 0x6c6676 /* vfl */
-#define KEY_LEVEL 0x6c766c76 /* vlvl */
-
-#define MAX_CORNER_RPMPD_STATE 6
-
-#define DEFINE_RPMPD_PAIR(_platform, _name, _active, r_type, r_key, \
- r_id) \
- static struct rpmpd _platform##_##_active; \
- static struct rpmpd _platform##_##_name = { \
- .pd = { .name = #_name, }, \
- .peer = &_platform##_##_active, \
- .res_type = RPMPD_##r_type, \
- .res_id = r_id, \
- .key = KEY_##r_key, \
- }; \
- static struct rpmpd _platform##_##_active = { \
- .pd = { .name = #_active, }, \
- .peer = &_platform##_##_name, \
- .active_only = true, \
- .res_type = RPMPD_##r_type, \
- .res_id = r_id, \
- .key = KEY_##r_key, \
- }
-
-#define DEFINE_RPMPD_CORNER(_platform, _name, r_type, r_id) \
- static struct rpmpd _platform##_##_name = { \
- .pd = { .name = #_name, }, \
- .res_type = RPMPD_##r_type, \
- .res_id = r_id, \
- .key = KEY_CORNER, \
- }
-
-#define DEFINE_RPMPD_LEVEL(_platform, _name, r_type, r_id) \
- static struct rpmpd _platform##_##_name = { \
- .pd = { .name = #_name, }, \
- .res_type = RPMPD_##r_type, \
- .res_id = r_id, \
- .key = KEY_LEVEL, \
- }
-
-#define DEFINE_RPMPD_VFC(_platform, _name, r_type, r_id) \
- static struct rpmpd _platform##_##_name = { \
- .pd = { .name = #_name, }, \
- .res_type = RPMPD_##r_type, \
- .res_id = r_id, \
- .key = KEY_FLOOR_CORNER, \
- }
-
-#define DEFINE_RPMPD_VFL(_platform, _name, r_type, r_id) \
- static struct rpmpd _platform##_##_name = { \
- .pd = { .name = #_name, }, \
- .res_type = RPMPD_##r_type, \
- .res_id = r_id, \
- .key = KEY_FLOOR_LEVEL, \
- }
-
-struct rpmpd_req {
- __le32 key;
- __le32 nbytes;
- __le32 value;
-};
-
-struct rpmpd {
- struct generic_pm_domain pd;
- struct rpmpd *peer;
- const bool active_only;
- unsigned int corner;
- bool enabled;
- const int res_type;
- const int res_id;
- struct qcom_smd_rpm *rpm;
- unsigned int max_state;
- __le32 key;
-};
-
-struct rpmpd_desc {
- struct rpmpd **rpmpds;
- size_t num_pds;
- unsigned int max_state;
-};
-
-static DEFINE_MUTEX(rpmpd_lock);
-
-/* mdm9607 RPM Power Domains */
-DEFINE_RPMPD_PAIR(mdm9607, vddcx, vddcx_ao, SMPA, LEVEL, 3);
-DEFINE_RPMPD_VFL(mdm9607, vddcx_vfl, SMPA, 3);
-
-DEFINE_RPMPD_PAIR(mdm9607, vddmx, vddmx_ao, LDOA, LEVEL, 12);
-DEFINE_RPMPD_VFL(mdm9607, vddmx_vfl, LDOA, 12);
-static struct rpmpd *mdm9607_rpmpds[] = {
- [MDM9607_VDDCX] = &mdm9607_vddcx,
- [MDM9607_VDDCX_AO] = &mdm9607_vddcx_ao,
- [MDM9607_VDDCX_VFL] = &mdm9607_vddcx_vfl,
- [MDM9607_VDDMX] = &mdm9607_vddmx,
- [MDM9607_VDDMX_AO] = &mdm9607_vddmx_ao,
- [MDM9607_VDDMX_VFL] = &mdm9607_vddmx_vfl,
-};
-
-static const struct rpmpd_desc mdm9607_desc = {
- .rpmpds = mdm9607_rpmpds,
- .num_pds = ARRAY_SIZE(mdm9607_rpmpds),
- .max_state = RPM_SMD_LEVEL_TURBO,
-};
-
-/* msm8226 RPM Power Domains */
-DEFINE_RPMPD_PAIR(msm8226, vddcx, vddcx_ao, SMPA, CORNER, 1);
-DEFINE_RPMPD_VFC(msm8226, vddcx_vfc, SMPA, 1);
-
-static struct rpmpd *msm8226_rpmpds[] = {
- [MSM8226_VDDCX] = &msm8226_vddcx,
- [MSM8226_VDDCX_AO] = &msm8226_vddcx_ao,
- [MSM8226_VDDCX_VFC] = &msm8226_vddcx_vfc,
-};
-
-static const struct rpmpd_desc msm8226_desc = {
- .rpmpds = msm8226_rpmpds,
- .num_pds = ARRAY_SIZE(msm8226_rpmpds),
- .max_state = MAX_CORNER_RPMPD_STATE,
-};
-
-/* msm8939 RPM Power Domains */
-DEFINE_RPMPD_PAIR(msm8939, vddmd, vddmd_ao, SMPA, CORNER, 1);
-DEFINE_RPMPD_VFC(msm8939, vddmd_vfc, SMPA, 1);
-
-DEFINE_RPMPD_PAIR(msm8939, vddcx, vddcx_ao, SMPA, CORNER, 2);
-DEFINE_RPMPD_VFC(msm8939, vddcx_vfc, SMPA, 2);
-
-DEFINE_RPMPD_PAIR(msm8939, vddmx, vddmx_ao, LDOA, CORNER, 3);
-
-static struct rpmpd *msm8939_rpmpds[] = {
- [MSM8939_VDDMDCX] = &msm8939_vddmd,
- [MSM8939_VDDMDCX_AO] = &msm8939_vddmd_ao,
- [MSM8939_VDDMDCX_VFC] = &msm8939_vddmd_vfc,
- [MSM8939_VDDCX] = &msm8939_vddcx,
- [MSM8939_VDDCX_AO] = &msm8939_vddcx_ao,
- [MSM8939_VDDCX_VFC] = &msm8939_vddcx_vfc,
- [MSM8939_VDDMX] = &msm8939_vddmx,
- [MSM8939_VDDMX_AO] = &msm8939_vddmx_ao,
-};
-
-static const struct rpmpd_desc msm8939_desc = {
- .rpmpds = msm8939_rpmpds,
- .num_pds = ARRAY_SIZE(msm8939_rpmpds),
- .max_state = MAX_CORNER_RPMPD_STATE,
-};
-
-/* msm8916 RPM Power Domains */
-DEFINE_RPMPD_PAIR(msm8916, vddcx, vddcx_ao, SMPA, CORNER, 1);
-DEFINE_RPMPD_PAIR(msm8916, vddmx, vddmx_ao, LDOA, CORNER, 3);
-
-DEFINE_RPMPD_VFC(msm8916, vddcx_vfc, SMPA, 1);
-
-static struct rpmpd *msm8916_rpmpds[] = {
- [MSM8916_VDDCX] = &msm8916_vddcx,
- [MSM8916_VDDCX_AO] = &msm8916_vddcx_ao,
- [MSM8916_VDDCX_VFC] = &msm8916_vddcx_vfc,
- [MSM8916_VDDMX] = &msm8916_vddmx,
- [MSM8916_VDDMX_AO] = &msm8916_vddmx_ao,
-};
-
-static const struct rpmpd_desc msm8916_desc = {
- .rpmpds = msm8916_rpmpds,
- .num_pds = ARRAY_SIZE(msm8916_rpmpds),
- .max_state = MAX_CORNER_RPMPD_STATE,
-};
-
-/* msm8953 RPM Power Domains */
-DEFINE_RPMPD_PAIR(msm8953, vddmd, vddmd_ao, SMPA, LEVEL, 1);
-DEFINE_RPMPD_PAIR(msm8953, vddcx, vddcx_ao, SMPA, LEVEL, 2);
-DEFINE_RPMPD_PAIR(msm8953, vddmx, vddmx_ao, SMPA, LEVEL, 7);
-
-DEFINE_RPMPD_VFL(msm8953, vddcx_vfl, SMPA, 2);
-
-static struct rpmpd *msm8953_rpmpds[] = {
- [MSM8953_VDDMD] = &msm8953_vddmd,
- [MSM8953_VDDMD_AO] = &msm8953_vddmd_ao,
- [MSM8953_VDDCX] = &msm8953_vddcx,
- [MSM8953_VDDCX_AO] = &msm8953_vddcx_ao,
- [MSM8953_VDDCX_VFL] = &msm8953_vddcx_vfl,
- [MSM8953_VDDMX] = &msm8953_vddmx,
- [MSM8953_VDDMX_AO] = &msm8953_vddmx_ao,
-};
-
-static const struct rpmpd_desc msm8953_desc = {
- .rpmpds = msm8953_rpmpds,
- .num_pds = ARRAY_SIZE(msm8953_rpmpds),
- .max_state = RPM_SMD_LEVEL_TURBO,
-};
-
-/* msm8976 RPM Power Domains */
-DEFINE_RPMPD_PAIR(msm8976, vddcx, vddcx_ao, SMPA, LEVEL, 2);
-DEFINE_RPMPD_PAIR(msm8976, vddmx, vddmx_ao, SMPA, LEVEL, 6);
-
-DEFINE_RPMPD_VFL(msm8976, vddcx_vfl, RWSC, 2);
-DEFINE_RPMPD_VFL(msm8976, vddmx_vfl, RWSM, 6);
-
-static struct rpmpd *msm8976_rpmpds[] = {
- [MSM8976_VDDCX] = &msm8976_vddcx,
- [MSM8976_VDDCX_AO] = &msm8976_vddcx_ao,
- [MSM8976_VDDCX_VFL] = &msm8976_vddcx_vfl,
- [MSM8976_VDDMX] = &msm8976_vddmx,
- [MSM8976_VDDMX_AO] = &msm8976_vddmx_ao,
- [MSM8976_VDDMX_VFL] = &msm8976_vddmx_vfl,
-};
-
-static const struct rpmpd_desc msm8976_desc = {
- .rpmpds = msm8976_rpmpds,
- .num_pds = ARRAY_SIZE(msm8976_rpmpds),
- .max_state = RPM_SMD_LEVEL_TURBO_HIGH,
-};
-
-/* msm8994 RPM Power domains */
-DEFINE_RPMPD_PAIR(msm8994, vddcx, vddcx_ao, SMPA, CORNER, 1);
-DEFINE_RPMPD_PAIR(msm8994, vddmx, vddmx_ao, SMPA, CORNER, 2);
-/* Attention! *Some* 8994 boards with pm8004 may use SMPC here! */
-DEFINE_RPMPD_CORNER(msm8994, vddgfx, SMPB, 2);
-
-DEFINE_RPMPD_VFC(msm8994, vddcx_vfc, SMPA, 1);
-DEFINE_RPMPD_VFC(msm8994, vddgfx_vfc, SMPB, 2);
-
-static struct rpmpd *msm8994_rpmpds[] = {
- [MSM8994_VDDCX] = &msm8994_vddcx,
- [MSM8994_VDDCX_AO] = &msm8994_vddcx_ao,
- [MSM8994_VDDCX_VFC] = &msm8994_vddcx_vfc,
- [MSM8994_VDDMX] = &msm8994_vddmx,
- [MSM8994_VDDMX_AO] = &msm8994_vddmx_ao,
- [MSM8994_VDDGFX] = &msm8994_vddgfx,
- [MSM8994_VDDGFX_VFC] = &msm8994_vddgfx_vfc,
-};
-
-static const struct rpmpd_desc msm8994_desc = {
- .rpmpds = msm8994_rpmpds,
- .num_pds = ARRAY_SIZE(msm8994_rpmpds),
- .max_state = MAX_CORNER_RPMPD_STATE,
-};
-
-/* msm8996 RPM Power domains */
-DEFINE_RPMPD_PAIR(msm8996, vddcx, vddcx_ao, SMPA, CORNER, 1);
-DEFINE_RPMPD_PAIR(msm8996, vddmx, vddmx_ao, SMPA, CORNER, 2);
-DEFINE_RPMPD_CORNER(msm8996, vddsscx, LDOA, 26);
-
-DEFINE_RPMPD_VFC(msm8996, vddcx_vfc, SMPA, 1);
-DEFINE_RPMPD_VFC(msm8996, vddsscx_vfc, LDOA, 26);
-
-static struct rpmpd *msm8996_rpmpds[] = {
- [MSM8996_VDDCX] = &msm8996_vddcx,
- [MSM8996_VDDCX_AO] = &msm8996_vddcx_ao,
- [MSM8996_VDDCX_VFC] = &msm8996_vddcx_vfc,
- [MSM8996_VDDMX] = &msm8996_vddmx,
- [MSM8996_VDDMX_AO] = &msm8996_vddmx_ao,
- [MSM8996_VDDSSCX] = &msm8996_vddsscx,
- [MSM8996_VDDSSCX_VFC] = &msm8996_vddsscx_vfc,
-};
-
-static const struct rpmpd_desc msm8996_desc = {
- .rpmpds = msm8996_rpmpds,
- .num_pds = ARRAY_SIZE(msm8996_rpmpds),
- .max_state = MAX_CORNER_RPMPD_STATE,
-};
-
-/* msm8998 RPM Power domains */
-DEFINE_RPMPD_PAIR(msm8998, vddcx, vddcx_ao, RWCX, LEVEL, 0);
-DEFINE_RPMPD_VFL(msm8998, vddcx_vfl, RWCX, 0);
-
-DEFINE_RPMPD_PAIR(msm8998, vddmx, vddmx_ao, RWMX, LEVEL, 0);
-DEFINE_RPMPD_VFL(msm8998, vddmx_vfl, RWMX, 0);
-
-DEFINE_RPMPD_LEVEL(msm8998, vdd_ssccx, RWSC, 0);
-DEFINE_RPMPD_VFL(msm8998, vdd_ssccx_vfl, RWSC, 0);
-
-DEFINE_RPMPD_LEVEL(msm8998, vdd_sscmx, RWSM, 0);
-DEFINE_RPMPD_VFL(msm8998, vdd_sscmx_vfl, RWSM, 0);
-
-static struct rpmpd *msm8998_rpmpds[] = {
- [MSM8998_VDDCX] = &msm8998_vddcx,
- [MSM8998_VDDCX_AO] = &msm8998_vddcx_ao,
- [MSM8998_VDDCX_VFL] = &msm8998_vddcx_vfl,
- [MSM8998_VDDMX] = &msm8998_vddmx,
- [MSM8998_VDDMX_AO] = &msm8998_vddmx_ao,
- [MSM8998_VDDMX_VFL] = &msm8998_vddmx_vfl,
- [MSM8998_SSCCX] = &msm8998_vdd_ssccx,
- [MSM8998_SSCCX_VFL] = &msm8998_vdd_ssccx_vfl,
- [MSM8998_SSCMX] = &msm8998_vdd_sscmx,
- [MSM8998_SSCMX_VFL] = &msm8998_vdd_sscmx_vfl,
-};
-
-static const struct rpmpd_desc msm8998_desc = {
- .rpmpds = msm8998_rpmpds,
- .num_pds = ARRAY_SIZE(msm8998_rpmpds),
- .max_state = RPM_SMD_LEVEL_BINNING,
-};
-
-/* qcs404 RPM Power domains */
-DEFINE_RPMPD_PAIR(qcs404, vddmx, vddmx_ao, RWMX, LEVEL, 0);
-DEFINE_RPMPD_VFL(qcs404, vddmx_vfl, RWMX, 0);
-
-DEFINE_RPMPD_LEVEL(qcs404, vdd_lpicx, RWLC, 0);
-DEFINE_RPMPD_VFL(qcs404, vdd_lpicx_vfl, RWLC, 0);
-
-DEFINE_RPMPD_LEVEL(qcs404, vdd_lpimx, RWLM, 0);
-DEFINE_RPMPD_VFL(qcs404, vdd_lpimx_vfl, RWLM, 0);
-
-static struct rpmpd *qcs404_rpmpds[] = {
- [QCS404_VDDMX] = &qcs404_vddmx,
- [QCS404_VDDMX_AO] = &qcs404_vddmx_ao,
- [QCS404_VDDMX_VFL] = &qcs404_vddmx_vfl,
- [QCS404_LPICX] = &qcs404_vdd_lpicx,
- [QCS404_LPICX_VFL] = &qcs404_vdd_lpicx_vfl,
- [QCS404_LPIMX] = &qcs404_vdd_lpimx,
- [QCS404_LPIMX_VFL] = &qcs404_vdd_lpimx_vfl,
-};
-
-static const struct rpmpd_desc qcs404_desc = {
- .rpmpds = qcs404_rpmpds,
- .num_pds = ARRAY_SIZE(qcs404_rpmpds),
- .max_state = RPM_SMD_LEVEL_BINNING,
-};
-
-/* sdm660 RPM Power domains */
-DEFINE_RPMPD_PAIR(sdm660, vddcx, vddcx_ao, RWCX, LEVEL, 0);
-DEFINE_RPMPD_VFL(sdm660, vddcx_vfl, RWCX, 0);
-
-DEFINE_RPMPD_PAIR(sdm660, vddmx, vddmx_ao, RWMX, LEVEL, 0);
-DEFINE_RPMPD_VFL(sdm660, vddmx_vfl, RWMX, 0);
-
-DEFINE_RPMPD_LEVEL(sdm660, vdd_ssccx, RWLC, 0);
-DEFINE_RPMPD_VFL(sdm660, vdd_ssccx_vfl, RWLC, 0);
-
-DEFINE_RPMPD_LEVEL(sdm660, vdd_sscmx, RWLM, 0);
-DEFINE_RPMPD_VFL(sdm660, vdd_sscmx_vfl, RWLM, 0);
-
-static struct rpmpd *sdm660_rpmpds[] = {
- [SDM660_VDDCX] = &sdm660_vddcx,
- [SDM660_VDDCX_AO] = &sdm660_vddcx_ao,
- [SDM660_VDDCX_VFL] = &sdm660_vddcx_vfl,
- [SDM660_VDDMX] = &sdm660_vddmx,
- [SDM660_VDDMX_AO] = &sdm660_vddmx_ao,
- [SDM660_VDDMX_VFL] = &sdm660_vddmx_vfl,
- [SDM660_SSCCX] = &sdm660_vdd_ssccx,
- [SDM660_SSCCX_VFL] = &sdm660_vdd_ssccx_vfl,
- [SDM660_SSCMX] = &sdm660_vdd_sscmx,
- [SDM660_SSCMX_VFL] = &sdm660_vdd_sscmx_vfl,
-};
-
-static const struct rpmpd_desc sdm660_desc = {
- .rpmpds = sdm660_rpmpds,
- .num_pds = ARRAY_SIZE(sdm660_rpmpds),
- .max_state = RPM_SMD_LEVEL_TURBO,
-};
-
-/* sm4250/6115 RPM Power domains */
-DEFINE_RPMPD_PAIR(sm6115, vddcx, vddcx_ao, RWCX, LEVEL, 0);
-DEFINE_RPMPD_VFL(sm6115, vddcx_vfl, RWCX, 0);
-
-DEFINE_RPMPD_PAIR(sm6115, vddmx, vddmx_ao, RWMX, LEVEL, 0);
-DEFINE_RPMPD_VFL(sm6115, vddmx_vfl, RWMX, 0);
-
-DEFINE_RPMPD_LEVEL(sm6115, vdd_lpi_cx, RWLC, 0);
-DEFINE_RPMPD_LEVEL(sm6115, vdd_lpi_mx, RWLM, 0);
-
-static struct rpmpd *sm6115_rpmpds[] = {
- [SM6115_VDDCX] = &sm6115_vddcx,
- [SM6115_VDDCX_AO] = &sm6115_vddcx_ao,
- [SM6115_VDDCX_VFL] = &sm6115_vddcx_vfl,
- [SM6115_VDDMX] = &sm6115_vddmx,
- [SM6115_VDDMX_AO] = &sm6115_vddmx_ao,
- [SM6115_VDDMX_VFL] = &sm6115_vddmx_vfl,
- [SM6115_VDD_LPI_CX] = &sm6115_vdd_lpi_cx,
- [SM6115_VDD_LPI_MX] = &sm6115_vdd_lpi_mx,
-};
-
-static const struct rpmpd_desc sm6115_desc = {
- .rpmpds = sm6115_rpmpds,
- .num_pds = ARRAY_SIZE(sm6115_rpmpds),
- .max_state = RPM_SMD_LEVEL_TURBO_NO_CPR,
-};
-
-/* sm6125 RPM Power domains */
-DEFINE_RPMPD_PAIR(sm6125, vddcx, vddcx_ao, RWCX, LEVEL, 0);
-DEFINE_RPMPD_VFL(sm6125, vddcx_vfl, RWCX, 0);
-
-DEFINE_RPMPD_PAIR(sm6125, vddmx, vddmx_ao, RWMX, LEVEL, 0);
-DEFINE_RPMPD_VFL(sm6125, vddmx_vfl, RWMX, 0);
-
-static struct rpmpd *sm6125_rpmpds[] = {
- [SM6125_VDDCX] = &sm6125_vddcx,
- [SM6125_VDDCX_AO] = &sm6125_vddcx_ao,
- [SM6125_VDDCX_VFL] = &sm6125_vddcx_vfl,
- [SM6125_VDDMX] = &sm6125_vddmx,
- [SM6125_VDDMX_AO] = &sm6125_vddmx_ao,
- [SM6125_VDDMX_VFL] = &sm6125_vddmx_vfl,
-};
-
-static const struct rpmpd_desc sm6125_desc = {
- .rpmpds = sm6125_rpmpds,
- .num_pds = ARRAY_SIZE(sm6125_rpmpds),
- .max_state = RPM_SMD_LEVEL_BINNING,
-};
-
-DEFINE_RPMPD_PAIR(sm6375, vddgx, vddgx_ao, RWGX, LEVEL, 0);
-static struct rpmpd *sm6375_rpmpds[] = {
- [SM6375_VDDCX] = &sm6125_vddcx,
- [SM6375_VDDCX_AO] = &sm6125_vddcx_ao,
- [SM6375_VDDCX_VFL] = &sm6125_vddcx_vfl,
- [SM6375_VDDMX] = &sm6125_vddmx,
- [SM6375_VDDMX_AO] = &sm6125_vddmx_ao,
- [SM6375_VDDMX_VFL] = &sm6125_vddmx_vfl,
- [SM6375_VDDGX] = &sm6375_vddgx,
- [SM6375_VDDGX_AO] = &sm6375_vddgx_ao,
- [SM6375_VDD_LPI_CX] = &sm6115_vdd_lpi_cx,
- [SM6375_VDD_LPI_MX] = &sm6115_vdd_lpi_mx,
-};
-
-static const struct rpmpd_desc sm6375_desc = {
- .rpmpds = sm6375_rpmpds,
- .num_pds = ARRAY_SIZE(sm6375_rpmpds),
- .max_state = RPM_SMD_LEVEL_TURBO_NO_CPR,
-};
-
-static struct rpmpd *qcm2290_rpmpds[] = {
- [QCM2290_VDDCX] = &sm6115_vddcx,
- [QCM2290_VDDCX_AO] = &sm6115_vddcx_ao,
- [QCM2290_VDDCX_VFL] = &sm6115_vddcx_vfl,
- [QCM2290_VDDMX] = &sm6115_vddmx,
- [QCM2290_VDDMX_AO] = &sm6115_vddmx_ao,
- [QCM2290_VDDMX_VFL] = &sm6115_vddmx_vfl,
- [QCM2290_VDD_LPI_CX] = &sm6115_vdd_lpi_cx,
- [QCM2290_VDD_LPI_MX] = &sm6115_vdd_lpi_mx,
-};
-
-static const struct rpmpd_desc qcm2290_desc = {
- .rpmpds = qcm2290_rpmpds,
- .num_pds = ARRAY_SIZE(qcm2290_rpmpds),
- .max_state = RPM_SMD_LEVEL_TURBO_NO_CPR,
-};
-
-static struct rpmpd *sm4250_rpmpds[] = {
- [SM4250_VDDCX] = &sm6115_vddcx,
- [SM4250_VDDCX_AO] = &sm6115_vddcx_ao,
- [SM4250_VDDCX_VFL] = &sm6115_vddcx_vfl,
- [SM4250_VDDMX] = &sm6115_vddmx,
- [SM4250_VDDMX_AO] = &sm6115_vddmx_ao,
- [SM4250_VDDMX_VFL] = &sm6115_vddmx_vfl,
- [SM4250_VDD_LPI_CX] = &sm6115_vdd_lpi_cx,
- [SM4250_VDD_LPI_MX] = &sm6115_vdd_lpi_mx,
-};
-
-static const struct rpmpd_desc sm4250_desc = {
- .rpmpds = sm4250_rpmpds,
- .num_pds = ARRAY_SIZE(sm4250_rpmpds),
- .max_state = RPM_SMD_LEVEL_TURBO_NO_CPR,
-};
-
-static const struct of_device_id rpmpd_match_table[] = {
- { .compatible = "qcom,mdm9607-rpmpd", .data = &mdm9607_desc },
- { .compatible = "qcom,msm8226-rpmpd", .data = &msm8226_desc },
- { .compatible = "qcom,msm8909-rpmpd", .data = &msm8916_desc },
- { .compatible = "qcom,msm8916-rpmpd", .data = &msm8916_desc },
- { .compatible = "qcom,msm8939-rpmpd", .data = &msm8939_desc },
- { .compatible = "qcom,msm8953-rpmpd", .data = &msm8953_desc },
- { .compatible = "qcom,msm8976-rpmpd", .data = &msm8976_desc },
- { .compatible = "qcom,msm8994-rpmpd", .data = &msm8994_desc },
- { .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc },
- { .compatible = "qcom,msm8998-rpmpd", .data = &msm8998_desc },
- { .compatible = "qcom,qcm2290-rpmpd", .data = &qcm2290_desc },
- { .compatible = "qcom,qcs404-rpmpd", .data = &qcs404_desc },
- { .compatible = "qcom,sdm660-rpmpd", .data = &sdm660_desc },
- { .compatible = "qcom,sm4250-rpmpd", .data = &sm4250_desc },
- { .compatible = "qcom,sm6115-rpmpd", .data = &sm6115_desc },
- { .compatible = "qcom,sm6125-rpmpd", .data = &sm6125_desc },
- { .compatible = "qcom,sm6375-rpmpd", .data = &sm6375_desc },
- { }
-};
-MODULE_DEVICE_TABLE(of, rpmpd_match_table);
-
-static int rpmpd_send_enable(struct rpmpd *pd, bool enable)
-{
- struct rpmpd_req req = {
- .key = KEY_ENABLE,
- .nbytes = cpu_to_le32(sizeof(u32)),
- .value = cpu_to_le32(enable),
- };
-
- return qcom_rpm_smd_write(pd->rpm, QCOM_SMD_RPM_ACTIVE_STATE,
- pd->res_type, pd->res_id, &req, sizeof(req));
-}
-
-static int rpmpd_send_corner(struct rpmpd *pd, int state, unsigned int corner)
-{
- struct rpmpd_req req = {
- .key = pd->key,
- .nbytes = cpu_to_le32(sizeof(u32)),
- .value = cpu_to_le32(corner),
- };
-
- return qcom_rpm_smd_write(pd->rpm, state, pd->res_type, pd->res_id,
- &req, sizeof(req));
-};
-
-static void to_active_sleep(struct rpmpd *pd, unsigned int corner,
- unsigned int *active, unsigned int *sleep)
-{
- *active = corner;
-
- if (pd->active_only)
- *sleep = 0;
- else
- *sleep = *active;
-}
-
-static int rpmpd_aggregate_corner(struct rpmpd *pd)
-{
- int ret;
- struct rpmpd *peer = pd->peer;
- unsigned int active_corner, sleep_corner;
- unsigned int this_active_corner = 0, this_sleep_corner = 0;
- unsigned int peer_active_corner = 0, peer_sleep_corner = 0;
-
- to_active_sleep(pd, pd->corner, &this_active_corner, &this_sleep_corner);
-
- if (peer && peer->enabled)
- to_active_sleep(peer, peer->corner, &peer_active_corner,
- &peer_sleep_corner);
-
- active_corner = max(this_active_corner, peer_active_corner);
-
- ret = rpmpd_send_corner(pd, QCOM_SMD_RPM_ACTIVE_STATE, active_corner);
- if (ret)
- return ret;
-
- sleep_corner = max(this_sleep_corner, peer_sleep_corner);
-
- return rpmpd_send_corner(pd, QCOM_SMD_RPM_SLEEP_STATE, sleep_corner);
-}
-
-static int rpmpd_power_on(struct generic_pm_domain *domain)
-{
- int ret;
- struct rpmpd *pd = domain_to_rpmpd(domain);
-
- mutex_lock(&rpmpd_lock);
-
- ret = rpmpd_send_enable(pd, true);
- if (ret)
- goto out;
-
- pd->enabled = true;
-
- if (pd->corner)
- ret = rpmpd_aggregate_corner(pd);
-
-out:
- mutex_unlock(&rpmpd_lock);
-
- return ret;
-}
-
-static int rpmpd_power_off(struct generic_pm_domain *domain)
-{
- int ret;
- struct rpmpd *pd = domain_to_rpmpd(domain);
-
- mutex_lock(&rpmpd_lock);
-
- ret = rpmpd_send_enable(pd, false);
- if (!ret)
- pd->enabled = false;
-
- mutex_unlock(&rpmpd_lock);
-
- return ret;
-}
-
-static int rpmpd_set_performance(struct generic_pm_domain *domain,
- unsigned int state)
-{
- int ret = 0;
- struct rpmpd *pd = domain_to_rpmpd(domain);
-
- if (state > pd->max_state)
- state = pd->max_state;
-
- mutex_lock(&rpmpd_lock);
-
- pd->corner = state;
-
- /* Always send updates for vfc and vfl */
- if (!pd->enabled && pd->key != KEY_FLOOR_CORNER &&
- pd->key != KEY_FLOOR_LEVEL)
- goto out;
-
- ret = rpmpd_aggregate_corner(pd);
-
-out:
- mutex_unlock(&rpmpd_lock);
-
- return ret;
-}
-
-static unsigned int rpmpd_get_performance(struct generic_pm_domain *genpd,
- struct dev_pm_opp *opp)
-{
- return dev_pm_opp_get_level(opp);
-}
-
-static int rpmpd_probe(struct platform_device *pdev)
-{
- int i;
- size_t num;
- struct genpd_onecell_data *data;
- struct qcom_smd_rpm *rpm;
- struct rpmpd **rpmpds;
- const struct rpmpd_desc *desc;
-
- rpm = dev_get_drvdata(pdev->dev.parent);
- if (!rpm) {
- dev_err(&pdev->dev, "Unable to retrieve handle to RPM\n");
- return -ENODEV;
- }
-
- desc = of_device_get_match_data(&pdev->dev);
- if (!desc)
- return -EINVAL;
-
- rpmpds = desc->rpmpds;
- num = desc->num_pds;
-
- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- data->domains = devm_kcalloc(&pdev->dev, num, sizeof(*data->domains),
- GFP_KERNEL);
- if (!data->domains)
- return -ENOMEM;
-
- data->num_domains = num;
-
- for (i = 0; i < num; i++) {
- if (!rpmpds[i]) {
- dev_warn(&pdev->dev, "rpmpds[] with empty entry at index=%d\n",
- i);
- continue;
- }
-
- rpmpds[i]->rpm = rpm;
- rpmpds[i]->max_state = desc->max_state;
- rpmpds[i]->pd.power_off = rpmpd_power_off;
- rpmpds[i]->pd.power_on = rpmpd_power_on;
- rpmpds[i]->pd.set_performance_state = rpmpd_set_performance;
- rpmpds[i]->pd.opp_to_performance_state = rpmpd_get_performance;
- pm_genpd_init(&rpmpds[i]->pd, NULL, true);
-
- data->domains[i] = &rpmpds[i]->pd;
- }
-
- return of_genpd_add_provider_onecell(pdev->dev.of_node, data);
-}
-
-static struct platform_driver rpmpd_driver = {
- .driver = {
- .name = "qcom-rpmpd",
- .of_match_table = rpmpd_match_table,
- .suppress_bind_attrs = true,
- },
- .probe = rpmpd_probe,
-};
-
-static int __init rpmpd_init(void)
-{
- return platform_driver_register(&rpmpd_driver);
-}
-core_initcall(rpmpd_init);
-
-MODULE_DESCRIPTION("Qualcomm Technologies, Inc. RPM Power Domain Driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c
index 7e3b6a7ea34c..f2b3e02abdf1 100644
--- a/drivers/soc/qcom/smd-rpm.c
+++ b/drivers/soc/qcom/smd-rpm.c
@@ -19,7 +19,6 @@
/**
* struct qcom_smd_rpm - state of the rpm device driver
* @rpm_channel: reference to the smd channel
- * @icc: interconnect proxy device
* @dev: rpm device
* @ack: completion for acks
* @lock: mutual exclusion around the send/complete pair
@@ -27,7 +26,6 @@
*/
struct qcom_smd_rpm {
struct rpmsg_endpoint *rpm_channel;
- struct platform_device *icc;
struct device *dev;
struct completion ack;
@@ -113,7 +111,7 @@ int qcom_rpm_smd_write(struct qcom_smd_rpm *rpm,
if (WARN_ON(size >= 256))
return -EINVAL;
- pkt = kmalloc(size, GFP_KERNEL);
+ pkt = kmalloc(size, GFP_ATOMIC);
if (!pkt)
return -ENOMEM;
@@ -144,7 +142,7 @@ out:
mutex_unlock(&rpm->lock);
return ret;
}
-EXPORT_SYMBOL(qcom_rpm_smd_write);
+EXPORT_SYMBOL_GPL(qcom_rpm_smd_write);
static int qcom_smd_rpm_callback(struct rpmsg_device *rpdev,
void *data,
@@ -197,7 +195,6 @@ static int qcom_smd_rpm_callback(struct rpmsg_device *rpdev,
static int qcom_smd_rpm_probe(struct rpmsg_device *rpdev)
{
struct qcom_smd_rpm *rpm;
- int ret;
rpm = devm_kzalloc(&rpdev->dev, sizeof(*rpm), GFP_KERNEL);
if (!rpm)
@@ -210,29 +207,24 @@ static int qcom_smd_rpm_probe(struct rpmsg_device *rpdev)
rpm->rpm_channel = rpdev->ept;
dev_set_drvdata(&rpdev->dev, rpm);
- rpm->icc = platform_device_register_data(&rpdev->dev, "icc_smd_rpm", -1,
- NULL, 0);
- if (IS_ERR(rpm->icc))
- return PTR_ERR(rpm->icc);
-
- ret = of_platform_populate(rpdev->dev.of_node, NULL, NULL, &rpdev->dev);
- if (ret)
- platform_device_unregister(rpm->icc);
-
- return ret;
+ return of_platform_populate(rpdev->dev.of_node, NULL, NULL, &rpdev->dev);
}
static void qcom_smd_rpm_remove(struct rpmsg_device *rpdev)
{
- struct qcom_smd_rpm *rpm = dev_get_drvdata(&rpdev->dev);
-
- platform_device_unregister(rpm->icc);
of_platform_depopulate(&rpdev->dev);
}
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" },
diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c
index 4f163d62942c..fef840b54574 100644
--- a/drivers/soc/qcom/smem.c
+++ b/drivers/soc/qcom/smem.c
@@ -14,6 +14,7 @@
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/soc/qcom/smem.h>
+#include <linux/soc/qcom/socinfo.h>
/*
* The Qualcomm shared memory system is a allocate only heap structure that
@@ -85,7 +86,7 @@
#define SMEM_GLOBAL_HOST 0xfffe
/* Max number of processors/hosts in a system */
-#define SMEM_HOST_COUNT 15
+#define SMEM_HOST_COUNT 25
/**
* struct smem_proc_comm - proc_comm communication struct (legacy)
@@ -284,7 +285,7 @@ struct qcom_smem {
struct smem_partition partitions[SMEM_HOST_COUNT];
unsigned num_regions;
- struct smem_region regions[];
+ struct smem_region regions[] __counted_by(num_regions);
};
static void *
@@ -352,12 +353,53 @@ static void *cached_entry_to_item(struct smem_private_entry *e)
return p - le32_to_cpu(e->size);
}
-/* Pointer to the one and only smem handle */
-static struct qcom_smem *__smem;
+/*
+ * Pointer to the one and only smem handle.
+ * Init to -EPROBE_DEFER to signal SMEM still has to be probed.
+ * Can be set to -ENODEV if SMEM is not initialized by SBL.
+ */
+static struct qcom_smem *__smem = INIT_ERR_PTR(-EPROBE_DEFER);
/* 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
+ *
+ * Return: true if SMEM is available, false otherwise.
+ */
+bool qcom_smem_is_available(void)
+{
+ return !!__smem;
+}
+EXPORT_SYMBOL_GPL(qcom_smem_is_available);
+
static int qcom_smem_alloc_private(struct qcom_smem *smem,
struct smem_partition *part,
unsigned item,
@@ -461,6 +503,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)
{
@@ -468,8 +512,8 @@ int qcom_smem_alloc(unsigned host, unsigned item, size_t size)
unsigned long flags;
int ret;
- if (!__smem)
- return -EPROBE_DEFER;
+ if (IS_ERR(__smem))
+ return PTR_ERR(__smem);
if (item < SMEM_ITEM_LAST_FIXED) {
dev_err(__smem->dev,
@@ -477,7 +521,7 @@ int qcom_smem_alloc(unsigned host, unsigned item, size_t size)
return -EINVAL;
}
- if (WARN_ON(item >= __smem->item_count))
+ if (item >= __smem->item_count)
return -EINVAL;
ret = hwspin_lock_timeout_irqsave(__smem->hwlock,
@@ -500,7 +544,7 @@ int qcom_smem_alloc(unsigned host, unsigned item, size_t size)
return ret;
}
-EXPORT_SYMBOL(qcom_smem_alloc);
+EXPORT_SYMBOL_GPL(qcom_smem_alloc);
static void *qcom_smem_get_global(struct qcom_smem *smem,
unsigned item,
@@ -639,26 +683,20 @@ 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);
+ void *ptr;
- if (!__smem)
- return ptr;
+ if (IS_ERR(__smem))
+ return __smem;
- if (WARN_ON(item >= __smem->item_count))
+ if (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);
@@ -669,12 +707,9 @@ 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(qcom_smem_get);
+EXPORT_SYMBOL_GPL(qcom_smem_get);
/**
* qcom_smem_get_free_space() - retrieve amount of free space in a partition
@@ -682,6 +717,8 @@ EXPORT_SYMBOL(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)
{
@@ -690,8 +727,8 @@ int qcom_smem_get_free_space(unsigned host)
struct smem_header *header;
unsigned ret;
- if (!__smem)
- return -EPROBE_DEFER;
+ if (IS_ERR(__smem))
+ return PTR_ERR(__smem);
if (host < SMEM_HOST_COUNT && __smem->partitions[host].virt_base) {
part = &__smem->partitions[host];
@@ -719,11 +756,11 @@ int qcom_smem_get_free_space(unsigned host)
return ret;
}
-EXPORT_SYMBOL(qcom_smem_get_free_space);
+EXPORT_SYMBOL_GPL(qcom_smem_get_free_space);
static bool addr_in_range(void __iomem *base, size_t size, void *addr)
{
- return base && (addr >= base && addr < base + size);
+ return base && ((void __iomem *)addr >= base && (void __iomem *)addr < base + size);
}
/**
@@ -731,7 +768,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)
{
@@ -770,7 +807,62 @@ phys_addr_t qcom_smem_virt_to_phys(void *p)
return 0;
}
-EXPORT_SYMBOL(qcom_smem_virt_to_phys);
+EXPORT_SYMBOL_GPL(qcom_smem_virt_to_phys);
+
+/**
+ * qcom_smem_get_soc_id() - return the SoC ID
+ * @id: On success, we return the SoC ID here.
+ *
+ * Look up SoC ID from HW/SW build ID and return it.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int qcom_smem_get_soc_id(u32 *id)
+{
+ struct socinfo *info;
+
+ info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_HW_SW_BUILD_ID, NULL);
+ if (IS_ERR(info))
+ return PTR_ERR(info);
+
+ *id = __le32_to_cpu(info->id);
+
+ return 0;
+}
+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)
{
@@ -810,7 +902,7 @@ static u32 qcom_smem_get_item_count(struct qcom_smem *smem)
if (IS_ERR_OR_NULL(ptable))
return SMEM_ITEM_COUNT;
- info = (struct smem_info *)&ptable->entry[ptable->num_entries];
+ info = (struct smem_info *)&ptable->entry[le32_to_cpu(ptable->num_entries)];
if (memcmp(info->magic, SMEM_INFO_MAGIC, sizeof(info->magic)))
return SMEM_ITEM_COUNT;
@@ -1036,7 +1128,6 @@ static int qcom_smem_probe(struct platform_device *pdev)
struct reserved_mem *rmem;
struct qcom_smem *smem;
unsigned long flags;
- size_t array_size;
int num_regions;
int hwlock_id;
u32 version;
@@ -1045,11 +1136,11 @@ static int qcom_smem_probe(struct platform_device *pdev)
int i;
num_regions = 1;
- if (of_find_property(pdev->dev.of_node, "qcom,rpm-msg-ram", NULL))
+ if (of_property_present(pdev->dev.of_node, "qcom,rpm-msg-ram"))
num_regions++;
- array_size = num_regions * sizeof(struct smem_region);
- smem = devm_kzalloc(&pdev->dev, sizeof(*smem) + array_size, GFP_KERNEL);
+ smem = devm_kzalloc(&pdev->dev, struct_size(smem, regions, num_regions),
+ GFP_KERNEL);
if (!smem)
return -ENOMEM;
@@ -1094,18 +1185,16 @@ static int qcom_smem_probe(struct platform_device *pdev)
header = smem->regions[0].virt_base;
if (le32_to_cpu(header->initialized) != 1 ||
le32_to_cpu(header->reserved)) {
- dev_err(&pdev->dev, "SMEM is not initialized by SBL\n");
- return -EINVAL;
+ __smem = ERR_PTR(-ENODEV);
+ return dev_err_probe(&pdev->dev, PTR_ERR(__smem), "SMEM is not initialized by SBL\n");
}
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);
+ smem->hwlock = devm_hwspin_lock_request_specific(&pdev->dev, hwlock_id);
if (!smem->hwlock)
return -ENXIO;
@@ -1154,14 +1243,11 @@ static int qcom_smem_probe(struct platform_device *pdev)
return 0;
}
-static int qcom_smem_remove(struct platform_device *pdev)
+static void qcom_smem_remove(struct platform_device *pdev)
{
platform_device_unregister(__smem->socinfo);
- hwspin_lock_free(__smem->hwlock);
__smem = NULL;
-
- return 0;
}
static const struct of_device_id 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 e9c8030d50ee..cb515c2340c1 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,
@@ -381,7 +399,7 @@ static int qcom_smp2p_inbound_entry(struct qcom_smp2p *smp2p,
struct smp2p_entry *entry,
struct device_node *node)
{
- entry->domain = irq_domain_add_linear(node, 32, &smp2p_irq_ops, entry);
+ entry->domain = irq_domain_create_linear(of_fwnode_handle(node), 32, &smp2p_irq_ops, entry);
if (!entry->domain) {
dev_err(smp2p->dev, "failed to add irq_domain\n");
return -ENOMEM;
@@ -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;
@@ -559,7 +575,7 @@ static int qcom_smp2p_probe(struct platform_device *pdev)
smp2p->mbox_client.knows_txdone = true;
smp2p->mbox_chan = mbox_request_channel(&smp2p->mbox_client, 0);
if (IS_ERR(smp2p->mbox_chan)) {
- if (PTR_ERR(smp2p->mbox_chan) != -ENODEV)
+ if (PTR_ERR(smp2p->mbox_chan) != -ENOENT)
return PTR_ERR(smp2p->mbox_chan);
smp2p->mbox_chan = NULL;
@@ -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;
@@ -660,7 +669,7 @@ report_read_failure:
return -EINVAL;
}
-static int qcom_smp2p_remove(struct platform_device *pdev)
+static void qcom_smp2p_remove(struct platform_device *pdev)
{
struct qcom_smp2p *smp2p = platform_get_drvdata(pdev);
struct smp2p_entry *entry;
@@ -676,8 +685,6 @@ static int qcom_smp2p_remove(struct platform_device *pdev)
mbox_free_channel(smp2p->mbox_chan);
smp2p->out->valid_entries = 0;
-
- return 0;
}
static const struct of_device_id qcom_smp2p_of_match[] = {
diff --git a/drivers/soc/qcom/smsm.c b/drivers/soc/qcom/smsm.c
index 3e8994d6110e..021e9d1f61dc 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
@@ -421,7 +456,7 @@ static int smsm_inbound_entry(struct qcom_smsm *smsm,
return ret;
}
- entry->domain = irq_domain_add_linear(node, 32, &smsm_irq_ops, entry);
+ entry->domain = irq_domain_create_linear(of_fwnode_handle(node), 32, &smsm_irq_ops, entry);
if (!entry->domain) {
dev_err(smsm->dev, "failed to add irq_domain\n");
return -ENOMEM;
@@ -452,11 +487,10 @@ static int smsm_get_size_info(struct qcom_smsm *smsm)
} *info;
info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_SMSM_SIZE_INFO, &size);
- if (IS_ERR(info) && PTR_ERR(info) != -ENOENT) {
- if (PTR_ERR(info) != -EPROBE_DEFER)
- dev_err(smsm->dev, "unable to retrieve smsm size info\n");
- return PTR_ERR(info);
- } else if (IS_ERR(info) || size != sizeof(*info)) {
+ if (IS_ERR(info) && PTR_ERR(info) != -ENOENT)
+ return dev_err_probe(smsm->dev, PTR_ERR(info),
+ "unable to retrieve smsm size info\n");
+ else if (IS_ERR(info) || size != sizeof(*info)) {
dev_warn(smsm->dev, "no smsm size info, using defaults\n");
smsm->num_entries = SMSM_DEFAULT_NUM_ENTRIES;
smsm->num_hosts = SMSM_DEFAULT_NUM_HOSTS;
@@ -510,7 +544,7 @@ static int qcom_smsm_probe(struct platform_device *pdev)
return -ENOMEM;
for_each_child_of_node(pdev->dev.of_node, local_node) {
- if (of_find_property(local_node, "#qcom,smem-state-cells", NULL))
+ if (of_property_present(local_node, "#qcom,smem-state-cells"))
break;
}
if (!local_node) {
@@ -522,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;
@@ -610,11 +652,14 @@ 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;
}
-static int qcom_smsm_remove(struct platform_device *pdev)
+static void qcom_smsm_remove(struct platform_device *pdev)
{
struct qcom_smsm *smsm = platform_get_drvdata(pdev);
unsigned id;
@@ -623,9 +668,10 @@ static int qcom_smsm_remove(struct platform_device *pdev)
if (smsm->entries[id].domain)
irq_domain_remove(smsm->entries[id].domain);
- qcom_smem_state_unregister(smsm->state);
+ for (id = 0; id < smsm->num_hosts; id++)
+ mbox_free_channel(smsm->hosts[id].mbox_chan);
- return 0;
+ qcom_smem_state_unregister(smsm->state);
}
static const struct of_device_id qcom_smsm_of_match[] = {
@@ -637,8 +683,8 @@ MODULE_DEVICE_TABLE(of, qcom_smsm_of_match);
static struct platform_driver qcom_smsm_driver = {
.probe = qcom_smsm_probe,
.remove = qcom_smsm_remove,
- .driver = {
- .name = "qcom-smsm",
+ .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 ebcbf9b9c18b..003a2304d535 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -11,36 +11,20 @@
#include <linux/random.h>
#include <linux/slab.h>
#include <linux/soc/qcom/smem.h>
+#include <linux/soc/qcom/socinfo.h>
#include <linux/string.h>
#include <linux/stringify.h>
#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)
-#define SMEM_SOCINFO_BUILD_ID_LENGTH 32
-#define SMEM_SOCINFO_CHIP_ID_LENGTH 32
-
-/*
- * SMEM item id, used to acquire handles to respective
- * SMEM region.
- */
-#define SMEM_HW_SW_BUILD_ID 137
-
#ifdef CONFIG_DEBUG_FS
#define SMEM_IMAGE_VERSION_BLOCKS_COUNT 32
#define SMEM_IMAGE_VERSION_SIZE 4096
@@ -53,26 +37,92 @@
*/
#define SMEM_IMAGE_TABLE_BOOT_INDEX 0
#define SMEM_IMAGE_TABLE_TZ_INDEX 1
+#define SMEM_IMAGE_TABLE_TZSECAPP_INDEX 2
#define SMEM_IMAGE_TABLE_RPM_INDEX 3
+#define SMEM_IMAGE_TABLE_SDI_INDEX 4
+#define SMEM_IMAGE_TABLE_HYP_INDEX 5
+#define SMEM_IMAGE_TABLE_ADSP1_INDEX 6
+#define SMEM_IMAGE_TABLE_ADSP2_INDEX 7
+#define SMEM_IMAGE_TABLE_CDSP2_INDEX 8
+#define SMEM_IMAGE_TABLE_APPSBL_INDEX 9
#define SMEM_IMAGE_TABLE_APPS_INDEX 10
#define SMEM_IMAGE_TABLE_MPSS_INDEX 11
#define SMEM_IMAGE_TABLE_ADSP_INDEX 12
#define SMEM_IMAGE_TABLE_CNSS_INDEX 13
#define SMEM_IMAGE_TABLE_VIDEO_INDEX 14
+#define SMEM_IMAGE_TABLE_DSPS_INDEX 15
+#define SMEM_IMAGE_TABLE_CDSP_INDEX 16
+#define SMEM_IMAGE_TABLE_NPU_INDEX 17
+#define SMEM_IMAGE_TABLE_WPSS_INDEX 18
+#define SMEM_IMAGE_TABLE_CDSP1_INDEX 19
+#define SMEM_IMAGE_TABLE_GPDSP_INDEX 20
+#define SMEM_IMAGE_TABLE_GPDSP1_INDEX 21
+#define SMEM_IMAGE_TABLE_SENSORPD_INDEX 22
+#define SMEM_IMAGE_TABLE_AUDIOPD_INDEX 23
+#define SMEM_IMAGE_TABLE_OEMPD_INDEX 24
+#define SMEM_IMAGE_TABLE_CHARGERPD_INDEX 25
+#define SMEM_IMAGE_TABLE_OISPD_INDEX 26
+#define SMEM_IMAGE_TABLE_SOCCP_INDEX 27
+#define SMEM_IMAGE_TABLE_TME_INDEX 28
+#define SMEM_IMAGE_TABLE_GEARVM_INDEX 29
+#define SMEM_IMAGE_TABLE_UEFI_INDEX 30
+#define SMEM_IMAGE_TABLE_CDSP3_INDEX 31
+#define SMEM_IMAGE_TABLE_AUDIOPD_ADSP1_INDEX 32
+#define SMEM_IMAGE_TABLE_AUDIOPD_ADSP2_INDEX 33
+#define SMEM_IMAGE_TABLE_DCP_INDEX 34
+#define SMEM_IMAGE_TABLE_OOBS_INDEX 35
+#define SMEM_IMAGE_TABLE_OOBNS_INDEX 36
+#define SMEM_IMAGE_TABLE_DEVCFG_INDEX 37
+#define SMEM_IMAGE_TABLE_BTPD_INDEX 38
+#define SMEM_IMAGE_TABLE_QECP_INDEX 39
+
#define SMEM_IMAGE_VERSION_TABLE 469
+#define SMEM_IMAGE_VERSION_TABLE_2 667
/*
* SMEM Image table names
*/
static const char *const socinfo_image_names[] = {
+ [SMEM_IMAGE_TABLE_ADSP1_INDEX] = "adsp1",
+ [SMEM_IMAGE_TABLE_ADSP2_INDEX] = "adsp2",
[SMEM_IMAGE_TABLE_ADSP_INDEX] = "adsp",
+ [SMEM_IMAGE_TABLE_APPSBL_INDEX] = "appsbl",
[SMEM_IMAGE_TABLE_APPS_INDEX] = "apps",
+ [SMEM_IMAGE_TABLE_AUDIOPD_INDEX] = "audiopd",
+ [SMEM_IMAGE_TABLE_AUDIOPD_ADSP1_INDEX] = "audiopd_adsp1",
+ [SMEM_IMAGE_TABLE_AUDIOPD_ADSP2_INDEX] = "audiopd_adsp2",
[SMEM_IMAGE_TABLE_BOOT_INDEX] = "boot",
+ [SMEM_IMAGE_TABLE_BTPD_INDEX] = "btpd",
+ [SMEM_IMAGE_TABLE_CDSP1_INDEX] = "cdsp1",
+ [SMEM_IMAGE_TABLE_CDSP2_INDEX] = "cdsp2",
+ [SMEM_IMAGE_TABLE_CDSP3_INDEX] = "cdsp3",
+ [SMEM_IMAGE_TABLE_CDSP_INDEX] = "cdsp",
+ [SMEM_IMAGE_TABLE_CHARGERPD_INDEX] = "chargerpd",
[SMEM_IMAGE_TABLE_CNSS_INDEX] = "cnss",
+ [SMEM_IMAGE_TABLE_DCP_INDEX] = "dcp",
+ [SMEM_IMAGE_TABLE_DEVCFG_INDEX] = "devcfg",
+ [SMEM_IMAGE_TABLE_DSPS_INDEX] = "dsps",
+ [SMEM_IMAGE_TABLE_GEARVM_INDEX] = "gearvm",
+ [SMEM_IMAGE_TABLE_GPDSP1_INDEX] = "gpdsp1",
+ [SMEM_IMAGE_TABLE_GPDSP_INDEX] = "gpdsp",
+ [SMEM_IMAGE_TABLE_HYP_INDEX] = "hyp",
[SMEM_IMAGE_TABLE_MPSS_INDEX] = "mpss",
+ [SMEM_IMAGE_TABLE_NPU_INDEX] = "npu",
+ [SMEM_IMAGE_TABLE_OEMPD_INDEX] = "oempd",
+ [SMEM_IMAGE_TABLE_OISPD_INDEX] = "oispd",
+ [SMEM_IMAGE_TABLE_OOBNS_INDEX] = "oobns",
+ [SMEM_IMAGE_TABLE_OOBS_INDEX] = "oobs",
+ [SMEM_IMAGE_TABLE_QECP_INDEX] = "qecp",
[SMEM_IMAGE_TABLE_RPM_INDEX] = "rpm",
+ [SMEM_IMAGE_TABLE_SDI_INDEX] = "sdi",
+ [SMEM_IMAGE_TABLE_SENSORPD_INDEX] = "sensorpd",
+ [SMEM_IMAGE_TABLE_SOCCP_INDEX] = "soccp",
+ [SMEM_IMAGE_TABLE_TME_INDEX] = "tme",
[SMEM_IMAGE_TABLE_TZ_INDEX] = "tz",
+ [SMEM_IMAGE_TABLE_TZSECAPP_INDEX] = "tzsecapp",
+ [SMEM_IMAGE_TABLE_UEFI_INDEX] = "uefi",
[SMEM_IMAGE_TABLE_VIDEO_INDEX] = "video",
+ [SMEM_IMAGE_TABLE_WPSS_INDEX] = "wpss",
};
static const char *const pmic_models[] = {
@@ -101,7 +151,7 @@ static const char *const pmic_models[] = {
[22] = "PM8821",
[23] = "PM8038",
[24] = "PM8005/PM8922",
- [25] = "PM8917",
+ [25] = "PM8917/PM8937",
[26] = "PM660L",
[27] = "PM660",
[30] = "PM8150",
@@ -109,69 +159,37 @@ static const char *const pmic_models[] = {
[32] = "PM8150B",
[33] = "PMK8002",
[36] = "PM8009",
+ [37] = "PMI632",
[38] = "PM8150C",
+ [40] = "PM6150",
[41] = "SMB2351",
+ [44] = "PM8008",
[45] = "PM6125",
+ [46] = "PM7250B",
[47] = "PMK8350",
[48] = "PM8350",
[49] = "PM8350C",
[50] = "PM8350B",
[51] = "PMR735A",
[52] = "PMR735B",
+ [54] = "PM6350",
+ [55] = "PM4125",
[58] = "PM8450",
[65] = "PM8010",
-};
-#endif /* CONFIG_DEBUG_FS */
-
-/* Socinfo SMEM item structure */
-struct socinfo {
- __le32 fmt;
- __le32 id;
- __le32 ver;
- char build_id[SMEM_SOCINFO_BUILD_ID_LENGTH];
- /* Version 2 */
- __le32 raw_id;
- __le32 raw_ver;
- /* Version 3 */
- __le32 hw_plat;
- /* Version 4 */
- __le32 plat_ver;
- /* Version 5 */
- __le32 accessory_chip;
- /* Version 6 */
- __le32 hw_plat_subtype;
- /* Version 7 */
- __le32 pmic_model;
- __le32 pmic_die_rev;
- /* Version 8 */
- __le32 pmic_model_1;
- __le32 pmic_die_rev_1;
- __le32 pmic_model_2;
- __le32 pmic_die_rev_2;
- /* Version 9 */
- __le32 foundry_id;
- /* Version 10 */
- __le32 serial_num;
- /* Version 11 */
- __le32 num_pmics;
- __le32 pmic_array_offset;
- /* Version 12 */
- __le32 chip_family;
- __le32 raw_device_family;
- __le32 raw_device_num;
- /* Version 13 */
- __le32 nproduct_id;
- char chip_id[SMEM_SOCINFO_CHIP_ID_LENGTH];
- /* Version 14 */
- __le32 num_clusters;
- __le32 ncluster_array_offset;
- __le32 num_defective_parts;
- __le32 ndefective_parts_array_offset;
- /* Version 15 */
- __le32 nmodem_supported;
+ [69] = "PM8550VS",
+ [70] = "PM8550VE",
+ [71] = "PM8550B",
+ [72] = "PMR735D",
+ [73] = "PM8550",
+ [74] = "PMK8550",
+ [78] = "PMM8650AU",
+ [79] = "PMM8650AU_PSAIL",
+ [80] = "PM7550",
+ [82] = "PMC8380",
+ [83] = "SMB2360",
+ [91] = "PMIV0108",
};
-#ifdef CONFIG_DEBUG_FS
struct socinfo_params {
u32 raw_device_family;
u32 hw_plat_subtype;
@@ -186,9 +204,16 @@ struct socinfo_params {
u32 nproduct_id;
u32 num_clusters;
u32 ncluster_array_offset;
- u32 num_defective_parts;
- u32 ndefective_parts_array_offset;
+ u32 num_subset_parts;
+ u32 nsubset_parts_array_offset;
u32 nmodem_supported;
+ u32 feature_code;
+ u32 pcode;
+ u32 oem_variant;
+ u32 num_func_clusters;
+ u32 boot_cluster;
+ u32 boot_core;
+ u32 raw_package_type;
};
struct smem_image_version {
@@ -214,44 +239,72 @@ struct soc_id {
};
static const struct soc_id soc_id[] = {
+ { qcom_board_id(MSM8260) },
+ { qcom_board_id(MSM8660) },
+ { qcom_board_id(APQ8060) },
{ qcom_board_id(MSM8960) },
{ qcom_board_id(APQ8064) },
+ { qcom_board_id(MSM8930) },
+ { qcom_board_id(MSM8630) },
+ { qcom_board_id(MSM8230) },
+ { qcom_board_id(APQ8030) },
+ { qcom_board_id(MSM8627) },
+ { qcom_board_id(MSM8227) },
{ qcom_board_id(MSM8660A) },
{ qcom_board_id(MSM8260A) },
{ qcom_board_id(APQ8060A) },
{ qcom_board_id(MSM8974) },
+ { qcom_board_id(MSM8225) },
+ { qcom_board_id(MSM8625) },
{ qcom_board_id(MPQ8064) },
{ qcom_board_id(MSM8960AB) },
{ qcom_board_id(APQ8060AB) },
{ qcom_board_id(MSM8260AB) },
{ qcom_board_id(MSM8660AB) },
+ { qcom_board_id(MSM8930AA) },
+ { qcom_board_id(MSM8630AA) },
+ { qcom_board_id(MSM8230AA) },
{ qcom_board_id(MSM8626) },
{ qcom_board_id(MSM8610) },
{ qcom_board_id(APQ8064AB) },
+ { qcom_board_id(MSM8930AB) },
+ { qcom_board_id(MSM8630AB) },
+ { qcom_board_id(MSM8230AB) },
+ { qcom_board_id(APQ8030AB) },
{ qcom_board_id(MSM8226) },
{ qcom_board_id(MSM8526) },
+ { qcom_board_id(APQ8030AA) },
{ qcom_board_id(MSM8110) },
{ qcom_board_id(MSM8210) },
{ qcom_board_id(MSM8810) },
{ qcom_board_id(MSM8212) },
{ qcom_board_id(MSM8612) },
{ qcom_board_id(MSM8112) },
+ { qcom_board_id(MSM8125) },
{ qcom_board_id(MSM8225Q) },
{ qcom_board_id(MSM8625Q) },
{ qcom_board_id(MSM8125Q) },
{ qcom_board_id(APQ8064AA) },
{ qcom_board_id(APQ8084) },
+ { qcom_board_id(MSM8130) },
+ { qcom_board_id(MSM8130AA) },
+ { qcom_board_id(MSM8130AB) },
+ { qcom_board_id(MSM8627AA) },
+ { qcom_board_id(MSM8227AA) },
{ qcom_board_id(APQ8074) },
{ qcom_board_id(MSM8274) },
{ qcom_board_id(MSM8674) },
+ { qcom_board_id(MDM9635) },
{ qcom_board_id_named(MSM8974PRO_AC, "MSM8974PRO-AC") },
{ qcom_board_id(MSM8126) },
{ qcom_board_id(APQ8026) },
{ qcom_board_id(MSM8926) },
+ { qcom_board_id(IPQ8062) },
+ { qcom_board_id(IPQ8064) },
+ { qcom_board_id(IPQ8066) },
+ { qcom_board_id(IPQ8068) },
{ qcom_board_id(MSM8326) },
{ qcom_board_id(MSM8916) },
- { qcom_board_id(MSM8956) },
- { qcom_board_id(MSM8976) },
{ qcom_board_id(MSM8994) },
{ qcom_board_id_named(APQ8074PRO_AA, "APQ8074PRO-AA") },
{ qcom_board_id_named(APQ8074PRO_AB, "APQ8074PRO-AB") },
@@ -273,32 +326,74 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(MSM8510) },
{ qcom_board_id(MSM8512) },
{ qcom_board_id(MSM8936) },
+ { qcom_board_id(MDM9640) },
{ qcom_board_id(MSM8939) },
{ qcom_board_id(APQ8036) },
{ qcom_board_id(APQ8039) },
+ { qcom_board_id(MSM8236) },
+ { qcom_board_id(MSM8636) },
+ { qcom_board_id(MSM8909) },
{ qcom_board_id(MSM8996) },
{ qcom_board_id(APQ8016) },
{ qcom_board_id(MSM8216) },
{ qcom_board_id(MSM8116) },
{ qcom_board_id(MSM8616) },
{ qcom_board_id(MSM8992) },
+ { qcom_board_id(APQ8092) },
{ qcom_board_id(APQ8094) },
+ { qcom_board_id(MSM8209) },
+ { qcom_board_id(MSM8208) },
+ { qcom_board_id(MDM9209) },
+ { qcom_board_id(MDM9309) },
+ { qcom_board_id(MDM9609) },
+ { qcom_board_id(MSM8239) },
+ { qcom_board_id(MSM8952) },
+ { qcom_board_id(APQ8009) },
+ { qcom_board_id(MSM8956) },
+ { qcom_board_id(MSM8929) },
+ { qcom_board_id(MSM8629) },
+ { qcom_board_id(MSM8229) },
+ { qcom_board_id(APQ8029) },
+ { qcom_board_id(APQ8056) },
+ { qcom_board_id(MSM8609) },
+ { qcom_board_id(APQ8076) },
+ { qcom_board_id(MSM8976) },
+ { qcom_board_id(IPQ8065) },
+ { qcom_board_id(IPQ8069) },
+ { qcom_board_id(MDM9650) },
+ { qcom_board_id(MDM9655) },
+ { qcom_board_id(MDM9250) },
+ { qcom_board_id(MDM9255) },
+ { qcom_board_id(MDM9350) },
+ { qcom_board_id(APQ8052) },
{ qcom_board_id(MDM9607) },
{ qcom_board_id(APQ8096) },
{ qcom_board_id(MSM8998) },
{ qcom_board_id(MSM8953) },
+ { qcom_board_id(MSM8937) },
+ { qcom_board_id(APQ8037) },
{ qcom_board_id(MDM8207) },
{ qcom_board_id(MDM9207) },
{ qcom_board_id(MDM9307) },
{ qcom_board_id(MDM9628) },
+ { qcom_board_id(MSM8909W) },
+ { qcom_board_id(APQ8009W) },
+ { qcom_board_id(MSM8996L) },
+ { qcom_board_id(MSM8917) },
{ qcom_board_id(APQ8053) },
{ qcom_board_id(MSM8996SG) },
+ { qcom_board_id(APQ8017) },
+ { qcom_board_id(MSM8217) },
+ { qcom_board_id(MSM8617) },
{ qcom_board_id(MSM8996AU) },
{ qcom_board_id(APQ8096AU) },
{ qcom_board_id(APQ8096SG) },
+ { qcom_board_id(MSM8940) },
+ { qcom_board_id(SDX201) },
{ qcom_board_id(SDM660) },
{ qcom_board_id(SDM630) },
{ qcom_board_id(APQ8098) },
+ { qcom_board_id(MSM8920) },
{ qcom_board_id(SDM845) },
{ qcom_board_id(MDM9206) },
{ qcom_board_id(IPQ8074) },
@@ -306,6 +401,9 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(SDM658) },
{ qcom_board_id(SDA658) },
{ 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) },
@@ -317,10 +415,17 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(SDM632) },
{ qcom_board_id(SDA632) },
{ qcom_board_id(SDA450) },
+ { qcom_board_id(SDM439) },
+ { qcom_board_id(SDM429) },
{ qcom_board_id(SM8250) },
{ qcom_board_id(SA8155) },
+ { qcom_board_id(SDA439) },
+ { qcom_board_id(SDA429) },
+ { qcom_board_id(SM7150) },
+ { qcom_board_id(SM7150P) },
{ qcom_board_id(IPQ8070) },
{ qcom_board_id(IPQ8071) },
+ { qcom_board_id(QM215) },
{ qcom_board_id(IPQ8072A) },
{ qcom_board_id(IPQ8074A) },
{ qcom_board_id(IPQ8076A) },
@@ -328,36 +433,95 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(SM6125) },
{ qcom_board_id(IPQ8070A) },
{ qcom_board_id(IPQ8071A) },
+ { qcom_board_id(IPQ8172) },
+ { qcom_board_id(IPQ8173) },
+ { qcom_board_id(IPQ8174) },
{ qcom_board_id(IPQ6018) },
{ qcom_board_id(IPQ6028) },
+ { qcom_board_id(SDM429W) },
{ qcom_board_id(SM4250) },
{ qcom_board_id(IPQ6000) },
{ qcom_board_id(IPQ6010) },
{ qcom_board_id(SC7180) },
{ qcom_board_id(SM6350) },
+ { qcom_board_id(QCM2150) },
+ { qcom_board_id(SDA429W) },
{ qcom_board_id(SM8350) },
+ { qcom_board_id(QCM2290) },
+ { qcom_board_id(SM7125) },
{ qcom_board_id(SM6115) },
+ { qcom_board_id(IPQ5010) },
+ { qcom_board_id(IPQ5018) },
+ { qcom_board_id(IPQ5028) },
{ qcom_board_id(SC8280XP) },
{ qcom_board_id(IPQ6005) },
{ qcom_board_id(QRB5165) },
{ qcom_board_id(SM8450) },
- { qcom_board_id(SM8550) },
{ qcom_board_id(SM7225) },
{ qcom_board_id(SA8295P) },
{ 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(QCS6490) },
+ { qcom_board_id(SM7325P) },
+ { qcom_board_id(IPQ5000) },
+ { qcom_board_id(IPQ0509) },
+ { qcom_board_id(IPQ0518) },
{ qcom_board_id(SM6375) },
+ { qcom_board_id(IPQ9514) },
+ { qcom_board_id(IPQ9550) },
+ { qcom_board_id(IPQ9554) },
+ { qcom_board_id(IPQ9570) },
+ { qcom_board_id(IPQ9574) },
+ { qcom_board_id(SM8550) },
+ { qcom_board_id(IPQ5016) },
+ { 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) },
{ qcom_board_id(QRU1062) },
+ { qcom_board_id(IPQ5332) },
+ { qcom_board_id(IPQ5322) },
+ { qcom_board_id(IPQ5312) },
+ { qcom_board_id(IPQ5302) },
+ { qcom_board_id(QCS8550) },
+ { qcom_board_id(QCM8550) },
+ { qcom_board_id(SM8750) },
+ { qcom_board_id(IPQ5300) },
+ { qcom_board_id(SM7635) },
+ { qcom_board_id(SM6650) },
+ { qcom_board_id(SM6650P) },
+ { qcom_board_id(IPQ5321) },
+ { qcom_board_id(IPQ5424) },
+ { qcom_board_id(QCM6690) },
+ { qcom_board_id(QCS6690) },
+ { qcom_board_id(SM8850) },
+ { 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)
@@ -500,7 +664,7 @@ static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo,
struct smem_image_version *versions;
struct dentry *dentry;
size_t size;
- int i;
+ int i, j;
unsigned int num_pmics;
unsigned int pmic_array_offset;
@@ -512,6 +676,41 @@ static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo,
&qcom_socinfo->info.fmt);
switch (qcom_socinfo->info.fmt) {
+ case SOCINFO_VERSION(0, 23):
+ case SOCINFO_VERSION(0, 22):
+ case SOCINFO_VERSION(0, 21):
+ case SOCINFO_VERSION(0, 20):
+ qcom_socinfo->info.raw_package_type = __le32_to_cpu(info->raw_package_type);
+ debugfs_create_u32("raw_package_type", 0444, qcom_socinfo->dbg_root,
+ &qcom_socinfo->info.raw_package_type);
+ fallthrough;
+ case SOCINFO_VERSION(0, 19):
+ qcom_socinfo->info.num_func_clusters = __le32_to_cpu(info->num_func_clusters);
+ qcom_socinfo->info.boot_cluster = __le32_to_cpu(info->boot_cluster);
+ qcom_socinfo->info.boot_core = __le32_to_cpu(info->boot_core);
+
+ debugfs_create_u32("num_func_clusters", 0444, qcom_socinfo->dbg_root,
+ &qcom_socinfo->info.num_func_clusters);
+ debugfs_create_u32("boot_cluster", 0444, qcom_socinfo->dbg_root,
+ &qcom_socinfo->info.boot_cluster);
+ debugfs_create_u32("boot_core", 0444, qcom_socinfo->dbg_root,
+ &qcom_socinfo->info.boot_core);
+ fallthrough;
+ case SOCINFO_VERSION(0, 18):
+ case SOCINFO_VERSION(0, 17):
+ qcom_socinfo->info.oem_variant = __le32_to_cpu(info->oem_variant);
+ debugfs_create_u32("oem_variant", 0444, qcom_socinfo->dbg_root,
+ &qcom_socinfo->info.oem_variant);
+ fallthrough;
+ case SOCINFO_VERSION(0, 16):
+ qcom_socinfo->info.feature_code = __le32_to_cpu(info->feature_code);
+ qcom_socinfo->info.pcode = __le32_to_cpu(info->pcode);
+
+ debugfs_create_u32("feature_code", 0444, qcom_socinfo->dbg_root,
+ &qcom_socinfo->info.feature_code);
+ debugfs_create_u32("pcode", 0444, qcom_socinfo->dbg_root,
+ &qcom_socinfo->info.pcode);
+ fallthrough;
case SOCINFO_VERSION(0, 15):
qcom_socinfo->info.nmodem_supported = __le32_to_cpu(info->nmodem_supported);
@@ -521,17 +720,18 @@ static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo,
case SOCINFO_VERSION(0, 14):
qcom_socinfo->info.num_clusters = __le32_to_cpu(info->num_clusters);
qcom_socinfo->info.ncluster_array_offset = __le32_to_cpu(info->ncluster_array_offset);
- qcom_socinfo->info.num_defective_parts = __le32_to_cpu(info->num_defective_parts);
- qcom_socinfo->info.ndefective_parts_array_offset = __le32_to_cpu(info->ndefective_parts_array_offset);
+ qcom_socinfo->info.num_subset_parts = __le32_to_cpu(info->num_subset_parts);
+ qcom_socinfo->info.nsubset_parts_array_offset =
+ __le32_to_cpu(info->nsubset_parts_array_offset);
debugfs_create_u32("num_clusters", 0444, qcom_socinfo->dbg_root,
&qcom_socinfo->info.num_clusters);
debugfs_create_u32("ncluster_array_offset", 0444, qcom_socinfo->dbg_root,
&qcom_socinfo->info.ncluster_array_offset);
- debugfs_create_u32("num_defective_parts", 0444, qcom_socinfo->dbg_root,
- &qcom_socinfo->info.num_defective_parts);
- debugfs_create_u32("ndefective_parts_array_offset", 0444, qcom_socinfo->dbg_root,
- &qcom_socinfo->info.ndefective_parts_array_offset);
+ debugfs_create_u32("num_subset_parts", 0444, qcom_socinfo->dbg_root,
+ &qcom_socinfo->info.num_subset_parts);
+ debugfs_create_u32("nsubset_parts_array_offset", 0444, qcom_socinfo->dbg_root,
+ &qcom_socinfo->info.nsubset_parts_array_offset);
fallthrough;
case SOCINFO_VERSION(0, 13):
qcom_socinfo->info.nproduct_id = __le32_to_cpu(info->nproduct_id);
@@ -616,20 +816,31 @@ static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo,
break;
}
- versions = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_IMAGE_VERSION_TABLE,
- &size);
-
- for (i = 0; i < ARRAY_SIZE(socinfo_image_names); i++) {
+ for (i = 0, j = 0; i < ARRAY_SIZE(socinfo_image_names); i++, j++) {
if (!socinfo_image_names[i])
continue;
+ if (i == 0) {
+ versions = qcom_smem_get(QCOM_SMEM_HOST_ANY,
+ SMEM_IMAGE_VERSION_TABLE,
+ &size);
+ } else if (i == 32) {
+ versions = qcom_smem_get(QCOM_SMEM_HOST_ANY,
+ SMEM_IMAGE_VERSION_TABLE_2,
+ &size);
+ if (IS_ERR(versions))
+ break;
+
+ j = 0;
+ }
+
dentry = debugfs_create_dir(socinfo_image_names[i],
qcom_socinfo->dbg_root);
- debugfs_create_file("name", 0444, dentry, &versions[i],
+ debugfs_create_file("name", 0444, dentry, &versions[j],
&qcom_image_name_ops);
- debugfs_create_file("variant", 0444, dentry, &versions[i],
+ debugfs_create_file("variant", 0444, dentry, &versions[j],
&qcom_image_variant_ops);
- debugfs_create_file("oem", 0444, dentry, &versions[i],
+ debugfs_create_file("oem", 0444, dentry, &versions[j],
&qcom_image_oem_ops);
}
}
@@ -671,10 +882,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))
@@ -690,15 +907,13 @@ static int qcom_socinfo_probe(struct platform_device *pdev)
return 0;
}
-static int qcom_socinfo_remove(struct platform_device *pdev)
+static void qcom_socinfo_remove(struct platform_device *pdev)
{
struct qcom_socinfo *qs = platform_get_drvdata(pdev);
soc_device_unregister(qs->soc_dev);
socinfo_debugfs_exit(qs);
-
- return 0;
}
static struct platform_driver qcom_socinfo_driver = {
diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c
index a6cbeb40831b..f75659fff287 100644
--- a/drivers/soc/qcom/spm.c
+++ b/drivers/soc/qcom/spm.c
@@ -6,22 +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/of_address.h>
-#include <linux/of_device.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,
@@ -31,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,
@@ -171,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,
@@ -178,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,
@@ -189,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,
@@ -240,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 },
@@ -275,15 +509,13 @@ static int spm_dev_probe(struct platform_device *pdev)
{
const struct of_device_id *match_id;
struct spm_driver_data *drv;
- struct resource *res;
void __iomem *addr;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- drv->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ drv->reg_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(drv->reg_base))
return PTR_ERR(drv->reg_base);
@@ -292,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.. */
@@ -319,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;
}
@@ -336,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 12b676b20cb2..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;
@@ -38,14 +38,15 @@ TRACE_EVENT(rpmh_tx_done,
TRACE_EVENT(rpmh_send_msg,
- TP_PROTO(struct rsc_drv *d, int m, int n, u32 h,
+ TP_PROTO(struct rsc_drv *d, int m, enum rpmh_state state, int n, u32 h,
const struct tcs_cmd *c),
- TP_ARGS(d, m, n, h, c),
+ TP_ARGS(d, m, state, n, h, c),
TP_STRUCT__entry(
__string(name, d->name)
__field(int, m)
+ __field(u32, state)
__field(int, n)
__field(u32, hdr)
__field(u32, addr)
@@ -54,8 +55,9 @@ 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;
__entry->hdr = h;
__entry->addr = c->addr;
@@ -63,8 +65,14 @@ TRACE_EVENT(rpmh_send_msg,
__entry->wait = c->wait;
),
- TP_printk("%s: send-msg: tcs(m): %d cmd(n): %d msgid: %#x addr: %#x data: %#x complete: %d",
- __get_str(name), __entry->m, __entry->n, __entry->hdr,
+ TP_printk("%s: tcs(m): %d [%s] cmd(n): %d msgid: %#x addr: %#x data: %#x complete: %d",
+ __get_str(name), __entry->m,
+ __print_symbolic(__entry->state,
+ { RPMH_SLEEP_STATE, "sleep" },
+ { RPMH_WAKE_ONLY_STATE, "wake" },
+ { RPMH_ACTIVE_ONLY_STATE, "active" }),
+ __entry->n,
+ __entry->hdr,
__entry->addr, __entry->data, __entry->wait)
);
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/ubwc_config.c b/drivers/soc/qcom/ubwc_config.c
new file mode 100644
index 000000000000..1c25aaf55e52
--- /dev/null
+++ b/drivers/soc/qcom/ubwc_config.c
@@ -0,0 +1,317 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+
+#include <linux/soc/qcom/ubwc.h>
+
+static const struct qcom_ubwc_cfg_data no_ubwc_data = {
+ /* no UBWC, no HBB */
+};
+
+static const struct qcom_ubwc_cfg_data kaanapali_data = {
+ .ubwc_enc_version = UBWC_6_0,
+ .ubwc_dec_version = UBWC_6_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ .highest_bank_bit = 16,
+ .macrotile_mode = true,
+};
+
+static const struct qcom_ubwc_cfg_data msm8937_data = {
+ .ubwc_enc_version = UBWC_1_0,
+ .ubwc_dec_version = UBWC_1_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL1 |
+ UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .highest_bank_bit = 14,
+};
+
+static const struct qcom_ubwc_cfg_data msm8998_data = {
+ .ubwc_enc_version = UBWC_1_0,
+ .ubwc_dec_version = UBWC_1_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL1 |
+ UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .highest_bank_bit = 15,
+};
+
+static const struct qcom_ubwc_cfg_data qcm2290_data = {
+ /* no UBWC */
+ .highest_bank_bit = 15,
+};
+
+static const struct qcom_ubwc_cfg_data sa8775p_data = {
+ .ubwc_enc_version = UBWC_4_0,
+ .ubwc_dec_version = UBWC_4_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ .highest_bank_bit = 13,
+ .macrotile_mode = true,
+};
+
+static const struct qcom_ubwc_cfg_data sar2130p_data = {
+ .ubwc_enc_version = UBWC_3_0, /* 4.0.2 in hw */
+ .ubwc_dec_version = UBWC_4_3,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ .highest_bank_bit = 13,
+ .macrotile_mode = true,
+};
+
+static const struct qcom_ubwc_cfg_data sc7180_data = {
+ .ubwc_enc_version = UBWC_2_0,
+ .ubwc_dec_version = UBWC_2_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ .highest_bank_bit = 14,
+};
+
+static const struct qcom_ubwc_cfg_data sc7280_data = {
+ .ubwc_enc_version = UBWC_3_0,
+ .ubwc_dec_version = UBWC_4_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ .highest_bank_bit = 14,
+ .macrotile_mode = true,
+};
+
+static const struct qcom_ubwc_cfg_data sc8180x_data = {
+ .ubwc_enc_version = UBWC_3_0,
+ .ubwc_dec_version = UBWC_3_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .highest_bank_bit = 16,
+ .macrotile_mode = true,
+};
+
+static const struct qcom_ubwc_cfg_data sc8280xp_data = {
+ .ubwc_enc_version = UBWC_4_0,
+ .ubwc_dec_version = UBWC_4_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ .highest_bank_bit = 16,
+ .macrotile_mode = true,
+};
+
+static const struct qcom_ubwc_cfg_data sdm670_data = {
+ .ubwc_enc_version = UBWC_2_0,
+ .ubwc_dec_version = UBWC_2_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .highest_bank_bit = 14,
+};
+
+static const struct qcom_ubwc_cfg_data sdm845_data = {
+ .ubwc_enc_version = UBWC_2_0,
+ .ubwc_dec_version = UBWC_2_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .highest_bank_bit = 15,
+};
+
+static const struct qcom_ubwc_cfg_data sm6115_data = {
+ .ubwc_enc_version = UBWC_1_0,
+ .ubwc_dec_version = UBWC_2_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL1 |
+ UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ .highest_bank_bit = 14,
+};
+
+static const struct qcom_ubwc_cfg_data sm6125_data = {
+ .ubwc_enc_version = UBWC_1_0,
+ .ubwc_dec_version = UBWC_3_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL1 |
+ UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .highest_bank_bit = 14,
+};
+
+static const struct qcom_ubwc_cfg_data sm6150_data = {
+ .ubwc_enc_version = UBWC_2_0,
+ .ubwc_dec_version = UBWC_2_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .highest_bank_bit = 14,
+};
+
+static const struct qcom_ubwc_cfg_data sm6350_data = {
+ .ubwc_enc_version = UBWC_2_0,
+ .ubwc_dec_version = UBWC_2_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ .highest_bank_bit = 14,
+};
+
+static const struct qcom_ubwc_cfg_data sm7150_data = {
+ .ubwc_enc_version = UBWC_2_0,
+ .ubwc_dec_version = UBWC_2_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .highest_bank_bit = 14,
+};
+
+static const struct qcom_ubwc_cfg_data sm8150_data = {
+ .ubwc_enc_version = UBWC_3_0,
+ .ubwc_dec_version = UBWC_3_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .highest_bank_bit = 15,
+};
+
+static const struct qcom_ubwc_cfg_data sm8250_data = {
+ .ubwc_enc_version = UBWC_4_0,
+ .ubwc_dec_version = UBWC_4_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ /* TODO: highest_bank_bit = 15 for LP_DDR4 */
+ .highest_bank_bit = 16,
+ .macrotile_mode = true,
+};
+
+static const struct qcom_ubwc_cfg_data sm8350_data = {
+ .ubwc_enc_version = UBWC_4_0,
+ .ubwc_dec_version = UBWC_4_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ /* TODO: highest_bank_bit = 15 for LP_DDR4 */
+ .highest_bank_bit = 16,
+ .macrotile_mode = true,
+};
+
+static const struct qcom_ubwc_cfg_data sm8550_data = {
+ .ubwc_enc_version = UBWC_4_0,
+ .ubwc_dec_version = UBWC_4_3,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ /* TODO: highest_bank_bit = 15 for LP_DDR4 */
+ .highest_bank_bit = 16,
+ .macrotile_mode = true,
+};
+
+static const struct qcom_ubwc_cfg_data sm8750_data = {
+ .ubwc_enc_version = UBWC_5_0,
+ .ubwc_dec_version = UBWC_5_0,
+ .ubwc_swizzle = 6,
+ .ubwc_bank_spread = true,
+ /* TODO: highest_bank_bit = 15 for LP_DDR4 */
+ .highest_bank_bit = 16,
+ .macrotile_mode = true,
+};
+
+static const struct qcom_ubwc_cfg_data x1e80100_data = {
+ .ubwc_enc_version = UBWC_4_0,
+ .ubwc_dec_version = UBWC_4_3,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ /* TODO: highest_bank_bit = 15 for LP_DDR4 */
+ .highest_bank_bit = 16,
+ .macrotile_mode = true,
+};
+
+static const struct qcom_ubwc_cfg_data glymur_data = {
+ .ubwc_enc_version = UBWC_5_0,
+ .ubwc_dec_version = UBWC_5_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ /* TODO: highest_bank_bit = 15 for LP_DDR4 */
+ .highest_bank_bit = 16,
+ .macrotile_mode = true,
+};
+
+static const struct of_device_id qcom_ubwc_configs[] __maybe_unused = {
+ { .compatible = "qcom,apq8016", .data = &no_ubwc_data },
+ { .compatible = "qcom,apq8026", .data = &no_ubwc_data },
+ { .compatible = "qcom,apq8074", .data = &no_ubwc_data },
+ { .compatible = "qcom,apq8096", .data = &msm8998_data },
+ { .compatible = "qcom,kaanapali", .data = &kaanapali_data, },
+ { .compatible = "qcom,glymur", .data = &glymur_data},
+ { .compatible = "qcom,msm8226", .data = &no_ubwc_data },
+ { .compatible = "qcom,msm8916", .data = &no_ubwc_data },
+ { .compatible = "qcom,msm8917", .data = &no_ubwc_data },
+ { .compatible = "qcom,msm8937", .data = &msm8937_data },
+ { .compatible = "qcom,msm8929", .data = &no_ubwc_data },
+ { .compatible = "qcom,msm8939", .data = &no_ubwc_data },
+ { .compatible = "qcom,msm8953", .data = &msm8937_data },
+ { .compatible = "qcom,msm8956", .data = &no_ubwc_data },
+ { .compatible = "qcom,msm8974", .data = &no_ubwc_data },
+ { .compatible = "qcom,msm8976", .data = &no_ubwc_data },
+ { .compatible = "qcom,msm8996", .data = &msm8998_data },
+ { .compatible = "qcom,msm8998", .data = &msm8998_data },
+ { .compatible = "qcom,qcm2290", .data = &qcm2290_data, },
+ { .compatible = "qcom,qcm6490", .data = &sc7280_data, },
+ { .compatible = "qcom,qcs8300", .data = &sc8280xp_data, },
+ { .compatible = "qcom,sa8155p", .data = &sm8150_data, },
+ { .compatible = "qcom,sa8540p", .data = &sc8280xp_data, },
+ { .compatible = "qcom,sa8775p", .data = &sa8775p_data, },
+ { .compatible = "qcom,sar2130p", .data = &sar2130p_data },
+ { .compatible = "qcom,sc7180", .data = &sc7180_data },
+ { .compatible = "qcom,sc7280", .data = &sc7280_data, },
+ { .compatible = "qcom,sc8180x", .data = &sc8180x_data, },
+ { .compatible = "qcom,sc8280xp", .data = &sc8280xp_data, },
+ { .compatible = "qcom,sda660", .data = &msm8937_data },
+ { .compatible = "qcom,sdm450", .data = &msm8937_data },
+ { .compatible = "qcom,sdm630", .data = &msm8937_data },
+ { .compatible = "qcom,sdm632", .data = &msm8937_data },
+ { .compatible = "qcom,sdm636", .data = &msm8937_data },
+ { .compatible = "qcom,sdm660", .data = &msm8937_data },
+ { .compatible = "qcom,sdm670", .data = &sdm670_data, },
+ { .compatible = "qcom,sdm845", .data = &sdm845_data, },
+ { .compatible = "qcom,sm4250", .data = &sm6115_data, },
+ { .compatible = "qcom,sm6115", .data = &sm6115_data, },
+ { .compatible = "qcom,sm6125", .data = &sm6125_data, },
+ { .compatible = "qcom,sm6150", .data = &sm6150_data, },
+ { .compatible = "qcom,sm6350", .data = &sm6350_data, },
+ { .compatible = "qcom,sm6375", .data = &sm6350_data, },
+ { .compatible = "qcom,sm7125", .data = &sc7180_data },
+ { .compatible = "qcom,sm7150", .data = &sm7150_data, },
+ { .compatible = "qcom,sm7225", .data = &sm6350_data, },
+ { .compatible = "qcom,sm7325", .data = &sc7280_data, },
+ { .compatible = "qcom,sm8150", .data = &sm8150_data, },
+ { .compatible = "qcom,sm8250", .data = &sm8250_data, },
+ { .compatible = "qcom,sm8350", .data = &sm8350_data, },
+ { .compatible = "qcom,sm8450", .data = &sm8350_data, },
+ { .compatible = "qcom,sm8550", .data = &sm8550_data, },
+ { .compatible = "qcom,sm8650", .data = &sm8550_data, },
+ { .compatible = "qcom,sm8750", .data = &sm8750_data, },
+ { .compatible = "qcom,x1e80100", .data = &x1e80100_data, },
+ { .compatible = "qcom,x1p42100", .data = &x1e80100_data, },
+ { }
+};
+
+const struct qcom_ubwc_cfg_data *qcom_ubwc_config_get_data(void)
+{
+ const struct qcom_ubwc_cfg_data *data;
+
+ data = of_machine_get_match_data(qcom_ubwc_configs);
+ if (!data) {
+ pr_err("Couldn't find UBWC config data for this platform!\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ return data;
+}
+EXPORT_SYMBOL_GPL(qcom_ubwc_config_get_data);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("UBWC config database for QTI SoCs");
diff --git a/drivers/soc/qcom/wcnss_ctrl.c b/drivers/soc/qcom/wcnss_ctrl.c
index 2a06d631e415..62b424e90d90 100644
--- a/drivers/soc/qcom/wcnss_ctrl.c
+++ b/drivers/soc/qcom/wcnss_ctrl.c
@@ -3,10 +3,12 @@
* 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>
#include <linux/io.h>
+#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/rpmsg.h>
@@ -197,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;
@@ -205,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;
@@ -262,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;
}
@@ -286,7 +286,7 @@ struct rpmsg_endpoint *qcom_wcnss_open_channel(void *wcnss, const char *name, rp
return rpmsg_create_ept(_wcnss->channel->rpdev, cb, priv, chinfo);
}
-EXPORT_SYMBOL(qcom_wcnss_open_channel);
+EXPORT_SYMBOL_GPL(qcom_wcnss_open_channel);
static void wcnss_async_probe(struct work_struct *work)
{
@@ -354,7 +354,6 @@ static struct rpmsg_driver wcnss_ctrl_driver = {
.callback = wcnss_ctrl_smd_callback,
.drv = {
.name = "qcom_wcnss_ctrl",
- .owner = THIS_MODULE,
.of_match_table = wcnss_ctrl_of_match,
},
};
diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig
index 660498252ec5..340a1ff7e92b 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,14 @@ 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_RCAR_GEN5
+ bool
+ select ARCH_RCAR_GEN4
+
config ARCH_RMOBILE
bool
select PM
@@ -60,125 +69,144 @@ if ARM && ARCH_RENESAS
config ARCH_EMEV2
bool "ARM32 Platform support for Emma Mobile EV2"
+ default ARCH_RENESAS
select HAVE_ARM_SCU if SMP
select SYS_SUPPORTS_EM_STI
-config ARCH_R8A7794
- bool "ARM32 Platform support for R-Car E2"
- select ARCH_RCAR_GEN2
- select ARM_ERRATA_814220
- select SYSC_R8A7794
-
-config ARCH_R8A7779
- bool "ARM32 Platform support for R-Car H1"
- select ARCH_RCAR_GEN1
+config ARCH_R7S72100
+ bool "ARM32 Platform support for R7S72100 (RZ/A1H)"
+ default ARCH_RENESAS
select ARM_ERRATA_754322
- select ARM_GLOBAL_TIMER
- select HAVE_ARM_SCU if SMP
- select HAVE_ARM_TWD if SMP
- select SYSC_R8A7779
+ select PM
+ select PM_GENERIC_DOMAINS
+ select RENESAS_OSTM
+ select RENESAS_RZA1_IRQC
+ select SYS_SUPPORTS_SH_MTU2
-config ARCH_R8A7790
- bool "ARM32 Platform support for R-Car H2"
- select ARCH_RCAR_GEN2
+config ARCH_R7S9210
+ bool "ARM32 Platform support for R7S9210 (RZ/A2)"
+ default ARCH_RENESAS
+ select PM
+ select PM_GENERIC_DOMAINS
+ select RENESAS_OSTM
+ select RENESAS_RZA1_IRQC
+
+config ARCH_R8A73A4
+ bool "ARM32 Platform support for R8A73A4 (R-Mobile APE6)"
+ default ARCH_RENESAS
+ select ARCH_RMOBILE
select ARM_ERRATA_798181 if SMP
select ARM_ERRATA_814220
- select I2C
- select SYSC_R8A7790
+ select HAVE_ARM_ARCH_TIMER
+ select RENESAS_IRQC
-config ARCH_R8A7778
- bool "ARM32 Platform support for R-Car M1A"
- select ARCH_RCAR_GEN1
+config ARCH_R8A7740
+ bool "ARM32 Platform support for R8A7740 (R-Mobile A1)"
+ default ARCH_RENESAS
+ select ARCH_RMOBILE
select ARM_ERRATA_754322
+ select RENESAS_INTC_IRQPIN
-config ARCH_R8A7793
- bool "ARM32 Platform support for R-Car M2-N"
+config ARCH_R8A7742
+ bool "ARM32 Platform support for R8A7742 (RZ/G1H)"
+ default ARCH_RENESAS
select ARCH_RCAR_GEN2
select ARM_ERRATA_798181 if SMP
- select I2C
- select SYSC_R8A7791
+ select ARM_ERRATA_814220
+ select SYSC_R8A7742
-config ARCH_R8A7791
- bool "ARM32 Platform support for R-Car M2-W"
+config ARCH_R8A7743
+ bool "ARM32 Platform support for R8A7743 (RZ/G1M)"
+ default ARCH_RENESAS
select ARCH_RCAR_GEN2
select ARM_ERRATA_798181 if SMP
- select I2C
- select SYSC_R8A7791
+ select SYSC_R8A7743
-config ARCH_R8A7792
- bool "ARM32 Platform support for R-Car V2H"
+config ARCH_R8A7744
+ bool "ARM32 Platform support for R8A7744 (RZ/G1N)"
+ default ARCH_RENESAS
select ARCH_RCAR_GEN2
select ARM_ERRATA_798181 if SMP
- select SYSC_R8A7792
-
-config ARCH_R8A7740
- bool "ARM32 Platform support for R-Mobile A1"
- select ARCH_RMOBILE
- select ARM_ERRATA_754322
- select RENESAS_INTC_IRQPIN
+ select SYSC_R8A7743
-config ARCH_R8A73A4
- bool "ARM32 Platform support for R-Mobile APE6"
- select ARCH_RMOBILE
- select ARM_ERRATA_798181 if SMP
+config ARCH_R8A7745
+ bool "ARM32 Platform support for R8A7745 (RZ/G1E)"
+ default ARCH_RENESAS
+ select ARCH_RCAR_GEN2
select ARM_ERRATA_814220
- select HAVE_ARM_ARCH_TIMER
- select RENESAS_IRQC
-
-config ARCH_R7S72100
- bool "ARM32 Platform support for RZ/A1H"
- select ARM_ERRATA_754322
- select PM
- select PM_GENERIC_DOMAINS
- select RENESAS_OSTM
- select RENESAS_RZA1_IRQC
- select SYS_SUPPORTS_SH_MTU2
-
-config ARCH_R7S9210
- bool "ARM32 Platform support for RZ/A2"
- select PM
- select PM_GENERIC_DOMAINS
- select RENESAS_OSTM
- select RENESAS_RZA1_IRQC
+ select SYSC_R8A7745
config ARCH_R8A77470
- bool "ARM32 Platform support for RZ/G1C"
+ bool "ARM32 Platform support for R8A77470 (RZ/G1C)"
+ default ARCH_RENESAS
select ARCH_RCAR_GEN2
select ARM_ERRATA_814220
select SYSC_R8A77470
-config ARCH_R8A7745
- bool "ARM32 Platform support for RZ/G1E"
+config ARCH_R8A7778
+ bool "ARM32 Platform support for R8A7778 (R-Car M1A)"
+ default ARCH_RENESAS
+ select ARCH_RCAR_GEN1
+ select ARM_ERRATA_754322
+
+config ARCH_R8A7779
+ bool "ARM32 Platform support for R8A7779 (R-Car H1)"
+ default ARCH_RENESAS
+ select ARCH_RCAR_GEN1
+ select ARM_ERRATA_754322
+ select ARM_GLOBAL_TIMER
+ select HAVE_ARM_SCU if SMP
+ select HAVE_ARM_TWD if SMP
+ select SYSC_R8A7779
+
+config ARCH_R8A7790
+ bool "ARM32 Platform support for R8A7790 (R-Car H2)"
+ default ARCH_RENESAS
select ARCH_RCAR_GEN2
+ select ARM_ERRATA_798181 if SMP
select ARM_ERRATA_814220
- select SYSC_R8A7745
+ select I2C
+ select SYSC_R8A7790
-config ARCH_R8A7742
- bool "ARM32 Platform support for RZ/G1H"
+config ARCH_R8A7791
+ bool "ARM32 Platform support for R8A7791 (R-Car M2-W)"
+ default ARCH_RENESAS
select ARCH_RCAR_GEN2
select ARM_ERRATA_798181 if SMP
- select ARM_ERRATA_814220
- select SYSC_R8A7742
+ select I2C
+ select SYSC_R8A7791
-config ARCH_R8A7743
- bool "ARM32 Platform support for RZ/G1M"
+config ARCH_R8A7792
+ bool "ARM32 Platform support for R8A7792 (R-Car V2H)"
+ default ARCH_RENESAS
select ARCH_RCAR_GEN2
select ARM_ERRATA_798181 if SMP
- select SYSC_R8A7743
+ select SYSC_R8A7792
-config ARCH_R8A7744
- bool "ARM32 Platform support for RZ/G1N"
+config ARCH_R8A7793
+ bool "ARM32 Platform support for R8A7793 (R-Car M2-N)"
+ default ARCH_RENESAS
select ARCH_RCAR_GEN2
select ARM_ERRATA_798181 if SMP
- select SYSC_R8A7743
+ select I2C
+ select SYSC_R8A7791
+
+config ARCH_R8A7794
+ bool "ARM32 Platform support for R8A7794 (R-Car E2)"
+ default ARCH_RENESAS
+ select ARCH_RCAR_GEN2
+ select ARM_ERRATA_814220
+ select SYSC_R8A7794
config ARCH_R9A06G032
- bool "ARM32 Platform support for RZ/N1D"
+ bool "ARM32 Platform support for R9A06G032 (RZ/N1D)"
+ default ARCH_RENESAS
select ARCH_RZN1
select ARM_ERRATA_814220
config ARCH_SH73A0
- bool "ARM32 Platform support for SH-Mobile AG5"
+ bool "ARM32 Platform support for SH73A0 (SH-Mobile AG5)"
+ default ARCH_RENESAS
select ARCH_RMOBILE
select ARM_ERRATA_754322
select ARM_GLOBAL_TIMER
@@ -190,31 +218,41 @@ endif # ARM
if ARM64
-config ARCH_R8A77995
- bool "ARM64 Platform support for R-Car D3"
+config ARCH_R8A774A1
+ bool "ARM64 Platform support for R8A774A1 (RZ/G2M)"
+ default y if ARCH_RENESAS
select ARCH_RCAR_GEN3
- select SYSC_R8A77995
+ select SYSC_R8A774A1
help
- This enables support for the Renesas R-Car D3 SoC.
- This includes different gradings like R-Car D3e.
+ This enables support for the Renesas RZ/G2M SoC.
-config ARCH_R8A77990
- bool "ARM64 Platform support for R-Car E3"
+config ARCH_R8A774B1
+ bool "ARM64 Platform support for R8A774B1 (RZ/G2N)"
+ default y if ARCH_RENESAS
select ARCH_RCAR_GEN3
- select SYSC_R8A77990
+ select SYSC_R8A774B1
help
- This enables support for the Renesas R-Car E3 SoC.
- This includes different gradings like R-Car E3e.
+ This enables support for the Renesas RZ/G2N SoC.
-config ARCH_R8A77950
- bool "ARM64 Platform support for R-Car H3 ES1.x"
+config ARCH_R8A774C0
+ bool "ARM64 Platform support for R8A774C0 (RZ/G2E)"
+ default y if ARCH_RENESAS
select ARCH_RCAR_GEN3
- select SYSC_R8A7795
+ select SYSC_R8A774C0
help
- This enables support for the Renesas R-Car H3 SoC (revision 1.x).
+ This enables support for the Renesas RZ/G2E SoC.
+
+config ARCH_R8A774E1
+ bool "ARM64 Platform support for R8A774E1 (RZ/G2H)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN3
+ select SYSC_R8A774E1
+ help
+ This enables support for the Renesas RZ/G2H SoC.
config ARCH_R8A77951
- bool "ARM64 Platform support for R-Car H3 ES2.0+"
+ bool "ARM64 Platform support for R8A77951 (R-Car H3 ES2.0+)"
+ default y if ARCH_RENESAS
select ARCH_RCAR_GEN3
select SYSC_R8A7795
help
@@ -222,235 +260,223 @@ config ARCH_R8A77951
later).
This includes different gradings like R-Car H3e, H3e-2G, and H3Ne.
-config ARCH_R8A77965
- bool "ARM64 Platform support for R-Car M3-N"
- select ARCH_RCAR_GEN3
- select SYSC_R8A77965
- help
- This enables support for the Renesas R-Car M3-N SoC.
- This includes different gradings like R-Car M3Ne and M3Ne-2G.
-
config ARCH_R8A77960
- bool "ARM64 Platform support for R-Car M3-W"
+ bool "ARM64 Platform support for R8A77960 (R-Car M3-W)"
+ default y if ARCH_RENESAS
select ARCH_RCAR_GEN3
select SYSC_R8A77960
help
This enables support for the Renesas R-Car M3-W SoC.
config ARCH_R8A77961
- bool "ARM64 Platform support for R-Car M3-W+"
+ bool "ARM64 Platform support for R8A77961 (R-Car M3-W+)"
+ default y if ARCH_RENESAS
select ARCH_RCAR_GEN3
select SYSC_R8A77961
help
This enables support for the Renesas R-Car M3-W+ SoC.
This includes different gradings like R-Car M3e and M3e-2G.
-config ARCH_R8A779F0
- bool "ARM64 Platform support for R-Car S4-8"
+config ARCH_R8A77965
+ bool "ARM64 Platform support for R8A77965 (R-Car M3-N)"
+ default y if ARCH_RENESAS
select ARCH_RCAR_GEN3
- select SYSC_R8A779F0
+ select SYSC_R8A77965
help
- This enables support for the Renesas R-Car S4-8 SoC.
+ This enables support for the Renesas R-Car M3-N SoC.
+ This includes different gradings like R-Car M3Ne and M3Ne-2G.
+
+config ARCH_R8A77970
+ bool "ARM64 Platform support for R8A77970 (R-Car V3M)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN3
+ select SYSC_R8A77970
+ help
+ This enables support for the Renesas R-Car V3M SoC.
config ARCH_R8A77980
- bool "ARM64 Platform support for R-Car V3H"
+ bool "ARM64 Platform support for R8A77980 (R-Car V3H)"
+ default y if ARCH_RENESAS
select ARCH_RCAR_GEN3
select SYSC_R8A77980
help
This enables support for the Renesas R-Car V3H SoC.
-config ARCH_R8A77970
- bool "ARM64 Platform support for R-Car V3M"
+config ARCH_R8A77990
+ bool "ARM64 Platform support for R8A77990 (R-Car E3)"
+ default y if ARCH_RENESAS
select ARCH_RCAR_GEN3
- select SYSC_R8A77970
+ select SYSC_R8A77990
help
- This enables support for the Renesas R-Car V3M SoC.
+ This enables support for the Renesas R-Car E3 SoC.
+ This includes different gradings like R-Car E3e.
-config ARCH_R8A779A0
- bool "ARM64 Platform support for R-Car V3U"
+config ARCH_R8A77995
+ bool "ARM64 Platform support for R8A77995 (R-Car D3)"
+ default y if ARCH_RENESAS
select ARCH_RCAR_GEN3
+ select SYSC_R8A77995
+ help
+ This enables support for the Renesas R-Car D3 SoC.
+ This includes different gradings like R-Car D3e.
+
+config ARCH_R8A779A0
+ bool "ARM64 Platform support for R8A779A0 (R-Car V3U)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN4
select SYSC_R8A779A0
help
This enables support for the Renesas R-Car V3U SoC.
+config ARCH_R8A779F0
+ bool "ARM64 Platform support for R8A779F0 (R-Car S4-8)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN4
+ select SYSC_R8A779F0
+ help
+ This enables support for the Renesas R-Car S4-8 SoC.
+
config ARCH_R8A779G0
- bool "ARM64 Platform support for R-Car V4H"
- select ARCH_RCAR_GEN3
+ bool "ARM64 Platform support for R8A779G0 (R-Car V4H)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN4
select SYSC_R8A779G0
help
This enables support for the Renesas R-Car V4H SoC.
-config ARCH_R8A774C0
- bool "ARM64 Platform support for RZ/G2E"
- select ARCH_RCAR_GEN3
- select SYSC_R8A774C0
- help
- This enables support for the Renesas RZ/G2E SoC.
-
-config ARCH_R8A774E1
- bool "ARM64 Platform support for RZ/G2H"
- select ARCH_RCAR_GEN3
- select SYSC_R8A774E1
- help
- This enables support for the Renesas RZ/G2H SoC.
-
-config ARCH_R8A774A1
- bool "ARM64 Platform support for RZ/G2M"
- select ARCH_RCAR_GEN3
- select SYSC_R8A774A1
+config ARCH_R8A779H0
+ bool "ARM64 Platform support for R8A779H0 (R-Car V4M)"
+ default y if ARCH_RENESAS
+ select ARCH_RCAR_GEN4
+ select SYSC_R8A779H0
help
- This enables support for the Renesas RZ/G2M SoC.
+ This enables support for the Renesas R-Car V4M SoC.
-config ARCH_R8A774B1
- bool "ARM64 Platform support for RZ/G2N"
- select ARCH_RCAR_GEN3
- select SYSC_R8A774B1
+config ARCH_R8A78000
+ bool "ARM64 Platform support for R8A78000 (R-Car X5H)"
+ default y if ARCH_RENESAS
+ default ARCH_RENESAS
+ select ARCH_RCAR_GEN5
help
- This enables support for the Renesas RZ/G2N SoC.
+ This enables support for the Renesas R-Car X5H SoC.
config ARCH_R9A07G043
- bool "ARM64 Platform support for RZ/G2UL"
+ bool "ARM64 Platform support for R9A07G043U (RZ/G2UL)"
+ default y if ARCH_RENESAS
select ARCH_RZG2L
help
This enables support for the Renesas RZ/G2UL SoC variants.
config ARCH_R9A07G044
- bool "ARM64 Platform support for RZ/G2L"
+ bool "ARM64 Platform support for R9A07G044 (RZ/G2L)"
+ default y if ARCH_RENESAS
select ARCH_RZG2L
help
This enables support for the Renesas RZ/G2L SoC variants.
config ARCH_R9A07G054
- bool "ARM64 Platform support for RZ/V2L"
+ bool "ARM64 Platform support for R9A07G054 (RZ/V2L)"
+ default y if ARCH_RENESAS
select ARCH_RZG2L
help
This enables support for the Renesas RZ/V2L SoC variants.
+config ARCH_R9A08G045
+ bool "ARM64 Platform support for R9A08G045 (RZ/G3S)"
+ default y if ARCH_RENESAS
+ select ARCH_RZG2L
+ select SYSC_R9A08G045
+ help
+ This enables support for the Renesas RZ/G3S SoC variants.
+
config ARCH_R9A09G011
- bool "ARM64 Platform support for RZ/V2M"
+ bool "ARM64 Platform support for R9A09G011 (RZ/V2M)"
+ default y if ARCH_RENESAS
select PM
select PM_GENERIC_DOMAINS
+ select PWC_RZV2M
help
This enables support for the Renesas RZ/V2M SoC.
+config ARCH_R9A09G047
+ bool "ARM64 Platform support for R9A09G047 (RZ/G3E)"
+ default y if ARCH_RENESAS
+ select SYS_R9A09G047
+ help
+ This enables support for the Renesas RZ/G3E SoC variants.
+
+config ARCH_R9A09G056
+ bool "ARM64 Platform support for R9A09G056 (RZ/V2N)"
+ default y if ARCH_RENESAS
+ select SYS_R9A09G056
+ help
+ This enables support for the Renesas RZ/V2N SoC variants.
+
+config ARCH_R9A09G057
+ bool "ARM64 Platform support for R9A09G057 (RZ/V2H(P))"
+ default y if ARCH_RENESAS
+ select RENESAS_RZV2H_ICU
+ select SYS_R9A09G057
+ help
+ This enables support for the Renesas RZ/V2H(P) SoC variants.
+
+config ARCH_R9A09G077
+ bool "ARM64 Platform support for R9A09G077 (RZ/T2H)"
+ default y if ARCH_RENESAS
+ help
+ This enables support for the Renesas RZ/T2H SoC variants.
+
+config ARCH_R9A09G087
+ bool "ARM64 Platform support for R9A09G087 (RZ/N2H)"
+ default y if ARCH_RENESAS
+ help
+ This enables support for the Renesas RZ/N2H SoC variants.
+
endif # ARM64
if RISCV
config ARCH_R9A07G043
- bool "RISC-V Platform support for RZ/Five"
+ bool "RISC-V Platform support for R9A07G043F (RZ/Five)"
+ depends on NONPORTABLE
+ depends on !DMA_DIRECT_REMAP
+ depends on RISCV_ALTERNATIVE
+ depends on !RISCV_ISA_ZICBOM
+ depends on RISCV_SBI
select ARCH_RZG2L
+ select AX45MP_L2_CACHE
+ select DMA_GLOBAL_POOL
+ select ERRATA_ANDES
+ select ERRATA_ANDES_CMO
help
This enables support for the Renesas RZ/Five SoC.
endif # RISCV
+config PWC_RZV2M
+ bool "Renesas RZ/V2M PWC support" if COMPILE_TEST
+
config RST_RCAR
bool "Reset Controller support for R-Car" if COMPILE_TEST
-config SYSC_RCAR
- bool "System Controller support for R-Car" if COMPILE_TEST
-
-config SYSC_RCAR_GEN4
- bool "System Controller support for R-Car Gen4" if COMPILE_TEST
-
-config SYSC_R8A77995
- bool "System Controller support for R-Car D3" if COMPILE_TEST
- select SYSC_RCAR
-
-config SYSC_R8A7794
- bool "System Controller support for R-Car E2" if COMPILE_TEST
- select SYSC_RCAR
-
-config SYSC_R8A77990
- bool "System Controller support for R-Car E3" if COMPILE_TEST
- select SYSC_RCAR
-
-config SYSC_R8A7779
- bool "System Controller support for R-Car H1" if COMPILE_TEST
- select SYSC_RCAR
-
-config SYSC_R8A7790
- bool "System Controller support for R-Car H2" if COMPILE_TEST
- select SYSC_RCAR
-
-config SYSC_R8A7795
- bool "System Controller support for R-Car H3" if COMPILE_TEST
- select SYSC_RCAR
-
-config SYSC_R8A7791
- bool "System Controller support for R-Car M2-W/N" if COMPILE_TEST
- select SYSC_RCAR
-
-config SYSC_R8A77965
- bool "System Controller support for R-Car M3-N" if COMPILE_TEST
- select SYSC_RCAR
-
-config SYSC_R8A77960
- bool "System Controller support for R-Car M3-W" if COMPILE_TEST
- select SYSC_RCAR
-
-config SYSC_R8A77961
- bool "System Controller support for R-Car M3-W+" if COMPILE_TEST
- select SYSC_RCAR
-
-config SYSC_R8A779F0
- bool "System Controller support for R-Car S4-8" if COMPILE_TEST
- select SYSC_RCAR_GEN4
-
-config SYSC_R8A7792
- bool "System Controller support for R-Car V2H" if COMPILE_TEST
- select SYSC_RCAR
-
-config SYSC_R8A77980
- bool "System Controller support for R-Car V3H" if COMPILE_TEST
- select SYSC_RCAR
-
-config SYSC_R8A77970
- bool "System Controller support for R-Car V3M" if COMPILE_TEST
- select SYSC_RCAR
-
-config SYSC_R8A779A0
- bool "System Controller support for R-Car V3U" if COMPILE_TEST
- select SYSC_RCAR_GEN4
-
-config SYSC_R8A779G0
- bool "System Controller support for R-Car V4H" if COMPILE_TEST
- select SYSC_RCAR_GEN4
-
-config SYSC_RMOBILE
- bool "System Controller support for R-Mobile" if COMPILE_TEST
-
-config SYSC_R8A77470
- bool "System Controller support for RZ/G1C" if COMPILE_TEST
- select SYSC_RCAR
-
-config SYSC_R8A7745
- bool "System Controller support for RZ/G1E" if COMPILE_TEST
- select SYSC_RCAR
-
-config SYSC_R8A7742
- bool "System Controller support for RZ/G1H" if COMPILE_TEST
- select SYSC_RCAR
-
-config SYSC_R8A7743
- bool "System Controller support for RZ/G1M" if COMPILE_TEST
- select SYSC_RCAR
+config SYSC_RZ
+ bool "System controller for RZ SoCs" if COMPILE_TEST
+ select MFD_SYSCON
-config SYSC_R8A774C0
- bool "System Controller support for RZ/G2E" if COMPILE_TEST
- select SYSC_RCAR
+config SYSC_R9A08G045
+ bool "Renesas System controller support for R9A08G045 (RZ/G3S)" if COMPILE_TEST
+ select SYSC_RZ
-config SYSC_R8A774E1
- bool "System Controller support for RZ/G2H" if COMPILE_TEST
- select SYSC_RCAR
+config SYS_R9A09G047
+ bool "Renesas System controller support for R9A09G047 (RZ/G3E)" if COMPILE_TEST
+ select SYSC_RZ
-config SYSC_R8A774A1
- bool "System Controller support for RZ/G2M" if COMPILE_TEST
- select SYSC_RCAR
+config SYS_R9A09G056
+ bool "Renesas System controller support for R9A09G056 (RZ/V2N)" if COMPILE_TEST
+ select SYSC_RZ
-config SYSC_R8A774B1
- bool "System Controller support for RZ/G2N" if COMPILE_TEST
- select SYSC_RCAR
+config SYS_R9A09G057
+ bool "Renesas System controller support for R9A09G057 (RZ/V2H)" if COMPILE_TEST
+ select SYSC_RZ
endif # SOC_RENESAS
diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile
index 535868c9c7e4..3bdcc6a395d5 100644
--- a/drivers/soc/renesas/Makefile
+++ b/drivers/soc/renesas/Makefile
@@ -3,36 +3,15 @@
obj-$(CONFIG_SOC_RENESAS) += renesas-soc.o
# SoC
-obj-$(CONFIG_SYSC_R8A7742) += r8a7742-sysc.o
-obj-$(CONFIG_SYSC_R8A7743) += r8a7743-sysc.o
-obj-$(CONFIG_SYSC_R8A7745) += r8a7745-sysc.o
-obj-$(CONFIG_SYSC_R8A77470) += r8a77470-sysc.o
-obj-$(CONFIG_SYSC_R8A774A1) += r8a774a1-sysc.o
-obj-$(CONFIG_SYSC_R8A774B1) += r8a774b1-sysc.o
-obj-$(CONFIG_SYSC_R8A774C0) += r8a774c0-sysc.o
-obj-$(CONFIG_SYSC_R8A774E1) += r8a774e1-sysc.o
-obj-$(CONFIG_SYSC_R8A7779) += r8a7779-sysc.o
-obj-$(CONFIG_SYSC_R8A7790) += r8a7790-sysc.o
-obj-$(CONFIG_SYSC_R8A7791) += r8a7791-sysc.o
-obj-$(CONFIG_SYSC_R8A7792) += r8a7792-sysc.o
-obj-$(CONFIG_SYSC_R8A7794) += r8a7794-sysc.o
-obj-$(CONFIG_SYSC_R8A7795) += r8a7795-sysc.o
-obj-$(CONFIG_SYSC_R8A77960) += r8a7796-sysc.o
-obj-$(CONFIG_SYSC_R8A77961) += r8a7796-sysc.o
-obj-$(CONFIG_SYSC_R8A77965) += r8a77965-sysc.o
-obj-$(CONFIG_SYSC_R8A77970) += r8a77970-sysc.o
-obj-$(CONFIG_SYSC_R8A77980) += r8a77980-sysc.o
-obj-$(CONFIG_SYSC_R8A77990) += r8a77990-sysc.o
-obj-$(CONFIG_SYSC_R8A77995) += r8a77995-sysc.o
-obj-$(CONFIG_SYSC_R8A779A0) += r8a779a0-sysc.o
-obj-$(CONFIG_SYSC_R8A779F0) += r8a779f0-sysc.o
-obj-$(CONFIG_SYSC_R8A779G0) += r8a779g0-sysc.o
ifdef CONFIG_SMP
obj-$(CONFIG_ARCH_R9A06G032) += r9a06g032-smp.o
endif
+obj-$(CONFIG_SYSC_R9A08G045) += r9a08g045-sysc.o
+obj-$(CONFIG_SYS_R9A09G047) += r9a09g047-sys.o
+obj-$(CONFIG_SYS_R9A09G056) += r9a09g056-sys.o
+obj-$(CONFIG_SYS_R9A09G057) += r9a09g057-sys.o
# Family
+obj-$(CONFIG_PWC_RZV2M) += pwc-rzv2m.o
obj-$(CONFIG_RST_RCAR) += rcar-rst.o
-obj-$(CONFIG_SYSC_RCAR) += rcar-sysc.o
-obj-$(CONFIG_SYSC_RCAR_GEN4) += rcar-gen4-sysc.o
-obj-$(CONFIG_SYSC_RMOBILE) += rmobile-sysc.o
+obj-$(CONFIG_SYSC_RZ) += rz-sysc.o
diff --git a/drivers/soc/renesas/pwc-rzv2m.c b/drivers/soc/renesas/pwc-rzv2m.c
new file mode 100644
index 000000000000..6209168b3734
--- /dev/null
+++ b/drivers/soc/renesas/pwc-rzv2m.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 Renesas Electronics Corporation
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/driver.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+
+#define PWC_PWCRST 0x00
+#define PWC_PWCCKEN 0x04
+#define PWC_PWCCTL 0x50
+#define PWC_GPIO 0x80
+
+#define PWC_PWCRST_RSTSOFTAX 0x1
+#define PWC_PWCCKEN_ENGCKMAIN 0x1
+#define PWC_PWCCTL_PWOFF 0x1
+
+struct rzv2m_pwc_priv {
+ void __iomem *base;
+ struct device *dev;
+ struct gpio_chip gp;
+ DECLARE_BITMAP(ch_en_bits, 2);
+};
+
+static int rzv2m_pwc_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ struct rzv2m_pwc_priv *priv = gpiochip_get_data(chip);
+ u32 reg;
+
+ /* BIT 16 enables write to BIT 0, and BIT 17 enables write to BIT 1 */
+ reg = BIT(offset + 16);
+ if (value)
+ reg |= BIT(offset);
+
+ writel(reg, priv->base + PWC_GPIO);
+
+ assign_bit(offset, priv->ch_en_bits, value);
+
+ return 0;
+}
+
+static int rzv2m_pwc_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct rzv2m_pwc_priv *priv = gpiochip_get_data(chip);
+
+ return test_bit(offset, priv->ch_en_bits);
+}
+
+static int rzv2m_pwc_gpio_direction_output(struct gpio_chip *gc,
+ unsigned int nr, int value)
+{
+ if (nr > 1)
+ return -EINVAL;
+
+ rzv2m_pwc_gpio_set(gc, nr, value);
+
+ return 0;
+}
+
+static const struct gpio_chip rzv2m_pwc_gc = {
+ .label = "gpio_rzv2m_pwc",
+ .owner = THIS_MODULE,
+ .get = rzv2m_pwc_gpio_get,
+ .set = rzv2m_pwc_gpio_set,
+ .direction_output = rzv2m_pwc_gpio_direction_output,
+ .can_sleep = false,
+ .ngpio = 2,
+ .base = -1,
+};
+
+static int rzv2m_pwc_poweroff(struct sys_off_data *data)
+{
+ struct rzv2m_pwc_priv *priv = data->cb_data;
+
+ writel(PWC_PWCRST_RSTSOFTAX, priv->base + PWC_PWCRST);
+ writel(PWC_PWCCKEN_ENGCKMAIN, priv->base + PWC_PWCCKEN);
+ writel(PWC_PWCCTL_PWOFF, priv->base + PWC_PWCCTL);
+
+ mdelay(150);
+
+ dev_err(priv->dev, "Failed to power off the system");
+
+ return NOTIFY_DONE;
+}
+
+static int rzv2m_pwc_probe(struct platform_device *pdev)
+{
+ struct rzv2m_pwc_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ /*
+ * The register used by this driver cannot be read, therefore set the
+ * outputs to their default values and initialize priv->ch_en_bits
+ * accordingly. BIT 16 enables write to BIT 0, BIT 17 enables write to
+ * BIT 1, and the default value of both BIT 0 and BIT 1 is 0.
+ */
+ writel(BIT(17) | BIT(16), priv->base + PWC_GPIO);
+ bitmap_zero(priv->ch_en_bits, 2);
+
+ priv->gp = rzv2m_pwc_gc;
+ priv->gp.parent = pdev->dev.parent;
+ priv->gp.fwnode = dev_fwnode(&pdev->dev);
+
+ ret = devm_gpiochip_add_data(&pdev->dev, &priv->gp, priv);
+ if (ret)
+ return ret;
+
+ if (device_property_read_bool(&pdev->dev, "renesas,rzv2m-pwc-power"))
+ ret = devm_register_power_off_handler(&pdev->dev,
+ rzv2m_pwc_poweroff, priv);
+
+ return ret;
+}
+
+static const struct of_device_id rzv2m_pwc_of_match[] = {
+ { .compatible = "renesas,rzv2m-pwc" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rzv2m_pwc_of_match);
+
+static struct platform_driver rzv2m_pwc_driver = {
+ .probe = rzv2m_pwc_probe,
+ .driver = {
+ .name = "rzv2m_pwc",
+ .of_match_table = rzv2m_pwc_of_match,
+ },
+};
+module_platform_driver(rzv2m_pwc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Fabrizio Castro <castro.fabrizio.jz@renesas.com>");
+MODULE_DESCRIPTION("Renesas RZ/V2M PWC driver");
diff --git a/drivers/soc/renesas/r8a7742-sysc.c b/drivers/soc/renesas/r8a7742-sysc.c
deleted file mode 100644
index 219a675f83f4..000000000000
--- a/drivers/soc/renesas/r8a7742-sysc.c
+++ /dev/null
@@ -1,42 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas RZ/G1H System Controller
- *
- * Copyright (C) 2020 Renesas Electronics Corp.
- */
-
-#include <linux/kernel.h>
-
-#include <dt-bindings/power/r8a7742-sysc.h>
-
-#include "rcar-sysc.h"
-
-static const struct rcar_sysc_area r8a7742_areas[] __initconst = {
- { "always-on", 0, 0, R8A7742_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "ca15-scu", 0x180, 0, R8A7742_PD_CA15_SCU, R8A7742_PD_ALWAYS_ON,
- PD_SCU },
- { "ca15-cpu0", 0x40, 0, R8A7742_PD_CA15_CPU0, R8A7742_PD_CA15_SCU,
- PD_CPU_NOCR },
- { "ca15-cpu1", 0x40, 1, R8A7742_PD_CA15_CPU1, R8A7742_PD_CA15_SCU,
- PD_CPU_NOCR },
- { "ca15-cpu2", 0x40, 2, R8A7742_PD_CA15_CPU2, R8A7742_PD_CA15_SCU,
- PD_CPU_NOCR },
- { "ca15-cpu3", 0x40, 3, R8A7742_PD_CA15_CPU3, R8A7742_PD_CA15_SCU,
- PD_CPU_NOCR },
- { "ca7-scu", 0x100, 0, R8A7742_PD_CA7_SCU, R8A7742_PD_ALWAYS_ON,
- PD_SCU },
- { "ca7-cpu0", 0x1c0, 0, R8A7742_PD_CA7_CPU0, R8A7742_PD_CA7_SCU,
- PD_CPU_NOCR },
- { "ca7-cpu1", 0x1c0, 1, R8A7742_PD_CA7_CPU1, R8A7742_PD_CA7_SCU,
- PD_CPU_NOCR },
- { "ca7-cpu2", 0x1c0, 2, R8A7742_PD_CA7_CPU2, R8A7742_PD_CA7_SCU,
- PD_CPU_NOCR },
- { "ca7-cpu3", 0x1c0, 3, R8A7742_PD_CA7_CPU3, R8A7742_PD_CA7_SCU,
- PD_CPU_NOCR },
- { "rgx", 0xc0, 0, R8A7742_PD_RGX, R8A7742_PD_ALWAYS_ON },
-};
-
-const struct rcar_sysc_info r8a7742_sysc_info __initconst = {
- .areas = r8a7742_areas,
- .num_areas = ARRAY_SIZE(r8a7742_areas),
-};
diff --git a/drivers/soc/renesas/r8a7743-sysc.c b/drivers/soc/renesas/r8a7743-sysc.c
deleted file mode 100644
index 4e2c0ab951b3..000000000000
--- a/drivers/soc/renesas/r8a7743-sysc.c
+++ /dev/null
@@ -1,28 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas RZ/G1M System Controller
- *
- * Copyright (C) 2016 Cogent Embedded Inc.
- */
-
-#include <linux/kernel.h>
-
-#include <dt-bindings/power/r8a7743-sysc.h>
-
-#include "rcar-sysc.h"
-
-static const struct rcar_sysc_area r8a7743_areas[] __initconst = {
- { "always-on", 0, 0, R8A7743_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "ca15-scu", 0x180, 0, R8A7743_PD_CA15_SCU, R8A7743_PD_ALWAYS_ON,
- PD_SCU },
- { "ca15-cpu0", 0x40, 0, R8A7743_PD_CA15_CPU0, R8A7743_PD_CA15_SCU,
- PD_CPU_NOCR },
- { "ca15-cpu1", 0x40, 1, R8A7743_PD_CA15_CPU1, R8A7743_PD_CA15_SCU,
- PD_CPU_NOCR },
- { "sgx", 0xc0, 0, R8A7743_PD_SGX, R8A7743_PD_ALWAYS_ON },
-};
-
-const struct rcar_sysc_info r8a7743_sysc_info __initconst = {
- .areas = r8a7743_areas,
- .num_areas = ARRAY_SIZE(r8a7743_areas),
-};
diff --git a/drivers/soc/renesas/r8a7745-sysc.c b/drivers/soc/renesas/r8a7745-sysc.c
deleted file mode 100644
index 865821a2f0c6..000000000000
--- a/drivers/soc/renesas/r8a7745-sysc.c
+++ /dev/null
@@ -1,28 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas RZ/G1E System Controller
- *
- * Copyright (C) 2016 Cogent Embedded Inc.
- */
-
-#include <linux/kernel.h>
-
-#include <dt-bindings/power/r8a7745-sysc.h>
-
-#include "rcar-sysc.h"
-
-static const struct rcar_sysc_area r8a7745_areas[] __initconst = {
- { "always-on", 0, 0, R8A7745_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "ca7-scu", 0x100, 0, R8A7745_PD_CA7_SCU, R8A7745_PD_ALWAYS_ON,
- PD_SCU },
- { "ca7-cpu0", 0x1c0, 0, R8A7745_PD_CA7_CPU0, R8A7745_PD_CA7_SCU,
- PD_CPU_NOCR },
- { "ca7-cpu1", 0x1c0, 1, R8A7745_PD_CA7_CPU1, R8A7745_PD_CA7_SCU,
- PD_CPU_NOCR },
- { "sgx", 0xc0, 0, R8A7745_PD_SGX, R8A7745_PD_ALWAYS_ON },
-};
-
-const struct rcar_sysc_info r8a7745_sysc_info __initconst = {
- .areas = r8a7745_areas,
- .num_areas = ARRAY_SIZE(r8a7745_areas),
-};
diff --git a/drivers/soc/renesas/r8a77470-sysc.c b/drivers/soc/renesas/r8a77470-sysc.c
deleted file mode 100644
index 1eeb8018df50..000000000000
--- a/drivers/soc/renesas/r8a77470-sysc.c
+++ /dev/null
@@ -1,28 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas RZ/G1C System Controller
- *
- * Copyright (C) 2018 Renesas Electronics Corp.
- */
-
-#include <linux/kernel.h>
-
-#include <dt-bindings/power/r8a77470-sysc.h>
-
-#include "rcar-sysc.h"
-
-static const struct rcar_sysc_area r8a77470_areas[] __initconst = {
- { "always-on", 0, 0, R8A77470_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "ca7-scu", 0x100, 0, R8A77470_PD_CA7_SCU, R8A77470_PD_ALWAYS_ON,
- PD_SCU },
- { "ca7-cpu0", 0x1c0, 0, R8A77470_PD_CA7_CPU0, R8A77470_PD_CA7_SCU,
- PD_CPU_NOCR },
- { "ca7-cpu1", 0x1c0, 1, R8A77470_PD_CA7_CPU1, R8A77470_PD_CA7_SCU,
- PD_CPU_NOCR },
- { "sgx", 0xc0, 0, R8A77470_PD_SGX, R8A77470_PD_ALWAYS_ON },
-};
-
-const struct rcar_sysc_info r8a77470_sysc_info __initconst = {
- .areas = r8a77470_areas,
- .num_areas = ARRAY_SIZE(r8a77470_areas),
-};
diff --git a/drivers/soc/renesas/r8a774a1-sysc.c b/drivers/soc/renesas/r8a774a1-sysc.c
deleted file mode 100644
index 38ac2c689ff0..000000000000
--- a/drivers/soc/renesas/r8a774a1-sysc.c
+++ /dev/null
@@ -1,44 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas RZ/G2M System Controller
- * Copyright (C) 2018 Renesas Electronics Corp.
- *
- * Based on Renesas R-Car M3-W System Controller
- * Copyright (C) 2016 Glider bvba
- */
-
-#include <linux/kernel.h>
-
-#include <dt-bindings/power/r8a774a1-sysc.h>
-
-#include "rcar-sysc.h"
-
-static const struct rcar_sysc_area r8a774a1_areas[] __initconst = {
- { "always-on", 0, 0, R8A774A1_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "ca57-scu", 0x1c0, 0, R8A774A1_PD_CA57_SCU, R8A774A1_PD_ALWAYS_ON,
- PD_SCU },
- { "ca57-cpu0", 0x80, 0, R8A774A1_PD_CA57_CPU0, R8A774A1_PD_CA57_SCU,
- PD_CPU_NOCR },
- { "ca57-cpu1", 0x80, 1, R8A774A1_PD_CA57_CPU1, R8A774A1_PD_CA57_SCU,
- PD_CPU_NOCR },
- { "ca53-scu", 0x140, 0, R8A774A1_PD_CA53_SCU, R8A774A1_PD_ALWAYS_ON,
- PD_SCU },
- { "ca53-cpu0", 0x200, 0, R8A774A1_PD_CA53_CPU0, R8A774A1_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "ca53-cpu1", 0x200, 1, R8A774A1_PD_CA53_CPU1, R8A774A1_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "ca53-cpu2", 0x200, 2, R8A774A1_PD_CA53_CPU2, R8A774A1_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "ca53-cpu3", 0x200, 3, R8A774A1_PD_CA53_CPU3, R8A774A1_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "a3vc", 0x380, 0, R8A774A1_PD_A3VC, R8A774A1_PD_ALWAYS_ON },
- { "a2vc0", 0x3c0, 0, R8A774A1_PD_A2VC0, R8A774A1_PD_A3VC },
- { "a2vc1", 0x3c0, 1, R8A774A1_PD_A2VC1, R8A774A1_PD_A3VC },
- { "3dg-a", 0x100, 0, R8A774A1_PD_3DG_A, R8A774A1_PD_ALWAYS_ON },
- { "3dg-b", 0x100, 1, R8A774A1_PD_3DG_B, R8A774A1_PD_3DG_A },
-};
-
-const struct rcar_sysc_info r8a774a1_sysc_info __initconst = {
- .areas = r8a774a1_areas,
- .num_areas = ARRAY_SIZE(r8a774a1_areas),
-};
diff --git a/drivers/soc/renesas/r8a774b1-sysc.c b/drivers/soc/renesas/r8a774b1-sysc.c
deleted file mode 100644
index 5f97ff26f3f8..000000000000
--- a/drivers/soc/renesas/r8a774b1-sysc.c
+++ /dev/null
@@ -1,37 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas RZ/G2N System Controller
- * Copyright (C) 2019 Renesas Electronics Corp.
- *
- * Based on Renesas R-Car M3-W System Controller
- * Copyright (C) 2016 Glider bvba
- */
-
-#include <linux/bits.h>
-#include <linux/kernel.h>
-
-#include <dt-bindings/power/r8a774b1-sysc.h>
-
-#include "rcar-sysc.h"
-
-static const struct rcar_sysc_area r8a774b1_areas[] __initconst = {
- { "always-on", 0, 0, R8A774B1_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "ca57-scu", 0x1c0, 0, R8A774B1_PD_CA57_SCU, R8A774B1_PD_ALWAYS_ON,
- PD_SCU },
- { "ca57-cpu0", 0x80, 0, R8A774B1_PD_CA57_CPU0, R8A774B1_PD_CA57_SCU,
- PD_CPU_NOCR },
- { "ca57-cpu1", 0x80, 1, R8A774B1_PD_CA57_CPU1, R8A774B1_PD_CA57_SCU,
- PD_CPU_NOCR },
- { "a3vc", 0x380, 0, R8A774B1_PD_A3VC, R8A774B1_PD_ALWAYS_ON },
- { "a3vp", 0x340, 0, R8A774B1_PD_A3VP, R8A774B1_PD_ALWAYS_ON },
- { "a2vc1", 0x3c0, 1, R8A774B1_PD_A2VC1, R8A774B1_PD_A3VC },
- { "3dg-a", 0x100, 0, R8A774B1_PD_3DG_A, R8A774B1_PD_ALWAYS_ON },
- { "3dg-b", 0x100, 1, R8A774B1_PD_3DG_B, R8A774B1_PD_3DG_A },
-};
-
-const struct rcar_sysc_info r8a774b1_sysc_info __initconst = {
- .areas = r8a774b1_areas,
- .num_areas = ARRAY_SIZE(r8a774b1_areas),
- .extmask_offs = 0x2f8,
- .extmask_val = BIT(0),
-};
diff --git a/drivers/soc/renesas/r8a774c0-sysc.c b/drivers/soc/renesas/r8a774c0-sysc.c
deleted file mode 100644
index c1c216f7d073..000000000000
--- a/drivers/soc/renesas/r8a774c0-sysc.c
+++ /dev/null
@@ -1,55 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas RZ/G2E System Controller
- * Copyright (C) 2018 Renesas Electronics Corp.
- *
- * Based on Renesas R-Car E3 System Controller
- */
-
-#include <linux/bits.h>
-#include <linux/kernel.h>
-#include <linux/sys_soc.h>
-
-#include <dt-bindings/power/r8a774c0-sysc.h>
-
-#include "rcar-sysc.h"
-
-static struct rcar_sysc_area r8a774c0_areas[] __initdata = {
- { "always-on", 0, 0, R8A774C0_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "ca53-scu", 0x140, 0, R8A774C0_PD_CA53_SCU, R8A774C0_PD_ALWAYS_ON,
- PD_SCU },
- { "ca53-cpu0", 0x200, 0, R8A774C0_PD_CA53_CPU0, R8A774C0_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "ca53-cpu1", 0x200, 1, R8A774C0_PD_CA53_CPU1, R8A774C0_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "a3vc", 0x380, 0, R8A774C0_PD_A3VC, R8A774C0_PD_ALWAYS_ON },
- { "a2vc1", 0x3c0, 1, R8A774C0_PD_A2VC1, R8A774C0_PD_A3VC },
- { "3dg-a", 0x100, 0, R8A774C0_PD_3DG_A, R8A774C0_PD_ALWAYS_ON },
- { "3dg-b", 0x100, 1, R8A774C0_PD_3DG_B, R8A774C0_PD_3DG_A },
-};
-
-/* Fixups for RZ/G2E ES1.0 revision */
-static const struct soc_device_attribute r8a774c0[] __initconst = {
- { .soc_id = "r8a774c0", .revision = "ES1.0" },
- { /* sentinel */ }
-};
-
-static int __init r8a774c0_sysc_init(void)
-{
- if (soc_device_match(r8a774c0)) {
- /* Fix incorrect 3DG hierarchy */
- swap(r8a774c0_areas[6], r8a774c0_areas[7]);
- r8a774c0_areas[6].parent = R8A774C0_PD_ALWAYS_ON;
- r8a774c0_areas[7].parent = R8A774C0_PD_3DG_B;
- }
-
- return 0;
-}
-
-const struct rcar_sysc_info r8a774c0_sysc_info __initconst = {
- .init = r8a774c0_sysc_init,
- .areas = r8a774c0_areas,
- .num_areas = ARRAY_SIZE(r8a774c0_areas),
- .extmask_offs = 0x2f8,
- .extmask_val = BIT(0),
-};
diff --git a/drivers/soc/renesas/r8a774e1-sysc.c b/drivers/soc/renesas/r8a774e1-sysc.c
deleted file mode 100644
index 18449f746455..000000000000
--- a/drivers/soc/renesas/r8a774e1-sysc.c
+++ /dev/null
@@ -1,43 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas RZ/G2H System Controller
- * Copyright (C) 2020 Renesas Electronics Corp.
- *
- * Based on Renesas R-Car H3 System Controller
- * Copyright (C) 2016-2017 Glider bvba
- */
-
-#include <linux/kernel.h>
-
-#include <dt-bindings/power/r8a774e1-sysc.h>
-
-#include "rcar-sysc.h"
-
-static const struct rcar_sysc_area r8a774e1_areas[] __initconst = {
- { "always-on", 0, 0, R8A774E1_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "ca57-scu", 0x1c0, 0, R8A774E1_PD_CA57_SCU, R8A774E1_PD_ALWAYS_ON, PD_SCU },
- { "ca57-cpu0", 0x80, 0, R8A774E1_PD_CA57_CPU0, R8A774E1_PD_CA57_SCU, PD_CPU_NOCR },
- { "ca57-cpu1", 0x80, 1, R8A774E1_PD_CA57_CPU1, R8A774E1_PD_CA57_SCU, PD_CPU_NOCR },
- { "ca57-cpu2", 0x80, 2, R8A774E1_PD_CA57_CPU2, R8A774E1_PD_CA57_SCU, PD_CPU_NOCR },
- { "ca57-cpu3", 0x80, 3, R8A774E1_PD_CA57_CPU3, R8A774E1_PD_CA57_SCU, PD_CPU_NOCR },
- { "ca53-scu", 0x140, 0, R8A774E1_PD_CA53_SCU, R8A774E1_PD_ALWAYS_ON, PD_SCU },
- { "ca53-cpu0", 0x200, 0, R8A774E1_PD_CA53_CPU0, R8A774E1_PD_CA53_SCU, PD_CPU_NOCR },
- { "ca53-cpu1", 0x200, 1, R8A774E1_PD_CA53_CPU1, R8A774E1_PD_CA53_SCU, PD_CPU_NOCR },
- { "ca53-cpu2", 0x200, 2, R8A774E1_PD_CA53_CPU2, R8A774E1_PD_CA53_SCU, PD_CPU_NOCR },
- { "ca53-cpu3", 0x200, 3, R8A774E1_PD_CA53_CPU3, R8A774E1_PD_CA53_SCU, PD_CPU_NOCR },
- { "a3vp", 0x340, 0, R8A774E1_PD_A3VP, R8A774E1_PD_ALWAYS_ON },
- { "a3vc", 0x380, 0, R8A774E1_PD_A3VC, R8A774E1_PD_ALWAYS_ON },
- { "a2vc1", 0x3c0, 1, R8A774E1_PD_A2VC1, R8A774E1_PD_A3VC },
- { "3dg-a", 0x100, 0, R8A774E1_PD_3DG_A, R8A774E1_PD_ALWAYS_ON },
- { "3dg-b", 0x100, 1, R8A774E1_PD_3DG_B, R8A774E1_PD_3DG_A },
- { "3dg-c", 0x100, 2, R8A774E1_PD_3DG_C, R8A774E1_PD_3DG_B },
- { "3dg-d", 0x100, 3, R8A774E1_PD_3DG_D, R8A774E1_PD_3DG_C },
- { "3dg-e", 0x100, 4, R8A774E1_PD_3DG_E, R8A774E1_PD_3DG_D },
-};
-
-const struct rcar_sysc_info r8a774e1_sysc_info __initconst = {
- .areas = r8a774e1_areas,
- .num_areas = ARRAY_SIZE(r8a774e1_areas),
- .extmask_offs = 0x2f8,
- .extmask_val = BIT(0),
-};
diff --git a/drivers/soc/renesas/r8a7779-sysc.c b/drivers/soc/renesas/r8a7779-sysc.c
deleted file mode 100644
index e24a7151d55f..000000000000
--- a/drivers/soc/renesas/r8a7779-sysc.c
+++ /dev/null
@@ -1,30 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas R-Car H1 System Controller
- *
- * Copyright (C) 2016 Glider bvba
- */
-
-#include <linux/kernel.h>
-
-#include <dt-bindings/power/r8a7779-sysc.h>
-
-#include "rcar-sysc.h"
-
-static const struct rcar_sysc_area r8a7779_areas[] __initconst = {
- { "always-on", 0, 0, R8A7779_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "arm1", 0x40, 1, R8A7779_PD_ARM1, R8A7779_PD_ALWAYS_ON,
- PD_CPU_CR },
- { "arm2", 0x40, 2, R8A7779_PD_ARM2, R8A7779_PD_ALWAYS_ON,
- PD_CPU_CR },
- { "arm3", 0x40, 3, R8A7779_PD_ARM3, R8A7779_PD_ALWAYS_ON,
- PD_CPU_CR },
- { "sgx", 0xc0, 0, R8A7779_PD_SGX, R8A7779_PD_ALWAYS_ON },
- { "vdp", 0x100, 0, R8A7779_PD_VDP, R8A7779_PD_ALWAYS_ON },
- { "imp", 0x140, 0, R8A7779_PD_IMP, R8A7779_PD_ALWAYS_ON },
-};
-
-const struct rcar_sysc_info r8a7779_sysc_info __initconst = {
- .areas = r8a7779_areas,
- .num_areas = ARRAY_SIZE(r8a7779_areas),
-};
diff --git a/drivers/soc/renesas/r8a7790-sysc.c b/drivers/soc/renesas/r8a7790-sysc.c
deleted file mode 100644
index b9afe7f6245b..000000000000
--- a/drivers/soc/renesas/r8a7790-sysc.c
+++ /dev/null
@@ -1,44 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas R-Car H2 System Controller
- *
- * Copyright (C) 2016 Glider bvba
- */
-
-#include <linux/kernel.h>
-
-#include <dt-bindings/power/r8a7790-sysc.h>
-
-#include "rcar-sysc.h"
-
-static const struct rcar_sysc_area r8a7790_areas[] __initconst = {
- { "always-on", 0, 0, R8A7790_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "ca15-scu", 0x180, 0, R8A7790_PD_CA15_SCU, R8A7790_PD_ALWAYS_ON,
- PD_SCU },
- { "ca15-cpu0", 0x40, 0, R8A7790_PD_CA15_CPU0, R8A7790_PD_CA15_SCU,
- PD_CPU_NOCR },
- { "ca15-cpu1", 0x40, 1, R8A7790_PD_CA15_CPU1, R8A7790_PD_CA15_SCU,
- PD_CPU_NOCR },
- { "ca15-cpu2", 0x40, 2, R8A7790_PD_CA15_CPU2, R8A7790_PD_CA15_SCU,
- PD_CPU_NOCR },
- { "ca15-cpu3", 0x40, 3, R8A7790_PD_CA15_CPU3, R8A7790_PD_CA15_SCU,
- PD_CPU_NOCR },
- { "ca7-scu", 0x100, 0, R8A7790_PD_CA7_SCU, R8A7790_PD_ALWAYS_ON,
- PD_SCU },
- { "ca7-cpu0", 0x1c0, 0, R8A7790_PD_CA7_CPU0, R8A7790_PD_CA7_SCU,
- PD_CPU_NOCR },
- { "ca7-cpu1", 0x1c0, 1, R8A7790_PD_CA7_CPU1, R8A7790_PD_CA7_SCU,
- PD_CPU_NOCR },
- { "ca7-cpu2", 0x1c0, 2, R8A7790_PD_CA7_CPU2, R8A7790_PD_CA7_SCU,
- PD_CPU_NOCR },
- { "ca7-cpu3", 0x1c0, 3, R8A7790_PD_CA7_CPU3, R8A7790_PD_CA7_SCU,
- PD_CPU_NOCR },
- { "sh-4a", 0x80, 0, R8A7790_PD_SH_4A, R8A7790_PD_ALWAYS_ON },
- { "rgx", 0xc0, 0, R8A7790_PD_RGX, R8A7790_PD_ALWAYS_ON },
- { "imp", 0x140, 0, R8A7790_PD_IMP, R8A7790_PD_ALWAYS_ON },
-};
-
-const struct rcar_sysc_info r8a7790_sysc_info __initconst = {
- .areas = r8a7790_areas,
- .num_areas = ARRAY_SIZE(r8a7790_areas),
-};
diff --git a/drivers/soc/renesas/r8a7791-sysc.c b/drivers/soc/renesas/r8a7791-sysc.c
deleted file mode 100644
index f00fa24522a3..000000000000
--- a/drivers/soc/renesas/r8a7791-sysc.c
+++ /dev/null
@@ -1,29 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas R-Car M2-W/N System Controller
- *
- * Copyright (C) 2016 Glider bvba
- */
-
-#include <linux/kernel.h>
-
-#include <dt-bindings/power/r8a7791-sysc.h>
-
-#include "rcar-sysc.h"
-
-static const struct rcar_sysc_area r8a7791_areas[] __initconst = {
- { "always-on", 0, 0, R8A7791_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "ca15-scu", 0x180, 0, R8A7791_PD_CA15_SCU, R8A7791_PD_ALWAYS_ON,
- PD_SCU },
- { "ca15-cpu0", 0x40, 0, R8A7791_PD_CA15_CPU0, R8A7791_PD_CA15_SCU,
- PD_CPU_NOCR },
- { "ca15-cpu1", 0x40, 1, R8A7791_PD_CA15_CPU1, R8A7791_PD_CA15_SCU,
- PD_CPU_NOCR },
- { "sh-4a", 0x80, 0, R8A7791_PD_SH_4A, R8A7791_PD_ALWAYS_ON },
- { "sgx", 0xc0, 0, R8A7791_PD_SGX, R8A7791_PD_ALWAYS_ON },
-};
-
-const struct rcar_sysc_info r8a7791_sysc_info __initconst = {
- .areas = r8a7791_areas,
- .num_areas = ARRAY_SIZE(r8a7791_areas),
-};
diff --git a/drivers/soc/renesas/r8a7792-sysc.c b/drivers/soc/renesas/r8a7792-sysc.c
deleted file mode 100644
index 60aae242c43f..000000000000
--- a/drivers/soc/renesas/r8a7792-sysc.c
+++ /dev/null
@@ -1,30 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas R-Car V2H (R8A7792) System Controller
- *
- * Copyright (C) 2016 Cogent Embedded Inc.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <dt-bindings/power/r8a7792-sysc.h>
-
-#include "rcar-sysc.h"
-
-static const struct rcar_sysc_area r8a7792_areas[] __initconst = {
- { "always-on", 0, 0, R8A7792_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "ca15-scu", 0x180, 0, R8A7792_PD_CA15_SCU, R8A7792_PD_ALWAYS_ON,
- PD_SCU },
- { "ca15-cpu0", 0x40, 0, R8A7792_PD_CA15_CPU0, R8A7792_PD_CA15_SCU,
- PD_CPU_NOCR },
- { "ca15-cpu1", 0x40, 1, R8A7792_PD_CA15_CPU1, R8A7792_PD_CA15_SCU,
- PD_CPU_NOCR },
- { "sgx", 0xc0, 0, R8A7792_PD_SGX, R8A7792_PD_ALWAYS_ON },
- { "imp", 0x140, 0, R8A7792_PD_IMP, R8A7792_PD_ALWAYS_ON },
-};
-
-const struct rcar_sysc_info r8a7792_sysc_info __initconst = {
- .areas = r8a7792_areas,
- .num_areas = ARRAY_SIZE(r8a7792_areas),
-};
diff --git a/drivers/soc/renesas/r8a7794-sysc.c b/drivers/soc/renesas/r8a7794-sysc.c
deleted file mode 100644
index 72ef4e85458f..000000000000
--- a/drivers/soc/renesas/r8a7794-sysc.c
+++ /dev/null
@@ -1,29 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas R-Car E2 System Controller
- *
- * Copyright (C) 2016 Glider bvba
- */
-
-#include <linux/kernel.h>
-
-#include <dt-bindings/power/r8a7794-sysc.h>
-
-#include "rcar-sysc.h"
-
-static const struct rcar_sysc_area r8a7794_areas[] __initconst = {
- { "always-on", 0, 0, R8A7794_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "ca7-scu", 0x100, 0, R8A7794_PD_CA7_SCU, R8A7794_PD_ALWAYS_ON,
- PD_SCU },
- { "ca7-cpu0", 0x1c0, 0, R8A7794_PD_CA7_CPU0, R8A7794_PD_CA7_SCU,
- PD_CPU_NOCR },
- { "ca7-cpu1", 0x1c0, 1, R8A7794_PD_CA7_CPU1, R8A7794_PD_CA7_SCU,
- PD_CPU_NOCR },
- { "sh-4a", 0x80, 0, R8A7794_PD_SH_4A, R8A7794_PD_ALWAYS_ON },
- { "sgx", 0xc0, 0, R8A7794_PD_SGX, R8A7794_PD_ALWAYS_ON },
-};
-
-const struct rcar_sysc_info r8a7794_sysc_info __initconst = {
- .areas = r8a7794_areas,
- .num_areas = ARRAY_SIZE(r8a7794_areas),
-};
diff --git a/drivers/soc/renesas/r8a7795-sysc.c b/drivers/soc/renesas/r8a7795-sysc.c
deleted file mode 100644
index 91074411b8cf..000000000000
--- a/drivers/soc/renesas/r8a7795-sysc.c
+++ /dev/null
@@ -1,96 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas R-Car H3 System Controller
- *
- * Copyright (C) 2016-2017 Glider bvba
- */
-
-#include <linux/bits.h>
-#include <linux/kernel.h>
-#include <linux/sys_soc.h>
-
-#include <dt-bindings/power/r8a7795-sysc.h>
-
-#include "rcar-sysc.h"
-
-static struct rcar_sysc_area r8a7795_areas[] __initdata = {
- { "always-on", 0, 0, R8A7795_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "ca57-scu", 0x1c0, 0, R8A7795_PD_CA57_SCU, R8A7795_PD_ALWAYS_ON,
- PD_SCU },
- { "ca57-cpu0", 0x80, 0, R8A7795_PD_CA57_CPU0, R8A7795_PD_CA57_SCU,
- PD_CPU_NOCR },
- { "ca57-cpu1", 0x80, 1, R8A7795_PD_CA57_CPU1, R8A7795_PD_CA57_SCU,
- PD_CPU_NOCR },
- { "ca57-cpu2", 0x80, 2, R8A7795_PD_CA57_CPU2, R8A7795_PD_CA57_SCU,
- PD_CPU_NOCR },
- { "ca57-cpu3", 0x80, 3, R8A7795_PD_CA57_CPU3, R8A7795_PD_CA57_SCU,
- PD_CPU_NOCR },
- { "ca53-scu", 0x140, 0, R8A7795_PD_CA53_SCU, R8A7795_PD_ALWAYS_ON,
- PD_SCU },
- { "ca53-cpu0", 0x200, 0, R8A7795_PD_CA53_CPU0, R8A7795_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "ca53-cpu1", 0x200, 1, R8A7795_PD_CA53_CPU1, R8A7795_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "ca53-cpu2", 0x200, 2, R8A7795_PD_CA53_CPU2, R8A7795_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "ca53-cpu3", 0x200, 3, R8A7795_PD_CA53_CPU3, R8A7795_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "a3vp", 0x340, 0, R8A7795_PD_A3VP, R8A7795_PD_ALWAYS_ON },
- { "cr7", 0x240, 0, R8A7795_PD_CR7, R8A7795_PD_ALWAYS_ON },
- { "a3vc", 0x380, 0, R8A7795_PD_A3VC, R8A7795_PD_ALWAYS_ON },
- /* A2VC0 exists on ES1.x only */
- { "a2vc0", 0x3c0, 0, R8A7795_PD_A2VC0, R8A7795_PD_A3VC },
- { "a2vc1", 0x3c0, 1, R8A7795_PD_A2VC1, R8A7795_PD_A3VC },
- { "3dg-a", 0x100, 0, R8A7795_PD_3DG_A, R8A7795_PD_ALWAYS_ON },
- { "3dg-b", 0x100, 1, R8A7795_PD_3DG_B, R8A7795_PD_3DG_A },
- { "3dg-c", 0x100, 2, R8A7795_PD_3DG_C, R8A7795_PD_3DG_B },
- { "3dg-d", 0x100, 3, R8A7795_PD_3DG_D, R8A7795_PD_3DG_C },
- { "3dg-e", 0x100, 4, R8A7795_PD_3DG_E, R8A7795_PD_3DG_D },
- { "a3ir", 0x180, 0, R8A7795_PD_A3IR, R8A7795_PD_ALWAYS_ON },
-};
-
-
- /*
- * Fixups for R-Car H3 revisions
- */
-
-#define HAS_A2VC0 BIT(0) /* Power domain A2VC0 is present */
-#define NO_EXTMASK BIT(1) /* Missing SYSCEXTMASK register */
-
-static const struct soc_device_attribute r8a7795_quirks_match[] __initconst = {
- {
- .soc_id = "r8a7795", .revision = "ES1.*",
- .data = (void *)(HAS_A2VC0 | NO_EXTMASK),
- }, {
- .soc_id = "r8a7795", .revision = "ES2.*",
- .data = (void *)(NO_EXTMASK),
- },
- { /* sentinel */ }
-};
-
-static int __init r8a7795_sysc_init(void)
-{
- const struct soc_device_attribute *attr;
- u32 quirks = 0;
-
- attr = soc_device_match(r8a7795_quirks_match);
- if (attr)
- quirks = (uintptr_t)attr->data;
-
- if (!(quirks & HAS_A2VC0))
- rcar_sysc_nullify(r8a7795_areas, ARRAY_SIZE(r8a7795_areas),
- R8A7795_PD_A2VC0);
-
- if (quirks & NO_EXTMASK)
- r8a7795_sysc_info.extmask_val = 0;
-
- return 0;
-}
-
-struct rcar_sysc_info r8a7795_sysc_info __initdata = {
- .init = r8a7795_sysc_init,
- .areas = r8a7795_areas,
- .num_areas = ARRAY_SIZE(r8a7795_areas),
- .extmask_offs = 0x2f8,
- .extmask_val = BIT(0),
-};
diff --git a/drivers/soc/renesas/r8a7796-sysc.c b/drivers/soc/renesas/r8a7796-sysc.c
deleted file mode 100644
index 471bd5b3b6ad..000000000000
--- a/drivers/soc/renesas/r8a7796-sysc.c
+++ /dev/null
@@ -1,67 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas R-Car M3-W/W+ System Controller
- *
- * Copyright (C) 2016 Glider bvba
- * Copyright (C) 2018-2019 Renesas Electronics Corporation
- */
-
-#include <linux/bits.h>
-#include <linux/kernel.h>
-
-#include <dt-bindings/power/r8a7796-sysc.h>
-
-#include "rcar-sysc.h"
-
-static struct rcar_sysc_area r8a7796_areas[] __initdata = {
- { "always-on", 0, 0, R8A7796_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "ca57-scu", 0x1c0, 0, R8A7796_PD_CA57_SCU, R8A7796_PD_ALWAYS_ON,
- PD_SCU },
- { "ca57-cpu0", 0x80, 0, R8A7796_PD_CA57_CPU0, R8A7796_PD_CA57_SCU,
- PD_CPU_NOCR },
- { "ca57-cpu1", 0x80, 1, R8A7796_PD_CA57_CPU1, R8A7796_PD_CA57_SCU,
- PD_CPU_NOCR },
- { "ca53-scu", 0x140, 0, R8A7796_PD_CA53_SCU, R8A7796_PD_ALWAYS_ON,
- PD_SCU },
- { "ca53-cpu0", 0x200, 0, R8A7796_PD_CA53_CPU0, R8A7796_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "ca53-cpu1", 0x200, 1, R8A7796_PD_CA53_CPU1, R8A7796_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "ca53-cpu2", 0x200, 2, R8A7796_PD_CA53_CPU2, R8A7796_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "ca53-cpu3", 0x200, 3, R8A7796_PD_CA53_CPU3, R8A7796_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "cr7", 0x240, 0, R8A7796_PD_CR7, R8A7796_PD_ALWAYS_ON },
- { "a3vc", 0x380, 0, R8A7796_PD_A3VC, R8A7796_PD_ALWAYS_ON },
- { "a2vc0", 0x3c0, 0, R8A7796_PD_A2VC0, R8A7796_PD_A3VC },
- { "a2vc1", 0x3c0, 1, R8A7796_PD_A2VC1, R8A7796_PD_A3VC },
- { "3dg-a", 0x100, 0, R8A7796_PD_3DG_A, R8A7796_PD_ALWAYS_ON },
- { "3dg-b", 0x100, 1, R8A7796_PD_3DG_B, R8A7796_PD_3DG_A },
- { "a3ir", 0x180, 0, R8A7796_PD_A3IR, R8A7796_PD_ALWAYS_ON },
-};
-
-
-#ifdef CONFIG_SYSC_R8A77960
-const struct rcar_sysc_info r8a77960_sysc_info __initconst = {
- .areas = r8a7796_areas,
- .num_areas = ARRAY_SIZE(r8a7796_areas),
-};
-#endif /* CONFIG_SYSC_R8A77960 */
-
-#ifdef CONFIG_SYSC_R8A77961
-static int __init r8a77961_sysc_init(void)
-{
- rcar_sysc_nullify(r8a7796_areas, ARRAY_SIZE(r8a7796_areas),
- R8A7796_PD_A2VC0);
-
- return 0;
-}
-
-const struct rcar_sysc_info r8a77961_sysc_info __initconst = {
- .init = r8a77961_sysc_init,
- .areas = r8a7796_areas,
- .num_areas = ARRAY_SIZE(r8a7796_areas),
- .extmask_offs = 0x2f8,
- .extmask_val = BIT(0),
-};
-#endif /* CONFIG_SYSC_R8A77961 */
diff --git a/drivers/soc/renesas/r8a77965-sysc.c b/drivers/soc/renesas/r8a77965-sysc.c
deleted file mode 100644
index ff0b0d116992..000000000000
--- a/drivers/soc/renesas/r8a77965-sysc.c
+++ /dev/null
@@ -1,38 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas R-Car M3-N System Controller
- * Copyright (C) 2018 Jacopo Mondi <jacopo+renesas@jmondi.org>
- *
- * Based on Renesas R-Car M3-W System Controller
- * Copyright (C) 2016 Glider bvba
- */
-
-#include <linux/bits.h>
-#include <linux/kernel.h>
-
-#include <dt-bindings/power/r8a77965-sysc.h>
-
-#include "rcar-sysc.h"
-
-static const struct rcar_sysc_area r8a77965_areas[] __initconst = {
- { "always-on", 0, 0, R8A77965_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "ca57-scu", 0x1c0, 0, R8A77965_PD_CA57_SCU, R8A77965_PD_ALWAYS_ON,
- PD_SCU },
- { "ca57-cpu0", 0x80, 0, R8A77965_PD_CA57_CPU0, R8A77965_PD_CA57_SCU,
- PD_CPU_NOCR },
- { "ca57-cpu1", 0x80, 1, R8A77965_PD_CA57_CPU1, R8A77965_PD_CA57_SCU,
- PD_CPU_NOCR },
- { "cr7", 0x240, 0, R8A77965_PD_CR7, R8A77965_PD_ALWAYS_ON },
- { "a3vc", 0x380, 0, R8A77965_PD_A3VC, R8A77965_PD_ALWAYS_ON },
- { "a3vp", 0x340, 0, R8A77965_PD_A3VP, R8A77965_PD_ALWAYS_ON },
- { "a2vc1", 0x3c0, 1, R8A77965_PD_A2VC1, R8A77965_PD_A3VC },
- { "3dg-a", 0x100, 0, R8A77965_PD_3DG_A, R8A77965_PD_ALWAYS_ON },
- { "3dg-b", 0x100, 1, R8A77965_PD_3DG_B, R8A77965_PD_3DG_A },
-};
-
-const struct rcar_sysc_info r8a77965_sysc_info __initconst = {
- .areas = r8a77965_areas,
- .num_areas = ARRAY_SIZE(r8a77965_areas),
- .extmask_offs = 0x2f8,
- .extmask_val = BIT(0),
-};
diff --git a/drivers/soc/renesas/r8a77970-sysc.c b/drivers/soc/renesas/r8a77970-sysc.c
deleted file mode 100644
index 706258250600..000000000000
--- a/drivers/soc/renesas/r8a77970-sysc.c
+++ /dev/null
@@ -1,37 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas R-Car V3M System Controller
- *
- * Copyright (C) 2017 Cogent Embedded Inc.
- */
-
-#include <linux/bits.h>
-#include <linux/kernel.h>
-
-#include <dt-bindings/power/r8a77970-sysc.h>
-
-#include "rcar-sysc.h"
-
-static const struct rcar_sysc_area r8a77970_areas[] __initconst = {
- { "always-on", 0, 0, R8A77970_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "ca53-scu", 0x140, 0, R8A77970_PD_CA53_SCU, R8A77970_PD_ALWAYS_ON,
- PD_SCU },
- { "ca53-cpu0", 0x200, 0, R8A77970_PD_CA53_CPU0, R8A77970_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "ca53-cpu1", 0x200, 1, R8A77970_PD_CA53_CPU1, R8A77970_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "a3ir", 0x180, 0, R8A77970_PD_A3IR, R8A77970_PD_ALWAYS_ON },
- { "a2ir0", 0x400, 0, R8A77970_PD_A2IR0, R8A77970_PD_A3IR },
- { "a2ir1", 0x400, 1, R8A77970_PD_A2IR1, R8A77970_PD_A3IR },
- { "a2dp", 0x400, 2, R8A77970_PD_A2DP, R8A77970_PD_A3IR },
- { "a2cn", 0x400, 3, R8A77970_PD_A2CN, R8A77970_PD_A3IR },
- { "a2sc0", 0x400, 4, R8A77970_PD_A2SC0, R8A77970_PD_A3IR },
- { "a2sc1", 0x400, 5, R8A77970_PD_A2SC1, R8A77970_PD_A3IR },
-};
-
-const struct rcar_sysc_info r8a77970_sysc_info __initconst = {
- .areas = r8a77970_areas,
- .num_areas = ARRAY_SIZE(r8a77970_areas),
- .extmask_offs = 0x1b0,
- .extmask_val = BIT(0),
-};
diff --git a/drivers/soc/renesas/r8a77980-sysc.c b/drivers/soc/renesas/r8a77980-sysc.c
deleted file mode 100644
index 39ca84a67daa..000000000000
--- a/drivers/soc/renesas/r8a77980-sysc.c
+++ /dev/null
@@ -1,54 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas R-Car V3H System Controller
- *
- * Copyright (C) 2018 Renesas Electronics Corp.
- * Copyright (C) 2018 Cogent Embedded, Inc.
- */
-
-#include <linux/bits.h>
-#include <linux/kernel.h>
-
-#include <dt-bindings/power/r8a77980-sysc.h>
-
-#include "rcar-sysc.h"
-
-static const struct rcar_sysc_area r8a77980_areas[] __initconst = {
- { "always-on", 0, 0, R8A77980_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "ca53-scu", 0x140, 0, R8A77980_PD_CA53_SCU, R8A77980_PD_ALWAYS_ON,
- PD_SCU },
- { "ca53-cpu0", 0x200, 0, R8A77980_PD_CA53_CPU0, R8A77980_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "ca53-cpu1", 0x200, 1, R8A77980_PD_CA53_CPU1, R8A77980_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "ca53-cpu2", 0x200, 2, R8A77980_PD_CA53_CPU2, R8A77980_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "ca53-cpu3", 0x200, 3, R8A77980_PD_CA53_CPU3, R8A77980_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "cr7", 0x240, 0, R8A77980_PD_CR7, R8A77980_PD_ALWAYS_ON },
- { "a3ir", 0x180, 0, R8A77980_PD_A3IR, R8A77980_PD_ALWAYS_ON },
- { "a2ir0", 0x400, 0, R8A77980_PD_A2IR0, R8A77980_PD_A3IR },
- { "a2ir1", 0x400, 1, R8A77980_PD_A2IR1, R8A77980_PD_A3IR },
- { "a2ir2", 0x400, 2, R8A77980_PD_A2IR2, R8A77980_PD_A3IR },
- { "a2ir3", 0x400, 3, R8A77980_PD_A2IR3, R8A77980_PD_A3IR },
- { "a2ir4", 0x400, 4, R8A77980_PD_A2IR4, R8A77980_PD_A3IR },
- { "a2ir5", 0x400, 5, R8A77980_PD_A2IR5, R8A77980_PD_A3IR },
- { "a2sc0", 0x400, 6, R8A77980_PD_A2SC0, R8A77980_PD_A3IR },
- { "a2sc1", 0x400, 7, R8A77980_PD_A2SC1, R8A77980_PD_A3IR },
- { "a2sc2", 0x400, 8, R8A77980_PD_A2SC2, R8A77980_PD_A3IR },
- { "a2sc3", 0x400, 9, R8A77980_PD_A2SC3, R8A77980_PD_A3IR },
- { "a2sc4", 0x400, 10, R8A77980_PD_A2SC4, R8A77980_PD_A3IR },
- { "a2dp0", 0x400, 11, R8A77980_PD_A2DP0, R8A77980_PD_A3IR },
- { "a2dp1", 0x400, 12, R8A77980_PD_A2DP1, R8A77980_PD_A3IR },
- { "a2cn", 0x400, 13, R8A77980_PD_A2CN, R8A77980_PD_A3IR },
- { "a3vip0", 0x2c0, 0, R8A77980_PD_A3VIP0, R8A77980_PD_ALWAYS_ON },
- { "a3vip1", 0x300, 0, R8A77980_PD_A3VIP1, R8A77980_PD_ALWAYS_ON },
- { "a3vip2", 0x280, 0, R8A77980_PD_A3VIP2, R8A77980_PD_ALWAYS_ON },
-};
-
-const struct rcar_sysc_info r8a77980_sysc_info __initconst = {
- .areas = r8a77980_areas,
- .num_areas = ARRAY_SIZE(r8a77980_areas),
- .extmask_offs = 0x138,
- .extmask_val = BIT(0),
-};
diff --git a/drivers/soc/renesas/r8a77990-sysc.c b/drivers/soc/renesas/r8a77990-sysc.c
deleted file mode 100644
index 9f92737dc352..000000000000
--- a/drivers/soc/renesas/r8a77990-sysc.c
+++ /dev/null
@@ -1,55 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas R-Car E3 System Controller
- *
- * Copyright (C) 2018 Renesas Electronics Corp.
- */
-
-#include <linux/bits.h>
-#include <linux/kernel.h>
-#include <linux/sys_soc.h>
-
-#include <dt-bindings/power/r8a77990-sysc.h>
-
-#include "rcar-sysc.h"
-
-static struct rcar_sysc_area r8a77990_areas[] __initdata = {
- { "always-on", 0, 0, R8A77990_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "ca53-scu", 0x140, 0, R8A77990_PD_CA53_SCU, R8A77990_PD_ALWAYS_ON,
- PD_SCU },
- { "ca53-cpu0", 0x200, 0, R8A77990_PD_CA53_CPU0, R8A77990_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "ca53-cpu1", 0x200, 1, R8A77990_PD_CA53_CPU1, R8A77990_PD_CA53_SCU,
- PD_CPU_NOCR },
- { "cr7", 0x240, 0, R8A77990_PD_CR7, R8A77990_PD_ALWAYS_ON },
- { "a3vc", 0x380, 0, R8A77990_PD_A3VC, R8A77990_PD_ALWAYS_ON },
- { "a2vc1", 0x3c0, 1, R8A77990_PD_A2VC1, R8A77990_PD_A3VC },
- { "3dg-a", 0x100, 0, R8A77990_PD_3DG_A, R8A77990_PD_ALWAYS_ON },
- { "3dg-b", 0x100, 1, R8A77990_PD_3DG_B, R8A77990_PD_3DG_A },
-};
-
-/* Fixups for R-Car E3 ES1.0 revision */
-static const struct soc_device_attribute r8a77990[] __initconst = {
- { .soc_id = "r8a77990", .revision = "ES1.0" },
- { /* sentinel */ }
-};
-
-static int __init r8a77990_sysc_init(void)
-{
- if (soc_device_match(r8a77990)) {
- /* Fix incorrect 3DG hierarchy */
- swap(r8a77990_areas[7], r8a77990_areas[8]);
- r8a77990_areas[7].parent = R8A77990_PD_ALWAYS_ON;
- r8a77990_areas[8].parent = R8A77990_PD_3DG_B;
- }
-
- return 0;
-}
-
-const struct rcar_sysc_info r8a77990_sysc_info __initconst = {
- .init = r8a77990_sysc_init,
- .areas = r8a77990_areas,
- .num_areas = ARRAY_SIZE(r8a77990_areas),
- .extmask_offs = 0x2f8,
- .extmask_val = BIT(0),
-};
diff --git a/drivers/soc/renesas/r8a77995-sysc.c b/drivers/soc/renesas/r8a77995-sysc.c
deleted file mode 100644
index efcc67e3d76d..000000000000
--- a/drivers/soc/renesas/r8a77995-sysc.c
+++ /dev/null
@@ -1,26 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas R-Car D3 System Controller
- *
- * Copyright (C) 2017 Glider bvba
- */
-
-#include <linux/kernel.h>
-
-#include <dt-bindings/power/r8a77995-sysc.h>
-
-#include "rcar-sysc.h"
-
-static const struct rcar_sysc_area r8a77995_areas[] __initconst = {
- { "always-on", 0, 0, R8A77995_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "ca53-scu", 0x140, 0, R8A77995_PD_CA53_SCU, R8A77995_PD_ALWAYS_ON,
- PD_SCU },
- { "ca53-cpu0", 0x200, 0, R8A77995_PD_CA53_CPU0, R8A77995_PD_CA53_SCU,
- PD_CPU_NOCR },
-};
-
-
-const struct rcar_sysc_info r8a77995_sysc_info __initconst = {
- .areas = r8a77995_areas,
- .num_areas = ARRAY_SIZE(r8a77995_areas),
-};
diff --git a/drivers/soc/renesas/r8a779a0-sysc.c b/drivers/soc/renesas/r8a779a0-sysc.c
deleted file mode 100644
index 04f1bc322ae7..000000000000
--- a/drivers/soc/renesas/r8a779a0-sysc.c
+++ /dev/null
@@ -1,76 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas R-Car V3U System Controller
- *
- * Copyright (C) 2020 Renesas Electronics Corp.
- */
-
-#include <linux/bits.h>
-#include <linux/clk/renesas.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/of_address.h>
-#include <linux/pm_domain.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-#include <dt-bindings/power/r8a779a0-sysc.h>
-
-#include "rcar-gen4-sysc.h"
-
-static struct rcar_gen4_sysc_area r8a779a0_areas[] __initdata = {
- { "always-on", R8A779A0_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "a3e0", R8A779A0_PD_A3E0, R8A779A0_PD_ALWAYS_ON, PD_SCU },
- { "a3e1", R8A779A0_PD_A3E1, R8A779A0_PD_ALWAYS_ON, PD_SCU },
- { "a2e0d0", R8A779A0_PD_A2E0D0, R8A779A0_PD_A3E0, PD_SCU },
- { "a2e0d1", R8A779A0_PD_A2E0D1, R8A779A0_PD_A3E0, PD_SCU },
- { "a2e1d0", R8A779A0_PD_A2E1D0, R8A779A0_PD_A3E1, PD_SCU },
- { "a2e1d1", R8A779A0_PD_A2E1D1, R8A779A0_PD_A3E1, PD_SCU },
- { "a1e0d0c0", R8A779A0_PD_A1E0D0C0, R8A779A0_PD_A2E0D0, PD_CPU_NOCR },
- { "a1e0d0c1", R8A779A0_PD_A1E0D0C1, R8A779A0_PD_A2E0D0, PD_CPU_NOCR },
- { "a1e0d1c0", R8A779A0_PD_A1E0D1C0, R8A779A0_PD_A2E0D1, PD_CPU_NOCR },
- { "a1e0d1c1", R8A779A0_PD_A1E0D1C1, R8A779A0_PD_A2E0D1, PD_CPU_NOCR },
- { "a1e1d0c0", R8A779A0_PD_A1E1D0C0, R8A779A0_PD_A2E1D0, PD_CPU_NOCR },
- { "a1e1d0c1", R8A779A0_PD_A1E1D0C1, R8A779A0_PD_A2E1D0, PD_CPU_NOCR },
- { "a1e1d1c0", R8A779A0_PD_A1E1D1C0, R8A779A0_PD_A2E1D1, PD_CPU_NOCR },
- { "a1e1d1c1", R8A779A0_PD_A1E1D1C1, R8A779A0_PD_A2E1D1, PD_CPU_NOCR },
- { "3dg-a", R8A779A0_PD_3DG_A, R8A779A0_PD_ALWAYS_ON },
- { "3dg-b", R8A779A0_PD_3DG_B, R8A779A0_PD_3DG_A },
- { "a3vip0", R8A779A0_PD_A3VIP0, R8A779A0_PD_ALWAYS_ON },
- { "a3vip1", R8A779A0_PD_A3VIP1, R8A779A0_PD_ALWAYS_ON },
- { "a3vip3", R8A779A0_PD_A3VIP3, R8A779A0_PD_ALWAYS_ON },
- { "a3vip2", R8A779A0_PD_A3VIP2, R8A779A0_PD_ALWAYS_ON },
- { "a3isp01", R8A779A0_PD_A3ISP01, R8A779A0_PD_ALWAYS_ON },
- { "a3isp23", R8A779A0_PD_A3ISP23, R8A779A0_PD_ALWAYS_ON },
- { "a3ir", R8A779A0_PD_A3IR, R8A779A0_PD_ALWAYS_ON },
- { "a2cn0", R8A779A0_PD_A2CN0, R8A779A0_PD_A3IR },
- { "a2imp01", R8A779A0_PD_A2IMP01, R8A779A0_PD_A3IR },
- { "a2dp0", R8A779A0_PD_A2DP0, R8A779A0_PD_A3IR },
- { "a2cv0", R8A779A0_PD_A2CV0, R8A779A0_PD_A3IR },
- { "a2cv1", R8A779A0_PD_A2CV1, R8A779A0_PD_A3IR },
- { "a2cv4", R8A779A0_PD_A2CV4, R8A779A0_PD_A3IR },
- { "a2cv6", R8A779A0_PD_A2CV6, R8A779A0_PD_A3IR },
- { "a2cn2", R8A779A0_PD_A2CN2, R8A779A0_PD_A3IR },
- { "a2imp23", R8A779A0_PD_A2IMP23, R8A779A0_PD_A3IR },
- { "a2dp1", R8A779A0_PD_A2DP1, R8A779A0_PD_A3IR },
- { "a2cv2", R8A779A0_PD_A2CV2, R8A779A0_PD_A3IR },
- { "a2cv3", R8A779A0_PD_A2CV3, R8A779A0_PD_A3IR },
- { "a2cv5", R8A779A0_PD_A2CV5, R8A779A0_PD_A3IR },
- { "a2cv7", R8A779A0_PD_A2CV7, R8A779A0_PD_A3IR },
- { "a2cn1", R8A779A0_PD_A2CN1, R8A779A0_PD_A3IR },
- { "a1cnn0", R8A779A0_PD_A1CNN0, R8A779A0_PD_A2CN0 },
- { "a1cnn2", R8A779A0_PD_A1CNN2, R8A779A0_PD_A2CN2 },
- { "a1dsp0", R8A779A0_PD_A1DSP0, R8A779A0_PD_A2CN2 },
- { "a1cnn1", R8A779A0_PD_A1CNN1, R8A779A0_PD_A2CN1 },
- { "a1dsp1", R8A779A0_PD_A1DSP1, R8A779A0_PD_A2CN1 },
-};
-
-const struct rcar_gen4_sysc_info r8a779a0_sysc_info __initconst = {
- .areas = r8a779a0_areas,
- .num_areas = ARRAY_SIZE(r8a779a0_areas),
-};
diff --git a/drivers/soc/renesas/r8a779f0-sysc.c b/drivers/soc/renesas/r8a779f0-sysc.c
deleted file mode 100644
index 5602aa6bd7ed..000000000000
--- a/drivers/soc/renesas/r8a779f0-sysc.c
+++ /dev/null
@@ -1,47 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas R-Car S4-8 System Controller
- *
- * Copyright (C) 2021 Renesas Electronics Corp.
- */
-
-#include <linux/bits.h>
-#include <linux/clk/renesas.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/of_address.h>
-#include <linux/pm_domain.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-#include <dt-bindings/power/r8a779f0-sysc.h>
-
-#include "rcar-gen4-sysc.h"
-
-static struct rcar_gen4_sysc_area r8a779f0_areas[] __initdata = {
- { "always-on", R8A779F0_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "a3e0", R8A779F0_PD_A3E0, R8A779F0_PD_ALWAYS_ON, PD_SCU },
- { "a3e1", R8A779F0_PD_A3E1, R8A779F0_PD_ALWAYS_ON, PD_SCU },
- { "a2e0d0", R8A779F0_PD_A2E0D0, R8A779F0_PD_A3E0, PD_SCU },
- { "a2e0d1", R8A779F0_PD_A2E0D1, R8A779F0_PD_A3E0, PD_SCU },
- { "a2e1d0", R8A779F0_PD_A2E1D0, R8A779F0_PD_A3E1, PD_SCU },
- { "a2e1d1", R8A779F0_PD_A2E1D1, R8A779F0_PD_A3E1, PD_SCU },
- { "a1e0d0c0", R8A779F0_PD_A1E0D0C0, R8A779F0_PD_A2E0D0, PD_CPU_NOCR },
- { "a1e0d0c1", R8A779F0_PD_A1E0D0C1, R8A779F0_PD_A2E0D0, PD_CPU_NOCR },
- { "a1e0d1c0", R8A779F0_PD_A1E0D1C0, R8A779F0_PD_A2E0D1, PD_CPU_NOCR },
- { "a1e0d1c1", R8A779F0_PD_A1E0D1C1, R8A779F0_PD_A2E0D1, PD_CPU_NOCR },
- { "a1e1d0c0", R8A779F0_PD_A1E1D0C0, R8A779F0_PD_A2E1D0, PD_CPU_NOCR },
- { "a1e1d0c1", R8A779F0_PD_A1E1D0C1, R8A779F0_PD_A2E1D0, PD_CPU_NOCR },
- { "a1e1d1c0", R8A779F0_PD_A1E1D1C0, R8A779F0_PD_A2E1D1, PD_CPU_NOCR },
- { "a1e1d1c1", R8A779F0_PD_A1E1D1C1, R8A779F0_PD_A2E1D1, PD_CPU_NOCR },
-};
-
-const struct rcar_gen4_sysc_info r8a779f0_sysc_info __initconst = {
- .areas = r8a779f0_areas,
- .num_areas = ARRAY_SIZE(r8a779f0_areas),
-};
diff --git a/drivers/soc/renesas/r8a779g0-sysc.c b/drivers/soc/renesas/r8a779g0-sysc.c
deleted file mode 100644
index a452709f066d..000000000000
--- a/drivers/soc/renesas/r8a779g0-sysc.c
+++ /dev/null
@@ -1,62 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas R-Car V4H System Controller
- *
- * Copyright (C) 2022 Renesas Electronics Corp.
- */
-
-#include <linux/bits.h>
-#include <linux/clk/renesas.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/of_address.h>
-#include <linux/pm_domain.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-#include <dt-bindings/power/r8a779g0-sysc.h>
-
-#include "rcar-gen4-sysc.h"
-
-static struct rcar_gen4_sysc_area r8a779g0_areas[] __initdata = {
- { "always-on", R8A779G0_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
- { "a3e0", R8A779G0_PD_A3E0, R8A779G0_PD_ALWAYS_ON, PD_SCU },
- { "a2e0d0", R8A779G0_PD_A2E0D0, R8A779G0_PD_A3E0, PD_SCU },
- { "a2e0d1", R8A779G0_PD_A2E0D1, R8A779G0_PD_A3E0, PD_SCU },
- { "a1e0d0c0", R8A779G0_PD_A1E0D0C0, R8A779G0_PD_A2E0D0, PD_CPU_NOCR },
- { "a1e0d0c1", R8A779G0_PD_A1E0D0C1, R8A779G0_PD_A2E0D0, PD_CPU_NOCR },
- { "a1e0d1c0", R8A779G0_PD_A1E0D1C0, R8A779G0_PD_A2E0D1, PD_CPU_NOCR },
- { "a1e0d1c1", R8A779G0_PD_A1E0D1C1, R8A779G0_PD_A2E0D1, PD_CPU_NOCR },
- { "a33dga", R8A779G0_PD_A33DGA, R8A779G0_PD_ALWAYS_ON },
- { "a23dgb", R8A779G0_PD_A23DGB, R8A779G0_PD_A33DGA },
- { "a3vip0", R8A779G0_PD_A3VIP0, R8A779G0_PD_ALWAYS_ON },
- { "a3vip1", R8A779G0_PD_A3VIP1, R8A779G0_PD_ALWAYS_ON },
- { "a3vip2", R8A779G0_PD_A3VIP2, R8A779G0_PD_ALWAYS_ON },
- { "a3isp0", R8A779G0_PD_A3ISP0, R8A779G0_PD_ALWAYS_ON },
- { "a3isp1", R8A779G0_PD_A3ISP1, R8A779G0_PD_ALWAYS_ON },
- { "a3ir", R8A779G0_PD_A3IR, R8A779G0_PD_ALWAYS_ON },
- { "a2cn0", R8A779G0_PD_A2CN0, R8A779G0_PD_A3IR },
- { "a1cnn0", R8A779G0_PD_A1CNN0, R8A779G0_PD_A2CN0 },
- { "a1dsp0", R8A779G0_PD_A1DSP0, R8A779G0_PD_A2CN0 },
- { "a1dsp1", R8A779G0_PD_A1DSP1, R8A779G0_PD_A2CN0 },
- { "a1dsp2", R8A779G0_PD_A1DSP2, R8A779G0_PD_A2CN0 },
- { "a1dsp3", R8A779G0_PD_A1DSP3, R8A779G0_PD_A2CN0 },
- { "a2imp01", R8A779G0_PD_A2IMP01, R8A779G0_PD_A3IR },
- { "a2imp23", R8A779G0_PD_A2IMP23, R8A779G0_PD_A3IR },
- { "a2psc", R8A779G0_PD_A2PSC, R8A779G0_PD_A3IR },
- { "a2dma", R8A779G0_PD_A2DMA, R8A779G0_PD_A3IR },
- { "a2cv0", R8A779G0_PD_A2CV0, R8A779G0_PD_A3IR },
- { "a2cv1", R8A779G0_PD_A2CV1, R8A779G0_PD_A3IR },
- { "a2cv2", R8A779G0_PD_A2CV2, R8A779G0_PD_A3IR },
- { "a2cv3", R8A779G0_PD_A2CV3, R8A779G0_PD_A3IR },
-};
-
-const struct rcar_gen4_sysc_info r8a779g0_sysc_info __initconst = {
- .areas = r8a779g0_areas,
- .num_areas = ARRAY_SIZE(r8a779g0_areas),
-};
diff --git a/drivers/soc/renesas/r9a08g045-sysc.c b/drivers/soc/renesas/r9a08g045-sysc.c
new file mode 100644
index 000000000000..03d653d5cde5
--- /dev/null
+++ b/drivers/soc/renesas/r9a08g045-sysc.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/G3S System controller driver
+ *
+ * Copyright (C) 2024 Renesas Electronics Corp.
+ */
+
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/init.h>
+
+#include "rz-sysc.h"
+
+#define SYS_XSPI_MAP_STAADD_CS0 0x348
+#define SYS_XSPI_MAP_ENDADD_CS0 0x34c
+#define SYS_XSPI_MAP_STAADD_CS1 0x350
+#define SYS_XSPI_MAP_ENDADD_CS1 0x354
+#define SYS_GETH0_CFG 0x380
+#define SYS_GETH1_CFG 0x390
+#define SYS_PCIE_CFG 0x3a0
+#define SYS_PCIE_MON 0x3a4
+#define SYS_PCIE_ERR_MON 0x3ac
+#define SYS_PCIE_PHY 0x3b4
+#define SYS_I2C0_CFG 0x400
+#define SYS_I2C1_CFG 0x410
+#define SYS_I2C2_CFG 0x420
+#define SYS_I2C3_CFG 0x430
+#define SYS_I3C_CFG 0x440
+#define SYS_USB_PWRRDY 0xd70
+#define SYS_PCIE_RST_RSM_B 0xd74
+
+static const struct rz_sysc_soc_id_init_data rzg3s_sysc_soc_id_init_data __initconst = {
+ .family = "RZ/G3S",
+ .id = 0x85e0447,
+ .devid_offset = 0xa04,
+ .revision_mask = GENMASK(31, 28),
+ .specific_id_mask = GENMASK(27, 0),
+};
+
+static bool rzg3s_regmap_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SYS_XSPI_MAP_STAADD_CS0:
+ case SYS_XSPI_MAP_ENDADD_CS0:
+ case SYS_XSPI_MAP_STAADD_CS1:
+ case SYS_XSPI_MAP_ENDADD_CS1:
+ case SYS_GETH0_CFG:
+ case SYS_GETH1_CFG:
+ case SYS_PCIE_CFG:
+ case SYS_PCIE_MON:
+ case SYS_PCIE_ERR_MON:
+ case SYS_PCIE_PHY:
+ case SYS_I2C0_CFG:
+ case SYS_I2C1_CFG:
+ case SYS_I2C2_CFG:
+ case SYS_I2C3_CFG:
+ case SYS_I3C_CFG:
+ case SYS_USB_PWRRDY:
+ case SYS_PCIE_RST_RSM_B:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rzg3s_regmap_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SYS_XSPI_MAP_STAADD_CS0:
+ case SYS_XSPI_MAP_ENDADD_CS0:
+ case SYS_XSPI_MAP_STAADD_CS1:
+ case SYS_XSPI_MAP_ENDADD_CS1:
+ case SYS_PCIE_CFG:
+ case SYS_PCIE_PHY:
+ case SYS_I2C0_CFG:
+ case SYS_I2C1_CFG:
+ case SYS_I2C2_CFG:
+ case SYS_I2C3_CFG:
+ case SYS_I3C_CFG:
+ case SYS_USB_PWRRDY:
+ case SYS_PCIE_RST_RSM_B:
+ return true;
+ default:
+ return false;
+ }
+}
+
+const struct rz_sysc_init_data rzg3s_sysc_init_data __initconst = {
+ .soc_id_init_data = &rzg3s_sysc_soc_id_init_data,
+ .readable_reg = rzg3s_regmap_readable_reg,
+ .writeable_reg = rzg3s_regmap_writeable_reg,
+ .max_register = 0xe20,
+};
diff --git a/drivers/soc/renesas/r9a09g047-sys.c b/drivers/soc/renesas/r9a09g047-sys.c
new file mode 100644
index 000000000000..e413b0eff9bf
--- /dev/null
+++ b/drivers/soc/renesas/r9a09g047-sys.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/G3E System controller (SYS) driver
+ *
+ * Copyright (C) 2025 Renesas Electronics Corp.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include "rz-sysc.h"
+
+/* Register Offsets */
+#define SYS_LSI_MODE 0x300
+/*
+ * BOOTPLLCA[1:0]
+ * [0,0] => 1.1GHZ
+ * [0,1] => 1.5GHZ
+ * [1,0] => 1.6GHZ
+ * [1,1] => 1.7GHZ
+ */
+#define SYS_LSI_MODE_STAT_BOOTPLLCA55 GENMASK(12, 11)
+#define SYS_LSI_MODE_CA55_1_7GHZ 0x3
+
+#define SYS_LSI_PRR 0x308
+#define SYS_LSI_PRR_CA55_DIS BIT(8)
+#define SYS_LSI_PRR_NPU_DIS BIT(1)
+
+#define SYS_LSI_OTPTSU1TRMVAL0 0x330
+#define SYS_LSI_OTPTSU1TRMVAL1 0x334
+#define SYS_SPI_STAADDCS0 0x900
+#define SYS_SPI_ENDADDCS0 0x904
+#define SYS_SPI_STAADDCS1 0x908
+#define SYS_SPI_ENDADDCS1 0x90c
+#define SYS_VSP_CLK 0xe00
+#define SYS_GBETH0_CFG 0xf00
+#define SYS_GBETH1_CFG 0xf04
+#define SYS_PCIE_INTX_CH0 0x1000
+#define SYS_PCIE_MSI1_CH0 0x1004
+#define SYS_PCIE_MSI2_CH0 0x1008
+#define SYS_PCIE_MSI3_CH0 0x100c
+#define SYS_PCIE_MSI4_CH0 0x1010
+#define SYS_PCIE_MSI5_CH0 0x1014
+#define SYS_PCIE_PME_CH0 0x1018
+#define SYS_PCIE_ACK_CH0 0x101c
+#define SYS_PCIE_MISC_CH0 0x1020
+#define SYS_PCIE_MODE_CH0 0x1024
+#define SYS_ADC_CFG 0x1600
+
+static void rzg3e_sys_print_id(struct device *dev,
+ void __iomem *sysc_base,
+ struct soc_device_attribute *soc_dev_attr)
+{
+ bool is_quad_core, npu_enabled;
+ u32 prr_val, mode_val;
+
+ prr_val = readl(sysc_base + SYS_LSI_PRR);
+ mode_val = readl(sysc_base + SYS_LSI_MODE);
+
+ /* Check CPU and NPU configuration */
+ is_quad_core = !(prr_val & SYS_LSI_PRR_CA55_DIS);
+ npu_enabled = !(prr_val & SYS_LSI_PRR_NPU_DIS);
+
+ dev_info(dev, "Detected Renesas %s Core %s %s Rev %s%s\n",
+ is_quad_core ? "Quad" : "Dual", soc_dev_attr->family,
+ soc_dev_attr->soc_id, soc_dev_attr->revision,
+ npu_enabled ? " with Ethos-U55" : "");
+
+ /* Check CA55 PLL configuration */
+ if (FIELD_GET(SYS_LSI_MODE_STAT_BOOTPLLCA55, mode_val) != SYS_LSI_MODE_CA55_1_7GHZ)
+ dev_warn(dev, "CA55 PLL is not set to 1.7GHz\n");
+}
+
+static const struct rz_sysc_soc_id_init_data rzg3e_sys_soc_id_init_data __initconst = {
+ .family = "RZ/G3E",
+ .id = 0x8679447,
+ .devid_offset = 0x304,
+ .revision_mask = GENMASK(31, 28),
+ .specific_id_mask = GENMASK(27, 0),
+ .print_id = rzg3e_sys_print_id,
+};
+
+static bool rzg3e_regmap_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SYS_LSI_OTPTSU1TRMVAL0:
+ case SYS_LSI_OTPTSU1TRMVAL1:
+ case SYS_SPI_STAADDCS0:
+ case SYS_SPI_ENDADDCS0:
+ case SYS_SPI_STAADDCS1:
+ case SYS_SPI_ENDADDCS1:
+ case SYS_VSP_CLK:
+ case SYS_GBETH0_CFG:
+ case SYS_GBETH1_CFG:
+ case SYS_PCIE_INTX_CH0:
+ case SYS_PCIE_MSI1_CH0:
+ case SYS_PCIE_MSI2_CH0:
+ case SYS_PCIE_MSI3_CH0:
+ case SYS_PCIE_MSI4_CH0:
+ case SYS_PCIE_MSI5_CH0:
+ case SYS_PCIE_PME_CH0:
+ case SYS_PCIE_ACK_CH0:
+ case SYS_PCIE_MISC_CH0:
+ case SYS_PCIE_MODE_CH0:
+ case SYS_ADC_CFG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rzg3e_regmap_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SYS_SPI_STAADDCS0:
+ case SYS_SPI_ENDADDCS0:
+ case SYS_SPI_STAADDCS1:
+ case SYS_SPI_ENDADDCS1:
+ case SYS_VSP_CLK:
+ case SYS_GBETH0_CFG:
+ case SYS_GBETH1_CFG:
+ case SYS_PCIE_INTX_CH0:
+ case SYS_PCIE_MSI1_CH0:
+ case SYS_PCIE_MSI2_CH0:
+ case SYS_PCIE_MSI3_CH0:
+ case SYS_PCIE_MSI4_CH0:
+ case SYS_PCIE_MSI5_CH0:
+ case SYS_PCIE_PME_CH0:
+ case SYS_PCIE_ACK_CH0:
+ case SYS_PCIE_MISC_CH0:
+ case SYS_PCIE_MODE_CH0:
+ case SYS_ADC_CFG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+const struct rz_sysc_init_data rzg3e_sys_init_data = {
+ .soc_id_init_data = &rzg3e_sys_soc_id_init_data,
+ .readable_reg = rzg3e_regmap_readable_reg,
+ .writeable_reg = rzg3e_regmap_writeable_reg,
+ .max_register = 0x170c,
+};
diff --git a/drivers/soc/renesas/r9a09g056-sys.c b/drivers/soc/renesas/r9a09g056-sys.c
new file mode 100644
index 000000000000..42f5eff291fd
--- /dev/null
+++ b/drivers/soc/renesas/r9a09g056-sys.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/V2N System controller (SYS) driver
+ *
+ * Copyright (C) 2025 Renesas Electronics Corp.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include "rz-sysc.h"
+
+/* Register Offsets */
+#define SYS_LSI_MODE 0x300
+#define SYS_LSI_MODE_SEC_EN BIT(16)
+/*
+ * BOOTPLLCA[1:0]
+ * [0,0] => 1.1GHZ
+ * [0,1] => 1.5GHZ
+ * [1,0] => 1.6GHZ
+ * [1,1] => 1.7GHZ
+ */
+#define SYS_LSI_MODE_STAT_BOOTPLLCA55 GENMASK(12, 11)
+#define SYS_LSI_MODE_CA55_1_7GHZ 0x3
+
+#define SYS_LSI_PRR 0x308
+#define SYS_LSI_PRR_GPU_DIS BIT(0)
+#define SYS_LSI_PRR_ISP_DIS BIT(4)
+
+#define SYS_RZV2N_FEATURE_G31 BIT(0)
+#define SYS_RZV2N_FEATURE_C55 BIT(1)
+#define SYS_RZV2N_FEATURE_SEC BIT(2)
+
+#define SYS_LSI_OTPTSU0TRMVAL0 0x320
+#define SYS_LSI_OTPTSU0TRMVAL1 0x324
+#define SYS_LSI_OTPTSU1TRMVAL0 0x330
+#define SYS_LSI_OTPTSU1TRMVAL1 0x334
+#define SYS_GBETH0_CFG 0xf00
+#define SYS_GBETH1_CFG 0xf04
+#define SYS_PCIE_INTX_CH0 0x1000
+#define SYS_PCIE_MSI1_CH0 0x1004
+#define SYS_PCIE_MSI2_CH0 0x1008
+#define SYS_PCIE_MSI3_CH0 0x100c
+#define SYS_PCIE_MSI4_CH0 0x1010
+#define SYS_PCIE_MSI5_CH0 0x1014
+#define SYS_PCIE_PME_CH0 0x1018
+#define SYS_PCIE_ACK_CH0 0x101c
+#define SYS_PCIE_MISC_CH0 0x1020
+#define SYS_PCIE_MODE_CH0 0x1024
+#define SYS_ADC_CFG 0x1600
+
+static void rzv2n_sys_print_id(struct device *dev,
+ void __iomem *sysc_base,
+ struct soc_device_attribute *soc_dev_attr)
+{
+ u32 prr_val, mode_val;
+ u8 feature_flags;
+
+ prr_val = readl(sysc_base + SYS_LSI_PRR);
+ mode_val = readl(sysc_base + SYS_LSI_MODE);
+
+ /* Check GPU, ISP and Cryptographic configuration */
+ feature_flags = !(prr_val & SYS_LSI_PRR_GPU_DIS) ? SYS_RZV2N_FEATURE_G31 : 0;
+ feature_flags |= !(prr_val & SYS_LSI_PRR_ISP_DIS) ? SYS_RZV2N_FEATURE_C55 : 0;
+ feature_flags |= (mode_val & SYS_LSI_MODE_SEC_EN) ? SYS_RZV2N_FEATURE_SEC : 0;
+
+ dev_info(dev, "Detected Renesas %s %sn%d Rev %s%s%s%s%s\n", soc_dev_attr->family,
+ soc_dev_attr->soc_id, 41 + feature_flags, soc_dev_attr->revision,
+ feature_flags ? " with" : "",
+ feature_flags & SYS_RZV2N_FEATURE_G31 ? " GE3D (Mali-G31)" : "",
+ feature_flags & SYS_RZV2N_FEATURE_SEC ? " Cryptographic engine" : "",
+ feature_flags & SYS_RZV2N_FEATURE_C55 ? " ISP (Mali-C55)" : "");
+
+ /* Check CA55 PLL configuration */
+ if (FIELD_GET(SYS_LSI_MODE_STAT_BOOTPLLCA55, mode_val) != SYS_LSI_MODE_CA55_1_7GHZ)
+ dev_warn(dev, "CA55 PLL is not set to 1.7GHz\n");
+}
+
+static const struct rz_sysc_soc_id_init_data rzv2n_sys_soc_id_init_data __initconst = {
+ .family = "RZ/V2N",
+ .id = 0x867d447,
+ .devid_offset = 0x304,
+ .revision_mask = GENMASK(31, 28),
+ .specific_id_mask = GENMASK(27, 0),
+ .print_id = rzv2n_sys_print_id,
+};
+
+static bool rzv2n_regmap_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SYS_LSI_OTPTSU0TRMVAL0:
+ case SYS_LSI_OTPTSU0TRMVAL1:
+ case SYS_LSI_OTPTSU1TRMVAL0:
+ case SYS_LSI_OTPTSU1TRMVAL1:
+ case SYS_GBETH0_CFG:
+ case SYS_GBETH1_CFG:
+ case SYS_PCIE_INTX_CH0:
+ case SYS_PCIE_MSI1_CH0:
+ case SYS_PCIE_MSI2_CH0:
+ case SYS_PCIE_MSI3_CH0:
+ case SYS_PCIE_MSI4_CH0:
+ case SYS_PCIE_MSI5_CH0:
+ case SYS_PCIE_PME_CH0:
+ case SYS_PCIE_ACK_CH0:
+ case SYS_PCIE_MISC_CH0:
+ case SYS_PCIE_MODE_CH0:
+ case SYS_ADC_CFG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rzv2n_regmap_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SYS_GBETH0_CFG:
+ case SYS_GBETH1_CFG:
+ case SYS_PCIE_INTX_CH0:
+ case SYS_PCIE_MSI1_CH0:
+ case SYS_PCIE_MSI2_CH0:
+ case SYS_PCIE_MSI3_CH0:
+ case SYS_PCIE_MSI4_CH0:
+ case SYS_PCIE_MSI5_CH0:
+ case SYS_PCIE_PME_CH0:
+ case SYS_PCIE_ACK_CH0:
+ case SYS_PCIE_MISC_CH0:
+ case SYS_PCIE_MODE_CH0:
+ case SYS_ADC_CFG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+const struct rz_sysc_init_data rzv2n_sys_init_data = {
+ .soc_id_init_data = &rzv2n_sys_soc_id_init_data,
+ .readable_reg = rzv2n_regmap_readable_reg,
+ .writeable_reg = rzv2n_regmap_writeable_reg,
+ .max_register = 0x170c,
+};
diff --git a/drivers/soc/renesas/r9a09g057-sys.c b/drivers/soc/renesas/r9a09g057-sys.c
new file mode 100644
index 000000000000..827c718ac7c5
--- /dev/null
+++ b/drivers/soc/renesas/r9a09g057-sys.c
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/V2H System controller (SYS) driver
+ *
+ * Copyright (C) 2025 Renesas Electronics Corp.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include "rz-sysc.h"
+
+/* Register Offsets */
+#define SYS_LSI_MODE 0x300
+/*
+ * BOOTPLLCA[1:0]
+ * [0,0] => 1.1GHZ
+ * [0,1] => 1.5GHZ
+ * [1,0] => 1.6GHZ
+ * [1,1] => 1.7GHZ
+ */
+#define SYS_LSI_MODE_STAT_BOOTPLLCA55 GENMASK(12, 11)
+#define SYS_LSI_MODE_CA55_1_7GHZ 0x3
+
+#define SYS_LSI_PRR 0x308
+#define SYS_LSI_PRR_GPU_DIS BIT(0)
+#define SYS_LSI_PRR_ISP_DIS BIT(4)
+
+#define SYS_LSI_OTPTSU0TRMVAL0 0x320
+#define SYS_LSI_OTPTSU0TRMVAL1 0x324
+#define SYS_LSI_OTPTSU1TRMVAL0 0x330
+#define SYS_LSI_OTPTSU1TRMVAL1 0x334
+#define SYS_GBETH0_CFG 0xf00
+#define SYS_GBETH1_CFG 0xf04
+#define SYS_PCIE_INTX_CH0 0x1000
+#define SYS_PCIE_MSI1_CH0 0x1004
+#define SYS_PCIE_MSI2_CH0 0x1008
+#define SYS_PCIE_MSI3_CH0 0x100c
+#define SYS_PCIE_MSI4_CH0 0x1010
+#define SYS_PCIE_MSI5_CH0 0x1014
+#define SYS_PCIE_PME_CH0 0x1018
+#define SYS_PCIE_ACK_CH0 0x101c
+#define SYS_PCIE_MISC_CH0 0x1020
+#define SYS_PCIE_MODE_CH0 0x1024
+#define SYS_PCIE_INTX_CH1 0x1030
+#define SYS_PCIE_MSI1_CH1 0x1034
+#define SYS_PCIE_MSI2_CH1 0x1038
+#define SYS_PCIE_MSI3_CH1 0x103c
+#define SYS_PCIE_MSI4_CH1 0x1040
+#define SYS_PCIE_MSI5_CH1 0x1044
+#define SYS_PCIE_PME_CH1 0x1048
+#define SYS_PCIE_ACK_CH1 0x104c
+#define SYS_PCIE_MISC_CH1 0x1050
+#define SYS_PCIE_MODE_CH1 0x1054
+#define SYS_PCIE_MODE 0x1060
+#define SYS_ADC_CFG 0x1600
+
+static void rzv2h_sys_print_id(struct device *dev,
+ void __iomem *sysc_base,
+ struct soc_device_attribute *soc_dev_attr)
+{
+ bool gpu_enabled, isp_enabled;
+ u32 prr_val, mode_val;
+
+ prr_val = readl(sysc_base + SYS_LSI_PRR);
+ mode_val = readl(sysc_base + SYS_LSI_MODE);
+
+ /* Check GPU and ISP configuration */
+ gpu_enabled = !(prr_val & SYS_LSI_PRR_GPU_DIS);
+ isp_enabled = !(prr_val & SYS_LSI_PRR_ISP_DIS);
+
+ dev_info(dev, "Detected Renesas %s %s Rev %s%s%s\n",
+ soc_dev_attr->family, soc_dev_attr->soc_id, soc_dev_attr->revision,
+ gpu_enabled ? " with GE3D (Mali-G31)" : "",
+ isp_enabled ? " with ISP (Mali-C55)" : "");
+
+ /* Check CA55 PLL configuration */
+ if (FIELD_GET(SYS_LSI_MODE_STAT_BOOTPLLCA55, mode_val) != SYS_LSI_MODE_CA55_1_7GHZ)
+ dev_warn(dev, "CA55 PLL is not set to 1.7GHz\n");
+}
+
+static const struct rz_sysc_soc_id_init_data rzv2h_sys_soc_id_init_data __initconst = {
+ .family = "RZ/V2H",
+ .id = 0x847a447,
+ .devid_offset = 0x304,
+ .revision_mask = GENMASK(31, 28),
+ .specific_id_mask = GENMASK(27, 0),
+ .print_id = rzv2h_sys_print_id,
+};
+
+static bool rzv2h_regmap_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SYS_LSI_OTPTSU0TRMVAL0:
+ case SYS_LSI_OTPTSU0TRMVAL1:
+ case SYS_LSI_OTPTSU1TRMVAL0:
+ case SYS_LSI_OTPTSU1TRMVAL1:
+ case SYS_GBETH0_CFG:
+ case SYS_GBETH1_CFG:
+ case SYS_PCIE_INTX_CH0:
+ case SYS_PCIE_MSI1_CH0:
+ case SYS_PCIE_MSI2_CH0:
+ case SYS_PCIE_MSI3_CH0:
+ case SYS_PCIE_MSI4_CH0:
+ case SYS_PCIE_MSI5_CH0:
+ case SYS_PCIE_PME_CH0:
+ case SYS_PCIE_ACK_CH0:
+ case SYS_PCIE_MISC_CH0:
+ case SYS_PCIE_MODE_CH0:
+ case SYS_PCIE_INTX_CH1:
+ case SYS_PCIE_MSI1_CH1:
+ case SYS_PCIE_MSI2_CH1:
+ case SYS_PCIE_MSI3_CH1:
+ case SYS_PCIE_MSI4_CH1:
+ case SYS_PCIE_MSI5_CH1:
+ case SYS_PCIE_PME_CH1:
+ case SYS_PCIE_ACK_CH1:
+ case SYS_PCIE_MISC_CH1:
+ case SYS_PCIE_MODE_CH1:
+ case SYS_PCIE_MODE:
+ case SYS_ADC_CFG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rzv2h_regmap_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SYS_GBETH0_CFG:
+ case SYS_GBETH1_CFG:
+ case SYS_PCIE_INTX_CH0:
+ case SYS_PCIE_MSI1_CH0:
+ case SYS_PCIE_MSI2_CH0:
+ case SYS_PCIE_MSI3_CH0:
+ case SYS_PCIE_MSI4_CH0:
+ case SYS_PCIE_MSI5_CH0:
+ case SYS_PCIE_PME_CH0:
+ case SYS_PCIE_ACK_CH0:
+ case SYS_PCIE_MISC_CH0:
+ case SYS_PCIE_MODE_CH0:
+ case SYS_PCIE_INTX_CH1:
+ case SYS_PCIE_MSI1_CH1:
+ case SYS_PCIE_MSI2_CH1:
+ case SYS_PCIE_MSI3_CH1:
+ case SYS_PCIE_MSI4_CH1:
+ case SYS_PCIE_MSI5_CH1:
+ case SYS_PCIE_PME_CH1:
+ case SYS_PCIE_ACK_CH1:
+ case SYS_PCIE_MISC_CH1:
+ case SYS_PCIE_MODE_CH1:
+ case SYS_PCIE_MODE:
+ case SYS_ADC_CFG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+const struct rz_sysc_init_data rzv2h_sys_init_data = {
+ .soc_id_init_data = &rzv2h_sys_soc_id_init_data,
+ .readable_reg = rzv2h_regmap_readable_reg,
+ .writeable_reg = rzv2h_regmap_writeable_reg,
+ .max_register = 0x170c,
+};
diff --git a/drivers/soc/renesas/rcar-gen4-sysc.c b/drivers/soc/renesas/rcar-gen4-sysc.c
deleted file mode 100644
index 9e5e6e077abc..000000000000
--- a/drivers/soc/renesas/rcar-gen4-sysc.c
+++ /dev/null
@@ -1,379 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * R-Car Gen4 SYSC Power management support
- *
- * Copyright (C) 2021 Renesas Electronics Corp.
- */
-
-#include <linux/bits.h>
-#include <linux/clk/renesas.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/of_address.h>
-#include <linux/pm_domain.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-#include "rcar-gen4-sysc.h"
-
-/* SYSC Common */
-#define SYSCSR 0x000 /* SYSC Status Register */
-#define SYSCPONSR(x) (0x800 + ((x) * 0x4)) /* Power-ON Status Register 0 */
-#define SYSCPOFFSR(x) (0x808 + ((x) * 0x4)) /* Power-OFF Status Register */
-#define SYSCISCR(x) (0x810 + ((x) * 0x4)) /* Interrupt Status/Clear Register */
-#define SYSCIER(x) (0x820 + ((x) * 0x4)) /* Interrupt Enable Register */
-#define SYSCIMR(x) (0x830 + ((x) * 0x4)) /* Interrupt Mask Register */
-
-/* Power Domain Registers */
-#define PDRSR(n) (0x1000 + ((n) * 0x40))
-#define PDRONCR(n) (0x1004 + ((n) * 0x40))
-#define PDROFFCR(n) (0x1008 + ((n) * 0x40))
-#define PDRESR(n) (0x100C + ((n) * 0x40))
-
-/* PWRON/PWROFF */
-#define PWRON_PWROFF BIT(0) /* Power-ON/OFF request */
-
-/* PDRESR */
-#define PDRESR_ERR BIT(0)
-
-/* PDRSR */
-#define PDRSR_OFF BIT(0) /* Power-OFF state */
-#define PDRSR_ON BIT(4) /* Power-ON state */
-#define PDRSR_OFF_STATE BIT(8) /* Processing Power-OFF sequence */
-#define PDRSR_ON_STATE BIT(12) /* Processing Power-ON sequence */
-
-#define SYSCSR_BUSY GENMASK(1, 0) /* All bit sets is not busy */
-
-#define SYSCSR_TIMEOUT 10000
-#define SYSCSR_DELAY_US 10
-
-#define PDRESR_RETRIES 1000
-#define PDRESR_DELAY_US 10
-
-#define SYSCISR_TIMEOUT 10000
-#define SYSCISR_DELAY_US 10
-
-#define RCAR_GEN4_PD_ALWAYS_ON 64
-#define NUM_DOMAINS_EACH_REG BITS_PER_TYPE(u32)
-
-static void __iomem *rcar_gen4_sysc_base;
-static DEFINE_SPINLOCK(rcar_gen4_sysc_lock); /* SMP CPUs + I/O devices */
-
-static int rcar_gen4_sysc_pwr_on_off(u8 pdr, bool on)
-{
- unsigned int reg_offs;
- u32 val;
- int ret;
-
- if (on)
- reg_offs = PDRONCR(pdr);
- else
- reg_offs = PDROFFCR(pdr);
-
- /* Wait until SYSC is ready to accept a power request */
- ret = readl_poll_timeout_atomic(rcar_gen4_sysc_base + SYSCSR, val,
- (val & SYSCSR_BUSY) == SYSCSR_BUSY,
- SYSCSR_DELAY_US, SYSCSR_TIMEOUT);
- if (ret < 0)
- return -EAGAIN;
-
- /* Submit power shutoff or power resume request */
- iowrite32(PWRON_PWROFF, rcar_gen4_sysc_base + reg_offs);
-
- return 0;
-}
-
-static int clear_irq_flags(unsigned int reg_idx, unsigned int isr_mask)
-{
- u32 val;
- int ret;
-
- iowrite32(isr_mask, rcar_gen4_sysc_base + SYSCISCR(reg_idx));
-
- ret = readl_poll_timeout_atomic(rcar_gen4_sysc_base + SYSCISCR(reg_idx),
- val, !(val & isr_mask),
- SYSCISR_DELAY_US, SYSCISR_TIMEOUT);
- if (ret < 0) {
- pr_err("\n %s : Can not clear IRQ flags in SYSCISCR", __func__);
- return -EIO;
- }
-
- return 0;
-}
-
-static int rcar_gen4_sysc_power(u8 pdr, bool on)
-{
- unsigned int isr_mask;
- unsigned int reg_idx, bit_idx;
- unsigned int status;
- unsigned long flags;
- int ret = 0;
- u32 val;
- int k;
-
- spin_lock_irqsave(&rcar_gen4_sysc_lock, flags);
-
- reg_idx = pdr / NUM_DOMAINS_EACH_REG;
- bit_idx = pdr % NUM_DOMAINS_EACH_REG;
-
- isr_mask = BIT(bit_idx);
-
- /*
- * The interrupt source needs to be enabled, but masked, to prevent the
- * CPU from receiving it.
- */
- iowrite32(ioread32(rcar_gen4_sysc_base + SYSCIER(reg_idx)) | isr_mask,
- rcar_gen4_sysc_base + SYSCIER(reg_idx));
- iowrite32(ioread32(rcar_gen4_sysc_base + SYSCIMR(reg_idx)) | isr_mask,
- rcar_gen4_sysc_base + SYSCIMR(reg_idx));
-
- ret = clear_irq_flags(reg_idx, isr_mask);
- if (ret)
- goto out;
-
- /* Submit power shutoff or resume request until it was accepted */
- for (k = 0; k < PDRESR_RETRIES; k++) {
- ret = rcar_gen4_sysc_pwr_on_off(pdr, on);
- if (ret)
- goto out;
-
- status = ioread32(rcar_gen4_sysc_base + PDRESR(pdr));
- if (!(status & PDRESR_ERR))
- break;
-
- udelay(PDRESR_DELAY_US);
- }
-
- if (k == PDRESR_RETRIES) {
- ret = -EIO;
- goto out;
- }
-
- /* Wait until the power shutoff or resume request has completed * */
- ret = readl_poll_timeout_atomic(rcar_gen4_sysc_base + SYSCISCR(reg_idx),
- val, (val & isr_mask),
- SYSCISR_DELAY_US, SYSCISR_TIMEOUT);
- if (ret < 0) {
- ret = -EIO;
- goto out;
- }
-
- /* Clear interrupt flags */
- ret = clear_irq_flags(reg_idx, isr_mask);
- if (ret)
- goto out;
-
- out:
- spin_unlock_irqrestore(&rcar_gen4_sysc_lock, flags);
-
- pr_debug("sysc power %s domain %d: %08x -> %d\n", on ? "on" : "off",
- pdr, ioread32(rcar_gen4_sysc_base + SYSCISCR(reg_idx)), ret);
- return ret;
-}
-
-static bool rcar_gen4_sysc_power_is_off(u8 pdr)
-{
- unsigned int st;
-
- st = ioread32(rcar_gen4_sysc_base + PDRSR(pdr));
-
- if (st & PDRSR_OFF)
- return true;
-
- return false;
-}
-
-struct rcar_gen4_sysc_pd {
- struct generic_pm_domain genpd;
- u8 pdr;
- unsigned int flags;
- char name[];
-};
-
-static inline struct rcar_gen4_sysc_pd *to_rcar_gen4_pd(struct generic_pm_domain *d)
-{
- return container_of(d, struct rcar_gen4_sysc_pd, genpd);
-}
-
-static int rcar_gen4_sysc_pd_power_off(struct generic_pm_domain *genpd)
-{
- struct rcar_gen4_sysc_pd *pd = to_rcar_gen4_pd(genpd);
-
- pr_debug("%s: %s\n", __func__, genpd->name);
- return rcar_gen4_sysc_power(pd->pdr, false);
-}
-
-static int rcar_gen4_sysc_pd_power_on(struct generic_pm_domain *genpd)
-{
- struct rcar_gen4_sysc_pd *pd = to_rcar_gen4_pd(genpd);
-
- pr_debug("%s: %s\n", __func__, genpd->name);
- return rcar_gen4_sysc_power(pd->pdr, true);
-}
-
-static int __init rcar_gen4_sysc_pd_setup(struct rcar_gen4_sysc_pd *pd)
-{
- struct generic_pm_domain *genpd = &pd->genpd;
- const char *name = pd->genpd.name;
- int error;
-
- if (pd->flags & PD_CPU) {
- /*
- * This domain contains a CPU core and therefore it should
- * only be turned off if the CPU is not in use.
- */
- pr_debug("PM domain %s contains %s\n", name, "CPU");
- genpd->flags |= GENPD_FLAG_ALWAYS_ON;
- } else if (pd->flags & PD_SCU) {
- /*
- * This domain contains an SCU and cache-controller, and
- * therefore it should only be turned off if the CPU cores are
- * not in use.
- */
- pr_debug("PM domain %s contains %s\n", name, "SCU");
- genpd->flags |= GENPD_FLAG_ALWAYS_ON;
- } else if (pd->flags & PD_NO_CR) {
- /*
- * This domain cannot be turned off.
- */
- genpd->flags |= GENPD_FLAG_ALWAYS_ON;
- }
-
- if (!(pd->flags & (PD_CPU | PD_SCU))) {
- /* Enable Clock Domain for I/O devices */
- genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
- genpd->attach_dev = cpg_mssr_attach_dev;
- genpd->detach_dev = cpg_mssr_detach_dev;
- }
-
- genpd->power_off = rcar_gen4_sysc_pd_power_off;
- genpd->power_on = rcar_gen4_sysc_pd_power_on;
-
- if (pd->flags & (PD_CPU | PD_NO_CR)) {
- /* Skip CPUs (handled by SMP code) and areas without control */
- pr_debug("%s: Not touching %s\n", __func__, genpd->name);
- goto finalize;
- }
-
- if (!rcar_gen4_sysc_power_is_off(pd->pdr)) {
- pr_debug("%s: %s is already powered\n", __func__, genpd->name);
- goto finalize;
- }
-
- rcar_gen4_sysc_power(pd->pdr, true);
-
-finalize:
- error = pm_genpd_init(genpd, &simple_qos_governor, false);
- if (error)
- pr_err("Failed to init PM domain %s: %d\n", name, error);
-
- return error;
-}
-
-static const struct of_device_id rcar_gen4_sysc_matches[] __initconst = {
-#ifdef CONFIG_SYSC_R8A779A0
- { .compatible = "renesas,r8a779a0-sysc", .data = &r8a779a0_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A779F0
- { .compatible = "renesas,r8a779f0-sysc", .data = &r8a779f0_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A779G0
- { .compatible = "renesas,r8a779g0-sysc", .data = &r8a779g0_sysc_info },
-#endif
- { /* sentinel */ }
-};
-
-struct rcar_gen4_pm_domains {
- struct genpd_onecell_data onecell_data;
- struct generic_pm_domain *domains[RCAR_GEN4_PD_ALWAYS_ON + 1];
-};
-
-static struct genpd_onecell_data *rcar_gen4_sysc_onecell_data;
-
-static int __init rcar_gen4_sysc_pd_init(void)
-{
- const struct rcar_gen4_sysc_info *info;
- const struct of_device_id *match;
- struct rcar_gen4_pm_domains *domains;
- struct device_node *np;
- void __iomem *base;
- unsigned int i;
- int error;
-
- np = of_find_matching_node_and_match(NULL, rcar_gen4_sysc_matches, &match);
- if (!np)
- return -ENODEV;
-
- info = match->data;
-
- base = of_iomap(np, 0);
- if (!base) {
- pr_warn("%pOF: Cannot map regs\n", np);
- error = -ENOMEM;
- goto out_put;
- }
-
- rcar_gen4_sysc_base = base;
-
- domains = kzalloc(sizeof(*domains), GFP_KERNEL);
- if (!domains) {
- error = -ENOMEM;
- goto out_put;
- }
-
- domains->onecell_data.domains = domains->domains;
- domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains);
- rcar_gen4_sysc_onecell_data = &domains->onecell_data;
-
- for (i = 0; i < info->num_areas; i++) {
- const struct rcar_gen4_sysc_area *area = &info->areas[i];
- struct rcar_gen4_sysc_pd *pd;
- size_t n;
-
- if (!area->name) {
- /* Skip NULLified area */
- continue;
- }
-
- n = strlen(area->name) + 1;
- pd = kzalloc(sizeof(*pd) + n, GFP_KERNEL);
- if (!pd) {
- error = -ENOMEM;
- goto out_put;
- }
-
- memcpy(pd->name, area->name, n);
- pd->genpd.name = pd->name;
- pd->pdr = area->pdr;
- pd->flags = area->flags;
-
- error = rcar_gen4_sysc_pd_setup(pd);
- if (error)
- goto out_put;
-
- domains->domains[area->pdr] = &pd->genpd;
-
- if (area->parent < 0)
- continue;
-
- error = pm_genpd_add_subdomain(domains->domains[area->parent],
- &pd->genpd);
- if (error) {
- pr_warn("Failed to add PM subdomain %s to parent %u\n",
- area->name, area->parent);
- goto out_put;
- }
- }
-
- error = of_genpd_add_provider_onecell(np, &domains->onecell_data);
-
-out_put:
- of_node_put(np);
- return error;
-}
-early_initcall(rcar_gen4_sysc_pd_init);
diff --git a/drivers/soc/renesas/rcar-gen4-sysc.h b/drivers/soc/renesas/rcar-gen4-sysc.h
deleted file mode 100644
index 388cfa8f8f9f..000000000000
--- a/drivers/soc/renesas/rcar-gen4-sysc.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * R-Car Gen4 System Controller
- *
- * Copyright (C) 2021 Renesas Electronics Corp.
- */
-#ifndef __SOC_RENESAS_RCAR_GEN4_SYSC_H__
-#define __SOC_RENESAS_RCAR_GEN4_SYSC_H__
-
-#include <linux/types.h>
-
-/*
- * Power Domain flags
- */
-#define PD_CPU BIT(0) /* Area contains main CPU core */
-#define PD_SCU BIT(1) /* Area contains SCU and L2 cache */
-#define PD_NO_CR BIT(2) /* Area lacks PWR{ON,OFF}CR registers */
-
-#define PD_CPU_NOCR (PD_CPU | PD_NO_CR) /* CPU area lacks CR */
-#define PD_ALWAYS_ON PD_NO_CR /* Always-on area */
-
-/*
- * Description of a Power Area
- */
-struct rcar_gen4_sysc_area {
- const char *name;
- u8 pdr; /* PDRn */
- s8 parent; /* -1 if none */
- u8 flags; /* See PD_* */
-};
-
-/*
- * SoC-specific Power Area Description
- */
-struct rcar_gen4_sysc_info {
- const struct rcar_gen4_sysc_area *areas;
- unsigned int num_areas;
-};
-
-extern const struct rcar_gen4_sysc_info r8a779a0_sysc_info;
-extern const struct rcar_gen4_sysc_info r8a779f0_sysc_info;
-extern const struct rcar_gen4_sysc_info r8a779g0_sysc_info;
-
-#endif /* __SOC_RENESAS_RCAR_GEN4_SYSC_H__ */
diff --git a/drivers/soc/renesas/rcar-rst.c b/drivers/soc/renesas/rcar-rst.c
index e1c7e91f5a86..0541990901fc 100644
--- a/drivers/soc/renesas/rcar-rst.c
+++ b/drivers/soc/renesas/rcar-rst.c
@@ -12,6 +12,8 @@
#define WDTRSTCR_RESET 0xA55A0002
#define WDTRSTCR 0x0054
+#define GEN4_WDTRSTCR_RESET 0xA55A8002
+#define GEN4_WDTRSTCR 0x0010
#define CR7BAR 0x0070
#define CR7BAREN BIT(4)
@@ -27,6 +29,12 @@ static int rcar_rst_enable_wdt_reset(void __iomem *base)
return 0;
}
+static int rcar_rst_v3u_enable_wdt_reset(void __iomem *base)
+{
+ iowrite32(GEN4_WDTRSTCR_RESET, base + GEN4_WDTRSTCR);
+ return 0;
+}
+
/*
* Most of the R-Car Gen3 SoCs have an ARM Realtime Core.
* Firmware boot address has to be set in CR7BAR before
@@ -66,6 +74,12 @@ static const struct rst_config rcar_rst_gen3 __initconst = {
.set_rproc_boot_addr = rcar_rst_set_gen3_rproc_boot_addr,
};
+/* V3U firmware doesn't enable WDT reset and there won't be updates anymore */
+static const struct rst_config rcar_rst_v3u __initconst = {
+ .modemr = 0x00, /* MODEMR0 and it has CPG related bits */
+ .configure = rcar_rst_v3u_enable_wdt_reset,
+};
+
static const struct rst_config rcar_rst_gen4 __initconst = {
.modemr = 0x00, /* MODEMR0 and it has CPG related bits */
};
@@ -101,9 +115,10 @@ static const struct of_device_id rcar_rst_matches[] __initconst = {
{ .compatible = "renesas,r8a77990-rst", .data = &rcar_rst_gen3 },
{ .compatible = "renesas,r8a77995-rst", .data = &rcar_rst_gen3 },
/* R-Car Gen4 */
- { .compatible = "renesas,r8a779a0-rst", .data = &rcar_rst_gen4 },
+ { .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/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c
deleted file mode 100644
index b0a80de34c98..000000000000
--- a/drivers/soc/renesas/rcar-sysc.c
+++ /dev/null
@@ -1,494 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * R-Car SYSC Power management support
- *
- * Copyright (C) 2014 Magnus Damm
- * Copyright (C) 2015-2017 Glider bvba
- */
-
-#include <linux/clk/renesas.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/mm.h>
-#include <linux/of_address.h>
-#include <linux/pm_domain.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/soc/renesas/rcar-sysc.h>
-
-#include "rcar-sysc.h"
-
-/* SYSC Common */
-#define SYSCSR 0x00 /* SYSC Status Register */
-#define SYSCISR 0x04 /* Interrupt Status Register */
-#define SYSCISCR 0x08 /* Interrupt Status Clear Register */
-#define SYSCIER 0x0c /* Interrupt Enable Register */
-#define SYSCIMR 0x10 /* Interrupt Mask Register */
-
-/* SYSC Status Register */
-#define SYSCSR_PONENB 1 /* Ready for power resume requests */
-#define SYSCSR_POFFENB 0 /* Ready for power shutoff requests */
-
-/*
- * Power Control Register Offsets inside the register block for each domain
- * Note: The "CR" registers for ARM cores exist on H1 only
- * Use WFI to power off, CPG/APMU to resume ARM cores on R-Car Gen2
- * Use PSCI on R-Car Gen3
- */
-#define PWRSR_OFFS 0x00 /* Power Status Register */
-#define PWROFFCR_OFFS 0x04 /* Power Shutoff Control Register */
-#define PWROFFSR_OFFS 0x08 /* Power Shutoff Status Register */
-#define PWRONCR_OFFS 0x0c /* Power Resume Control Register */
-#define PWRONSR_OFFS 0x10 /* Power Resume Status Register */
-#define PWRER_OFFS 0x14 /* Power Shutoff/Resume Error */
-
-
-#define SYSCSR_TIMEOUT 100
-#define SYSCSR_DELAY_US 1
-
-#define PWRER_RETRIES 100
-#define PWRER_DELAY_US 1
-
-#define SYSCISR_TIMEOUT 1000
-#define SYSCISR_DELAY_US 1
-
-#define RCAR_PD_ALWAYS_ON 32 /* Always-on power area */
-
-struct rcar_sysc_ch {
- u16 chan_offs;
- u8 chan_bit;
- u8 isr_bit;
-};
-
-static void __iomem *rcar_sysc_base;
-static DEFINE_SPINLOCK(rcar_sysc_lock); /* SMP CPUs + I/O devices */
-static u32 rcar_sysc_extmask_offs, rcar_sysc_extmask_val;
-
-static int rcar_sysc_pwr_on_off(const struct rcar_sysc_ch *sysc_ch, bool on)
-{
- unsigned int sr_bit, reg_offs;
- u32 val;
- int ret;
-
- if (on) {
- sr_bit = SYSCSR_PONENB;
- reg_offs = PWRONCR_OFFS;
- } else {
- sr_bit = SYSCSR_POFFENB;
- reg_offs = PWROFFCR_OFFS;
- }
-
- /* Wait until SYSC is ready to accept a power request */
- ret = readl_poll_timeout_atomic(rcar_sysc_base + SYSCSR, val,
- val & BIT(sr_bit), SYSCSR_DELAY_US,
- SYSCSR_TIMEOUT);
- if (ret)
- return -EAGAIN;
-
- /* Submit power shutoff or power resume request */
- iowrite32(BIT(sysc_ch->chan_bit),
- rcar_sysc_base + sysc_ch->chan_offs + reg_offs);
-
- return 0;
-}
-
-static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on)
-{
- unsigned int isr_mask = BIT(sysc_ch->isr_bit);
- unsigned int chan_mask = BIT(sysc_ch->chan_bit);
- unsigned int status, k;
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&rcar_sysc_lock, flags);
-
- /*
- * Mask external power requests for CPU or 3DG domains
- */
- if (rcar_sysc_extmask_val) {
- iowrite32(rcar_sysc_extmask_val,
- rcar_sysc_base + rcar_sysc_extmask_offs);
- }
-
- /*
- * The interrupt source needs to be enabled, but masked, to prevent the
- * CPU from receiving it.
- */
- iowrite32(ioread32(rcar_sysc_base + SYSCIMR) | isr_mask,
- rcar_sysc_base + SYSCIMR);
- iowrite32(ioread32(rcar_sysc_base + SYSCIER) | isr_mask,
- rcar_sysc_base + SYSCIER);
-
- iowrite32(isr_mask, rcar_sysc_base + SYSCISCR);
-
- /* Submit power shutoff or resume request until it was accepted */
- for (k = 0; k < PWRER_RETRIES; k++) {
- ret = rcar_sysc_pwr_on_off(sysc_ch, on);
- if (ret)
- goto out;
-
- status = ioread32(rcar_sysc_base +
- sysc_ch->chan_offs + PWRER_OFFS);
- if (!(status & chan_mask))
- break;
-
- udelay(PWRER_DELAY_US);
- }
-
- if (k == PWRER_RETRIES) {
- ret = -EIO;
- goto out;
- }
-
- /* Wait until the power shutoff or resume request has completed * */
- ret = readl_poll_timeout_atomic(rcar_sysc_base + SYSCISR, status,
- status & isr_mask, SYSCISR_DELAY_US,
- SYSCISR_TIMEOUT);
- if (ret)
- ret = -EIO;
-
- iowrite32(isr_mask, rcar_sysc_base + SYSCISCR);
-
- out:
- if (rcar_sysc_extmask_val)
- iowrite32(0, rcar_sysc_base + rcar_sysc_extmask_offs);
-
- spin_unlock_irqrestore(&rcar_sysc_lock, flags);
-
- pr_debug("sysc power %s domain %d: %08x -> %d\n", on ? "on" : "off",
- sysc_ch->isr_bit, ioread32(rcar_sysc_base + SYSCISR), ret);
- return ret;
-}
-
-static bool rcar_sysc_power_is_off(const struct rcar_sysc_ch *sysc_ch)
-{
- unsigned int st;
-
- st = ioread32(rcar_sysc_base + sysc_ch->chan_offs + PWRSR_OFFS);
- if (st & BIT(sysc_ch->chan_bit))
- return true;
-
- return false;
-}
-
-struct rcar_sysc_pd {
- struct generic_pm_domain genpd;
- struct rcar_sysc_ch ch;
- unsigned int flags;
- char name[];
-};
-
-static inline struct rcar_sysc_pd *to_rcar_pd(struct generic_pm_domain *d)
-{
- return container_of(d, struct rcar_sysc_pd, genpd);
-}
-
-static int rcar_sysc_pd_power_off(struct generic_pm_domain *genpd)
-{
- struct rcar_sysc_pd *pd = to_rcar_pd(genpd);
-
- pr_debug("%s: %s\n", __func__, genpd->name);
- return rcar_sysc_power(&pd->ch, false);
-}
-
-static int rcar_sysc_pd_power_on(struct generic_pm_domain *genpd)
-{
- struct rcar_sysc_pd *pd = to_rcar_pd(genpd);
-
- pr_debug("%s: %s\n", __func__, genpd->name);
- return rcar_sysc_power(&pd->ch, true);
-}
-
-static bool has_cpg_mstp;
-
-static int __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd)
-{
- struct generic_pm_domain *genpd = &pd->genpd;
- const char *name = pd->genpd.name;
- int error;
-
- if (pd->flags & PD_CPU) {
- /*
- * This domain contains a CPU core and therefore it should
- * only be turned off if the CPU is not in use.
- */
- pr_debug("PM domain %s contains %s\n", name, "CPU");
- genpd->flags |= GENPD_FLAG_ALWAYS_ON;
- } else if (pd->flags & PD_SCU) {
- /*
- * This domain contains an SCU and cache-controller, and
- * therefore it should only be turned off if the CPU cores are
- * not in use.
- */
- pr_debug("PM domain %s contains %s\n", name, "SCU");
- genpd->flags |= GENPD_FLAG_ALWAYS_ON;
- } else if (pd->flags & PD_NO_CR) {
- /*
- * This domain cannot be turned off.
- */
- genpd->flags |= GENPD_FLAG_ALWAYS_ON;
- }
-
- if (!(pd->flags & (PD_CPU | PD_SCU))) {
- /* Enable Clock Domain for I/O devices */
- genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
- if (has_cpg_mstp) {
- genpd->attach_dev = cpg_mstp_attach_dev;
- genpd->detach_dev = cpg_mstp_detach_dev;
- } else {
- genpd->attach_dev = cpg_mssr_attach_dev;
- genpd->detach_dev = cpg_mssr_detach_dev;
- }
- }
-
- genpd->power_off = rcar_sysc_pd_power_off;
- genpd->power_on = rcar_sysc_pd_power_on;
-
- if (pd->flags & (PD_CPU | PD_NO_CR)) {
- /* Skip CPUs (handled by SMP code) and areas without control */
- pr_debug("%s: Not touching %s\n", __func__, genpd->name);
- goto finalize;
- }
-
- if (!rcar_sysc_power_is_off(&pd->ch)) {
- pr_debug("%s: %s is already powered\n", __func__, genpd->name);
- goto finalize;
- }
-
- rcar_sysc_power(&pd->ch, true);
-
-finalize:
- error = pm_genpd_init(genpd, &simple_qos_governor, false);
- if (error)
- pr_err("Failed to init PM domain %s: %d\n", name, error);
-
- return error;
-}
-
-static const struct of_device_id rcar_sysc_matches[] __initconst = {
-#ifdef CONFIG_SYSC_R8A7742
- { .compatible = "renesas,r8a7742-sysc", .data = &r8a7742_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A7743
- { .compatible = "renesas,r8a7743-sysc", .data = &r8a7743_sysc_info },
- /* RZ/G1N is identical to RZ/G2M w.r.t. power domains. */
- { .compatible = "renesas,r8a7744-sysc", .data = &r8a7743_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A7745
- { .compatible = "renesas,r8a7745-sysc", .data = &r8a7745_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A77470
- { .compatible = "renesas,r8a77470-sysc", .data = &r8a77470_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A774A1
- { .compatible = "renesas,r8a774a1-sysc", .data = &r8a774a1_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A774B1
- { .compatible = "renesas,r8a774b1-sysc", .data = &r8a774b1_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A774C0
- { .compatible = "renesas,r8a774c0-sysc", .data = &r8a774c0_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A774E1
- { .compatible = "renesas,r8a774e1-sysc", .data = &r8a774e1_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A7779
- { .compatible = "renesas,r8a7779-sysc", .data = &r8a7779_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A7790
- { .compatible = "renesas,r8a7790-sysc", .data = &r8a7790_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A7791
- { .compatible = "renesas,r8a7791-sysc", .data = &r8a7791_sysc_info },
- /* R-Car M2-N is identical to R-Car M2-W w.r.t. power domains. */
- { .compatible = "renesas,r8a7793-sysc", .data = &r8a7791_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A7792
- { .compatible = "renesas,r8a7792-sysc", .data = &r8a7792_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A7794
- { .compatible = "renesas,r8a7794-sysc", .data = &r8a7794_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A7795
- { .compatible = "renesas,r8a7795-sysc", .data = &r8a7795_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A77960
- { .compatible = "renesas,r8a7796-sysc", .data = &r8a77960_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A77961
- { .compatible = "renesas,r8a77961-sysc", .data = &r8a77961_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A77965
- { .compatible = "renesas,r8a77965-sysc", .data = &r8a77965_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A77970
- { .compatible = "renesas,r8a77970-sysc", .data = &r8a77970_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A77980
- { .compatible = "renesas,r8a77980-sysc", .data = &r8a77980_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A77990
- { .compatible = "renesas,r8a77990-sysc", .data = &r8a77990_sysc_info },
-#endif
-#ifdef CONFIG_SYSC_R8A77995
- { .compatible = "renesas,r8a77995-sysc", .data = &r8a77995_sysc_info },
-#endif
- { /* sentinel */ }
-};
-
-struct rcar_pm_domains {
- struct genpd_onecell_data onecell_data;
- struct generic_pm_domain *domains[RCAR_PD_ALWAYS_ON + 1];
-};
-
-static struct genpd_onecell_data *rcar_sysc_onecell_data;
-
-static int __init rcar_sysc_pd_init(void)
-{
- const struct rcar_sysc_info *info;
- const struct of_device_id *match;
- struct rcar_pm_domains *domains;
- struct device_node *np;
- void __iomem *base;
- unsigned int i;
- int error;
-
- np = of_find_matching_node_and_match(NULL, rcar_sysc_matches, &match);
- if (!np)
- return -ENODEV;
-
- info = match->data;
-
- if (info->init) {
- error = info->init();
- if (error)
- goto out_put;
- }
-
- has_cpg_mstp = of_find_compatible_node(NULL, NULL,
- "renesas,cpg-mstp-clocks");
-
- base = of_iomap(np, 0);
- if (!base) {
- pr_warn("%pOF: Cannot map regs\n", np);
- error = -ENOMEM;
- goto out_put;
- }
-
- rcar_sysc_base = base;
-
- /* Optional External Request Mask Register */
- rcar_sysc_extmask_offs = info->extmask_offs;
- rcar_sysc_extmask_val = info->extmask_val;
-
- domains = kzalloc(sizeof(*domains), GFP_KERNEL);
- if (!domains) {
- error = -ENOMEM;
- goto out_put;
- }
-
- domains->onecell_data.domains = domains->domains;
- domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains);
- rcar_sysc_onecell_data = &domains->onecell_data;
-
- for (i = 0; i < info->num_areas; i++) {
- const struct rcar_sysc_area *area = &info->areas[i];
- struct rcar_sysc_pd *pd;
- size_t n;
-
- if (!area->name) {
- /* Skip NULLified area */
- continue;
- }
-
- n = strlen(area->name) + 1;
- pd = kzalloc(sizeof(*pd) + n, GFP_KERNEL);
- if (!pd) {
- error = -ENOMEM;
- goto out_put;
- }
-
- memcpy(pd->name, area->name, n);
- pd->genpd.name = pd->name;
- pd->ch.chan_offs = area->chan_offs;
- pd->ch.chan_bit = area->chan_bit;
- pd->ch.isr_bit = area->isr_bit;
- pd->flags = area->flags;
-
- error = rcar_sysc_pd_setup(pd);
- if (error)
- goto out_put;
-
- domains->domains[area->isr_bit] = &pd->genpd;
-
- if (area->parent < 0)
- continue;
-
- error = pm_genpd_add_subdomain(domains->domains[area->parent],
- &pd->genpd);
- if (error) {
- pr_warn("Failed to add PM subdomain %s to parent %u\n",
- area->name, area->parent);
- goto out_put;
- }
- }
-
- error = of_genpd_add_provider_onecell(np, &domains->onecell_data);
- if (!error)
- of_node_set_flag(np, OF_POPULATED);
-
-out_put:
- of_node_put(np);
- return error;
-}
-early_initcall(rcar_sysc_pd_init);
-
-void __init rcar_sysc_nullify(struct rcar_sysc_area *areas,
- unsigned int num_areas, u8 id)
-{
- unsigned int i;
-
- for (i = 0; i < num_areas; i++)
- if (areas[i].isr_bit == id) {
- areas[i].name = NULL;
- return;
- }
-}
-
-#ifdef CONFIG_ARCH_R8A7779
-static int rcar_sysc_power_cpu(unsigned int idx, bool on)
-{
- struct generic_pm_domain *genpd;
- struct rcar_sysc_pd *pd;
- unsigned int i;
-
- if (!rcar_sysc_onecell_data)
- return -ENODEV;
-
- for (i = 0; i < rcar_sysc_onecell_data->num_domains; i++) {
- genpd = rcar_sysc_onecell_data->domains[i];
- if (!genpd)
- continue;
-
- pd = to_rcar_pd(genpd);
- if (!(pd->flags & PD_CPU) || pd->ch.chan_bit != idx)
- continue;
-
- return rcar_sysc_power(&pd->ch, on);
- }
-
- return -ENOENT;
-}
-
-int rcar_sysc_power_down_cpu(unsigned int cpu)
-{
- return rcar_sysc_power_cpu(cpu, false);
-}
-
-int rcar_sysc_power_up_cpu(unsigned int cpu)
-{
- return rcar_sysc_power_cpu(cpu, true);
-}
-#endif /* CONFIG_ARCH_R8A7779 */
diff --git a/drivers/soc/renesas/rcar-sysc.h b/drivers/soc/renesas/rcar-sysc.h
deleted file mode 100644
index 266c599a0a9b..000000000000
--- a/drivers/soc/renesas/rcar-sysc.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Renesas R-Car System Controller
- *
- * Copyright (C) 2016 Glider bvba
- */
-#ifndef __SOC_RENESAS_RCAR_SYSC_H__
-#define __SOC_RENESAS_RCAR_SYSC_H__
-
-#include <linux/types.h>
-
-
-/*
- * Power Domain flags
- */
-#define PD_CPU BIT(0) /* Area contains main CPU core */
-#define PD_SCU BIT(1) /* Area contains SCU and L2 cache */
-#define PD_NO_CR BIT(2) /* Area lacks PWR{ON,OFF}CR registers */
-
-#define PD_CPU_CR PD_CPU /* CPU area has CR (R-Car H1) */
-#define PD_CPU_NOCR PD_CPU | PD_NO_CR /* CPU area lacks CR (R-Car Gen2/3) */
-#define PD_ALWAYS_ON PD_NO_CR /* Always-on area */
-
-
-/*
- * Description of a Power Area
- */
-
-struct rcar_sysc_area {
- const char *name;
- u16 chan_offs; /* Offset of PWRSR register for this area */
- u8 chan_bit; /* Bit in PWR* (except for PWRUP in PWRSR) */
- u8 isr_bit; /* Bit in SYSCI*R */
- s8 parent; /* -1 if none */
- u8 flags; /* See PD_* */
-};
-
-
-/*
- * SoC-specific Power Area Description
- */
-
-struct rcar_sysc_info {
- int (*init)(void); /* Optional */
- const struct rcar_sysc_area *areas;
- unsigned int num_areas;
- /* Optional External Request Mask Register */
- u32 extmask_offs; /* SYSCEXTMASK register offset */
- u32 extmask_val; /* SYSCEXTMASK register mask value */
-};
-
-extern const struct rcar_sysc_info r8a7742_sysc_info;
-extern const struct rcar_sysc_info r8a7743_sysc_info;
-extern const struct rcar_sysc_info r8a7745_sysc_info;
-extern const struct rcar_sysc_info r8a77470_sysc_info;
-extern const struct rcar_sysc_info r8a774a1_sysc_info;
-extern const struct rcar_sysc_info r8a774b1_sysc_info;
-extern const struct rcar_sysc_info r8a774c0_sysc_info;
-extern const struct rcar_sysc_info r8a774e1_sysc_info;
-extern const struct rcar_sysc_info r8a7779_sysc_info;
-extern const struct rcar_sysc_info r8a7790_sysc_info;
-extern const struct rcar_sysc_info r8a7791_sysc_info;
-extern const struct rcar_sysc_info r8a7792_sysc_info;
-extern const struct rcar_sysc_info r8a7794_sysc_info;
-extern struct rcar_sysc_info r8a7795_sysc_info;
-extern const struct rcar_sysc_info r8a77960_sysc_info;
-extern const struct rcar_sysc_info r8a77961_sysc_info;
-extern const struct rcar_sysc_info r8a77965_sysc_info;
-extern const struct rcar_sysc_info r8a77970_sysc_info;
-extern const struct rcar_sysc_info r8a77980_sysc_info;
-extern const struct rcar_sysc_info r8a77990_sysc_info;
-extern const struct rcar_sysc_info r8a77995_sysc_info;
-
-
- /*
- * Helpers for fixing up power area tables depending on SoC revision
- */
-
-extern void rcar_sysc_nullify(struct rcar_sysc_area *areas,
- unsigned int num_areas, u8 id);
-
-#endif /* __SOC_RENESAS_RCAR_SYSC_H__ */
diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c
index 468ebce1ea88..ee4f17bb4db4 100644
--- a/drivers/soc/renesas/renesas-soc.c
+++ b/drivers/soc/renesas/renesas-soc.c
@@ -5,6 +5,7 @@
* Copyright (C) 2014-2016 Glider bvba
*/
+#include <linux/bitfield.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -12,7 +13,6 @@
#include <linux/string.h>
#include <linux/sys_soc.h>
-
struct renesas_family {
const char name[16];
u32 reg; /* CCCR or PRR, if not in DT */
@@ -37,6 +37,10 @@ static const struct renesas_family fam_rcar_gen4 __initconst __maybe_unused = {
.name = "R-Car Gen4",
};
+static const struct renesas_family fam_rcar_gen5 __initconst __maybe_unused = {
+ .name = "R-Car Gen5",
+};
+
static const struct renesas_family fam_rmobile __initconst __maybe_unused = {
.name = "R-Mobile",
.reg = 0xe600101c, /* CCCR (Common Chip Code Register) */
@@ -85,7 +89,6 @@ static const struct renesas_family fam_shmobile __initconst __maybe_unused = {
.reg = 0xe600101c, /* CCCR (Common Chip Code Register) */
};
-
struct renesas_soc {
const struct renesas_family *family;
u32 id;
@@ -263,13 +266,22 @@ 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_rcar_x5h __initconst __maybe_unused = {
+ .family = &fam_rcar_gen5,
+ .id = 0x60,
+};
+
static const struct renesas_soc soc_shmobile_ag5 __initconst __maybe_unused = {
.family = &fam_shmobile,
.id = 0x37,
};
-
-static const struct of_device_id renesas_socs[] __initconst = {
+static const struct of_device_id renesas_socs[] __initconst __maybe_unused = {
#ifdef CONFIG_ARCH_R7S72100
{ .compatible = "renesas,r7s72100", .data = &soc_rz_a1h },
#endif
@@ -330,10 +342,8 @@ static const struct of_device_id renesas_socs[] __initconst = {
#ifdef CONFIG_ARCH_R8A7794
{ .compatible = "renesas,r8a7794", .data = &soc_rcar_e2 },
#endif
-#if defined(CONFIG_ARCH_R8A77950) || defined(CONFIG_ARCH_R8A77951)
- { .compatible = "renesas,r8a7795", .data = &soc_rcar_h3 },
-#endif
#ifdef CONFIG_ARCH_R8A77951
+ { .compatible = "renesas,r8a7795", .data = &soc_rcar_h3 },
{ .compatible = "renesas,r8a779m0", .data = &soc_rcar_h3 },
{ .compatible = "renesas,r8a779m1", .data = &soc_rcar_h3 },
{ .compatible = "renesas,r8a779m8", .data = &soc_rcar_h3 },
@@ -375,20 +385,26 @@ static const struct of_device_id renesas_socs[] __initconst = {
#ifdef CONFIG_ARCH_R8A779G0
{ .compatible = "renesas,r8a779g0", .data = &soc_rcar_v4h },
#endif
-#if defined(CONFIG_ARCH_R9A07G043)
+#ifdef CONFIG_ARCH_R8A779H0
+ { .compatible = "renesas,r8a779h0", .data = &soc_rcar_v4m },
+#endif
+#ifdef CONFIG_ARCH_R8A78000
+ { .compatible = "renesas,r8a78000", .data = &soc_rcar_x5h },
+#endif
+#ifdef CONFIG_ARCH_R9A07G043
#ifdef CONFIG_RISCV
{ .compatible = "renesas,r9a07g043", .data = &soc_rz_five },
#else
{ .compatible = "renesas,r9a07g043", .data = &soc_rz_g2ul },
#endif
#endif
-#if defined(CONFIG_ARCH_R9A07G044)
+#ifdef CONFIG_ARCH_R9A07G044
{ .compatible = "renesas,r9a07g044", .data = &soc_rz_g2l },
#endif
-#if defined(CONFIG_ARCH_R9A07G054)
+#ifdef CONFIG_ARCH_R9A07G054
{ .compatible = "renesas,r9a07g054", .data = &soc_rz_v2l },
#endif
-#if defined(CONFIG_ARCH_R9A09G011)
+#ifdef CONFIG_ARCH_R9A09G011
{ .compatible = "renesas,r9a09g011", .data = &soc_rz_v2m },
#endif
#ifdef CONFIG_ARCH_SH73A0
@@ -431,6 +447,7 @@ static const struct of_device_id renesas_ids[] __initconst = {
{ .compatible = "renesas,r9a07g043-sysc", .data = &id_rzg2l },
{ .compatible = "renesas,r9a07g044-sysc", .data = &id_rzg2l },
{ .compatible = "renesas,r9a07g054-sysc", .data = &id_rzg2l },
+ { .compatible = "renesas,r9a08g045-sysc", .data = &id_rzg2l },
{ .compatible = "renesas,r9a09g011-sys", .data = &id_rzv2m },
{ .compatible = "renesas,prr", .data = &id_prr },
{ /* sentinel */ }
@@ -471,12 +488,11 @@ static int __init renesas_soc_init(void)
}
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
- if (!soc_dev_attr)
+ if (!soc_dev_attr) {
+ if (chipid)
+ iounmap(chipid);
return -ENOMEM;
-
- np = of_find_node_by_path("/");
- of_property_read_string(np, "model", &soc_dev_attr->machine);
- of_node_put(np);
+ }
soc_dev_attr->family = kstrdup_const(family->name, GFP_KERNEL);
soc_dev_attr->soc_id = kstrdup_const(soc_id, GFP_KERNEL);
@@ -509,8 +525,7 @@ static int __init renesas_soc_init(void)
eshi, eslo);
}
- if (soc->id &&
- ((product & id->mask) >> __ffs(id->mask)) != soc->id) {
+ if (soc->id && field_get(id->mask, product) != soc->id) {
pr_warn("SoC mismatch (product = 0x%x)\n", product);
ret = -ENODEV;
goto free_soc_dev_attr;
diff --git a/drivers/soc/renesas/rmobile-sysc.c b/drivers/soc/renesas/rmobile-sysc.c
deleted file mode 100644
index 204e6135180b..000000000000
--- a/drivers/soc/renesas/rmobile-sysc.c
+++ /dev/null
@@ -1,354 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * rmobile power management support
- *
- * Copyright (C) 2012 Renesas Solutions Corp.
- * Copyright (C) 2012 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- * Copyright (C) 2014 Glider bvba
- *
- * based on pm-sh7372.c
- * Copyright (C) 2011 Magnus Damm
- */
-#include <linux/clk/renesas.h>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/pm.h>
-#include <linux/pm_clock.h>
-#include <linux/pm_domain.h>
-#include <linux/slab.h>
-
-#include <asm/io.h>
-
-/* SYSC */
-#define SPDCR 0x08 /* SYS Power Down Control Register */
-#define SWUCR 0x14 /* SYS Wakeup Control Register */
-#define PSTR 0x80 /* Power Status Register */
-
-#define PSTR_RETRIES 100
-#define PSTR_DELAY_US 10
-
-struct rmobile_pm_domain {
- struct generic_pm_domain genpd;
- struct dev_power_governor *gov;
- int (*suspend)(void);
- void __iomem *base;
- unsigned int bit_shift;
-};
-
-static inline
-struct rmobile_pm_domain *to_rmobile_pd(struct generic_pm_domain *d)
-{
- return container_of(d, struct rmobile_pm_domain, genpd);
-}
-
-static int rmobile_pd_power_down(struct generic_pm_domain *genpd)
-{
- struct rmobile_pm_domain *rmobile_pd = to_rmobile_pd(genpd);
- unsigned int mask = BIT(rmobile_pd->bit_shift);
-
- if (rmobile_pd->suspend) {
- int ret = rmobile_pd->suspend();
-
- if (ret)
- return ret;
- }
-
- if (readl(rmobile_pd->base + PSTR) & mask) {
- unsigned int retry_count;
- writel(mask, rmobile_pd->base + SPDCR);
-
- for (retry_count = PSTR_RETRIES; retry_count; retry_count--) {
- if (!(readl(rmobile_pd->base + SPDCR) & mask))
- break;
- cpu_relax();
- }
- }
-
- pr_debug("%s: Power off, 0x%08x -> PSTR = 0x%08x\n", genpd->name, mask,
- readl(rmobile_pd->base + PSTR));
-
- return 0;
-}
-
-static int __rmobile_pd_power_up(struct rmobile_pm_domain *rmobile_pd)
-{
- unsigned int mask = BIT(rmobile_pd->bit_shift);
- unsigned int retry_count;
- int ret = 0;
-
- if (readl(rmobile_pd->base + PSTR) & mask)
- return ret;
-
- writel(mask, rmobile_pd->base + SWUCR);
-
- for (retry_count = 2 * PSTR_RETRIES; retry_count; retry_count--) {
- if (!(readl(rmobile_pd->base + SWUCR) & mask))
- break;
- if (retry_count > PSTR_RETRIES)
- udelay(PSTR_DELAY_US);
- else
- cpu_relax();
- }
- if (!retry_count)
- ret = -EIO;
-
- pr_debug("%s: Power on, 0x%08x -> PSTR = 0x%08x\n",
- rmobile_pd->genpd.name, mask,
- readl(rmobile_pd->base + PSTR));
-
- return ret;
-}
-
-static int rmobile_pd_power_up(struct generic_pm_domain *genpd)
-{
- return __rmobile_pd_power_up(to_rmobile_pd(genpd));
-}
-
-static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
-{
- struct generic_pm_domain *genpd = &rmobile_pd->genpd;
- struct dev_power_governor *gov = rmobile_pd->gov;
-
- genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
- genpd->attach_dev = cpg_mstp_attach_dev;
- genpd->detach_dev = cpg_mstp_detach_dev;
-
- if (!(genpd->flags & GENPD_FLAG_ALWAYS_ON)) {
- genpd->power_off = rmobile_pd_power_down;
- genpd->power_on = rmobile_pd_power_up;
- __rmobile_pd_power_up(rmobile_pd);
- }
-
- pm_genpd_init(genpd, gov ? : &simple_qos_governor, false);
-}
-
-static int rmobile_pd_suspend_console(void)
-{
- /*
- * Serial consoles make use of SCIF hardware located in this domain,
- * hence keep the power domain on if "no_console_suspend" is set.
- */
- return console_suspend_enabled ? 0 : -EBUSY;
-}
-
-enum pd_types {
- PD_NORMAL,
- PD_CPU,
- PD_CONSOLE,
- PD_DEBUG,
- PD_MEMCTL,
-};
-
-#define MAX_NUM_SPECIAL_PDS 16
-
-static struct special_pd {
- struct device_node *pd;
- enum pd_types type;
-} special_pds[MAX_NUM_SPECIAL_PDS] __initdata;
-
-static unsigned int num_special_pds __initdata;
-
-static const struct of_device_id special_ids[] __initconst = {
- { .compatible = "arm,coresight-etm3x", .data = (void *)PD_DEBUG },
- { .compatible = "renesas,dbsc-r8a73a4", .data = (void *)PD_MEMCTL, },
- { .compatible = "renesas,dbsc3-r8a7740", .data = (void *)PD_MEMCTL, },
- { .compatible = "renesas,sbsc-sh73a0", .data = (void *)PD_MEMCTL, },
- { /* sentinel */ },
-};
-
-static void __init add_special_pd(struct device_node *np, enum pd_types type)
-{
- unsigned int i;
- struct device_node *pd;
-
- pd = of_parse_phandle(np, "power-domains", 0);
- if (!pd)
- return;
-
- for (i = 0; i < num_special_pds; i++)
- if (pd == special_pds[i].pd && type == special_pds[i].type) {
- of_node_put(pd);
- return;
- }
-
- if (num_special_pds == ARRAY_SIZE(special_pds)) {
- pr_warn("Too many special PM domains\n");
- of_node_put(pd);
- return;
- }
-
- pr_debug("Special PM domain %pOFn type %d for %pOF\n", pd, type, np);
-
- special_pds[num_special_pds].pd = pd;
- special_pds[num_special_pds].type = type;
- num_special_pds++;
-}
-
-static void __init get_special_pds(void)
-{
- struct device_node *np;
- const struct of_device_id *id;
-
- /* PM domains containing CPUs */
- for_each_of_cpu_node(np)
- add_special_pd(np, PD_CPU);
-
- /* PM domain containing console */
- if (of_stdout)
- add_special_pd(of_stdout, PD_CONSOLE);
-
- /* PM domains containing other special devices */
- for_each_matching_node_and_match(np, special_ids, &id)
- add_special_pd(np, (enum pd_types)id->data);
-}
-
-static void __init put_special_pds(void)
-{
- unsigned int i;
-
- for (i = 0; i < num_special_pds; i++)
- of_node_put(special_pds[i].pd);
-}
-
-static enum pd_types __init pd_type(const struct device_node *pd)
-{
- unsigned int i;
-
- for (i = 0; i < num_special_pds; i++)
- if (pd == special_pds[i].pd)
- return special_pds[i].type;
-
- return PD_NORMAL;
-}
-
-static void __init rmobile_setup_pm_domain(struct device_node *np,
- struct rmobile_pm_domain *pd)
-{
- const char *name = pd->genpd.name;
-
- switch (pd_type(np)) {
- case PD_CPU:
- /*
- * This domain contains the CPU core and therefore it should
- * only be turned off if the CPU is not in use.
- */
- pr_debug("PM domain %s contains CPU\n", name);
- pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
- break;
-
- case PD_CONSOLE:
- pr_debug("PM domain %s contains serial console\n", name);
- pd->gov = &pm_domain_always_on_gov;
- pd->suspend = rmobile_pd_suspend_console;
- break;
-
- case PD_DEBUG:
- /*
- * This domain contains the Coresight-ETM hardware block and
- * therefore it should only be turned off if the debug module
- * is not in use.
- */
- pr_debug("PM domain %s contains Coresight-ETM\n", name);
- pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
- break;
-
- case PD_MEMCTL:
- /*
- * This domain contains a memory-controller and therefore it
- * should only be turned off if memory is not in use.
- */
- pr_debug("PM domain %s contains MEMCTL\n", name);
- pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
- break;
-
- case PD_NORMAL:
- if (pd->bit_shift == ~0) {
- /* Top-level always-on domain */
- pr_debug("PM domain %s is always-on domain\n", name);
- pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
- }
- break;
- }
-
- rmobile_init_pm_domain(pd);
-}
-
-static int __init rmobile_add_pm_domains(void __iomem *base,
- struct device_node *parent,
- struct generic_pm_domain *genpd_parent)
-{
- struct device_node *np;
-
- for_each_child_of_node(parent, np) {
- struct rmobile_pm_domain *pd;
- u32 idx = ~0;
-
- if (of_property_read_u32(np, "reg", &idx)) {
- /* always-on domain */
- }
-
- pd = kzalloc(sizeof(*pd), GFP_KERNEL);
- if (!pd) {
- of_node_put(np);
- return -ENOMEM;
- }
-
- pd->genpd.name = np->name;
- pd->base = base;
- pd->bit_shift = idx;
-
- rmobile_setup_pm_domain(np, pd);
- if (genpd_parent)
- pm_genpd_add_subdomain(genpd_parent, &pd->genpd);
- of_genpd_add_provider_simple(np, &pd->genpd);
-
- rmobile_add_pm_domains(base, np, &pd->genpd);
- }
- return 0;
-}
-
-static int __init rmobile_init_pm_domains(void)
-{
- struct device_node *np, *pmd;
- bool scanned = false;
- void __iomem *base;
- int ret = 0;
-
- for_each_compatible_node(np, NULL, "renesas,sysc-rmobile") {
- base = of_iomap(np, 0);
- if (!base) {
- pr_warn("%pOF cannot map reg 0\n", np);
- continue;
- }
-
- pmd = of_get_child_by_name(np, "pm-domains");
- if (!pmd) {
- iounmap(base);
- pr_warn("%pOF lacks pm-domains node\n", np);
- continue;
- }
-
- if (!scanned) {
- /* Find PM domains containing special blocks */
- get_special_pds();
- scanned = true;
- }
-
- ret = rmobile_add_pm_domains(base, pmd, NULL);
- of_node_put(pmd);
- if (ret) {
- of_node_put(np);
- break;
- }
-
- fwnode_dev_initialized(&np->fwnode, true);
- }
-
- put_special_pds();
-
- return ret;
-}
-
-core_initcall(rmobile_init_pm_domains);
diff --git a/drivers/soc/renesas/rz-sysc.c b/drivers/soc/renesas/rz-sysc.c
new file mode 100644
index 000000000000..ae727d9c8cc5
--- /dev/null
+++ b/drivers/soc/renesas/rz-sysc.c
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ System controller driver
+ *
+ * Copyright (C) 2024 Renesas Electronics Corp.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/sys_soc.h>
+
+#include "rz-sysc.h"
+
+/**
+ * struct rz_sysc - RZ SYSC private data structure
+ * @base: SYSC base address
+ * @dev: SYSC device pointer
+ */
+struct rz_sysc {
+ void __iomem *base;
+ struct device *dev;
+};
+
+static int rz_sysc_soc_init(struct rz_sysc *sysc, const struct of_device_id *match)
+{
+ const struct rz_sysc_init_data *sysc_data = match->data;
+ const struct rz_sysc_soc_id_init_data *soc_data = sysc_data->soc_id_init_data;
+ struct soc_device_attribute *soc_dev_attr;
+ const char *soc_id_start, *soc_id_end;
+ u32 val, revision, specific_id;
+ struct soc_device *soc_dev;
+ char soc_id[32] = {0};
+ size_t size;
+
+ soc_id_start = strchr(match->compatible, ',') + 1;
+ soc_id_end = strchr(match->compatible, '-');
+ size = soc_id_end - soc_id_start + 1;
+ if (size > 32)
+ size = sizeof(soc_id);
+ strscpy(soc_id, soc_id_start, size);
+
+ soc_dev_attr = devm_kzalloc(sysc->dev, sizeof(*soc_dev_attr), GFP_KERNEL);
+ if (!soc_dev_attr)
+ return -ENOMEM;
+
+ soc_dev_attr->family = devm_kstrdup(sysc->dev, soc_data->family, GFP_KERNEL);
+ if (!soc_dev_attr->family)
+ return -ENOMEM;
+
+ soc_dev_attr->soc_id = devm_kstrdup(sysc->dev, soc_id, GFP_KERNEL);
+ if (!soc_dev_attr->soc_id)
+ return -ENOMEM;
+
+ val = readl(sysc->base + soc_data->devid_offset);
+ revision = field_get(soc_data->revision_mask, val);
+ specific_id = field_get(soc_data->specific_id_mask, val);
+ soc_dev_attr->revision = devm_kasprintf(sysc->dev, GFP_KERNEL, "%u", revision);
+ if (!soc_dev_attr->revision)
+ return -ENOMEM;
+
+ if (soc_data->id && specific_id != soc_data->id) {
+ dev_warn(sysc->dev, "SoC mismatch (product = 0x%x)\n", specific_id);
+ return -ENODEV;
+ }
+
+ /* Try to call SoC-specific device identification */
+ if (soc_data->print_id) {
+ soc_data->print_id(sysc->dev, sysc->base, soc_dev_attr);
+ } else {
+ dev_info(sysc->dev, "Detected Renesas %s %s Rev %s\n",
+ soc_dev_attr->family, soc_dev_attr->soc_id, soc_dev_attr->revision);
+ }
+
+ soc_dev = soc_device_register(soc_dev_attr);
+ if (IS_ERR(soc_dev))
+ return PTR_ERR(soc_dev);
+
+ return 0;
+}
+
+static const struct of_device_id rz_sysc_match[] = {
+#ifdef CONFIG_SYSC_R9A08G045
+ { .compatible = "renesas,r9a08g045-sysc", .data = &rzg3s_sysc_init_data },
+#endif
+#ifdef CONFIG_SYS_R9A09G047
+ { .compatible = "renesas,r9a09g047-sys", .data = &rzg3e_sys_init_data },
+#endif
+#ifdef CONFIG_SYS_R9A09G056
+ { .compatible = "renesas,r9a09g056-sys", .data = &rzv2n_sys_init_data },
+#endif
+#ifdef CONFIG_SYS_R9A09G057
+ { .compatible = "renesas,r9a09g057-sys", .data = &rzv2h_sys_init_data },
+#endif
+ { }
+};
+MODULE_DEVICE_TABLE(of, rz_sysc_match);
+
+static int rz_sysc_probe(struct platform_device *pdev)
+{
+ const struct rz_sysc_init_data *data;
+ const struct of_device_id *match;
+ struct device *dev = &pdev->dev;
+ struct regmap *regmap;
+ struct rz_sysc *sysc;
+ int ret;
+
+ struct regmap_config *regmap_cfg __free(kfree) = kzalloc(sizeof(*regmap_cfg), GFP_KERNEL);
+ if (!regmap_cfg)
+ return -ENOMEM;
+
+ match = of_match_node(rz_sysc_match, dev->of_node);
+ if (!match)
+ return -ENODEV;
+
+ data = match->data;
+
+ sysc = devm_kzalloc(dev, sizeof(*sysc), GFP_KERNEL);
+ if (!sysc)
+ return -ENOMEM;
+
+ sysc->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(sysc->base))
+ return PTR_ERR(sysc->base);
+
+ sysc->dev = dev;
+ ret = rz_sysc_soc_init(sysc, match);
+ if (ret)
+ return ret;
+
+ regmap_cfg->name = "rz_sysc_regs";
+ regmap_cfg->reg_bits = 32;
+ regmap_cfg->reg_stride = 4;
+ regmap_cfg->val_bits = 32;
+ regmap_cfg->fast_io = true;
+ regmap_cfg->max_register = data->max_register;
+ regmap_cfg->readable_reg = data->readable_reg;
+ regmap_cfg->writeable_reg = data->writeable_reg;
+
+ regmap = devm_regmap_init_mmio(dev, sysc->base, regmap_cfg);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return of_syscon_register_regmap(dev->of_node, regmap);
+}
+
+static struct platform_driver rz_sysc_driver = {
+ .driver = {
+ .name = "renesas-rz-sysc",
+ .suppress_bind_attrs = true,
+ .of_match_table = rz_sysc_match
+ },
+ .probe = rz_sysc_probe
+};
+
+static int __init rz_sysc_init(void)
+{
+ return platform_driver_register(&rz_sysc_driver);
+}
+subsys_initcall(rz_sysc_init);
+
+MODULE_DESCRIPTION("Renesas RZ System Controller Driver");
+MODULE_AUTHOR("Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/renesas/rz-sysc.h b/drivers/soc/renesas/rz-sysc.h
new file mode 100644
index 000000000000..88929bf21cb1
--- /dev/null
+++ b/drivers/soc/renesas/rz-sysc.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Renesas RZ System Controller
+ *
+ * Copyright (C) 2024 Renesas Electronics Corp.
+ */
+
+#ifndef __SOC_RENESAS_RZ_SYSC_H__
+#define __SOC_RENESAS_RZ_SYSC_H__
+
+#include <linux/device.h>
+#include <linux/sys_soc.h>
+#include <linux/types.h>
+
+/**
+ * struct rz_syc_soc_id_init_data - RZ SYSC SoC identification initialization data
+ * @family: RZ SoC family
+ * @id: RZ SoC expected ID
+ * @devid_offset: SYSC SoC ID register offset
+ * @revision_mask: SYSC SoC ID revision mask
+ * @specific_id_mask: SYSC SoC ID specific ID mask
+ * @print_id: print SoC-specific extended device identification
+ */
+struct rz_sysc_soc_id_init_data {
+ const char * const family;
+ u32 id;
+ u32 devid_offset;
+ u32 revision_mask;
+ u32 specific_id_mask;
+ void (*print_id)(struct device *dev, void __iomem *sysc_base,
+ struct soc_device_attribute *soc_dev_attr);
+};
+
+/**
+ * struct rz_sysc_init_data - RZ SYSC initialization data
+ * @soc_id_init_data: RZ SYSC SoC ID initialization data
+ * @writeable_reg: Regmap writeable register check function
+ * @readable_reg: Regmap readable register check function
+ * @max_register: Maximum SYSC register offset to be used by the regmap config
+ */
+struct rz_sysc_init_data {
+ const struct rz_sysc_soc_id_init_data *soc_id_init_data;
+ bool (*writeable_reg)(struct device *dev, unsigned int reg);
+ bool (*readable_reg)(struct device *dev, unsigned int reg);
+ u32 max_register;
+};
+
+extern const struct rz_sysc_init_data rzg3e_sys_init_data;
+extern const struct rz_sysc_init_data rzg3s_sysc_init_data;
+extern const struct rz_sysc_init_data rzv2h_sys_init_data;
+extern const struct rz_sysc_init_data rzv2n_sys_init_data;
+
+#endif /* __SOC_RENESAS_RZ_SYSC_H__ */
diff --git a/drivers/soc/rockchip/Kconfig b/drivers/soc/rockchip/Kconfig
index aff2f7e95237..785f60c6f3ad 100644
--- a/drivers/soc/rockchip/Kconfig
+++ b/drivers/soc/rockchip/Kconfig
@@ -22,18 +22,6 @@ config ROCKCHIP_IODOMAIN
necessary for the io domain setting of the SoC to match the
voltage supplied by the regulators.
-config ROCKCHIP_PM_DOMAINS
- bool "Rockchip generic power domain"
- depends on PM
- select PM_GENERIC_DOMAINS
- help
- Say y here to enable power domain support.
- In order to meet high performance and low power requirements, a power
- management unit is designed or saving power when RK3288 in low power
- mode. The RK3288 PMU is dedicated for managing the power of the whole chip.
-
- If unsure, say N.
-
config ROCKCHIP_DTPM
tristate "Rockchip DTPM hierarchy"
depends on DTPM && m
diff --git a/drivers/soc/rockchip/Makefile b/drivers/soc/rockchip/Makefile
index 05f31a4e743c..23d414433c8c 100644
--- a/drivers/soc/rockchip/Makefile
+++ b/drivers/soc/rockchip/Makefile
@@ -4,5 +4,4 @@
#
obj-$(CONFIG_ROCKCHIP_GRF) += grf.o
obj-$(CONFIG_ROCKCHIP_IODOMAIN) += io-domain.o
-obj-$(CONFIG_ROCKCHIP_PM_DOMAINS) += pm_domains.o
obj-$(CONFIG_ROCKCHIP_DTPM) += dtpm.o
diff --git a/drivers/soc/rockchip/dtpm.c b/drivers/soc/rockchip/dtpm.c
index 5a23784b5221..b36d4f752c30 100644
--- a/drivers/soc/rockchip/dtpm.c
+++ b/drivers/soc/rockchip/dtpm.c
@@ -12,33 +12,33 @@
#include <linux/platform_device.h>
static struct dtpm_node __initdata rk3399_hierarchy[] = {
- [0]{ .name = "rk3399",
- .type = DTPM_NODE_VIRTUAL },
- [1]{ .name = "package",
- .type = DTPM_NODE_VIRTUAL,
- .parent = &rk3399_hierarchy[0] },
- [2]{ .name = "/cpus/cpu@0",
- .type = DTPM_NODE_DT,
- .parent = &rk3399_hierarchy[1] },
- [3]{ .name = "/cpus/cpu@1",
- .type = DTPM_NODE_DT,
- .parent = &rk3399_hierarchy[1] },
- [4]{ .name = "/cpus/cpu@2",
- .type = DTPM_NODE_DT,
- .parent = &rk3399_hierarchy[1] },
- [5]{ .name = "/cpus/cpu@3",
- .type = DTPM_NODE_DT,
- .parent = &rk3399_hierarchy[1] },
- [6]{ .name = "/cpus/cpu@100",
- .type = DTPM_NODE_DT,
- .parent = &rk3399_hierarchy[1] },
- [7]{ .name = "/cpus/cpu@101",
- .type = DTPM_NODE_DT,
- .parent = &rk3399_hierarchy[1] },
- [8]{ .name = "/gpu@ff9a0000",
- .type = DTPM_NODE_DT,
- .parent = &rk3399_hierarchy[1] },
- [9]{ /* sentinel */ }
+ [0] = { .name = "rk3399",
+ .type = DTPM_NODE_VIRTUAL },
+ [1] = { .name = "package",
+ .type = DTPM_NODE_VIRTUAL,
+ .parent = &rk3399_hierarchy[0] },
+ [2] = { .name = "/cpus/cpu@0",
+ .type = DTPM_NODE_DT,
+ .parent = &rk3399_hierarchy[1] },
+ [3] = { .name = "/cpus/cpu@1",
+ .type = DTPM_NODE_DT,
+ .parent = &rk3399_hierarchy[1] },
+ [4] = { .name = "/cpus/cpu@2",
+ .type = DTPM_NODE_DT,
+ .parent = &rk3399_hierarchy[1] },
+ [5] = { .name = "/cpus/cpu@3",
+ .type = DTPM_NODE_DT,
+ .parent = &rk3399_hierarchy[1] },
+ [6] = { .name = "/cpus/cpu@100",
+ .type = DTPM_NODE_DT,
+ .parent = &rk3399_hierarchy[1] },
+ [7] = { .name = "/cpus/cpu@101",
+ .type = DTPM_NODE_DT,
+ .parent = &rk3399_hierarchy[1] },
+ [8] = { .name = "/gpu@ff9a0000",
+ .type = DTPM_NODE_DT,
+ .parent = &rk3399_hierarchy[1] },
+ [9] = { /* sentinel */ }
};
static struct of_device_id __initdata rockchip_dtpm_match_table[] = {
diff --git a/drivers/soc/rockchip/grf.c b/drivers/soc/rockchip/grf.c
index 15a3970e3509..27bfa09ff251 100644
--- a/drivers/soc/rockchip/grf.c
+++ b/drivers/soc/rockchip/grf.c
@@ -6,13 +6,12 @@
*/
#include <linux/err.h>
+#include <linux/hw_bitfield.h>
#include <linux/mfd/syscon.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
-#define HIWORD_UPDATE(val, mask, shift) \
- ((val) << (shift) | (mask) << ((shift) + 16))
struct rockchip_grf_value {
const char *desc;
@@ -32,7 +31,7 @@ static const struct rockchip_grf_value rk3036_defaults[] __initconst = {
* Disable auto jtag/sdmmc switching that causes issues with the
* clock-framework and the mmc controllers making them unreliable.
*/
- { "jtag switching", RK3036_GRF_SOC_CON0, HIWORD_UPDATE(0, 1, 11) },
+ { "jtag switching", RK3036_GRF_SOC_CON0, FIELD_PREP_WM16_CONST(BIT(11), 0) },
};
static const struct rockchip_grf_info rk3036_grf __initconst = {
@@ -41,9 +40,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) },
+ { "jtag switching", RK3128_GRF_SOC_CON0, FIELD_PREP_WM16_CONST(BIT(8), 0) },
+ { "vpu main clock", RK3128_GRF_SOC_CON1, FIELD_PREP_WM16_CONST(BIT(10), 0) },
};
static const struct rockchip_grf_info rk3128_grf __initconst = {
@@ -54,7 +55,7 @@ static const struct rockchip_grf_info rk3128_grf __initconst = {
#define RK3228_GRF_SOC_CON6 0x418
static const struct rockchip_grf_value rk3228_defaults[] __initconst = {
- { "jtag switching", RK3228_GRF_SOC_CON6, HIWORD_UPDATE(0, 1, 8) },
+ { "jtag switching", RK3228_GRF_SOC_CON6, FIELD_PREP_WM16_CONST(BIT(8), 0) },
};
static const struct rockchip_grf_info rk3228_grf __initconst = {
@@ -66,8 +67,8 @@ static const struct rockchip_grf_info rk3228_grf __initconst = {
#define RK3288_GRF_SOC_CON2 0x24c
static const struct rockchip_grf_value rk3288_defaults[] __initconst = {
- { "jtag switching", RK3288_GRF_SOC_CON0, HIWORD_UPDATE(0, 1, 12) },
- { "pwm select", RK3288_GRF_SOC_CON2, HIWORD_UPDATE(1, 1, 0) },
+ { "jtag switching", RK3288_GRF_SOC_CON0, FIELD_PREP_WM16_CONST(BIT(12), 0) },
+ { "pwm select", RK3288_GRF_SOC_CON2, FIELD_PREP_WM16_CONST(BIT(0), 1) },
};
static const struct rockchip_grf_info rk3288_grf __initconst = {
@@ -78,7 +79,7 @@ static const struct rockchip_grf_info rk3288_grf __initconst = {
#define RK3328_GRF_SOC_CON4 0x410
static const struct rockchip_grf_value rk3328_defaults[] __initconst = {
- { "jtag switching", RK3328_GRF_SOC_CON4, HIWORD_UPDATE(0, 1, 12) },
+ { "jtag switching", RK3328_GRF_SOC_CON4, FIELD_PREP_WM16_CONST(BIT(12), 0) },
};
static const struct rockchip_grf_info rk3328_grf __initconst = {
@@ -89,7 +90,8 @@ static const struct rockchip_grf_info rk3328_grf __initconst = {
#define RK3368_GRF_SOC_CON15 0x43c
static const struct rockchip_grf_value rk3368_defaults[] __initconst = {
- { "jtag switching", RK3368_GRF_SOC_CON15, HIWORD_UPDATE(0, 1, 13) },
+ { "jtag switching", RK3368_GRF_SOC_CON15, FIELD_PREP_WM16_CONST(BIT(13), 0) },
+ { "pwm select", RK3368_GRF_SOC_CON15, FIELD_PREP_WM16_CONST(BIT(12), 1) },
};
static const struct rockchip_grf_info rk3368_grf __initconst = {
@@ -97,10 +99,21 @@ static const struct rockchip_grf_info rk3368_grf __initconst = {
.num_values = ARRAY_SIZE(rk3368_defaults),
};
+#define RK3368_PMUGRF_SOC_CON0 0x100
+
+static const struct rockchip_grf_value rk3368_pmugrf_defaults[] __initconst = {
+ { "pwm2 select", RK3368_PMUGRF_SOC_CON0, FIELD_PREP_WM16_CONST(BIT(7), 0) },
+};
+
+static const struct rockchip_grf_info rk3368_pmugrf __initconst = {
+ .values = rk3368_pmugrf_defaults,
+ .num_values = ARRAY_SIZE(rk3368_pmugrf_defaults),
+};
+
#define RK3399_GRF_SOC_CON7 0xe21c
static const struct rockchip_grf_value rk3399_defaults[] __initconst = {
- { "jtag switching", RK3399_GRF_SOC_CON7, HIWORD_UPDATE(0, 1, 12) },
+ { "jtag switching", RK3399_GRF_SOC_CON7, FIELD_PREP_WM16_CONST(BIT(12), 0) },
};
static const struct rockchip_grf_info rk3399_grf __initconst = {
@@ -111,9 +124,9 @@ static const struct rockchip_grf_info rk3399_grf __initconst = {
#define RK3566_GRF_USB3OTG0_CON1 0x0104
static const struct rockchip_grf_value rk3566_defaults[] __initconst = {
- { "usb3otg port switch", RK3566_GRF_USB3OTG0_CON1, HIWORD_UPDATE(0, 1, 12) },
- { "usb3otg clock switch", RK3566_GRF_USB3OTG0_CON1, HIWORD_UPDATE(1, 1, 7) },
- { "usb3otg disable usb3", RK3566_GRF_USB3OTG0_CON1, HIWORD_UPDATE(1, 1, 0) },
+ { "usb3otg port switch", RK3566_GRF_USB3OTG0_CON1, FIELD_PREP_WM16_CONST(BIT(12), 0) },
+ { "usb3otg clock switch", RK3566_GRF_USB3OTG0_CON1, FIELD_PREP_WM16_CONST(BIT(7), 1) },
+ { "usb3otg disable usb3", RK3566_GRF_USB3OTG0_CON1, FIELD_PREP_WM16_CONST(BIT(0), 1) },
};
static const struct rockchip_grf_info rk3566_pipegrf __initconst = {
@@ -121,6 +134,39 @@ 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, FIELD_PREP_WM16_CONST(GENMASK(7, 6), 3) },
+ { "i3c1 weakpull", RK3576_SYSGRF_SOC_CON1, FIELD_PREP_WM16_CONST(GENMASK(9, 8), 3) },
+};
+
+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, FIELD_PREP_WM16_CONST(BIT(1), 0) },
+};
+
+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 = {
+ { "jtag switching", RK3588_GRF_SOC_CON6, FIELD_PREP_WM16_CONST(BIT(14), 0) },
+};
+
+static const struct rockchip_grf_info rk3588_sysgrf __initconst = {
+ .values = rk3588_defaults,
+ .num_values = ARRAY_SIZE(rk3588_defaults),
+};
static const struct of_device_id rockchip_grf_dt_match[] __initconst = {
{
@@ -142,11 +188,23 @@ static const struct of_device_id rockchip_grf_dt_match[] __initconst = {
.compatible = "rockchip,rk3368-grf",
.data = (void *)&rk3368_grf,
}, {
+ .compatible = "rockchip,rk3368-pmugrf",
+ .data = (void *)&rk3368_pmugrf,
+ }, {
.compatible = "rockchip,rk3399-grf",
.data = (void *)&rk3399_grf,
}, {
.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,
},
{ /* sentinel */ },
};
diff --git a/drivers/soc/rockchip/io-domain.c b/drivers/soc/rockchip/io-domain.c
index 6619256c2d11..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
},
@@ -687,7 +727,7 @@ unreg_notify:
return ret;
}
-static int rockchip_iodomain_remove(struct platform_device *pdev)
+static void rockchip_iodomain_remove(struct platform_device *pdev)
{
struct rockchip_iodomain *iod = platform_get_drvdata(pdev);
int i;
@@ -699,15 +739,13 @@ static int rockchip_iodomain_remove(struct platform_device *pdev)
regulator_unregister_notifier(io_supply->reg,
&io_supply->nb);
}
-
- return 0;
}
static struct platform_driver rockchip_iodomain_driver = {
- .probe = rockchip_iodomain_probe,
- .remove = 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/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c
deleted file mode 100644
index 84bc022f9e5b..000000000000
--- a/drivers/soc/rockchip/pm_domains.c
+++ /dev/null
@@ -1,1305 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Rockchip Generic power domain support.
- *
- * Copyright (c) 2015 ROCKCHIP, Co. Ltd.
- */
-
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/err.h>
-#include <linux/mutex.h>
-#include <linux/pm_clock.h>
-#include <linux/pm_domain.h>
-#include <linux/of_address.h>
-#include <linux/of_clk.h>
-#include <linux/of_platform.h>
-#include <linux/clk.h>
-#include <linux/regmap.h>
-#include <linux/mfd/syscon.h>
-#include <soc/rockchip/pm_domains.h>
-#include <dt-bindings/power/px30-power.h>
-#include <dt-bindings/power/rockchip,rv1126-power.h>
-#include <dt-bindings/power/rk3036-power.h>
-#include <dt-bindings/power/rk3066-power.h>
-#include <dt-bindings/power/rk3128-power.h>
-#include <dt-bindings/power/rk3188-power.h>
-#include <dt-bindings/power/rk3228-power.h>
-#include <dt-bindings/power/rk3288-power.h>
-#include <dt-bindings/power/rk3328-power.h>
-#include <dt-bindings/power/rk3366-power.h>
-#include <dt-bindings/power/rk3368-power.h>
-#include <dt-bindings/power/rk3399-power.h>
-#include <dt-bindings/power/rk3568-power.h>
-#include <dt-bindings/power/rk3588-power.h>
-
-struct rockchip_domain_info {
- const char *name;
- int pwr_mask;
- int status_mask;
- int req_mask;
- int idle_mask;
- int ack_mask;
- bool active_wakeup;
- int pwr_w_mask;
- int req_w_mask;
- int repair_status_mask;
- u32 pwr_offset;
- u32 req_offset;
-};
-
-struct rockchip_pmu_info {
- u32 pwr_offset;
- u32 status_offset;
- u32 req_offset;
- u32 idle_offset;
- u32 ack_offset;
- u32 repair_status_offset;
-
- u32 core_pwrcnt_offset;
- u32 gpu_pwrcnt_offset;
-
- unsigned int core_power_transition_time;
- unsigned int gpu_power_transition_time;
-
- int num_domains;
- const struct rockchip_domain_info *domain_info;
-};
-
-#define MAX_QOS_REGS_NUM 5
-#define QOS_PRIORITY 0x08
-#define QOS_MODE 0x0c
-#define QOS_BANDWIDTH 0x10
-#define QOS_SATURATION 0x14
-#define QOS_EXTCONTROL 0x18
-
-struct rockchip_pm_domain {
- struct generic_pm_domain genpd;
- const struct rockchip_domain_info *info;
- struct rockchip_pmu *pmu;
- int num_qos;
- struct regmap **qos_regmap;
- u32 *qos_save_regs[MAX_QOS_REGS_NUM];
- int num_clks;
- struct clk_bulk_data *clks;
-};
-
-struct rockchip_pmu {
- struct device *dev;
- struct regmap *regmap;
- const struct rockchip_pmu_info *info;
- struct mutex mutex; /* mutex lock for pmu */
- struct genpd_onecell_data genpd_data;
- struct generic_pm_domain *domains[];
-};
-
-#define to_rockchip_pd(gpd) container_of(gpd, struct rockchip_pm_domain, genpd)
-
-#define DOMAIN(_name, pwr, status, req, idle, ack, wakeup) \
-{ \
- .name = _name, \
- .pwr_mask = (pwr), \
- .status_mask = (status), \
- .req_mask = (req), \
- .idle_mask = (idle), \
- .ack_mask = (ack), \
- .active_wakeup = (wakeup), \
-}
-
-#define DOMAIN_M(_name, pwr, status, req, idle, ack, wakeup) \
-{ \
- .name = _name, \
- .pwr_w_mask = (pwr) << 16, \
- .pwr_mask = (pwr), \
- .status_mask = (status), \
- .req_w_mask = (req) << 16, \
- .req_mask = (req), \
- .idle_mask = (idle), \
- .ack_mask = (ack), \
- .active_wakeup = wakeup, \
-}
-
-#define DOMAIN_M_O_R(_name, p_offset, pwr, status, r_status, r_offset, req, idle, ack, wakeup) \
-{ \
- .name = _name, \
- .pwr_offset = p_offset, \
- .pwr_w_mask = (pwr) << 16, \
- .pwr_mask = (pwr), \
- .status_mask = (status), \
- .repair_status_mask = (r_status), \
- .req_offset = r_offset, \
- .req_w_mask = (req) << 16, \
- .req_mask = (req), \
- .idle_mask = (idle), \
- .ack_mask = (ack), \
- .active_wakeup = wakeup, \
-}
-
-#define DOMAIN_RK3036(_name, req, ack, idle, wakeup) \
-{ \
- .name = _name, \
- .req_mask = (req), \
- .req_w_mask = (req) << 16, \
- .ack_mask = (ack), \
- .idle_mask = (idle), \
- .active_wakeup = wakeup, \
-}
-
-#define DOMAIN_PX30(name, pwr, status, req, wakeup) \
- DOMAIN_M(name, pwr, status, req, (req) << 16, req, wakeup)
-
-#define DOMAIN_RV1126(name, pwr, req, idle, wakeup) \
- DOMAIN_M(name, pwr, pwr, req, idle, idle, wakeup)
-
-#define DOMAIN_RK3288(name, pwr, status, req, wakeup) \
- DOMAIN(name, pwr, status, req, req, (req) << 16, wakeup)
-
-#define DOMAIN_RK3328(name, pwr, status, req, wakeup) \
- DOMAIN_M(name, pwr, pwr, req, (req) << 10, req, wakeup)
-
-#define DOMAIN_RK3368(name, pwr, status, req, wakeup) \
- DOMAIN(name, pwr, status, req, (req) << 16, req, wakeup)
-
-#define DOMAIN_RK3399(name, pwr, status, req, wakeup) \
- DOMAIN(name, pwr, status, req, req, req, wakeup)
-
-#define DOMAIN_RK3568(name, pwr, req, wakeup) \
- DOMAIN_M(name, pwr, pwr, req, req, req, wakeup)
-
-/*
- * Dynamic Memory Controller may need to coordinate with us -- see
- * rockchip_pmu_block().
- *
- * dmc_pmu_mutex protects registration-time races, so DMC driver doesn't try to
- * block() while we're initializing the PMU.
- */
-static DEFINE_MUTEX(dmc_pmu_mutex);
-static struct rockchip_pmu *dmc_pmu;
-
-/*
- * Block PMU transitions and make sure they don't interfere with ARM Trusted
- * Firmware operations. There are two conflicts, noted in the comments below.
- *
- * Caller must unblock PMU transitions via rockchip_pmu_unblock().
- */
-int rockchip_pmu_block(void)
-{
- struct rockchip_pmu *pmu;
- struct generic_pm_domain *genpd;
- struct rockchip_pm_domain *pd;
- int i, ret;
-
- mutex_lock(&dmc_pmu_mutex);
-
- /* No PMU (yet)? Then we just block rockchip_pmu_probe(). */
- if (!dmc_pmu)
- return 0;
- pmu = dmc_pmu;
-
- /*
- * mutex blocks all idle transitions: we can't touch the
- * PMU_BUS_IDLE_REQ (our ".idle_offset") register while ARM Trusted
- * Firmware might be using it.
- */
- mutex_lock(&pmu->mutex);
-
- /*
- * Power domain clocks: Per Rockchip, we *must* keep certain clocks
- * enabled for the duration of power-domain transitions. Most
- * transitions are handled by this driver, but some cases (in
- * particular, DRAM DVFS / memory-controller idle) must be handled by
- * firmware. Firmware can handle most clock management via a special
- * "ungate" register (PMU_CRU_GATEDIS_CON0), but unfortunately, this
- * doesn't handle PLLs. We can assist this transition by doing the
- * clock management on behalf of firmware.
- */
- for (i = 0; i < pmu->genpd_data.num_domains; i++) {
- genpd = pmu->genpd_data.domains[i];
- if (genpd) {
- pd = to_rockchip_pd(genpd);
- ret = clk_bulk_enable(pd->num_clks, pd->clks);
- if (ret < 0) {
- dev_err(pmu->dev,
- "failed to enable clks for domain '%s': %d\n",
- genpd->name, ret);
- goto err;
- }
- }
- }
-
- return 0;
-
-err:
- for (i = i - 1; i >= 0; i--) {
- genpd = pmu->genpd_data.domains[i];
- if (genpd) {
- pd = to_rockchip_pd(genpd);
- clk_bulk_disable(pd->num_clks, pd->clks);
- }
- }
- mutex_unlock(&pmu->mutex);
- mutex_unlock(&dmc_pmu_mutex);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(rockchip_pmu_block);
-
-/* Unblock PMU transitions. */
-void rockchip_pmu_unblock(void)
-{
- struct rockchip_pmu *pmu;
- struct generic_pm_domain *genpd;
- struct rockchip_pm_domain *pd;
- int i;
-
- if (dmc_pmu) {
- pmu = dmc_pmu;
- for (i = 0; i < pmu->genpd_data.num_domains; i++) {
- genpd = pmu->genpd_data.domains[i];
- if (genpd) {
- pd = to_rockchip_pd(genpd);
- clk_bulk_disable(pd->num_clks, pd->clks);
- }
- }
-
- mutex_unlock(&pmu->mutex);
- }
-
- mutex_unlock(&dmc_pmu_mutex);
-}
-EXPORT_SYMBOL_GPL(rockchip_pmu_unblock);
-
-#define DOMAIN_RK3588(name, p_offset, pwr, status, r_status, r_offset, req, idle, wakeup) \
- DOMAIN_M_O_R(name, p_offset, pwr, status, r_status, r_offset, req, idle, idle, wakeup)
-
-static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd)
-{
- struct rockchip_pmu *pmu = pd->pmu;
- const struct rockchip_domain_info *pd_info = pd->info;
- unsigned int val;
-
- regmap_read(pmu->regmap, pmu->info->idle_offset, &val);
- return (val & pd_info->idle_mask) == pd_info->idle_mask;
-}
-
-static unsigned int rockchip_pmu_read_ack(struct rockchip_pmu *pmu)
-{
- unsigned int val;
-
- regmap_read(pmu->regmap, pmu->info->ack_offset, &val);
- return val;
-}
-
-static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd,
- bool idle)
-{
- const struct rockchip_domain_info *pd_info = pd->info;
- struct generic_pm_domain *genpd = &pd->genpd;
- struct rockchip_pmu *pmu = pd->pmu;
- u32 pd_req_offset = pd_info->req_offset;
- unsigned int target_ack;
- unsigned int val;
- bool is_idle;
- int ret;
-
- if (pd_info->req_mask == 0)
- return 0;
- else if (pd_info->req_w_mask)
- regmap_write(pmu->regmap, pmu->info->req_offset + pd_req_offset,
- idle ? (pd_info->req_mask | pd_info->req_w_mask) :
- pd_info->req_w_mask);
- else
- regmap_update_bits(pmu->regmap, pmu->info->req_offset + pd_req_offset,
- pd_info->req_mask, idle ? -1U : 0);
-
- wmb();
-
- /* Wait util idle_ack = 1 */
- target_ack = idle ? pd_info->ack_mask : 0;
- ret = readx_poll_timeout_atomic(rockchip_pmu_read_ack, pmu, val,
- (val & pd_info->ack_mask) == target_ack,
- 0, 10000);
- if (ret) {
- dev_err(pmu->dev,
- "failed to get ack on domain '%s', val=0x%x\n",
- genpd->name, val);
- return ret;
- }
-
- ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_idle, pd,
- is_idle, is_idle == idle, 0, 10000);
- if (ret) {
- dev_err(pmu->dev,
- "failed to set idle on domain '%s', val=%d\n",
- genpd->name, is_idle);
- return ret;
- }
-
- return 0;
-}
-
-static int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd)
-{
- int i;
-
- for (i = 0; i < pd->num_qos; i++) {
- regmap_read(pd->qos_regmap[i],
- QOS_PRIORITY,
- &pd->qos_save_regs[0][i]);
- regmap_read(pd->qos_regmap[i],
- QOS_MODE,
- &pd->qos_save_regs[1][i]);
- regmap_read(pd->qos_regmap[i],
- QOS_BANDWIDTH,
- &pd->qos_save_regs[2][i]);
- regmap_read(pd->qos_regmap[i],
- QOS_SATURATION,
- &pd->qos_save_regs[3][i]);
- regmap_read(pd->qos_regmap[i],
- QOS_EXTCONTROL,
- &pd->qos_save_regs[4][i]);
- }
- return 0;
-}
-
-static int rockchip_pmu_restore_qos(struct rockchip_pm_domain *pd)
-{
- int i;
-
- for (i = 0; i < pd->num_qos; i++) {
- regmap_write(pd->qos_regmap[i],
- QOS_PRIORITY,
- pd->qos_save_regs[0][i]);
- regmap_write(pd->qos_regmap[i],
- QOS_MODE,
- pd->qos_save_regs[1][i]);
- regmap_write(pd->qos_regmap[i],
- QOS_BANDWIDTH,
- pd->qos_save_regs[2][i]);
- regmap_write(pd->qos_regmap[i],
- QOS_SATURATION,
- pd->qos_save_regs[3][i]);
- regmap_write(pd->qos_regmap[i],
- QOS_EXTCONTROL,
- pd->qos_save_regs[4][i]);
- }
-
- return 0;
-}
-
-static bool rockchip_pmu_domain_is_on(struct rockchip_pm_domain *pd)
-{
- struct rockchip_pmu *pmu = pd->pmu;
- unsigned int val;
-
- if (pd->info->repair_status_mask) {
- regmap_read(pmu->regmap, pmu->info->repair_status_offset, &val);
- /* 1'b1: power on, 1'b0: power off */
- return val & pd->info->repair_status_mask;
- }
-
- /* check idle status for idle-only domains */
- if (pd->info->status_mask == 0)
- return !rockchip_pmu_domain_is_idle(pd);
-
- regmap_read(pmu->regmap, pmu->info->status_offset, &val);
-
- /* 1'b0: power on, 1'b1: power off */
- return !(val & pd->info->status_mask);
-}
-
-static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
- bool on)
-{
- struct rockchip_pmu *pmu = pd->pmu;
- struct generic_pm_domain *genpd = &pd->genpd;
- u32 pd_pwr_offset = pd->info->pwr_offset;
- bool is_on;
-
- if (pd->info->pwr_mask == 0)
- return;
- else if (pd->info->pwr_w_mask)
- regmap_write(pmu->regmap, pmu->info->pwr_offset + pd_pwr_offset,
- on ? pd->info->pwr_w_mask :
- (pd->info->pwr_mask | pd->info->pwr_w_mask));
- else
- regmap_update_bits(pmu->regmap, pmu->info->pwr_offset + pd_pwr_offset,
- pd->info->pwr_mask, on ? 0 : -1U);
-
- wmb();
-
- if (readx_poll_timeout_atomic(rockchip_pmu_domain_is_on, pd, is_on,
- is_on == on, 0, 10000)) {
- dev_err(pmu->dev,
- "failed to set domain '%s', val=%d\n",
- genpd->name, is_on);
- return;
- }
-}
-
-static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
-{
- struct rockchip_pmu *pmu = pd->pmu;
- int ret;
-
- mutex_lock(&pmu->mutex);
-
- if (rockchip_pmu_domain_is_on(pd) != power_on) {
- ret = clk_bulk_enable(pd->num_clks, pd->clks);
- if (ret < 0) {
- dev_err(pmu->dev, "failed to enable clocks\n");
- mutex_unlock(&pmu->mutex);
- return ret;
- }
-
- if (!power_on) {
- rockchip_pmu_save_qos(pd);
-
- /* if powering down, idle request to NIU first */
- rockchip_pmu_set_idle_request(pd, true);
- }
-
- rockchip_do_pmu_set_power_domain(pd, power_on);
-
- if (power_on) {
- /* if powering up, leave idle mode */
- rockchip_pmu_set_idle_request(pd, false);
-
- rockchip_pmu_restore_qos(pd);
- }
-
- clk_bulk_disable(pd->num_clks, pd->clks);
- }
-
- mutex_unlock(&pmu->mutex);
- return 0;
-}
-
-static int rockchip_pd_power_on(struct generic_pm_domain *domain)
-{
- struct rockchip_pm_domain *pd = to_rockchip_pd(domain);
-
- return rockchip_pd_power(pd, true);
-}
-
-static int rockchip_pd_power_off(struct generic_pm_domain *domain)
-{
- struct rockchip_pm_domain *pd = to_rockchip_pd(domain);
-
- return rockchip_pd_power(pd, false);
-}
-
-static int rockchip_pd_attach_dev(struct generic_pm_domain *genpd,
- struct device *dev)
-{
- struct clk *clk;
- int i;
- int error;
-
- dev_dbg(dev, "attaching to power domain '%s'\n", genpd->name);
-
- error = pm_clk_create(dev);
- if (error) {
- dev_err(dev, "pm_clk_create failed %d\n", error);
- return error;
- }
-
- i = 0;
- while ((clk = of_clk_get(dev->of_node, i++)) && !IS_ERR(clk)) {
- dev_dbg(dev, "adding clock '%pC' to list of PM clocks\n", clk);
- error = pm_clk_add_clk(dev, clk);
- if (error) {
- dev_err(dev, "pm_clk_add_clk failed %d\n", error);
- clk_put(clk);
- pm_clk_destroy(dev);
- return error;
- }
- }
-
- return 0;
-}
-
-static void rockchip_pd_detach_dev(struct generic_pm_domain *genpd,
- struct device *dev)
-{
- dev_dbg(dev, "detaching from power domain '%s'\n", genpd->name);
-
- pm_clk_destroy(dev);
-}
-
-static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
- struct device_node *node)
-{
- const struct rockchip_domain_info *pd_info;
- struct rockchip_pm_domain *pd;
- struct device_node *qos_node;
- int i, j;
- u32 id;
- int error;
-
- error = of_property_read_u32(node, "reg", &id);
- if (error) {
- dev_err(pmu->dev,
- "%pOFn: failed to retrieve domain id (reg): %d\n",
- node, error);
- return -EINVAL;
- }
-
- if (id >= pmu->info->num_domains) {
- dev_err(pmu->dev, "%pOFn: invalid domain id %d\n",
- node, id);
- return -EINVAL;
- }
- /* RK3588 has domains with two parents (RKVDEC0/RKVDEC1) */
- if (pmu->genpd_data.domains[id])
- return 0;
-
- pd_info = &pmu->info->domain_info[id];
- if (!pd_info) {
- dev_err(pmu->dev, "%pOFn: undefined domain id %d\n",
- node, id);
- return -EINVAL;
- }
-
- pd = devm_kzalloc(pmu->dev, sizeof(*pd), GFP_KERNEL);
- if (!pd)
- return -ENOMEM;
-
- pd->info = pd_info;
- pd->pmu = pmu;
-
- pd->num_clks = of_clk_get_parent_count(node);
- if (pd->num_clks > 0) {
- pd->clks = devm_kcalloc(pmu->dev, pd->num_clks,
- sizeof(*pd->clks), GFP_KERNEL);
- if (!pd->clks)
- return -ENOMEM;
- } else {
- dev_dbg(pmu->dev, "%pOFn: doesn't have clocks: %d\n",
- node, pd->num_clks);
- pd->num_clks = 0;
- }
-
- for (i = 0; i < pd->num_clks; i++) {
- pd->clks[i].clk = of_clk_get(node, i);
- if (IS_ERR(pd->clks[i].clk)) {
- error = PTR_ERR(pd->clks[i].clk);
- dev_err(pmu->dev,
- "%pOFn: failed to get clk at index %d: %d\n",
- node, i, error);
- return error;
- }
- }
-
- error = clk_bulk_prepare(pd->num_clks, pd->clks);
- if (error)
- goto err_put_clocks;
-
- pd->num_qos = of_count_phandle_with_args(node, "pm_qos",
- NULL);
-
- if (pd->num_qos > 0) {
- pd->qos_regmap = devm_kcalloc(pmu->dev, pd->num_qos,
- sizeof(*pd->qos_regmap),
- GFP_KERNEL);
- if (!pd->qos_regmap) {
- error = -ENOMEM;
- goto err_unprepare_clocks;
- }
-
- for (j = 0; j < MAX_QOS_REGS_NUM; j++) {
- pd->qos_save_regs[j] = devm_kcalloc(pmu->dev,
- pd->num_qos,
- sizeof(u32),
- GFP_KERNEL);
- if (!pd->qos_save_regs[j]) {
- error = -ENOMEM;
- goto err_unprepare_clocks;
- }
- }
-
- for (j = 0; j < pd->num_qos; j++) {
- qos_node = of_parse_phandle(node, "pm_qos", j);
- if (!qos_node) {
- error = -ENODEV;
- goto err_unprepare_clocks;
- }
- pd->qos_regmap[j] = syscon_node_to_regmap(qos_node);
- if (IS_ERR(pd->qos_regmap[j])) {
- error = -ENODEV;
- of_node_put(qos_node);
- goto err_unprepare_clocks;
- }
- of_node_put(qos_node);
- }
- }
-
- if (pd->info->name)
- pd->genpd.name = pd->info->name;
- else
- pd->genpd.name = kbasename(node->full_name);
- pd->genpd.power_off = rockchip_pd_power_off;
- pd->genpd.power_on = rockchip_pd_power_on;
- pd->genpd.attach_dev = rockchip_pd_attach_dev;
- pd->genpd.detach_dev = rockchip_pd_detach_dev;
- pd->genpd.flags = GENPD_FLAG_PM_CLK;
- if (pd_info->active_wakeup)
- pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
- pm_genpd_init(&pd->genpd, NULL, !rockchip_pmu_domain_is_on(pd));
-
- pmu->genpd_data.domains[id] = &pd->genpd;
- return 0;
-
-err_unprepare_clocks:
- clk_bulk_unprepare(pd->num_clks, pd->clks);
-err_put_clocks:
- clk_bulk_put(pd->num_clks, pd->clks);
- return error;
-}
-
-static void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd)
-{
- int ret;
-
- /*
- * We're in the error cleanup already, so we only complain,
- * but won't emit another error on top of the original one.
- */
- ret = pm_genpd_remove(&pd->genpd);
- if (ret < 0)
- dev_err(pd->pmu->dev, "failed to remove domain '%s' : %d - state may be inconsistent\n",
- pd->genpd.name, ret);
-
- clk_bulk_unprepare(pd->num_clks, pd->clks);
- clk_bulk_put(pd->num_clks, pd->clks);
-
- /* protect the zeroing of pm->num_clks */
- mutex_lock(&pd->pmu->mutex);
- pd->num_clks = 0;
- mutex_unlock(&pd->pmu->mutex);
-
- /* devm will free our memory */
-}
-
-static void rockchip_pm_domain_cleanup(struct rockchip_pmu *pmu)
-{
- struct generic_pm_domain *genpd;
- struct rockchip_pm_domain *pd;
- int i;
-
- for (i = 0; i < pmu->genpd_data.num_domains; i++) {
- genpd = pmu->genpd_data.domains[i];
- if (genpd) {
- pd = to_rockchip_pd(genpd);
- rockchip_pm_remove_one_domain(pd);
- }
- }
-
- /* devm will free our memory */
-}
-
-static void rockchip_configure_pd_cnt(struct rockchip_pmu *pmu,
- u32 domain_reg_offset,
- unsigned int count)
-{
- /* First configure domain power down transition count ... */
- regmap_write(pmu->regmap, domain_reg_offset, count);
- /* ... and then power up count. */
- regmap_write(pmu->regmap, domain_reg_offset + 4, count);
-}
-
-static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu,
- struct device_node *parent)
-{
- struct device_node *np;
- struct generic_pm_domain *child_domain, *parent_domain;
- int error;
-
- for_each_child_of_node(parent, np) {
- u32 idx;
-
- error = of_property_read_u32(parent, "reg", &idx);
- if (error) {
- dev_err(pmu->dev,
- "%pOFn: failed to retrieve domain id (reg): %d\n",
- parent, error);
- goto err_out;
- }
- parent_domain = pmu->genpd_data.domains[idx];
-
- error = rockchip_pm_add_one_domain(pmu, np);
- if (error) {
- dev_err(pmu->dev, "failed to handle node %pOFn: %d\n",
- np, error);
- goto err_out;
- }
-
- error = of_property_read_u32(np, "reg", &idx);
- if (error) {
- dev_err(pmu->dev,
- "%pOFn: failed to retrieve domain id (reg): %d\n",
- np, error);
- goto err_out;
- }
- child_domain = pmu->genpd_data.domains[idx];
-
- error = pm_genpd_add_subdomain(parent_domain, child_domain);
- if (error) {
- dev_err(pmu->dev, "%s failed to add subdomain %s: %d\n",
- parent_domain->name, child_domain->name, error);
- goto err_out;
- } else {
- dev_dbg(pmu->dev, "%s add subdomain: %s\n",
- parent_domain->name, child_domain->name);
- }
-
- rockchip_pm_add_subdomain(pmu, np);
- }
-
- return 0;
-
-err_out:
- of_node_put(np);
- return error;
-}
-
-static int rockchip_pm_domain_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
- struct device_node *node;
- struct device *parent;
- struct rockchip_pmu *pmu;
- const struct of_device_id *match;
- const struct rockchip_pmu_info *pmu_info;
- int error;
-
- if (!np) {
- dev_err(dev, "device tree node not found\n");
- return -ENODEV;
- }
-
- match = of_match_device(dev->driver->of_match_table, dev);
- if (!match || !match->data) {
- dev_err(dev, "missing pmu data\n");
- return -EINVAL;
- }
-
- pmu_info = match->data;
-
- pmu = devm_kzalloc(dev,
- struct_size(pmu, domains, pmu_info->num_domains),
- GFP_KERNEL);
- if (!pmu)
- return -ENOMEM;
-
- pmu->dev = &pdev->dev;
- mutex_init(&pmu->mutex);
-
- pmu->info = pmu_info;
-
- pmu->genpd_data.domains = pmu->domains;
- pmu->genpd_data.num_domains = pmu_info->num_domains;
-
- parent = dev->parent;
- if (!parent) {
- dev_err(dev, "no parent for syscon devices\n");
- return -ENODEV;
- }
-
- pmu->regmap = syscon_node_to_regmap(parent->of_node);
- if (IS_ERR(pmu->regmap)) {
- dev_err(dev, "no regmap available\n");
- return PTR_ERR(pmu->regmap);
- }
-
- /*
- * Configure power up and down transition delays for CORE
- * and GPU domains.
- */
- if (pmu_info->core_power_transition_time)
- rockchip_configure_pd_cnt(pmu, pmu_info->core_pwrcnt_offset,
- pmu_info->core_power_transition_time);
- if (pmu_info->gpu_pwrcnt_offset)
- rockchip_configure_pd_cnt(pmu, pmu_info->gpu_pwrcnt_offset,
- pmu_info->gpu_power_transition_time);
-
- error = -ENODEV;
-
- /*
- * Prevent any rockchip_pmu_block() from racing with the remainder of
- * setup (clocks, register initialization).
- */
- mutex_lock(&dmc_pmu_mutex);
-
- for_each_available_child_of_node(np, node) {
- error = rockchip_pm_add_one_domain(pmu, node);
- if (error) {
- dev_err(dev, "failed to handle node %pOFn: %d\n",
- node, error);
- of_node_put(node);
- goto err_out;
- }
-
- error = rockchip_pm_add_subdomain(pmu, node);
- if (error < 0) {
- dev_err(dev, "failed to handle subdomain node %pOFn: %d\n",
- node, error);
- of_node_put(node);
- goto err_out;
- }
- }
-
- if (error) {
- dev_dbg(dev, "no power domains defined\n");
- goto err_out;
- }
-
- error = of_genpd_add_provider_onecell(np, &pmu->genpd_data);
- if (error) {
- dev_err(dev, "failed to add provider: %d\n", error);
- goto err_out;
- }
-
- /* We only expect one PMU. */
- if (!WARN_ON_ONCE(dmc_pmu))
- dmc_pmu = pmu;
-
- mutex_unlock(&dmc_pmu_mutex);
-
- return 0;
-
-err_out:
- rockchip_pm_domain_cleanup(pmu);
- mutex_unlock(&dmc_pmu_mutex);
- return error;
-}
-
-static const struct rockchip_domain_info px30_pm_domains[] = {
- [PX30_PD_USB] = DOMAIN_PX30("usb", BIT(5), BIT(5), BIT(10), false),
- [PX30_PD_SDCARD] = DOMAIN_PX30("sdcard", BIT(8), BIT(8), BIT(9), false),
- [PX30_PD_GMAC] = DOMAIN_PX30("gmac", BIT(10), BIT(10), BIT(6), false),
- [PX30_PD_MMC_NAND] = DOMAIN_PX30("mmc_nand", BIT(11), BIT(11), BIT(5), false),
- [PX30_PD_VPU] = DOMAIN_PX30("vpu", BIT(12), BIT(12), BIT(14), false),
- [PX30_PD_VO] = DOMAIN_PX30("vo", BIT(13), BIT(13), BIT(7), false),
- [PX30_PD_VI] = DOMAIN_PX30("vi", BIT(14), BIT(14), BIT(8), false),
- [PX30_PD_GPU] = DOMAIN_PX30("gpu", BIT(15), BIT(15), BIT(2), false),
-};
-
-static const struct rockchip_domain_info rv1126_pm_domains[] = {
- [RV1126_PD_VEPU] = DOMAIN_RV1126("vepu", BIT(2), BIT(9), BIT(9), false),
- [RV1126_PD_VI] = DOMAIN_RV1126("vi", BIT(4), BIT(6), BIT(6), false),
- [RV1126_PD_ISPP] = DOMAIN_RV1126("ispp", BIT(1), BIT(8), BIT(8), false),
- [RV1126_PD_VDPU] = DOMAIN_RV1126("vdpu", BIT(3), BIT(10), BIT(10), false),
- [RV1126_PD_NVM] = DOMAIN_RV1126("nvm", BIT(7), BIT(11), BIT(11), false),
- [RV1126_PD_SDIO] = DOMAIN_RV1126("sdio", BIT(8), BIT(13), BIT(13), false),
- [RV1126_PD_USB] = DOMAIN_RV1126("usb", BIT(9), BIT(15), BIT(15), false),
-};
-
-static const struct rockchip_domain_info rk3036_pm_domains[] = {
- [RK3036_PD_MSCH] = DOMAIN_RK3036("msch", BIT(14), BIT(23), BIT(30), true),
- [RK3036_PD_CORE] = DOMAIN_RK3036("core", BIT(13), BIT(17), BIT(24), false),
- [RK3036_PD_PERI] = DOMAIN_RK3036("peri", BIT(12), BIT(18), BIT(25), false),
- [RK3036_PD_VIO] = DOMAIN_RK3036("vio", BIT(11), BIT(19), BIT(26), false),
- [RK3036_PD_VPU] = DOMAIN_RK3036("vpu", BIT(10), BIT(20), BIT(27), false),
- [RK3036_PD_GPU] = DOMAIN_RK3036("gpu", BIT(9), BIT(21), BIT(28), false),
- [RK3036_PD_SYS] = DOMAIN_RK3036("sys", BIT(8), BIT(22), BIT(29), false),
-};
-
-static const struct rockchip_domain_info rk3066_pm_domains[] = {
- [RK3066_PD_GPU] = DOMAIN("gpu", BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false),
- [RK3066_PD_VIDEO] = DOMAIN("video", BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false),
- [RK3066_PD_VIO] = DOMAIN("vio", BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false),
- [RK3066_PD_PERI] = DOMAIN("peri", BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false),
- [RK3066_PD_CPU] = DOMAIN("cpu", 0, BIT(5), BIT(1), BIT(26), BIT(31), false),
-};
-
-static const struct rockchip_domain_info rk3128_pm_domains[] = {
- [RK3128_PD_CORE] = DOMAIN_RK3288("core", BIT(0), BIT(0), BIT(4), false),
- [RK3128_PD_MSCH] = DOMAIN_RK3288("msch", 0, 0, BIT(6), true),
- [RK3128_PD_VIO] = DOMAIN_RK3288("vio", BIT(3), BIT(3), BIT(2), false),
- [RK3128_PD_VIDEO] = DOMAIN_RK3288("video", BIT(2), BIT(2), BIT(1), false),
- [RK3128_PD_GPU] = DOMAIN_RK3288("gpu", BIT(1), BIT(1), BIT(3), false),
-};
-
-static const struct rockchip_domain_info rk3188_pm_domains[] = {
- [RK3188_PD_GPU] = DOMAIN("gpu", BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false),
- [RK3188_PD_VIDEO] = DOMAIN("video", BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false),
- [RK3188_PD_VIO] = DOMAIN("vio", BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false),
- [RK3188_PD_PERI] = DOMAIN("peri", BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false),
- [RK3188_PD_CPU] = DOMAIN("cpu", BIT(5), BIT(5), BIT(1), BIT(26), BIT(31), false),
-};
-
-static const struct rockchip_domain_info rk3228_pm_domains[] = {
- [RK3228_PD_CORE] = DOMAIN_RK3036("core", BIT(0), BIT(0), BIT(16), true),
- [RK3228_PD_MSCH] = DOMAIN_RK3036("msch", BIT(1), BIT(1), BIT(17), true),
- [RK3228_PD_BUS] = DOMAIN_RK3036("bus", BIT(2), BIT(2), BIT(18), true),
- [RK3228_PD_SYS] = DOMAIN_RK3036("sys", BIT(3), BIT(3), BIT(19), true),
- [RK3228_PD_VIO] = DOMAIN_RK3036("vio", BIT(4), BIT(4), BIT(20), false),
- [RK3228_PD_VOP] = DOMAIN_RK3036("vop", BIT(5), BIT(5), BIT(21), false),
- [RK3228_PD_VPU] = DOMAIN_RK3036("vpu", BIT(6), BIT(6), BIT(22), false),
- [RK3228_PD_RKVDEC] = DOMAIN_RK3036("vdec", BIT(7), BIT(7), BIT(23), false),
- [RK3228_PD_GPU] = DOMAIN_RK3036("gpu", BIT(8), BIT(8), BIT(24), false),
- [RK3228_PD_PERI] = DOMAIN_RK3036("peri", BIT(9), BIT(9), BIT(25), true),
- [RK3228_PD_GMAC] = DOMAIN_RK3036("gmac", BIT(10), BIT(10), BIT(26), false),
-};
-
-static const struct rockchip_domain_info rk3288_pm_domains[] = {
- [RK3288_PD_VIO] = DOMAIN_RK3288("vio", BIT(7), BIT(7), BIT(4), false),
- [RK3288_PD_HEVC] = DOMAIN_RK3288("hevc", BIT(14), BIT(10), BIT(9), false),
- [RK3288_PD_VIDEO] = DOMAIN_RK3288("video", BIT(8), BIT(8), BIT(3), false),
- [RK3288_PD_GPU] = DOMAIN_RK3288("gpu", BIT(9), BIT(9), BIT(2), false),
-};
-
-static const struct rockchip_domain_info rk3328_pm_domains[] = {
- [RK3328_PD_CORE] = DOMAIN_RK3328("core", 0, BIT(0), BIT(0), false),
- [RK3328_PD_GPU] = DOMAIN_RK3328("gpu", 0, BIT(1), BIT(1), false),
- [RK3328_PD_BUS] = DOMAIN_RK3328("bus", 0, BIT(2), BIT(2), true),
- [RK3328_PD_MSCH] = DOMAIN_RK3328("msch", 0, BIT(3), BIT(3), true),
- [RK3328_PD_PERI] = DOMAIN_RK3328("peri", 0, BIT(4), BIT(4), true),
- [RK3328_PD_VIDEO] = DOMAIN_RK3328("video", 0, BIT(5), BIT(5), false),
- [RK3328_PD_HEVC] = DOMAIN_RK3328("hevc", 0, BIT(6), BIT(6), false),
- [RK3328_PD_VIO] = DOMAIN_RK3328("vio", 0, BIT(8), BIT(8), false),
- [RK3328_PD_VPU] = DOMAIN_RK3328("vpu", 0, BIT(9), BIT(9), false),
-};
-
-static const struct rockchip_domain_info rk3366_pm_domains[] = {
- [RK3366_PD_PERI] = DOMAIN_RK3368("peri", BIT(10), BIT(10), BIT(6), true),
- [RK3366_PD_VIO] = DOMAIN_RK3368("vio", BIT(14), BIT(14), BIT(8), false),
- [RK3366_PD_VIDEO] = DOMAIN_RK3368("video", BIT(13), BIT(13), BIT(7), false),
- [RK3366_PD_RKVDEC] = DOMAIN_RK3368("vdec", BIT(11), BIT(11), BIT(7), false),
- [RK3366_PD_WIFIBT] = DOMAIN_RK3368("wifibt", BIT(8), BIT(8), BIT(9), false),
- [RK3366_PD_VPU] = DOMAIN_RK3368("vpu", BIT(12), BIT(12), BIT(7), false),
- [RK3366_PD_GPU] = DOMAIN_RK3368("gpu", BIT(15), BIT(15), BIT(2), false),
-};
-
-static const struct rockchip_domain_info rk3368_pm_domains[] = {
- [RK3368_PD_PERI] = DOMAIN_RK3368("peri", BIT(13), BIT(12), BIT(6), true),
- [RK3368_PD_VIO] = DOMAIN_RK3368("vio", BIT(15), BIT(14), BIT(8), false),
- [RK3368_PD_VIDEO] = DOMAIN_RK3368("video", BIT(14), BIT(13), BIT(7), false),
- [RK3368_PD_GPU_0] = DOMAIN_RK3368("gpu_0", BIT(16), BIT(15), BIT(2), false),
- [RK3368_PD_GPU_1] = DOMAIN_RK3368("gpu_1", BIT(17), BIT(16), BIT(2), false),
-};
-
-static const struct rockchip_domain_info rk3399_pm_domains[] = {
- [RK3399_PD_TCPD0] = DOMAIN_RK3399("tcpd0", BIT(8), BIT(8), 0, false),
- [RK3399_PD_TCPD1] = DOMAIN_RK3399("tcpd1", BIT(9), BIT(9), 0, false),
- [RK3399_PD_CCI] = DOMAIN_RK3399("cci", BIT(10), BIT(10), 0, true),
- [RK3399_PD_CCI0] = DOMAIN_RK3399("cci0", 0, 0, BIT(15), true),
- [RK3399_PD_CCI1] = DOMAIN_RK3399("cci1", 0, 0, BIT(16), true),
- [RK3399_PD_PERILP] = DOMAIN_RK3399("perilp", BIT(11), BIT(11), BIT(1), true),
- [RK3399_PD_PERIHP] = DOMAIN_RK3399("perihp", BIT(12), BIT(12), BIT(2), true),
- [RK3399_PD_CENTER] = DOMAIN_RK3399("center", BIT(13), BIT(13), BIT(14), true),
- [RK3399_PD_VIO] = DOMAIN_RK3399("vio", BIT(14), BIT(14), BIT(17), false),
- [RK3399_PD_GPU] = DOMAIN_RK3399("gpu", BIT(15), BIT(15), BIT(0), false),
- [RK3399_PD_VCODEC] = DOMAIN_RK3399("vcodec", BIT(16), BIT(16), BIT(3), false),
- [RK3399_PD_VDU] = DOMAIN_RK3399("vdu", BIT(17), BIT(17), BIT(4), false),
- [RK3399_PD_RGA] = DOMAIN_RK3399("rga", BIT(18), BIT(18), BIT(5), false),
- [RK3399_PD_IEP] = DOMAIN_RK3399("iep", BIT(19), BIT(19), BIT(6), false),
- [RK3399_PD_VO] = DOMAIN_RK3399("vo", BIT(20), BIT(20), 0, false),
- [RK3399_PD_VOPB] = DOMAIN_RK3399("vopb", 0, 0, BIT(7), false),
- [RK3399_PD_VOPL] = DOMAIN_RK3399("vopl", 0, 0, BIT(8), false),
- [RK3399_PD_ISP0] = DOMAIN_RK3399("isp0", BIT(22), BIT(22), BIT(9), false),
- [RK3399_PD_ISP1] = DOMAIN_RK3399("isp1", BIT(23), BIT(23), BIT(10), false),
- [RK3399_PD_HDCP] = DOMAIN_RK3399("hdcp", BIT(24), BIT(24), BIT(11), false),
- [RK3399_PD_GMAC] = DOMAIN_RK3399("gmac", BIT(25), BIT(25), BIT(23), true),
- [RK3399_PD_EMMC] = DOMAIN_RK3399("emmc", BIT(26), BIT(26), BIT(24), true),
- [RK3399_PD_USB3] = DOMAIN_RK3399("usb3", BIT(27), BIT(27), BIT(12), true),
- [RK3399_PD_EDP] = DOMAIN_RK3399("edp", BIT(28), BIT(28), BIT(22), false),
- [RK3399_PD_GIC] = DOMAIN_RK3399("gic", BIT(29), BIT(29), BIT(27), true),
- [RK3399_PD_SD] = DOMAIN_RK3399("sd", BIT(30), BIT(30), BIT(28), true),
- [RK3399_PD_SDIOAUDIO] = DOMAIN_RK3399("sdioaudio", BIT(31), BIT(31), BIT(29), true),
-};
-
-static const struct rockchip_domain_info rk3568_pm_domains[] = {
- [RK3568_PD_NPU] = DOMAIN_RK3568("npu", BIT(1), BIT(2), false),
- [RK3568_PD_GPU] = DOMAIN_RK3568("gpu", BIT(0), BIT(1), false),
- [RK3568_PD_VI] = DOMAIN_RK3568("vi", BIT(6), BIT(3), false),
- [RK3568_PD_VO] = DOMAIN_RK3568("vo", BIT(7), BIT(4), false),
- [RK3568_PD_RGA] = DOMAIN_RK3568("rga", BIT(5), BIT(5), false),
- [RK3568_PD_VPU] = DOMAIN_RK3568("vpu", BIT(2), BIT(6), false),
- [RK3568_PD_RKVDEC] = DOMAIN_RK3568("vdec", BIT(4), BIT(8), false),
- [RK3568_PD_RKVENC] = DOMAIN_RK3568("venc", BIT(3), BIT(7), false),
- [RK3568_PD_PIPE] = DOMAIN_RK3568("pipe", BIT(8), BIT(11), false),
-};
-
-static const struct rockchip_domain_info rk3588_pm_domains[] = {
- [RK3588_PD_GPU] = DOMAIN_RK3588("gpu", 0x0, BIT(0), 0, BIT(1), 0x0, BIT(0), BIT(0), false),
- [RK3588_PD_NPU] = DOMAIN_RK3588("npu", 0x0, BIT(1), BIT(1), 0, 0x0, 0, 0, false),
- [RK3588_PD_VCODEC] = DOMAIN_RK3588("vcodec", 0x0, BIT(2), BIT(2), 0, 0x0, 0, 0, false),
- [RK3588_PD_NPUTOP] = DOMAIN_RK3588("nputop", 0x0, BIT(3), 0, BIT(2), 0x0, BIT(1), BIT(1), false),
- [RK3588_PD_NPU1] = DOMAIN_RK3588("npu1", 0x0, BIT(4), 0, BIT(3), 0x0, BIT(2), BIT(2), false),
- [RK3588_PD_NPU2] = DOMAIN_RK3588("npu2", 0x0, BIT(5), 0, BIT(4), 0x0, BIT(3), BIT(3), false),
- [RK3588_PD_VENC0] = DOMAIN_RK3588("venc0", 0x0, BIT(6), 0, BIT(5), 0x0, BIT(4), BIT(4), false),
- [RK3588_PD_VENC1] = DOMAIN_RK3588("venc1", 0x0, BIT(7), 0, BIT(6), 0x0, BIT(5), BIT(5), false),
- [RK3588_PD_RKVDEC0] = DOMAIN_RK3588("rkvdec0", 0x0, BIT(8), 0, BIT(7), 0x0, BIT(6), BIT(6), false),
- [RK3588_PD_RKVDEC1] = DOMAIN_RK3588("rkvdec1", 0x0, BIT(9), 0, BIT(8), 0x0, BIT(7), BIT(7), false),
- [RK3588_PD_VDPU] = DOMAIN_RK3588("vdpu", 0x0, BIT(10), 0, BIT(9), 0x0, BIT(8), BIT(8), false),
- [RK3588_PD_RGA30] = DOMAIN_RK3588("rga30", 0x0, BIT(11), 0, BIT(10), 0x0, 0, 0, false),
- [RK3588_PD_AV1] = DOMAIN_RK3588("av1", 0x0, BIT(12), 0, BIT(11), 0x0, BIT(9), BIT(9), false),
- [RK3588_PD_VI] = DOMAIN_RK3588("vi", 0x0, BIT(13), 0, BIT(12), 0x0, BIT(10), BIT(10), false),
- [RK3588_PD_FEC] = DOMAIN_RK3588("fec", 0x0, BIT(14), 0, BIT(13), 0x0, 0, 0, false),
- [RK3588_PD_ISP1] = DOMAIN_RK3588("isp1", 0x0, BIT(15), 0, BIT(14), 0x0, BIT(11), BIT(11), false),
- [RK3588_PD_RGA31] = DOMAIN_RK3588("rga31", 0x4, BIT(0), 0, BIT(15), 0x0, BIT(12), BIT(12), false),
- [RK3588_PD_VOP] = DOMAIN_RK3588("vop", 0x4, BIT(1), 0, BIT(16), 0x0, BIT(13) | BIT(14), BIT(13) | BIT(14), false),
- [RK3588_PD_VO0] = DOMAIN_RK3588("vo0", 0x4, BIT(2), 0, BIT(17), 0x0, BIT(15), BIT(15), false),
- [RK3588_PD_VO1] = DOMAIN_RK3588("vo1", 0x4, BIT(3), 0, BIT(18), 0x4, BIT(0), BIT(16), false),
- [RK3588_PD_AUDIO] = DOMAIN_RK3588("audio", 0x4, BIT(4), 0, BIT(19), 0x4, BIT(1), BIT(17), false),
- [RK3588_PD_PHP] = DOMAIN_RK3588("php", 0x4, BIT(5), 0, BIT(20), 0x4, BIT(5), BIT(21), false),
- [RK3588_PD_GMAC] = DOMAIN_RK3588("gmac", 0x4, BIT(6), 0, BIT(21), 0x0, 0, 0, false),
- [RK3588_PD_PCIE] = DOMAIN_RK3588("pcie", 0x4, BIT(7), 0, BIT(22), 0x0, 0, 0, true),
- [RK3588_PD_NVM] = DOMAIN_RK3588("nvm", 0x4, BIT(8), BIT(24), 0, 0x4, BIT(2), BIT(18), false),
- [RK3588_PD_NVM0] = DOMAIN_RK3588("nvm0", 0x4, BIT(9), 0, BIT(23), 0x0, 0, 0, false),
- [RK3588_PD_SDIO] = DOMAIN_RK3588("sdio", 0x4, BIT(10), 0, BIT(24), 0x4, BIT(3), BIT(19), false),
- [RK3588_PD_USB] = DOMAIN_RK3588("usb", 0x4, BIT(11), 0, BIT(25), 0x4, BIT(4), BIT(20), true),
- [RK3588_PD_SDMMC] = DOMAIN_RK3588("sdmmc", 0x4, BIT(13), 0, BIT(26), 0x0, 0, 0, false),
-};
-
-static const struct rockchip_pmu_info px30_pmu = {
- .pwr_offset = 0x18,
- .status_offset = 0x20,
- .req_offset = 0x64,
- .idle_offset = 0x6c,
- .ack_offset = 0x6c,
-
- .num_domains = ARRAY_SIZE(px30_pm_domains),
- .domain_info = px30_pm_domains,
-};
-
-static const struct rockchip_pmu_info rk3036_pmu = {
- .req_offset = 0x148,
- .idle_offset = 0x14c,
- .ack_offset = 0x14c,
-
- .num_domains = ARRAY_SIZE(rk3036_pm_domains),
- .domain_info = rk3036_pm_domains,
-};
-
-static const struct rockchip_pmu_info rk3066_pmu = {
- .pwr_offset = 0x08,
- .status_offset = 0x0c,
- .req_offset = 0x38, /* PMU_MISC_CON1 */
- .idle_offset = 0x0c,
- .ack_offset = 0x0c,
-
- .num_domains = ARRAY_SIZE(rk3066_pm_domains),
- .domain_info = rk3066_pm_domains,
-};
-
-static const struct rockchip_pmu_info rk3128_pmu = {
- .pwr_offset = 0x04,
- .status_offset = 0x08,
- .req_offset = 0x0c,
- .idle_offset = 0x10,
- .ack_offset = 0x10,
-
- .num_domains = ARRAY_SIZE(rk3128_pm_domains),
- .domain_info = rk3128_pm_domains,
-};
-
-static const struct rockchip_pmu_info rk3188_pmu = {
- .pwr_offset = 0x08,
- .status_offset = 0x0c,
- .req_offset = 0x38, /* PMU_MISC_CON1 */
- .idle_offset = 0x0c,
- .ack_offset = 0x0c,
-
- .num_domains = ARRAY_SIZE(rk3188_pm_domains),
- .domain_info = rk3188_pm_domains,
-};
-
-static const struct rockchip_pmu_info rk3228_pmu = {
- .req_offset = 0x40c,
- .idle_offset = 0x488,
- .ack_offset = 0x488,
-
- .num_domains = ARRAY_SIZE(rk3228_pm_domains),
- .domain_info = rk3228_pm_domains,
-};
-
-static const struct rockchip_pmu_info rk3288_pmu = {
- .pwr_offset = 0x08,
- .status_offset = 0x0c,
- .req_offset = 0x10,
- .idle_offset = 0x14,
- .ack_offset = 0x14,
-
- .core_pwrcnt_offset = 0x34,
- .gpu_pwrcnt_offset = 0x3c,
-
- .core_power_transition_time = 24, /* 1us */
- .gpu_power_transition_time = 24, /* 1us */
-
- .num_domains = ARRAY_SIZE(rk3288_pm_domains),
- .domain_info = rk3288_pm_domains,
-};
-
-static const struct rockchip_pmu_info rk3328_pmu = {
- .req_offset = 0x414,
- .idle_offset = 0x484,
- .ack_offset = 0x484,
-
- .num_domains = ARRAY_SIZE(rk3328_pm_domains),
- .domain_info = rk3328_pm_domains,
-};
-
-static const struct rockchip_pmu_info rk3366_pmu = {
- .pwr_offset = 0x0c,
- .status_offset = 0x10,
- .req_offset = 0x3c,
- .idle_offset = 0x40,
- .ack_offset = 0x40,
-
- .core_pwrcnt_offset = 0x48,
- .gpu_pwrcnt_offset = 0x50,
-
- .core_power_transition_time = 24,
- .gpu_power_transition_time = 24,
-
- .num_domains = ARRAY_SIZE(rk3366_pm_domains),
- .domain_info = rk3366_pm_domains,
-};
-
-static const struct rockchip_pmu_info rk3368_pmu = {
- .pwr_offset = 0x0c,
- .status_offset = 0x10,
- .req_offset = 0x3c,
- .idle_offset = 0x40,
- .ack_offset = 0x40,
-
- .core_pwrcnt_offset = 0x48,
- .gpu_pwrcnt_offset = 0x50,
-
- .core_power_transition_time = 24,
- .gpu_power_transition_time = 24,
-
- .num_domains = ARRAY_SIZE(rk3368_pm_domains),
- .domain_info = rk3368_pm_domains,
-};
-
-static const struct rockchip_pmu_info rk3399_pmu = {
- .pwr_offset = 0x14,
- .status_offset = 0x18,
- .req_offset = 0x60,
- .idle_offset = 0x64,
- .ack_offset = 0x68,
-
- /* ARM Trusted Firmware manages power transition times */
-
- .num_domains = ARRAY_SIZE(rk3399_pm_domains),
- .domain_info = rk3399_pm_domains,
-};
-
-static const struct rockchip_pmu_info rk3568_pmu = {
- .pwr_offset = 0xa0,
- .status_offset = 0x98,
- .req_offset = 0x50,
- .idle_offset = 0x68,
- .ack_offset = 0x60,
-
- .num_domains = ARRAY_SIZE(rk3568_pm_domains),
- .domain_info = rk3568_pm_domains,
-};
-
-static const struct rockchip_pmu_info rk3588_pmu = {
- .pwr_offset = 0x14c,
- .status_offset = 0x180,
- .req_offset = 0x10c,
- .idle_offset = 0x120,
- .ack_offset = 0x118,
- .repair_status_offset = 0x290,
-
- .num_domains = ARRAY_SIZE(rk3588_pm_domains),
- .domain_info = rk3588_pm_domains,
-};
-
-static const struct rockchip_pmu_info rv1126_pmu = {
- .pwr_offset = 0x110,
- .status_offset = 0x108,
- .req_offset = 0xc0,
- .idle_offset = 0xd8,
- .ack_offset = 0xd0,
-
- .num_domains = ARRAY_SIZE(rv1126_pm_domains),
- .domain_info = rv1126_pm_domains,
-};
-
-static const struct of_device_id rockchip_pm_domain_dt_match[] = {
- {
- .compatible = "rockchip,px30-power-controller",
- .data = (void *)&px30_pmu,
- },
- {
- .compatible = "rockchip,rk3036-power-controller",
- .data = (void *)&rk3036_pmu,
- },
- {
- .compatible = "rockchip,rk3066-power-controller",
- .data = (void *)&rk3066_pmu,
- },
- {
- .compatible = "rockchip,rk3128-power-controller",
- .data = (void *)&rk3128_pmu,
- },
- {
- .compatible = "rockchip,rk3188-power-controller",
- .data = (void *)&rk3188_pmu,
- },
- {
- .compatible = "rockchip,rk3228-power-controller",
- .data = (void *)&rk3228_pmu,
- },
- {
- .compatible = "rockchip,rk3288-power-controller",
- .data = (void *)&rk3288_pmu,
- },
- {
- .compatible = "rockchip,rk3328-power-controller",
- .data = (void *)&rk3328_pmu,
- },
- {
- .compatible = "rockchip,rk3366-power-controller",
- .data = (void *)&rk3366_pmu,
- },
- {
- .compatible = "rockchip,rk3368-power-controller",
- .data = (void *)&rk3368_pmu,
- },
- {
- .compatible = "rockchip,rk3399-power-controller",
- .data = (void *)&rk3399_pmu,
- },
- {
- .compatible = "rockchip,rk3568-power-controller",
- .data = (void *)&rk3568_pmu,
- },
- {
- .compatible = "rockchip,rk3588-power-controller",
- .data = (void *)&rk3588_pmu,
- },
- {
- .compatible = "rockchip,rv1126-power-controller",
- .data = (void *)&rv1126_pmu,
- },
- { /* sentinel */ },
-};
-
-static struct platform_driver rockchip_pm_domain_driver = {
- .probe = rockchip_pm_domain_probe,
- .driver = {
- .name = "rockchip-pm-domain",
- .of_match_table = rockchip_pm_domain_dt_match,
- /*
- * We can't forcibly eject devices from the power
- * domain, so we can't really remove power domains
- * once they were added.
- */
- .suppress_bind_attrs = true,
- },
-};
-
-static int __init rockchip_pm_domain_drv_register(void)
-{
- return platform_driver_register(&rockchip_pm_domain_driver);
-}
-postcore_initcall(rockchip_pm_domain_drv_register);
diff --git a/drivers/soc/samsung/Kconfig b/drivers/soc/samsung/Kconfig
index 02e319508cc6..1a5dfdc978dc 100644
--- a/drivers/soc/samsung/Kconfig
+++ b/drivers/soc/samsung/Kconfig
@@ -42,39 +42,16 @@ 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
bool "Exynos PMU ARMv7-specific driver extensions" if COMPILE_TEST
depends on EXYNOS_PMU
-config EXYNOS_PM_DOMAINS
- bool "Exynos PM domains" if COMPILE_TEST
- depends on (ARCH_EXYNOS && PM_GENERIC_DOMAINS) || COMPILE_TEST
-
-config SAMSUNG_PM_DEBUG
- bool "Samsung PM Suspend debug"
- depends on PM && DEBUG_KERNEL
- depends on PLAT_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210
- depends on DEBUG_S3C24XX_UART || DEBUG_S3C2410_UART
- depends on DEBUG_LL && MMU
- help
- Say Y here if you want verbose debugging from the PM Suspend and
- Resume code. See <file:Documentation/arm/samsung-s3c24xx/suspend.rst>
- for more information.
-
-config S3C_PM_DEBUG_LED_SMDK
- bool "SMDK LED suspend/resume debugging"
- depends on PM && (MACH_SMDK6410)
- help
- Say Y here to enable the use of the SMDK LEDs on the baseboard
- for debugging of the state of the suspend and resume process.
-
- Note, this currently only works for S3C64XX based SMDK boards.
-
config SAMSUNG_PM_CHECK
bool "S3C2410 PM Suspend Memory CRC"
- depends on PM && (PLAT_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210)
+ depends on PM && (ARCH_S3C64XX || ARCH_S5PV210)
select CRC32
help
Enable the PM code's memory area checksum over sleep. This option
@@ -85,8 +62,6 @@ config SAMSUNG_PM_CHECK
Note, this can take several seconds depending on memory size
and CPU speed.
- See <file:Documentation/arm/samsung-s3c24xx/suspend.rst>
-
config SAMSUNG_PM_CHECK_CHUNKSIZE
int "S3C2410 PM Suspend CRC Chunksize (KiB)"
depends on PM && SAMSUNG_PM_CHECK
@@ -97,8 +72,6 @@ config SAMSUNG_PM_CHECK_CHUNKSIZE
the CRC data block will take more memory, but will identify any
faults with better precision.
- See <file:Documentation/arm/samsung-s3c24xx/suspend.rst>
-
config EXYNOS_REGULATOR_COUPLER
bool "Exynos SoC Regulator Coupler" if COMPILE_TEST
depends on ARCH_EXYNOS || COMPILE_TEST
diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile
index 9f59d1905ab0..636a762608c9 100644
--- a/drivers/soc/samsung/Makefile
+++ b/drivers/soc/samsung/Makefile
@@ -6,12 +6,11 @@ exynos_chipid-y += exynos-chipid.o exynos-asv.o
obj-$(CONFIG_EXYNOS_USI) += exynos-usi.o
-obj-$(CONFIG_EXYNOS_PMU) += exynos-pmu.o
+obj-$(CONFIG_EXYNOS_PMU) += exynos_pmu.o
+exynos_pmu-y += exynos-pmu.o gs101-pmu.o
obj-$(CONFIG_EXYNOS_PMU_ARM_DRIVERS) += exynos3250-pmu.o exynos4-pmu.o \
exynos5250-pmu.o exynos5420-pmu.o
-obj-$(CONFIG_EXYNOS_PM_DOMAINS) += pm_domains.o
obj-$(CONFIG_EXYNOS_REGULATOR_COUPLER) += exynos-regulator-coupler.o
obj-$(CONFIG_SAMSUNG_PM_CHECK) += s3c-pm-check.o
-obj-$(CONFIG_SAMSUNG_PM_DEBUG) += s3c-pm-debug.o
diff --git a/drivers/soc/samsung/exynos-asv.c b/drivers/soc/samsung/exynos-asv.c
index d60af8acc391..8e681f519526 100644
--- a/drivers/soc/samsung/exynos-asv.c
+++ b/drivers/soc/samsung/exynos-asv.c
@@ -9,8 +9,10 @@
* Samsung Exynos SoC Adaptive Supply Voltage support
*/
+#include <linux/array_size.h>
#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 +99,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 0fb3631e7346..d3b4b5508e0c 100644
--- a/drivers/soc/samsung/exynos-chipid.c
+++ b/drivers/soc/samsung/exynos-chipid.c
@@ -12,12 +12,12 @@
* Samsung Exynos SoC Adaptive Supply Voltage and Chip ID support
*/
+#include <linux/array_size.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -56,10 +56,18 @@ static const struct exynos_soc_id {
{ "EXYNOS5440", 0xE5440000 },
{ "EXYNOS5800", 0xE5422000 },
{ "EXYNOS7420", 0xE7420000 },
+ { "EXYNOS7870", 0xE7870000 },
+ { "EXYNOS8890", 0xE8890000 },
/* Compatible with: samsung,exynos850-chipid */
+ { "EXYNOS2200", 0xE9925000 },
{ "EXYNOS7885", 0xE7885000 },
{ "EXYNOS850", 0xE3830000 },
+ { "EXYNOS8895", 0xE8895000 },
+ { "EXYNOS9610", 0xE9610000 },
+ { "EXYNOS9810", 0xE9810000 },
+ { "EXYNOS990", 0xE9830000 },
{ "EXYNOSAUTOV9", 0xAAA80000 },
+ { "EXYNOSAUTOV920", 0x0A920000 },
};
static const char *product_id_to_soc_id(unsigned int product_id)
@@ -101,16 +109,17 @@ static int exynos_chipid_probe(struct platform_device *pdev)
const struct exynos_chipid_variant *drv_data;
struct exynos_chipid_info soc_info;
struct soc_device_attribute *soc_dev_attr;
+ struct device *dev = &pdev->dev;
struct soc_device *soc_dev;
struct device_node *root;
struct regmap *regmap;
int ret;
- drv_data = of_device_get_match_data(&pdev->dev);
+ drv_data = of_device_get_match_data(dev);
if (!drv_data)
return -EINVAL;
- regmap = device_node_to_regmap(pdev->dev.of_node);
+ regmap = device_node_to_regmap(dev->of_node);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
@@ -118,8 +127,7 @@ static int exynos_chipid_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- soc_dev_attr = devm_kzalloc(&pdev->dev, sizeof(*soc_dev_attr),
- GFP_KERNEL);
+ soc_dev_attr = devm_kzalloc(dev, sizeof(*soc_dev_attr), GFP_KERNEL);
if (!soc_dev_attr)
return -ENOMEM;
@@ -129,8 +137,10 @@ static int exynos_chipid_probe(struct platform_device *pdev)
of_property_read_string(root, "model", &soc_dev_attr->machine);
of_node_put(root);
- soc_dev_attr->revision = devm_kasprintf(&pdev->dev, GFP_KERNEL,
- "%x", soc_info.revision);
+ soc_dev_attr->revision = devm_kasprintf(dev, GFP_KERNEL, "%x",
+ soc_info.revision);
+ if (!soc_dev_attr->revision)
+ return -ENOMEM;
soc_dev_attr->soc_id = product_id_to_soc_id(soc_info.product_id);
if (!soc_dev_attr->soc_id) {
pr_err("Unknown SoC\n");
@@ -142,13 +152,13 @@ static int exynos_chipid_probe(struct platform_device *pdev)
if (IS_ERR(soc_dev))
return PTR_ERR(soc_dev);
- ret = exynos_asv_init(&pdev->dev, regmap);
+ ret = exynos_asv_init(dev, regmap);
if (ret)
goto err;
platform_set_drvdata(pdev, soc_dev);
- dev_info(&pdev->dev, "Exynos: CPU[%s] PRO_ID[0x%x] REV[0x%x] Detected\n",
+ dev_info(dev, "Exynos: CPU[%s] PRO_ID[0x%x] REV[0x%x] Detected\n",
soc_dev_attr->soc_id, soc_info.product_id, soc_info.revision);
return 0;
@@ -159,13 +169,11 @@ err:
return ret;
}
-static int exynos_chipid_remove(struct platform_device *pdev)
+static void exynos_chipid_remove(struct platform_device *pdev)
{
struct soc_device *soc_dev = platform_get_drvdata(pdev);
soc_device_unregister(soc_dev);
-
- return 0;
}
static const struct exynos_chipid_variant exynos4210_chipid_drv_data = {
@@ -197,8 +205,8 @@ static struct platform_driver exynos_chipid_driver = {
.name = "exynos-chipid",
.of_match_table = exynos_chipid_of_device_ids,
},
- .probe = exynos_chipid_probe,
- .remove = 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 732c86ce2be8..d58376c38179 100644
--- a/drivers/soc/samsung/exynos-pmu.c
+++ b/drivers/soc/samsung/exynos-pmu.c
@@ -5,13 +5,19 @@
//
// Exynos - CPU PMU(Power Management Unit) support
+#include <linux/array_size.h>
+#include <linux/bitmap.h>
+#include <linux/cpuhotplug.h>
+#include <linux/cpu_pm.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/syscon.h>
+#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <linux/regmap.h>
#include <linux/soc/samsung/exynos-regs-pmu.h>
#include <linux/soc/samsung/exynos-pmu.h>
@@ -21,10 +27,23 @@
struct exynos_pmu_context {
struct device *dev;
const struct exynos_pmu_data *pmu_data;
+ struct regmap *pmureg;
+ struct regmap *pmuintrgen;
+ /*
+ * Serialization lock for CPU hot plug and cpuidle ACPM hint
+ * programming. Also protects in_cpuhp, sys_insuspend & sys_inreboot
+ * flags.
+ */
+ raw_spinlock_t cpupm_lock;
+ unsigned long *in_cpuhp;
+ bool sys_insuspend;
+ bool sys_inreboot;
};
void __iomem *pmu_base_addr;
static struct exynos_pmu_context *pmu_context;
+/* forward declaration */
+static struct platform_driver exynos_pmu_driver;
void pmu_raw_writel(u32 val, u32 offset)
{
@@ -57,6 +76,12 @@ void exynos_sys_powerdown_conf(enum sys_powerdown mode)
if (pmu_data->powerdown_conf_extra)
pmu_data->powerdown_conf_extra(mode);
+
+ if (pmu_data->pmu_config_extra) {
+ for (i = 0; pmu_data->pmu_config_extra[i].offset != PMU_TABLE_END; i++)
+ pmu_raw_writel(pmu_data->pmu_config_extra[i].val[mode],
+ pmu_data->pmu_config_extra[i].offset);
+ }
}
/*
@@ -69,17 +94,45 @@ 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,
+ .use_raw_spinlock = true,
+};
+
+static const struct regmap_config regmap_pmu_intr = {
+ .name = "pmu_intr_gen",
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .use_raw_spinlock = 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),
}, {
.compatible = "samsung,exynos4210-pmu",
.data = exynos_pmu_data_arm_ptr(exynos4210_pmu_data),
}, {
+ .compatible = "samsung,exynos4212-pmu",
+ .data = exynos_pmu_data_arm_ptr(exynos4212_pmu_data),
+ }, {
.compatible = "samsung,exynos4412-pmu",
.data = exynos_pmu_data_arm_ptr(exynos4412_pmu_data),
}, {
@@ -104,19 +157,328 @@ 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);
+
+ put_device(dev);
+
+ return syscon_node_to_regmap(pmu_np);
+}
+EXPORT_SYMBOL_GPL(exynos_get_pmu_regmap_by_phandle);
+
+/*
+ * CPU_INFORM register "hint" values are required to be programmed in addition to
+ * the standard PSCI calls to have functional CPU hotplug and CPU idle states.
+ * This is required to workaround limitations in the el3mon/ACPM firmware.
+ */
+#define CPU_INFORM_CLEAR 0
+#define CPU_INFORM_C2 1
+
+/*
+ * __gs101_cpu_pmu_ prefix functions are common code shared by CPU PM notifiers
+ * (CPUIdle) and CPU hotplug callbacks. Functions should be called with IRQs
+ * disabled and cpupm_lock held.
+ */
+static int __gs101_cpu_pmu_online(unsigned int cpu)
+ __must_hold(&pmu_context->cpupm_lock)
+{
+ unsigned int cpuhint = smp_processor_id();
+ u32 reg, mask;
+
+ /* clear cpu inform hint */
+ regmap_write(pmu_context->pmureg, GS101_CPU_INFORM(cpuhint),
+ CPU_INFORM_CLEAR);
+
+ mask = BIT(cpu);
+
+ regmap_update_bits(pmu_context->pmuintrgen, GS101_GRP2_INTR_BID_ENABLE,
+ mask, (0 << cpu));
+
+ regmap_read(pmu_context->pmuintrgen, GS101_GRP2_INTR_BID_UPEND, &reg);
+
+ regmap_write(pmu_context->pmuintrgen, GS101_GRP2_INTR_BID_CLEAR,
+ reg & mask);
+
+ return 0;
+}
+
+/* Called from CPU PM notifier (CPUIdle code path) with IRQs disabled */
+static int gs101_cpu_pmu_online(void)
+{
+ int cpu;
+
+ raw_spin_lock(&pmu_context->cpupm_lock);
+
+ if (pmu_context->sys_inreboot) {
+ raw_spin_unlock(&pmu_context->cpupm_lock);
+ return NOTIFY_OK;
+ }
+
+ cpu = smp_processor_id();
+ __gs101_cpu_pmu_online(cpu);
+ raw_spin_unlock(&pmu_context->cpupm_lock);
+
+ return NOTIFY_OK;
+}
+
+/* Called from CPU hot plug callback with IRQs enabled */
+static int gs101_cpuhp_pmu_online(unsigned int cpu)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&pmu_context->cpupm_lock, flags);
+
+ __gs101_cpu_pmu_online(cpu);
+ /*
+ * Mark this CPU as having finished the hotplug.
+ * This means this CPU can now enter C2 idle state.
+ */
+ clear_bit(cpu, pmu_context->in_cpuhp);
+ raw_spin_unlock_irqrestore(&pmu_context->cpupm_lock, flags);
+
+ return 0;
+}
+
+/* Common function shared by both CPU hot plug and CPUIdle */
+static int __gs101_cpu_pmu_offline(unsigned int cpu)
+ __must_hold(&pmu_context->cpupm_lock)
+{
+ unsigned int cpuhint = smp_processor_id();
+ u32 reg, mask;
+
+ /* set cpu inform hint */
+ regmap_write(pmu_context->pmureg, GS101_CPU_INFORM(cpuhint),
+ CPU_INFORM_C2);
+
+ mask = BIT(cpu);
+ regmap_update_bits(pmu_context->pmuintrgen, GS101_GRP2_INTR_BID_ENABLE,
+ mask, BIT(cpu));
+
+ regmap_read(pmu_context->pmuintrgen, GS101_GRP1_INTR_BID_UPEND, &reg);
+ regmap_write(pmu_context->pmuintrgen, GS101_GRP1_INTR_BID_CLEAR,
+ reg & mask);
+
+ mask = (BIT(cpu + 8));
+ regmap_read(pmu_context->pmuintrgen, GS101_GRP1_INTR_BID_UPEND, &reg);
+ regmap_write(pmu_context->pmuintrgen, GS101_GRP1_INTR_BID_CLEAR,
+ reg & mask);
+
+ return 0;
+}
+
+/* Called from CPU PM notifier (CPUIdle code path) with IRQs disabled */
+static int gs101_cpu_pmu_offline(void)
+{
+ int cpu;
+
+ raw_spin_lock(&pmu_context->cpupm_lock);
+ cpu = smp_processor_id();
+
+ if (test_bit(cpu, pmu_context->in_cpuhp)) {
+ raw_spin_unlock(&pmu_context->cpupm_lock);
+ return NOTIFY_BAD;
+ }
+
+ /* Ignore CPU_PM_ENTER event in reboot or suspend sequence. */
+ if (pmu_context->sys_insuspend || pmu_context->sys_inreboot) {
+ raw_spin_unlock(&pmu_context->cpupm_lock);
+ return NOTIFY_OK;
+ }
+
+ __gs101_cpu_pmu_offline(cpu);
+ raw_spin_unlock(&pmu_context->cpupm_lock);
+
+ return NOTIFY_OK;
+}
+
+/* Called from CPU hot plug callback with IRQs enabled */
+static int gs101_cpuhp_pmu_offline(unsigned int cpu)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&pmu_context->cpupm_lock, flags);
+ /*
+ * Mark this CPU as entering hotplug. So as not to confuse
+ * ACPM the CPU entering hotplug should not enter C2 idle state.
+ */
+ set_bit(cpu, pmu_context->in_cpuhp);
+ __gs101_cpu_pmu_offline(cpu);
+
+ raw_spin_unlock_irqrestore(&pmu_context->cpupm_lock, flags);
+
+ return 0;
+}
+
+static int gs101_cpu_pm_notify_callback(struct notifier_block *self,
+ unsigned long action, void *v)
+{
+ switch (action) {
+ case CPU_PM_ENTER:
+ return gs101_cpu_pmu_offline();
+
+ case CPU_PM_EXIT:
+ return gs101_cpu_pmu_online();
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block gs101_cpu_pm_notifier = {
+ .notifier_call = gs101_cpu_pm_notify_callback,
+ /*
+ * We want to be called first, as the ACPM hint and handshake is what
+ * puts the CPU into C2.
+ */
+ .priority = INT_MAX
+};
+
+static int exynos_cpupm_reboot_notifier(struct notifier_block *nb,
+ unsigned long event, void *v)
+{
+ unsigned long flags;
+
+ switch (event) {
+ case SYS_POWER_OFF:
+ case SYS_RESTART:
+ raw_spin_lock_irqsave(&pmu_context->cpupm_lock, flags);
+ pmu_context->sys_inreboot = true;
+ raw_spin_unlock_irqrestore(&pmu_context->cpupm_lock, flags);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block exynos_cpupm_reboot_nb = {
+ .priority = INT_MAX,
+ .notifier_call = exynos_cpupm_reboot_notifier,
+};
+
+static int setup_cpuhp_and_cpuidle(struct device *dev)
+{
+ struct device_node *intr_gen_node;
+ struct resource intrgen_res;
+ void __iomem *virt_addr;
+ int ret, cpu;
+
+ intr_gen_node = of_parse_phandle(dev->of_node,
+ "google,pmu-intr-gen-syscon", 0);
+ if (!intr_gen_node) {
+ /*
+ * To maintain support for older DTs that didn't specify syscon
+ * phandle just issue a warning rather than fail to probe.
+ */
+ dev_warn(dev, "pmu-intr-gen syscon unavailable\n");
+ return 0;
+ }
+
+ /*
+ * To avoid lockdep issues (CPU PM notifiers use raw spinlocks) create
+ * a mmio regmap for pmu-intr-gen that uses raw spinlocks instead of
+ * syscon provided regmap.
+ */
+ ret = of_address_to_resource(intr_gen_node, 0, &intrgen_res);
+ of_node_put(intr_gen_node);
+
+ virt_addr = devm_ioremap(dev, intrgen_res.start,
+ resource_size(&intrgen_res));
+ if (!virt_addr)
+ return -ENOMEM;
+
+ pmu_context->pmuintrgen = devm_regmap_init_mmio(dev, virt_addr,
+ &regmap_pmu_intr);
+ if (IS_ERR(pmu_context->pmuintrgen)) {
+ dev_err(dev, "failed to initialize pmu-intr-gen regmap\n");
+ return PTR_ERR(pmu_context->pmuintrgen);
+ }
+
+ /* register custom mmio regmap with syscon */
+ ret = of_syscon_register_regmap(intr_gen_node,
+ pmu_context->pmuintrgen);
+ if (ret)
+ return ret;
+
+ pmu_context->in_cpuhp = devm_bitmap_zalloc(dev, num_possible_cpus(),
+ GFP_KERNEL);
+ if (!pmu_context->in_cpuhp)
+ return -ENOMEM;
+
+ /* set PMU to power on */
+ for_each_online_cpu(cpu)
+ gs101_cpuhp_pmu_online(cpu);
+
+ /* register CPU hotplug callbacks */
+ cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "soc/exynos-pmu:prepare",
+ gs101_cpuhp_pmu_online, NULL);
+
+ cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "soc/exynos-pmu:online",
+ NULL, gs101_cpuhp_pmu_offline);
+
+ /* register CPU PM notifiers for cpuidle */
+ cpu_pm_register_notifier(&gs101_cpu_pm_notifier);
+ register_reboot_notifier(&exynos_cpupm_reboot_nb);
+ return 0;
+}
+
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);
@@ -128,9 +490,53 @@ 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;
+ pmu_regmcfg.wr_table = pmu_context->pmu_data->wr_table;
+ pmu_regmcfg.rd_table = pmu_context->pmu_data->rd_table;
+
+ /* 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;
+ raw_spin_lock_init(&pmu_context->cpupm_lock);
+ pmu_context->sys_inreboot = false;
+ pmu_context->sys_insuspend = false;
+
+ if (pmu_context->pmu_data && pmu_context->pmu_data->pmu_cpuhp) {
+ ret = setup_cpuhp_and_cpuidle(dev);
+ if (ret)
+ return ret;
+ }
+
if (pmu_context->pmu_data && pmu_context->pmu_data->pmu_init)
pmu_context->pmu_data->pmu_init();
@@ -148,10 +554,32 @@ static int exynos_pmu_probe(struct platform_device *pdev)
return 0;
}
+static int exynos_cpupm_suspend_noirq(struct device *dev)
+{
+ raw_spin_lock(&pmu_context->cpupm_lock);
+ pmu_context->sys_insuspend = true;
+ raw_spin_unlock(&pmu_context->cpupm_lock);
+ return 0;
+}
+
+static int exynos_cpupm_resume_noirq(struct device *dev)
+{
+ raw_spin_lock(&pmu_context->cpupm_lock);
+ pmu_context->sys_insuspend = false;
+ raw_spin_unlock(&pmu_context->cpupm_lock);
+ return 0;
+}
+
+static const struct dev_pm_ops cpupm_pm_ops = {
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos_cpupm_suspend_noirq,
+ exynos_cpupm_resume_noirq)
+};
+
static struct platform_driver exynos_pmu_driver = {
.driver = {
.name = "exynos-pmu",
.of_match_table = exynos_pmu_of_device_ids,
+ .pm = pm_sleep_ptr(&cpupm_pm_ops),
},
.probe = exynos_pmu_probe,
};
diff --git a/drivers/soc/samsung/exynos-pmu.h b/drivers/soc/samsung/exynos-pmu.h
index 5e851f32307e..fbe381e2a2e1 100644
--- a/drivers/soc/samsung/exynos-pmu.h
+++ b/drivers/soc/samsung/exynos-pmu.h
@@ -13,17 +13,50 @@
#define PMU_TABLE_END (-1U)
+struct regmap_access_table;
+
struct exynos_pmu_conf {
unsigned int offset;
u8 val[NUM_SYS_POWERDOWN];
};
+/**
+ * struct exynos_pmu_data - of_device_id (match) data
+ *
+ * @pmu_config: Optional table detailing register writes for target system
+ * states: SYS_AFTR, SYS_LPA, SYS_SLEEP.
+ * @pmu_config_extra: Optional secondary table detailing additional register
+ * writes for target system states: SYS_AFTR, SYS_LPA,
+ * SYS_SLEEP.
+ * @pmu_secure: Whether or not PMU register writes need to be done via SMC call.
+ * @pmu_cpuhp: Whether or not extra handling is required for CPU hotplug and
+ * CPUidle outside of standard PSCI calls, due to non-compliant
+ * firmware.
+ * @pmu_init: Optional init function.
+ * @powerdown_conf: Optional callback before entering target system states:
+ * SYS_AFTR, SYS_LPA, SYS_SLEEP. This will be invoked before
+ * the registers from @pmu_config are written.
+ * @powerdown_conf_extra: Optional secondary callback before entering
+ * target system states: SYS_AFTR, SYS_LPA, SYS_SLEEP.
+ * This will be invoked after @pmu_config registers have
+ * been written.
+ * @rd_table: A table of readable register ranges in case a custom regmap is
+ * used (i.e. when @pmu_secure is @true).
+ * @wr_table: A table of writable register ranges in case a custom regmap is
+ * used (i.e. when @pmu_secure is @true).
+ */
struct exynos_pmu_data {
const struct exynos_pmu_conf *pmu_config;
+ const struct exynos_pmu_conf *pmu_config_extra;
+ bool pmu_secure;
+ bool pmu_cpuhp;
void (*pmu_init)(void);
void (*powerdown_conf)(enum sys_powerdown);
void (*powerdown_conf_extra)(enum sys_powerdown);
+
+ const struct regmap_access_table *rd_table;
+ const struct regmap_access_table *wr_table;
};
extern void __iomem *pmu_base_addr;
@@ -32,11 +65,19 @@ extern void __iomem *pmu_base_addr;
/* list of all exported SoC specific data */
extern const struct exynos_pmu_data exynos3250_pmu_data;
extern const struct exynos_pmu_data exynos4210_pmu_data;
+extern const struct exynos_pmu_data exynos4212_pmu_data;
extern const struct exynos_pmu_data exynos4412_pmu_data;
extern const struct exynos_pmu_data exynos5250_pmu_data;
extern const struct exynos_pmu_data exynos5420_pmu_data;
#endif
+extern const struct exynos_pmu_data gs101_pmu_data;
extern void pmu_raw_writel(u32 val, u32 offset);
extern u32 pmu_raw_readl(u32 offset);
+
+int tensor_sec_reg_write(void *context, unsigned int reg, unsigned int val);
+int tensor_sec_reg_read(void *context, unsigned int reg, unsigned int *val);
+int tensor_sec_update_bits(void *context, unsigned int reg, unsigned int mask,
+ unsigned int val);
+
#endif /* __EXYNOS_PMU_H */
diff --git a/drivers/soc/samsung/exynos-usi.c b/drivers/soc/samsung/exynos-usi.c
index 114352695ac2..5f7bdf3bab05 100644
--- a/drivers/soc/samsung/exynos-usi.c
+++ b/drivers/soc/samsung/exynos-usi.c
@@ -6,6 +6,7 @@
* Samsung Exynos USI driver (Universal Serial Interface).
*/
+#include <linux/array_size.h>
#include <linux/clk.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
@@ -16,6 +17,18 @@
#include <dt-bindings/soc/samsung,exynos-usi.h>
+/* USIv1: System Register: SW_CONF register bits */
+#define USI_V1_SW_CONF_NONE 0x0
+#define USI_V1_SW_CONF_I2C0 0x1
+#define USI_V1_SW_CONF_I2C1 0x2
+#define USI_V1_SW_CONF_I2C0_1 0x3
+#define USI_V1_SW_CONF_SPI 0x4
+#define USI_V1_SW_CONF_UART 0x8
+#define USI_V1_SW_CONF_UART_I2C1 0xa
+#define USI_V1_SW_CONF_MASK (USI_V1_SW_CONF_I2C0 | USI_V1_SW_CONF_I2C1 | \
+ USI_V1_SW_CONF_I2C0_1 | USI_V1_SW_CONF_SPI | \
+ USI_V1_SW_CONF_UART | USI_V1_SW_CONF_UART_I2C1)
+
/* USIv2: System Register: SW_CONF register bits */
#define USI_V2_SW_CONF_NONE 0x0
#define USI_V2_SW_CONF_UART BIT(0)
@@ -34,7 +47,8 @@
#define USI_OPTION_CLKSTOP_ON BIT(2)
enum exynos_usi_ver {
- USI_VER2 = 2,
+ USI_VER1 = 0,
+ USI_VER2,
};
struct exynos_usi_variant {
@@ -66,19 +80,39 @@ struct exynos_usi_mode {
unsigned int val; /* mode register value */
};
-static const struct exynos_usi_mode exynos_usi_modes[] = {
- [USI_V2_NONE] = { .name = "none", .val = USI_V2_SW_CONF_NONE },
- [USI_V2_UART] = { .name = "uart", .val = USI_V2_SW_CONF_UART },
- [USI_V2_SPI] = { .name = "spi", .val = USI_V2_SW_CONF_SPI },
- [USI_V2_I2C] = { .name = "i2c", .val = USI_V2_SW_CONF_I2C },
+#define USI_MODES_MAX (USI_MODE_UART_I2C1 + 1)
+static const struct exynos_usi_mode exynos_usi_modes[][USI_MODES_MAX] = {
+ [USI_VER1] = {
+ [USI_MODE_NONE] = { .name = "none", .val = USI_V1_SW_CONF_NONE },
+ [USI_MODE_UART] = { .name = "uart", .val = USI_V1_SW_CONF_UART },
+ [USI_MODE_SPI] = { .name = "spi", .val = USI_V1_SW_CONF_SPI },
+ [USI_MODE_I2C] = { .name = "i2c", .val = USI_V1_SW_CONF_I2C0 },
+ [USI_MODE_I2C1] = { .name = "i2c1", .val = USI_V1_SW_CONF_I2C1 },
+ [USI_MODE_I2C0_1] = { .name = "i2c0_1", .val = USI_V1_SW_CONF_I2C0_1 },
+ [USI_MODE_UART_I2C1] = { .name = "uart_i2c1", .val = USI_V1_SW_CONF_UART_I2C1 },
+ }, [USI_VER2] = {
+ [USI_MODE_NONE] = { .name = "none", .val = USI_V2_SW_CONF_NONE },
+ [USI_MODE_UART] = { .name = "uart", .val = USI_V2_SW_CONF_UART },
+ [USI_MODE_SPI] = { .name = "spi", .val = USI_V2_SW_CONF_SPI },
+ [USI_MODE_I2C] = { .name = "i2c", .val = USI_V2_SW_CONF_I2C },
+ },
};
static const char * const exynos850_usi_clk_names[] = { "pclk", "ipclk" };
static const struct exynos_usi_variant exynos850_usi_data = {
.ver = USI_VER2,
.sw_conf_mask = USI_V2_SW_CONF_MASK,
- .min_mode = USI_V2_NONE,
- .max_mode = USI_V2_I2C,
+ .min_mode = USI_MODE_NONE,
+ .max_mode = USI_MODE_I2C,
+ .num_clks = ARRAY_SIZE(exynos850_usi_clk_names),
+ .clk_names = exynos850_usi_clk_names,
+};
+
+static const struct exynos_usi_variant exynos8895_usi_data = {
+ .ver = USI_VER1,
+ .sw_conf_mask = USI_V1_SW_CONF_MASK,
+ .min_mode = USI_MODE_NONE,
+ .max_mode = USI_MODE_UART_I2C1,
.num_clks = ARRAY_SIZE(exynos850_usi_clk_names),
.clk_names = exynos850_usi_clk_names,
};
@@ -87,6 +121,9 @@ static const struct of_device_id exynos_usi_dt_match[] = {
{
.compatible = "samsung,exynos850-usi",
.data = &exynos850_usi_data,
+ }, {
+ .compatible = "samsung,exynos8895-usi",
+ .data = &exynos8895_usi_data,
},
{ } /* sentinel */
};
@@ -109,14 +146,15 @@ static int exynos_usi_set_sw_conf(struct exynos_usi *usi, size_t mode)
if (mode < usi->data->min_mode || mode > usi->data->max_mode)
return -EINVAL;
- val = exynos_usi_modes[mode].val;
+ val = exynos_usi_modes[usi->data->ver][mode].val;
ret = regmap_update_bits(usi->sysreg, usi->sw_conf,
usi->data->sw_conf_mask, val);
if (ret)
return ret;
usi->mode = mode;
- dev_dbg(usi->dev, "protocol: %s\n", exynos_usi_modes[usi->mode].name);
+ dev_dbg(usi->dev, "protocol: %s\n",
+ exynos_usi_modes[usi->data->ver][usi->mode].name);
return 0;
}
@@ -168,10 +206,42 @@ static int exynos_usi_configure(struct exynos_usi *usi)
if (ret)
return ret;
- if (usi->data->ver == USI_VER2)
- return exynos_usi_enable(usi);
+ if (usi->data->ver == USI_VER1)
+ ret = clk_bulk_prepare_enable(usi->data->num_clks,
+ usi->clks);
+ else if (usi->data->ver == USI_VER2)
+ ret = exynos_usi_enable(usi);
- return 0;
+ return ret;
+}
+
+static void exynos_usi_unconfigure(void *data)
+{
+ struct exynos_usi *usi = data;
+ u32 val;
+ int ret;
+
+ if (usi->data->ver == USI_VER1) {
+ clk_bulk_disable_unprepare(usi->data->num_clks, usi->clks);
+ return;
+ }
+
+ ret = clk_bulk_prepare_enable(usi->data->num_clks, usi->clks);
+ if (ret)
+ return;
+
+ /* Make sure that we've stopped providing the clock to USI IP */
+ val = readl(usi->regs + USI_OPTION);
+ val &= ~USI_OPTION_CLKREQ_ON;
+ val |= USI_OPTION_CLKSTOP_ON;
+ writel(val, usi->regs + USI_OPTION);
+
+ /* Set USI block state to reset */
+ val = readl(usi->regs + USI_CON);
+ val |= USI_CON_RESET;
+ writel(val, usi->regs + USI_CON);
+
+ clk_bulk_disable_unprepare(usi->data->num_clks, usi->clks);
}
static int exynos_usi_parse_dt(struct device_node *np, struct exynos_usi *usi)
@@ -186,15 +256,11 @@ static int exynos_usi_parse_dt(struct device_node *np, struct exynos_usi *usi)
return -EINVAL;
usi->mode = mode;
- usi->sysreg = syscon_regmap_lookup_by_phandle(np, "samsung,sysreg");
+ usi->sysreg = syscon_regmap_lookup_by_phandle_args(np, "samsung,sysreg",
+ 1, &usi->sw_conf);
if (IS_ERR(usi->sysreg))
return PTR_ERR(usi->sysreg);
- ret = of_property_read_u32_index(np, "samsung,sysreg", 1,
- &usi->sw_conf);
- if (ret)
- return ret;
-
usi->clkreq_on = of_property_read_bool(np, "samsung,clkreq-on");
return 0;
@@ -255,6 +321,10 @@ static int exynos_usi_probe(struct platform_device *pdev)
if (ret)
return ret;
+ ret = devm_add_action_or_reset(&pdev->dev, exynos_usi_unconfigure, usi);
+ if (ret)
+ return ret;
+
/* Make it possible to embed protocol nodes into USI np */
return of_platform_populate(np, NULL, NULL, dev);
}
diff --git a/drivers/soc/samsung/exynos3250-pmu.c b/drivers/soc/samsung/exynos3250-pmu.c
index 30f230ed1769..4bad12a99542 100644
--- a/drivers/soc/samsung/exynos3250-pmu.c
+++ b/drivers/soc/samsung/exynos3250-pmu.c
@@ -5,6 +5,7 @@
//
// Exynos3250 - CPU PMU (Power Management Unit) support
+#include <linux/array_size.h>
#include <linux/soc/samsung/exynos-regs-pmu.h>
#include <linux/soc/samsung/exynos-pmu.h>
diff --git a/drivers/soc/samsung/exynos4-pmu.c b/drivers/soc/samsung/exynos4-pmu.c
index cb35103565a6..f8092190b938 100644
--- a/drivers/soc/samsung/exynos4-pmu.c
+++ b/drivers/soc/samsung/exynos4-pmu.c
@@ -86,7 +86,7 @@ static const struct exynos_pmu_conf exynos4210_pmu_config[] = {
{ PMU_TABLE_END,},
};
-static const struct exynos_pmu_conf exynos4412_pmu_config[] = {
+static const struct exynos_pmu_conf exynos4x12_pmu_config[] = {
{ S5P_ARM_CORE0_LOWPWR, { 0x0, 0x0, 0x2 } },
{ S5P_DIS_IRQ_CORE0, { 0x0, 0x0, 0x0 } },
{ S5P_DIS_IRQ_CENTRAL0, { 0x0, 0x0, 0x0 } },
@@ -191,6 +191,10 @@ static const struct exynos_pmu_conf exynos4412_pmu_config[] = {
{ S5P_GPS_ALIVE_LOWPWR, { 0x7, 0x0, 0x0 } },
{ S5P_CMU_SYSCLK_ISP_LOWPWR, { 0x1, 0x0, 0x0 } },
{ S5P_CMU_SYSCLK_GPS_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { PMU_TABLE_END,},
+};
+
+static const struct exynos_pmu_conf exynos4412_pmu_config[] = {
{ S5P_ARM_CORE2_LOWPWR, { 0x0, 0x0, 0x2 } },
{ S5P_DIS_IRQ_CORE2, { 0x0, 0x0, 0x0 } },
{ S5P_DIS_IRQ_CENTRAL2, { 0x0, 0x0, 0x0 } },
@@ -204,6 +208,11 @@ const struct exynos_pmu_data exynos4210_pmu_data = {
.pmu_config = exynos4210_pmu_config,
};
+const struct exynos_pmu_data exynos4212_pmu_data = {
+ .pmu_config = exynos4x12_pmu_config,
+};
+
const struct exynos_pmu_data exynos4412_pmu_data = {
- .pmu_config = exynos4412_pmu_config,
+ .pmu_config = exynos4x12_pmu_config,
+ .pmu_config_extra = exynos4412_pmu_config,
};
diff --git a/drivers/soc/samsung/exynos5250-pmu.c b/drivers/soc/samsung/exynos5250-pmu.c
index 7a2d50be6b4a..2ae5c3e1b07a 100644
--- a/drivers/soc/samsung/exynos5250-pmu.c
+++ b/drivers/soc/samsung/exynos5250-pmu.c
@@ -5,6 +5,7 @@
//
// Exynos5250 - CPU PMU (Power Management Unit) support
+#include <linux/array_size.h>
#include <linux/soc/samsung/exynos-regs-pmu.h>
#include <linux/soc/samsung/exynos-pmu.h>
diff --git a/drivers/soc/samsung/exynos5420-pmu.c b/drivers/soc/samsung/exynos5420-pmu.c
index 6fedcd78cb45..58a2209795f7 100644
--- a/drivers/soc/samsung/exynos5420-pmu.c
+++ b/drivers/soc/samsung/exynos5420-pmu.c
@@ -5,6 +5,7 @@
//
// Exynos5420 - CPU PMU (Power Management Unit) support
+#include <linux/array_size.h>
#include <linux/pm.h>
#include <linux/soc/samsung/exynos-regs-pmu.h>
#include <linux/soc/samsung/exynos-pmu.h>
diff --git a/drivers/soc/samsung/gs101-pmu.c b/drivers/soc/samsung/gs101-pmu.c
new file mode 100644
index 000000000000..17dadc1b9c6e
--- /dev/null
+++ b/drivers/soc/samsung/gs101-pmu.c
@@ -0,0 +1,446 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2025 Linaro Ltd.
+ *
+ * GS101 PMU (Power Management Unit) support
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/array_size.h>
+#include <linux/soc/samsung/exynos-pmu.h>
+#include <linux/soc/samsung/exynos-regs-pmu.h>
+#include <linux/regmap.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
+
+static const struct regmap_range gs101_pmu_registers[] = {
+ regmap_reg_range(GS101_OM_STAT, GS101_SYSTEM_INFO),
+ regmap_reg_range(GS101_IDLE_IP(0), GS101_IDLE_IP_MASK(3)),
+ regmap_reg_range(GS101_DATARAM_STATE_SLC_CH(0),
+ GS101_PPMPURAM_INFORM_SCL_CH(3)),
+ regmap_reg_range(GS101_INFORM0, GS101_SYSIP_DAT(0)),
+ /* skip SYSIP_DAT1 SYSIP_DAT2 */
+ regmap_reg_range(GS101_SYSIP_DAT(3), GS101_PWR_HOLD_SW_TRIP),
+ regmap_reg_range(GS101_GSA_INFORM(0), GS101_GSA_INFORM(1)),
+ regmap_reg_range(GS101_INFORM4, GS101_IROM_INFORM),
+ regmap_reg_range(GS101_IROM_CPU_INFORM(0), GS101_IROM_CPU_INFORM(7)),
+ regmap_reg_range(GS101_PMU_SPARE(0), GS101_PMU_SPARE(3)),
+ /* skip most IROM_xxx registers */
+ regmap_reg_range(GS101_DREX_CALIBRATION(0), GS101_DREX_CALIBRATION(7)),
+
+#define CLUSTER_CPU_RANGE(cl, cpu) \
+ regmap_reg_range(GS101_CLUSTER_CPU_CONFIGURATION(cl, cpu), \
+ GS101_CLUSTER_CPU_OPTION(cl, cpu)), \
+ regmap_reg_range(GS101_CLUSTER_CPU_OUT(cl, cpu), \
+ GS101_CLUSTER_CPU_IN(cl, cpu)), \
+ regmap_reg_range(GS101_CLUSTER_CPU_INT_IN(cl, cpu), \
+ GS101_CLUSTER_CPU_INT_DIR(cl, cpu))
+
+ /* cluster 0..2 and cpu 0..4 or 0..1 */
+ CLUSTER_CPU_RANGE(GS101_CLUSTER0_OFFSET, 0),
+ CLUSTER_CPU_RANGE(GS101_CLUSTER0_OFFSET, 1),
+ CLUSTER_CPU_RANGE(GS101_CLUSTER0_OFFSET, 2),
+ CLUSTER_CPU_RANGE(GS101_CLUSTER0_OFFSET, 3),
+ CLUSTER_CPU_RANGE(GS101_CLUSTER1_OFFSET, 0),
+ CLUSTER_CPU_RANGE(GS101_CLUSTER1_OFFSET, 1),
+ CLUSTER_CPU_RANGE(GS101_CLUSTER2_OFFSET, 0),
+ CLUSTER_CPU_RANGE(GS101_CLUSTER2_OFFSET, 1),
+#undef CLUSTER_CPU_RANGE
+
+#define CLUSTER_NONCPU_RANGE(cl) \
+ regmap_reg_range(GS101_CLUSTER_NONCPU_CONFIGURATION(cl), \
+ GS101_CLUSTER_NONCPU_OPTION(cl)), \
+ regmap_reg_range(GS101_CLUSTER_NONCPU_OUT(cl), \
+ GS101_CLUSTER_NONCPU_IN(cl)), \
+ regmap_reg_range(GS101_CLUSTER_NONCPU_INT_IN(cl), \
+ GS101_CLUSTER_NONCPU_INT_DIR(cl)), \
+ regmap_reg_range(GS101_CLUSTER_NONCPU_DUALRAIL_CTRL_OUT(cl), \
+ GS101_CLUSTER_NONCPU_DUALRAIL_POS_OUT(cl)), \
+ regmap_reg_range(GS101_CLUSTER_NONCPU_DUALRAIL_CTRL_IN(cl), \
+ GS101_CLUSTER_NONCPU_DUALRAIL_CTRL_IN(cl))
+
+ CLUSTER_NONCPU_RANGE(0),
+ regmap_reg_range(GS101_CLUSTER0_NONCPU_DSU_PCH,
+ GS101_CLUSTER0_NONCPU_DSU_PCH),
+ CLUSTER_NONCPU_RANGE(1),
+ CLUSTER_NONCPU_RANGE(2),
+#undef CLUSTER_NONCPU_RANGE
+
+#define SUBBLK_RANGE(blk) \
+ regmap_reg_range(GS101_SUBBLK_CONFIGURATION(blk), \
+ GS101_SUBBLK_CTRL(blk)), \
+ regmap_reg_range(GS101_SUBBLK_OUT(blk), GS101_SUBBLK_IN(blk)), \
+ regmap_reg_range(GS101_SUBBLK_INT_IN(blk), \
+ GS101_SUBBLK_INT_DIR(blk)), \
+ regmap_reg_range(GS101_SUBBLK_MEMORY_OUT(blk), \
+ GS101_SUBBLK_MEMORY_IN(blk))
+
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_ALIVE),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_AOC),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_APM),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CMU),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_BUS0),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_BUS1),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_BUS2),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CORE),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_EH),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CPUCL0),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CPUCL1),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CPUCL2),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_G3D),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_EMBEDDED_CPUCL0),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_EMBEDDED_G3D),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_HSI0),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_HSI1),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_HSI2),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_DPU),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_DISP),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_G2D),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MFC),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CSIS),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_PDP),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_DNS),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_G3AA),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_IPP),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_ITP),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MCSC),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_GDC),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_TNR),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_BO),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_TPU),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MIF0),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MIF1),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MIF2),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MIF3),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MISC),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_PERIC0),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_PERIC1),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_S2D),
+#undef SUBBLK_RANGE
+
+#define SUBBLK_CPU_RANGE(blk) \
+ regmap_reg_range(GS101_SUBBLK_CPU_CONFIGURATION(blk), \
+ GS101_SUBBLK_CPU_OPTION(blk)), \
+ regmap_reg_range(GS101_SUBBLK_CPU_OUT(blk), \
+ GS101_SUBBLK_CPU_IN(blk)), \
+ regmap_reg_range(GS101_SUBBLK_CPU_INT_IN(blk), \
+ GS101_SUBBLK_CPU_INT_DIR(blk))
+
+ SUBBLK_CPU_RANGE(GS101_SUBBBLK_CPU_OFFSET_APM),
+ SUBBLK_CPU_RANGE(GS101_SUBBBLK_CPU_OFFSET_DBGCORE),
+ SUBBLK_CPU_RANGE(GS101_SUBBBLK_CPU_OFFSET_SSS),
+#undef SUBBLK_CPU_RANGE
+
+ regmap_reg_range(GS101_MIF_CONFIGURATION, GS101_MIF_CTRL),
+ regmap_reg_range(GS101_MIF_OUT, GS101_MIF_IN),
+ regmap_reg_range(GS101_MIF_INT_IN, GS101_MIF_INT_DIR),
+ regmap_reg_range(GS101_TOP_CONFIGURATION, GS101_TOP_OPTION),
+ regmap_reg_range(GS101_TOP_OUT, GS101_TOP_IN),
+ regmap_reg_range(GS101_TOP_INT_IN, GS101_WAKEUP2_STAT),
+ regmap_reg_range(GS101_WAKEUP2_INT_IN, GS101_WAKEUP2_INT_DIR),
+ regmap_reg_range(GS101_SYSTEM_CONFIGURATION, GS101_USER_DEFINED_OUT),
+ regmap_reg_range(GS101_SYSTEM_OUT, GS101_SYSTEM_IN),
+ regmap_reg_range(GS101_SYSTEM_INT_IN, GS101_EINT_WAKEUP_MASK3),
+ regmap_reg_range(GS101_USER_DEFINED_INT_IN, GS101_SCAN2DRAM_INT_DIR),
+ /* skip HCU_START */
+ regmap_reg_range(GS101_CUSTOM_OUT, GS101_CUSTOM_IN),
+ regmap_reg_range(GS101_CUSTOM_INT_IN, GS101_CUSTOM_INT_DIR),
+ regmap_reg_range(GS101_ACK_LAST_CPU, GS101_HCU_R(3)),
+ regmap_reg_range(GS101_HCU_SP, GS101_HCU_PC),
+ /* skip PMU_RAM_CTRL */
+ regmap_reg_range(GS101_APM_HCU_CTRL, GS101_APM_HCU_CTRL),
+ regmap_reg_range(GS101_APM_NMI_ENABLE, GS101_RST_STAT_PMU),
+ regmap_reg_range(GS101_HPM_INT_IN, GS101_BOOT_STAT),
+ regmap_reg_range(GS101_PMLINK_OUT, GS101_PMLINK_AOC_CTRL),
+ regmap_reg_range(GS101_TCXO_BUF_CTRL, GS101_ADD_CTRL),
+ regmap_reg_range(GS101_HCU_TIMEOUT_RESET, GS101_HCU_TIMEOUT_SCAN2DRAM),
+ regmap_reg_range(GS101_TIMER(0), GS101_TIMER(3)),
+ regmap_reg_range(GS101_PPC_MIF(0), GS101_PPC_EH),
+ /* PPC_OFFSET, skip PPC_CPUCL1_0 PPC_CPUCL1_1 */
+ regmap_reg_range(GS101_EXT_REGULATOR_MIF_DURATION, GS101_TCXO_DURATION),
+ regmap_reg_range(GS101_BURNIN_CTRL, GS101_TMU_SUB_TRIP),
+ regmap_reg_range(GS101_MEMORY_CEN, GS101_MEMORY_SMX_FEEDBACK),
+ regmap_reg_range(GS101_SLC_PCH_CHANNEL, GS101_SLC_PCH_CB),
+ regmap_reg_range(GS101_FORCE_NOMC, GS101_FORCE_NOMC),
+ regmap_reg_range(GS101_FORCE_BOOST, GS101_PMLINK_SLC_BUSY),
+ regmap_reg_range(GS101_BOOTSYNC_OUT, GS101_CTRL_SECJTAG_ALIVE),
+ regmap_reg_range(GS101_CTRL_DIV_PLL_ALV_DIVLOW, GS101_CTRL_CLKDIV__CLKRTC),
+ regmap_reg_range(GS101_CTRL_SOC32K, GS101_CTRL_SBU_SW_EN),
+ regmap_reg_range(GS101_PAD_CTRL_CLKOUT0, GS101_PAD_CTRL_WRESETO_n),
+ regmap_reg_range(GS101_PHY_CTRL_USB20, GS101_PHY_CTRL_UFS),
+};
+
+static const struct regmap_range gs101_pmu_ro_registers[] = {
+ regmap_reg_range(GS101_OM_STAT, GS101_VERSION),
+ regmap_reg_range(GS101_OTP_STATUS, GS101_OTP_STATUS),
+
+ regmap_reg_range(GS101_DATARAM_STATE_SLC_CH(0),
+ GS101_PPMPURAM_STATE_SLC_CH(0)),
+ regmap_reg_range(GS101_DATARAM_STATE_SLC_CH(1),
+ GS101_PPMPURAM_STATE_SLC_CH(1)),
+ regmap_reg_range(GS101_DATARAM_STATE_SLC_CH(2),
+ GS101_PPMPURAM_STATE_SLC_CH(2)),
+ regmap_reg_range(GS101_DATARAM_STATE_SLC_CH(3),
+ GS101_PPMPURAM_STATE_SLC_CH(3)),
+
+#define CLUSTER_CPU_RANGE(cl, cpu) \
+ regmap_reg_range(GS101_CLUSTER_CPU_IN(cl, cpu), \
+ GS101_CLUSTER_CPU_IN(cl, cpu)), \
+ regmap_reg_range(GS101_CLUSTER_CPU_INT_IN(cl, cpu), \
+ GS101_CLUSTER_CPU_INT_IN(cl, cpu))
+
+ CLUSTER_CPU_RANGE(GS101_CLUSTER0_OFFSET, 0),
+ CLUSTER_CPU_RANGE(GS101_CLUSTER0_OFFSET, 1),
+ CLUSTER_CPU_RANGE(GS101_CLUSTER0_OFFSET, 2),
+ CLUSTER_CPU_RANGE(GS101_CLUSTER0_OFFSET, 3),
+ CLUSTER_CPU_RANGE(GS101_CLUSTER1_OFFSET, 0),
+ CLUSTER_CPU_RANGE(GS101_CLUSTER1_OFFSET, 1),
+ CLUSTER_CPU_RANGE(GS101_CLUSTER2_OFFSET, 0),
+ CLUSTER_CPU_RANGE(GS101_CLUSTER2_OFFSET, 1),
+#undef CLUSTER_CPU_RANGE
+
+#define CLUSTER_NONCPU_RANGE(cl) \
+ regmap_reg_range(GS101_CLUSTER_NONCPU_IN(cl), \
+ GS101_CLUSTER_NONCPU_IN(cl)), \
+ regmap_reg_range(GS101_CLUSTER_NONCPU_INT_IN(cl), \
+ GS101_CLUSTER_NONCPU_INT_IN(cl)), \
+ regmap_reg_range(GS101_CLUSTER_NONCPU_DUALRAIL_CTRL_IN(cl), \
+ GS101_CLUSTER_NONCPU_DUALRAIL_CTRL_IN(cl))
+
+ CLUSTER_NONCPU_RANGE(0),
+ CLUSTER_NONCPU_RANGE(1),
+ CLUSTER_NONCPU_RANGE(2),
+ regmap_reg_range(GS101_CLUSTER_NONCPU_INT_EN(2),
+ GS101_CLUSTER_NONCPU_INT_DIR(2)),
+#undef CLUSTER_NONCPU_RANGE
+
+#define SUBBLK_RANGE(blk) \
+ regmap_reg_range(GS101_SUBBLK_IN(blk), GS101_SUBBLK_IN(blk)), \
+ regmap_reg_range(GS101_SUBBLK_INT_IN(blk), \
+ GS101_SUBBLK_INT_IN(blk)), \
+ regmap_reg_range(GS101_SUBBLK_MEMORY_IN(blk), \
+ GS101_SUBBLK_MEMORY_IN(blk))
+
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_ALIVE),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_AOC),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_APM),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CMU),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_BUS0),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_BUS1),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_BUS2),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CORE),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_EH),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CPUCL0),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CPUCL1),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CPUCL2),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_G3D),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_EMBEDDED_CPUCL0),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_EMBEDDED_G3D),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_HSI0),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_HSI1),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_HSI2),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_DPU),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_DISP),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_G2D),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MFC),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_CSIS),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_PDP),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_DNS),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_G3AA),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_IPP),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_ITP),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MCSC),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_GDC),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_TNR),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_BO),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_TPU),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MIF0),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MIF1),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MIF2),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MIF3),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_MISC),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_PERIC0),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_PERIC1),
+ SUBBLK_RANGE(GS101_SUBBBLK_OFFSET_S2D),
+#undef SUBBLK_RANGE
+
+#define SUBBLK_CPU_RANGE(blk) \
+ regmap_reg_range(GS101_SUBBLK_CPU_IN(blk), \
+ GS101_SUBBLK_CPU_IN(blk)), \
+ regmap_reg_range(GS101_SUBBLK_CPU_INT_IN(blk), \
+ GS101_SUBBLK_CPU_INT_IN(blk))
+
+ SUBBLK_CPU_RANGE(GS101_SUBBBLK_CPU_OFFSET_APM),
+ SUBBLK_CPU_RANGE(GS101_SUBBBLK_CPU_OFFSET_DBGCORE),
+ SUBBLK_CPU_RANGE(GS101_SUBBBLK_CPU_OFFSET_SSS),
+#undef SUBBLK_CPU_RANGE
+
+ regmap_reg_range(GS101_MIF_CONFIGURATION, GS101_MIF_CONFIGURATION),
+ regmap_reg_range(GS101_MIF_IN, GS101_MIF_IN),
+ regmap_reg_range(GS101_MIF_INT_IN, GS101_MIF_INT_IN),
+ regmap_reg_range(GS101_TOP_IN, GS101_TOP_IN),
+ regmap_reg_range(GS101_TOP_INT_IN, GS101_TOP_INT_IN),
+ regmap_reg_range(GS101_WAKEUP2_INT_IN, GS101_WAKEUP2_INT_IN),
+ regmap_reg_range(GS101_SYSTEM_IN, GS101_SYSTEM_IN),
+ regmap_reg_range(GS101_SYSTEM_INT_IN, GS101_SYSTEM_INT_IN),
+ regmap_reg_range(GS101_EINT_INT_IN, GS101_EINT_INT_IN),
+ regmap_reg_range(GS101_EINT2_INT_IN, GS101_EINT2_INT_IN),
+ regmap_reg_range(GS101_EINT3_INT_IN, GS101_EINT3_INT_IN),
+ regmap_reg_range(GS101_USER_DEFINED_INT_IN, GS101_USER_DEFINED_INT_IN),
+ regmap_reg_range(GS101_SCAN2DRAM_INT_IN, GS101_SCAN2DRAM_INT_IN),
+ regmap_reg_range(GS101_CUSTOM_IN, GS101_CUSTOM_IN),
+ regmap_reg_range(GS101_CUSTOM_INT_IN, GS101_CUSTOM_INT_IN),
+ regmap_reg_range(GS101_HCU_R(0), GS101_HCU_R(3)),
+ regmap_reg_range(GS101_HCU_SP, GS101_HCU_PC),
+ regmap_reg_range(GS101_NMI_SRC_IN, GS101_NMI_SRC_IN),
+ regmap_reg_range(GS101_HPM_INT_IN, GS101_HPM_INT_IN),
+ regmap_reg_range(GS101_MEMORY_PGEN_FEEDBACK, GS101_MEMORY_PGEN_FEEDBACK),
+ regmap_reg_range(GS101_MEMORY_SMX_FEEDBACK, GS101_MEMORY_SMX_FEEDBACK),
+ regmap_reg_range(GS101_PMLINK_SLC_ACK, GS101_PMLINK_SLC_BUSY),
+ regmap_reg_range(GS101_BOOTSYNC_IN, GS101_BOOTSYNC_IN),
+ regmap_reg_range(GS101_SCAN_READY_IN, GS101_SCAN_READY_IN),
+ regmap_reg_range(GS101_CTRL_PLL_ALV_LOCK, GS101_CTRL_PLL_ALV_LOCK),
+};
+
+static const struct regmap_access_table gs101_pmu_rd_table = {
+ .yes_ranges = gs101_pmu_registers,
+ .n_yes_ranges = ARRAY_SIZE(gs101_pmu_registers),
+};
+
+static const struct regmap_access_table gs101_pmu_wr_table = {
+ .yes_ranges = gs101_pmu_registers,
+ .n_yes_ranges = ARRAY_SIZE(gs101_pmu_registers),
+ .no_ranges = gs101_pmu_ro_registers,
+ .n_no_ranges = ARRAY_SIZE(gs101_pmu_ro_registers),
+};
+
+const struct exynos_pmu_data gs101_pmu_data = {
+ .pmu_secure = true,
+ .pmu_cpuhp = true,
+ .rd_table = &gs101_pmu_rd_table,
+ .wr_table = &gs101_pmu_wr_table,
+};
+
+/*
+ * 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. */
+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.
+ */
+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 *context, 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(context, 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_DAT(0):
+ case GS101_SYSTEM_CONFIGURATION:
+ return false;
+ default:
+ return true;
+ }
+}
+
+int tensor_sec_update_bits(void *context, unsigned int reg, unsigned int mask,
+ unsigned int val)
+{
+ if (!tensor_is_atomic(reg))
+ return tensor_sec_reg_rmw(context, reg, mask, val);
+
+ return tensor_set_bits_atomic(context, reg, val, mask);
+}
diff --git a/drivers/soc/samsung/pm_domains.c b/drivers/soc/samsung/pm_domains.c
deleted file mode 100644
index d07f3c9d6903..000000000000
--- a/drivers/soc/samsung/pm_domains.c
+++ /dev/null
@@ -1,166 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// Exynos Generic power domain support.
-//
-// Copyright (c) 2012 Samsung Electronics Co., Ltd.
-// http://www.samsung.com
-//
-// Implementation of Exynos specific power domain control which is used in
-// conjunction with runtime-pm. Support for both device-tree and non-device-tree
-// based power domain support is included.
-
-#include <linux/io.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/pm_domain.h>
-#include <linux/delay.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <linux/pm_runtime.h>
-
-struct exynos_pm_domain_config {
- /* Value for LOCAL_PWR_CFG and STATUS fields for each domain */
- u32 local_pwr_cfg;
-};
-
-/*
- * Exynos specific wrapper around the generic power domain
- */
-struct exynos_pm_domain {
- void __iomem *base;
- struct generic_pm_domain pd;
- u32 local_pwr_cfg;
-};
-
-static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
-{
- struct exynos_pm_domain *pd;
- void __iomem *base;
- u32 timeout, pwr;
- char *op;
-
- pd = container_of(domain, struct exynos_pm_domain, pd);
- base = pd->base;
-
- pwr = power_on ? pd->local_pwr_cfg : 0;
- writel_relaxed(pwr, base);
-
- /* Wait max 1ms */
- timeout = 10;
-
- while ((readl_relaxed(base + 0x4) & pd->local_pwr_cfg) != pwr) {
- if (!timeout) {
- op = (power_on) ? "enable" : "disable";
- pr_err("Power domain %s %s failed\n", domain->name, op);
- return -ETIMEDOUT;
- }
- timeout--;
- cpu_relax();
- usleep_range(80, 100);
- }
-
- return 0;
-}
-
-static int exynos_pd_power_on(struct generic_pm_domain *domain)
-{
- return exynos_pd_power(domain, true);
-}
-
-static int exynos_pd_power_off(struct generic_pm_domain *domain)
-{
- return exynos_pd_power(domain, false);
-}
-
-static const struct exynos_pm_domain_config exynos4210_cfg = {
- .local_pwr_cfg = 0x7,
-};
-
-static const struct exynos_pm_domain_config exynos5433_cfg = {
- .local_pwr_cfg = 0xf,
-};
-
-static const struct of_device_id exynos_pm_domain_of_match[] = {
- {
- .compatible = "samsung,exynos4210-pd",
- .data = &exynos4210_cfg,
- }, {
- .compatible = "samsung,exynos5433-pd",
- .data = &exynos5433_cfg,
- },
- { },
-};
-
-static const char *exynos_get_domain_name(struct device_node *node)
-{
- const char *name;
-
- if (of_property_read_string(node, "label", &name) < 0)
- name = kbasename(node->full_name);
- return kstrdup_const(name, GFP_KERNEL);
-}
-
-static int exynos_pd_probe(struct platform_device *pdev)
-{
- const struct exynos_pm_domain_config *pm_domain_cfg;
- struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
- struct of_phandle_args child, parent;
- struct exynos_pm_domain *pd;
- int on, ret;
-
- pm_domain_cfg = of_device_get_match_data(dev);
- pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
- if (!pd)
- return -ENOMEM;
-
- pd->pd.name = exynos_get_domain_name(np);
- if (!pd->pd.name)
- return -ENOMEM;
-
- pd->base = of_iomap(np, 0);
- if (!pd->base) {
- kfree_const(pd->pd.name);
- return -ENODEV;
- }
-
- pd->pd.power_off = exynos_pd_power_off;
- pd->pd.power_on = exynos_pd_power_on;
- pd->local_pwr_cfg = pm_domain_cfg->local_pwr_cfg;
-
- on = readl_relaxed(pd->base + 0x4) & pd->local_pwr_cfg;
-
- pm_genpd_init(&pd->pd, NULL, !on);
- ret = of_genpd_add_provider_simple(np, &pd->pd);
-
- if (ret == 0 && of_parse_phandle_with_args(np, "power-domains",
- "#power-domain-cells", 0, &parent) == 0) {
- child.np = np;
- child.args_count = 0;
-
- if (of_genpd_add_subdomain(&parent, &child))
- pr_warn("%pOF failed to add subdomain: %pOF\n",
- parent.np, child.np);
- else
- pr_info("%pOF has as child subdomain: %pOF.\n",
- parent.np, child.np);
- }
-
- pm_runtime_enable(dev);
- return ret;
-}
-
-static struct platform_driver exynos_pd_driver = {
- .probe = exynos_pd_probe,
- .driver = {
- .name = "exynos-pd",
- .of_match_table = exynos_pm_domain_of_match,
- .suppress_bind_attrs = true,
- }
-};
-
-static __init int exynos4_pm_init_power_domain(void)
-{
- return platform_driver_register(&exynos_pd_driver);
-}
-core_initcall(exynos4_pm_init_power_domain);
diff --git a/drivers/soc/samsung/s3c-pm-debug.c b/drivers/soc/samsung/s3c-pm-debug.c
deleted file mode 100644
index b5ce0e9a41e5..000000000000
--- a/drivers/soc/samsung/s3c-pm-debug.c
+++ /dev/null
@@ -1,79 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// Copyright (C) 2013 Samsung Electronics Co., Ltd.
-// Tomasz Figa <t.figa@samsung.com>
-// Copyright (C) 2008 Openmoko, Inc.
-// Copyright (C) 2004-2008 Simtec Electronics
-// Ben Dooks <ben@simtec.co.uk>
-// http://armlinux.simtec.co.uk/
-//
-// Samsung common power management (suspend to RAM) debug support
-
-#include <linux/serial_core.h>
-#include <linux/serial_s3c.h>
-#include <linux/io.h>
-
-#include <asm/mach/map.h>
-
-#include <linux/soc/samsung/s3c-pm.h>
-
-static struct pm_uart_save uart_save;
-
-extern void printascii(const char *);
-
-void s3c_pm_dbg(const char *fmt, ...)
-{
- va_list va;
- char buff[256];
-
- va_start(va, fmt);
- vsnprintf(buff, sizeof(buff), fmt, va);
- va_end(va);
-
- printascii(buff);
-}
-
-static inline void __iomem *s3c_pm_uart_base(void)
-{
- unsigned long paddr;
- unsigned long vaddr;
-
- debug_ll_addr(&paddr, &vaddr);
-
- return (void __iomem *)vaddr;
-}
-
-void s3c_pm_save_uarts(bool is_s3c2410)
-{
- void __iomem *regs = s3c_pm_uart_base();
- struct pm_uart_save *save = &uart_save;
-
- save->ulcon = __raw_readl(regs + S3C2410_ULCON);
- save->ucon = __raw_readl(regs + S3C2410_UCON);
- save->ufcon = __raw_readl(regs + S3C2410_UFCON);
- save->umcon = __raw_readl(regs + S3C2410_UMCON);
- save->ubrdiv = __raw_readl(regs + S3C2410_UBRDIV);
-
- if (!is_s3c2410)
- save->udivslot = __raw_readl(regs + S3C2443_DIVSLOT);
-
- S3C_PMDBG("UART[%p]: ULCON=%04x, UCON=%04x, UFCON=%04x, UBRDIV=%04x\n",
- regs, save->ulcon, save->ucon, save->ufcon, save->ubrdiv);
-}
-
-void s3c_pm_restore_uarts(bool is_s3c2410)
-{
- void __iomem *regs = s3c_pm_uart_base();
- struct pm_uart_save *save = &uart_save;
-
- s3c_pm_arch_update_uart(regs, save);
-
- __raw_writel(save->ulcon, regs + S3C2410_ULCON);
- __raw_writel(save->ucon, regs + S3C2410_UCON);
- __raw_writel(save->ufcon, regs + S3C2410_UFCON);
- __raw_writel(save->umcon, regs + S3C2410_UMCON);
- __raw_writel(save->ubrdiv, regs + S3C2410_UBRDIV);
-
- if (!is_s3c2410)
- __raw_writel(save->udivslot, regs + S3C2443_DIVSLOT);
-}
diff --git a/drivers/soc/sifive/Kconfig b/drivers/soc/sifive/Kconfig
deleted file mode 100644
index ed4c571f8771..000000000000
--- a/drivers/soc/sifive/Kconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-if SOC_SIFIVE
-
-config SIFIVE_CCACHE
- bool "Sifive Composable Cache controller"
- help
- Support for the composable cache controller on SiFive platforms.
-
-endif
diff --git a/drivers/soc/sifive/Makefile b/drivers/soc/sifive/Makefile
deleted file mode 100644
index 1f5dc339bf82..000000000000
--- a/drivers/soc/sifive/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-obj-$(CONFIG_SIFIVE_CCACHE) += sifive_ccache.o
diff --git a/drivers/soc/sifive/sifive_ccache.c b/drivers/soc/sifive/sifive_ccache.c
deleted file mode 100644
index 3684f5b40a80..000000000000
--- a/drivers/soc/sifive/sifive_ccache.c
+++ /dev/null
@@ -1,272 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * SiFive composable cache controller Driver
- *
- * Copyright (C) 2018-2022 SiFive, Inc.
- *
- */
-
-#define pr_fmt(fmt) "CCACHE: " fmt
-
-#include <linux/debugfs.h>
-#include <linux/interrupt.h>
-#include <linux/of_irq.h>
-#include <linux/of_address.h>
-#include <linux/device.h>
-#include <linux/bitfield.h>
-#include <asm/cacheinfo.h>
-#include <soc/sifive/sifive_ccache.h>
-
-#define SIFIVE_CCACHE_DIRECCFIX_LOW 0x100
-#define SIFIVE_CCACHE_DIRECCFIX_HIGH 0x104
-#define SIFIVE_CCACHE_DIRECCFIX_COUNT 0x108
-
-#define SIFIVE_CCACHE_DIRECCFAIL_LOW 0x120
-#define SIFIVE_CCACHE_DIRECCFAIL_HIGH 0x124
-#define SIFIVE_CCACHE_DIRECCFAIL_COUNT 0x128
-
-#define SIFIVE_CCACHE_DATECCFIX_LOW 0x140
-#define SIFIVE_CCACHE_DATECCFIX_HIGH 0x144
-#define SIFIVE_CCACHE_DATECCFIX_COUNT 0x148
-
-#define SIFIVE_CCACHE_DATECCFAIL_LOW 0x160
-#define SIFIVE_CCACHE_DATECCFAIL_HIGH 0x164
-#define SIFIVE_CCACHE_DATECCFAIL_COUNT 0x168
-
-#define SIFIVE_CCACHE_CONFIG 0x00
-#define SIFIVE_CCACHE_CONFIG_BANK_MASK GENMASK_ULL(7, 0)
-#define SIFIVE_CCACHE_CONFIG_WAYS_MASK GENMASK_ULL(15, 8)
-#define SIFIVE_CCACHE_CONFIG_SETS_MASK GENMASK_ULL(23, 16)
-#define SIFIVE_CCACHE_CONFIG_BLKS_MASK GENMASK_ULL(31, 24)
-
-#define SIFIVE_CCACHE_WAYENABLE 0x08
-#define SIFIVE_CCACHE_ECCINJECTERR 0x40
-
-#define SIFIVE_CCACHE_MAX_ECCINTR 4
-
-static void __iomem *ccache_base;
-static int g_irq[SIFIVE_CCACHE_MAX_ECCINTR];
-static struct riscv_cacheinfo_ops ccache_cache_ops;
-static int level;
-
-enum {
- DIR_CORR = 0,
- DATA_CORR,
- DATA_UNCORR,
- DIR_UNCORR,
-};
-
-#ifdef CONFIG_DEBUG_FS
-static struct dentry *sifive_test;
-
-static ssize_t ccache_write(struct file *file, const char __user *data,
- size_t count, loff_t *ppos)
-{
- unsigned int val;
-
- if (kstrtouint_from_user(data, count, 0, &val))
- return -EINVAL;
- if ((val < 0xFF) || (val >= 0x10000 && val < 0x100FF))
- writel(val, ccache_base + SIFIVE_CCACHE_ECCINJECTERR);
- else
- return -EINVAL;
- return count;
-}
-
-static const struct file_operations ccache_fops = {
- .owner = THIS_MODULE,
- .open = simple_open,
- .write = ccache_write
-};
-
-static void setup_sifive_debug(void)
-{
- sifive_test = debugfs_create_dir("sifive_ccache_cache", NULL);
-
- debugfs_create_file("sifive_debug_inject_error", 0200,
- sifive_test, NULL, &ccache_fops);
-}
-#endif
-
-static void ccache_config_read(void)
-{
- u32 cfg;
-
- cfg = readl(ccache_base + SIFIVE_CCACHE_CONFIG);
- pr_info("%llu banks, %llu ways, sets/bank=%llu, bytes/block=%llu\n",
- FIELD_GET(SIFIVE_CCACHE_CONFIG_BANK_MASK, cfg),
- FIELD_GET(SIFIVE_CCACHE_CONFIG_WAYS_MASK, cfg),
- BIT_ULL(FIELD_GET(SIFIVE_CCACHE_CONFIG_SETS_MASK, cfg)),
- BIT_ULL(FIELD_GET(SIFIVE_CCACHE_CONFIG_BLKS_MASK, cfg)));
-
- cfg = readl(ccache_base + SIFIVE_CCACHE_WAYENABLE);
- pr_info("Index of the largest way enabled: %u\n", cfg);
-}
-
-static const struct of_device_id sifive_ccache_ids[] = {
- { .compatible = "sifive,fu540-c000-ccache" },
- { .compatible = "sifive,fu740-c000-ccache" },
- { .compatible = "sifive,ccache0" },
- { /* end of table */ }
-};
-
-static ATOMIC_NOTIFIER_HEAD(ccache_err_chain);
-
-int register_sifive_ccache_error_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_register(&ccache_err_chain, nb);
-}
-EXPORT_SYMBOL_GPL(register_sifive_ccache_error_notifier);
-
-int unregister_sifive_ccache_error_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_unregister(&ccache_err_chain, nb);
-}
-EXPORT_SYMBOL_GPL(unregister_sifive_ccache_error_notifier);
-
-static int ccache_largest_wayenabled(void)
-{
- return readl(ccache_base + SIFIVE_CCACHE_WAYENABLE) & 0xFF;
-}
-
-static ssize_t number_of_ways_enabled_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%u\n", ccache_largest_wayenabled());
-}
-
-static DEVICE_ATTR_RO(number_of_ways_enabled);
-
-static struct attribute *priv_attrs[] = {
- &dev_attr_number_of_ways_enabled.attr,
- NULL,
-};
-
-static const struct attribute_group priv_attr_group = {
- .attrs = priv_attrs,
-};
-
-static const struct attribute_group *ccache_get_priv_group(struct cacheinfo
- *this_leaf)
-{
- /* We want to use private group for composable cache only */
- if (this_leaf->level == level)
- return &priv_attr_group;
- else
- return NULL;
-}
-
-static irqreturn_t ccache_int_handler(int irq, void *device)
-{
- unsigned int add_h, add_l;
-
- if (irq == g_irq[DIR_CORR]) {
- add_h = readl(ccache_base + SIFIVE_CCACHE_DIRECCFIX_HIGH);
- add_l = readl(ccache_base + SIFIVE_CCACHE_DIRECCFIX_LOW);
- pr_err("DirError @ 0x%08X.%08X\n", add_h, add_l);
- /* Reading this register clears the DirError interrupt sig */
- readl(ccache_base + SIFIVE_CCACHE_DIRECCFIX_COUNT);
- atomic_notifier_call_chain(&ccache_err_chain,
- SIFIVE_CCACHE_ERR_TYPE_CE,
- "DirECCFix");
- }
- if (irq == g_irq[DIR_UNCORR]) {
- add_h = readl(ccache_base + SIFIVE_CCACHE_DIRECCFAIL_HIGH);
- add_l = readl(ccache_base + SIFIVE_CCACHE_DIRECCFAIL_LOW);
- /* Reading this register clears the DirFail interrupt sig */
- readl(ccache_base + SIFIVE_CCACHE_DIRECCFAIL_COUNT);
- atomic_notifier_call_chain(&ccache_err_chain,
- SIFIVE_CCACHE_ERR_TYPE_UE,
- "DirECCFail");
- panic("CCACHE: DirFail @ 0x%08X.%08X\n", add_h, add_l);
- }
- if (irq == g_irq[DATA_CORR]) {
- add_h = readl(ccache_base + SIFIVE_CCACHE_DATECCFIX_HIGH);
- add_l = readl(ccache_base + SIFIVE_CCACHE_DATECCFIX_LOW);
- pr_err("DataError @ 0x%08X.%08X\n", add_h, add_l);
- /* Reading this register clears the DataError interrupt sig */
- readl(ccache_base + SIFIVE_CCACHE_DATECCFIX_COUNT);
- atomic_notifier_call_chain(&ccache_err_chain,
- SIFIVE_CCACHE_ERR_TYPE_CE,
- "DatECCFix");
- }
- if (irq == g_irq[DATA_UNCORR]) {
- add_h = readl(ccache_base + SIFIVE_CCACHE_DATECCFAIL_HIGH);
- add_l = readl(ccache_base + SIFIVE_CCACHE_DATECCFAIL_LOW);
- pr_err("DataFail @ 0x%08X.%08X\n", add_h, add_l);
- /* Reading this register clears the DataFail interrupt sig */
- readl(ccache_base + SIFIVE_CCACHE_DATECCFAIL_COUNT);
- atomic_notifier_call_chain(&ccache_err_chain,
- SIFIVE_CCACHE_ERR_TYPE_UE,
- "DatECCFail");
- }
-
- return IRQ_HANDLED;
-}
-
-static int __init sifive_ccache_init(void)
-{
- struct device_node *np;
- struct resource res;
- int i, rc, intr_num;
-
- np = of_find_matching_node(NULL, sifive_ccache_ids);
- if (!np)
- return -ENODEV;
-
- if (of_address_to_resource(np, 0, &res)) {
- rc = -ENODEV;
- goto err_node_put;
- }
-
- ccache_base = ioremap(res.start, resource_size(&res));
- if (!ccache_base) {
- rc = -ENOMEM;
- goto err_node_put;
- }
-
- if (of_property_read_u32(np, "cache-level", &level)) {
- rc = -ENOENT;
- goto err_unmap;
- }
-
- intr_num = of_property_count_u32_elems(np, "interrupts");
- if (!intr_num) {
- pr_err("No interrupts property\n");
- rc = -ENODEV;
- goto err_unmap;
- }
-
- for (i = 0; i < intr_num; i++) {
- g_irq[i] = irq_of_parse_and_map(np, i);
- rc = request_irq(g_irq[i], ccache_int_handler, 0, "ccache_ecc",
- NULL);
- if (rc) {
- pr_err("Could not request IRQ %d\n", g_irq[i]);
- goto err_free_irq;
- }
- }
- of_node_put(np);
-
- ccache_config_read();
-
- ccache_cache_ops.get_priv_group = ccache_get_priv_group;
- riscv_set_cacheinfo_ops(&ccache_cache_ops);
-
-#ifdef CONFIG_DEBUG_FS
- setup_sifive_debug();
-#endif
- return 0;
-
-err_free_irq:
- while (--i >= 0)
- free_irq(g_irq[i], NULL);
-err_unmap:
- iounmap(ccache_base);
-err_node_put:
- of_node_put(np);
- return rc;
-}
-
-device_initcall(sifive_ccache_init);
diff --git a/drivers/soc/sophgo/Kconfig b/drivers/soc/sophgo/Kconfig
new file mode 100644
index 000000000000..45f78b270c91
--- /dev/null
+++ b/drivers/soc/sophgo/Kconfig
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Sophgo SoC drivers
+#
+
+if ARCH_SOPHGO || COMPILE_TEST
+menu "Sophgo SoC drivers"
+
+config SOPHGO_CV1800_RTCSYS
+ tristate "Sophgo CV1800 RTC MFD"
+ select MFD_CORE
+ help
+ If you say yes here you get support the RTC MFD driver for Sophgo
+ CV1800 series SoC. The RTC module comprises a 32kHz oscillator,
+ Power-on-Reset (PoR) sub-module, HW state machine to control chip
+ power-on, power-off and reset. Furthermore, the 8051 subsystem is
+ located within RTCSYS including associated SRAM block.
+
+ This driver can also be built as a module. If so, the module will be
+ called cv1800-rtcsys.
+
+config SOPHGO_SG2044_TOPSYS
+ tristate "Sophgo SG2044 TOP syscon driver"
+ select MFD_CORE
+ help
+ This is the core driver for the Sophgo SG2044 TOP system
+ controller device. This driver provide PLL clock device
+ for the SoC.
+
+ This driver can also be built as a module. If so, the module
+ will be called sg2044-topsys.
+
+endmenu
+endif
diff --git a/drivers/soc/sophgo/Makefile b/drivers/soc/sophgo/Makefile
new file mode 100644
index 000000000000..27f68df22c4d
--- /dev/null
+++ b/drivers/soc/sophgo/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_SOPHGO_CV1800_RTCSYS) += cv1800-rtcsys.o
+obj-$(CONFIG_SOPHGO_SG2044_TOPSYS) += sg2044-topsys.o
diff --git a/drivers/soc/sophgo/cv1800-rtcsys.c b/drivers/soc/sophgo/cv1800-rtcsys.c
new file mode 100644
index 000000000000..fdae2e2a61c5
--- /dev/null
+++ b/drivers/soc/sophgo/cv1800-rtcsys.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Sophgo CV1800 series SoC RTC subsystem
+ *
+ * The RTC module comprises a 32kHz oscillator, Power-on-Reset (PoR) sub-module,
+ * HW state machine to control chip power-on, power-off and reset. Furthermore,
+ * the 8051 subsystem is located within RTCSYS including associated SRAM block.
+ *
+ * Copyright (C) 2025 Alexander Sverdlin <alexander.sverdlin@gmail.com>
+ *
+ */
+
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/property.h>
+
+static struct resource cv1800_rtcsys_irq_resources[] = {
+ DEFINE_RES_IRQ_NAMED(0, "alarm"),
+};
+
+static const struct mfd_cell cv1800_rtcsys_subdev[] = {
+ {
+ .name = "cv1800b-rtc",
+ .num_resources = 1,
+ .resources = &cv1800_rtcsys_irq_resources[0],
+ },
+};
+
+static int cv1800_rtcsys_probe(struct platform_device *pdev)
+{
+ int irq;
+
+ irq = platform_get_irq_byname(pdev, "alarm");
+ if (irq < 0)
+ return irq;
+ cv1800_rtcsys_irq_resources[0].start = irq;
+ cv1800_rtcsys_irq_resources[0].end = irq;
+
+ return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO,
+ cv1800_rtcsys_subdev,
+ ARRAY_SIZE(cv1800_rtcsys_subdev),
+ NULL, 0, NULL);
+}
+
+static const struct of_device_id cv1800_rtcsys_of_match[] = {
+ { .compatible = "sophgo,cv1800b-rtc" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, cv1800_rtcsys_of_match);
+
+static struct platform_driver cv1800_rtcsys_mfd = {
+ .probe = cv1800_rtcsys_probe,
+ .driver = {
+ .name = "cv1800_rtcsys",
+ .of_match_table = cv1800_rtcsys_of_match,
+ },
+};
+module_platform_driver(cv1800_rtcsys_mfd);
+
+MODULE_AUTHOR("Alexander Sverdlin <alexander.sverdlin@gmail.com>");
+MODULE_DESCRIPTION("Sophgo CV1800 series SoC RTC subsystem driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/sophgo/sg2044-topsys.c b/drivers/soc/sophgo/sg2044-topsys.c
new file mode 100644
index 000000000000..179f2620b2a9
--- /dev/null
+++ b/drivers/soc/sophgo/sg2044-topsys.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sophgo SG2044 multi-function system controller driver
+ *
+ * Copyright (C) 2025 Inochi Amaoto <inochiama@gmail.com>
+ */
+
+#include <linux/mfd/core.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/resource.h>
+
+static const struct mfd_cell sg2044_topsys_subdev[] = {
+ {
+ .name = "sg2044-pll",
+ },
+};
+
+static int sg2044_topsys_probe(struct platform_device *pdev)
+{
+ return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO,
+ sg2044_topsys_subdev,
+ ARRAY_SIZE(sg2044_topsys_subdev),
+ NULL, 0, NULL);
+}
+
+static const struct of_device_id sg2044_topsys_of_match[] = {
+ { .compatible = "sophgo,sg2044-top-syscon" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sg2044_topsys_of_match);
+
+static struct platform_driver sg2044_topsys_driver = {
+ .probe = sg2044_topsys_probe,
+ .driver = {
+ .name = "sg2044-topsys",
+ .of_match_table = sg2044_topsys_of_match,
+ },
+};
+module_platform_driver(sg2044_topsys_driver);
+
+MODULE_AUTHOR("Inochi Amaoto <inochiama@gmail.com>");
+MODULE_DESCRIPTION("Sophgo SG2044 multi-function system controller driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/sunxi/sunxi_mbus.c b/drivers/soc/sunxi/sunxi_mbus.c
index d90e4a264b6f..1734da357ca2 100644
--- a/drivers/soc/sunxi/sunxi_mbus.c
+++ b/drivers/soc/sunxi/sunxi_mbus.c
@@ -82,7 +82,7 @@ static int sunxi_mbus_notifier(struct notifier_block *nb,
* Older DTs or SoCs who are not clearly understood need to set
* that DMA offset though.
*/
- if (of_find_property(dev->of_node, "interconnects", NULL))
+ if (of_property_present(dev->of_node, "interconnects"))
return NOTIFY_DONE;
ret = dma_direct_set_offset(dev, PHYS_OFFSET, 0, SZ_4G);
diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
index 92f9186c1c42..446b9fc1f175 100644
--- a/drivers/soc/sunxi/sunxi_sram.c
+++ b/drivers/soc/sunxi/sunxi_sram.c
@@ -12,10 +12,11 @@
#include <linux/debugfs.h>
#include <linux/io.h>
+#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
+#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
@@ -33,7 +34,6 @@ struct sunxi_sram_data {
u8 offset;
u8 width;
struct sunxi_sram_func *func;
- struct list_head list;
};
struct sunxi_sram_desc {
@@ -103,7 +103,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;
@@ -120,6 +119,9 @@ static int sunxi_sram_show(struct seq_file *s, void *data)
seq_puts(s, "--------------------\n\n");
for_each_child_of_node(sram_dev->of_node, sram_node) {
+ if (!of_device_is_compatible(sram_node, "mmio-sram"))
+ continue;
+
sram_addr_p = of_get_address(sram_node, 0, NULL, NULL);
seq_printf(s, "sram@%08x\n",
@@ -284,6 +286,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 = {
@@ -305,8 +308,14 @@ 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,
};
+static const struct sunxi_sramc_variant sun55i_a523_sramc_variant = {
+ .num_emac_clocks = 2,
+};
+
+#define SUNXI_SRAM_THS_OFFSET_REG 0x0
#define SUNXI_SRAM_EMAC_CLOCK_REG 0x30
#define SUNXI_SYS_LDO_CTRL_REG 0x150
@@ -315,6 +324,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;
@@ -324,7 +335,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,
@@ -333,6 +358,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)
@@ -340,6 +368,7 @@ static int __init sunxi_sram_probe(struct platform_device *pdev)
const struct sunxi_sramc_variant *variant;
struct device *dev = &pdev->dev;
struct regmap *regmap;
+ int ret;
sram_dev = &pdev->dev;
@@ -357,6 +386,10 @@ static int __init sunxi_sram_probe(struct platform_device *pdev)
regmap = devm_regmap_init_mmio(dev, base, &sunxi_sram_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
+
+ ret = of_syscon_register_regmap(dev->of_node, regmap);
+ if (ret)
+ return ret;
}
of_platform_populate(dev->of_node, NULL, NULL, dev);
@@ -407,6 +440,10 @@ static const struct of_device_id sunxi_sram_dt_match[] = {
.compatible = "allwinner,sun50i-h616-system-control",
.data = &sun50i_h616_sramc_variant,
},
+ {
+ .compatible = "allwinner,sun55i-a523-system-control",
+ .data = &sun55i_a523_sramc_variant,
+ },
{ },
};
MODULE_DEVICE_TABLE(of, sunxi_sram_dt_match);
@@ -421,4 +458,3 @@ builtin_platform_driver_probe(sunxi_sram_driver, sunxi_sram_probe);
MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
MODULE_DESCRIPTION("Allwinner sunXi SRAM Controller Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig
index 3658fb0f0c5b..c0fc54c3cd35 100644
--- a/drivers/soc/tegra/Kconfig
+++ b/drivers/soc/tegra/Kconfig
@@ -96,10 +96,8 @@ config ARCH_TEGRA_210_SOC
config ARCH_TEGRA_186_SOC
bool "NVIDIA Tegra186 SoC"
depends on !CPU_BIG_ENDIAN
+ select PINCTRL_TEGRA186
select MAILBOX
- select TEGRA_BPMP
- select TEGRA_HSP_MBOX
- select TEGRA_IVC
select SOC_TEGRA_PMC
help
Enable support for the NVIDIA Tegar186 SoC. The Tegra186 features a
@@ -114,9 +112,6 @@ config ARCH_TEGRA_194_SOC
depends on !CPU_BIG_ENDIAN
select MAILBOX
select PINCTRL_TEGRA194
- select TEGRA_BPMP
- select TEGRA_HSP_MBOX
- select TEGRA_IVC
select SOC_TEGRA_PMC
help
Enable support for the NVIDIA Tegra194 SoC.
@@ -125,13 +120,24 @@ config ARCH_TEGRA_234_SOC
bool "NVIDIA Tegra234 SoC"
depends on !CPU_BIG_ENDIAN
select MAILBOX
- select TEGRA_BPMP
- select TEGRA_HSP_MBOX
- select TEGRA_IVC
+ select PINCTRL_TEGRA234
select SOC_TEGRA_PMC
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.
+
+config ARCH_TEGRA_264_SOC
+ bool "NVIDIA Tegra264 SoC"
+ depends on !CPU_BIG_ENDIAN
+ select MAILBOX
+ select SOC_TEGRA_PMC
+ help
+ Enable support for the NVIDIA Tegra264 SoC.
+
endif
endif
@@ -151,11 +157,6 @@ config SOC_TEGRA_PMC
select PM_GENERIC_DOMAINS
select REGMAP
-config SOC_TEGRA_POWERGATE_BPMP
- def_bool y
- depends on PM_GENERIC_DOMAINS
- depends on TEGRA_BPMP
-
config SOC_TEGRA20_VOLTAGE_COUPLER
bool "Voltage scaling support for Tegra20 SoCs"
depends on ARCH_TEGRA_2x_SOC || COMPILE_TEST
diff --git a/drivers/soc/tegra/Makefile b/drivers/soc/tegra/Makefile
index d722f512dc9d..01059619e764 100644
--- a/drivers/soc/tegra/Makefile
+++ b/drivers/soc/tegra/Makefile
@@ -5,7 +5,6 @@ obj-y += cbb/
obj-y += common.o
obj-$(CONFIG_SOC_TEGRA_FLOWCTRL) += flowctrl.o
obj-$(CONFIG_SOC_TEGRA_PMC) += pmc.o
-obj-$(CONFIG_SOC_TEGRA_POWERGATE_BPMP) += powergate-bpmp.o
obj-$(CONFIG_SOC_TEGRA20_VOLTAGE_COUPLER) += regulators-tegra20.o
obj-$(CONFIG_SOC_TEGRA30_VOLTAGE_COUPLER) += regulators-tegra30.o
obj-$(CONFIG_ARCH_TEGRA_186_SOC) += ari-tegra186.o
diff --git a/drivers/soc/tegra/cbb/tegra-cbb.c b/drivers/soc/tegra/cbb/tegra-cbb.c
index a8566b9dd8de..6215c6a84fbe 100644
--- a/drivers/soc/tegra/cbb/tegra-cbb.c
+++ b/drivers/soc/tegra/cbb/tegra-cbb.c
@@ -7,16 +7,11 @@
#include <linux/cpufeature.h>
#include <linux/debugfs.h>
#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/io.h>
-#include <linux/of_irq.h>
-#include <linux/of_address.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
-#include <linux/version.h>
#include <soc/tegra/fuse.h>
#include <soc/tegra/tegra-cbb.h>
@@ -74,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)
@@ -127,20 +115,16 @@ int tegra_cbb_get_irq(struct platform_device *pdev, unsigned int *nonsec_irq,
if (num_intr == 2) {
irq = platform_get_irq(pdev, index);
- if (irq <= 0) {
- dev_err(&pdev->dev, "failed to get non-secure IRQ: %d\n", irq);
+ if (irq <= 0)
return -ENOENT;
- }
*nonsec_irq = irq;
index++;
}
irq = platform_get_irq(pdev, index);
- if (irq <= 0) {
- dev_err(&pdev->dev, "failed to get secure IRQ: %d\n", irq);
+ if (irq <= 0)
return -ENOENT;
- }
*sec_irq = irq;
@@ -157,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 d4112b683f00..ab75d50cc85c 100644
--- a/drivers/soc/tegra/cbb/tegra194-cbb.c
+++ b/drivers/soc/tegra/cbb/tegra194-cbb.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (c) 2021-2022, NVIDIA CORPORATION. All rights reserved
+ * Copyright (c) 2021-2025, NVIDIA CORPORATION. All rights reserved
*
* The driver handles Error's from Control Backbone(CBB) generated due to
* illegal accesses. When an error is reported from a NOC within CBB,
@@ -15,15 +15,12 @@
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/io.h>
-#include <linux/of_irq.h>
-#include <linux/of_address.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
-#include <linux/version.h>
#include <soc/tegra/fuse.h>
#include <soc/tegra/tegra-cbb.h>
@@ -141,7 +138,7 @@ struct tegra194_cbb_userbits {
struct tegra194_cbb_noc_data {
const char *name;
bool erd_mask_inband_err;
- const char * const *master_id;
+ const char * const *initiator_id;
unsigned int max_aperture;
const struct tegra194_cbb_aperture *noc_aperture;
const char * const *routeid_initflow;
@@ -219,7 +216,7 @@ static const char * const tegra194_axi2apb_error[] = {
"CH2RFIFOF - Ch2 Request FIFO Full interrupt"
};
-static const char * const tegra194_master_id[] = {
+static const char * const tegra194_initiator_id[] = {
[0x0] = "CCPLEX",
[0x1] = "CCPLEX_DPMU",
[0x2] = "BPMP",
@@ -241,7 +238,7 @@ static const struct tegra_cbb_error tegra194_cbb_errors[] = {
{
.code = "SLV",
.source = "Target",
- .desc = "Target error detected by CBB slave"
+ .desc = "Target error detected by CBB target"
}, {
.code = "DEC",
.source = "Initiator NIU",
@@ -1777,8 +1774,8 @@ static void print_errlog5(struct seq_file *file, struct tegra194_cbb *cbb)
tegra_cbb_print_err(file, "\t AXI ID\t\t: %#x\n", userbits.axi_id);
}
- tegra_cbb_print_err(file, "\t Master ID\t\t: %s\n",
- cbb->noc->master_id[userbits.mstr_id]);
+ tegra_cbb_print_err(file, "\t Initiator ID\t\t: %s\n",
+ cbb->noc->initiator_id[userbits.mstr_id]);
tegra_cbb_print_err(file, "\t Security Group(GRPSEC): %#x\n", userbits.grpsec);
tegra_cbb_print_cache(file, userbits.axcache);
tegra_cbb_print_prot(file, userbits.axprot);
@@ -1839,15 +1836,15 @@ print_errlog1_2(struct seq_file *file, struct tegra194_cbb *cbb,
}
/*
- * Print transcation type, error code and description from ErrLog0 for all
- * errors. For NOC slave errors, all relevant error info is printed using
+ * Print transaction type, error code and description from ErrLog0 for all
+ * errors. For NOC target errors, all relevant error info is printed using
* ErrLog0 only. But additional information is printed for errors from
- * APB slaves because for them:
- * - All errors are logged as SLV(slave) errors due to APB having only single
+ * APB targets because for them:
+ * - All errors are logged as SLV(target) errors due to APB having only single
* bit pslverr to report all errors.
* - Exact cause is printed by reading DMAAPB_X_RAW_INTERRUPT_STATUS register.
* - The driver prints information showing AXI2APB bridge and exact error
- * only if there is error in any AXI2APB slave.
+ * only if there is error in any AXI2APB target.
* - There is still no way to disambiguate a DEC error from SLV error type.
*/
static bool print_errlog0(struct seq_file *file, struct tegra194_cbb *cbb)
@@ -1887,8 +1884,8 @@ static bool print_errlog0(struct seq_file *file, struct tegra194_cbb *cbb)
/* For all SLV errors, read DMAAPB_X_RAW_INTERRUPT_STATUS
* register to get error status for all AXI2APB bridges.
* Print bridge details if a bit is set in a bridge's
- * status register due to error in a APB slave connected
- * to that bridge. For other NOC slaves, none of the status
+ * status register due to error in a APB target connected
+ * to that bridge. For other NOC targets, none of the status
* register will be set.
*/
@@ -2121,7 +2118,7 @@ static const struct tegra_cbb_ops tegra194_cbb_ops = {
static struct tegra194_cbb_noc_data tegra194_cbb_central_noc_data = {
.name = "cbb-noc",
.erd_mask_inband_err = true,
- .master_id = tegra194_master_id,
+ .initiator_id = tegra194_initiator_id,
.noc_aperture = tegra194_cbbcentralnoc_apert_lookup,
.max_aperture = ARRAY_SIZE(tegra194_cbbcentralnoc_apert_lookup),
.routeid_initflow = tegra194_cbbcentralnoc_routeid_initflow,
@@ -2133,7 +2130,7 @@ static struct tegra194_cbb_noc_data tegra194_cbb_central_noc_data = {
static struct tegra194_cbb_noc_data tegra194_aon_noc_data = {
.name = "aon-noc",
.erd_mask_inband_err = false,
- .master_id = tegra194_master_id,
+ .initiator_id = tegra194_initiator_id,
.noc_aperture = tegra194_aonnoc_aperture_lookup,
.max_aperture = ARRAY_SIZE(tegra194_aonnoc_aperture_lookup),
.routeid_initflow = tegra194_aonnoc_routeid_initflow,
@@ -2145,7 +2142,7 @@ static struct tegra194_cbb_noc_data tegra194_aon_noc_data = {
static struct tegra194_cbb_noc_data tegra194_bpmp_noc_data = {
.name = "bpmp-noc",
.erd_mask_inband_err = false,
- .master_id = tegra194_master_id,
+ .initiator_id = tegra194_initiator_id,
.noc_aperture = tegra194_bpmpnoc_apert_lookup,
.max_aperture = ARRAY_SIZE(tegra194_bpmpnoc_apert_lookup),
.routeid_initflow = tegra194_bpmpnoc_routeid_initflow,
@@ -2157,7 +2154,7 @@ static struct tegra194_cbb_noc_data tegra194_bpmp_noc_data = {
static struct tegra194_cbb_noc_data tegra194_rce_noc_data = {
.name = "rce-noc",
.erd_mask_inband_err = false,
- .master_id = tegra194_master_id,
+ .initiator_id = tegra194_initiator_id,
.noc_aperture = tegra194_scenoc_apert_lookup,
.max_aperture = ARRAY_SIZE(tegra194_scenoc_apert_lookup),
.routeid_initflow = tegra194_scenoc_routeid_initflow,
@@ -2169,7 +2166,7 @@ static struct tegra194_cbb_noc_data tegra194_rce_noc_data = {
static struct tegra194_cbb_noc_data tegra194_sce_noc_data = {
.name = "sce-noc",
.erd_mask_inband_err = false,
- .master_id = tegra194_master_id,
+ .initiator_id = tegra194_initiator_id,
.noc_aperture = tegra194_scenoc_apert_lookup,
.max_aperture = ARRAY_SIZE(tegra194_scenoc_apert_lookup),
.routeid_initflow = tegra194_scenoc_routeid_initflow,
@@ -2191,7 +2188,6 @@ MODULE_DEVICE_TABLE(of, tegra194_cbb_match);
static int tegra194_cbb_get_bridges(struct tegra194_cbb *cbb, struct device_node *np)
{
struct tegra_cbb *entry;
- struct resource res;
unsigned long flags;
unsigned int i;
int err;
@@ -2211,8 +2207,7 @@ static int tegra194_cbb_get_bridges(struct tegra194_cbb *cbb, struct device_node
spin_unlock_irqrestore(&cbb_lock, flags);
if (!cbb->bridges) {
- while (of_address_to_resource(np, cbb->num_bridges, &res) == 0)
- cbb->num_bridges++;
+ cbb->num_bridges = of_address_count(np);
cbb->bridges = devm_kcalloc(cbb->base.dev, cbb->num_bridges,
sizeof(*cbb->bridges), GFP_KERNEL);
@@ -2298,7 +2293,7 @@ static int tegra194_cbb_probe(struct platform_device *pdev)
return tegra_cbb_register(&cbb->base);
}
-static int tegra194_cbb_remove(struct platform_device *pdev)
+static void tegra194_cbb_remove(struct platform_device *pdev)
{
struct tegra194_cbb *cbb = platform_get_drvdata(pdev);
struct tegra_cbb *noc, *tmp;
@@ -2316,8 +2311,6 @@ static int tegra194_cbb_remove(struct platform_device *pdev)
}
spin_unlock_irqrestore(&cbb_lock, flags);
-
- return 0;
}
static int __maybe_unused tegra194_cbb_resume_noirq(struct device *dev)
@@ -2359,4 +2352,3 @@ module_exit(tegra194_cbb_exit);
MODULE_AUTHOR("Sumit Gupta <sumitg@nvidia.com>");
MODULE_DESCRIPTION("Control Backbone error handling driver for Tegra194");
-MODULE_LICENSE("GPL");
diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c
index f33d094e5ea6..a9adbcecd47c 100644
--- a/drivers/soc/tegra/cbb/tegra234-cbb.c
+++ b/drivers/soc/tegra/cbb/tegra234-cbb.c
@@ -1,13 +1,13 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (c) 2021-2022, NVIDIA CORPORATION. All rights reserved
+ * Copyright (c) 2021-2025, NVIDIA CORPORATION. All rights reserved
*
* The driver handles Error's from Control Backbone(CBB) version 2.0.
* generated due to illegal accesses. The driver prints debug information
* about failed transaction on receiving interrupt from Error Notifier.
* Error types supported by CBB2.0 are:
* UNSUPPORTED_ERR, PWRDOWN_ERR, TIMEOUT_ERR, FIREWALL_ERR, DECODE_ERR,
- * SLAVE_ERR
+ * TARGET_ERR
*/
#include <linux/acpi.h>
@@ -16,15 +16,11 @@
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/io.h>
-#include <linux/of_irq.h>
-#include <linux/of_address.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
-#include <linux/version.h>
#include <soc/tegra/fuse.h>
#include <soc/tegra/tegra-cbb.h>
@@ -34,18 +30,22 @@
#define FABRIC_EN_CFG_ADDR_LOW_0 0x80
#define FABRIC_EN_CFG_ADDR_HI_0 0x84
-#define FABRIC_MN_MASTER_ERR_EN_0 0x200
-#define FABRIC_MN_MASTER_ERR_FORCE_0 0x204
-#define FABRIC_MN_MASTER_ERR_STATUS_0 0x208
-#define FABRIC_MN_MASTER_ERR_OVERFLOW_STATUS_0 0x20c
+#define FABRIC_EN_CFG_TARGET_NODE_ADDR_INDEX_0_0 0x100
+#define FABRIC_EN_CFG_TARGET_NODE_ADDR_LOW_0 0x140
+#define FABRIC_EN_CFG_TARGET_NODE_ADDR_HI_0 0x144
-#define FABRIC_MN_MASTER_LOG_ERR_STATUS_0 0x300
-#define FABRIC_MN_MASTER_LOG_ADDR_LOW_0 0x304
-#define FABRIC_MN_MASTER_LOG_ADDR_HIGH_0 0x308
-#define FABRIC_MN_MASTER_LOG_ATTRIBUTES0_0 0x30c
-#define FABRIC_MN_MASTER_LOG_ATTRIBUTES1_0 0x310
-#define FABRIC_MN_MASTER_LOG_ATTRIBUTES2_0 0x314
-#define FABRIC_MN_MASTER_LOG_USER_BITS0_0 0x318
+#define FABRIC_MN_INITIATOR_ERR_EN_0 0x200
+#define FABRIC_MN_INITIATOR_ERR_FORCE_0 0x204
+#define FABRIC_MN_INITIATOR_ERR_STATUS_0 0x208
+#define FABRIC_MN_INITIATOR_ERR_OVERFLOW_STATUS_0 0x20c
+
+#define FABRIC_MN_INITIATOR_LOG_ERR_STATUS_0 0x300
+#define FABRIC_MN_INITIATOR_LOG_ADDR_LOW_0 0x304
+#define FABRIC_MN_INITIATOR_LOG_ADDR_HIGH_0 0x308
+#define FABRIC_MN_INITIATOR_LOG_ATTRIBUTES0_0 0x30c
+#define FABRIC_MN_INITIATOR_LOG_ATTRIBUTES1_0 0x310
+#define FABRIC_MN_INITIATOR_LOG_ATTRIBUTES2_0 0x314
+#define FABRIC_MN_INITIATOR_LOG_USER_BITS0_0 0x318
#define AXI_SLV_TIMEOUT_STATUS_0_0 0x8
#define APB_BLOCK_TMO_STATUS_0 0xc00
@@ -57,7 +57,7 @@
#define FAB_EM_EL_FALCONSEC GENMASK(1, 0)
#define FAB_EM_EL_FABID GENMASK(20, 16)
-#define FAB_EM_EL_SLAVEID GENMASK(7, 0)
+#define FAB_EM_EL_TARGETID GENMASK(7, 0)
#define FAB_EM_EL_ACCESSID GENMASK(7, 0)
@@ -78,34 +78,79 @@
#define WEN 0x20000
enum tegra234_cbb_fabric_ids {
- CBB_FAB_ID,
- SCE_FAB_ID,
- RCE_FAB_ID,
- DCE_FAB_ID,
- AON_FAB_ID,
- PSC_FAB_ID,
- BPMP_FAB_ID,
- FSI_FAB_ID,
- MAX_FAB_ID,
+ T234_CBB_FABRIC_ID,
+ T234_SCE_FABRIC_ID,
+ T234_RCE_FABRIC_ID,
+ T234_DCE_FABRIC_ID,
+ T234_AON_FABRIC_ID,
+ T234_PSC_FABRIC_ID,
+ T234_BPMP_FABRIC_ID,
+ T234_FSI_FABRIC_ID,
+ T234_MAX_FABRIC_ID,
+};
+
+enum tegra264_cbb_fabric_ids {
+ T264_SYSTEM_CBB_FABRIC_ID,
+ T264_TOP_0_CBB_FABRIC_ID,
+ T264_VISION_CBB_FABRIC_ID,
+ T264_DISP_USB_CBB_FABRIC_ID,
+ T264_UPHY0_CBB_FABRIC_ID,
+ T264_RSVD0_FABRIC_ID,
+ T264_RSVD1_FABRIC_ID,
+ T264_RSVD2_FABRIC_ID,
+ T264_RSVD3_FABRIC_ID,
+ T264_RSVD4_FABRIC_ID,
+ T264_RSVD5_FABRIC_ID,
+ T264_AON_FABRIC_ID,
+ T264_PSC_FABRIC_ID,
+ T264_OESP_FABRIC_ID,
+ T264_APE_FABRIC_ID,
+ T264_BPMP_FABRIC_ID,
+ T264_RCE_0_FABRIC_ID,
+ T264_RCE_1_FABRIC_ID,
+ T264_RSVD6_FABRIC_ID,
+ T264_DCE_FABRIC_ID,
+ T264_FSI_FABRIC_ID,
+ T264_ISC_FABRIC_ID,
+ T264_SB_FABRIC_ID,
+ T264_ISC_CPU_FABRIC_ID,
+ T264_RSVD7_FABRIC_ID,
+};
+
+enum t254_cbb_fabric_ids {
+ T254_DCE_FABRIC_ID = 19,
+ T254_DISP_CLUSTER_FABRIC_ID = 25,
+ T254_C2C_FABRIC_ID = 26,
+ T254_GPU_FABRIC_ID = 27,
+ T254_DISP_CLUSTER_1_FABRIC_ID = 28,
+ T254_MAX_FABRIC_ID,
};
-struct tegra234_slave_lookup {
+struct tegra234_target_lookup {
const char *name;
unsigned int offset;
};
-struct tegra234_cbb_fabric {
+struct tegra234_fabric_lookup {
const char *name;
+ bool is_lookup;
+ const struct tegra234_target_lookup *target_map;
+ const int max_targets;
+};
+
+struct tegra234_cbb_fabric {
+ int fab_id;
phys_addr_t off_mask_erd;
phys_addr_t firewall_base;
unsigned int firewall_ctl;
unsigned int firewall_wr_ctl;
- const char * const *master_id;
+ const char * const *initiator_id;
unsigned int notifier_offset;
const struct tegra_cbb_error *errors;
const int max_errors;
- const struct tegra234_slave_lookup *slave_map;
- const int max_slaves;
+ const struct tegra234_fabric_lookup *fab_list;
+ const u32 err_intr_enbl;
+ const u32 err_status_clr;
};
struct tegra234_cbb {
@@ -181,7 +226,7 @@ static void tegra234_cbb_fault_enable(struct tegra_cbb *cbb)
void __iomem *addr;
addr = priv->regs + priv->fabric->notifier_offset;
- writel(0x1ff, addr + FABRIC_EN_CFG_INTERRUPT_ENABLE_0_0);
+ writel(priv->fabric->err_intr_enbl, addr + FABRIC_EN_CFG_INTERRUPT_ENABLE_0_0);
dsb(sy);
}
@@ -189,7 +234,9 @@ static void tegra234_cbb_error_clear(struct tegra_cbb *cbb)
{
struct tegra234_cbb *priv = to_tegra234_cbb(cbb);
- writel(0x3f, priv->mon + FABRIC_MN_MASTER_ERR_STATUS_0);
+ writel(0, priv->mon + FABRIC_MN_INITIATOR_ERR_FORCE_0);
+
+ writel(priv->fabric->err_status_clr, priv->mon + FABRIC_MN_INITIATOR_ERR_STATUS_0);
dsb(sy);
}
@@ -220,13 +267,13 @@ static u32 tegra234_cbb_get_tmo_slv(void __iomem *addr)
return timeout;
}
-static void tegra234_cbb_tmo_slv(struct seq_file *file, const char *slave, void __iomem *addr,
+static void tegra234_cbb_tmo_slv(struct seq_file *file, const char *target, void __iomem *addr,
u32 status)
{
- tegra_cbb_print_err(file, "\t %s : %#x\n", slave, status);
+ tegra_cbb_print_err(file, "\t %s : %#x\n", target, status);
}
-static void tegra234_cbb_lookup_apbslv(struct seq_file *file, const char *slave,
+static void tegra234_cbb_lookup_apbslv(struct seq_file *file, const char *target,
void __iomem *base)
{
unsigned int block = 0;
@@ -236,7 +283,7 @@ static void tegra234_cbb_lookup_apbslv(struct seq_file *file, const char *slave,
status = tegra234_cbb_get_tmo_slv(base);
if (status)
- tegra_cbb_print_err(file, "\t %s_BLOCK_TMO_STATUS : %#x\n", slave, status);
+ tegra_cbb_print_err(file, "\t %s_BLOCK_TMO_STATUS : %#x\n", target, status);
while (status) {
if (status & BIT(0)) {
@@ -251,7 +298,7 @@ static void tegra234_cbb_lookup_apbslv(struct seq_file *file, const char *slave,
if (clients != 0xffffffff)
clients &= BIT(client);
- sprintf(name, "%s_BLOCK%d_TMO", slave, block);
+ sprintf(name, "%s_BLOCK%d_TMO", target, block);
tegra234_cbb_tmo_slv(file, name, addr, clients);
}
@@ -266,22 +313,27 @@ static void tegra234_cbb_lookup_apbslv(struct seq_file *file, const char *slave,
}
}
-static void tegra234_lookup_slave_timeout(struct seq_file *file, struct tegra234_cbb *cbb,
- u8 slave_id, u8 fab_id)
+static void tegra234_sw_lookup_target_timeout(struct seq_file *file, struct tegra234_cbb *cbb,
+ u8 target_id, u8 fab_id)
{
- const struct tegra234_slave_lookup *map = cbb->fabric->slave_map;
+ const struct tegra234_target_lookup *map = cbb->fabric->fab_list[fab_id].target_map;
void __iomem *addr;
+ if (target_id >= cbb->fabric->fab_list[fab_id].max_targets) {
+ tegra_cbb_print_err(file, "\t Invalid target_id:%d\n", target_id);
+ return;
+ }
+
/*
- * 1) Get slave node name and address mapping using slave_id.
- * 2) Check if the timed out slave node is APB or AXI.
- * 3) If AXI, then print timeout register and reset axi slave
+ * 1) Get target node name and address mapping using target_id.
+ * 2) Check if the timed out target node is APB or AXI.
+ * 3) If AXI, then print timeout register and reset axi target
* using <FABRIC>_SN_<>_SLV_TIMEOUT_STATUS_0_0 register.
* 4) If APB, then perform an additional lookup to find the client
* 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.
@@ -289,12 +341,12 @@ static void tegra234_lookup_slave_timeout(struct seq_file *file, struct tegra234
* e) Goto step-a till all bits are set.
*/
- addr = cbb->regs + map[slave_id].offset;
+ addr = cbb->regs + map[target_id].offset;
- if (strstr(map[slave_id].name, "AXI2APB")) {
+ if (strstr(map[target_id].name, "AXI2APB")) {
addr += APB_BLOCK_TMO_STATUS_0;
- tegra234_cbb_lookup_apbslv(file, map[slave_id].name, addr);
+ tegra234_cbb_lookup_apbslv(file, map[target_id].name, addr);
} else {
char name[64];
u32 status;
@@ -303,12 +355,29 @@ static void tegra234_lookup_slave_timeout(struct seq_file *file, struct tegra234
status = tegra234_cbb_get_tmo_slv(addr);
if (status) {
- sprintf(name, "%s_SLV_TIMEOUT_STATUS", map[slave_id].name);
+ sprintf(name, "%s_SLV_TIMEOUT_STATUS", map[target_id].name);
tegra234_cbb_tmo_slv(file, name, addr, status);
}
}
}
+static void tegra234_hw_lookup_target_timeout(struct seq_file *file, struct tegra234_cbb *cbb,
+ u8 target_id, u8 fab_id)
+{
+ unsigned int notifier = cbb->fabric->notifier_offset;
+ u32 hi, lo;
+ u64 addr;
+
+ writel(target_id, cbb->regs + notifier + FABRIC_EN_CFG_TARGET_NODE_ADDR_INDEX_0_0);
+
+ hi = readl(cbb->regs + notifier + FABRIC_EN_CFG_TARGET_NODE_ADDR_HI_0);
+ lo = readl(cbb->regs + notifier + FABRIC_EN_CFG_TARGET_NODE_ADDR_LOW_0);
+
+ addr = (u64)hi << 32 | lo;
+
+ tegra_cbb_print_err(file, "\t Target Node Addr : %#llx\n", addr);
+}
+
static void tegra234_cbb_print_error(struct seq_file *file, struct tegra234_cbb *cbb, u32 status,
u32 overflow)
{
@@ -353,8 +422,7 @@ static void tegra234_cbb_print_error(struct seq_file *file, struct tegra234_cbb
static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb)
{
u8 cache_type, prot_type, burst_length, mstr_id, grpsec, vqc, falconsec, beat_size;
- u8 access_type, access_id, requester_socket_id, local_socket_id, slave_id, fab_id;
- char fabric_name[20];
+ u8 access_type, access_id, requester_socket_id, local_socket_id, target_id, fab_id;
bool is_numa = false;
u8 burst_type;
@@ -368,7 +436,7 @@ static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb)
/*
* For SOC with multiple NUMA nodes, print cross socket access
- * errors only if initiator/master_id is CCPLEX, CPMU or GPU.
+ * errors only if initiator_id is CCPLEX, CPMU or GPU.
*/
if (is_numa) {
local_socket_id = numa_node_id();
@@ -381,7 +449,7 @@ static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb)
}
fab_id = FIELD_GET(FAB_EM_EL_FABID, cbb->mn_attr2);
- slave_id = FIELD_GET(FAB_EM_EL_SLAVEID, cbb->mn_attr2);
+ target_id = FIELD_GET(FAB_EM_EL_TARGETID, cbb->mn_attr2);
access_id = FIELD_GET(FAB_EM_EL_ACCESSID, cbb->mn_attr1);
@@ -399,21 +467,18 @@ static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb)
else
tegra_cbb_print_err(file, "\t Wrong type index:%u\n", cbb->type);
- tegra_cbb_print_err(file, "\t MASTER_ID\t\t: %s\n", cbb->fabric->master_id[mstr_id]);
+ tegra_cbb_print_err(file, "\t Initiator_Id\t\t: %#x\n", mstr_id);
+ if (cbb->fabric->initiator_id)
+ tegra_cbb_print_err(file, "\t Initiator\t\t: %s\n",
+ cbb->fabric->initiator_id[mstr_id]);
+
tegra_cbb_print_err(file, "\t Address\t\t: %#llx\n", cbb->access);
tegra_cbb_print_cache(file, cache_type);
tegra_cbb_print_prot(file, prot_type);
tegra_cbb_print_err(file, "\t Access_Type\t\t: %s", (access_type) ? "Write\n" : "Read\n");
- tegra_cbb_print_err(file, "\t Access_ID\t\t: %#x", access_id);
-
- if (fab_id == PSC_FAB_ID)
- strcpy(fabric_name, "psc-fabric");
- else if (fab_id == FSI_FAB_ID)
- strcpy(fabric_name, "fsi-fabric");
- else
- strcpy(fabric_name, cbb->fabric->name);
+ tegra_cbb_print_err(file, "\t Access_ID\t\t: %#x\n", access_id);
if (is_numa) {
tegra_cbb_print_err(file, "\t Requester_Socket_Id\t: %#x\n",
@@ -424,8 +489,21 @@ static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb)
num_possible_nodes());
}
- tegra_cbb_print_err(file, "\t Fabric\t\t: %s\n", fabric_name);
- tegra_cbb_print_err(file, "\t Slave_Id\t\t: %#x\n", slave_id);
+ tegra_cbb_print_err(file, "\t Fabric\t\t: %s (id:%#x)\n",
+ cbb->fabric->fab_list[fab_id].name, fab_id);
+
+ if (of_machine_is_compatible("nvidia,tegra264") && fab_id == T264_UPHY0_CBB_FABRIC_ID) {
+ /*
+ * In T264, AON Fabric ID value is incorrectly same as UPHY0 fabric ID.
+ * For 'ID = 0x4', we must check for the address which caused the error
+ * to find the correct fabric which returned error.
+ */
+ tegra_cbb_print_err(file, "\t or Fabric\t\t: %s\n",
+ cbb->fabric->fab_list[T264_AON_FABRIC_ID].name);
+ tegra_cbb_print_err(file, "\t Please use Address to determine correct fabric.\n");
+ }
+
+ tegra_cbb_print_err(file, "\t Target_Id\t\t: %#x\n", target_id);
tegra_cbb_print_err(file, "\t Burst_length\t\t: %#x\n", burst_length);
tegra_cbb_print_err(file, "\t Burst_type\t\t: %#x\n", burst_type);
tegra_cbb_print_err(file, "\t Beat_size\t\t: %#x\n", beat_size);
@@ -433,27 +511,30 @@ static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb)
tegra_cbb_print_err(file, "\t GRPSEC\t\t: %#x\n", grpsec);
tegra_cbb_print_err(file, "\t FALCONSEC\t\t: %#x\n", falconsec);
- if ((fab_id == PSC_FAB_ID) || (fab_id == FSI_FAB_ID))
+ if (!cbb->fabric->fab_list[fab_id].is_lookup)
return;
- if (slave_id >= cbb->fabric->max_slaves) {
- tegra_cbb_print_err(file, "\t Invalid slave_id:%d\n", slave_id);
- return;
- }
-
+ /*
+ * If is_lookup field is set in fabric_lookup table of soc data, it
+ * means that address lookup of target is supported for Timeout errors.
+ * If is_lookup is set and the target_map is not populated making
+ * max_targets as zero, then it means HW lookup is to be performed.
+ */
if (!strcmp(cbb->fabric->errors[cbb->type].code, "TIMEOUT_ERR")) {
- tegra234_lookup_slave_timeout(file, cbb, slave_id, fab_id);
- return;
+ if (cbb->fabric->fab_list[fab_id].max_targets)
+ tegra234_sw_lookup_target_timeout(file, cbb, target_id, fab_id);
+ else
+ tegra234_hw_lookup_target_timeout(file, cbb, target_id, fab_id);
}
- tegra_cbb_print_err(file, "\t Slave\t\t\t: %s\n", cbb->fabric->slave_map[slave_id].name);
+ return;
}
static int print_errmonX_info(struct seq_file *file, struct tegra234_cbb *cbb)
{
u32 overflow, status, error;
- status = readl(cbb->mon + FABRIC_MN_MASTER_ERR_STATUS_0);
+ status = readl(cbb->mon + FABRIC_MN_INITIATOR_ERR_STATUS_0);
if (!status) {
pr_err("Error Notifier received a spurious notification\n");
return -ENODATA;
@@ -464,11 +545,11 @@ static int print_errmonX_info(struct seq_file *file, struct tegra234_cbb *cbb)
return -EINVAL;
}
- overflow = readl(cbb->mon + FABRIC_MN_MASTER_ERR_OVERFLOW_STATUS_0);
+ overflow = readl(cbb->mon + FABRIC_MN_INITIATOR_ERR_OVERFLOW_STATUS_0);
tegra234_cbb_print_error(file, cbb, status, overflow);
- error = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ERR_STATUS_0);
+ error = readl(cbb->mon + FABRIC_MN_INITIATOR_LOG_ERR_STATUS_0);
if (!error) {
pr_info("Error Monitor doesn't have Error Logger\n");
return -EINVAL;
@@ -480,15 +561,15 @@ static int print_errmonX_info(struct seq_file *file, struct tegra234_cbb *cbb)
if (error & BIT(0)) {
u32 hi, lo;
- hi = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ADDR_HIGH_0);
- lo = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ADDR_LOW_0);
+ hi = readl(cbb->mon + FABRIC_MN_INITIATOR_LOG_ADDR_HIGH_0);
+ lo = readl(cbb->mon + FABRIC_MN_INITIATOR_LOG_ADDR_LOW_0);
cbb->access = (u64)hi << 32 | lo;
- cbb->mn_attr0 = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ATTRIBUTES0_0);
- cbb->mn_attr1 = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ATTRIBUTES1_0);
- cbb->mn_attr2 = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ATTRIBUTES2_0);
- cbb->mn_user_bits = readl(cbb->mon + FABRIC_MN_MASTER_LOG_USER_BITS0_0);
+ cbb->mn_attr0 = readl(cbb->mon + FABRIC_MN_INITIATOR_LOG_ATTRIBUTES0_0);
+ cbb->mn_attr1 = readl(cbb->mon + FABRIC_MN_INITIATOR_LOG_ATTRIBUTES1_0);
+ cbb->mn_attr2 = readl(cbb->mon + FABRIC_MN_INITIATOR_LOG_ATTRIBUTES2_0);
+ cbb->mn_user_bits = readl(cbb->mon + FABRIC_MN_INITIATOR_LOG_USER_BITS0_0);
print_errlog_err(file, cbb);
}
@@ -507,7 +588,7 @@ static int print_err_notifier(struct seq_file *file, struct tegra234_cbb *cbb, u
pr_crit("**************************************\n");
pr_crit("CPU:%d, Error:%s, Errmon:%d\n", smp_processor_id(),
- cbb->fabric->name, status);
+ cbb->fabric->fab_list[cbb->fabric->fab_id].name, status);
while (status) {
if (status & BIT(0)) {
@@ -530,13 +611,13 @@ static int print_err_notifier(struct seq_file *file, struct tegra234_cbb *cbb, u
tegra234_cbb_error_clear(&cbb->base);
if (err)
return err;
+ tegra_cbb_print_err(file, "\t**************************************\n");
}
status >>= 1;
index++;
}
- tegra_cbb_print_err(file, "\t**************************************\n");
return 0;
}
@@ -585,7 +666,8 @@ static irqreturn_t tegra234_cbb_isr(int irq, void *data)
if (status && (irq == priv->sec_irq)) {
tegra_cbb_print_err(NULL, "CPU:%d, Error: %s@0x%llx, irq=%d\n",
- smp_processor_id(), priv->fabric->name,
+ smp_processor_id(),
+ priv->fabric->fab_list[priv->fabric->fab_id].name,
priv->res->start, irq);
err = print_err_notifier(NULL, priv, status);
@@ -593,7 +675,7 @@ static irqreturn_t tegra234_cbb_isr(int irq, void *data)
goto unlock;
/*
- * If illegal request is from CCPLEX(id:0x1) master then call WARN()
+ * If illegal request is from CCPLEX(id:0x1) initiator then call WARN()
*/
if (priv->fabric->off_mask_erd) {
mstr_id = FIELD_GET(USRBITS_MSTR_ID, priv->mn_user_bits);
@@ -645,7 +727,7 @@ static const struct tegra_cbb_ops tegra234_cbb_ops = {
#endif
};
-static const char * const tegra234_master_id[] = {
+static const char * const tegra234_initiator_id[] = {
[0x00] = "TZ",
[0x01] = "CCPLEX",
[0x02] = "CCPMU",
@@ -676,8 +758,8 @@ static const char * const tegra234_master_id[] = {
static const struct tegra_cbb_error tegra234_cbb_errors[] = {
{
- .code = "SLAVE_ERR",
- .desc = "Slave being accessed responded with an error"
+ .code = "TARGET_ERR",
+ .desc = "Target being accessed responded with an error"
}, {
.code = "DECODE_ERR",
.desc = "Attempt to access an address hole"
@@ -686,37 +768,24 @@ static const struct tegra_cbb_error tegra234_cbb_errors[] = {
.desc = "Attempt to access a region which is firewall protected"
}, {
.code = "TIMEOUT_ERR",
- .desc = "No response returned by slave"
+ .desc = "No response returned by target"
}, {
.code = "PWRDOWN_ERR",
.desc = "Attempt to access a portion of fabric that is powered down"
}, {
.code = "UNSUPPORTED_ERR",
- .desc = "Attempt to access a slave through an unsupported access"
+ .desc = "Attempt to access a target through an unsupported access"
}
};
-static const struct tegra234_slave_lookup tegra234_aon_slave_map[] = {
+static const struct tegra234_target_lookup tegra234_aon_target_map[] = {
{ "AXI2APB", 0x00000 },
{ "AST", 0x14000 },
{ "CBB", 0x15000 },
{ "CPU", 0x16000 },
};
-static const struct tegra234_cbb_fabric tegra234_aon_fabric = {
- .name = "aon-fabric",
- .master_id = tegra234_master_id,
- .slave_map = tegra234_aon_slave_map,
- .max_slaves = ARRAY_SIZE(tegra234_aon_slave_map),
- .errors = tegra234_cbb_errors,
- .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
- .notifier_offset = 0x17000,
- .firewall_base = 0x30000,
- .firewall_ctl = 0x8d0,
- .firewall_wr_ctl = 0x8c8,
-};
-
-static const struct tegra234_slave_lookup tegra234_bpmp_slave_map[] = {
+static const struct tegra234_target_lookup tegra234_bpmp_target_map[] = {
{ "AXI2APB", 0x00000 },
{ "AST0", 0x15000 },
{ "AST1", 0x16000 },
@@ -724,20 +793,16 @@ static const struct tegra234_slave_lookup tegra234_bpmp_slave_map[] = {
{ "CPU", 0x18000 },
};
-static const struct tegra234_cbb_fabric tegra234_bpmp_fabric = {
- .name = "bpmp-fabric",
- .master_id = tegra234_master_id,
- .slave_map = tegra234_bpmp_slave_map,
- .max_slaves = ARRAY_SIZE(tegra234_bpmp_slave_map),
- .errors = tegra234_cbb_errors,
- .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
- .notifier_offset = 0x19000,
- .firewall_base = 0x30000,
- .firewall_ctl = 0x8f0,
- .firewall_wr_ctl = 0x8e8,
+static const struct tegra234_target_lookup tegra234_common_target_map[] = {
+ { "AXI2APB", 0x00000 },
+ { "AST0", 0x15000 },
+ { "AST1", 0x16000 },
+ { "CBB", 0x17000 },
+ { "RSVD", 0x00000 },
+ { "CPU", 0x18000 },
};
-static const struct tegra234_slave_lookup tegra234_cbb_slave_map[] = {
+static const struct tegra234_target_lookup tegra234_cbb_target_map[] = {
{ "AON", 0x40000 },
{ "BPMP", 0x41000 },
{ "CBB", 0x42000 },
@@ -801,13 +866,65 @@ static const struct tegra234_slave_lookup tegra234_cbb_slave_map[] = {
{ "AXI2APB_3", 0x91000 },
};
+static const struct tegra234_fabric_lookup tegra234_cbb_fab_list[] = {
+ [T234_CBB_FABRIC_ID] = { "cbb-fabric", true,
+ tegra234_cbb_target_map,
+ ARRAY_SIZE(tegra234_cbb_target_map) },
+ [T234_SCE_FABRIC_ID] = { "sce-fabric", true,
+ tegra234_common_target_map,
+ ARRAY_SIZE(tegra234_common_target_map) },
+ [T234_RCE_FABRIC_ID] = { "rce-fabric", true,
+ tegra234_common_target_map,
+ ARRAY_SIZE(tegra234_common_target_map) },
+ [T234_DCE_FABRIC_ID] = { "dce-fabric", true,
+ tegra234_common_target_map,
+ ARRAY_SIZE(tegra234_common_target_map) },
+ [T234_AON_FABRIC_ID] = { "aon-fabric", true,
+ tegra234_aon_target_map,
+ ARRAY_SIZE(tegra234_bpmp_target_map) },
+ [T234_PSC_FABRIC_ID] = { "psc-fabric" },
+ [T234_BPMP_FABRIC_ID] = { "bpmp-fabric", true,
+ tegra234_bpmp_target_map,
+ ARRAY_SIZE(tegra234_bpmp_target_map) },
+ [T234_FSI_FABRIC_ID] = { "fsi-fabric" },
+};
+
+static const struct tegra234_cbb_fabric tegra234_aon_fabric = {
+ .fab_id = T234_AON_FABRIC_ID,
+ .fab_list = tegra234_cbb_fab_list,
+ .initiator_id = tegra234_initiator_id,
+ .errors = tegra234_cbb_errors,
+ .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
+ .err_intr_enbl = 0x7,
+ .err_status_clr = 0x3f,
+ .notifier_offset = 0x17000,
+ .firewall_base = 0x30000,
+ .firewall_ctl = 0x8d0,
+ .firewall_wr_ctl = 0x8c8,
+};
+
+static const struct tegra234_cbb_fabric tegra234_bpmp_fabric = {
+ .fab_id = T234_BPMP_FABRIC_ID,
+ .fab_list = tegra234_cbb_fab_list,
+ .initiator_id = tegra234_initiator_id,
+ .errors = tegra234_cbb_errors,
+ .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
+ .err_intr_enbl = 0xf,
+ .err_status_clr = 0x3f,
+ .notifier_offset = 0x19000,
+ .firewall_base = 0x30000,
+ .firewall_ctl = 0x8f0,
+ .firewall_wr_ctl = 0x8e8,
+};
+
static const struct tegra234_cbb_fabric tegra234_cbb_fabric = {
- .name = "cbb-fabric",
- .master_id = tegra234_master_id,
- .slave_map = tegra234_cbb_slave_map,
- .max_slaves = ARRAY_SIZE(tegra234_cbb_slave_map),
+ .fab_id = T234_CBB_FABRIC_ID,
+ .fab_list = tegra234_cbb_fab_list,
+ .initiator_id = tegra234_initiator_id,
.errors = tegra234_cbb_errors,
.max_errors = ARRAY_SIZE(tegra234_cbb_errors),
+ .err_intr_enbl = 0x7f,
+ .err_status_clr = 0x3f,
.notifier_offset = 0x60000,
.off_mask_erd = 0x3a004,
.firewall_base = 0x10000,
@@ -815,22 +932,14 @@ static const struct tegra234_cbb_fabric tegra234_cbb_fabric = {
.firewall_wr_ctl = 0x23e8,
};
-static const struct tegra234_slave_lookup tegra234_common_slave_map[] = {
- { "AXI2APB", 0x00000 },
- { "AST0", 0x15000 },
- { "AST1", 0x16000 },
- { "CBB", 0x17000 },
- { "RSVD", 0x00000 },
- { "CPU", 0x18000 },
-};
-
static const struct tegra234_cbb_fabric tegra234_dce_fabric = {
- .name = "dce-fabric",
- .master_id = tegra234_master_id,
- .slave_map = tegra234_common_slave_map,
- .max_slaves = ARRAY_SIZE(tegra234_common_slave_map),
+ .fab_id = T234_DCE_FABRIC_ID,
+ .fab_list = tegra234_cbb_fab_list,
+ .initiator_id = tegra234_initiator_id,
.errors = tegra234_cbb_errors,
.max_errors = ARRAY_SIZE(tegra234_cbb_errors),
+ .err_intr_enbl = 0xf,
+ .err_status_clr = 0x3f,
.notifier_offset = 0x19000,
.firewall_base = 0x30000,
.firewall_ctl = 0x290,
@@ -838,12 +947,13 @@ static const struct tegra234_cbb_fabric tegra234_dce_fabric = {
};
static const struct tegra234_cbb_fabric tegra234_rce_fabric = {
- .name = "rce-fabric",
- .master_id = tegra234_master_id,
- .slave_map = tegra234_common_slave_map,
- .max_slaves = ARRAY_SIZE(tegra234_common_slave_map),
+ .fab_id = T234_RCE_FABRIC_ID,
+ .fab_list = tegra234_cbb_fab_list,
+ .initiator_id = tegra234_initiator_id,
.errors = tegra234_cbb_errors,
.max_errors = ARRAY_SIZE(tegra234_cbb_errors),
+ .err_intr_enbl = 0xf,
+ .err_status_clr = 0x3f,
.notifier_offset = 0x19000,
.firewall_base = 0x30000,
.firewall_ctl = 0x290,
@@ -851,19 +961,20 @@ static const struct tegra234_cbb_fabric tegra234_rce_fabric = {
};
static const struct tegra234_cbb_fabric tegra234_sce_fabric = {
- .name = "sce-fabric",
- .master_id = tegra234_master_id,
- .slave_map = tegra234_common_slave_map,
- .max_slaves = ARRAY_SIZE(tegra234_common_slave_map),
+ .fab_id = T234_SCE_FABRIC_ID,
+ .fab_list = tegra234_cbb_fab_list,
+ .initiator_id = tegra234_initiator_id,
.errors = tegra234_cbb_errors,
.max_errors = ARRAY_SIZE(tegra234_cbb_errors),
+ .err_intr_enbl = 0xf,
+ .err_status_clr = 0x3f,
.notifier_offset = 0x19000,
.firewall_base = 0x30000,
.firewall_ctl = 0x290,
.firewall_wr_ctl = 0x288,
};
-static const char * const tegra241_master_id[] = {
+static const char * const tegra241_initiator_id[] = {
[0x0] = "TZ",
[0x1] = "CCPLEX",
[0x2] = "CCPMU",
@@ -881,22 +992,22 @@ static const char * const tegra241_master_id[] = {
};
/*
- * Possible causes for Slave and Timeout errors.
- * SLAVE_ERR:
- * Slave being accessed responded with an error. Slave could return
+ * Possible causes for Target and Timeout errors.
+ * TARGET_ERR:
+ * Target being accessed responded with an error. Target could return
* an error for various cases :
* Unsupported access, clamp setting when power gated, register
- * level firewall(SCR), address hole within the slave, etc
+ * level firewall(SCR), address hole within the target, etc
*
* TIMEOUT_ERR:
- * No response returned by slave. Can be due to slave being clock
- * gated, under reset, powered down or slave inability to respond
- * for an internal slave issue
+ * No response returned by target. Can be due to target being clock
+ * gated, under reset, powered down or target inability to respond
+ * for an internal target issue
*/
static const struct tegra_cbb_error tegra241_cbb_errors[] = {
{
- .code = "SLAVE_ERR",
- .desc = "Slave being accessed responded with an error."
+ .code = "TARGET_ERR",
+ .desc = "Target being accessed responded with an error."
}, {
.code = "DECODE_ERR",
.desc = "Attempt to access an address hole or Reserved region of memory."
@@ -905,16 +1016,16 @@ static const struct tegra_cbb_error tegra241_cbb_errors[] = {
.desc = "Attempt to access a region which is firewalled."
}, {
.code = "TIMEOUT_ERR",
- .desc = "No response returned by slave."
+ .desc = "No response returned by target."
}, {
.code = "PWRDOWN_ERR",
.desc = "Attempt to access a portion of the fabric that is powered down."
}, {
.code = "UNSUPPORTED_ERR",
- .desc = "Attempt to access a slave through an unsupported access."
+ .desc = "Attempt to access a target through an unsupported access."
}, {
.code = "POISON_ERR",
- .desc = "Slave responds with poison error to indicate error in data."
+ .desc = "Target responds with poison error to indicate error in data."
}, {
.code = "RSVD"
}, {
@@ -972,7 +1083,18 @@ static const struct tegra_cbb_error tegra241_cbb_errors[] = {
},
};
-static const struct tegra234_slave_lookup tegra241_cbb_slave_map[] = {
+static const struct tegra234_target_lookup tegra241_bpmp_target_map[] = {
+ { "RSVD", 0x00000 },
+ { "RSVD", 0x00000 },
+ { "RSVD", 0x00000 },
+ { "CBB", 0x15000 },
+ { "CPU", 0x16000 },
+ { "AXI2APB", 0x00000 },
+ { "DBB0", 0x17000 },
+ { "DBB1", 0x18000 },
+};
+
+static const struct tegra234_target_lookup tegra241_cbb_target_map[] = {
{ "RSVD", 0x00000 },
{ "PCIE_C8", 0x51000 },
{ "PCIE_C9", 0x52000 },
@@ -1034,13 +1156,20 @@ static const struct tegra234_slave_lookup tegra241_cbb_slave_map[] = {
{ "AXI2APB_32", 0x8F000 },
};
+static const struct tegra234_fabric_lookup tegra241_cbb_fab_list[] = {
+ [T234_CBB_FABRIC_ID] = { "cbb-fabric", true,
+ tegra241_cbb_target_map, ARRAY_SIZE(tegra241_cbb_target_map) },
+ [T234_BPMP_FABRIC_ID] = { "bpmp-fabric", true,
+ tegra241_bpmp_target_map, ARRAY_SIZE(tegra241_cbb_target_map) },
+};
static const struct tegra234_cbb_fabric tegra241_cbb_fabric = {
- .name = "cbb-fabric",
- .master_id = tegra241_master_id,
- .slave_map = tegra241_cbb_slave_map,
- .max_slaves = ARRAY_SIZE(tegra241_cbb_slave_map),
+ .fab_id = T234_CBB_FABRIC_ID,
+ .fab_list = tegra241_cbb_fab_list,
+ .initiator_id = tegra241_initiator_id,
.errors = tegra241_cbb_errors,
.max_errors = ARRAY_SIZE(tegra241_cbb_errors),
+ .err_intr_enbl = 0x7,
+ .err_status_clr = 0x1ff007f,
.notifier_offset = 0x60000,
.off_mask_erd = 0x40004,
.firewall_base = 0x20000,
@@ -1048,30 +1177,302 @@ static const struct tegra234_cbb_fabric tegra241_cbb_fabric = {
.firewall_wr_ctl = 0x2368,
};
-static const struct tegra234_slave_lookup tegra241_bpmp_slave_map[] = {
- { "RSVD", 0x00000 },
- { "RSVD", 0x00000 },
- { "RSVD", 0x00000 },
- { "CBB", 0x15000 },
- { "CPU", 0x16000 },
- { "AXI2APB", 0x00000 },
- { "DBB0", 0x17000 },
- { "DBB1", 0x18000 },
-};
-
static const struct tegra234_cbb_fabric tegra241_bpmp_fabric = {
- .name = "bpmp-fabric",
- .master_id = tegra241_master_id,
- .slave_map = tegra241_bpmp_slave_map,
- .max_slaves = ARRAY_SIZE(tegra241_bpmp_slave_map),
+ .fab_id = T234_BPMP_FABRIC_ID,
+ .fab_list = tegra241_cbb_fab_list,
+ .initiator_id = tegra241_initiator_id,
.errors = tegra241_cbb_errors,
.max_errors = ARRAY_SIZE(tegra241_cbb_errors),
+ .err_intr_enbl = 0xf,
+ .err_status_clr = 0x1ff007f,
.notifier_offset = 0x19000,
.firewall_base = 0x30000,
.firewall_ctl = 0x8f0,
.firewall_wr_ctl = 0x8e8,
};
+static const char * const tegra264_initiator_id[] = {
+ [0x0] = "TZ",
+ [0x1] = "CCPLEX",
+ [0x2] = "ISC",
+ [0x3] = "BPMP_FW",
+ [0x4] = "AON",
+ [0x5] = "MSS_SEQ",
+ [0x6] = "GPCDMA_P",
+ [0x7] = "TSECA_NONSECURE",
+ [0x8] = "TSECA_LIGHTSECURE",
+ [0x9] = "TSECA_HEAVYSECURE",
+ [0xa] = "CORESIGHT",
+ [0xb] = "APE_0",
+ [0xc] = "APE_1",
+ [0xd] = "PEATRANS",
+ [0xe] = "JTAGM_DFT",
+ [0xf] = "RCE",
+ [0x10] = "DCE",
+ [0x11] = "PSC_FW_USER",
+ [0x12] = "PSC_FW_SUPERVISOR",
+ [0x13] = "PSC_FW_MACHINE",
+ [0x14] = "PSC_BOOT",
+ [0x15] = "BPMP_BOOT",
+ [0x16] = "GPU_0",
+ [0x17] = "GPU_1",
+ [0x18] = "GPU_2",
+ [0x19] = "GPU_3",
+ [0x1a] = "GPU_4",
+ [0x1b] = "PSC_EXT_BOOT",
+ [0x1c] = "PSC_EXT_RUNTIME",
+ [0x1d] = "OESP_EXT",
+ [0x1e] = "SB_EXT",
+ [0x1f] = "FSI_SAFETY_0",
+ [0x20] = "FSI_SAFETY_1",
+ [0x21] = "FSI_SAFETY_2",
+ [0x22] = "FSI_SAFETY_3",
+ [0x23] = "FSI_CHSM",
+ [0x24] = "RCE_1",
+ [0x25] = "BPMP_OEM_FW",
+ [0x26 ... 0x3d] = "RSVD",
+ [0x3e] = "CBB_SMN",
+ [0x3f] = "CBB_RSVD"
+};
+
+static const struct tegra234_target_lookup tegra264_top0_cbb_target_map[] = {
+ { "RSVD", 0x000000 },
+ { "CBB_CENTRAL", 0xC020000 },
+ { "AXI2APB_1", 0x80000 },
+ { "AXI2APB_10", 0x81000 },
+ { "AXI2APB_11", 0x82000 },
+ { "RSVD", 0x00000 },
+ { "RSVD", 0x00000 },
+ { "AXI2APB_14", 0x83000 },
+ { "AXI2APB_15", 0x84000 },
+ { "AXI2APB_16", 0x85000 },
+ { "AXI2APB_17", 0x86000 },
+ { "AXI2APB_2", 0x87000 },
+ { "AXI2APB_3", 0x88000 },
+ { "RSVD", 0x00000 },
+ { "AXI2APB_5", 0x8A000 },
+ { "AXI2APB_6", 0x8B000 },
+ { "AXI2APB_7", 0x8C000 },
+ { "AXI2APB_8", 0x8D000 },
+ { "AXI2APB_9", 0x8E000 },
+ { "FSI_SLAVE", 0x64000 },
+ { "DISP_USB_CBB_T", 0x65000 },
+ { "SYSTEM_CBB_T", 0x66000 },
+ { "UPHY0_CBB_T", 0x67000 },
+ { "VISION_CBB_T", 0x68000 },
+ { "CCPLEX_SLAVE", 0x69000 },
+ { "PCIE_C0", 0x6A000 },
+ { "SMN_UCF_RX_0", 0x6B000 },
+ { "SMN_UCF_RX_1", 0x6C000 },
+ { "AXI2APB_4", 0x89000 },
+};
+
+static const struct tegra234_target_lookup tegra264_sys_cbb_target_map[] = {
+ { "RSVD", 0x00000 },
+ { "AXI2APB_1", 0xE1000 },
+ { "RSVD", 0x00000 },
+ { "AON_SLAVE", 0x79000 },
+ { "APE_SLAVE", 0x73000 },
+ { "BPMP_SLAVE", 0x74000 },
+ { "OESP_SLAVE", 0x75000 },
+ { "PSC_SLAVE", 0x76000 },
+ { "SB_SLAVE", 0x7A000 },
+ { "SMN_SYSTEM_RX", 0x7B000 },
+ { "STM", 0x77000 },
+ { "RSVD", 0x00000 },
+ { "AXI2APB_3", 0xE3000 },
+ { "TOP_CBB_T", 0x7C000 },
+ { "AXI2APB_2", 0xE4000 },
+ { "AXI2APB_4", 0xE5000 },
+ { "AXI2APB_5", 0xE6000 },
+};
+
+static const struct tegra234_target_lookup tegra264_uphy0_cbb_target_map[] = {
+ [0 ... 20] = { "RSVD", 0x00000 },
+ { "AXI2APB_1", 0x71000 },
+ { "RSVD", 0x00000 },
+ { "AXI2APB_3", 0x75000 },
+ { "SMN_UPHY0_RX", 0x53000 },
+ { "RSVD", 0x00000 },
+ { "RSVD", 0x00000 },
+ { "RSVD", 0x00000 },
+ { "RSVD", 0x00000 },
+ { "PCIE_C4", 0x4B000 },
+ { "AXI2APB_2", 0x74000 },
+ { "AXI2APB_4", 0x76000 },
+ { "AXI2APB_5", 0x77000 },
+ { "RSVD", 0x00000 },
+ { "AXI2APB_7", 0x79000 },
+ { "PCIE_C2", 0x56000 },
+ { "RSVD", 0x00000 },
+ { "RSVD", 0x00000 },
+ { "PCIE_C1", 0x55000 },
+ { "RSVD", 0x00000 },
+ { "AXI2APB_10", 0x72000 },
+ { "AXI2APB_11", 0x7C000 },
+ { "AXI2APB_8", 0x7A000 },
+ { "AXI2APB_9", 0x7B000 },
+ { "RSVD", 0x00000 },
+ { "RSVD", 0x00000 },
+ { "PCIE_C5", 0x4E000 },
+ { "PCIE_C3", 0x58000 },
+ { "RSVD", 0x00000 },
+ { "ISC_SLAVE", 0x54000 },
+ { "TOP_CBB_T", 0x57000 },
+ { "AXI2APB_12", 0x7D000 },
+ { "AXI2APB_13", 0x70000 },
+ { "AXI2APB_6", 0x7E000 },
+};
+
+static const struct tegra234_target_lookup tegra264_vision_cbb_target_map[] = {
+ [0 ... 5] = { "RSVD", 0x0 },
+ { "HOST1X", 0x45000 },
+ { "RSVD", 0x00000 },
+ { "RSVD", 0x00000 },
+ { "AXI2APB_2", 0x71000 },
+ { "RSVD", 0x00000 },
+ { "RSVD", 0x00000 },
+ { "SMN_VISION_RX", 0x47000 },
+ [13 ... 19] = { "RSVD", 0x0 },
+ { "RCE_0_SLAVE", 0x4B000 },
+ { "RCE_1_SLAVE", 0x4C000 },
+ { "AXI2APB_1", 0x72000 },
+ { "AXI2APB_3", 0x73000 },
+ { "TOP_CBB_T", 0x4D000 },
+
+};
+
+static const struct tegra234_fabric_lookup tegra264_cbb_fab_list[] = {
+ [T264_SYSTEM_CBB_FABRIC_ID] = { "system-cbb-fabric", true,
+ tegra264_sys_cbb_target_map,
+ ARRAY_SIZE(tegra264_sys_cbb_target_map) },
+ [T264_TOP_0_CBB_FABRIC_ID] = { "top0-cbb-fabric", true,
+ tegra264_top0_cbb_target_map,
+ ARRAY_SIZE(tegra264_top0_cbb_target_map) },
+ [T264_VISION_CBB_FABRIC_ID] = { "vision-cbb-fabric", true,
+ tegra264_vision_cbb_target_map,
+ ARRAY_SIZE(tegra264_vision_cbb_target_map) },
+ [T264_DISP_USB_CBB_FABRIC_ID] = { "disp-usb-cbb-fabric" },
+ [T264_UPHY0_CBB_FABRIC_ID] = { "uphy0-cbb-fabric", true,
+ tegra264_uphy0_cbb_target_map,
+ ARRAY_SIZE(tegra264_uphy0_cbb_target_map) },
+ [T264_AON_FABRIC_ID] = { "aon-fabric" },
+ [T264_PSC_FABRIC_ID] = { "psc-fabric" },
+ [T264_OESP_FABRIC_ID] = { "oesp-fabric" },
+ [T264_APE_FABRIC_ID] = { "ape-fabirc" },
+ [T264_BPMP_FABRIC_ID] = { "bpmp-fabric" },
+ [T264_RCE_0_FABRIC_ID] = { "rce0-fabric" },
+ [T264_RCE_1_FABRIC_ID] = { "rce1-fabric" },
+ [T264_DCE_FABRIC_ID] = { "dce-fabric" },
+ [T264_FSI_FABRIC_ID] = { "fsi-fabric" },
+ [T264_ISC_FABRIC_ID] = { "isc-fabric" },
+ [T264_SB_FABRIC_ID] = { "sb-fabric" },
+ [T264_ISC_CPU_FABRIC_ID] = { "isc-cpu-fabric" },
+};
+
+static const struct tegra234_cbb_fabric tegra264_top0_cbb_fabric = {
+ .fab_id = T264_TOP_0_CBB_FABRIC_ID,
+ .fab_list = tegra264_cbb_fab_list,
+ .initiator_id = tegra264_initiator_id,
+ .errors = tegra241_cbb_errors,
+ .max_errors = ARRAY_SIZE(tegra241_cbb_errors),
+ .err_intr_enbl = 0x7,
+ .err_status_clr = 0x1ff007f,
+ .notifier_offset = 0x90000,
+ .off_mask_erd = 0x4a004,
+ .firewall_base = 0x3c0000,
+ .firewall_ctl = 0x5b0,
+ .firewall_wr_ctl = 0x5a8,
+};
+
+static const struct tegra234_cbb_fabric tegra264_sys_cbb_fabric = {
+ .fab_id = T264_SYSTEM_CBB_FABRIC_ID,
+ .fab_list = tegra264_cbb_fab_list,
+ .initiator_id = tegra264_initiator_id,
+ .errors = tegra241_cbb_errors,
+ .max_errors = ARRAY_SIZE(tegra241_cbb_errors),
+ .err_intr_enbl = 0xf,
+ .err_status_clr = 0x1ff007f,
+ .notifier_offset = 0x40000,
+ .firewall_base = 0x29c000,
+ .firewall_ctl = 0x170,
+ .firewall_wr_ctl = 0x168,
+};
+
+static const struct tegra234_cbb_fabric tegra264_uphy0_cbb_fabric = {
+ .fab_id = T264_UPHY0_CBB_FABRIC_ID,
+ .fab_list = tegra264_cbb_fab_list,
+ .initiator_id = tegra264_initiator_id,
+ .errors = tegra241_cbb_errors,
+ .max_errors = ARRAY_SIZE(tegra241_cbb_errors),
+ .err_intr_enbl = 0x1,
+ .err_status_clr = 0x1ff007f,
+ .notifier_offset = 0x80000,
+ .firewall_base = 0x360000,
+ .firewall_ctl = 0x590,
+ .firewall_wr_ctl = 0x588,
+};
+
+static const struct tegra234_cbb_fabric tegra264_vision_cbb_fabric = {
+ .fab_id = T264_VISION_CBB_FABRIC_ID,
+ .fab_list = tegra264_cbb_fab_list,
+ .initiator_id = tegra264_initiator_id,
+ .errors = tegra241_cbb_errors,
+ .max_errors = ARRAY_SIZE(tegra241_cbb_errors),
+ .err_intr_enbl = 0x1,
+ .err_status_clr = 0x1ff007f,
+ .notifier_offset = 0x80000,
+ .firewall_base = 0x290000,
+ .firewall_ctl = 0x5d0,
+ .firewall_wr_ctl = 0x5c8,
+};
+
+static const struct tegra234_fabric_lookup t254_cbb_fab_list[] = {
+ [T254_C2C_FABRIC_ID] = { "c2c-fabric", true },
+ [T254_DISP_CLUSTER_FABRIC_ID] = { "display-cluster-fabric", true },
+ [T254_GPU_FABRIC_ID] = { "gpu-fabric", true },
+};
+
+static const struct tegra234_cbb_fabric t254_c2c_fabric = {
+ .fab_id = T254_C2C_FABRIC_ID,
+ .fab_list = t254_cbb_fab_list,
+ .errors = tegra241_cbb_errors,
+ .max_errors = ARRAY_SIZE(tegra241_cbb_errors),
+ .err_intr_enbl = 0xf,
+ .err_status_clr = 0x1ff007f,
+ .notifier_offset = 0x50000,
+ .off_mask_erd = 0x14004,
+ .firewall_base = 0x40000,
+ .firewall_ctl = 0x9b0,
+ .firewall_wr_ctl = 0x9a8,
+};
+
+static const struct tegra234_cbb_fabric t254_disp_fabric = {
+ .fab_id = T254_DISP_CLUSTER_FABRIC_ID,
+ .fab_list = t254_cbb_fab_list,
+ .errors = tegra241_cbb_errors,
+ .max_errors = ARRAY_SIZE(tegra241_cbb_errors),
+ .err_intr_enbl = 0x1,
+ .err_status_clr = 0x1ff007f,
+ .notifier_offset = 0x50000,
+ .firewall_base = 0x30000,
+ .firewall_ctl = 0x810,
+ .firewall_wr_ctl = 0x808,
+};
+
+static const struct tegra234_cbb_fabric t254_gpu_fabric = {
+ .fab_id = T254_GPU_FABRIC_ID,
+ .fab_list = t254_cbb_fab_list,
+ .errors = tegra241_cbb_errors,
+ .max_errors = ARRAY_SIZE(tegra241_cbb_errors),
+ .err_intr_enbl = 0x1f,
+ .err_status_clr = 0x1ff007f,
+ .notifier_offset = 0x50000,
+ .firewall_base = 0x30000,
+ .firewall_ctl = 0x930,
+ .firewall_wr_ctl = 0x928,
+};
+
static const struct of_device_id tegra234_cbb_dt_ids[] = {
{ .compatible = "nvidia,tegra234-cbb-fabric", .data = &tegra234_cbb_fabric },
{ .compatible = "nvidia,tegra234-aon-fabric", .data = &tegra234_aon_fabric },
@@ -1079,6 +1480,10 @@ static const struct of_device_id tegra234_cbb_dt_ids[] = {
{ .compatible = "nvidia,tegra234-dce-fabric", .data = &tegra234_dce_fabric },
{ .compatible = "nvidia,tegra234-rce-fabric", .data = &tegra234_rce_fabric },
{ .compatible = "nvidia,tegra234-sce-fabric", .data = &tegra234_sce_fabric },
+ { .compatible = "nvidia,tegra264-sys-cbb-fabric", .data = &tegra264_sys_cbb_fabric },
+ { .compatible = "nvidia,tegra264-top0-cbb-fabric", .data = &tegra264_top0_cbb_fabric },
+ { .compatible = "nvidia,tegra264-uphy0-cbb-fabric", .data = &tegra264_uphy0_cbb_fabric },
+ { .compatible = "nvidia,tegra264-vision-cbb-fabric", .data = &tegra264_vision_cbb_fabric },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, tegra234_cbb_dt_ids);
@@ -1092,6 +1497,9 @@ struct tegra234_cbb_acpi_uid {
static const struct tegra234_cbb_acpi_uid tegra234_cbb_acpi_uids[] = {
{ "NVDA1070", "1", &tegra241_cbb_fabric },
{ "NVDA1070", "2", &tegra241_bpmp_fabric },
+ { "NVDA1070", "3", &t254_c2c_fabric },
+ { "NVDA1070", "4", &t254_disp_fabric },
+ { "NVDA1070", "5", &t254_gpu_fabric },
{ },
};
@@ -1174,18 +1582,13 @@ static int tegra234_cbb_probe(struct platform_device *pdev)
return tegra_cbb_register(&cbb->base);
}
-static int tegra234_cbb_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
static int __maybe_unused tegra234_cbb_resume_noirq(struct device *dev)
{
struct tegra234_cbb *cbb = dev_get_drvdata(dev);
tegra234_cbb_error_enable(&cbb->base);
- dev_dbg(dev, "%s resumed\n", cbb->fabric->name);
+ dev_dbg(dev, "%s resumed\n", cbb->fabric->fab_list[cbb->fabric->fab_id].name);
return 0;
}
@@ -1196,7 +1599,6 @@ static const struct dev_pm_ops tegra234_cbb_pm = {
static struct platform_driver tegra234_cbb_driver = {
.probe = tegra234_cbb_probe,
- .remove = tegra234_cbb_remove,
.driver = {
.name = "tegra234-cbb",
.of_match_table = tegra234_cbb_dt_ids,
@@ -1218,4 +1620,3 @@ static void __exit tegra234_cbb_exit(void)
module_exit(tegra234_cbb_exit);
MODULE_DESCRIPTION("Control Backbone 2.0 error handling driver for Tegra234");
-MODULE_LICENSE("GPL");
diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c
index dff6d5ef4e46..d82b7670abb7 100644
--- a/drivers/soc/tegra/common.c
+++ b/drivers/soc/tegra/common.c
@@ -27,17 +27,7 @@ static const struct of_device_id tegra_machine_match[] = {
bool soc_is_tegra(void)
{
- const struct of_device_id *match;
- struct device_node *root;
-
- root = of_find_node_by_path("/");
- if (!root)
- return false;
-
- match = of_match_node(tegra_machine_match, root);
- of_node_put(root);
-
- return match != NULL;
+ return of_machine_device_match(tegra_machine_match);
}
static int tegra_core_dev_init_opp_state(struct device *dev)
diff --git a/drivers/soc/tegra/flowctrl.c b/drivers/soc/tegra/flowctrl.c
index 5db919d96aba..221202db3313 100644
--- a/drivers/soc/tegra/flowctrl.c
+++ b/drivers/soc/tegra/flowctrl.c
@@ -156,10 +156,8 @@ void flowctrl_cpu_suspend_exit(unsigned int cpuid)
static int tegra_flowctrl_probe(struct platform_device *pdev)
{
void __iomem *base = tegra_flowctrl_base;
- struct resource *res;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- tegra_flowctrl_base = devm_ioremap_resource(&pdev->dev, res);
+ tegra_flowctrl_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(tegra_flowctrl_base))
return PTR_ERR(tegra_flowctrl_base);
diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c
index f02953f793e9..74d2fedea71c 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra.c
@@ -1,13 +1,15 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2013-2022, NVIDIA CORPORATION. All rights reserved.
+ * 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;
@@ -125,23 +149,49 @@ static int tegra_fuse_probe(struct platform_device *pdev)
return err;
/* take over the memory region from the early initialization */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ fuse->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ if (IS_ERR(fuse->base))
+ return PTR_ERR(fuse->base);
fuse->phys = res->start;
- fuse->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(fuse->base)) {
- err = PTR_ERR(fuse->base);
- return err;
- }
- 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);
+
+ 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;
@@ -166,7 +216,7 @@ static int tegra_fuse_probe(struct platform_device *pdev)
nvmem.nkeepout = fuse->soc->num_keepouts;
nvmem.type = NVMEM_TYPE_OTP;
nvmem.read_only = true;
- nvmem.root_only = true;
+ nvmem.root_only = false;
nvmem.reg_read = tegra_fuse_read;
nvmem.size = fuse->soc->info->size;
nvmem.word_size = 4;
@@ -182,12 +232,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
@@ -265,10 +311,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,
},
@@ -290,7 +343,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))
@@ -346,7 +408,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)
{
@@ -373,7 +436,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;
@@ -410,6 +473,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();
@@ -500,22 +564,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);
-
- if (fuse->soc->lookups) {
- size_t size = sizeof(*fuse->lookups) * fuse->soc->num_lookups;
+ tegra_fuse_print_sku_info(&tegra_sku_info);
- 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-tegra20.c b/drivers/soc/tegra/fuse/fuse-tegra20.c
index 12503f563e36..fdecf7b7c246 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra20.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra20.c
@@ -14,7 +14,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/random.h>
diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c
index 932a03c64534..524fa1b0cd3d 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra30.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra30.c
@@ -10,8 +10,6 @@
#include <linux/kernel.h>
#include <linux/nvmem-consumer.h>
#include <linux/nvmem-provider.h>
-#include <linux/of_device.h>
-#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/random.h>
@@ -40,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))
@@ -118,6 +117,124 @@ const struct tegra_fuse_soc tegra30_fuse_soc = {
#endif
#ifdef CONFIG_ARCH_TEGRA_114_SOC
+static const struct nvmem_cell_info tegra114_fuse_cells[] = {
+ {
+ .name = "tsensor-cpu1",
+ .offset = 0x084,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-cpu2",
+ .offset = 0x088,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-common",
+ .offset = 0x08c,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-cpu0",
+ .offset = 0x098,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "xusb-pad-calibration",
+ .offset = 0x0f0,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-cpu3",
+ .offset = 0x12c,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-gpu",
+ .offset = 0x154,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-mem0",
+ .offset = 0x158,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-mem1",
+ .offset = 0x15c,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ }, {
+ .name = "tsensor-pllx",
+ .offset = 0x160,
+ .bytes = 4,
+ .bit_offset = 0,
+ .nbits = 32,
+ },
+};
+
+static const struct nvmem_cell_lookup tegra114_fuse_lookups[] = {
+ {
+ .nvmem_name = "fuse",
+ .cell_name = "xusb-pad-calibration",
+ .dev_id = "7009f000.padctl",
+ .con_id = "calibration",
+ }, {
+ .nvmem_name = "fuse",
+ .cell_name = "tsensor-common",
+ .dev_id = "700e2000.thermal-sensor",
+ .con_id = "common",
+ }, {
+ .nvmem_name = "fuse",
+ .cell_name = "tsensor-cpu0",
+ .dev_id = "700e2000.thermal-sensor",
+ .con_id = "cpu0",
+ }, {
+ .nvmem_name = "fuse",
+ .cell_name = "tsensor-cpu1",
+ .dev_id = "700e2000.thermal-sensor",
+ .con_id = "cpu1",
+ }, {
+ .nvmem_name = "fuse",
+ .cell_name = "tsensor-cpu2",
+ .dev_id = "700e2000.thermal-sensor",
+ .con_id = "cpu2",
+ }, {
+ .nvmem_name = "fuse",
+ .cell_name = "tsensor-cpu3",
+ .dev_id = "700e2000.thermal-sensor",
+ .con_id = "cpu3",
+ }, {
+ .nvmem_name = "fuse",
+ .cell_name = "tsensor-mem0",
+ .dev_id = "700e2000.thermal-sensor",
+ .con_id = "mem0",
+ }, {
+ .nvmem_name = "fuse",
+ .cell_name = "tsensor-mem1",
+ .dev_id = "700e2000.thermal-sensor",
+ .con_id = "mem1",
+ }, {
+ .nvmem_name = "fuse",
+ .cell_name = "tsensor-gpu",
+ .dev_id = "700e2000.thermal-sensor",
+ .con_id = "gpu",
+ }, {
+ .nvmem_name = "fuse",
+ .cell_name = "tsensor-pllx",
+ .dev_id = "700e2000.thermal-sensor",
+ .con_id = "pllx",
+ },
+};
+
static const struct tegra_fuse_info tegra114_fuse_info = {
.read = tegra30_fuse_read,
.size = 0x2a0,
@@ -128,6 +245,10 @@ const struct tegra_fuse_soc tegra114_fuse_soc = {
.init = tegra30_fuse_init,
.speedo_init = tegra114_init_speedo_data,
.info = &tegra114_fuse_info,
+ .lookups = tegra114_fuse_lookups,
+ .num_lookups = ARRAY_SIZE(tegra114_fuse_lookups),
+ .cells = tegra114_fuse_cells,
+ .num_cells = ARRAY_SIZE(tegra114_fuse_cells),
.soc_attr_group = &tegra_soc_attr_group,
.clk_suspend_on = false,
};
@@ -648,22 +769,27 @@ 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 }
};
static const struct tegra_fuse_info tegra234_fuse_info = {
.read = tegra30_fuse_read,
- .size = 0x98c,
+ .size = 0xf90,
.spare = 0x280,
};
@@ -680,3 +806,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/speedo-tegra210.c b/drivers/soc/tegra/fuse/speedo-tegra210.c
index 695d0b7f9a8a..06c2bcbee573 100644
--- a/drivers/soc/tegra/fuse/speedo-tegra210.c
+++ b/drivers/soc/tegra/fuse/speedo-tegra210.c
@@ -65,27 +65,52 @@ static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info,
sku_info->gpu_speedo_id = 0;
*threshold = THRESHOLD_INDEX_0;
- switch (sku) {
- case 0x00: /* Engineering SKU */
- case 0x01: /* Engineering SKU */
- case 0x07:
- case 0x17:
- case 0x27:
- if (speedo_rev >= 2)
+ if (sku_info->revision >= TEGRA_REVISION_A02) {
+ switch (sku) {
+ case 0x00: /* Engineering SKU */
+ case 0x01: /* Engineering SKU */
+ case 0x13:
+ sku_info->cpu_speedo_id = 5;
+ sku_info->gpu_speedo_id = 2;
+ break;
+
+ case 0x07:
+ case 0x17:
+ case 0x1F:
+ sku_info->cpu_speedo_id = 7;
+ sku_info->gpu_speedo_id = 2;
+ break;
+
+ case 0x27:
+ sku_info->cpu_speedo_id = 1;
+ sku_info->gpu_speedo_id = 2;
+ break;
+
+ case 0x83:
+ sku_info->cpu_speedo_id = 3;
+ sku_info->gpu_speedo_id = 3;
+ break;
+
+ case 0x87:
+ sku_info->cpu_speedo_id = 2;
sku_info->gpu_speedo_id = 1;
- break;
-
- case 0x13:
- if (speedo_rev >= 2)
- sku_info->gpu_speedo_id = 1;
-
- sku_info->cpu_speedo_id = 1;
- break;
-
- default:
+ break;
+
+ case 0x8F:
+ sku_info->soc_speedo_id = 2;
+ sku_info->cpu_speedo_id = 9;
+ sku_info->gpu_speedo_id = 2;
+ break;
+
+ default:
+ pr_err("Tegra210: unknown revision 2 or newer SKU %#04x\n", sku);
+ /* Using the default for the error case */
+ break;
+ }
+ } else if (sku == 0x00 || sku == 0x01 || sku == 0x07 || sku == 0x13 || sku == 0x17) {
+ sku_info->gpu_speedo_id = 1;
+ } else {
pr_err("Tegra210: unknown SKU %#04x\n", sku);
- /* Using the default for the error case */
- break;
}
}
diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c
index 4591c5bcb690..0ce94fdc536f 100644
--- a/drivers/soc/tegra/fuse/tegra-apbmisc.c
+++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c
@@ -1,16 +1,18 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ * 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>
-#include <linux/io.h>
-#include <soc/tegra/fuse.h>
#include <soc/tegra/common.h>
+#include <soc/tegra/fuse.h>
#include "fuse.h"
@@ -62,6 +64,8 @@ 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;
@@ -124,6 +128,7 @@ static const struct of_device_id apbmisc_match[] __initconst = {
{ .compatible = "nvidia,tegra186-misc", },
{ .compatible = "nvidia,tegra194-misc", },
{ .compatible = "nvidia,tegra234-misc", },
+ { .compatible = "nvidia,tegra264-misc", },
{},
};
@@ -159,9 +164,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;
@@ -218,23 +248,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 cf4cfbf9f7c5..f3760a3b3026 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-2022, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved.
*
* Author:
* Colin Cross <ccross@google.com>
@@ -47,6 +47,7 @@
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/string_choices.h>
#include <linux/syscore_ops.h>
#include <soc/tegra/common.h>
@@ -177,6 +178,7 @@
/* Tegra186 and later */
#define WAKE_AOWAKE_CNTRL(x) (0x000 + ((x) << 2))
#define WAKE_AOWAKE_CNTRL_LEVEL (1 << 3)
+#define WAKE_AOWAKE_CNTRL_SR_CAPTURE_EN (1 << 1)
#define WAKE_AOWAKE_MASK_W(x) (0x180 + ((x) << 2))
#define WAKE_AOWAKE_MASK_R(x) (0x300 + ((x) << 2))
#define WAKE_AOWAKE_STATUS_W(x) (0x30c + ((x) << 2))
@@ -191,6 +193,8 @@
#define WAKE_AOWAKE_CTRL 0x4f4
#define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0)
+#define SW_WAKE_ID 83 /* wake83 */
+
/* for secure PMC */
#define TEGRA_SMC_PMC 0xc2fffe00
#define TEGRA_SMC_PMC_READ 0xaa
@@ -355,6 +359,7 @@ struct tegra_pmc_soc {
void (*setup_irq_polarity)(struct tegra_pmc *pmc,
struct device_node *np,
bool invert);
+ void (*set_wake_filters)(struct tegra_pmc *pmc);
int (*irq_set_wake)(struct irq_data *data, unsigned int on);
int (*irq_set_type)(struct irq_data *data, unsigned int type);
int (*powergate_set)(struct tegra_pmc *pmc, unsigned int id,
@@ -380,6 +385,7 @@ struct tegra_pmc_soc {
bool has_blink_output;
bool has_usb_sleepwalk;
bool supports_core_domain;
+ bool has_single_mmio_aperture;
};
/**
@@ -392,7 +398,6 @@ struct tegra_pmc_soc {
* @clk: pointer to pclk clock
* @soc: pointer to SoC data structure
* @tz_only: flag specifying if the PMC can only be accessed via TrustZone
- * @debugfs: pointer to debugfs entry
* @rate: currently configured rate of pclk
* @suspend_mode: lowest suspend mode available
* @cpu_good_time: CPU power good time (in microseconds)
@@ -413,12 +418,12 @@ struct tegra_pmc_soc {
* @irq: chip implementation for the IRQ domain
* @clk_nb: pclk clock changes handler
* @core_domain_state_synced: flag marking the core domain's state as synced
- * @core_domain_registered: flag marking the core domain as registered
* @wake_type_level_map: Bitmap indicating level type for non-dual edge wakes
* @wake_type_dual_edge_map: Bitmap indicating if a wake is dual-edge or not
* @wake_sw_status_map: Bitmap to hold raw status of wakes without mask
* @wake_cntrl_level_map: Bitmap to hold wake levels to be programmed in
* cntrl register associated with each wake during system suspend.
+ * @syscore: syscore suspend/resume callbacks
*/
struct tegra_pmc {
struct device *dev;
@@ -427,7 +432,6 @@ struct tegra_pmc {
void __iomem *aotag;
void __iomem *scratch;
struct clk *clk;
- struct dentry *debugfs;
const struct tegra_pmc_soc *soc;
bool tz_only;
@@ -458,13 +462,12 @@ struct tegra_pmc {
struct notifier_block clk_nb;
bool core_domain_state_synced;
- bool core_domain_registered;
unsigned long *wake_type_level_map;
unsigned long *wake_type_dual_edge_map;
unsigned long *wake_sw_status_map;
unsigned long *wake_cntrl_level_map;
- struct syscore_ops syscore;
+ struct syscore syscore;
};
static struct tegra_pmc *pmc = &(struct tegra_pmc) {
@@ -1178,7 +1181,7 @@ static int powergate_show(struct seq_file *s, void *data)
continue;
seq_printf(s, " %9s %7s\n", pmc->soc->powergates[i],
- status ? "yes" : "no");
+ str_yes_no(status));
}
return 0;
@@ -1186,16 +1189,6 @@ static int powergate_show(struct seq_file *s, void *data)
DEFINE_SHOW_ATTRIBUTE(powergate);
-static int tegra_powergate_debugfs_init(void)
-{
- pmc->debugfs = debugfs_create_file("powergate", S_IRUGO, NULL, NULL,
- &powergate_fops);
- if (!pmc->debugfs)
- return -ENOMEM;
-
- return 0;
-}
-
static int tegra_powergate_of_get_clks(struct tegra_powergate *pg,
struct device_node *np)
{
@@ -1240,7 +1233,7 @@ err:
}
static int tegra_powergate_of_get_resets(struct tegra_powergate *pg,
- struct device_node *np, bool off)
+ struct device_node *np)
{
struct device *dev = pg->pmc->dev;
int err;
@@ -1255,22 +1248,6 @@ static int tegra_powergate_of_get_resets(struct tegra_powergate *pg,
err = reset_control_acquire(pg->reset);
if (err < 0) {
pr_err("failed to acquire resets: %d\n", err);
- goto out;
- }
-
- if (off) {
- err = reset_control_assert(pg->reset);
- } else {
- err = reset_control_deassert(pg->reset);
- if (err < 0)
- goto out;
-
- reset_control_release(pg->reset);
- }
-
-out:
- if (err) {
- reset_control_release(pg->reset);
reset_control_put(pg->reset);
}
@@ -1303,6 +1280,7 @@ static int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
pg->id = id;
pg->genpd.name = np->name;
+ pg->genpd.flags = GENPD_FLAG_NO_SYNC_STATE;
pg->genpd.power_off = tegra_genpd_power_off;
pg->genpd.power_on = tegra_genpd_power_on;
pg->pmc = pmc;
@@ -1315,20 +1293,43 @@ static int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
goto set_available;
}
- err = tegra_powergate_of_get_resets(pg, np, off);
+ err = tegra_powergate_of_get_resets(pg, np);
if (err < 0) {
dev_err(dev, "failed to get resets for %pOFn: %d\n", np, err);
goto remove_clks;
}
- if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) {
- if (off)
- WARN_ON(tegra_powergate_power_up(pg, true));
+ /*
+ * If the power-domain is off, then ensure the resets are asserted.
+ * If the power-domain is on, then power down to ensure that when is
+ * it turned on the power-domain, clocks and resets are all in the
+ * expected state.
+ */
+ if (off) {
+ err = reset_control_assert(pg->reset);
+ if (err) {
+ pr_err("failed to assert resets: %d\n", err);
+ goto remove_resets;
+ }
+ } else {
+ err = tegra_powergate_power_down(pg);
+ if (err) {
+ dev_err(dev, "failed to turn off PM domain %s: %d\n",
+ pg->genpd.name, err);
+ goto remove_resets;
+ }
+ }
+ /*
+ * If PM_GENERIC_DOMAINS is not enabled, power-on
+ * the domain and skip the genpd registration.
+ */
+ if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) {
+ WARN_ON(tegra_powergate_power_up(pg, true));
goto remove_resets;
}
- err = pm_genpd_init(&pg->genpd, NULL, off);
+ err = pm_genpd_init(&pg->genpd, NULL, true);
if (err < 0) {
dev_err(dev, "failed to initialise PM domain %pOFn: %d\n", np,
err);
@@ -1401,13 +1402,6 @@ tegra_pmc_core_pd_set_performance_state(struct generic_pm_domain *genpd,
return 0;
}
-static unsigned int
-tegra_pmc_core_pd_opp_to_performance_state(struct generic_pm_domain *genpd,
- struct dev_pm_opp *opp)
-{
- return dev_pm_opp_get_level(opp);
-}
-
static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np)
{
struct generic_pm_domain *genpd;
@@ -1419,8 +1413,8 @@ static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np)
return -ENOMEM;
genpd->name = "core";
+ genpd->flags = GENPD_FLAG_NO_SYNC_STATE;
genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state;
- genpd->opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state;
err = devm_pm_opp_set_regulators(pmc->dev, rname);
if (err)
@@ -1439,8 +1433,6 @@ static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np)
goto remove_genpd;
}
- pmc->core_domain_registered = true;
-
return 0;
remove_genpd:
@@ -1453,7 +1445,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;
/*
@@ -1472,12 +1464,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",
@@ -1489,10 +1479,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);
@@ -1793,30 +1781,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)
{
@@ -2416,6 +2380,17 @@ static int tegra210_pmc_irq_set_type(struct irq_data *data, unsigned int type)
return 0;
}
+static void tegra186_pmc_set_wake_filters(struct tegra_pmc *pmc)
+{
+ u32 value;
+
+ /* SW Wake (wake83) needs SR_CAPTURE filter to be enabled */
+ value = readl(pmc->wake + WAKE_AOWAKE_CNTRL(SW_WAKE_ID));
+ value |= WAKE_AOWAKE_CNTRL_SR_CAPTURE_EN;
+ writel(value, pmc->wake + WAKE_AOWAKE_CNTRL(SW_WAKE_ID));
+ dev_dbg(pmc->dev, "WAKE_AOWAKE_CNTRL_83 = 0x%x\n", value);
+}
+
static int tegra186_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
{
struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
@@ -2531,8 +2506,8 @@ static int tegra_pmc_irq_init(struct tegra_pmc *pmc)
pmc->irq.irq_set_type = pmc->soc->irq_set_type;
pmc->irq.irq_set_wake = pmc->soc->irq_set_wake;
- pmc->domain = irq_domain_add_hierarchy(parent, 0, 96, pmc->dev->of_node,
- &tegra_pmc_irq_domain_ops, pmc);
+ pmc->domain = irq_domain_create_hierarchy(parent, 0, 96, dev_fwnode(pmc->dev),
+ &tegra_pmc_irq_domain_ops, pmc);
if (!pmc->domain) {
dev_err(pmc->dev, "failed to allocate domain\n");
return -ENOMEM;
@@ -2914,31 +2889,36 @@ 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);
- if (IS_ERR(pmc->aotag))
- return PTR_ERR(pmc->aotag);
- } else {
- pmc->aotag = base;
- }
+ /* "aotag" is an optional aperture */
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "aotag");
+ if (res) {
+ pmc->aotag = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pmc->aotag))
+ return PTR_ERR(pmc->aotag);
+ } else {
+ pmc->aotag = NULL;
+ }
- 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");
@@ -2950,12 +2930,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,
@@ -2989,7 +2972,8 @@ static int tegra_pmc_probe(struct platform_device *pdev)
*/
if (pmc->clk) {
pmc->clk_nb.notifier_call = tegra_pmc_clk_notify_cb;
- err = clk_notifier_register(pmc->clk, &pmc->clk_nb);
+ err = devm_clk_notifier_register(&pdev->dev, pmc->clk,
+ &pmc->clk_nb);
if (err) {
dev_err(&pdev->dev,
"failed to register clk notifier\n");
@@ -3011,19 +2995,13 @@ static int tegra_pmc_probe(struct platform_device *pdev)
tegra_pmc_reset_sysfs_init(pmc);
- if (IS_ENABLED(CONFIG_DEBUG_FS)) {
- err = tegra_powergate_debugfs_init();
- if (err < 0)
- goto cleanup_sysfs;
- }
-
err = tegra_pmc_pinctrl_init(pmc);
if (err)
- goto cleanup_debugfs;
+ goto cleanup_sysfs;
err = tegra_pmc_regmap_init(pmc);
if (err < 0)
- goto cleanup_debugfs;
+ goto cleanup_sysfs;
err = tegra_powergate_init(pmc, pdev->dev.of_node);
if (err < 0)
@@ -3042,16 +3020,19 @@ static int tegra_pmc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pmc);
tegra_pm_init_suspend();
+ /* Some wakes require specific filter configuration */
+ if (pmc->soc->set_wake_filters)
+ pmc->soc->set_wake_filters(pmc);
+
+ debugfs_create_file("powergate", 0444, NULL, NULL, &powergate_fops);
+
return 0;
cleanup_powergates:
tegra_powergate_remove_all(pdev->dev.of_node);
-cleanup_debugfs:
- debugfs_remove(pmc->debugfs);
cleanup_sysfs:
device_remove_file(&pdev->dev, &dev_attr_reset_reason);
device_remove_file(&pdev->dev, &dev_attr_reset_level);
- clk_notifier_unregister(pmc->clk, &pmc->clk_nb);
return err;
}
@@ -3174,7 +3155,7 @@ static void tegra186_pmc_process_wake_events(struct tegra_pmc *pmc, unsigned int
}
}
-static void tegra186_pmc_wake_syscore_resume(void)
+static void tegra186_pmc_wake_syscore_resume(void *data)
{
u32 status, mask;
unsigned int i;
@@ -3187,7 +3168,7 @@ static void tegra186_pmc_wake_syscore_resume(void)
}
}
-static int tegra186_pmc_wake_syscore_suspend(void)
+static int tegra186_pmc_wake_syscore_suspend(void *data)
{
wke_read_sw_wake_status(pmc);
@@ -3206,6 +3187,11 @@ static int tegra186_pmc_wake_syscore_suspend(void)
return 0;
}
+static const struct syscore_ops tegra186_pmc_wake_syscore_ops = {
+ .suspend = tegra186_pmc_wake_syscore_suspend,
+ .resume = tegra186_pmc_wake_syscore_resume,
+};
+
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
static int tegra_pmc_suspend(struct device *dev)
{
@@ -3331,6 +3317,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[] = {
@@ -3392,6 +3379,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[] = {
@@ -3449,6 +3437,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[] = {
@@ -3593,6 +3582,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[] = {
@@ -3756,6 +3746,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[] = {
@@ -3851,10 +3842,8 @@ static const struct tegra_pmc_regs tegra186_pmc_regs = {
static void tegra186_pmc_init(struct tegra_pmc *pmc)
{
- pmc->syscore.suspend = tegra186_pmc_wake_syscore_suspend;
- pmc->syscore.resume = tegra186_pmc_wake_syscore_resume;
-
- register_syscore_ops(&pmc->syscore);
+ pmc->syscore.ops = &tegra186_pmc_wake_syscore_ops;
+ register_syscore(&pmc->syscore);
}
static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
@@ -3938,6 +3927,7 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
.regs = &tegra186_pmc_regs,
.init = tegra186_pmc_init,
.setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
+ .set_wake_filters = tegra186_pmc_set_wake_filters,
.irq_set_wake = tegra186_pmc_irq_set_wake,
.irq_set_type = tegra186_pmc_irq_set_type,
.reset_sources = tegra186_reset_sources,
@@ -3952,6 +3942,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[] = {
@@ -4092,6 +4083,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),
@@ -4122,6 +4114,7 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = {
.regs = &tegra194_pmc_regs,
.init = tegra186_pmc_init,
.setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
+ .set_wake_filters = tegra186_pmc_set_wake_filters,
.irq_set_wake = tegra186_pmc_irq_set_wake,
.irq_set_type = tegra186_pmc_irq_set_type,
.reset_sources = tegra194_reset_sources,
@@ -4136,6 +4129,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[] = {
@@ -4225,8 +4219,20 @@ 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)),
TEGRA_WAKE_IRQ("rtc", 73, 10),
+ TEGRA_WAKE_IRQ("usb3-port-0", 76, 167),
+ TEGRA_WAKE_IRQ("usb3-port-1", 77, 167),
+ TEGRA_WAKE_IRQ("usb3-port-2-3", 78, 167),
+ TEGRA_WAKE_IRQ("usb2-port-0", 79, 167),
+ TEGRA_WAKE_IRQ("usb2-port-1", 80, 167),
+ TEGRA_WAKE_IRQ("usb2-port-2", 81, 167),
+ TEGRA_WAKE_IRQ("usb2-port-3", 82, 167),
+ TEGRA_WAKE_IRQ("sw-wake", SW_WAKE_ID, 179),
};
static const struct tegra_pmc_soc tegra234_pmc_soc = {
@@ -4247,6 +4253,7 @@ static const struct tegra_pmc_soc tegra234_pmc_soc = {
.regs = &tegra234_pmc_regs,
.init = tegra186_pmc_init,
.setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
+ .set_wake_filters = tegra186_pmc_set_wake_filters,
.irq_set_wake = tegra186_pmc_irq_set_wake,
.irq_set_type = tegra186_pmc_irq_set_type,
.reset_sources = tegra234_reset_sources,
@@ -4260,9 +4267,131 @@ 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 tegra_pmc_regs tegra264_pmc_regs = {
+ .scratch0 = 0x684,
+ .rst_status = 0x4,
+ .rst_source_shift = 0x2,
+ .rst_source_mask = 0x1fc,
+ .rst_level_shift = 0x0,
+ .rst_level_mask = 0x3,
+};
+
+static const char * const tegra264_reset_sources[] = {
+ "SYS_RESET_N", /* 0x0 */
+ "CSDC_RTC_XTAL",
+ "VREFRO_POWER_BAD",
+ "SCPM_SOC_XTAL",
+ "SCPM_RTC_XTAL",
+ "FMON_32K",
+ "FMON_OSC",
+ "POD_RTC",
+ "POD_IO", /* 0x8 */
+ "POD_PLUS_IO_SPLL",
+ "POD_PLUS_SOC",
+ "VMON_PLUS_UV",
+ "VMON_PLUS_OV",
+ "FUSECRC_FAULT",
+ "OSC_FAULT",
+ "BPMP_BOOT_FAULT",
+ "SCPM_BPMP_CORE_CLK", /* 0x10 */
+ "SCPM_PSC_SE_CLK",
+ "VMON_SOC_MIN",
+ "VMON_SOC_MAX",
+ "VMON_MSS_MIN",
+ "VMON_MSS_MAX",
+ "POD_PLUS_IO_VMON",
+ "NVJTAG_SEL_MONITOR",
+ "NV_THERM_FAULT", /* 0x18 */
+ "FSI_THERM_FAULT",
+ "PSC_SW",
+ "SCPM_OESP_SE_CLK",
+ "SCPM_SB_SE_CLK",
+ "POD_CPU",
+ "POD_GPU",
+ "DCLS_GPU",
+ "POD_MSS", /* 0x20 */
+ "FMON_FSI",
+ "POD_FSI",
+ "VMON_FSI_MIN",
+ "VMON_FSI_MAX",
+ "VMON_CPU0_MIN",
+ "VMON_CPU0_MAX",
+ "BPMP_FMON",
+ "AO_WDT_POR", /* 0x28 */
+ "BPMP_WDT_POR",
+ "AO_TKE_WDT_POR",
+ "RCE0_WDT_POR",
+ "RCE1_WDT_POR",
+ "DCE_WDT_POR",
+ "FSI_R5_WDT_POR",
+ "FSI_R52_0_WDT_POR",
+ "FSI_R52_1_WDT_POR", /* 0x30 */
+ "FSI_R52_2_WDT_POR",
+ "FSI_R52_3_WDT_POR",
+ "TOP_0_WDT_POR",
+ "TOP_1_WDT_POR",
+ "TOP_2_WDT_POR",
+ "APE_C0_WDT_POR",
+ "APE_C1_WDT_POR",
+ "GPU_TKE_WDT_POR", /* 0x38 */
+ "PSC_WDT_POR",
+ "OESP_WDT_POR",
+ "SB_WDT_POR",
+ "SW_MAIN",
+ "L0L1_RST_OUT_N",
+ "FSI_HSM",
+ "CSITE_SW",
+ "AO_WDT_DBG", /* 0x40 */
+ "BPMP_WDT_DBG",
+ "AO_TKE_WDT_DBG",
+ "RCE0_WDT_DBG",
+ "RCE1_WDT_DBG",
+ "DCE_WDT_DBG",
+ "FSI_R5_WDT_DBG",
+ "FSI_R52_0_WDT_DBG",
+ "FSI_R52_1_WDT_DBG", /* 0x48 */
+ "FSI_R52_2_WDT_DBG",
+ "FSI_R52_3_WDT_DBG",
+ "TOP_0_WDT_DBG",
+ "TOP_1_WDT_DBG",
+ "TOP_2_WDT_DBG",
+ "APE_C0_WDT_DBG",
+ "APE_C1_WDT_DBG",
+ "PSC_WDT_DBG", /* 0x50 */
+ "OESP_WDT_DBG",
+ "SB_WDT_DBG",
+ "TSC_0_WDT_DBG",
+ "TSC_1_WDT_DBG",
+ "L2_RST_OUT_N",
+ "SC7"
+};
+
+static const struct tegra_wake_event tegra264_wake_events[] = {
+};
+
+static const struct tegra_pmc_soc tegra264_pmc_soc = {
+ .has_impl_33v_pwr = true,
+ .regs = &tegra264_pmc_regs,
+ .init = tegra186_pmc_init,
+ .setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
+ .set_wake_filters = tegra186_pmc_set_wake_filters,
+ .irq_set_wake = tegra186_pmc_irq_set_wake,
+ .irq_set_type = tegra186_pmc_irq_set_type,
+ .reset_sources = tegra264_reset_sources,
+ .num_reset_sources = ARRAY_SIZE(tegra264_reset_sources),
+ .reset_levels = tegra186_reset_levels,
+ .num_reset_levels = ARRAY_SIZE(tegra186_reset_levels),
+ .wake_events = tegra264_wake_events,
+ .num_wake_events = ARRAY_SIZE(tegra264_wake_events),
+ .max_wake_events = 128,
+ .max_wake_vectors = 4,
};
static const struct of_device_id tegra_pmc_match[] = {
+ { .compatible = "nvidia,tegra264-pmc", .data = &tegra264_pmc_soc },
{ .compatible = "nvidia,tegra234-pmc", .data = &tegra234_pmc_soc },
{ .compatible = "nvidia,tegra194-pmc", .data = &tegra194_pmc_soc },
{ .compatible = "nvidia,tegra186-pmc", .data = &tegra186_pmc_soc },
@@ -4277,8 +4406,25 @@ static const struct of_device_id tegra_pmc_match[] = {
static void tegra_pmc_sync_state(struct device *dev)
{
+ struct device_node *np, *child;
int err;
+ np = of_get_child_by_name(dev->of_node, "powergates");
+ if (!np)
+ return;
+
+ for_each_child_of_node(np, child)
+ of_genpd_sync_state(child);
+
+ of_node_put(np);
+
+ np = of_get_child_by_name(dev->of_node, "core-domain");
+ if (!np)
+ return;
+
+ of_genpd_sync_state(np);
+ of_node_put(np);
+
/*
* Newer device-trees have power domains, but we need to prepare all
* device drivers with runtime PM and OPP support first, otherwise
@@ -4292,9 +4438,6 @@ static void tegra_pmc_sync_state(struct device *dev)
* no dependencies that will block the state syncing. We shouldn't
* mark the domain as synced in this case.
*/
- if (!pmc->core_domain_registered)
- return;
-
pmc->core_domain_state_synced = true;
/* this is a no-op if core regulator isn't used */
diff --git a/drivers/soc/tegra/powergate-bpmp.c b/drivers/soc/tegra/powergate-bpmp.c
deleted file mode 100644
index 8eaf50d0b6af..000000000000
--- a/drivers/soc/tegra/powergate-bpmp.c
+++ /dev/null
@@ -1,361 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved
- */
-
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <linux/slab.h>
-
-#include <soc/tegra/bpmp.h>
-#include <soc/tegra/bpmp-abi.h>
-
-struct tegra_powergate_info {
- unsigned int id;
- char *name;
-};
-
-struct tegra_powergate {
- struct generic_pm_domain genpd;
- struct tegra_bpmp *bpmp;
- unsigned int id;
-};
-
-static inline struct tegra_powergate *
-to_tegra_powergate(struct generic_pm_domain *genpd)
-{
- return container_of(genpd, struct tegra_powergate, genpd);
-}
-
-static int tegra_bpmp_powergate_set_state(struct tegra_bpmp *bpmp,
- unsigned int id, u32 state)
-{
- struct mrq_pg_request request;
- struct tegra_bpmp_message msg;
- int err;
-
- memset(&request, 0, sizeof(request));
- request.cmd = CMD_PG_SET_STATE;
- request.id = id;
- request.set_state.state = state;
-
- memset(&msg, 0, sizeof(msg));
- msg.mrq = MRQ_PG;
- msg.tx.data = &request;
- msg.tx.size = sizeof(request);
-
- err = tegra_bpmp_transfer(bpmp, &msg);
- if (err < 0)
- return err;
- else if (msg.rx.ret < 0)
- return -EINVAL;
-
- return 0;
-}
-
-static int tegra_bpmp_powergate_get_state(struct tegra_bpmp *bpmp,
- unsigned int id)
-{
- struct mrq_pg_response response;
- struct mrq_pg_request request;
- struct tegra_bpmp_message msg;
- int err;
-
- memset(&request, 0, sizeof(request));
- request.cmd = CMD_PG_GET_STATE;
- request.id = id;
-
- memset(&response, 0, sizeof(response));
-
- memset(&msg, 0, sizeof(msg));
- msg.mrq = MRQ_PG;
- msg.tx.data = &request;
- msg.tx.size = sizeof(request);
- msg.rx.data = &response;
- msg.rx.size = sizeof(response);
-
- err = tegra_bpmp_transfer(bpmp, &msg);
- if (err < 0)
- return PG_STATE_OFF;
- else if (msg.rx.ret < 0)
- return -EINVAL;
-
- return response.get_state.state;
-}
-
-static int tegra_bpmp_powergate_get_max_id(struct tegra_bpmp *bpmp)
-{
- struct mrq_pg_response response;
- struct mrq_pg_request request;
- struct tegra_bpmp_message msg;
- int err;
-
- memset(&request, 0, sizeof(request));
- request.cmd = CMD_PG_GET_MAX_ID;
-
- memset(&response, 0, sizeof(response));
-
- memset(&msg, 0, sizeof(msg));
- msg.mrq = MRQ_PG;
- msg.tx.data = &request;
- msg.tx.size = sizeof(request);
- msg.rx.data = &response;
- msg.rx.size = sizeof(response);
-
- err = tegra_bpmp_transfer(bpmp, &msg);
- if (err < 0)
- return err;
- else if (msg.rx.ret < 0)
- return -EINVAL;
-
- return response.get_max_id.max_id;
-}
-
-static char *tegra_bpmp_powergate_get_name(struct tegra_bpmp *bpmp,
- unsigned int id)
-{
- struct mrq_pg_response response;
- struct mrq_pg_request request;
- struct tegra_bpmp_message msg;
- int err;
-
- memset(&request, 0, sizeof(request));
- request.cmd = CMD_PG_GET_NAME;
- request.id = id;
-
- memset(&response, 0, sizeof(response));
-
- memset(&msg, 0, sizeof(msg));
- msg.mrq = MRQ_PG;
- msg.tx.data = &request;
- msg.tx.size = sizeof(request);
- msg.rx.data = &response;
- msg.rx.size = sizeof(response);
-
- err = tegra_bpmp_transfer(bpmp, &msg);
- if (err < 0 || msg.rx.ret < 0)
- return NULL;
-
- return kstrdup(response.get_name.name, GFP_KERNEL);
-}
-
-static inline bool tegra_bpmp_powergate_is_powered(struct tegra_bpmp *bpmp,
- unsigned int id)
-{
- return tegra_bpmp_powergate_get_state(bpmp, id) != PG_STATE_OFF;
-}
-
-static int tegra_powergate_power_on(struct generic_pm_domain *domain)
-{
- struct tegra_powergate *powergate = to_tegra_powergate(domain);
- struct tegra_bpmp *bpmp = powergate->bpmp;
-
- return tegra_bpmp_powergate_set_state(bpmp, powergate->id,
- PG_STATE_ON);
-}
-
-static int tegra_powergate_power_off(struct generic_pm_domain *domain)
-{
- struct tegra_powergate *powergate = to_tegra_powergate(domain);
- struct tegra_bpmp *bpmp = powergate->bpmp;
-
- return tegra_bpmp_powergate_set_state(bpmp, powergate->id,
- PG_STATE_OFF);
-}
-
-static struct tegra_powergate *
-tegra_powergate_add(struct tegra_bpmp *bpmp,
- const struct tegra_powergate_info *info)
-{
- struct tegra_powergate *powergate;
- bool off;
- int err;
-
- off = !tegra_bpmp_powergate_is_powered(bpmp, info->id);
-
- powergate = devm_kzalloc(bpmp->dev, sizeof(*powergate), GFP_KERNEL);
- if (!powergate)
- return ERR_PTR(-ENOMEM);
-
- powergate->id = info->id;
- powergate->bpmp = bpmp;
-
- powergate->genpd.name = kstrdup(info->name, GFP_KERNEL);
- powergate->genpd.power_on = tegra_powergate_power_on;
- powergate->genpd.power_off = tegra_powergate_power_off;
-
- err = pm_genpd_init(&powergate->genpd, NULL, off);
- if (err < 0) {
- kfree(powergate->genpd.name);
- return ERR_PTR(err);
- }
-
- return powergate;
-}
-
-static void tegra_powergate_remove(struct tegra_powergate *powergate)
-{
- struct generic_pm_domain *genpd = &powergate->genpd;
- struct tegra_bpmp *bpmp = powergate->bpmp;
- int err;
-
- err = pm_genpd_remove(genpd);
- if (err < 0)
- dev_err(bpmp->dev, "failed to remove power domain %s: %d\n",
- genpd->name, err);
-
- kfree(genpd->name);
-}
-
-static int
-tegra_bpmp_probe_powergates(struct tegra_bpmp *bpmp,
- struct tegra_powergate_info **powergatesp)
-{
- struct tegra_powergate_info *powergates;
- unsigned int max_id, id, count = 0;
- unsigned int num_holes = 0;
- int err;
-
- err = tegra_bpmp_powergate_get_max_id(bpmp);
- if (err < 0)
- return err;
-
- max_id = err;
-
- dev_dbg(bpmp->dev, "maximum powergate ID: %u\n", max_id);
-
- powergates = kcalloc(max_id + 1, sizeof(*powergates), GFP_KERNEL);
- if (!powergates)
- return -ENOMEM;
-
- for (id = 0; id <= max_id; id++) {
- struct tegra_powergate_info *info = &powergates[count];
-
- info->name = tegra_bpmp_powergate_get_name(bpmp, id);
- if (!info->name || info->name[0] == '\0') {
- num_holes++;
- continue;
- }
-
- info->id = id;
- count++;
- }
-
- dev_dbg(bpmp->dev, "holes: %u\n", num_holes);
-
- *powergatesp = powergates;
-
- return count;
-}
-
-static int tegra_bpmp_add_powergates(struct tegra_bpmp *bpmp,
- struct tegra_powergate_info *powergates,
- unsigned int count)
-{
- struct genpd_onecell_data *genpd = &bpmp->genpd;
- struct generic_pm_domain **domains;
- struct tegra_powergate *powergate;
- unsigned int i;
- int err;
-
- domains = kcalloc(count, sizeof(*domains), GFP_KERNEL);
- if (!domains)
- return -ENOMEM;
-
- for (i = 0; i < count; i++) {
- powergate = tegra_powergate_add(bpmp, &powergates[i]);
- if (IS_ERR(powergate)) {
- err = PTR_ERR(powergate);
- goto remove;
- }
-
- dev_dbg(bpmp->dev, "added power domain %s\n",
- powergate->genpd.name);
- domains[i] = &powergate->genpd;
- }
-
- genpd->num_domains = count;
- genpd->domains = domains;
-
- return 0;
-
-remove:
- while (i--) {
- powergate = to_tegra_powergate(domains[i]);
- tegra_powergate_remove(powergate);
- }
-
- kfree(genpd->domains);
- return err;
-}
-
-static void tegra_bpmp_remove_powergates(struct tegra_bpmp *bpmp)
-{
- struct genpd_onecell_data *genpd = &bpmp->genpd;
- unsigned int i = genpd->num_domains;
- struct tegra_powergate *powergate;
-
- while (i--) {
- dev_dbg(bpmp->dev, "removing power domain %s\n",
- genpd->domains[i]->name);
- powergate = to_tegra_powergate(genpd->domains[i]);
- tegra_powergate_remove(powergate);
- }
-}
-
-static struct generic_pm_domain *
-tegra_powergate_xlate(struct of_phandle_args *spec, void *data)
-{
- struct generic_pm_domain *domain = ERR_PTR(-ENOENT);
- struct genpd_onecell_data *genpd = data;
- unsigned int i;
-
- for (i = 0; i < genpd->num_domains; i++) {
- struct tegra_powergate *powergate;
-
- powergate = to_tegra_powergate(genpd->domains[i]);
- if (powergate->id == spec->args[0]) {
- domain = &powergate->genpd;
- break;
- }
- }
-
- return domain;
-}
-
-int tegra_bpmp_init_powergates(struct tegra_bpmp *bpmp)
-{
- struct device_node *np = bpmp->dev->of_node;
- struct tegra_powergate_info *powergates;
- struct device *dev = bpmp->dev;
- unsigned int count, i;
- int err;
-
- err = tegra_bpmp_probe_powergates(bpmp, &powergates);
- if (err < 0)
- return err;
-
- count = err;
-
- dev_dbg(dev, "%u power domains probed\n", count);
-
- err = tegra_bpmp_add_powergates(bpmp, powergates, count);
- if (err < 0)
- goto free;
-
- bpmp->genpd.xlate = tegra_powergate_xlate;
-
- err = of_genpd_add_provider_onecell(np, &bpmp->genpd);
- if (err < 0) {
- dev_err(dev, "failed to add power domain provider: %d\n", err);
- tegra_bpmp_remove_powergates(bpmp);
- }
-
-free:
- for (i = 0; i < count; i++)
- kfree(powergates[i].name);
-
- kfree(powergates);
- return err;
-}
diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig
index 8c2a1036bef5..1a93001c9e36 100644
--- a/drivers/soc/ti/Kconfig
+++ b/drivers/soc/ti/Kconfig
@@ -50,18 +50,6 @@ config WKUP_M3_IPC
to communicate and use the Wakeup M3 for PM features like suspend
resume and boots it using wkup_m3_rproc driver.
-config TI_SCI_PM_DOMAINS
- tristate "TI SCI PM Domains Driver"
- depends on TI_SCI_PROTOCOL
- depends on PM_GENERIC_DOMAINS
- help
- Generic power domain implementation for TI device implementing
- the TI SCI protocol.
-
- To compile this as a module, choose M here. The module will be
- called ti_sci_pm_domains. Note this is needed early in boot before
- rootfs may be available.
-
config TI_K3_RINGACC
tristate "K3 Ring accelerator Sub System"
depends on ARCH_K3 || COMPILE_TEST
@@ -85,7 +73,7 @@ config TI_K3_SOCINFO
config TI_PRUSS
tristate "TI PRU-ICSS Subsystem Platform drivers"
- depends on SOC_AM33XX || SOC_AM43XX || SOC_DRA7XX || ARCH_KEYSTONE || ARCH_K3
+ depends on SOC_AM33XX || SOC_AM43XX || SOC_DRA7XX || ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
select MFD_SYSCON
help
TI PRU-ICSS Subsystem platform specific support.
diff --git a/drivers/soc/ti/Makefile b/drivers/soc/ti/Makefile
index cc3c972fad2e..cb800a745e66 100644
--- a/drivers/soc/ti/Makefile
+++ b/drivers/soc/ti/Makefile
@@ -6,9 +6,7 @@ obj-$(CONFIG_KEYSTONE_NAVIGATOR_QMSS) += knav_qmss.o
knav_qmss-y := knav_qmss_queue.o knav_qmss_acc.o
obj-$(CONFIG_KEYSTONE_NAVIGATOR_DMA) += knav_dma.o
obj-$(CONFIG_AMX3_PM) += pm33xx.o
-obj-$(CONFIG_ARCH_OMAP2PLUS) += omap_prm.o
obj-$(CONFIG_WKUP_M3_IPC) += wkup_m3_ipc.o
-obj-$(CONFIG_TI_SCI_PM_DOMAINS) += ti_sci_pm_domains.o
obj-$(CONFIG_TI_SCI_INTA_MSI_DOMAIN) += ti_sci_inta_msi.o
obj-$(CONFIG_TI_K3_RINGACC) += k3-ringacc.o
obj-$(CONFIG_TI_K3_SOCINFO) += k3-socinfo.o
diff --git a/drivers/soc/ti/k3-ringacc.c b/drivers/soc/ti/k3-ringacc.c
index e01e4d815230..7602b8a909b0 100644
--- a/drivers/soc/ti/k3-ringacc.c
+++ b/drivers/soc/ti/k3-ringacc.c
@@ -9,7 +9,6 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/sys_soc.h>
#include <linux/dma/ti-cppi5.h>
@@ -125,6 +124,7 @@ struct k3_ring_ops {
* @occ: Occupancy
* @windex: Write index
* @rindex: Read index
+ * @tdown_complete: Tear down complete state
*/
struct k3_ring_state {
u32 free;
@@ -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;
@@ -192,7 +192,7 @@ struct k3_ringacc_ops {
* @num_rings: number of ring in RA
* @rings_inuse: bitfield for ring usage tracking
* @rm_gp_range: general purpose rings range from tisci
- * @dma_ring_reset_quirk: DMA reset w/a enable
+ * @dma_ring_reset_quirk: DMA reset workaround enable
* @num_proxies: number of RA proxies
* @proxy_inuse: bitfield for proxy usage tracking
* @rings: array of rings descriptors (struct @k3_ring)
@@ -229,9 +229,9 @@ struct k3_ringacc {
};
/**
- * struct k3_ringacc - Rings accelerator SoC data
+ * struct k3_ringacc_soc_data - Rings accelerator SoC data
*
- * @dma_ring_reset_quirk: DMA reset w/a enable
+ * @dma_ring_reset_quirk: DMA reset workaround enable
*/
struct k3_ringacc_soc_data {
unsigned dma_ring_reset_quirk:1;
@@ -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,
@@ -406,6 +406,11 @@ static int k3_dmaring_request_dual_ring(struct k3_ringacc *ringacc, int fwd_id,
mutex_lock(&ringacc->req_lock);
+ if (!try_module_get(ringacc->dev->driver->owner)) {
+ ret = -EINVAL;
+ goto err_module_get;
+ }
+
if (test_bit(fwd_id, ringacc->rings_inuse)) {
ret = -EBUSY;
goto error;
@@ -421,6 +426,8 @@ static int k3_dmaring_request_dual_ring(struct k3_ringacc *ringacc, int fwd_id,
return 0;
error:
+ module_put(ringacc->dev->driver->owner);
+err_module_get:
mutex_unlock(&ringacc->req_lock);
return ret;
}
@@ -1284,7 +1291,7 @@ struct k3_ringacc *of_k3_ringacc_get_by_phandle(struct device_node *np,
mutex_lock(&k3_ringacc_list_lock);
list_for_each_entry(entry, &k3_ringacc_list, list)
- if (entry->dev->of_node == ringacc_np) {
+ if (device_match_of_node(entry->dev, ringacc_np)) {
ringacc = entry;
break;
}
@@ -1361,15 +1368,12 @@ static int k3_ringacc_init(struct platform_device *pdev,
const struct soc_device_attribute *soc;
void __iomem *base_fifo, *base_rt;
struct device *dev = &pdev->dev;
- struct resource *res;
int ret, i;
dev->msi.domain = of_msi_get_domain(dev, dev->of_node,
DOMAIN_BUS_TI_SCI_INTA_MSI);
- if (!dev->msi.domain) {
- dev_err(dev, "Failed to get MSI domain\n");
+ if (!dev->msi.domain)
return -EPROBE_DEFER;
- }
ret = k3_ringacc_probe_dt(ringacc);
if (ret)
@@ -1382,24 +1386,20 @@ static int k3_ringacc_init(struct platform_device *pdev,
ringacc->dma_ring_reset_quirk = soc_data->dma_ring_reset_quirk;
}
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rt");
- base_rt = devm_ioremap_resource(dev, res);
+ base_rt = devm_platform_ioremap_resource_byname(pdev, "rt");
if (IS_ERR(base_rt))
return PTR_ERR(base_rt);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fifos");
- base_fifo = devm_ioremap_resource(dev, res);
+ base_fifo = devm_platform_ioremap_resource_byname(pdev, "fifos");
if (IS_ERR(base_fifo))
return PTR_ERR(base_fifo);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "proxy_gcfg");
- ringacc->proxy_gcfg = devm_ioremap_resource(dev, res);
+ ringacc->proxy_gcfg = devm_platform_ioremap_resource_byname(pdev, "proxy_gcfg");
if (IS_ERR(ringacc->proxy_gcfg))
return PTR_ERR(ringacc->proxy_gcfg);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "proxy_target");
- ringacc->proxy_target_base = devm_ioremap_resource(dev, res);
+ ringacc->proxy_target_base = devm_platform_ioremap_resource_byname(pdev,
+ "proxy_target");
if (IS_ERR(ringacc->proxy_target_base))
return PTR_ERR(ringacc->proxy_target_base);
@@ -1466,7 +1466,6 @@ struct k3_ringacc *k3_ringacc_dmarings_init(struct platform_device *pdev,
struct device *dev = &pdev->dev;
struct k3_ringacc *ringacc;
void __iomem *base_rt;
- struct resource *res;
int i;
ringacc = devm_kzalloc(dev, sizeof(*ringacc), GFP_KERNEL);
@@ -1481,8 +1480,7 @@ struct k3_ringacc *k3_ringacc_dmarings_init(struct platform_device *pdev,
mutex_init(&ringacc->req_lock);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ringrt");
- base_rt = devm_ioremap_resource(dev, res);
+ base_rt = devm_platform_ioremap_resource_byname(pdev, "ringrt");
if (IS_ERR(base_rt))
return ERR_CAST(base_rt);
@@ -1553,14 +1551,13 @@ static int k3_ringacc_probe(struct platform_device *pdev)
return 0;
}
-static int k3_ringacc_remove(struct platform_device *pdev)
+static void k3_ringacc_remove(struct platform_device *pdev)
{
struct k3_ringacc *ringacc = dev_get_drvdata(&pdev->dev);
mutex_lock(&k3_ringacc_list_lock);
list_del(&ringacc->list);
mutex_unlock(&k3_ringacc_list_lock);
- return 0;
}
static struct platform_driver k3_ringacc_driver = {
diff --git a/drivers/soc/ti/k3-socinfo.c b/drivers/soc/ti/k3-socinfo.c
index d15764e19d96..50c170a995f9 100644
--- a/drivers/soc/ti/k3-socinfo.c
+++ b/drivers/soc/ti/k3-socinfo.c
@@ -20,7 +20,7 @@
* 31-28 VARIANT Device variant
* 27-12 PARTNO Part number
* 11-1 MFG Indicates TI as manufacturer (0x17)
- * 1 Always 1
+ * 0 Always 1
*/
#define CTRLMMR_WKUP_JTAGID_VARIANT_SHIFT (28)
#define CTRLMMR_WKUP_JTAGID_VARIANT_MASK GENMASK(31, 28)
@@ -33,17 +33,41 @@
#define CTRLMMR_WKUP_JTAGID_MFG_TI 0x17
+#define JTAG_ID_PARTNO_AM65X 0xBB5A
+#define JTAG_ID_PARTNO_J721E 0xBB64
+#define JTAG_ID_PARTNO_J7200 0xBB6D
+#define JTAG_ID_PARTNO_AM64X 0xBB38
+#define JTAG_ID_PARTNO_J721S2 0xBB75
+#define JTAG_ID_PARTNO_AM62X 0xBB7E
+#define JTAG_ID_PARTNO_J784S4 0xBB80
+#define JTAG_ID_PARTNO_AM62AX 0xBB8D
+#define JTAG_ID_PARTNO_AM62PX 0xBB9D
+#define JTAG_ID_PARTNO_J722S 0xBBA0
+#define JTAG_ID_PARTNO_AM62LX 0xBBA7
+
static const struct k3_soc_id {
unsigned int id;
const char *family_name;
} k3_soc_ids[] = {
- { 0xBB5A, "AM65X" },
- { 0xBB64, "J721E" },
- { 0xBB6D, "J7200" },
- { 0xBB38, "AM64X" },
- { 0xBB75, "J721S2"},
- { 0xBB7E, "AM62X" },
- { 0xBB8D, "AM62AX" },
+ { JTAG_ID_PARTNO_AM65X, "AM65X" },
+ { JTAG_ID_PARTNO_J721E, "J721E" },
+ { JTAG_ID_PARTNO_J7200, "J7200" },
+ { JTAG_ID_PARTNO_AM64X, "AM64X" },
+ { JTAG_ID_PARTNO_J721S2, "J721S2"},
+ { JTAG_ID_PARTNO_AM62X, "AM62X" },
+ { JTAG_ID_PARTNO_J784S4, "J784S4" },
+ { JTAG_ID_PARTNO_AM62AX, "AM62AX" },
+ { JTAG_ID_PARTNO_AM62PX, "AM62PX" },
+ { JTAG_ID_PARTNO_J722S, "J722S" },
+ { JTAG_ID_PARTNO_AM62LX, "AM62LX" },
+};
+
+static const char * const j721e_rev_string_map[] = {
+ "1.0", "1.1", "2.0",
+};
+
+static const char * const am62lx_rev_string_map[] = {
+ "1.0", "1.1",
};
static int
@@ -58,9 +82,47 @@ k3_chipinfo_partno_to_names(unsigned int partno,
return 0;
}
- return -EINVAL;
+ return -ENODEV;
}
+static int
+k3_chipinfo_variant_to_sr(unsigned int partno, unsigned int variant,
+ struct soc_device_attribute *soc_dev_attr)
+{
+ switch (partno) {
+ case JTAG_ID_PARTNO_J721E:
+ if (variant >= ARRAY_SIZE(j721e_rev_string_map))
+ goto err_unknown_variant;
+ soc_dev_attr->revision = kasprintf(GFP_KERNEL, "SR%s",
+ j721e_rev_string_map[variant]);
+ break;
+ case JTAG_ID_PARTNO_AM62LX:
+ if (variant >= ARRAY_SIZE(am62lx_rev_string_map))
+ goto err_unknown_variant;
+ soc_dev_attr->revision = kasprintf(GFP_KERNEL, "SR%s",
+ am62lx_rev_string_map[variant]);
+ break;
+ default:
+ variant++;
+ soc_dev_attr->revision = kasprintf(GFP_KERNEL, "SR%x.0",
+ variant);
+ }
+
+ if (!soc_dev_attr->revision)
+ return -ENOMEM;
+
+ return 0;
+
+err_unknown_variant:
+ return -ENODEV;
+}
+
+static const struct regmap_config k3_chipinfo_regmap_cfg = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
static int k3_chipinfo_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
@@ -68,13 +130,18 @@ static int k3_chipinfo_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct soc_device *soc_dev;
struct regmap *regmap;
+ void __iomem *base;
u32 partno_id;
u32 variant;
u32 jtag_id;
u32 mfg;
int ret;
- regmap = device_node_to_regmap(node);
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ regmap = regmap_init_mmio(dev, base, &k3_chipinfo_regmap_cfg);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
@@ -92,7 +159,6 @@ static int k3_chipinfo_probe(struct platform_device *pdev)
variant = (jtag_id & CTRLMMR_WKUP_JTAGID_VARIANT_MASK) >>
CTRLMMR_WKUP_JTAGID_VARIANT_SHIFT;
- variant++;
partno_id = (jtag_id & CTRLMMR_WKUP_JTAGID_PARTNO_MASK) >>
CTRLMMR_WKUP_JTAGID_PARTNO_SHIFT;
@@ -101,17 +167,16 @@ static int k3_chipinfo_probe(struct platform_device *pdev)
if (!soc_dev_attr)
return -ENOMEM;
- soc_dev_attr->revision = kasprintf(GFP_KERNEL, "SR%x.0", variant);
- if (!soc_dev_attr->revision) {
- ret = -ENOMEM;
+ ret = k3_chipinfo_partno_to_names(partno_id, soc_dev_attr);
+ if (ret) {
+ dev_err(dev, "Unknown SoC JTAGID[0x%08X]: %d\n", jtag_id, ret);
goto err;
}
- ret = k3_chipinfo_partno_to_names(partno_id, soc_dev_attr);
+ ret = k3_chipinfo_variant_to_sr(partno_id, variant, soc_dev_attr);
if (ret) {
- dev_err(dev, "Unknown SoC JTAGID[0x%08X]\n", jtag_id);
- ret = -ENODEV;
- goto err_free_rev;
+ dev_err(dev, "Unknown SoC SR[0x%08X]: %d\n", jtag_id, ret);
+ goto err;
}
node = of_find_node_by_path("/");
diff --git a/drivers/soc/ti/knav_dma.c b/drivers/soc/ti/knav_dma.c
index 84afebd355be..553ae7ee20f1 100644
--- a/drivers/soc/ti/knav_dma.c
+++ b/drivers/soc/ti/knav_dma.c
@@ -402,7 +402,7 @@ static int of_channel_match_helper(struct device_node *np, const char *name,
* @name: slave channel name
* @config: dma configuration parameters
*
- * Returns pointer to appropriate DMA channel on success or error.
+ * Return: Pointer to appropriate DMA channel on success or NULL on error.
*/
void *knav_dma_open_channel(struct device *dev, const char *name,
struct knav_dma_cfg *config)
@@ -414,13 +414,13 @@ void *knav_dma_open_channel(struct device *dev, const char *name,
if (!kdev) {
pr_err("keystone-navigator-dma driver not registered\n");
- return (void *)-EINVAL;
+ return NULL;
}
chan_num = of_channel_match_helper(dev->of_node, name, &instance);
if (chan_num < 0) {
dev_err(kdev->dev, "No DMA instance with name %s\n", name);
- return (void *)-EINVAL;
+ return NULL;
}
dev_dbg(kdev->dev, "initializing %s channel %d from DMA %s\n",
@@ -431,7 +431,7 @@ void *knav_dma_open_channel(struct device *dev, const char *name,
if (config->direction != DMA_MEM_TO_DEV &&
config->direction != DMA_DEV_TO_MEM) {
dev_err(kdev->dev, "bad direction\n");
- return (void *)-EINVAL;
+ return NULL;
}
/* Look for correct dma instance */
@@ -443,7 +443,7 @@ void *knav_dma_open_channel(struct device *dev, const char *name,
}
if (!dma) {
dev_err(kdev->dev, "No DMA instance with name %s\n", instance);
- return (void *)-EINVAL;
+ return NULL;
}
/* Look for correct dma channel from dma instance */
@@ -463,14 +463,14 @@ void *knav_dma_open_channel(struct device *dev, const char *name,
if (!chan) {
dev_err(kdev->dev, "channel %d is not in DMA %s\n",
chan_num, instance);
- return (void *)-EINVAL;
+ return NULL;
}
if (atomic_read(&chan->ref_count) >= 1) {
if (!check_config(chan, config)) {
dev_err(kdev->dev, "channel %d config miss-match\n",
chan_num);
- return (void *)-EINVAL;
+ return NULL;
}
}
@@ -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))
@@ -666,8 +654,8 @@ static int dma_init(struct device_node *cloud, struct device_node *dma_node)
dma->rx_priority = DMA_PRIO_DEFAULT;
dma->tx_priority = DMA_PRIO_DEFAULT;
- dma->enable_all = (of_get_property(node, "ti,enable-all", NULL) != NULL);
- dma->loopback = (of_get_property(node, "ti,loop-back", NULL) != NULL);
+ dma->enable_all = of_property_read_bool(node, "ti,enable-all");
+ dma->loopback = of_property_read_bool(node, "ti,loop-back");
ret = of_property_read_u32(node, "ti,rx-retry-timeout", &timeout);
if (ret < 0) {
@@ -773,7 +761,7 @@ err_pm_disable:
return ret;
}
-static int knav_dma_remove(struct platform_device *pdev)
+static void knav_dma_remove(struct platform_device *pdev)
{
struct knav_dma_device *dma;
@@ -784,8 +772,6 @@ static int knav_dma_remove(struct platform_device *pdev)
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
static struct of_device_id of_match[] = {
@@ -798,7 +784,7 @@ MODULE_DEVICE_TABLE(of, of_match);
static struct platform_driver knav_dma_driver = {
.probe = knav_dma_probe,
.remove = knav_dma_remove,
- .driver = {
+ .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 fde66e28e046..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,
@@ -521,7 +521,7 @@ int knav_init_acc_range(struct knav_device *kdev,
info->pdsp = pdsp;
channels = range->num_queues;
- if (of_get_property(node, "multi-queue", NULL)) {
+ if (of_property_read_bool(node, "multi-queue")) {
range->flags |= RANGE_MULTI_QUEUE;
channels = 1;
if (range->queue_base & (32 - 1)) {
diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c
index 8fb76908be70..6e56e7609ccd 100644
--- a/drivers/soc/ti/knav_qmss_queue.c
+++ b/drivers/soc/ti/knav_qmss_queue.c
@@ -14,10 +14,12 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/of_irq.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/property.h>
#include <linux/slab.h>
#include <linux/soc/ti/knav_qmss.h>
@@ -117,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) {
@@ -251,8 +252,7 @@ static struct knav_queue *__knav_queue_open(struct knav_queue_inst *inst,
return qh;
err:
- if (qh->stats)
- free_percpu(qh->stats);
+ free_percpu(qh->stats);
devm_kfree(inst->kdev->dev, qh);
return ERR_PTR(ret);
}
@@ -409,7 +409,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,
@@ -721,7 +721,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);
@@ -1074,14 +1073,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) {
@@ -1102,11 +1107,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) {
@@ -1119,10 +1119,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)
@@ -1264,10 +1263,10 @@ static int knav_setup_queue_range(struct knav_device *kdev,
if (range->num_irqs)
range->flags |= RANGE_HAS_IRQ;
- if (of_get_property(node, "qalloc-by-id", NULL))
+ if (of_property_read_bool(node, "qalloc-by-id"))
range->flags |= RANGE_RESERVED;
- if (of_get_property(node, "accumulator", NULL)) {
+ if (of_property_present(node, "accumulator")) {
ret = knav_init_acc_range(kdev, node, range);
if (ret < 0) {
devm_kfree(dev, range);
@@ -1304,10 +1303,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... */
@@ -1316,10 +1321,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;
}
@@ -1387,14 +1391,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) {
@@ -1666,6 +1676,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;
@@ -1753,8 +1783,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;
- const struct of_device_id *match;
struct device *dev = &pdev->dev;
u32 temp[2];
int ret;
@@ -1770,8 +1798,7 @@ static int knav_queue_probe(struct platform_device *pdev)
return -ENOMEM;
}
- match = of_match_device(of_match_ptr(keystone_qmss_of_match), dev);
- if (match && match->data)
+ if (device_get_match_data(dev))
kdev->version = QMSS_66AK2G;
platform_set_drvdata(pdev, kdev);
@@ -1799,39 +1826,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 +1858,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;
@@ -1884,12 +1882,11 @@ err:
return ret;
}
-static int knav_queue_remove(struct platform_device *pdev)
+static void knav_queue_remove(struct platform_device *pdev)
{
/* TODO: Free resources */
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- return 0;
}
static struct platform_driver keystone_qmss_driver = {
diff --git a/drivers/soc/ti/omap_prm.c b/drivers/soc/ti/omap_prm.c
deleted file mode 100644
index 913b964374a4..000000000000
--- a/drivers/soc/ti/omap_prm.c
+++ /dev/null
@@ -1,994 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * OMAP2+ PRM driver
- *
- * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
- * Tero Kristo <t-kristo@ti.com>
- */
-
-#include <linux/kernel.h>
-#include <linux/clk.h>
-#include <linux/device.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/pm_clock.h>
-#include <linux/pm_domain.h>
-#include <linux/reset-controller.h>
-#include <linux/delay.h>
-
-#include <linux/platform_data/ti-prm.h>
-
-enum omap_prm_domain_mode {
- OMAP_PRMD_OFF,
- OMAP_PRMD_RETENTION,
- OMAP_PRMD_ON_INACTIVE,
- OMAP_PRMD_ON_ACTIVE,
-};
-
-struct omap_prm_domain_map {
- unsigned int usable_modes; /* Mask of hardware supported modes */
- unsigned long statechange:1; /* Optional low-power state change */
- unsigned long logicretstate:1; /* Optional logic off mode */
-};
-
-struct omap_prm_domain {
- struct device *dev;
- struct omap_prm *prm;
- struct generic_pm_domain pd;
- u16 pwrstctrl;
- u16 pwrstst;
- const struct omap_prm_domain_map *cap;
- u32 pwrstctrl_saved;
- unsigned int uses_pm_clk:1;
-};
-
-struct omap_rst_map {
- s8 rst;
- s8 st;
-};
-
-struct omap_prm_data {
- u32 base;
- const char *name;
- const char *clkdm_name;
- u16 pwrstctrl;
- u16 pwrstst;
- const struct omap_prm_domain_map *dmap;
- u16 rstctrl;
- u16 rstst;
- const struct omap_rst_map *rstmap;
- u8 flags;
-};
-
-struct omap_prm {
- const struct omap_prm_data *data;
- void __iomem *base;
- struct omap_prm_domain *prmd;
-};
-
-struct omap_reset_data {
- struct reset_controller_dev rcdev;
- struct omap_prm *prm;
- u32 mask;
- spinlock_t lock;
- struct clockdomain *clkdm;
- struct device *dev;
-};
-
-#define genpd_to_prm_domain(gpd) container_of(gpd, struct omap_prm_domain, pd)
-#define to_omap_reset_data(p) container_of((p), struct omap_reset_data, rcdev)
-
-#define OMAP_MAX_RESETS 8
-#define OMAP_RESET_MAX_WAIT 10000
-
-#define OMAP_PRM_HAS_RSTCTRL BIT(0)
-#define OMAP_PRM_HAS_RSTST BIT(1)
-#define OMAP_PRM_HAS_NO_CLKDM BIT(2)
-#define OMAP_PRM_RET_WHEN_IDLE BIT(3)
-
-#define OMAP_PRM_HAS_RESETS (OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_RSTST)
-
-#define PRM_STATE_MAX_WAIT 10000
-#define PRM_LOGICRETSTATE BIT(2)
-#define PRM_LOWPOWERSTATECHANGE BIT(4)
-#define PRM_POWERSTATE_MASK OMAP_PRMD_ON_ACTIVE
-
-#define PRM_ST_INTRANSITION BIT(20)
-
-static const struct omap_prm_domain_map omap_prm_all = {
- .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_ON_INACTIVE) |
- BIT(OMAP_PRMD_RETENTION) | BIT(OMAP_PRMD_OFF),
- .statechange = 1,
- .logicretstate = 1,
-};
-
-static const struct omap_prm_domain_map omap_prm_noinact = {
- .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_RETENTION) |
- BIT(OMAP_PRMD_OFF),
- .statechange = 1,
- .logicretstate = 1,
-};
-
-static const struct omap_prm_domain_map omap_prm_nooff = {
- .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_ON_INACTIVE) |
- BIT(OMAP_PRMD_RETENTION),
- .statechange = 1,
- .logicretstate = 1,
-};
-
-static const struct omap_prm_domain_map omap_prm_onoff_noauto = {
- .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_OFF),
- .statechange = 1,
-};
-
-static const struct omap_prm_domain_map omap_prm_alwon = {
- .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE),
-};
-
-static const struct omap_prm_domain_map omap_prm_reton = {
- .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_RETENTION),
- .statechange = 1,
- .logicretstate = 1,
-};
-
-static const struct omap_rst_map rst_map_0[] = {
- { .rst = 0, .st = 0 },
- { .rst = -1 },
-};
-
-static const struct omap_rst_map rst_map_01[] = {
- { .rst = 0, .st = 0 },
- { .rst = 1, .st = 1 },
- { .rst = -1 },
-};
-
-static const struct omap_rst_map rst_map_012[] = {
- { .rst = 0, .st = 0 },
- { .rst = 1, .st = 1 },
- { .rst = 2, .st = 2 },
- { .rst = -1 },
-};
-
-static const struct omap_prm_data omap4_prm_data[] = {
- {
- .name = "mpu", .base = 0x4a306300,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
- },
- {
- .name = "tesla", .base = 0x4a306400,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
- .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
- },
- {
- .name = "abe", .base = 0x4a306500,
- .pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_all,
- },
- {
- .name = "always_on_core", .base = 0x4a306600,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
- },
- {
- .name = "core", .base = 0x4a306700,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
- .rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ducati",
- .rstmap = rst_map_012,
- .flags = OMAP_PRM_RET_WHEN_IDLE,
- },
- {
- .name = "ivahd", .base = 0x4a306f00,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
- .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012
- },
- {
- .name = "cam", .base = 0x4a307000,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
- },
- {
- .name = "dss", .base = 0x4a307100,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact
- },
- {
- .name = "gfx", .base = 0x4a307200,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
- },
- {
- .name = "l3init", .base = 0x4a307300,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton
- },
- {
- .name = "l4per", .base = 0x4a307400,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
- .flags = OMAP_PRM_RET_WHEN_IDLE,
- },
- {
- .name = "cefuse", .base = 0x4a307600,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
- },
- {
- .name = "wkup", .base = 0x4a307700,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon
- },
- {
- .name = "emu", .base = 0x4a307900,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
- },
- {
- .name = "device", .base = 0x4a307b00,
- .rstctrl = 0x0, .rstst = 0x4, .rstmap = rst_map_01,
- .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM
- },
- { },
-};
-
-static const struct omap_prm_data omap5_prm_data[] = {
- {
- .name = "mpu", .base = 0x4ae06300,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
- },
- {
- .name = "dsp", .base = 0x4ae06400,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
- .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
- },
- {
- .name = "abe", .base = 0x4ae06500,
- .pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_nooff,
- },
- {
- .name = "coreaon", .base = 0x4ae06600,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon
- },
- {
- .name = "core", .base = 0x4ae06700,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
- .rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ipu",
- .rstmap = rst_map_012
- },
- {
- .name = "iva", .base = 0x4ae07200,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
- .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012
- },
- {
- .name = "cam", .base = 0x4ae07300,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
- },
- {
- .name = "dss", .base = 0x4ae07400,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact
- },
- {
- .name = "gpu", .base = 0x4ae07500,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
- },
- {
- .name = "l3init", .base = 0x4ae07600,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton
- },
- {
- .name = "custefuse", .base = 0x4ae07700,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
- },
- {
- .name = "wkupaon", .base = 0x4ae07800,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon
- },
- {
- .name = "emu", .base = 0x4ae07a00,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
- },
- {
- .name = "device", .base = 0x4ae07c00,
- .rstctrl = 0x0, .rstst = 0x4, .rstmap = rst_map_01,
- .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM
- },
- { },
-};
-
-static const struct omap_prm_data dra7_prm_data[] = {
- {
- .name = "mpu", .base = 0x4ae06300,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
- },
- {
- .name = "dsp1", .base = 0x4ae06400,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
- .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01,
- },
- {
- .name = "ipu", .base = 0x4ae06500,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
- .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012,
- .clkdm_name = "ipu1"
- },
- {
- .name = "coreaon", .base = 0x4ae06628,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
- },
- {
- .name = "core", .base = 0x4ae06700,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
- .rstctrl = 0x210, .rstst = 0x214, .rstmap = rst_map_012,
- .clkdm_name = "ipu2"
- },
- {
- .name = "iva", .base = 0x4ae06f00,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
- .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012,
- },
- {
- .name = "cam", .base = 0x4ae07000,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
- },
- {
- .name = "dss", .base = 0x4ae07100,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
- },
- {
- .name = "gpu", .base = 0x4ae07200,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
- },
- {
- .name = "l3init", .base = 0x4ae07300,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
- .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01,
- .clkdm_name = "pcie"
- },
- {
- .name = "l4per", .base = 0x4ae07400,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
- },
- {
- .name = "custefuse", .base = 0x4ae07600,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
- },
- {
- .name = "wkupaon", .base = 0x4ae07724,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
- },
- {
- .name = "emu", .base = 0x4ae07900,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
- },
- {
- .name = "dsp2", .base = 0x4ae07b00,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
- .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
- },
- {
- .name = "eve1", .base = 0x4ae07b40,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
- .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
- },
- {
- .name = "eve2", .base = 0x4ae07b80,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
- .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
- },
- {
- .name = "eve3", .base = 0x4ae07bc0,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
- .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
- },
- {
- .name = "eve4", .base = 0x4ae07c00,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
- .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
- },
- {
- .name = "rtc", .base = 0x4ae07c60,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
- },
- {
- .name = "vpe", .base = 0x4ae07c80,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
- },
- { },
-};
-
-static const struct omap_rst_map am3_per_rst_map[] = {
- { .rst = 1 },
- { .rst = -1 },
-};
-
-static const struct omap_rst_map am3_wkup_rst_map[] = {
- { .rst = 3, .st = 5 },
- { .rst = -1 },
-};
-
-static const struct omap_prm_data am3_prm_data[] = {
- {
- .name = "per", .base = 0x44e00c00,
- .pwrstctrl = 0xc, .pwrstst = 0x8, .dmap = &omap_prm_noinact,
- .rstctrl = 0x0, .rstmap = am3_per_rst_map,
- .flags = OMAP_PRM_HAS_RSTCTRL, .clkdm_name = "pruss_ocp"
- },
- {
- .name = "wkup", .base = 0x44e00d00,
- .pwrstctrl = 0x4, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
- .rstctrl = 0x0, .rstst = 0xc, .rstmap = am3_wkup_rst_map,
- .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM
- },
- {
- .name = "mpu", .base = 0x44e00e00,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
- },
- {
- .name = "device", .base = 0x44e00f00,
- .rstctrl = 0x0, .rstst = 0x8, .rstmap = rst_map_01,
- .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM
- },
- {
- .name = "rtc", .base = 0x44e01000,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
- },
- {
- .name = "gfx", .base = 0x44e01100,
- .pwrstctrl = 0, .pwrstst = 0x10, .dmap = &omap_prm_noinact,
- .rstctrl = 0x4, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3",
- },
- {
- .name = "cefuse", .base = 0x44e01200,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
- },
- { },
-};
-
-static const struct omap_rst_map am4_per_rst_map[] = {
- { .rst = 1, .st = 0 },
- { .rst = -1 },
-};
-
-static const struct omap_rst_map am4_device_rst_map[] = {
- { .rst = 0, .st = 1 },
- { .rst = 1, .st = 0 },
- { .rst = -1 },
-};
-
-static const struct omap_prm_data am4_prm_data[] = {
- {
- .name = "mpu", .base = 0x44df0300,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
- },
- {
- .name = "gfx", .base = 0x44df0400,
- .pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
- .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3",
- },
- {
- .name = "rtc", .base = 0x44df0500,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
- },
- {
- .name = "tamper", .base = 0x44df0600,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
- },
- {
- .name = "cefuse", .base = 0x44df0700,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
- },
- {
- .name = "per", .base = 0x44df0800,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
- .rstctrl = 0x10, .rstst = 0x14, .rstmap = am4_per_rst_map,
- .clkdm_name = "pruss_ocp"
- },
- {
- .name = "wkup", .base = 0x44df2000,
- .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
- .rstctrl = 0x10, .rstst = 0x14, .rstmap = am3_wkup_rst_map,
- .flags = OMAP_PRM_HAS_NO_CLKDM
- },
- {
- .name = "device", .base = 0x44df4000,
- .rstctrl = 0x0, .rstst = 0x4, .rstmap = am4_device_rst_map,
- .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM
- },
- { },
-};
-
-static const struct of_device_id omap_prm_id_table[] = {
- { .compatible = "ti,omap4-prm-inst", .data = omap4_prm_data },
- { .compatible = "ti,omap5-prm-inst", .data = omap5_prm_data },
- { .compatible = "ti,dra7-prm-inst", .data = dra7_prm_data },
- { .compatible = "ti,am3-prm-inst", .data = am3_prm_data },
- { .compatible = "ti,am4-prm-inst", .data = am4_prm_data },
- { },
-};
-
-#ifdef DEBUG
-static void omap_prm_domain_show_state(struct omap_prm_domain *prmd,
- const char *desc)
-{
- dev_dbg(prmd->dev, "%s %s: %08x/%08x\n",
- prmd->pd.name, desc,
- readl_relaxed(prmd->prm->base + prmd->pwrstctrl),
- readl_relaxed(prmd->prm->base + prmd->pwrstst));
-}
-#else
-static inline void omap_prm_domain_show_state(struct omap_prm_domain *prmd,
- const char *desc)
-{
-}
-#endif
-
-static int omap_prm_domain_power_on(struct generic_pm_domain *domain)
-{
- struct omap_prm_domain *prmd;
- int ret;
- u32 v, mode;
-
- prmd = genpd_to_prm_domain(domain);
- if (!prmd->cap)
- return 0;
-
- omap_prm_domain_show_state(prmd, "on: previous state");
-
- if (prmd->pwrstctrl_saved)
- v = prmd->pwrstctrl_saved;
- else
- v = readl_relaxed(prmd->prm->base + prmd->pwrstctrl);
-
- if (prmd->prm->data->flags & OMAP_PRM_RET_WHEN_IDLE)
- mode = OMAP_PRMD_RETENTION;
- else
- mode = OMAP_PRMD_ON_ACTIVE;
-
- writel_relaxed((v & ~PRM_POWERSTATE_MASK) | mode,
- prmd->prm->base + prmd->pwrstctrl);
-
- /* wait for the transition bit to get cleared */
- ret = readl_relaxed_poll_timeout(prmd->prm->base + prmd->pwrstst,
- v, !(v & PRM_ST_INTRANSITION), 1,
- PRM_STATE_MAX_WAIT);
- if (ret)
- dev_err(prmd->dev, "%s: %s timed out\n",
- prmd->pd.name, __func__);
-
- omap_prm_domain_show_state(prmd, "on: new state");
-
- return ret;
-}
-
-/* No need to check for holes in the mask for the lowest mode */
-static int omap_prm_domain_find_lowest(struct omap_prm_domain *prmd)
-{
- return __ffs(prmd->cap->usable_modes);
-}
-
-static int omap_prm_domain_power_off(struct generic_pm_domain *domain)
-{
- struct omap_prm_domain *prmd;
- int ret;
- u32 v;
-
- prmd = genpd_to_prm_domain(domain);
- if (!prmd->cap)
- return 0;
-
- omap_prm_domain_show_state(prmd, "off: previous state");
-
- v = readl_relaxed(prmd->prm->base + prmd->pwrstctrl);
- prmd->pwrstctrl_saved = v;
-
- v &= ~PRM_POWERSTATE_MASK;
- v |= omap_prm_domain_find_lowest(prmd);
-
- if (prmd->cap->statechange)
- v |= PRM_LOWPOWERSTATECHANGE;
- if (prmd->cap->logicretstate)
- v &= ~PRM_LOGICRETSTATE;
- else
- v |= PRM_LOGICRETSTATE;
-
- writel_relaxed(v, prmd->prm->base + prmd->pwrstctrl);
-
- /* wait for the transition bit to get cleared */
- ret = readl_relaxed_poll_timeout(prmd->prm->base + prmd->pwrstst,
- v, !(v & PRM_ST_INTRANSITION), 1,
- PRM_STATE_MAX_WAIT);
- if (ret)
- dev_warn(prmd->dev, "%s: %s timed out\n",
- __func__, prmd->pd.name);
-
- omap_prm_domain_show_state(prmd, "off: new state");
-
- return 0;
-}
-
-/*
- * Note that ti-sysc already manages the module clocks separately so
- * no need to manage those. Interconnect instances need clocks managed
- * for simple-pm-bus.
- */
-static int omap_prm_domain_attach_clock(struct device *dev,
- struct omap_prm_domain *prmd)
-{
- struct device_node *np = dev->of_node;
- int error;
-
- if (!of_device_is_compatible(np, "simple-pm-bus"))
- return 0;
-
- if (!of_property_read_bool(np, "clocks"))
- return 0;
-
- error = pm_clk_create(dev);
- if (error)
- return error;
-
- error = of_pm_clk_add_clks(dev);
- if (error < 0) {
- pm_clk_destroy(dev);
- return error;
- }
-
- prmd->uses_pm_clk = 1;
-
- return 0;
-}
-
-static int omap_prm_domain_attach_dev(struct generic_pm_domain *domain,
- struct device *dev)
-{
- struct generic_pm_domain_data *genpd_data;
- struct of_phandle_args pd_args;
- struct omap_prm_domain *prmd;
- struct device_node *np;
- int ret;
-
- prmd = genpd_to_prm_domain(domain);
- np = dev->of_node;
-
- ret = of_parse_phandle_with_args(np, "power-domains",
- "#power-domain-cells", 0, &pd_args);
- if (ret < 0)
- return ret;
-
- if (pd_args.args_count != 0)
- dev_warn(dev, "%s: unusupported #power-domain-cells: %i\n",
- prmd->pd.name, pd_args.args_count);
-
- genpd_data = dev_gpd_data(dev);
- genpd_data->data = NULL;
-
- ret = omap_prm_domain_attach_clock(dev, prmd);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static void omap_prm_domain_detach_dev(struct generic_pm_domain *domain,
- struct device *dev)
-{
- struct generic_pm_domain_data *genpd_data;
- struct omap_prm_domain *prmd;
-
- prmd = genpd_to_prm_domain(domain);
- if (prmd->uses_pm_clk)
- pm_clk_destroy(dev);
- genpd_data = dev_gpd_data(dev);
- genpd_data->data = NULL;
-}
-
-static int omap_prm_domain_init(struct device *dev, struct omap_prm *prm)
-{
- struct omap_prm_domain *prmd;
- struct device_node *np = dev->of_node;
- const struct omap_prm_data *data;
- const char *name;
- int error;
-
- if (!of_find_property(dev->of_node, "#power-domain-cells", NULL))
- return 0;
-
- of_node_put(dev->of_node);
-
- prmd = devm_kzalloc(dev, sizeof(*prmd), GFP_KERNEL);
- if (!prmd)
- return -ENOMEM;
-
- data = prm->data;
- name = devm_kasprintf(dev, GFP_KERNEL, "prm_%s",
- data->name);
-
- prmd->dev = dev;
- prmd->prm = prm;
- prmd->cap = prmd->prm->data->dmap;
- prmd->pwrstctrl = prmd->prm->data->pwrstctrl;
- prmd->pwrstst = prmd->prm->data->pwrstst;
-
- prmd->pd.name = name;
- prmd->pd.power_on = omap_prm_domain_power_on;
- prmd->pd.power_off = omap_prm_domain_power_off;
- prmd->pd.attach_dev = omap_prm_domain_attach_dev;
- prmd->pd.detach_dev = omap_prm_domain_detach_dev;
- prmd->pd.flags = GENPD_FLAG_PM_CLK;
-
- pm_genpd_init(&prmd->pd, NULL, true);
- error = of_genpd_add_provider_simple(np, &prmd->pd);
- if (error)
- pm_genpd_remove(&prmd->pd);
- else
- prm->prmd = prmd;
-
- return error;
-}
-
-static bool _is_valid_reset(struct omap_reset_data *reset, unsigned long id)
-{
- if (reset->mask & BIT(id))
- return true;
-
- return false;
-}
-
-static int omap_reset_get_st_bit(struct omap_reset_data *reset,
- unsigned long id)
-{
- const struct omap_rst_map *map = reset->prm->data->rstmap;
-
- while (map->rst >= 0) {
- if (map->rst == id)
- return map->st;
-
- map++;
- }
-
- return id;
-}
-
-static int omap_reset_status(struct reset_controller_dev *rcdev,
- unsigned long id)
-{
- struct omap_reset_data *reset = to_omap_reset_data(rcdev);
- u32 v;
- int st_bit = omap_reset_get_st_bit(reset, id);
- bool has_rstst = reset->prm->data->rstst ||
- (reset->prm->data->flags & OMAP_PRM_HAS_RSTST);
-
- /* Check if we have rstst */
- if (!has_rstst)
- return -ENOTSUPP;
-
- /* Check if hw reset line is asserted */
- v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
- if (v & BIT(id))
- return 1;
-
- /*
- * Check reset status, high value means reset sequence has been
- * completed successfully so we can return 0 here (reset deasserted)
- */
- v = readl_relaxed(reset->prm->base + reset->prm->data->rstst);
- v >>= st_bit;
- v &= 1;
-
- return !v;
-}
-
-static int omap_reset_assert(struct reset_controller_dev *rcdev,
- unsigned long id)
-{
- struct omap_reset_data *reset = to_omap_reset_data(rcdev);
- u32 v;
- unsigned long flags;
-
- /* assert the reset control line */
- spin_lock_irqsave(&reset->lock, flags);
- v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
- v |= 1 << id;
- writel_relaxed(v, reset->prm->base + reset->prm->data->rstctrl);
- spin_unlock_irqrestore(&reset->lock, flags);
-
- return 0;
-}
-
-static int omap_reset_deassert(struct reset_controller_dev *rcdev,
- unsigned long id)
-{
- struct omap_reset_data *reset = to_omap_reset_data(rcdev);
- u32 v;
- int st_bit;
- bool has_rstst;
- unsigned long flags;
- struct ti_prm_platform_data *pdata = dev_get_platdata(reset->dev);
- int ret = 0;
-
- /* Nothing to do if the reset is already deasserted */
- if (!omap_reset_status(rcdev, id))
- return 0;
-
- has_rstst = reset->prm->data->rstst ||
- (reset->prm->data->flags & OMAP_PRM_HAS_RSTST);
-
- if (has_rstst) {
- st_bit = omap_reset_get_st_bit(reset, id);
-
- /* Clear the reset status by writing 1 to the status bit */
- v = 1 << st_bit;
- writel_relaxed(v, reset->prm->base + reset->prm->data->rstst);
- }
-
- if (reset->clkdm)
- pdata->clkdm_deny_idle(reset->clkdm);
-
- /* de-assert the reset control line */
- spin_lock_irqsave(&reset->lock, flags);
- v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
- v &= ~(1 << id);
- writel_relaxed(v, reset->prm->base + reset->prm->data->rstctrl);
- spin_unlock_irqrestore(&reset->lock, flags);
-
- /* wait for the reset bit to clear */
- ret = readl_relaxed_poll_timeout_atomic(reset->prm->base +
- reset->prm->data->rstctrl,
- v, !(v & BIT(id)), 1,
- OMAP_RESET_MAX_WAIT);
- if (ret)
- pr_err("%s: timedout waiting for %s:%lu\n", __func__,
- reset->prm->data->name, id);
-
- /* wait for the status to be set */
- if (has_rstst) {
- ret = readl_relaxed_poll_timeout_atomic(reset->prm->base +
- reset->prm->data->rstst,
- v, v & BIT(st_bit), 1,
- OMAP_RESET_MAX_WAIT);
- if (ret)
- pr_err("%s: timedout waiting for %s:%lu\n", __func__,
- reset->prm->data->name, id);
- }
-
- if (reset->clkdm)
- pdata->clkdm_allow_idle(reset->clkdm);
-
- return ret;
-}
-
-static const struct reset_control_ops omap_reset_ops = {
- .assert = omap_reset_assert,
- .deassert = omap_reset_deassert,
- .status = omap_reset_status,
-};
-
-static int omap_prm_reset_xlate(struct reset_controller_dev *rcdev,
- const struct of_phandle_args *reset_spec)
-{
- struct omap_reset_data *reset = to_omap_reset_data(rcdev);
-
- if (!_is_valid_reset(reset, reset_spec->args[0]))
- return -EINVAL;
-
- return reset_spec->args[0];
-}
-
-static int omap_prm_reset_init(struct platform_device *pdev,
- struct omap_prm *prm)
-{
- struct omap_reset_data *reset;
- const struct omap_rst_map *map;
- struct ti_prm_platform_data *pdata = dev_get_platdata(&pdev->dev);
- char buf[32];
- u32 v;
-
- /*
- * Check if we have controllable resets. If either rstctrl is non-zero
- * or OMAP_PRM_HAS_RSTCTRL flag is set, we have reset control register
- * for the domain.
- */
- if (!prm->data->rstctrl && !(prm->data->flags & OMAP_PRM_HAS_RSTCTRL))
- return 0;
-
- /* Check if we have the pdata callbacks in place */
- if (!pdata || !pdata->clkdm_lookup || !pdata->clkdm_deny_idle ||
- !pdata->clkdm_allow_idle)
- return -EINVAL;
-
- map = prm->data->rstmap;
- if (!map)
- return -EINVAL;
-
- reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL);
- if (!reset)
- return -ENOMEM;
-
- reset->rcdev.owner = THIS_MODULE;
- reset->rcdev.ops = &omap_reset_ops;
- reset->rcdev.of_node = pdev->dev.of_node;
- reset->rcdev.nr_resets = OMAP_MAX_RESETS;
- reset->rcdev.of_xlate = omap_prm_reset_xlate;
- reset->rcdev.of_reset_n_cells = 1;
- reset->dev = &pdev->dev;
- spin_lock_init(&reset->lock);
-
- reset->prm = prm;
-
- sprintf(buf, "%s_clkdm", prm->data->clkdm_name ? prm->data->clkdm_name :
- prm->data->name);
-
- if (!(prm->data->flags & OMAP_PRM_HAS_NO_CLKDM)) {
- reset->clkdm = pdata->clkdm_lookup(buf);
- if (!reset->clkdm)
- return -EINVAL;
- }
-
- while (map->rst >= 0) {
- reset->mask |= BIT(map->rst);
- map++;
- }
-
- /* Quirk handling to assert rst_map_012 bits on reset and avoid errors */
- if (prm->data->rstmap == rst_map_012) {
- v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
- if ((v & reset->mask) != reset->mask) {
- dev_dbg(&pdev->dev, "Asserting all resets: %08x\n", v);
- writel_relaxed(reset->mask, reset->prm->base +
- reset->prm->data->rstctrl);
- }
- }
-
- return devm_reset_controller_register(&pdev->dev, &reset->rcdev);
-}
-
-static int omap_prm_probe(struct platform_device *pdev)
-{
- struct resource *res;
- const struct omap_prm_data *data;
- struct omap_prm *prm;
- int ret;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
-
- data = of_device_get_match_data(&pdev->dev);
- if (!data)
- return -ENOTSUPP;
-
- prm = devm_kzalloc(&pdev->dev, sizeof(*prm), GFP_KERNEL);
- if (!prm)
- return -ENOMEM;
-
- while (data->base != res->start) {
- if (!data->base)
- return -EINVAL;
- data++;
- }
-
- prm->data = data;
-
- prm->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(prm->base))
- return PTR_ERR(prm->base);
-
- ret = omap_prm_domain_init(&pdev->dev, prm);
- if (ret)
- return ret;
-
- ret = omap_prm_reset_init(pdev, prm);
- if (ret)
- goto err_domain;
-
- return 0;
-
-err_domain:
- of_genpd_del_provider(pdev->dev.of_node);
- pm_genpd_remove(&prm->prmd->pd);
-
- return ret;
-}
-
-static struct platform_driver omap_prm_driver = {
- .probe = omap_prm_probe,
- .driver = {
- .name = KBUILD_MODNAME,
- .of_match_table = omap_prm_id_table,
- },
-};
-builtin_platform_driver(omap_prm_driver);
diff --git a/drivers/soc/ti/pm33xx.c b/drivers/soc/ti/pm33xx.c
index ce09c42eaed2..dc52a2197d24 100644
--- a/drivers/soc/ti/pm33xx.c
+++ b/drivers/soc/ti/pm33xx.c
@@ -145,7 +145,7 @@ static int am33xx_do_sram_idle(u32 wfi_flags)
return pm_ops->cpu_suspend(am33xx_do_wfi_sram, wfi_flags);
}
-static int __init am43xx_map_gic(void)
+static int am43xx_map_gic(void)
{
gic_dist_base = ioremap(AM43XX_GIC_DIST_BASE, SZ_4K);
@@ -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;
}
@@ -527,7 +517,7 @@ static int am33xx_pm_probe(struct platform_device *pdev)
ret = am33xx_pm_alloc_sram();
if (ret)
- return ret;
+ goto err_wkup_m3_ipc_put;
ret = am33xx_pm_rtc_setup();
if (ret)
@@ -572,17 +562,18 @@ err_pm_runtime_put:
pm_runtime_put_sync(dev);
err_pm_runtime_disable:
pm_runtime_disable(dev);
- wkup_m3_ipc_put(m3_ipc);
err_unsetup_rtc:
iounmap(rtc_base_virt);
clk_put(rtc_fck);
err_free_sram:
am33xx_pm_free_sram();
pm33xx_dev = NULL;
+err_wkup_m3_ipc_put:
+ wkup_m3_ipc_put(m3_ipc);
return ret;
}
-static int am33xx_pm_remove(struct platform_device *pdev)
+static void am33xx_pm_remove(struct platform_device *pdev)
{
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
@@ -593,7 +584,6 @@ static int am33xx_pm_remove(struct platform_device *pdev)
am33xx_pm_free_sram();
iounmap(rtc_base_virt);
clk_put(rtc_fck);
- return 0;
}
static struct platform_driver am33xx_pm_driver = {
diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c
index 6882c86b3ce5..038576805bfa 100644
--- a/drivers/soc/ti/pruss.c
+++ b/drivers/soc/ti/pruss.c
@@ -6,6 +6,7 @@
* Author(s):
* Suman Anna <s-anna@ti.com>
* Andrew F. Davis <afd@ti.com>
+ * Tero Kristo <t-kristo@ti.com>
*/
#include <linux/clk-provider.h>
@@ -13,12 +14,16 @@
#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/pruss_driver.h>
#include <linux/regmap.h>
+#include <linux/remoteproc.h>
#include <linux/slab.h>
+#include "pruss.h"
/**
* struct pruss_private_data - PRUSS driver private data
@@ -30,6 +35,257 @@ struct pruss_private_data {
bool has_core_mux_clock;
};
+/**
+ * pruss_get() - get the pruss for a given PRU remoteproc
+ * @rproc: remoteproc handle of a PRU instance
+ *
+ * Finds the parent pruss device for a PRU given the @rproc handle of the
+ * PRU remote processor. This function increments the pruss device's refcount,
+ * so always use pruss_put() to decrement it back once pruss isn't needed
+ * anymore.
+ *
+ * This API doesn't check if @rproc is valid or not. It is expected the caller
+ * will have done a pru_rproc_get() on @rproc, before calling this API to make
+ * sure that @rproc is valid.
+ *
+ * Return: pruss handle on success, and an ERR_PTR on failure using one
+ * of the following error values
+ * -EINVAL if invalid parameter
+ * -ENODEV if PRU device or PRUSS device is not found
+ */
+struct pruss *pruss_get(struct rproc *rproc)
+{
+ struct pruss *pruss;
+ struct device *dev;
+ struct platform_device *ppdev;
+
+ if (IS_ERR_OR_NULL(rproc))
+ return ERR_PTR(-EINVAL);
+
+ dev = &rproc->dev;
+
+ /* make sure it is PRU rproc */
+ if (!dev->parent || !is_pru_rproc(dev->parent))
+ return ERR_PTR(-ENODEV);
+
+ ppdev = to_platform_device(dev->parent->parent);
+ pruss = platform_get_drvdata(ppdev);
+ if (!pruss)
+ return ERR_PTR(-ENODEV);
+
+ get_device(pruss->dev);
+
+ return pruss;
+}
+EXPORT_SYMBOL_GPL(pruss_get);
+
+/**
+ * pruss_put() - decrement pruss device's usecount
+ * @pruss: pruss handle
+ *
+ * Complimentary function for pruss_get(). Needs to be called
+ * after the PRUSS is used, and only if the pruss_get() succeeds.
+ */
+void pruss_put(struct pruss *pruss)
+{
+ if (IS_ERR_OR_NULL(pruss))
+ return;
+
+ put_device(pruss->dev);
+}
+EXPORT_SYMBOL_GPL(pruss_put);
+
+/**
+ * pruss_request_mem_region() - request a memory resource
+ * @pruss: the pruss instance
+ * @mem_id: the memory resource id
+ * @region: pointer to memory region structure to be filled in
+ *
+ * This function allows a client driver to request a memory resource,
+ * and if successful, will let the client driver own the particular
+ * memory region until released using the pruss_release_mem_region()
+ * API.
+ *
+ * Return: 0 if requested memory region is available (in such case pointer to
+ * memory region is returned via @region), an error otherwise
+ */
+int pruss_request_mem_region(struct pruss *pruss, enum pruss_mem mem_id,
+ struct pruss_mem_region *region)
+{
+ if (!pruss || !region || mem_id >= PRUSS_MEM_MAX)
+ return -EINVAL;
+
+ mutex_lock(&pruss->lock);
+
+ if (pruss->mem_in_use[mem_id]) {
+ mutex_unlock(&pruss->lock);
+ return -EBUSY;
+ }
+
+ *region = pruss->mem_regions[mem_id];
+ pruss->mem_in_use[mem_id] = region;
+
+ mutex_unlock(&pruss->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_request_mem_region);
+
+/**
+ * pruss_release_mem_region() - release a memory resource
+ * @pruss: the pruss instance
+ * @region: the memory region to release
+ *
+ * This function is the complimentary function to
+ * pruss_request_mem_region(), and allows the client drivers to
+ * release back a memory resource.
+ *
+ * Return: 0 on success, an error code otherwise
+ */
+int pruss_release_mem_region(struct pruss *pruss,
+ struct pruss_mem_region *region)
+{
+ int id;
+
+ if (!pruss || !region)
+ return -EINVAL;
+
+ mutex_lock(&pruss->lock);
+
+ /* find out the memory region being released */
+ for (id = 0; id < PRUSS_MEM_MAX; id++) {
+ if (pruss->mem_in_use[id] == region)
+ break;
+ }
+
+ if (id == PRUSS_MEM_MAX) {
+ mutex_unlock(&pruss->lock);
+ return -EINVAL;
+ }
+
+ pruss->mem_in_use[id] = NULL;
+
+ mutex_unlock(&pruss->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_release_mem_region);
+
+/**
+ * pruss_cfg_get_gpmux() - get the current GPMUX value for a PRU device
+ * @pruss: pruss instance
+ * @pru_id: PRU identifier (0-1)
+ * @mux: pointer to store the current mux value into
+ *
+ * Return: 0 on success, or an error code otherwise
+ */
+int pruss_cfg_get_gpmux(struct pruss *pruss, enum pruss_pru_id pru_id, u8 *mux)
+{
+ int ret;
+ u32 val;
+
+ if (pru_id >= PRUSS_NUM_PRUS || !mux)
+ return -EINVAL;
+
+ ret = pruss_cfg_read(pruss, PRUSS_CFG_GPCFG(pru_id), &val);
+ if (!ret)
+ *mux = (u8)((val & PRUSS_GPCFG_PRU_MUX_SEL_MASK) >>
+ PRUSS_GPCFG_PRU_MUX_SEL_SHIFT);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pruss_cfg_get_gpmux);
+
+/**
+ * pruss_cfg_set_gpmux() - set the GPMUX value for a PRU device
+ * @pruss: pruss instance
+ * @pru_id: PRU identifier (0-1)
+ * @mux: new mux value for PRU
+ *
+ * Return: 0 on success, or an error code otherwise
+ */
+int pruss_cfg_set_gpmux(struct pruss *pruss, enum pruss_pru_id pru_id, u8 mux)
+{
+ if (mux >= PRUSS_GP_MUX_SEL_MAX ||
+ pru_id >= PRUSS_NUM_PRUS)
+ return -EINVAL;
+
+ return pruss_cfg_update(pruss, PRUSS_CFG_GPCFG(pru_id),
+ PRUSS_GPCFG_PRU_MUX_SEL_MASK,
+ (u32)mux << PRUSS_GPCFG_PRU_MUX_SEL_SHIFT);
+}
+EXPORT_SYMBOL_GPL(pruss_cfg_set_gpmux);
+
+/**
+ * pruss_cfg_gpimode() - set the GPI mode of the PRU
+ * @pruss: the pruss instance handle
+ * @pru_id: id of the PRU core within the PRUSS
+ * @mode: GPI mode to set
+ *
+ * Sets the GPI mode for a given PRU by programming the
+ * corresponding PRUSS_CFG_GPCFGx register
+ *
+ * Return: 0 on success, or an error code otherwise
+ */
+int pruss_cfg_gpimode(struct pruss *pruss, enum pruss_pru_id pru_id,
+ enum pruss_gpi_mode mode)
+{
+ if (pru_id >= PRUSS_NUM_PRUS || mode >= PRUSS_GPI_MODE_MAX)
+ return -EINVAL;
+
+ return pruss_cfg_update(pruss, PRUSS_CFG_GPCFG(pru_id),
+ PRUSS_GPCFG_PRU_GPI_MODE_MASK,
+ mode << PRUSS_GPCFG_PRU_GPI_MODE_SHIFT);
+}
+EXPORT_SYMBOL_GPL(pruss_cfg_gpimode);
+
+/**
+ * pruss_cfg_miirt_enable() - Enable/disable MII RT Events
+ * @pruss: the pruss instance
+ * @enable: enable/disable
+ *
+ * Enable/disable the MII RT Events for the PRUSS.
+ *
+ * Return: 0 on success, or an error code otherwise
+ */
+int pruss_cfg_miirt_enable(struct pruss *pruss, bool enable)
+{
+ u32 set = enable ? PRUSS_MII_RT_EVENT_EN : 0;
+
+ return pruss_cfg_update(pruss, PRUSS_CFG_MII_RT,
+ PRUSS_MII_RT_EVENT_EN, set);
+}
+EXPORT_SYMBOL_GPL(pruss_cfg_miirt_enable);
+
+/**
+ * pruss_cfg_xfr_enable() - Enable/disable XIN XOUT shift functionality
+ * @pruss: the pruss instance
+ * @pru_type: PRU core type identifier
+ * @enable: enable/disable
+ *
+ * Return: 0 on success, or an error code otherwise
+ */
+int pruss_cfg_xfr_enable(struct pruss *pruss, enum pru_type pru_type,
+ bool enable)
+{
+ u32 mask, set;
+
+ switch (pru_type) {
+ case PRU_TYPE_PRU:
+ mask = PRUSS_SPP_XFER_SHIFT_EN;
+ break;
+ case PRU_TYPE_RTU:
+ mask = PRUSS_SPP_RTU_XFR_SHIFT_EN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ set = enable ? mask : 0;
+
+ return pruss_cfg_update(pruss, PRUSS_CFG_SPP, mask, set);
+}
+EXPORT_SYMBOL_GPL(pruss_cfg_xfr_enable);
+
static void pruss_of_free_clk_provider(void *data)
{
struct device_node *clk_mux_np = data;
@@ -38,6 +294,11 @@ static void pruss_of_free_clk_provider(void *data)
of_node_put(clk_mux_np);
}
+static void pruss_clk_unregister_mux(void *data)
+{
+ clk_unregister_mux(data);
+}
+
static int pruss_clk_mux_setup(struct pruss *pruss, struct clk *clk_mux,
char *mux_name, struct device_node *clks_np)
{
@@ -93,8 +354,7 @@ static int pruss_clk_mux_setup(struct pruss *pruss, struct clk *clk_mux,
goto put_clk_mux_np;
}
- ret = devm_add_action_or_reset(dev, (void(*)(void *))clk_unregister_mux,
- clk_mux);
+ ret = devm_add_action_or_reset(dev, pruss_clk_unregister_mux, clk_mux);
if (ret) {
dev_err(dev, "failed to add clkmux unregister action %d", ret);
goto put_clk_mux_np;
@@ -120,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 %p\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 = {
@@ -164,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);
@@ -192,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) {
@@ -232,49 +517,11 @@ static int pruss_probe(struct platform_device *pdev)
return -ENOMEM;
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);
@@ -304,7 +551,7 @@ rpm_disable:
return ret;
}
-static int pruss_remove(struct platform_device *pdev)
+static void pruss_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -312,8 +559,6 @@ static int pruss_remove(struct platform_device *pdev)
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
-
- return 0;
}
/* instance-specific driver private data */
@@ -348,7 +593,7 @@ static struct platform_driver pruss_driver = {
.name = "pruss",
.of_match_table = pruss_of_match,
},
- .probe = pruss_probe,
+ .probe = pruss_probe,
.remove = pruss_remove,
};
module_platform_driver(pruss_driver);
diff --git a/drivers/soc/ti/pruss.h b/drivers/soc/ti/pruss.h
new file mode 100644
index 000000000000..6c55987e0e55
--- /dev/null
+++ b/drivers/soc/ti/pruss.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * PRU-ICSS Subsystem user interfaces
+ *
+ * Copyright (C) 2015-2023 Texas Instruments Incorporated - http://www.ti.com
+ * MD Danish Anwar <danishanwar@ti.com>
+ */
+
+#ifndef _SOC_TI_PRUSS_H_
+#define _SOC_TI_PRUSS_H_
+
+#include <linux/bits.h>
+#include <linux/regmap.h>
+
+/*
+ * PRU_ICSS_CFG registers
+ * SYSCFG, ISRP, ISP, IESP, IECP, SCRP applicable on AMxxxx devices only
+ */
+#define PRUSS_CFG_REVID 0x00
+#define PRUSS_CFG_SYSCFG 0x04
+#define PRUSS_CFG_GPCFG(x) (0x08 + (x) * 4)
+#define PRUSS_CFG_CGR 0x10
+#define PRUSS_CFG_ISRP 0x14
+#define PRUSS_CFG_ISP 0x18
+#define PRUSS_CFG_IESP 0x1C
+#define PRUSS_CFG_IECP 0x20
+#define PRUSS_CFG_SCRP 0x24
+#define PRUSS_CFG_PMAO 0x28
+#define PRUSS_CFG_MII_RT 0x2C
+#define PRUSS_CFG_IEPCLK 0x30
+#define PRUSS_CFG_SPP 0x34
+#define PRUSS_CFG_PIN_MX 0x40
+
+/* PRUSS_GPCFG register bits */
+#define PRUSS_GPCFG_PRU_GPI_MODE_MASK GENMASK(1, 0)
+#define PRUSS_GPCFG_PRU_GPI_MODE_SHIFT 0
+
+#define PRUSS_GPCFG_PRU_MUX_SEL_SHIFT 26
+#define PRUSS_GPCFG_PRU_MUX_SEL_MASK GENMASK(29, 26)
+
+/* PRUSS_MII_RT register bits */
+#define PRUSS_MII_RT_EVENT_EN BIT(0)
+
+/* PRUSS_SPP register bits */
+#define PRUSS_SPP_XFER_SHIFT_EN BIT(1)
+#define PRUSS_SPP_PRU1_PAD_HP_EN BIT(0)
+#define PRUSS_SPP_RTU_XFR_SHIFT_EN BIT(3)
+
+/**
+ * pruss_cfg_read() - read a PRUSS CFG sub-module register
+ * @pruss: the pruss instance handle
+ * @reg: register offset within the CFG sub-module
+ * @val: pointer to return the value in
+ *
+ * Reads a given register within the PRUSS CFG sub-module and
+ * returns it through the passed-in @val pointer
+ *
+ * Return: 0 on success, or an error code otherwise
+ */
+static int pruss_cfg_read(struct pruss *pruss, unsigned int reg, unsigned int *val)
+{
+ if (IS_ERR_OR_NULL(pruss))
+ return -EINVAL;
+
+ return regmap_read(pruss->cfg_regmap, reg, val);
+}
+
+/**
+ * pruss_cfg_update() - configure a PRUSS CFG sub-module register
+ * @pruss: the pruss instance handle
+ * @reg: register offset within the CFG sub-module
+ * @mask: bit mask to use for programming the @val
+ * @val: value to write
+ *
+ * Programs a given register within the PRUSS CFG sub-module
+ *
+ * Return: 0 on success, or an error code otherwise
+ */
+static int pruss_cfg_update(struct pruss *pruss, unsigned int reg,
+ unsigned int mask, unsigned int val)
+{
+ if (IS_ERR_OR_NULL(pruss))
+ return -EINVAL;
+
+ return regmap_update_bits(pruss->cfg_regmap, reg, mask, val);
+}
+
+#endif /* _SOC_TI_PRUSS_H_ */
diff --git a/drivers/soc/ti/smartreflex.c b/drivers/soc/ti/smartreflex.c
index 6a389a6444f3..ced3a73929e3 100644
--- a/drivers/soc/ti/smartreflex.c
+++ b/drivers/soc/ti/smartreflex.c
@@ -198,20 +198,16 @@ static void sr_stop_vddautocomp(struct omap_sr *sr)
*/
static int sr_late_init(struct omap_sr *sr_info)
{
- struct omap_sr_data *pdata = sr_info->pdev->dev.platform_data;
int ret = 0;
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);
}
- if (pdata && pdata->enable_on_init)
- sr_start_vddautocomp(sr_info);
-
return ret;
error:
@@ -819,7 +815,6 @@ static int omap_sr_probe(struct platform_device *pdev)
{
struct omap_sr *sr_info;
struct omap_sr_data *pdata = pdev->dev.platform_data;
- struct resource *mem;
struct dentry *nvalue_dir;
int i, ret = 0;
@@ -839,8 +834,7 @@ static int omap_sr_probe(struct platform_device *pdev)
return -EINVAL;
}
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- sr_info->base = devm_ioremap_resource(&pdev->dev, mem);
+ sr_info->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(sr_info->base))
return PTR_ERR(sr_info->base);
@@ -939,23 +933,10 @@ err_list_del:
return ret;
}
-static int omap_sr_remove(struct platform_device *pdev)
+static void omap_sr_remove(struct platform_device *pdev)
{
- struct omap_sr_data *pdata = pdev->dev.platform_data;
struct device *dev = &pdev->dev;
- struct omap_sr *sr_info;
-
- if (!pdata) {
- dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
- return -EINVAL;
- }
-
- sr_info = _sr_lookup(pdata->voltdm);
- if (IS_ERR(sr_info)) {
- dev_warn(&pdev->dev, "%s: omap_sr struct not found\n",
- __func__);
- return PTR_ERR(sr_info);
- }
+ struct omap_sr *sr_info = platform_get_drvdata(pdev);
if (sr_info->autocomp_active)
sr_stop_vddautocomp(sr_info);
@@ -964,25 +945,11 @@ static int omap_sr_remove(struct platform_device *pdev)
pm_runtime_disable(dev);
clk_unprepare(sr_info->fck);
list_del(&sr_info->node);
- return 0;
}
static void omap_sr_shutdown(struct platform_device *pdev)
{
- struct omap_sr_data *pdata = pdev->dev.platform_data;
- struct omap_sr *sr_info;
-
- if (!pdata) {
- dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
- return;
- }
-
- sr_info = _sr_lookup(pdata->voltdm);
- if (IS_ERR(sr_info)) {
- dev_warn(&pdev->dev, "%s: omap_sr struct not found\n",
- __func__);
- return;
- }
+ struct omap_sr *sr_info = platform_get_drvdata(pdev);
if (sr_info->autocomp_active)
sr_stop_vddautocomp(sr_info);
diff --git a/drivers/soc/ti/ti_sci_inta_msi.c b/drivers/soc/ti/ti_sci_inta_msi.c
index b9251e1d9a5c..193266f5e3f9 100644
--- a/drivers/soc/ti/ti_sci_inta_msi.c
+++ b/drivers/soc/ti/ti_sci_inta_msi.c
@@ -9,9 +9,10 @@
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/msi.h>
+#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/of_irq.h>
+#include <linux/platform_device.h>
#include <linux/soc/ti/ti_sci_inta_msi.h>
#include <linux/soc/ti/ti_sci_protocol.h>
@@ -102,19 +103,15 @@ int ti_sci_inta_msi_domain_alloc_irqs(struct device *dev,
if (ret)
return ret;
- msi_lock_descs(dev);
+ guard(msi_descs_lock)(dev);
nvec = ti_sci_inta_msi_alloc_descs(dev, res);
- if (nvec <= 0) {
- ret = nvec;
- goto unlock;
- }
+ if (nvec <= 0)
+ return nvec;
/* Use alloc ALL as it's unclear whether there are gaps in the indices */
ret = msi_domain_alloc_irqs_all_locked(dev, MSI_DEFAULT_DOMAIN, nvec);
if (ret)
dev_err(dev, "Failed to allocate IRQs %d\n", ret);
-unlock:
- msi_unlock_descs(dev);
return ret;
}
EXPORT_SYMBOL_GPL(ti_sci_inta_msi_domain_alloc_irqs);
diff --git a/drivers/soc/ti/ti_sci_pm_domains.c b/drivers/soc/ti/ti_sci_pm_domains.c
deleted file mode 100644
index a33ec7eaf23d..000000000000
--- a/drivers/soc/ti/ti_sci_pm_domains.c
+++ /dev/null
@@ -1,208 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * TI SCI Generic Power Domain Driver
- *
- * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/
- * J Keerthy <j-keerthy@ti.com>
- * Dave Gerlach <d-gerlach@ti.com>
- */
-
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <linux/slab.h>
-#include <linux/soc/ti/ti_sci_protocol.h>
-#include <dt-bindings/soc/ti,sci_pm_domain.h>
-
-/**
- * struct ti_sci_genpd_provider: holds common TI SCI genpd provider data
- * @ti_sci: handle to TI SCI protocol driver that provides ops to
- * communicate with system control processor.
- * @dev: pointer to dev for the driver for devm allocs
- * @pd_list: list of all the power domains on the device
- * @data: onecell data for genpd core
- */
-struct ti_sci_genpd_provider {
- const struct ti_sci_handle *ti_sci;
- struct device *dev;
- struct list_head pd_list;
- struct genpd_onecell_data data;
-};
-
-/**
- * struct ti_sci_pm_domain: TI specific data needed for power domain
- * @idx: index of the device that identifies it with the system
- * control processor.
- * @exclusive: Permissions for exclusive request or shared request of the
- * device.
- * @pd: generic_pm_domain for use with the genpd framework
- * @node: link for the genpd list
- * @parent: link to the parent TI SCI genpd provider
- */
-struct ti_sci_pm_domain {
- int idx;
- u8 exclusive;
- struct generic_pm_domain pd;
- struct list_head node;
- struct ti_sci_genpd_provider *parent;
-};
-
-#define genpd_to_ti_sci_pd(gpd) container_of(gpd, struct ti_sci_pm_domain, pd)
-
-/*
- * ti_sci_pd_power_off(): genpd power down hook
- * @domain: pointer to the powerdomain to power off
- */
-static int ti_sci_pd_power_off(struct generic_pm_domain *domain)
-{
- struct ti_sci_pm_domain *pd = genpd_to_ti_sci_pd(domain);
- const struct ti_sci_handle *ti_sci = pd->parent->ti_sci;
-
- return ti_sci->ops.dev_ops.put_device(ti_sci, pd->idx);
-}
-
-/*
- * ti_sci_pd_power_on(): genpd power up hook
- * @domain: pointer to the powerdomain to power on
- */
-static int ti_sci_pd_power_on(struct generic_pm_domain *domain)
-{
- struct ti_sci_pm_domain *pd = genpd_to_ti_sci_pd(domain);
- const struct ti_sci_handle *ti_sci = pd->parent->ti_sci;
-
- if (pd->exclusive)
- return ti_sci->ops.dev_ops.get_device_exclusive(ti_sci,
- pd->idx);
- else
- return ti_sci->ops.dev_ops.get_device(ti_sci, pd->idx);
-}
-
-/*
- * ti_sci_pd_xlate(): translation service for TI SCI genpds
- * @genpdspec: DT identification data for the genpd
- * @data: genpd core data for all the powerdomains on the device
- */
-static struct generic_pm_domain *ti_sci_pd_xlate(
- struct of_phandle_args *genpdspec,
- void *data)
-{
- struct genpd_onecell_data *genpd_data = data;
- unsigned int idx = genpdspec->args[0];
-
- if (genpdspec->args_count != 1 && genpdspec->args_count != 2)
- return ERR_PTR(-EINVAL);
-
- if (idx >= genpd_data->num_domains) {
- pr_err("%s: invalid domain index %u\n", __func__, idx);
- return ERR_PTR(-EINVAL);
- }
-
- if (!genpd_data->domains[idx])
- return ERR_PTR(-ENOENT);
-
- genpd_to_ti_sci_pd(genpd_data->domains[idx])->exclusive =
- genpdspec->args[1];
-
- return genpd_data->domains[idx];
-}
-
-static const struct of_device_id ti_sci_pm_domain_matches[] = {
- { .compatible = "ti,sci-pm-domain", },
- { },
-};
-MODULE_DEVICE_TABLE(of, ti_sci_pm_domain_matches);
-
-static int ti_sci_pm_domain_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct ti_sci_genpd_provider *pd_provider;
- struct ti_sci_pm_domain *pd;
- struct device_node *np = NULL;
- struct of_phandle_args args;
- int ret;
- u32 max_id = 0;
- int index;
-
- pd_provider = devm_kzalloc(dev, sizeof(*pd_provider), GFP_KERNEL);
- if (!pd_provider)
- return -ENOMEM;
-
- pd_provider->ti_sci = devm_ti_sci_get_handle(dev);
- if (IS_ERR(pd_provider->ti_sci))
- return PTR_ERR(pd_provider->ti_sci);
-
- pd_provider->dev = dev;
-
- INIT_LIST_HEAD(&pd_provider->pd_list);
-
- /* Find highest device ID used for power domains */
- while (1) {
- np = of_find_node_with_property(np, "power-domains");
- if (!np)
- break;
-
- index = 0;
-
- while (1) {
- ret = of_parse_phandle_with_args(np, "power-domains",
- "#power-domain-cells",
- index, &args);
- if (ret)
- break;
-
- if (args.args_count >= 1 && args.np == dev->of_node) {
- if (args.args[0] > max_id)
- max_id = args.args[0];
-
- pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
- if (!pd)
- return -ENOMEM;
-
- pd->pd.name = devm_kasprintf(dev, GFP_KERNEL,
- "pd:%d",
- args.args[0]);
- if (!pd->pd.name)
- return -ENOMEM;
-
- pd->pd.power_off = ti_sci_pd_power_off;
- pd->pd.power_on = ti_sci_pd_power_on;
- pd->idx = args.args[0];
- pd->parent = pd_provider;
-
- pm_genpd_init(&pd->pd, NULL, true);
-
- list_add(&pd->node, &pd_provider->pd_list);
- }
- index++;
- }
- }
-
- pd_provider->data.domains =
- devm_kcalloc(dev, max_id + 1,
- sizeof(*pd_provider->data.domains),
- GFP_KERNEL);
- if (!pd_provider->data.domains)
- return -ENOMEM;
-
- pd_provider->data.num_domains = max_id + 1;
- pd_provider->data.xlate = ti_sci_pd_xlate;
-
- list_for_each_entry(pd, &pd_provider->pd_list, node)
- pd_provider->data.domains[pd->idx] = &pd->pd;
-
- return of_genpd_add_provider_onecell(dev->of_node, &pd_provider->data);
-}
-
-static struct platform_driver ti_sci_pm_domains_driver = {
- .probe = ti_sci_pm_domain_probe,
- .driver = {
- .name = "ti_sci_pm_domains",
- .of_match_table = ti_sci_pm_domain_matches,
- },
-};
-module_platform_driver(ti_sci_pm_domains_driver);
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("TI System Control Interface (SCI) Power Domain driver");
-MODULE_AUTHOR("Dave Gerlach");
diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c
index 343c58ed5896..5845fc652adc 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>
@@ -202,7 +201,7 @@ static int wkup_m3_ipc_dbg_init(struct wkup_m3_ipc *m3_ipc)
{
m3_ipc->dbg_path = debugfs_create_dir("wkup_m3_ipc", NULL);
- if (!m3_ipc->dbg_path)
+ if (IS_ERR(m3_ipc->dbg_path))
return -EINVAL;
(void)debugfs_create_file("enable_late_halt", 0644,
@@ -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);
@@ -615,7 +612,6 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev)
int irq, ret, temp;
phandle rproc_phandle;
struct rproc *m3_rproc;
- struct resource *res;
struct task_struct *task;
struct wkup_m3_ipc *m3_ipc;
struct device_node *np = dev->of_node;
@@ -624,8 +620,7 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev)
if (!m3_ipc)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- m3_ipc->ipc_mem_base = devm_ioremap_resource(dev, res);
+ m3_ipc->ipc_mem_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(m3_ipc->ipc_mem_base))
return PTR_ERR(m3_ipc->ipc_mem_base);
@@ -649,11 +644,9 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev)
m3_ipc->mbox = mbox_request_channel(&m3_ipc->mbox_client, 0);
- if (IS_ERR(m3_ipc->mbox)) {
- dev_err(dev, "IPC Request for A8->M3 Channel failed! %ld\n",
- PTR_ERR(m3_ipc->mbox));
- return PTR_ERR(m3_ipc->mbox);
- }
+ if (IS_ERR(m3_ipc->mbox))
+ return dev_err_probe(dev, PTR_ERR(m3_ipc->mbox),
+ "IPC Request for A8->M3 Channel failed!\n");
if (of_property_read_u32(dev->of_node, "ti,rproc", &rproc_phandle)) {
dev_err(&pdev->dev, "could not get rproc phandle\n");
@@ -681,7 +674,7 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev)
dev_warn(dev, "Invalid VTT GPIO(%d) pin\n", temp);
}
- if (of_find_property(np, "ti,set-io-isolation", NULL))
+ if (of_property_read_bool(np, "ti,set-io-isolation"))
wkup_m3_set_io_isolation(m3_ipc);
ret = of_property_read_string(np, "firmware-name",
@@ -715,7 +708,7 @@ err_free_mbox:
return ret;
}
-static int wkup_m3_ipc_remove(struct platform_device *pdev)
+static void wkup_m3_ipc_remove(struct platform_device *pdev)
{
wkup_m3_ipc_dbg_destroy(m3_ipc_state);
@@ -725,8 +718,6 @@ static int wkup_m3_ipc_remove(struct platform_device *pdev)
rproc_put(m3_ipc_state->rproc);
m3_ipc_state = NULL;
-
- return 0;
}
static int __maybe_unused wkup_m3_ipc_suspend(struct device *dev)
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/vt8500/Kconfig b/drivers/soc/vt8500/Kconfig
new file mode 100644
index 000000000000..b4cc0ba1128b
--- /dev/null
+++ b/drivers/soc/vt8500/Kconfig
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+if ARCH_VT8500 || COMPILE_TEST
+
+menu "VIA/WonderMedia SoC drivers"
+
+config WMT_SOCINFO
+ bool "VIA/WonderMedia SoC Information driver"
+ default ARCH_VT8500
+ select SOC_BUS
+ help
+ Say yes to support decoding of VIA/WonderMedia system configuration
+ register information. This currently includes just the chip ID register
+ which helps identify the exact hardware revision of the SoC the kernel
+ is running on (to know if any revision-specific quirks are required)
+
+endmenu
+
+endif
diff --git a/drivers/soc/vt8500/Makefile b/drivers/soc/vt8500/Makefile
new file mode 100644
index 000000000000..05964c5f2890
--- /dev/null
+++ b/drivers/soc/vt8500/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_WMT_SOCINFO) += wmt-socinfo.o
diff --git a/drivers/soc/vt8500/wmt-socinfo.c b/drivers/soc/vt8500/wmt-socinfo.c
new file mode 100644
index 000000000000..461f8c1ae56e
--- /dev/null
+++ b/drivers/soc/vt8500/wmt-socinfo.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2025 Alexey Charkov <alchark@gmail.com>
+ * Based on aspeed-socinfo.c
+ */
+
+#include <linux/dev_printk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/sys_soc.h>
+
+static const struct {
+ const char *name;
+ const u32 id;
+} chip_id_table[] = {
+ /* VIA */
+ { "VT8420", 0x3300 },
+ { "VT8430", 0x3357 },
+ { "VT8500", 0x3400 },
+
+ /* WonderMedia */
+ { "WM8425", 0x3429 },
+ { "WM8435", 0x3437 },
+ { "WM8440", 0x3451 },
+ { "WM8505", 0x3426 },
+ { "WM8650", 0x3465 },
+ { "WM8750", 0x3445 },
+ { "WM8850", 0x3481 },
+ { "WM8880", 0x3498 },
+};
+
+static const char *sccid_to_name(u32 sccid)
+{
+ u32 id = sccid >> 16;
+ unsigned int i;
+
+ for (i = 0 ; i < ARRAY_SIZE(chip_id_table) ; ++i) {
+ if (chip_id_table[i].id == id)
+ return chip_id_table[i].name;
+ }
+
+ return "Unknown";
+}
+
+static int wmt_socinfo_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct soc_device_attribute *attrs;
+ struct soc_device *soc_dev;
+ char letter, digit;
+ void __iomem *reg;
+ u32 sccid;
+
+ reg = devm_of_iomap(&pdev->dev, np, 0, NULL);
+ if (IS_ERR(reg))
+ return PTR_ERR(reg);
+
+ sccid = readl(reg);
+
+ attrs = devm_kzalloc(&pdev->dev, sizeof(*attrs), GFP_KERNEL);
+ if (!attrs)
+ return -ENOMEM;
+
+ /*
+ * Machine: VIA APC Rock
+ * Family: WM8850
+ * Revision: A2
+ * SoC ID: raw silicon revision id (34810103 in hexadecimal)
+ */
+
+ attrs->family = sccid_to_name(sccid);
+
+ letter = (sccid >> 8) & 0xf;
+ letter = (letter - 1) + 'A';
+ digit = sccid & 0xff;
+ digit = (digit - 1) + '0';
+ attrs->revision = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+ "%c%c", letter, digit);
+
+ attrs->soc_id = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%08x", sccid);
+
+ if (!attrs->revision || !attrs->soc_id)
+ return -ENOMEM;
+
+ soc_dev = soc_device_register(attrs);
+ if (IS_ERR(soc_dev))
+ return PTR_ERR(soc_dev);
+
+ dev_info(&pdev->dev,
+ "VIA/WonderMedia %s rev %s (%s)\n",
+ attrs->family,
+ attrs->revision,
+ attrs->soc_id);
+
+ platform_set_drvdata(pdev, soc_dev);
+ return 0;
+}
+
+static void wmt_socinfo_remove(struct platform_device *pdev)
+{
+ struct soc_device *soc_dev = platform_get_drvdata(pdev);
+
+ soc_device_unregister(soc_dev);
+}
+
+static const struct of_device_id wmt_socinfo_ids[] = {
+ { .compatible = "via,vt8500-scc-id" },
+ { /* Sentinel */ },
+};
+
+static struct platform_driver wmt_socinfo = {
+ .probe = wmt_socinfo_probe,
+ .remove = wmt_socinfo_remove,
+ .driver = {
+ .name = "wmt-socinfo",
+ .of_match_table = wmt_socinfo_ids,
+ },
+};
+module_platform_driver(wmt_socinfo);
+
+MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>");
+MODULE_DESCRIPTION("VIA/WonderMedia socinfo driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/xilinx/Kconfig b/drivers/soc/xilinx/Kconfig
index 8a755a5c8836..49d69d6e18fe 100644
--- a/drivers/soc/xilinx/Kconfig
+++ b/drivers/soc/xilinx/Kconfig
@@ -16,15 +16,6 @@ config ZYNQMP_POWER
If in doubt, say N.
-config ZYNQMP_PM_DOMAINS
- bool "Enable Zynq MPSoC generic PM domains"
- default y
- depends on PM && ZYNQMP_FIRMWARE
- select PM_GENERIC_DOMAINS
- help
- Say yes to enable device power management through PM domains
- If in doubt, say N.
-
config XLNX_EVENT_MANAGER
bool "Enable Xilinx Event Management Driver"
depends on ZYNQMP_FIRMWARE
diff --git a/drivers/soc/xilinx/Makefile b/drivers/soc/xilinx/Makefile
index 41e585bc9c67..33d94395fd87 100644
--- a/drivers/soc/xilinx/Makefile
+++ b/drivers/soc/xilinx/Makefile
@@ -1,4 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_ZYNQMP_POWER) += zynqmp_power.o
-obj-$(CONFIG_ZYNQMP_PM_DOMAINS) += zynqmp_pm_domains.o
obj-$(CONFIG_XLNX_EVENT_MANAGER) += xlnx_event_manager.o
diff --git a/drivers/soc/xilinx/xlnx_event_manager.c b/drivers/soc/xilinx/xlnx_event_manager.c
index 2de082765bef..6fdf4d14b7e7 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);
@@ -77,11 +77,26 @@ struct registered_event_data {
static bool xlnx_is_error_event(const u32 node_id)
{
- if (node_id == EVENT_ERROR_PMC_ERR1 ||
- node_id == EVENT_ERROR_PMC_ERR2 ||
- node_id == EVENT_ERROR_PSM_ERR1 ||
- node_id == EVENT_ERROR_PSM_ERR2)
- return true;
+ u32 pm_family_code;
+
+ zynqmp_pm_get_family_info(&pm_family_code);
+
+ if (pm_family_code == PM_VERSAL_FAMILY_CODE) {
+ if (node_id == VERSAL_EVENT_ERROR_PMC_ERR1 ||
+ node_id == VERSAL_EVENT_ERROR_PMC_ERR2 ||
+ node_id == VERSAL_EVENT_ERROR_PSM_ERR1 ||
+ node_id == VERSAL_EVENT_ERROR_PSM_ERR2)
+ return true;
+ } else if (pm_family_code == PM_VERSAL_NET_FAMILY_CODE) {
+ if (node_id == VERSAL_NET_EVENT_ERROR_PMC_ERR1 ||
+ node_id == VERSAL_NET_EVENT_ERROR_PMC_ERR2 ||
+ node_id == VERSAL_NET_EVENT_ERROR_PMC_ERR3 ||
+ node_id == VERSAL_NET_EVENT_ERROR_PSM_ERR1 ||
+ node_id == VERSAL_NET_EVENT_ERROR_PSM_ERR2 ||
+ node_id == VERSAL_NET_EVENT_ERROR_PSM_ERR3 ||
+ node_id == VERSAL_NET_EVENT_ERROR_PSM_ERR4)
+ return true;
+ }
return false;
}
@@ -116,8 +131,10 @@ static int xlnx_add_cb_for_notify_event(const u32 node_id, const u32 event, cons
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;
@@ -171,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;
@@ -190,11 +209,12 @@ static int xlnx_remove_cb_for_suspend(event_cb_func_t cb_fun)
struct registered_event_data *eve_data;
struct agent_cb *cb_pos;
struct agent_cb *cb_next;
+ struct hlist_node *tmp;
is_need_to_unregister = false;
/* Check for existing entry in hash table for given cb_type */
- hash_for_each_possible(reg_driver_map, eve_data, hentry, PM_INIT_SUSPEND_CB) {
+ hash_for_each_possible_safe(reg_driver_map, eve_data, tmp, hentry, PM_INIT_SUSPEND_CB) {
if (eve_data->cb_type == PM_INIT_SUSPEND_CB) {
/* Delete the list of callback */
list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) {
@@ -226,11 +246,12 @@ static int xlnx_remove_cb_for_notify_event(const u32 node_id, const u32 event,
u64 key = ((u64)node_id << 32U) | (u64)event;
struct agent_cb *cb_pos;
struct agent_cb *cb_next;
+ struct hlist_node *tmp;
is_need_to_unregister = false;
/* Check for existing entry in hash table for given key id */
- hash_for_each_possible(reg_driver_map, eve_data, hentry, key) {
+ hash_for_each_possible_safe(reg_driver_map, eve_data, tmp, hentry, key) {
if (eve_data->key == key) {
/* Delete the list of callback */
list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) {
@@ -473,13 +494,13 @@ static void xlnx_call_notify_cb_handler(const u32 *payload)
}
}
if (!is_callback_found)
- pr_warn("Didn't find any registered callback for 0x%x 0x%x\n",
+ pr_warn("Unhandled SGI node 0x%x event 0x%x. Expected with Xen hypervisor\n",
payload[1], payload[2]);
}
static void xlnx_get_event_callback_data(u32 *buf)
{
- zynqmp_pm_invoke_fn(GET_CALLBACK_DATA, 0, 0, 0, 0, buf);
+ zynqmp_pm_invoke_fn(GET_CALLBACK_DATA, buf, 0);
}
static irqreturn_t xlnx_event_handler(int irq, void *dev_id)
@@ -551,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 = smp_processor_id();
/*
* IRQ related structures are used for the following:
* for each SGI interrupt ensure its mapped by GIC IRQ domain
@@ -588,9 +608,9 @@ static int xlnx_event_init_sgi(struct platform_device *pdev)
sgi_fwspec.param[0] = sgi_num;
virq_sgi = irq_create_fwspec_mapping(&sgi_fwspec);
- per_cpu(cpu_number1, cpu) = cpu;
ret = request_percpu_irq(virq_sgi, xlnx_event_handler, "xlnx_event_mgmt",
- &cpu_number1);
+ &dummy_cpu_number);
+
WARN_ON(ret);
if (ret) {
irq_dispose_mapping(virq_sgi);
@@ -605,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);
}
@@ -649,7 +665,11 @@ static int xlnx_event_manager_probe(struct platform_device *pdev)
ret = zynqmp_pm_register_sgi(sgi_num, 0);
if (ret) {
- dev_err(&pdev->dev, "SGI %d Registration over TF-A failed with %d\n", sgi_num, ret);
+ if (ret == -EOPNOTSUPP)
+ dev_err(&pdev->dev, "SGI registration not supported by TF-A or Xen\n");
+ else
+ dev_err(&pdev->dev, "SGI %d registration failed, err %d\n", sgi_num, ret);
+
xlnx_event_cleanup_sgi(pdev);
return ret;
}
@@ -662,7 +682,7 @@ static int xlnx_event_manager_probe(struct platform_device *pdev)
return ret;
}
-static int xlnx_event_manager_remove(struct platform_device *pdev)
+static void xlnx_event_manager_remove(struct platform_device *pdev)
{
int i;
struct registered_event_data *eve_data;
@@ -687,8 +707,6 @@ static int xlnx_event_manager_remove(struct platform_device *pdev)
xlnx_event_cleanup_sgi(pdev);
event_manager_availability = -EACCES;
-
- return ret;
}
static struct platform_driver xlnx_event_manager_driver = {
diff --git a/drivers/soc/xilinx/zynqmp_pm_domains.c b/drivers/soc/xilinx/zynqmp_pm_domains.c
deleted file mode 100644
index fcce2433bd6d..000000000000
--- a/drivers/soc/xilinx/zynqmp_pm_domains.c
+++ /dev/null
@@ -1,322 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * ZynqMP Generic PM domain support
- *
- * Copyright (C) 2015-2019 Xilinx, Inc.
- *
- * Davorin Mista <davorin.mista@aggios.com>
- * Jolly Shah <jollys@xilinx.com>
- * Rajan Vaja <rajan.vaja@xilinx.com>
- */
-
-#include <linux/err.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/of_platform.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <linux/slab.h>
-
-#include <linux/firmware/xlnx-zynqmp.h>
-
-#define ZYNQMP_NUM_DOMAINS (100)
-
-static int min_capability;
-
-/**
- * struct zynqmp_pm_domain - Wrapper around struct generic_pm_domain
- * @gpd: Generic power domain
- * @node_id: PM node ID corresponding to device inside PM domain
- * @requested: The PM node mapped to the PM domain has been requested
- */
-struct zynqmp_pm_domain {
- struct generic_pm_domain gpd;
- u32 node_id;
- bool requested;
-};
-
-#define to_zynqmp_pm_domain(pm_domain) \
- container_of(pm_domain, struct zynqmp_pm_domain, gpd)
-
-/**
- * zynqmp_gpd_is_active_wakeup_path() - Check if device is in wakeup source
- * path
- * @dev: Device to check for wakeup source path
- * @not_used: Data member (not required)
- *
- * This function is checks device's child hierarchy and checks if any device is
- * set as wakeup source.
- *
- * Return: 1 if device is in wakeup source path else 0
- */
-static int zynqmp_gpd_is_active_wakeup_path(struct device *dev, void *not_used)
-{
- int may_wakeup;
-
- may_wakeup = device_may_wakeup(dev);
- if (may_wakeup)
- return may_wakeup;
-
- return device_for_each_child(dev, NULL,
- zynqmp_gpd_is_active_wakeup_path);
-}
-
-/**
- * zynqmp_gpd_power_on() - Power on PM domain
- * @domain: Generic PM domain
- *
- * This function is called before devices inside a PM domain are resumed, to
- * power on PM domain.
- *
- * Return: 0 on success, error code otherwise
- */
-static int zynqmp_gpd_power_on(struct generic_pm_domain *domain)
-{
- struct zynqmp_pm_domain *pd = to_zynqmp_pm_domain(domain);
- int ret;
-
- ret = zynqmp_pm_set_requirement(pd->node_id,
- ZYNQMP_PM_CAPABILITY_ACCESS,
- ZYNQMP_PM_MAX_QOS,
- ZYNQMP_PM_REQUEST_ACK_BLOCKING);
- if (ret) {
- dev_err(&domain->dev,
- "failed to set requirement to 0x%x for PM node id %d: %d\n",
- ZYNQMP_PM_CAPABILITY_ACCESS, pd->node_id, ret);
- return ret;
- }
-
- dev_dbg(&domain->dev, "set requirement to 0x%x for PM node id %d\n",
- ZYNQMP_PM_CAPABILITY_ACCESS, pd->node_id);
-
- return 0;
-}
-
-/**
- * zynqmp_gpd_power_off() - Power off PM domain
- * @domain: Generic PM domain
- *
- * This function is called after devices inside a PM domain are suspended, to
- * power off PM domain.
- *
- * Return: 0 on success, error code otherwise
- */
-static int zynqmp_gpd_power_off(struct generic_pm_domain *domain)
-{
- struct zynqmp_pm_domain *pd = to_zynqmp_pm_domain(domain);
- int ret;
- struct pm_domain_data *pdd, *tmp;
- u32 capabilities = min_capability;
- bool may_wakeup;
-
- /* If domain is already released there is nothing to be done */
- if (!pd->requested) {
- dev_dbg(&domain->dev, "PM node id %d is already released\n",
- pd->node_id);
- return 0;
- }
-
- list_for_each_entry_safe(pdd, tmp, &domain->dev_list, list_node) {
- /* If device is in wakeup path, set capability to WAKEUP */
- may_wakeup = zynqmp_gpd_is_active_wakeup_path(pdd->dev, NULL);
- if (may_wakeup) {
- dev_dbg(pdd->dev, "device is in wakeup path in %s\n",
- domain->name);
- capabilities = ZYNQMP_PM_CAPABILITY_WAKEUP;
- break;
- }
- }
-
- ret = zynqmp_pm_set_requirement(pd->node_id, capabilities, 0,
- ZYNQMP_PM_REQUEST_ACK_NO);
- if (ret) {
- dev_err(&domain->dev,
- "failed to set requirement to 0x%x for PM node id %d: %d\n",
- capabilities, pd->node_id, ret);
- return ret;
- }
-
- dev_dbg(&domain->dev, "set requirement to 0x%x for PM node id %d\n",
- capabilities, pd->node_id);
-
- return 0;
-}
-
-/**
- * zynqmp_gpd_attach_dev() - Attach device to the PM domain
- * @domain: Generic PM domain
- * @dev: Device to attach
- *
- * Return: 0 on success, error code otherwise
- */
-static int zynqmp_gpd_attach_dev(struct generic_pm_domain *domain,
- struct device *dev)
-{
- struct zynqmp_pm_domain *pd = to_zynqmp_pm_domain(domain);
- struct device_link *link;
- int ret;
-
- link = device_link_add(dev, &domain->dev, DL_FLAG_SYNC_STATE_ONLY);
- if (!link)
- dev_dbg(&domain->dev, "failed to create device link for %s\n",
- dev_name(dev));
-
- /* If this is not the first device to attach there is nothing to do */
- if (domain->device_count)
- return 0;
-
- ret = zynqmp_pm_request_node(pd->node_id, 0, 0,
- ZYNQMP_PM_REQUEST_ACK_BLOCKING);
- if (ret) {
- dev_err(&domain->dev, "%s request failed for node %d: %d\n",
- domain->name, pd->node_id, ret);
- return ret;
- }
-
- pd->requested = true;
-
- dev_dbg(&domain->dev, "%s requested PM node id %d\n",
- dev_name(dev), pd->node_id);
-
- return 0;
-}
-
-/**
- * zynqmp_gpd_detach_dev() - Detach device from the PM domain
- * @domain: Generic PM domain
- * @dev: Device to detach
- */
-static void zynqmp_gpd_detach_dev(struct generic_pm_domain *domain,
- struct device *dev)
-{
- struct zynqmp_pm_domain *pd = to_zynqmp_pm_domain(domain);
- int ret;
-
- /* If this is not the last device to detach there is nothing to do */
- if (domain->device_count)
- return;
-
- ret = zynqmp_pm_release_node(pd->node_id);
- if (ret) {
- dev_err(&domain->dev, "failed to release PM node id %d: %d\n",
- pd->node_id, ret);
- return;
- }
-
- pd->requested = false;
-
- dev_dbg(&domain->dev, "%s released PM node id %d\n",
- dev_name(dev), pd->node_id);
-}
-
-static struct generic_pm_domain *zynqmp_gpd_xlate
- (struct of_phandle_args *genpdspec, void *data)
-{
- struct genpd_onecell_data *genpd_data = data;
- unsigned int i, idx = genpdspec->args[0];
- struct zynqmp_pm_domain *pd;
-
- pd = to_zynqmp_pm_domain(genpd_data->domains[0]);
-
- if (genpdspec->args_count != 1)
- return ERR_PTR(-EINVAL);
-
- /* Check for existing pm domains */
- for (i = 0; i < ZYNQMP_NUM_DOMAINS; i++) {
- if (pd[i].node_id == idx)
- goto done;
- }
-
- /**
- * Add index in empty node_id of power domain list as no existing
- * power domain found for current index.
- */
- for (i = 0; i < ZYNQMP_NUM_DOMAINS; i++) {
- if (pd[i].node_id == 0) {
- pd[i].node_id = idx;
- break;
- }
- }
-
-done:
- if (!genpd_data->domains[i] || i == ZYNQMP_NUM_DOMAINS)
- return ERR_PTR(-ENOENT);
-
- return genpd_data->domains[i];
-}
-
-static int zynqmp_gpd_probe(struct platform_device *pdev)
-{
- int i;
- struct genpd_onecell_data *zynqmp_pd_data;
- struct generic_pm_domain **domains;
- struct zynqmp_pm_domain *pd;
- struct device *dev = &pdev->dev;
-
- pd = devm_kcalloc(dev, ZYNQMP_NUM_DOMAINS, sizeof(*pd), GFP_KERNEL);
- if (!pd)
- return -ENOMEM;
-
- zynqmp_pd_data = devm_kzalloc(dev, sizeof(*zynqmp_pd_data), GFP_KERNEL);
- if (!zynqmp_pd_data)
- return -ENOMEM;
-
- zynqmp_pd_data->xlate = zynqmp_gpd_xlate;
-
- domains = devm_kcalloc(dev, ZYNQMP_NUM_DOMAINS, sizeof(*domains),
- GFP_KERNEL);
- if (!domains)
- return -ENOMEM;
-
- if (!of_device_is_compatible(dev->parent->of_node,
- "xlnx,zynqmp-firmware"))
- min_capability = ZYNQMP_PM_CAPABILITY_UNUSABLE;
-
- for (i = 0; i < ZYNQMP_NUM_DOMAINS; i++, pd++) {
- pd->node_id = 0;
- pd->gpd.name = kasprintf(GFP_KERNEL, "domain%d", i);
- pd->gpd.power_off = zynqmp_gpd_power_off;
- pd->gpd.power_on = zynqmp_gpd_power_on;
- pd->gpd.attach_dev = zynqmp_gpd_attach_dev;
- pd->gpd.detach_dev = zynqmp_gpd_detach_dev;
-
- domains[i] = &pd->gpd;
-
- /* Mark all PM domains as initially powered off */
- pm_genpd_init(&pd->gpd, NULL, true);
- }
-
- zynqmp_pd_data->domains = domains;
- zynqmp_pd_data->num_domains = ZYNQMP_NUM_DOMAINS;
- of_genpd_add_provider_onecell(dev->parent->of_node, zynqmp_pd_data);
-
- return 0;
-}
-
-static int zynqmp_gpd_remove(struct platform_device *pdev)
-{
- of_genpd_del_provider(pdev->dev.parent->of_node);
-
- return 0;
-}
-
-static void zynqmp_gpd_sync_state(struct device *dev)
-{
- int ret;
-
- ret = zynqmp_pm_init_finalize();
- if (ret)
- dev_warn(dev, "failed to release power management to firmware\n");
-}
-
-static struct platform_driver zynqmp_power_domain_driver = {
- .driver = {
- .name = "zynqmp_power_controller",
- .sync_state = zynqmp_gpd_sync_state,
- },
- .probe = zynqmp_gpd_probe,
- .remove = zynqmp_gpd_remove,
-};
-module_platform_driver(zynqmp_power_domain_driver);
-
-MODULE_ALIAS("platform:zynqmp_power_controller");
diff --git a/drivers/soc/xilinx/zynqmp_power.c b/drivers/soc/xilinx/zynqmp_power.c
index 78a8a7545d1e..9b7b2858b22a 100644
--- a/drivers/soc/xilinx/zynqmp_power.c
+++ b/drivers/soc/xilinx/zynqmp_power.c
@@ -11,6 +11,7 @@
#include <linux/mailbox_client.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/suspend.h>
@@ -29,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,
@@ -50,7 +69,20 @@ static enum pm_suspend_mode suspend_mode = PM_SUSPEND_MODE_STD;
static void zynqmp_pm_get_callback_data(u32 *buf)
{
- zynqmp_pm_invoke_fn(GET_CALLBACK_DATA, 0, 0, 0, 0, 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)
@@ -82,9 +114,11 @@ static irqreturn_t zynqmp_pm_isr(int irq, void *data)
pm_suspend(PM_SUSPEND_MEM);
break;
default:
- pr_err("%s Unsupported InitSuspendCb reason "
- "code %d\n", __func__, payload[1]);
+ pr_err("%s Unsupported InitSuspendCb reason code %d\n",
+ __func__, payload[1]);
}
+ } else {
+ pr_err("%s() Unsupported Callback %d\n", __func__, payload[0]);
}
return IRQ_HANDLED;
@@ -117,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
*
@@ -181,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, 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)
@@ -200,25 +303,49 @@ 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);
+ if (ret < 0)
+ return ret;
+
+ if (pm_family_code == PM_VERSAL_NET_FAMILY_CODE)
+ node_id = PM_DEV_ACPU_0_0;
+ else if (pm_family_code == PM_VERSAL_FAMILY_CODE)
+ node_id = PM_DEV_ACPU_0;
+ else
+ return -ENODEV;
+
+ 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;
- } else if (of_find_property(pdev->dev.of_node, "mboxes", NULL)) {
+ } else if (of_property_present(pdev->dev.of_node, "mboxes")) {
zynqmp_pm_init_suspend_work =
devm_kzalloc(&pdev->dev,
sizeof(struct zynqmp_pm_work_struct),
@@ -240,10 +367,10 @@ static int zynqmp_pm_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Failed to request rx channel\n");
return PTR_ERR(rx_chan);
}
- } else if (of_find_property(pdev->dev.of_node, "interrupts", NULL)) {
+ } else if (of_property_present(pdev->dev.of_node, "interrupts")) {
irq = platform_get_irq(pdev, 0);
- if (irq <= 0)
- return -ENXIO;
+ if (irq < 0)
+ return irq;
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
zynqmp_pm_isr,
@@ -251,8 +378,8 @@ static int zynqmp_pm_probe(struct platform_device *pdev)
dev_name(&pdev->dev),
&pdev->dev);
if (ret) {
- dev_err(&pdev->dev, "devm_request_threaded_irq '%d' "
- "failed with %d\n", irq, ret);
+ dev_err(&pdev->dev, "devm_request_threaded_irq '%d' failed with %d\n",
+ irq, ret);
return ret;
}
} else {
@@ -261,29 +388,18 @@ 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;
}
-static int zynqmp_pm_remove(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);
-
- return 0;
}
static const struct of_device_id pm_of_match[] = {