summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig1
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/adc/meson-saradc.c8
-rw-r--r--drivers/adc/stm32-adc-core.c1
-rw-r--r--drivers/adc/stm32-adc.c88
-rw-r--r--drivers/ata/sata_mv.c43
-rw-r--r--drivers/block/Kconfig1
-rw-r--r--drivers/block/efi_blk.c2
-rw-r--r--drivers/bus/Kconfig1
-rw-r--r--drivers/clk/Kconfig4
-rw-r--r--drivers/clk/airoha/clk-airoha.c127
-rw-r--r--drivers/clk/altera/clk-agilex.c130
-rw-r--r--drivers/clk/altera/clk-agilex.h20
-rw-r--r--drivers/clk/at91/Kconfig2
-rw-r--r--drivers/clk/at91/clk-sam9x60-pll.c7
-rw-r--r--drivers/clk/at91/pmc.h1
-rw-r--r--drivers/clk/at91/sam9x60.c2
-rw-r--r--drivers/clk/at91/sam9x7.c5
-rw-r--r--drivers/clk/at91/sama7d65.c1
-rw-r--r--drivers/clk/at91/sama7g5.c1
-rw-r--r--drivers/clk/clk-stub.c3
-rw-r--r--drivers/clk/clk_scmi.c160
-rw-r--r--drivers/clk/clk_versaclock.c10
-rw-r--r--drivers/clk/clk_versal.c55
-rw-r--r--drivers/clk/meson/g12a.c2
-rw-r--r--drivers/clk/qcom/Kconfig15
-rw-r--r--drivers/clk/qcom/Makefile2
-rw-r--r--drivers/clk/qcom/clock-sc7280.c28
-rw-r--r--drivers/clk/qcom/clock-sdm845.c127
-rw-r--r--drivers/clk/qcom/clock-sm6350.c193
-rw-r--r--drivers/clk/qcom/clock-sm7150.c250
-rw-r--r--drivers/clk/qcom/clock-sm8250.c5
-rw-r--r--drivers/clk/renesas/Kconfig4
-rw-r--r--drivers/clk/rockchip/clk_px30.c6
-rw-r--r--drivers/clk/sifive/Kconfig2
-rw-r--r--drivers/clk/sophgo/clk-common.h2
-rw-r--r--drivers/clk/ti/Kconfig8
-rw-r--r--drivers/core/ofnode.c29
-rw-r--r--drivers/cpu/imx8_cpu.c4
-rw-r--r--drivers/crypto/fsl/jr.c2
-rw-r--r--drivers/crypto/tegra/Kconfig2
-rw-r--r--drivers/ddr/altera/iossm_mailbox.c24
-rw-r--r--drivers/ddr/altera/sdram_soc64.c6
-rw-r--r--drivers/ddr/altera/sdram_soc64.h2
-rw-r--r--drivers/dfu/Kconfig1
-rw-r--r--drivers/fastboot/fb_nand.c7
-rw-r--r--drivers/firmware/firmware-zynqmp.c36
-rw-r--r--drivers/firmware/scmi/Kconfig8
-rw-r--r--drivers/firmware/scmi/Makefile1
-rw-r--r--drivers/firmware/scmi/sandbox-scmi_agent.c4
-rw-r--r--drivers/firmware/scmi/scmi_agent-uclass.c40
-rw-r--r--drivers/firmware/scmi/smt.c14
-rw-r--r--drivers/firmware/scmi/vendors/imx/Kconfig15
-rw-r--r--drivers/firmware/scmi/vendors/imx/Makefile8
-rw-r--r--drivers/firmware/scmi/vendors/imx/imx-sm-cpu.c179
-rw-r--r--drivers/firmware/scmi/vendors/imx/imx-sm-lmm.c213
-rw-r--r--drivers/firmware/ti_sci.c12
-rw-r--r--drivers/fpga/versalpl.c5
-rw-r--r--drivers/fpga/zynqmppl.c8
-rw-r--r--drivers/gpio/Kconfig7
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/ftgpio010.c110
-rw-r--r--drivers/gpio/gpio-aspeed-g7.c2
-rw-r--r--drivers/gpio/gpio-rcar.c84
-rw-r--r--drivers/gpio/gpio-uclass.c2
-rw-r--r--drivers/gpio/intel_gpio.c18
-rw-r--r--drivers/gpio/qcom_spmi_gpio.c4
-rw-r--r--drivers/gpio/tegra_gpio.c40
-rw-r--r--drivers/gpio/zynqmp_gpio_modepin.c4
-rw-r--r--drivers/i2c/Kconfig9
-rw-r--r--drivers/i2c/Makefile1
-rw-r--r--drivers/i2c/designware_i2c.c2
-rw-r--r--drivers/i2c/geni_i2c.c14
-rw-r--r--drivers/i2c/mt7621_i2c.c374
-rw-r--r--drivers/i2c/muxes/i2c-mux-uclass.c4
-rw-r--r--drivers/i2c/rcar_i2c.c1
-rw-r--r--drivers/iommu/qcom-hyp-smmu.c4
-rw-r--r--drivers/led/Kconfig5
-rw-r--r--drivers/led/led-uclass.c3
-rw-r--r--drivers/mailbox/mailbox-uclass.c9
-rw-r--r--drivers/memory/Kconfig2
-rw-r--r--drivers/misc/Kconfig10
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/fs_loader.c47
-rw-r--r--drivers/misc/nuvoton_nct6102d.c2
-rw-r--r--drivers/misc/qcom_geni.c580
-rw-r--r--drivers/misc/qfw_acpi.c1
-rw-r--r--drivers/misc/smsc_lpc47m.c2
-rw-r--r--drivers/misc/winbond_w83627.c2
-rw-r--r--drivers/mmc/cv1800b_sdhci.c2
-rw-r--r--drivers/mmc/dw_mmc.c44
-rw-r--r--drivers/mmc/exynos_dw_mmc.c182
-rw-r--r--drivers/mmc/mmc.c77
-rw-r--r--drivers/mmc/octeontx_hsmmc.c5
-rw-r--r--drivers/mmc/omap_hsmmc.c1
-rw-r--r--drivers/mmc/owl_mmc.c18
-rw-r--r--drivers/mmc/renesas-sdhi.c1
-rw-r--r--drivers/mmc/rockchip_sdhci.c27
-rw-r--r--drivers/mmc/sdhci-cadence6.c18
-rw-r--r--drivers/mmc/socfpga_dw_mmc.c33
-rw-r--r--drivers/mmc/zynq_sdhci.c13
-rw-r--r--drivers/mtd/Kconfig4
-rw-r--r--drivers/mtd/nand/raw/Kconfig19
-rw-r--r--drivers/mtd/nand/raw/am335x_spl_bch.c2
-rw-r--r--drivers/mtd/nand/raw/nand_base.c2
-rw-r--r--drivers/mtd/nand/spi/Makefile5
-rw-r--r--drivers/mtd/nand/spi/alliancememory.c155
-rw-r--r--drivers/mtd/nand/spi/ato.c88
-rw-r--r--drivers/mtd/nand/spi/core.c976
-rw-r--r--drivers/mtd/nand/spi/esmt.c123
-rw-r--r--drivers/mtd/nand/spi/fmsh.c76
-rw-r--r--drivers/mtd/nand/spi/foresee.c107
-rw-r--r--drivers/mtd/nand/spi/gigadevice.c86
-rw-r--r--drivers/mtd/nand/spi/macronix.c289
-rw-r--r--drivers/mtd/nand/spi/micron.c180
-rw-r--r--drivers/mtd/nand/spi/otp.c369
-rw-r--r--drivers/mtd/nand/spi/paragon.c24
-rw-r--r--drivers/mtd/nand/spi/skyhigh.c149
-rw-r--r--drivers/mtd/nand/spi/toshiba.c63
-rw-r--r--drivers/mtd/nand/spi/winbond.c361
-rw-r--r--drivers/mtd/nand/spi/xtx.c20
-rw-r--r--drivers/mtd/nvmxip/nvmxip.c4
-rw-r--r--drivers/mtd/nvmxip/nvmxip_qspi.c2
-rw-r--r--drivers/mtd/spi/sf_dataflash.c8
-rw-r--r--drivers/mtd/spi/spi-nor-ids.c6
-rw-r--r--drivers/mtd/ubi/io.c7
-rw-r--r--drivers/mtd/ubispl/ubispl.c2
-rw-r--r--drivers/net/Kconfig22
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/airoha_eth.c118
-rw-r--r--drivers/net/designware.c14
-rw-r--r--drivers/net/fsl_enetc_mdio.c25
-rw-r--r--drivers/net/fsl_enetc_netc_blk_ctrl.c329
-rw-r--r--drivers/net/mdio-mt7531-mmio.c168
-rw-r--r--drivers/net/mdio-mt7531-mmio.h9
-rw-r--r--drivers/net/mdio_mux_meson_gxl.c3
-rw-r--r--drivers/net/mtk_eth/Kconfig2
-rw-r--r--drivers/net/mtk_eth/mt7531.c20
-rw-r--r--drivers/net/mtk_eth/mt7988.c92
-rw-r--r--drivers/net/phy/Kconfig2
-rw-r--r--drivers/net/phy/aquantia.c2
-rw-r--r--drivers/net/phy/mediatek/Kconfig2
-rw-r--r--drivers/net/phy/mediatek/mtk-2p5ge.c8
-rw-r--r--drivers/net/phy/phy.c113
-rw-r--r--drivers/net/rswitch.c441
-rw-r--r--drivers/net/sun8i_emac.c40
-rw-r--r--drivers/net/ti/am65-cpsw-nuss.c35
-rw-r--r--drivers/net/xilinx_axi_emac.c16
-rw-r--r--drivers/net/zynq_gem.c95
-rw-r--r--drivers/pci/Kconfig6
-rw-r--r--drivers/pci/Makefile1
-rw-r--r--drivers/pci/pci-rcar-gen4.c33
-rw-r--r--drivers/pci/pci_mvebu.c2
-rw-r--r--drivers/pci/pcie_intel_fpga.c434
-rw-r--r--drivers/pci_endpoint/pcie_cdns_ti_ep.c33
-rw-r--r--drivers/phy/Kconfig14
-rw-r--r--drivers/phy/Makefile2
-rw-r--r--drivers/phy/marvell/Kconfig1
-rw-r--r--drivers/phy/qcom/Kconfig6
-rw-r--r--drivers/phy/qcom/phy-qcom-qmp-ufs.c62
-rw-r--r--drivers/phy/renesas/Kconfig12
-rw-r--r--drivers/phy/renesas/Makefile2
-rw-r--r--drivers/phy/renesas/r8a78000-ether-pcs.c424
-rw-r--r--drivers/phy/renesas/r8a78000-mp-phy.c225
-rw-r--r--drivers/phy/ti/phy-j721e-wiz.c29
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson.c20
-rw-r--r--drivers/pinctrl/nxp/pinctrl-imx-scmi.c5
-rw-r--r--drivers/pinctrl/pinctrl-zynqmp.c24
-rw-r--r--drivers/pinctrl/qcom/Kconfig20
-rw-r--r--drivers/pinctrl/qcom/Makefile3
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sc7280.c6
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sdm670.c247
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm6350.c104
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm7150.c142
-rw-r--r--drivers/pinctrl/renesas/Kconfig38
-rw-r--r--drivers/pinctrl/renesas/Makefile1
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a7790.c1
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a7791.c1
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a7792.c1
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a7794.c1
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a77951.c1
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a7796.c1
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a77965.c1
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a77970.c1
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a77980.c1
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a77990.c1
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a77995.c1
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a779a0.c1
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a779f0.c1
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a779g0.c101
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a779h0.c7
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a78000.c5254
-rw-r--r--drivers/pinctrl/renesas/pfc.c24
-rw-r--r--drivers/pinctrl/renesas/sh_pfc.h5
-rw-r--r--drivers/power/domain/Kconfig2
-rw-r--r--drivers/power/domain/zynqmp-power-domain.c2
-rw-r--r--drivers/power/pmic/s2mps11.c37
-rw-r--r--drivers/power/regulator/Kconfig2
-rw-r--r--drivers/power/regulator/fixed.c1
-rw-r--r--drivers/power/regulator/gpio-regulator.c1
-rw-r--r--drivers/power/regulator/qcom-rpmh-regulator.c31
-rw-r--r--drivers/power/regulator/regulator_common.c11
-rw-r--r--drivers/power/regulator/regulator_common.h1
-rw-r--r--drivers/power/regulator/s2mps11_regulator.c590
-rw-r--r--drivers/pwm/Kconfig54
-rw-r--r--drivers/pwm/pwm-cadence-ttc.c10
-rw-r--r--drivers/pwm/pwm-meson.c3
-rw-r--r--drivers/remoteproc/Kconfig7
-rw-r--r--drivers/remoteproc/Makefile1
-rw-r--r--drivers/remoteproc/imx_rproc.c370
-rw-r--r--drivers/remoteproc/imx_rproc.h56
-rw-r--r--drivers/remoteproc/renesas_apmu.c3
-rw-r--r--drivers/remoteproc/rproc-elf-loader.c95
-rw-r--r--drivers/remoteproc/sandbox_testproc.c3
-rw-r--r--drivers/remoteproc/stm32_copro.c3
-rw-r--r--drivers/remoteproc/ti_k3_dsp_rproc.c2
-rw-r--r--drivers/remoteproc/ti_k3_m4_rproc.c2
-rw-r--r--drivers/remoteproc/ti_k3_r5f_rproc.c2
-rw-r--r--drivers/reset/reset-airoha.c106
-rw-r--r--drivers/reset/reset-zynqmp.c2
-rw-r--r--drivers/rng/Kconfig4
-rw-r--r--drivers/rtc/ds1672.c2
-rw-r--r--drivers/scsi/scsi.c7
-rw-r--r--drivers/serial/Kconfig5
-rw-r--r--drivers/serial/serial_msm.c127
-rw-r--r--drivers/serial/serial_msm_geni.c107
-rw-r--r--drivers/serial/serial_sh.c11
-rw-r--r--drivers/soc/soc_amd_versal2.c2
-rw-r--r--drivers/soc/soc_xilinx_versal.c2
-rw-r--r--drivers/soc/soc_xilinx_versal_net.c2
-rw-r--r--drivers/soc/soc_xilinx_zynqmp.c2
-rw-r--r--drivers/sound/Kconfig10
-rw-r--r--drivers/sound/maxim_codec.c4
-rw-r--r--drivers/sound/maxim_codec.h4
-rw-r--r--drivers/sound/wm8994.c4
-rw-r--r--drivers/spi/Kconfig5
-rw-r--r--drivers/spi/airoha_snfi_spi.c688
-rw-r--r--drivers/spi/altera_spi.c1
-rw-r--r--drivers/spi/cadence_ospi_versal.c4
-rw-r--r--drivers/spi/cadence_qspi.c4
-rw-r--r--drivers/spi/cadence_qspi_apb.c4
-rw-r--r--drivers/spi/ich.c2
-rw-r--r--drivers/spi/npcm_fiu_spi.c3
-rw-r--r--drivers/spi/nxp_fspi.c50
-rw-r--r--drivers/spi/rockchip_sfc.c13
-rw-r--r--drivers/spi/spi-mem.c78
-rw-r--r--drivers/spi/spi-uclass.c3
-rw-r--r--drivers/spmi/spmi-sandbox.c2
-rw-r--r--drivers/tee/Makefile4
-rw-r--r--drivers/tee/optee/Makefile2
-rw-r--r--drivers/thermal/Kconfig8
-rw-r--r--drivers/thermal/Makefile1
-rw-r--r--drivers/thermal/imx_scu_thermal.c2
-rw-r--r--drivers/thermal/imx_thermal.c2
-rw-r--r--drivers/thermal/imx_tmu.c35
-rw-r--r--drivers/thermal/rcar_gen3_thermal.c467
-rw-r--r--drivers/thermal/thermal_sandbox.c2
-rw-r--r--drivers/thermal/ti-bandgap.c2
-rw-r--r--drivers/thermal/ti-lm74.c4
-rw-r--r--drivers/timer/Kconfig4
-rw-r--r--drivers/timer/riscv_aclint_timer.c1
-rw-r--r--drivers/timer/tegra-timer.c10
-rw-r--r--drivers/tpm/tpm_tis_infineon.c2
-rw-r--r--drivers/ufs/Kconfig72
-rw-r--r--drivers/ufs/Makefile7
-rw-r--r--drivers/ufs/cdns-platform.c8
-rw-r--r--drivers/ufs/ti-j721e-ufs.c6
-rw-r--r--drivers/ufs/ufs-amd-versal2.c18
-rw-r--r--drivers/ufs/ufs-mediatek-sip.h56
-rw-r--r--drivers/ufs/ufs-mediatek.c395
-rw-r--r--drivers/ufs/ufs-mediatek.h210
-rw-r--r--drivers/ufs/ufs-pci.c8
-rw-r--r--drivers/ufs/ufs-qcom.c8
-rw-r--r--drivers/ufs/ufs-renesas-rcar-gen5.c268
-rw-r--r--drivers/ufs/ufs-renesas.c8
-rw-r--r--drivers/ufs/ufs-rockchip.c203
-rw-r--r--drivers/ufs/ufs-rockchip.h88
-rw-r--r--drivers/ufs/ufs-uclass.c2303
-rw-r--r--drivers/ufs/ufs.c2093
-rw-r--r--drivers/ufs/ufs.h14
-rw-r--r--drivers/ufs/unipro.h1
-rw-r--r--drivers/usb/Kconfig2
-rw-r--r--drivers/usb/common/fsl-dt-fixup.c2
-rw-r--r--drivers/usb/common/fsl-errata.c2
-rw-r--r--drivers/usb/dwc3/Kconfig9
-rw-r--r--drivers/usb/dwc3/ep0.c5
-rw-r--r--drivers/usb/gadget/Kconfig17
-rw-r--r--drivers/usb/gadget/Makefile2
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c2
-rw-r--r--drivers/usb/gadget/bcm_udc_otg.h19
-rw-r--r--drivers/usb/gadget/bcm_udc_otg_phy.c54
-rw-r--r--drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c2
-rw-r--r--drivers/usb/gadget/f_sdp.c2
-rw-r--r--drivers/usb/gadget/max3420_udc.c879
-rw-r--r--drivers/usb/host/Kconfig14
-rw-r--r--drivers/usb/host/ehci-exynos.c3
-rw-r--r--drivers/usb/host/ehci-msm.c146
-rw-r--r--drivers/usb/host/ohci-hcd.c6
-rw-r--r--drivers/usb/host/xhci-brcm.c2
-rw-r--r--drivers/usb/host/xhci-exynos5.c5
-rw-r--r--drivers/usb/host/xhci-generic.c2
-rw-r--r--drivers/usb/host/xhci-mtk.c2
-rw-r--r--drivers/usb/host/xhci-mvebu.c2
-rw-r--r--drivers/usb/host/xhci-rcar.c2
-rw-r--r--drivers/usb/musb-new/Kconfig3
-rw-r--r--drivers/usb/musb-new/am35x.c4
-rw-r--r--drivers/usb/musb-new/musb_core.c2
-rw-r--r--drivers/usb/musb-new/musb_gadget.c4
-rw-r--r--drivers/usb/musb-new/musb_gadget_ep0.c5
-rw-r--r--drivers/usb/musb-new/musb_host.c2
-rw-r--r--drivers/usb/musb-new/omap2430.c34
-rw-r--r--drivers/usb/musb-new/ti-musb.c28
-rw-r--r--drivers/usb/musb/Kconfig20
-rw-r--r--drivers/usb/musb/Makefile9
-rw-r--r--drivers/usb/musb/am35x.c138
-rw-r--r--drivers/usb/musb/am35x.h81
-rw-r--r--drivers/usb/musb/musb_core.c150
-rw-r--r--drivers/usb/musb/musb_core.h343
-rw-r--r--drivers/usb/musb/musb_debug.h191
-rw-r--r--drivers/usb/musb/musb_hcd.c1161
-rw-r--r--drivers/usb/musb/musb_hcd.h93
-rw-r--r--drivers/usb/musb/musb_udc.c953
-rw-r--r--drivers/usb/musb/omap3.c129
-rw-r--r--drivers/usb/musb/omap3.h38
-rw-r--r--drivers/usb/ulpi/ulpi.c2
-rw-r--r--drivers/video/efi.c2
-rw-r--r--drivers/video/simple_panel.c1
-rw-r--r--drivers/video/stm32/Kconfig9
-rw-r--r--drivers/video/stm32/Makefile1
-rw-r--r--drivers/video/stm32/stm32_ltdc.c158
-rw-r--r--drivers/video/stm32/stm32_lvds.c693
-rw-r--r--drivers/video/tegra/tegra124/dp.c2
-rw-r--r--drivers/video/tegra/tegra124/sor.c2
-rw-r--r--drivers/video/zynqmp/zynqmp_dpsub.c12
-rw-r--r--drivers/virtio/virtio-uclass.c2
-rw-r--r--drivers/virtio/virtio_blk.c5
-rw-r--r--drivers/w1-eeprom/ds24xxx.c2
-rw-r--r--drivers/w1-eeprom/ds2502.c2
-rw-r--r--drivers/watchdog/Kconfig26
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/tegra_wdt.c118
341 files changed, 20841 insertions, 9313 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 0b0c610e629..fe35e07b124 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -162,6 +162,7 @@ source "drivers/xen/Kconfig"
config PHYS_TO_BUS
bool "Custom physical to bus address mapping"
+ depends on !COMPILE_TEST
help
Some SoCs use a different address map for CPU physical addresses and
peripheral DMA master accesses. If yours does, select this option in
diff --git a/drivers/Makefile b/drivers/Makefile
index 7560008a842..77fc66eb8ba 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_MULTIPLEXER) += mux/
obj-$(CONFIG_$(PHASE_)ETH) += net/
obj-$(CONFIG_$(PHASE_)PCH) += pch/
obj-$(CONFIG_$(PHASE_)PCI) += pci/
+obj-$(CONFIG_$(PHASE_)PCI_ENDPOINT) += pci_endpoint/
obj-$(CONFIG_$(PHASE_)PHY) += phy/
obj-$(CONFIG_$(PHASE_)PINCTRL) += pinctrl/
obj-$(CONFIG_$(PHASE_)POWER) += power/
diff --git a/drivers/adc/meson-saradc.c b/drivers/adc/meson-saradc.c
index 60e348968fb..0144ff828c5 100644
--- a/drivers/adc/meson-saradc.c
+++ b/drivers/adc/meson-saradc.c
@@ -205,9 +205,9 @@ static int meson_saradc_lock(struct meson_saradc_priv *priv)
do {
udelay(1);
regmap_read(priv->regmap, MESON_SAR_ADC_DELAY, &val);
- } while (val & MESON_SAR_ADC_DELAY_BL30_BUSY && timeout--);
+ } while (val & MESON_SAR_ADC_DELAY_BL30_BUSY && --timeout);
- if (timeout < 0) {
+ if (!timeout) {
printf("Timeout while waiting for BL30 unlock\n");
return -ETIMEDOUT;
}
@@ -256,9 +256,9 @@ static int meson_saradc_wait_busy_clear(struct meson_saradc_priv *priv)
do {
udelay(1);
regmap_read(priv->regmap, MESON_SAR_ADC_REG0, &regval);
- } while (FIELD_GET(MESON_SAR_ADC_REG0_BUSY_MASK, regval) && timeout--);
+ } while (FIELD_GET(MESON_SAR_ADC_REG0_BUSY_MASK, regval) && --timeout);
- if (timeout < 0)
+ if (!timeout)
return -ETIMEDOUT;
return 0;
diff --git a/drivers/adc/stm32-adc-core.c b/drivers/adc/stm32-adc-core.c
index af340b8b273..3446e34fa46 100644
--- a/drivers/adc/stm32-adc-core.c
+++ b/drivers/adc/stm32-adc-core.c
@@ -200,6 +200,7 @@ err_aclk_disable:
static const struct udevice_id stm32_adc_core_ids[] = {
{ .compatible = "st,stm32h7-adc-core" },
{ .compatible = "st,stm32mp1-adc-core" },
+ { .compatible = "st,stm32mp13-adc-core" },
{}
};
diff --git a/drivers/adc/stm32-adc.c b/drivers/adc/stm32-adc.c
index d50f00f1233..b11f771b71c 100644
--- a/drivers/adc/stm32-adc.c
+++ b/drivers/adc/stm32-adc.c
@@ -49,29 +49,68 @@
/* STM32H7_ADC_SQR1 - bit fields */
#define STM32H7_SQ1_SHIFT 6
+/* STM32H7_ADC_DIFSEL - bit fields */
+#define STM32H7_DIFSEL_SHIFT 0
+#define STM32H7_DIFSEL_MASK GENMASK(19, 0)
+
/* BOOST bit must be set on STM32H7 when ADC clock is above 20MHz */
#define STM32H7_BOOST_CLKRATE 20000000UL
+/* STM32MP13 - Registers for each ADC instance */
+#define STM32MP13_ADC_DIFSEL 0xB0
+
+/* STM32MP13_ADC_CFGR specific bit fields */
+#define STM32MP13_DMAEN BIT(0)
+#define STM32MP13_DMACFG BIT(1)
+
+/* STM32MP13_ADC_DIFSEL - bit fields */
+#define STM32MP13_DIFSEL_SHIFT 0
+#define STM32MP13_DIFSEL_MASK GENMASK(18, 0)
+
#define STM32_ADC_CH_MAX 20 /* max number of channels */
#define STM32_ADC_TIMEOUT_US 100000
+struct stm32_adc {
+ void __iomem *regs;
+ int active_channel;
+ const struct stm32_adc_cfg *cfg;
+};
+
+struct stm32_adc_regs {
+ int reg;
+ int mask;
+ int shift;
+};
+
+struct stm32_adc_regspec {
+ const struct stm32_adc_regs difsel;
+};
+
struct stm32_adc_cfg {
+ const struct stm32_adc_regspec *regs;
unsigned int max_channels;
unsigned int num_bits;
bool has_vregready;
+ bool has_boostmode;
+ bool has_linearcal;
+ bool has_presel;
};
-struct stm32_adc {
- void __iomem *regs;
- int active_channel;
- const struct stm32_adc_cfg *cfg;
+static const struct stm32_adc_regspec stm32h7_adc_regspec = {
+ .difsel = { STM32H7_ADC_DIFSEL, STM32H7_DIFSEL_MASK },
+};
+
+static const struct stm32_adc_regspec stm32mp13_adc_regspec = {
+ .difsel = { STM32MP13_ADC_DIFSEL, STM32MP13_DIFSEL_MASK },
};
static void stm32_adc_enter_pwr_down(struct udevice *dev)
{
struct stm32_adc *adc = dev_get_priv(dev);
- clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST);
+ if (adc->cfg->has_boostmode)
+ clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST);
+
/* Setting DEEPPWD disables ADC vreg and clears ADVREGEN */
setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD);
}
@@ -90,8 +129,7 @@ static int stm32_adc_exit_pwr_down(struct udevice *dev)
/* Exit deep power down, then enable ADC voltage regulator */
clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD);
setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADVREGEN);
-
- if (common->rate > STM32H7_BOOST_CLKRATE)
+ if (adc->cfg->has_boostmode && common->rate > STM32H7_BOOST_CLKRATE)
setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST);
/* Wait for startup time */
@@ -134,7 +172,7 @@ static int stm32_adc_start_channel(struct udevice *dev, int channel)
return ret;
/* Only use single ended channels */
- writel(0, adc->regs + STM32H7_ADC_DIFSEL);
+ clrbits_le32(adc->regs + adc->cfg->regs->difsel.reg, adc->cfg->regs->difsel.mask);
/* Enable ADC, Poll for ADRDY to be set (after adc startup time) */
setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADEN);
@@ -147,7 +185,8 @@ static int stm32_adc_start_channel(struct udevice *dev, int channel)
}
/* Preselect channels */
- writel(uc_pdata->channel_mask, adc->regs + STM32H7_ADC_PCSEL);
+ if (adc->cfg->has_presel)
+ writel(uc_pdata->channel_mask, adc->regs + STM32H7_ADC_PCSEL);
/* Set sampling time to max value by default */
writel(0xffffffff, adc->regs + STM32H7_ADC_SMPR1);
@@ -156,9 +195,11 @@ static int stm32_adc_start_channel(struct udevice *dev, int channel)
/* Program regular sequence: chan in SQ1 & len = 0 for one channel */
writel(channel << STM32H7_SQ1_SHIFT, adc->regs + STM32H7_ADC_SQR1);
- /* Trigger detection disabled (conversion can be launched in SW) */
- clrbits_le32(adc->regs + STM32H7_ADC_CFGR, STM32H7_EXTEN |
- STM32H7_DMNGT);
+ /*
+ * Trigger detection disabled (conversion can be launched in SW)
+ * STM32H7_DMNGT is equivalent to STM32MP13_DMAEN & STM32MP13_DMACFG
+ */
+ clrbits_le32(adc->regs + STM32H7_ADC_CFGR, STM32H7_EXTEN | STM32H7_DMNGT);
adc->active_channel = channel;
return 0;
@@ -206,7 +247,7 @@ static int stm32_adc_selfcalib(struct udevice *dev)
{
struct stm32_adc *adc = dev_get_priv(dev);
int ret;
- u32 val;
+ u32 val, mask;
/*
* Select calibration mode:
@@ -231,7 +272,10 @@ static int stm32_adc_selfcalib(struct udevice *dev)
* - Linearity calibration (needs to be done only once for single/diff)
* will run simultaneously with offset calibration.
*/
- setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCALDIF | STM32H7_ADCALLIN);
+ mask = STM32H7_ADCALDIF;
+ if (adc->cfg->has_linearcal)
+ mask |= STM32H7_ADCALLIN;
+ setbits_le32(adc->regs + STM32H7_ADC_CR, mask);
/* Start calibration, then wait for completion */
setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCAL);
@@ -394,14 +438,28 @@ static const struct adc_ops stm32_adc_ops = {
};
static const struct stm32_adc_cfg stm32h7_adc_cfg = {
+ .regs = &stm32h7_adc_regspec,
.num_bits = 16,
.max_channels = STM32_ADC_CH_MAX,
+ .has_boostmode = true,
+ .has_linearcal = true,
+ .has_presel = true,
};
static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
+ .regs = &stm32h7_adc_regspec,
.num_bits = 16,
.max_channels = STM32_ADC_CH_MAX,
.has_vregready = true,
+ .has_boostmode = true,
+ .has_linearcal = true,
+ .has_presel = true,
+};
+
+static const struct stm32_adc_cfg stm32mp13_adc_cfg = {
+ .regs = &stm32mp13_adc_regspec,
+ .num_bits = 12,
+ .max_channels = STM32_ADC_CH_MAX - 1,
};
static const struct udevice_id stm32_adc_ids[] = {
@@ -409,6 +467,8 @@ static const struct udevice_id stm32_adc_ids[] = {
.data = (ulong)&stm32h7_adc_cfg },
{ .compatible = "st,stm32mp1-adc",
.data = (ulong)&stm32mp1_adc_cfg },
+ { .compatible = "st,stm32mp13-adc",
+ .data = (ulong)&stm32mp13_adc_cfg },
{}
};
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index ac78760a33e..b8c73b4a9dd 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -363,7 +363,7 @@ static int mv_start_edma_engine(struct udevice *dev, int port)
return 0;
}
-static int mv_reset_channel(struct udevice *dev, int port)
+static void mv_reset_channel(struct udevice *dev, int port)
{
struct mv_priv *priv = dev_get_plat(dev);
@@ -374,8 +374,6 @@ static int mv_reset_channel(struct udevice *dev, int port)
udelay(25); /* allow reset propagation */
out_le32(priv->regbase + EDMA_CMD, 0);
mdelay(10);
-
- return 0;
}
static void mv_reset_port(struct udevice *dev, int port)
@@ -578,9 +576,9 @@ static void process_responses(struct udevice *dev, int port)
}
}
-static int mv_ata_exec_ata_cmd(struct udevice *dev, int port,
- struct sata_fis_h2d *cfis,
- u8 *buffer, u32 len, u32 iswrite)
+static void mv_ata_exec_ata_cmd(struct udevice *dev, int port,
+ struct sata_fis_h2d *cfis,
+ u8 *buffer, lbaint_t len, u32 iswrite)
{
struct mv_priv *priv = dev_get_plat(dev);
struct crqb *req;
@@ -589,7 +587,7 @@ static int mv_ata_exec_ata_cmd(struct udevice *dev, int port,
if (len >= 64 * 1024) {
printf("We only support <64K transfers for now\n");
- return -1;
+ return;
}
/* Initialize request */
@@ -653,7 +651,7 @@ static int mv_ata_exec_ata_cmd(struct udevice *dev, int port,
/* Wait for completion */
if (wait_dma_completion(dev, port, slot, 10000)) {
printf("ATA operation timed out\n");
- return -1;
+ return;
}
process_responses(dev, port);
@@ -664,16 +662,13 @@ static int mv_ata_exec_ata_cmd(struct udevice *dev, int port,
invalidate_dcache_range(start,
start + ALIGN(len, ARCH_DMA_MINALIGN));
}
-
- return len;
}
-static u32 mv_sata_rw_cmd_ext(struct udevice *dev, int port, lbaint_t start,
- u32 blkcnt,
- u8 *buffer, int is_write)
+static void mv_sata_rw_cmd_ext(struct udevice *dev, int port, lbaint_t start,
+ lbaint_t blkcnt,
+ u8 *buffer, int is_write)
{
struct sata_fis_h2d cfis;
- u32 res;
u64 block;
block = (u64)start;
@@ -693,18 +688,15 @@ static u32 mv_sata_rw_cmd_ext(struct udevice *dev, int port, lbaint_t start,
cfis.sector_count_exp = (blkcnt >> 8) & 0xff;
cfis.sector_count = blkcnt & 0xff;
- res = mv_ata_exec_ata_cmd(dev, port, &cfis, buffer,
- ATA_SECT_SIZE * blkcnt, is_write);
-
- return res >= 0 ? blkcnt : res;
+ mv_ata_exec_ata_cmd(dev, port, &cfis, buffer,
+ ATA_SECT_SIZE * blkcnt, is_write);
}
-static u32 mv_sata_rw_cmd(struct udevice *dev, int port, lbaint_t start,
- u32 blkcnt, u8 *buffer, int is_write)
+static void mv_sata_rw_cmd(struct udevice *dev, int port, lbaint_t start,
+ lbaint_t blkcnt, u8 *buffer, int is_write)
{
struct sata_fis_h2d cfis;
lbaint_t block;
- u32 res;
block = start;
@@ -720,19 +712,16 @@ static u32 mv_sata_rw_cmd(struct udevice *dev, int port, lbaint_t start,
cfis.lba_low = block & 0xff;
cfis.sector_count = (u8)(blkcnt & 0xff);
- res = mv_ata_exec_ata_cmd(dev, port, &cfis, buffer,
- ATA_SECT_SIZE * blkcnt, is_write);
-
- return res >= 0 ? blkcnt : res;
+ mv_ata_exec_ata_cmd(dev, port, &cfis, buffer,
+ ATA_SECT_SIZE * blkcnt, is_write);
}
static u32 ata_low_level_rw(struct udevice *dev, int port, lbaint_t blknr,
lbaint_t blkcnt, void *buffer, int is_write)
{
struct blk_desc *desc = dev_get_uclass_plat(dev);
- lbaint_t start, blks;
+ lbaint_t start, blks, max_blks;
u8 *addr;
- int max_blks;
debug("%s: " LBAFU " " LBAFU "\n", __func__, blknr, blkcnt);
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index c6c148ebd17..185da2b5cfc 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -137,6 +137,7 @@ endif # EFI_MEDIA
config IDE
bool "Support IDE controllers"
+ depends on !COMPILE_TEST
select BLK
help
Enables support for IDE (Integrated Drive Electronics) hard drives.
diff --git a/drivers/block/efi_blk.c b/drivers/block/efi_blk.c
index 9766cd6f832..f3ae70290e7 100644
--- a/drivers/block/efi_blk.c
+++ b/drivers/block/efi_blk.c
@@ -49,7 +49,7 @@ static ulong efi_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
* Write to block device
*
* @dev: device
- * @blknr: first block to be write
+ * @blknr: first block to write
* @blkcnt: number of blocks to write
* @buffer: input buffer
* Return: number of blocks transferred
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index e60aa722b97..a786fe430e4 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -14,6 +14,7 @@ config TI_PWMSS
config TI_SYSC
bool "TI sysc interconnect target module driver"
depends on DM && ARCH_OMAP2PLUS
+ select CLK
help
Generic driver for Texas Instruments interconnect target module
found on many TI SoCs.
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index e6483ddc88b..b884a02bdeb 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -131,7 +131,7 @@ config CLK_BOSTON
config CLK_CDCE9XX
bool "Enable CDCD9XX clock driver"
- depends on CLK
+ depends on CLK && ARCH_OMAP2PLUS
help
Enable the clock synthesizer driver for CDCE913/925/937/949
series of chips.
@@ -169,7 +169,7 @@ config CLK_K210_SET_RATE
config CLK_MPC83XX
bool "Enable MPC83xx clock driver"
- depends on CLK
+ depends on CLK && MPC83xx
help
Support for the clock driver of the MPC83xx series of SoCs.
diff --git a/drivers/clk/airoha/clk-airoha.c b/drivers/clk/airoha/clk-airoha.c
index 1b2c4c98de5..49dbca82135 100644
--- a/drivers/clk/airoha/clk-airoha.c
+++ b/drivers/clk/airoha/clk-airoha.c
@@ -16,7 +16,7 @@
#include <dm/device_compat.h>
#include <dm/lists.h>
#include <regmap.h>
-#include <syscon.h>
+#include <asm/arch/scu-regmap.h>
#include <dt-bindings/clock/en7523-clk.h>
@@ -26,6 +26,7 @@
#define REG_SPI_CLK_DIV_SEL 0x1c4
#define REG_SPI_CLK_FREQ_SEL 0x1c8
#define REG_NPU_CLK_DIV_SEL 0x1fc
+#define REG_CRYPTO_CLKSRC 0x200
#define REG_NP_SCU_PCIC 0x88
#define REG_NP_SCU_SSTR 0x9c
@@ -33,6 +34,7 @@
#define REG_PCIE_XSI1_SEL_MASK GENMASK(12, 11)
#define REG_CRYPTO_CLKSRC2 0x20c
+#define EN7523_MAX_CLKS 8
#define EN7581_MAX_CLKS 9
struct airoha_clk_desc {
@@ -66,14 +68,119 @@ struct airoha_clk_soc_data {
};
static const u32 gsw_base[] = { 400000000, 500000000 };
+static const u32 emi_base[] = { 333000000, 400000000 };
+static const u32 bus_base[] = { 500000000, 540000000 };
static const u32 slic_base[] = { 100000000, 3125000 };
-
+static const u32 npu_base[] = { 333000000, 400000000, 500000000 };
+/* EN7581 */
static const u32 emi7581_base[] = { 540000000, 480000000, 400000000, 300000000 };
static const u32 bus7581_base[] = { 600000000, 540000000 };
static const u32 npu7581_base[] = { 800000000, 750000000, 720000000, 600000000 };
static const u32 crypto_base[] = { 540000000, 480000000 };
static const u32 emmc7581_base[] = { 200000000, 150000000 };
+static const struct airoha_clk_desc en7523_base_clks[EN7523_MAX_CLKS] = {
+ [EN7523_CLK_GSW] = {
+ .id = EN7523_CLK_GSW,
+ .name = "gsw",
+
+ .base_reg = REG_GSW_CLK_DIV_SEL,
+ .base_bits = 1,
+ .base_shift = 8,
+ .base_values = gsw_base,
+ .n_base_values = ARRAY_SIZE(gsw_base),
+
+ .div_bits = 3,
+ .div_shift = 0,
+ .div_step = 1,
+ .div_offset = 1,
+ },
+ [EN7523_CLK_EMI] = {
+ .id = EN7523_CLK_EMI,
+ .name = "emi",
+
+ .base_reg = REG_EMI_CLK_DIV_SEL,
+ .base_bits = 1,
+ .base_shift = 8,
+ .base_values = emi_base,
+ .n_base_values = ARRAY_SIZE(emi_base),
+
+ .div_bits = 3,
+ .div_shift = 0,
+ .div_step = 1,
+ .div_offset = 1,
+ },
+ [EN7523_CLK_BUS] = {
+ .id = EN7523_CLK_BUS,
+ .name = "bus",
+
+ .base_reg = REG_BUS_CLK_DIV_SEL,
+ .base_bits = 1,
+ .base_shift = 8,
+ .base_values = bus_base,
+ .n_base_values = ARRAY_SIZE(bus_base),
+
+ .div_bits = 3,
+ .div_shift = 0,
+ .div_step = 1,
+ .div_offset = 1,
+ },
+ [EN7523_CLK_SLIC] = {
+ .id = EN7523_CLK_SLIC,
+ .name = "slic",
+
+ .base_reg = REG_SPI_CLK_FREQ_SEL,
+ .base_bits = 1,
+ .base_shift = 0,
+ .base_values = slic_base,
+ .n_base_values = ARRAY_SIZE(slic_base),
+
+ .div_reg = REG_SPI_CLK_DIV_SEL,
+ .div_bits = 5,
+ .div_shift = 24,
+ .div_val0 = 20,
+ .div_step = 2,
+ },
+ [EN7523_CLK_SPI] = {
+ .id = EN7523_CLK_SPI,
+ .name = "spi",
+
+ .base_reg = REG_SPI_CLK_DIV_SEL,
+
+ .base_value = 400000000,
+
+ .div_bits = 5,
+ .div_shift = 8,
+ .div_val0 = 40,
+ .div_step = 2,
+ },
+ [EN7523_CLK_NPU] = {
+ .id = EN7523_CLK_NPU,
+ .name = "npu",
+
+ .base_reg = REG_NPU_CLK_DIV_SEL,
+ .base_bits = 2,
+ .base_shift = 8,
+ .base_values = npu_base,
+ .n_base_values = ARRAY_SIZE(npu_base),
+
+ .div_bits = 3,
+ .div_shift = 0,
+ .div_step = 1,
+ .div_offset = 1,
+ },
+ [EN7523_CLK_CRYPTO] = {
+ .id = EN7523_CLK_CRYPTO,
+ .name = "crypto",
+
+ .base_reg = REG_CRYPTO_CLKSRC,
+ .base_bits = 1,
+ .base_shift = 0,
+ .base_values = emi_base,
+ .n_base_values = ARRAY_SIZE(emi_base),
+ }
+};
+
static const struct airoha_clk_desc en7581_base_clks[EN7581_MAX_CLKS] = {
[EN7523_CLK_GSW] = {
.id = EN7523_CLK_GSW,
@@ -400,14 +507,8 @@ const struct clk_ops airoha_clk_ops = {
static int airoha_clk_probe(struct udevice *dev)
{
struct airoha_clk_priv *priv = dev_get_priv(dev);
- ofnode chip_scu_node;
-
- chip_scu_node = ofnode_by_compatible(ofnode_null(),
- "airoha,en7581-chip-scu");
- if (!ofnode_valid(chip_scu_node))
- return -EINVAL;
- priv->chip_scu_map = syscon_node_to_regmap(chip_scu_node);
+ priv->chip_scu_map = airoha_get_chip_scu_regmap();
if (IS_ERR(priv->chip_scu_map))
return PTR_ERR(priv->chip_scu_map);
@@ -431,12 +532,20 @@ static int airoha_clk_bind(struct udevice *dev)
return ret;
}
+static const struct airoha_clk_soc_data en7523_data = {
+ .num_clocks = ARRAY_SIZE(en7523_base_clks),
+ .descs = en7523_base_clks,
+};
+
static const struct airoha_clk_soc_data en7581_data = {
.num_clocks = ARRAY_SIZE(en7581_base_clks),
.descs = en7581_base_clks,
};
static const struct udevice_id airoha_clk_ids[] = {
+ { .compatible = "airoha,en7523-scu",
+ .data = (ulong)&en7523_data,
+ },
{ .compatible = "airoha,en7581-scu",
.data = (ulong)&en7581_data,
},
diff --git a/drivers/clk/altera/clk-agilex.c b/drivers/clk/altera/clk-agilex.c
index 242740a4b00..fdbf834bb2f 100644
--- a/drivers/clk/altera/clk-agilex.c
+++ b/drivers/clk/altera/clk-agilex.c
@@ -14,6 +14,7 @@
#include <dm/lists.h>
#include <dm/util.h>
#include <dt-bindings/clock/agilex-clock.h>
+#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <asm/arch/clock_manager.h>
@@ -22,6 +23,8 @@ DECLARE_GLOBAL_DATA_PTR;
struct socfpga_clk_plat {
void __iomem *regs;
+ int pllgrp;
+ int bitmask;
};
/*
@@ -544,14 +547,11 @@ static u32 clk_get_emac_clk_hz(struct socfpga_clk_plat *plat, u32 emac_id)
/* Get EMAC clock source */
ctl = CM_REG_READL(plat, CLKMGR_PERPLL_EMACCTL);
if (emac_id == AGILEX_EMAC0_CLK)
- ctl = (ctl >> CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_OFFSET) &
- CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_MASK;
+ ctl = FIELD_GET(CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_MASK, ctl);
else if (emac_id == AGILEX_EMAC1_CLK)
- ctl = (ctl >> CLKMGR_PERPLLGRP_EMACCTL_EMAC1SELB_OFFSET) &
- CLKMGR_PERPLLGRP_EMACCTL_EMAC1SELB_MASK;
+ ctl = FIELD_GET(CLKMGR_PERPLLGRP_EMACCTL_EMAC1SELB_MASK, ctl);
else if (emac_id == AGILEX_EMAC2_CLK)
- ctl = (ctl >> CLKMGR_PERPLLGRP_EMACCTL_EMAC2SELB_OFFSET) &
- CLKMGR_PERPLLGRP_EMACCTL_EMAC2SELB_MASK;
+ ctl = FIELD_GET(CLKMGR_PERPLLGRP_EMACCTL_EMAC2SELB_MASK, ctl);
else
return 0;
@@ -643,8 +643,125 @@ static ulong socfpga_clk_get_rate(struct clk *clk)
}
}
+static int bitmask_from_clk_id(struct clk *clk)
+{
+ struct socfpga_clk_plat *plat = dev_get_plat(clk->dev);
+
+ switch (clk->id) {
+ case AGILEX_MPU_CLK:
+ plat->pllgrp = CLKMGR_MAINPLL_EN;
+ plat->bitmask = CLKMGR_MAINPLLGRP_EN_MPUCLK_MASK;
+ break;
+ case AGILEX_L4_MAIN_CLK:
+ plat->pllgrp = CLKMGR_MAINPLL_EN;
+ plat->bitmask = CLKMGR_MAINPLLGRP_EN_L4MAINCLK_MASK;
+ break;
+ case AGILEX_L4_MP_CLK:
+ plat->pllgrp = CLKMGR_MAINPLL_EN;
+ plat->bitmask = CLKMGR_MAINPLLGRP_EN_L4MPCLK_MASK;
+ break;
+ case AGILEX_L4_SP_CLK:
+ plat->pllgrp = CLKMGR_MAINPLL_EN;
+ plat->bitmask = CLKMGR_MAINPLLGRP_EN_L4SPCLK_MASK;
+ break;
+ case AGILEX_CS_AT_CLK:
+ plat->pllgrp = CLKMGR_MAINPLL_EN;
+ plat->bitmask = CLKMGR_MAINPLLGRP_EN_CSCLK_MASK;
+ break;
+ case AGILEX_CS_TRACE_CLK:
+ plat->pllgrp = CLKMGR_MAINPLL_EN;
+ plat->bitmask = CLKMGR_MAINPLLGRP_EN_CSCLK_MASK;
+ break;
+ case AGILEX_CS_PDBG_CLK:
+ plat->pllgrp = CLKMGR_MAINPLL_EN;
+ plat->bitmask = CLKMGR_MAINPLLGRP_EN_CSCLK_MASK;
+ break;
+ case AGILEX_CS_TIMER_CLK:
+ plat->pllgrp = CLKMGR_MAINPLL_EN;
+ plat->bitmask = CLKMGR_MAINPLLGRP_EN_CSTIMERCLK_MASK;
+ break;
+ case AGILEX_S2F_USER0_CLK:
+ plat->pllgrp = CLKMGR_MAINPLL_EN;
+ plat->bitmask = CLKMGR_MAINPLLGRP_EN_S2FUSER0CLK_MASK;
+ break;
+ case AGILEX_EMAC0_CLK:
+ plat->pllgrp = CLKMGR_PERPLL_EN;
+ plat->bitmask = CLKMGR_PERPLLGRP_EN_EMAC0CLK_MASK;
+ break;
+ case AGILEX_EMAC1_CLK:
+ plat->pllgrp = CLKMGR_PERPLL_EN;
+ plat->bitmask = CLKMGR_PERPLLGRP_EN_EMAC1CLK_MASK;
+ break;
+ case AGILEX_EMAC2_CLK:
+ plat->pllgrp = CLKMGR_PERPLL_EN;
+ plat->bitmask = CLKMGR_PERPLLGRP_EN_EMAC2CLK_MASK;
+ break;
+ case AGILEX_EMAC_PTP_CLK:
+ plat->pllgrp = CLKMGR_PERPLL_EN;
+ plat->bitmask = CLKMGR_PERPLLGRP_EN_EMACPTPCLK_MASK;
+ break;
+ case AGILEX_GPIO_DB_CLK:
+ plat->pllgrp = CLKMGR_PERPLL_EN;
+ plat->bitmask = CLKMGR_PERPLLGRP_EN_GPIODBCLK_MASK;
+ break;
+ case AGILEX_SDMMC_CLK:
+ plat->pllgrp = CLKMGR_PERPLL_EN;
+ plat->bitmask = CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK;
+ break;
+ case AGILEX_S2F_USER1_CLK:
+ plat->pllgrp = CLKMGR_PERPLL_EN;
+ plat->bitmask = CLKMGR_PERPLLGRP_EN_S2FUSER1CLK_MASK;
+ break;
+ case AGILEX_PSI_REF_CLK:
+ plat->pllgrp = CLKMGR_PERPLL_EN;
+ plat->bitmask = CLKMGR_PERPLLGRP_EN_PSIREFCLK_MASK;
+ break;
+ case AGILEX_USB_CLK:
+ plat->pllgrp = CLKMGR_PERPLL_EN;
+ plat->bitmask = CLKMGR_PERPLLGRP_EN_USBCLK_MASK;
+ break;
+ case AGILEX_SPI_M_CLK:
+ plat->pllgrp = CLKMGR_PERPLL_EN;
+ plat->bitmask = CLKMGR_PERPLLGRP_EN_SPIMCLK_MASK;
+ break;
+ case AGILEX_NAND_CLK:
+ plat->pllgrp = CLKMGR_PERPLL_EN;
+ plat->bitmask = CLKMGR_PERPLLGRP_EN_NANDCLK_MASK;
+ break;
+ default:
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
static int socfpga_clk_enable(struct clk *clk)
{
+ struct socfpga_clk_plat *plat = dev_get_plat(clk->dev);
+ uintptr_t base_addr = (uintptr_t)plat->regs;
+ int ret;
+
+ ret = bitmask_from_clk_id(clk);
+ if (ret)
+ return ret;
+
+ setbits_le32(base_addr + plat->pllgrp, plat->bitmask);
+
+ return 0;
+}
+
+static int socfpga_clk_disable(struct clk *clk)
+{
+ struct socfpga_clk_plat *plat = dev_get_plat(clk->dev);
+ uintptr_t base_addr = (uintptr_t)plat->regs;
+ int ret;
+
+ ret = bitmask_from_clk_id(clk);
+ if (ret)
+ return ret;
+
+ clrbits_le32(base_addr + plat->pllgrp, plat->bitmask);
+
return 0;
}
@@ -672,6 +789,7 @@ static int socfpga_clk_of_to_plat(struct udevice *dev)
static struct clk_ops socfpga_clk_ops = {
.enable = socfpga_clk_enable,
+ .disable = socfpga_clk_disable,
.get_rate = socfpga_clk_get_rate,
};
diff --git a/drivers/clk/altera/clk-agilex.h b/drivers/clk/altera/clk-agilex.h
index b3e8841a512..be639957940 100644
--- a/drivers/clk/altera/clk-agilex.h
+++ b/drivers/clk/altera/clk-agilex.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2019 Intel Corporation <www.intel.com>
+ * Copyright (C) 2025 Altera Corporation <www.altera.com>
*/
#ifndef _CLK_AGILEX_
@@ -210,7 +211,26 @@ struct cm_config {
#define CLKMGR_LOSTLOCK_SET_MASK BIT(0)
+#define CLKMGR_MAINPLLGRP_EN_MPUCLK_MASK BIT(0)
+#define CLKMGR_MAINPLLGRP_EN_L4MAINCLK_MASK BIT(1)
+#define CLKMGR_MAINPLLGRP_EN_L4MPCLK_MASK BIT(2)
+#define CLKMGR_MAINPLLGRP_EN_L4SPCLK_MASK BIT(3)
+#define CLKMGR_MAINPLLGRP_EN_CSCLK_MASK BIT(4)
+#define CLKMGR_MAINPLLGRP_EN_CSTIMERCLK_MASK BIT(5)
+#define CLKMGR_MAINPLLGRP_EN_S2FUSER0CLK_MASK BIT(6)
+
+#define CLKMGR_PERPLLGRP_EN_EMAC0CLK_MASK BIT(0)
+#define CLKMGR_PERPLLGRP_EN_EMAC1CLK_MASK BIT(1)
+#define CLKMGR_PERPLLGRP_EN_EMAC2CLK_MASK BIT(2)
+#define CLKMGR_PERPLLGRP_EN_EMACPTPCLK_MASK BIT(3)
+#define CLKMGR_PERPLLGRP_EN_GPIODBCLK_MASK BIT(4)
#define CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK BIT(5)
+#define CLKMGR_PERPLLGRP_EN_S2FUSER1CLK_MASK BIT(6)
+#define CLKMGR_PERPLLGRP_EN_PSIREFCLK_MASK BIT(7)
+#define CLKMGR_PERPLLGRP_EN_USBCLK_MASK BIT(8)
+#define CLKMGR_PERPLLGRP_EN_SPIMCLK_MASK BIT(9)
+#define CLKMGR_PERPLLGRP_EN_NANDCLK_MASK BIT(10)
+
#define CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_OFFSET 26
#define CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_MASK BIT(26)
#define CLKMGR_PERPLLGRP_EMACCTL_EMAC1SELB_OFFSET 27
diff --git a/drivers/clk/at91/Kconfig b/drivers/clk/at91/Kconfig
index 4563892647b..faeaa2808b0 100644
--- a/drivers/clk/at91/Kconfig
+++ b/drivers/clk/at91/Kconfig
@@ -1,6 +1,6 @@
config CLK_AT91
bool "AT91 clock drivers"
- depends on CLK
+ depends on CLK && ARCH_AT91
select MISC
help
This option is used to enable the AT91 clock driver.
diff --git a/drivers/clk/at91/clk-sam9x60-pll.c b/drivers/clk/at91/clk-sam9x60-pll.c
index 65be2775ac3..66f01472739 100644
--- a/drivers/clk/at91/clk-sam9x60-pll.c
+++ b/drivers/clk/at91/clk-sam9x60-pll.c
@@ -183,11 +183,8 @@ static int sam9x60_frac_pll_enable(struct clk *clk)
AT91_PMC_PLL_UPDT_ID_MSK,
AT91_PMC_PLL_UPDT_STUPTIM(0x3f) | pll->id);
- /* Recommended value for AT91_PMC_PLL_ACR */
- if (pll->characteristics->upll)
- val = AT91_PMC_PLL_ACR_DEFAULT_UPLL;
- else
- val = AT91_PMC_PLL_ACR_DEFAULT_PLLA;
+ /* Load recommended value for PMC_PLL_ACR */
+ val = pll->characteristics->acr;
pmc_write(base, AT91_PMC_PLL_ACR, val);
if (pll->characteristics->upll) {
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index 580c9964ff4..f38868d1665 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -42,6 +42,7 @@ struct clk_pll_characteristics {
u16 *icpll;
u8 *out;
u8 upll : 1;
+ u32 acr;
};
struct clk_pll_layout {
diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c
index e04266a2be2..2251e2846fa 100644
--- a/drivers/clk/at91/sam9x60.c
+++ b/drivers/clk/at91/sam9x60.c
@@ -123,6 +123,7 @@ static const struct clk_pll_characteristics apll_characteristics = {
.num_output = ARRAY_SIZE(plla_outputs),
.output = plla_outputs,
.core_output = core_outputs,
+ .acr = 0x00020010UL,
};
static const struct clk_pll_characteristics upll_characteristics = {
@@ -131,6 +132,7 @@ static const struct clk_pll_characteristics upll_characteristics = {
.output = upll_outputs,
.core_output = core_outputs,
.upll = true,
+ .acr = 0x12023010UL, /* fIN = [18 MHz, 32 MHz]*/
};
/* Layout for fractional PLLs. */
diff --git a/drivers/clk/at91/sam9x7.c b/drivers/clk/at91/sam9x7.c
index ad9865feff0..9ea253e6ff8 100644
--- a/drivers/clk/at91/sam9x7.c
+++ b/drivers/clk/at91/sam9x7.c
@@ -164,6 +164,7 @@ static const struct clk_pll_characteristics plla_characteristics = {
.num_output = ARRAY_SIZE(plla_outputs),
.output = plla_outputs,
.core_output = plla_core_outputs,
+ .acr = 0x00020010UL, /* Old ACR_DEFAULT_PLLA value */
};
static const struct clk_pll_characteristics upll_characteristics = {
@@ -172,6 +173,7 @@ static const struct clk_pll_characteristics upll_characteristics = {
.output = upll_outputs,
.core_output = upll_core_outputs,
.upll = true,
+ .acr = 0x12023010UL, /* fIN=[20 MHz, 32 MHz] */
};
static const struct clk_pll_characteristics lvdspll_characteristics = {
@@ -179,6 +181,7 @@ static const struct clk_pll_characteristics lvdspll_characteristics = {
.num_output = ARRAY_SIZE(lvdspll_outputs),
.output = lvdspll_outputs,
.core_output = lvdspll_core_outputs,
+ .acr = 0x12023010UL, /* fIN=[20 MHz, 32 MHz] */
};
static const struct clk_pll_characteristics audiopll_characteristics = {
@@ -186,6 +189,7 @@ static const struct clk_pll_characteristics audiopll_characteristics = {
.num_output = ARRAY_SIZE(audiopll_outputs),
.output = audiopll_outputs,
.core_output = audiopll_core_outputs,
+ .acr = 0x12023010UL, /* fIN=[20 MHz, 32 MHz] */
};
static const struct clk_pll_characteristics plladiv2_characteristics = {
@@ -193,6 +197,7 @@ static const struct clk_pll_characteristics plladiv2_characteristics = {
.num_output = ARRAY_SIZE(plladiv2_outputs),
.output = plladiv2_outputs,
.core_output = plladiv2_core_outputs,
+ .acr = 0x00020010UL, /* Old ACR_DEFAULT_PLLA value */
};
/* Layout for fractional PLLs. */
diff --git a/drivers/clk/at91/sama7d65.c b/drivers/clk/at91/sama7d65.c
index 8d2c25e6fa9..9f0b394543b 100644
--- a/drivers/clk/at91/sama7d65.c
+++ b/drivers/clk/at91/sama7d65.c
@@ -184,6 +184,7 @@ static const struct clk_pll_characteristics pll_characteristics = {
.num_output = ARRAY_SIZE(pll_outputs),
.output = pll_outputs,
.core_output = core_outputs,
+ .acr = 0x00070010UL,
};
/* Layout for fractional PLLs. */
diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c
index c0e27828b1a..f24d251857f 100644
--- a/drivers/clk/at91/sama7g5.c
+++ b/drivers/clk/at91/sama7g5.c
@@ -169,6 +169,7 @@ static const struct clk_pll_characteristics pll_characteristics = {
.num_output = ARRAY_SIZE(pll_outputs),
.output = pll_outputs,
.core_output = core_outputs,
+ .acr = 0x00070010UL,
};
/* Layout for fractional PLLs. */
diff --git a/drivers/clk/clk-stub.c b/drivers/clk/clk-stub.c
index 5f5aca41d5b..117266ac778 100644
--- a/drivers/clk/clk-stub.c
+++ b/drivers/clk/clk-stub.c
@@ -50,8 +50,11 @@ static struct clk_ops stub_clk_ops = {
static const struct udevice_id stub_clk_ids[] = {
{ .compatible = "qcom,rpmcc" },
+ { .compatible = "qcom,sdm670-rpmh-clk" },
{ .compatible = "qcom,sdm845-rpmh-clk" },
+ { .compatible = "qcom,sc7180-rpmh-clk" },
{ .compatible = "qcom,sc7280-rpmh-clk" },
+ { .compatible = "qcom,sm6350-rpmh-clk" },
{ .compatible = "qcom,sm8150-rpmh-clk" },
{ .compatible = "qcom,sm8250-rpmh-clk" },
{ .compatible = "qcom,sm8550-rpmh-clk" },
diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c
index a7d89f32cd7..683ac822a01 100644
--- a/drivers/clk/clk_scmi.c
+++ b/drivers/clk/clk_scmi.c
@@ -8,6 +8,7 @@
#include <clk-uclass.h>
#include <dm.h>
#include <dm/device_compat.h>
+#include <dm/device-internal.h>
#include <scmi_agent.h>
#include <scmi_agent-uclass.h>
#include <scmi_protocols.h>
@@ -16,7 +17,9 @@
struct clk_scmi {
struct clk clk;
+ char name[SCMI_CLOCK_NAME_LENGTH_MAX];
u32 ctrl_flags;
+ bool attrs_resolved;
};
struct scmi_clock_priv {
@@ -84,7 +87,7 @@ static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks)
return 0;
}
-static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name,
+static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char *name,
u32 *attr)
{
struct scmi_clock_priv *priv = dev_get_priv(dev);
@@ -108,7 +111,7 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name,
if (ret)
return ret;
- *name = strdup(out.clock_name);
+ strncpy(name, out.clock_name, SCMI_CLOCK_NAME_LENGTH_MAX);
*attr = out.attributes;
} else {
struct scmi_clk_attribute_out out;
@@ -125,7 +128,7 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name,
if (ret)
return ret;
- *name = strdup(out.clock_name);
+ strncpy(name, out.clock_name, SCMI_CLOCK_NAME_LENGTH_MAX);
*attr = out.attributes;
}
@@ -134,39 +137,93 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name,
static int scmi_clk_gate(struct clk *clk, int enable)
{
- struct scmi_clk_state_in in = {
+ struct scmi_clock_priv *priv = dev_get_parent_priv(clk->dev);
+ struct scmi_clk_state_in_v1 in_v1 = {
+ .clock_id = clk_get_id(clk),
+ .attributes = enable,
+ };
+ /* Valid only from SCMI clock v2.1 */
+ struct scmi_clk_state_in_v2 in_v2 = {
.clock_id = clk_get_id(clk),
.attributes = enable,
};
struct scmi_clk_state_out out;
- struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
- SCMI_CLOCK_CONFIG_SET,
- in, out);
+ struct scmi_msg msg_v1 = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
+ SCMI_CLOCK_CONFIG_SET,
+ in_v1, out);
+ struct scmi_msg msg_v2 = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
+ SCMI_CLOCK_CONFIG_SET,
+ in_v2, out);
int ret;
- ret = devm_scmi_process_msg(clk->dev, &msg);
+ ret = devm_scmi_process_msg(clk->dev,
+ (priv->version < CLOCK_PROTOCOL_VERSION_2_1) ?
+ &msg_v1 : &msg_v2);
if (ret)
return ret;
return scmi_to_linux_errno(out.status);
}
-static int scmi_clk_enable(struct clk *clk)
+static int scmi_clk_get_ctrl_flags(struct clk *clk, u32 *ctrl_flags)
{
struct clk_scmi *clkscmi;
+ struct udevice *dev;
+ u32 attributes;
struct clk *c;
int ret;
- if (!CONFIG_IS_ENABLED(CLK_CCF))
- return scmi_clk_gate(clk, 1);
-
ret = clk_get_by_id(clk->id, &c);
if (ret)
return ret;
+ dev = c->dev->parent;
+
clkscmi = container_of(c, struct clk_scmi, clk);
- if (clkscmi->ctrl_flags & SUPPORT_CLK_STAT_CONTROL)
+ if (!clkscmi->attrs_resolved) {
+ char name[SCMI_CLOCK_NAME_LENGTH_MAX];
+ ret = scmi_clk_get_attibute(dev, clk->id & CLK_ID_MSK,
+ name, &attributes);
+ if (ret)
+ return ret;
+
+ strncpy(clkscmi->name, name, SCMI_CLOCK_NAME_LENGTH_MAX);
+ if (CLK_HAS_RESTRICTIONS(attributes)) {
+ u32 perm;
+
+ ret = scmi_clk_get_permissions(dev, clk->id & CLK_ID_MSK, &perm);
+ if (ret < 0)
+ clkscmi->ctrl_flags = 0;
+ else
+ clkscmi->ctrl_flags = perm;
+ } else {
+ clkscmi->ctrl_flags = SUPPORT_CLK_STAT_CONTROL |
+ SUPPORT_CLK_PARENT_CONTROL |
+ SUPPORT_CLK_RATE_CONTROL;
+ }
+
+ clkscmi->attrs_resolved = true;
+ }
+
+ *ctrl_flags = clkscmi->ctrl_flags;
+
+ return 0;
+}
+
+static int scmi_clk_enable(struct clk *clk)
+{
+ u32 ctrl_flags;
+ int ret;
+
+ if (!CONFIG_IS_ENABLED(CLK_CCF))
+ return scmi_clk_gate(clk, 1);
+
+ ret = scmi_clk_get_ctrl_flags(clk, &ctrl_flags);
+ if (ret)
+ return ret;
+
+ if (ctrl_flags & SUPPORT_CLK_STAT_CONTROL)
return scmi_clk_gate(clk, 1);
/* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */
@@ -176,20 +233,17 @@ static int scmi_clk_enable(struct clk *clk)
static int scmi_clk_disable(struct clk *clk)
{
- struct clk_scmi *clkscmi;
- struct clk *c;
+ u32 ctrl_flags;
int ret;
if (!CONFIG_IS_ENABLED(CLK_CCF))
return scmi_clk_gate(clk, 0);
- ret = clk_get_by_id(clk->id, &c);
+ ret = scmi_clk_get_ctrl_flags(clk, &ctrl_flags);
if (ret)
return ret;
- clkscmi = container_of(c, struct clk_scmi, clk);
-
- if (clkscmi->ctrl_flags & SUPPORT_CLK_STAT_CONTROL)
+ if (ctrl_flags & SUPPORT_CLK_STAT_CONTROL)
return scmi_clk_gate(clk, 0);
/* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */
@@ -247,20 +301,17 @@ static ulong __scmi_clk_set_rate(struct clk *clk, ulong rate)
static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
{
- struct clk_scmi *clkscmi;
- struct clk *c;
+ u32 ctrl_flags;
int ret;
if (!CONFIG_IS_ENABLED(CLK_CCF))
return __scmi_clk_set_rate(clk, rate);
- ret = clk_get_by_id(clk->id, &c);
+ ret = scmi_clk_get_ctrl_flags(clk, &ctrl_flags);
if (ret)
return ret;
- clkscmi = container_of(c, struct clk_scmi, clk);
-
- if (clkscmi->ctrl_flags & SUPPORT_CLK_RATE_CONTROL)
+ if (ctrl_flags & SUPPORT_CLK_RATE_CONTROL)
return __scmi_clk_set_rate(clk, rate);
/* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */
@@ -271,7 +322,7 @@ static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
static int scmi_clk_probe(struct udevice *dev)
{
- struct clk_scmi *clk_scmi;
+ struct clk_scmi *clk_scmi_bulk, *clk_scmi;
struct scmi_clock_priv *priv = dev_get_priv(dev);
size_t num_clocks, i;
int ret;
@@ -300,39 +351,23 @@ static int scmi_clk_probe(struct udevice *dev)
return ret;
}
+ clk_scmi_bulk = kzalloc(num_clocks * sizeof(*clk_scmi), GFP_KERNEL);
+ if (!clk_scmi_bulk)
+ return -ENOMEM;
+
for (i = 0; i < num_clocks; i++) {
- char *clock_name;
- u32 attributes;
+ clk_scmi = clk_scmi_bulk + i;
+ char *clock_name = clk_scmi->name;
- if (!scmi_clk_get_attibute(dev, i, &clock_name, &attributes)) {
- clk_scmi = kzalloc(sizeof(*clk_scmi), GFP_KERNEL);
- if (!clk_scmi || !clock_name)
- ret = -ENOMEM;
- else
- ret = clk_register(&clk_scmi->clk, dev->driver->name,
- clock_name, dev->name);
-
- if (ret) {
- free(clk_scmi);
- free(clock_name);
- return ret;
- }
-
- dev_clk_dm(dev, i, &clk_scmi->clk);
-
- if (CLK_HAS_RESTRICTIONS(attributes)) {
- u32 perm;
-
- ret = scmi_clk_get_permissions(dev, i, &perm);
- if (ret < 0)
- clk_scmi->ctrl_flags = 0;
- else
- clk_scmi->ctrl_flags = perm;
- } else {
- clk_scmi->ctrl_flags = SUPPORT_CLK_STAT_CONTROL | SUPPORT_CLK_PARENT_CONTROL |
- SUPPORT_CLK_RATE_CONTROL;
- }
- }
+ snprintf(clock_name, SCMI_CLOCK_NAME_LENGTH_MAX, "scmi-%zu", i);
+
+ ret = clk_register(&clk_scmi->clk, dev->driver->name,
+ clock_name, dev->name);
+ if (ret)
+ return ret;
+
+ dev_clk_dm(dev, i, &clk_scmi->clk);
+ dev_set_parent_priv(clk_scmi->clk.dev, priv);
}
return 0;
@@ -359,20 +394,17 @@ static int __scmi_clk_set_parent(struct clk *clk, struct clk *parent)
static int scmi_clk_set_parent(struct clk *clk, struct clk *parent)
{
- struct clk_scmi *clkscmi;
- struct clk *c;
+ u32 ctrl_flags;
int ret;
if (!CONFIG_IS_ENABLED(CLK_CCF))
- return -ENOTSUPP;
+ return __scmi_clk_set_parent(clk, parent);
- ret = clk_get_by_id(clk->id, &c);
+ ret = scmi_clk_get_ctrl_flags(clk, &ctrl_flags);
if (ret)
return ret;
- clkscmi = container_of(c, struct clk_scmi, clk);
-
- if (clkscmi->ctrl_flags & SUPPORT_CLK_PARENT_CONTROL)
+ if (ctrl_flags & SUPPORT_CLK_PARENT_CONTROL)
return __scmi_clk_set_parent(clk, parent);
/* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */
diff --git a/drivers/clk/clk_versaclock.c b/drivers/clk/clk_versaclock.c
index 9ccaf13d242..19a787eaf0c 100644
--- a/drivers/clk/clk_versaclock.c
+++ b/drivers/clk/clk_versaclock.c
@@ -850,7 +850,7 @@ static char *versaclock_get_name(const char *dev_name, const char *clk_name, int
buf = malloc(length);
if (!buf)
- ERR_PTR(-ENOMEM);
+ return ERR_PTR(-ENOMEM);
if (index < 0)
snprintf(buf, length, "%s.%s", dev_name, clk_name);
@@ -904,12 +904,12 @@ int versaclock_probe(struct udevice *dev)
if (IS_ERR(mux_name))
return PTR_ERR(mux_name);
- clk_register(&vc5->clk_mux, "versaclock-mux", mux_name, vc5->pin_xin->dev->name);
-
- if (!IS_ERR(vc5->pin_xin))
+ if (!IS_ERR(vc5->pin_xin)) {
+ clk_register(&vc5->clk_mux, "versaclock-mux", mux_name, vc5->pin_xin->dev->name);
vc5_mux_set_parent(&vc5->clk_mux, 1);
- else
+ } else {
vc5_mux_set_parent(&vc5->clk_mux, 0);
+ }
/* Configure Optional Loading Capacitance for external XTAL */
if (!(vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL)) {
diff --git a/drivers/clk/clk_versal.c b/drivers/clk/clk_versal.c
index cb98f34b5ec..c62a747036d 100644
--- a/drivers/clk/clk_versal.c
+++ b/drivers/clk/clk_versal.c
@@ -121,25 +121,19 @@ static unsigned int clock_max_idx __section(".data");
#define PM_QUERY_DATA 35
-static int versal_pm_query(struct versal_pm_query_data qdata, u32 *ret_payload)
-{
- struct pt_regs regs;
-
- regs.regs[0] = PM_SIP_SVC | PM_QUERY_DATA;
- regs.regs[1] = ((u64)qdata.arg1 << 32) | qdata.qid;
- regs.regs[2] = ((u64)qdata.arg3 << 32) | qdata.arg2;
+typedef int (*versal_pm_query_t)(struct versal_pm_query_data qdata,
+ u32 *ret_payload);
+static versal_pm_query_t __data versal_pm_query;
- smc_call(&regs);
+static int versal_pm_query_legacy(struct versal_pm_query_data qdata,
+ u32 *ret_payload)
+{
+ int ret;
- if (ret_payload) {
- ret_payload[0] = (u32)regs.regs[0];
- ret_payload[1] = upper_32_bits(regs.regs[0]);
- ret_payload[2] = (u32)regs.regs[1];
- ret_payload[3] = upper_32_bits(regs.regs[1]);
- ret_payload[4] = (u32)regs.regs[2];
- }
+ ret = smc_call_handler(PM_QUERY_DATA, qdata.qid, qdata.arg1, qdata.arg2,
+ qdata.arg3, 0, 0, ret_payload);
- return qdata.qid == PM_QID_CLOCK_GET_NAME ? 0 : regs.regs[0];
+ return qdata.qid == PM_QID_CLOCK_GET_NAME ? 0 : ret;
}
static inline int versal_is_valid_clock(u32 clk_id)
@@ -356,7 +350,8 @@ static u32 versal_clock_get_div(u32 clk_id)
u32 ret_payload[PAYLOAD_ARG_CNT];
u32 div;
- xilinx_pm_request(PM_CLOCK_GETDIVIDER, clk_id, 0, 0, 0, ret_payload);
+ xilinx_pm_request(PM_CLOCK_GETDIVIDER, clk_id, 0, 0, 0, 0, 0,
+ ret_payload);
div = ret_payload[1];
return div;
@@ -366,7 +361,8 @@ static u32 versal_clock_set_div(u32 clk_id, u32 div)
{
u32 ret_payload[PAYLOAD_ARG_CNT];
- xilinx_pm_request(PM_CLOCK_SETDIVIDER, clk_id, div, 0, 0, ret_payload);
+ xilinx_pm_request(PM_CLOCK_SETDIVIDER, clk_id, div, 0, 0, 0, 0,
+ ret_payload);
return div;
}
@@ -424,7 +420,7 @@ static u32 versal_clock_get_parentid(u32 clk_id)
if (versal_clock_mux(clk_id)) {
xilinx_pm_request(PM_CLOCK_GETPARENT, clk_id, 0, 0, 0,
- ret_payload);
+ 0, 0, ret_payload);
parent_id = ret_payload[1];
}
@@ -442,7 +438,8 @@ static u64 versal_clock_get_pll_rate(u32 clk_id)
u32 parent_rate, parent_id, parent_ref_clk_id;
u32 id = clk_id & 0xFFF;
- xilinx_pm_request(PM_CLOCK_GETSTATE, clk_id, 0, 0, 0, ret_payload);
+ xilinx_pm_request(PM_CLOCK_GETSTATE, clk_id, 0, 0, 0, 0, 0,
+ ret_payload);
res = ret_payload[1];
if (!res) {
printf("0%x PLL not enabled\n", clk_id);
@@ -453,9 +450,11 @@ static u64 versal_clock_get_pll_rate(u32 clk_id)
parent_ref_clk_id = versal_clock_get_parentid(parent_id);
parent_rate = versal_clock_get_ref_rate(parent_ref_clk_id);
- xilinx_pm_request(PM_CLOCK_GETDIVIDER, clk_id, 0, 0, 0, ret_payload);
+ xilinx_pm_request(PM_CLOCK_GETDIVIDER, clk_id, 0, 0, 0, 0, 0,
+ ret_payload);
fbdiv = ret_payload[1];
- xilinx_pm_request(PM_CLOCK_PLL_GETPARAM, clk_id, 2, 0, 0, ret_payload);
+ xilinx_pm_request(PM_CLOCK_PLL_GETPARAM, clk_id, 2, 0, 0, 0, 0,
+ ret_payload);
frac = ret_payload[1];
freq = (fbdiv * parent_rate) >> (1 << frac);
@@ -679,6 +678,10 @@ static int versal_clk_probe(struct udevice *dev)
debug("%s\n", __func__);
+ versal_pm_query = (versal_pm_query_t)dev_get_driver_data(dev);
+ if (!versal_pm_query)
+ return -EINVAL;
+
ret = versal_clock_get_freq_by_name("pl_alt_ref",
dev, &pl_alt_ref_clk);
if (ret == -ENODATA) {
@@ -767,8 +770,10 @@ static int versal_clk_enable(struct clk *clk)
clk_id = priv->clk[clk->id].clk_id;
- if (versal_clock_gate(clk_id))
- return xilinx_pm_request(PM_CLOCK_ENABLE, clk_id, 0, 0, 0, NULL);
+ if (versal_clock_gate(clk_id)) {
+ return xilinx_pm_request(PM_CLOCK_ENABLE, clk_id, 0, 0, 0,
+ 0, 0, NULL);
+ }
return 0;
}
@@ -783,7 +788,7 @@ static struct clk_ops versal_clk_ops = {
};
static const struct udevice_id versal_clk_ids[] = {
- { .compatible = "xlnx,versal-clk" },
+ { .compatible = "xlnx,versal-clk", .data = (ulong)versal_pm_query_legacy },
{ }
};
diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c
index 5d7faaa3eab..a7a42b2edb6 100644
--- a/drivers/clk/meson/g12a.c
+++ b/drivers/clk/meson/g12a.c
@@ -916,8 +916,6 @@ static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id,
return -EINVAL;
case CLKID_PCIE_PLL:
return meson_pcie_pll_set_rate(clk, rate);
-
- return 0;
case CLKID_VPU:
return meson_clk_set_rate_by_id(clk,
meson_mux_get_parent(clk, CLKID_VPU), rate,
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 34e41461e72..8504ed5d656 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -103,6 +103,21 @@ config CLK_QCOM_SM6115
on the Snapdragon SM6115 SoC. This driver supports the clocks
and resets exposed by the GCC hardware block.
+config CLK_QCOM_SM6350
+ bool "Qualcomm SM6350 GCC"
+ select CLK_QCOM
+ help
+ Say Y here to enable support for the Global Clock Controller
+ on the Snapdragon SM6350 SoC. This driver supports the clocks
+
+config CLK_QCOM_SM7150
+ bool "Qualcomm SM7150 GCC"
+ select CLK_QCOM
+ help
+ Say Y here to enable support for the Global Clock Controller
+ on the Snapdragon SM7150 SoC. This driver supports the clocks
+ and resets exposed by the GCC hardware block.
+
config CLK_QCOM_SM8150
bool "Qualcomm SM8150 GCC"
select CLK_QCOM
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index b3d95b0faa3..82a5b166196 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -16,6 +16,8 @@ obj-$(CONFIG_CLK_QCOM_QCS615) += clock-qcs615.o
obj-$(CONFIG_CLK_QCOM_SA8775P) += clock-sa8775p.o
obj-$(CONFIG_CLK_QCOM_SC7280) += clock-sc7280.o
obj-$(CONFIG_CLK_QCOM_SM6115) += clock-sm6115.o
+obj-$(CONFIG_CLK_QCOM_SM6350) += clock-sm6350.o
+obj-$(CONFIG_CLK_QCOM_SM7150) += clock-sm7150.o
obj-$(CONFIG_CLK_QCOM_SM8150) += clock-sm8150.o
obj-$(CONFIG_CLK_QCOM_SM8250) += clock-sm8250.o
obj-$(CONFIG_CLK_QCOM_SM8550) += clock-sm8550.o
diff --git a/drivers/clk/qcom/clock-sc7280.c b/drivers/clk/qcom/clock-sc7280.c
index 47e0ca5f0e5..55a233df394 100644
--- a/drivers/clk/qcom/clock-sc7280.c
+++ b/drivers/clk/qcom/clock-sc7280.c
@@ -38,6 +38,22 @@ static const struct freq_tbl ftbl_gcc_usb30_sec_master_clk_src[] = {
{ }
};
+static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s2_clk_src[] = {
+ F(7372800, CFG_CLK_SRC_GPLL0_EVEN, 1, 384, 15625),
+ F(14745600, CFG_CLK_SRC_GPLL0_EVEN, 1, 768, 15625),
+ F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0),
+ F(29491200, CFG_CLK_SRC_GPLL0_EVEN, 1, 1536, 15625),
+ F(32000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 75),
+ F(48000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 25),
+ F(52174000, CFG_CLK_SRC_GPLL0, 1, 2, 23),
+ F(64000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 16, 75),
+ F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0),
+ F(80000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 15),
+ F(96000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 25),
+ F(100000000, CFG_CLK_SRC_GPLL0, 6, 0, 0),
+ { }
+};
+
static ulong sc7280_set_rate(struct clk *clk, ulong rate)
{
struct msm_clk_priv *priv = dev_get_priv(clk->dev);
@@ -47,6 +63,16 @@ static ulong sc7280_set_rate(struct clk *clk, ulong rate)
debug("%s: %s, requested rate=%ld\n", __func__, priv->data->clks[clk->id].name, rate);
switch (clk->id) {
+ case GCC_QUPV3_WRAP0_S5_CLK: /* UART5 */
+ freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s2_clk_src, rate);
+ clk_rcg_set_rate_mnd(priv->base, 0x17600,
+ freq->pre_div, freq->m, freq->n, freq->src, 16);
+ return freq->freq;
+ case GCC_QUPV3_WRAP0_S7_CLK: /* UART7 */
+ freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s2_clk_src, rate);
+ clk_rcg_set_rate_mnd(priv->base, 0x17860,
+ freq->pre_div, freq->m, freq->n, freq->src, 16);
+ return freq->freq;
case GCC_USB30_PRIM_MASTER_CLK:
freq = qcom_find_freq(ftbl_gcc_usb30_prim_master_clk_src, rate);
clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR,
@@ -107,6 +133,8 @@ static const struct gate_clk sc7280_clks[] = {
GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x52008, BIT(10)),
GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x52008, BIT(11)),
GATE_CLK(GCC_QUPV3_WRAP0_S3_CLK, 0x52008, BIT(13)),
+ GATE_CLK(GCC_QUPV3_WRAP0_S5_CLK, 0x52008, BIT(15)),
+ GATE_CLK(GCC_QUPV3_WRAP0_S7_CLK, 0x52008, BIT(17)),
GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x77010, BIT(0)),
GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x770cc, BIT(0)),
GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x77018, BIT(0)),
diff --git a/drivers/clk/qcom/clock-sdm845.c b/drivers/clk/qcom/clock-sdm845.c
index 5c8702ef2fe..c9a057cf6f9 100644
--- a/drivers/clk/qcom/clock-sdm845.c
+++ b/drivers/clk/qcom/clock-sdm845.c
@@ -23,6 +23,7 @@
#define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf018
#define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0xf030
#define USB3_PRIM_PHY_AUX_CMD_RCGR 0xf05c
+#define SDCC1_APPS_CLK_CMD_RCGR 0x26028
#define SDCC2_APPS_CLK_CMD_RCGR 0x1400c
static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = {
@@ -44,6 +45,18 @@ static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = {
{ }
};
+static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk_src[] = {
+ F(144000, CFG_CLK_SRC_CXO, 16, 3, 25),
+ F(400000, CFG_CLK_SRC_CXO, 12, 1, 4),
+ F(20000000, CFG_CLK_SRC_GPLL0_EVEN, 5, 1, 3),
+ F(25000000, CFG_CLK_SRC_GPLL0_EVEN, 6, 1, 2),
+ F(50000000, CFG_CLK_SRC_GPLL0_EVEN, 6, 0, 0),
+ F(100000000, CFG_CLK_SRC_GPLL0, 6, 0, 0),
+ F(192000000, CFG_CLK_SRC_GPLL6, 2, 0, 0),
+ F(384000000, CFG_CLK_SRC_GPLL6, 1, 0, 0),
+ { }
+};
+
static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = {
F(400000, CFG_CLK_SRC_CXO, 12, 1, 4),
F(9600000, CFG_CLK_SRC_CXO, 2, 0, 0),
@@ -55,6 +68,22 @@ static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = {
{ }
};
+static ulong sdm670_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+ const struct freq_tbl *freq;
+
+ switch (clk->id) {
+ case GCC_SDCC1_APPS_CLK:
+ freq = qcom_find_freq(ftbl_gcc_sdcc1_apps_clk_src, rate);
+ clk_rcg_set_rate_mnd(priv->base, SDCC1_APPS_CLK_CMD_RCGR,
+ freq->pre_div, freq->m, freq->n, freq->src, 8);
+ return freq->freq;
+ default:
+ return 0;
+ }
+}
+
static ulong sdm845_clk_set_rate(struct clk *clk, ulong rate)
{
struct msm_clk_priv *priv = dev_get_priv(clk->dev);
@@ -76,6 +105,54 @@ static ulong sdm845_clk_set_rate(struct clk *clk, ulong rate)
}
}
+static const struct gate_clk sdm670_clks[] = {
+ GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0x8201c, 0x00000001),
+ GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x0502c, 0x00000001),
+ GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x5200c, 0x00000400),
+ GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x5200c, 0x00000800),
+ GATE_CLK(GCC_QUPV3_WRAP0_S2_CLK, 0x5200c, 0x00001000),
+ GATE_CLK(GCC_QUPV3_WRAP0_S3_CLK, 0x5200c, 0x00002000),
+ GATE_CLK(GCC_QUPV3_WRAP0_S4_CLK, 0x5200c, 0x00004000),
+ GATE_CLK(GCC_QUPV3_WRAP0_S5_CLK, 0x5200c, 0x00008000),
+ GATE_CLK(GCC_QUPV3_WRAP0_S6_CLK, 0x5200c, 0x00010000),
+ GATE_CLK(GCC_QUPV3_WRAP0_S7_CLK, 0x5200c, 0x00020000),
+ GATE_CLK(GCC_QUPV3_WRAP1_S0_CLK, 0x5200c, 0x00400000),
+ GATE_CLK(GCC_QUPV3_WRAP1_S1_CLK, 0x5200c, 0x00800000),
+ GATE_CLK(GCC_QUPV3_WRAP1_S3_CLK, 0x5200c, 0x02000000),
+ GATE_CLK(GCC_QUPV3_WRAP1_S4_CLK, 0x5200c, 0x04000000),
+ GATE_CLK(GCC_QUPV3_WRAP1_S5_CLK, 0x5200c, 0x08000000),
+ GATE_CLK(GCC_QUPV3_WRAP1_S6_CLK, 0x5200c, 0x10000000),
+ GATE_CLK(GCC_QUPV3_WRAP1_S7_CLK, 0x5200c, 0x20000000),
+ GATE_CLK(GCC_QUPV3_WRAP_0_M_AHB_CLK, 0x5200c, 0x00000040),
+ GATE_CLK(GCC_QUPV3_WRAP_0_S_AHB_CLK, 0x5200c, 0x00000080),
+ GATE_CLK(GCC_QUPV3_WRAP_1_M_AHB_CLK, 0x5200c, 0x00100000),
+ GATE_CLK(GCC_QUPV3_WRAP_1_S_AHB_CLK, 0x5200c, 0x00200000),
+ GATE_CLK(GCC_SDCC1_AHB_CLK, 0x26008, 0x00000001),
+ GATE_CLK(GCC_SDCC1_APPS_CLK, 0x26004, 0x00000001),
+ GATE_CLK(GCC_SDCC1_ICE_CORE_CLK, 0x2600c, 0x00000001),
+ GATE_CLK(GCC_SDCC2_AHB_CLK, 0x14008, 0x00000001),
+ GATE_CLK(GCC_SDCC2_APPS_CLK, 0x14004, 0x00000001),
+ GATE_CLK(GCC_SDCC4_AHB_CLK, 0x16008, 0x00000001),
+ GATE_CLK(GCC_SDCC4_APPS_CLK, 0x16004, 0x00000001),
+ GATE_CLK(GCC_UFS_MEM_CLKREF_CLK, 0x8c000, 0x00000001),
+ GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x82024, 0x00000001),
+ GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x77010, 0x00000001),
+ GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x7700c, 0x00000001),
+ GATE_CLK(GCC_UFS_PHY_ICE_CORE_CLK, 0x77058, 0x00000001),
+ GATE_CLK(GCC_UFS_PHY_PHY_AUX_CLK, 0x7708c, 0x00000001),
+ GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_0_CLK, 0x77018, 0x00000001),
+ GATE_CLK(GCC_UFS_PHY_TX_SYMBOL_0_CLK, 0x77014, 0x00000001),
+ GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x77054, 0x00000001),
+ GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0x0f00c, 0x00000001),
+ GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0x0f014, 0x00000001),
+ GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0x0f010, 0x00000001),
+ GATE_CLK(GCC_USB3_PRIM_CLKREF_CLK, 0x8c008, 0x00000001),
+ GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0x0f04c, 0x00000001),
+ GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0x0f050, 0x00000001),
+ GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0x0f054, 0x00000001),
+ GATE_CLK(GCC_USB_PHY_CFG_AHB2PHY_CLK, 0x6a004, 0x00000001),
+};
+
static const struct gate_clk sdm845_clks[] = {
GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0x8201c, 0x00000001),
GATE_CLK(GCC_AGGRE_USB3_SEC_AXI_CLK, 0x82020, 0x00000001),
@@ -140,6 +217,28 @@ static const struct gate_clk sdm845_clks[] = {
GATE_CLK(GCC_USB_PHY_CFG_AHB2PHY_CLK, 0x6a004, 0x00000001),
};
+static int sdm670_clk_enable(struct clk *clk)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
+ debug("%s: clk %s\n", __func__, sdm670_clks[clk->id].name);
+
+ switch (clk->id) {
+ case GCC_USB30_PRIM_MASTER_CLK:
+ qcom_gate_clk_en(priv, GCC_USB_PHY_CFG_AHB2PHY_CLK);
+ /* These numbers are just pulled from the frequency tables in the Linux driver */
+ clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR,
+ (4.5 * 2) - 1, 0, 0, 1 << 8, 8);
+ clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR,
+ 1, 0, 0, 0, 8);
+ clk_rcg_set_rate_mnd(priv->base, USB3_PRIM_PHY_AUX_CMD_RCGR,
+ 1, 0, 0, 0, 8);
+ break;
+ }
+
+ return qcom_gate_clk_en(priv, clk->id);
+}
+
static int sdm845_clk_enable(struct clk *clk)
{
struct msm_clk_priv *priv = dev_get_priv(clk->dev);
@@ -188,6 +287,17 @@ static const struct qcom_reset_map sdm845_gcc_resets[] = {
[GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 },
};
+static const struct qcom_power_map sdm670_gdscs[] = {
+ [UFS_PHY_GDSC] = { 0x77004 },
+ [USB30_PRIM_GDSC] = { 0xf004 },
+ [HLOS1_VOTE_AGGRE_NOC_MMU_AUDIO_TBU_GDSC] = { 0x7d030 },
+ [HLOS1_VOTE_AGGRE_NOC_MMU_TBU1_GDSC] = { 0x7d034 },
+ [HLOS1_VOTE_AGGRE_NOC_MMU_TBU2_GDSC] = { 0x7d038 },
+ [HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC] = { 0x7d040 },
+ [HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC] = { 0x7d048 },
+ [HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC] = { 0x7d044 },
+};
+
static const struct qcom_power_map sdm845_gdscs[] = {
[PCIE_0_GDSC] = { 0x6b004 },
[PCIE_1_GDSC] = { 0x8d004 },
@@ -292,6 +402,19 @@ static const char *const sdm845_rcg_names[] = {
"GCC_UFS_PHY_PHY_AUX",
};
+static struct msm_clk_data sdm670_clk_data = {
+ /* Snapdragon 670 can function without its own exclusive resets. */
+ .resets = sdm845_gcc_resets,
+ .num_resets = ARRAY_SIZE(sdm845_gcc_resets),
+ .clks = sdm670_clks,
+ .num_clks = ARRAY_SIZE(sdm670_clks),
+ .power_domains = sdm670_gdscs,
+ .num_power_domains = ARRAY_SIZE(sdm670_gdscs),
+
+ .enable = sdm670_clk_enable,
+ .set_rate = sdm670_clk_set_rate,
+};
+
static struct msm_clk_data sdm845_clk_data = {
.resets = sdm845_gcc_resets,
.num_resets = ARRAY_SIZE(sdm845_gcc_resets),
@@ -311,6 +434,10 @@ static struct msm_clk_data sdm845_clk_data = {
static const struct udevice_id gcc_sdm845_of_match[] = {
{
+ .compatible = "qcom,gcc-sdm670",
+ .data = (ulong)&sdm670_clk_data,
+ },
+ {
.compatible = "qcom,gcc-sdm845",
.data = (ulong)&sdm845_clk_data,
},
diff --git a/drivers/clk/qcom/clock-sm6350.c b/drivers/clk/qcom/clock-sm6350.c
new file mode 100644
index 00000000000..ee6653848c7
--- /dev/null
+++ b/drivers/clk/qcom/clock-sm6350.c
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Clock drivers for Qualcomm sm6350
+ *
+ * (C) Copyright 2024 Linaro Ltd.
+ * (C) Copyright 2025 Luca Weiss <luca.weiss@fairphone.com>
+ */
+
+#include <clk-uclass.h>
+#include <dm.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <linux/bug.h>
+#include <linux/bitops.h>
+#include <dt-bindings/clock/qcom,gcc-sm6350.h>
+
+#include "clock-qcom.h"
+
+#undef CFG_CLK_SRC_GPLL0_ODD
+#define CFG_CLK_SRC_GPLL0_ODD (2 << 8)
+#define CFG_CLK_SRC_GPLL6_EVEN (2 << 8)
+
+#define GCC_SE12_UART_RCG_REG 0x223a8
+#define GCC_SDCC2_APPS_CLK_SRC_REG 0x2000c
+
+#define APCS_GPLL7_STATUS 0x7000
+#define APCS_GPLLX_ENA_REG 0x52010
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap1_s3_clk_src[] = {
+ F(7372800, CFG_CLK_SRC_GPLL0_EVEN, 1, 384, 15625),
+ F(14745600, CFG_CLK_SRC_GPLL0_EVEN, 1, 768, 15625),
+ F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0),
+ F(29491200, CFG_CLK_SRC_GPLL0_EVEN, 1, 1536, 15625),
+ F(32000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 75),
+ F(48000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 25),
+ F(64000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 16, 75),
+ F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0),
+ F(80000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 15),
+ F(96000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 25),
+ F(100000000, CFG_CLK_SRC_GPLL0_EVEN, 3, 0, 0),
+ F(102400000, CFG_CLK_SRC_GPLL0_EVEN, 1, 128, 375),
+ F(112000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 28, 75),
+ F(117964800, CFG_CLK_SRC_GPLL0_EVEN, 1, 6144, 15625),
+ F(120000000, CFG_CLK_SRC_GPLL0_EVEN, 2.5, 0, 0),
+ F(128000000, CFG_CLK_SRC_GPLL6_EVEN, 3, 0, 0),
+ {}
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = {
+ F(400000, CFG_CLK_SRC_CXO, 12, 1, 4),
+ F(9600000, CFG_CLK_SRC_CXO, 2, 0, 0),
+ F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0),
+ F(25000000, CFG_CLK_SRC_GPLL0_ODD, 8, 0, 0),
+ F(50000000, CFG_CLK_SRC_GPLL0_ODD, 4, 0, 0),
+ F(100000000, CFG_CLK_SRC_GPLL0_ODD, 2, 0, 0),
+ F(202000000, CFG_CLK_SRC_GPLL7, 4, 0, 0),
+ {}
+};
+
+static struct pll_vote_clk gpll7_vote_clk = {
+ .status = APCS_GPLL7_STATUS,
+ .status_bit = BIT(31),
+ .ena_vote = APCS_GPLLX_ENA_REG,
+ .vote_bit = BIT(7),
+};
+
+static ulong sm6350_set_rate(struct clk *clk, ulong rate)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+ const struct freq_tbl *freq;
+
+ if (clk->id < priv->data->num_clks)
+ debug("%s: %s, requested rate=%ld\n", __func__,
+ priv->data->clks[clk->id].name, rate);
+
+ switch (clk->id) {
+ case GCC_QUPV3_WRAP1_S3_CLK: /*UART9*/
+ freq = qcom_find_freq(ftbl_gcc_qupv3_wrap1_s3_clk_src, rate);
+ clk_rcg_set_rate_mnd(priv->base, GCC_SE12_UART_RCG_REG,
+ freq->pre_div, freq->m, freq->n, freq->src,
+ 16);
+
+ return freq->freq;
+ case GCC_SDCC2_APPS_CLK:
+ /* Enable GPLL7 so that we can point SDCC2_APPS_CLK_SRC at it */
+ clk_enable_gpll0(priv->base, &gpll7_vote_clk);
+ freq = qcom_find_freq(ftbl_gcc_sdcc2_apps_clk_src, rate);
+ WARN(freq->src != CFG_CLK_SRC_GPLL7,
+ "SDCC2_APPS_CLK_SRC not set to GPLL7, requested rate %lu\n",
+ rate);
+ clk_rcg_set_rate_mnd(priv->base, GCC_SDCC2_APPS_CLK_SRC_REG,
+ freq->pre_div, freq->m, freq->n,
+ CFG_CLK_SRC_GPLL7, 8);
+
+ return rate;
+ default:
+ return 0;
+ }
+}
+
+static const struct gate_clk sm6350_clks[] = {
+ GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x3e014, 0x00000001),
+ GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0x3e010, 0x00000001),
+ GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x1101c, 0x00000001),
+ GATE_CLK(GCC_QUPV3_WRAP1_S3_CLK, 0x52000, 0x00800000),
+ GATE_CLK(GCC_QUPV3_WRAP_1_M_AHB_CLK, 0x52000, 0x00040000),
+ GATE_CLK(GCC_QUPV3_WRAP_1_S_AHB_CLK, 0x52000, 0x00080000),
+ GATE_CLK(GCC_SDCC2_AHB_CLK, 0x20008, 0x00000001),
+ GATE_CLK(GCC_SDCC2_APPS_CLK, 0x20004, 0x00000001),
+ GATE_CLK(GCC_UFS_MEM_CLKREF_CLK, 0x8c000, 0x00000001),
+ GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x3a00c, 0x00000001),
+ GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x3a034, 0x00000001),
+ GATE_CLK(GCC_UFS_PHY_ICE_CORE_CLK, 0x3a0a4, 0x00000001),
+ GATE_CLK(GCC_UFS_PHY_PHY_AUX_CLK, 0x3a0ac, 0x00000001),
+ GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_0_CLK, 0x3a014, 0x00000001),
+ GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_1_CLK, 0x3a018, 0x00000001),
+ GATE_CLK(GCC_UFS_PHY_TX_SYMBOL_0_CLK, 0x3a010, 0x00000001),
+ GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x3a09c, 0x00000001),
+ GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0x1a00c, 0x00000001),
+ GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0x1a018, 0x00000001),
+ GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0x1a014, 0x00000001),
+ GATE_CLK(GCC_USB3_PRIM_CLKREF_CLK, 0x8c010, 0x00000001),
+ GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0x1a050, 0x00000001),
+ GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0x1a054, 0x00000001),
+ GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0x1a058, 0x00000001),
+};
+
+static int sm6350_enable(struct clk *clk)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
+ if (priv->data->num_clks < clk->id) {
+ debug("%s: unknown clk id %lu\n", __func__, clk->id);
+ return 0;
+ }
+
+ debug("%s: clk %s\n", __func__, sm6350_clks[clk->id].name);
+
+ switch (clk->id) {
+ case GCC_USB30_PRIM_MASTER_CLK:
+ qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_AUX_CLK);
+ qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_COM_AUX_CLK);
+ break;
+ }
+
+ return qcom_gate_clk_en(priv, clk->id);
+}
+
+static const struct qcom_reset_map sm6350_gcc_resets[] = {
+ [GCC_QUSB2PHY_PRIM_BCR] = { 0x1d000 },
+ [GCC_QUSB2PHY_SEC_BCR] = { 0x1e000 },
+ [GCC_SDCC1_BCR] = { 0x4b000 },
+ [GCC_SDCC2_BCR] = { 0x20000 },
+ [GCC_UFS_PHY_BCR] = { 0x3a000 },
+ [GCC_USB30_PRIM_BCR] = { 0x1a000 },
+ [GCC_USB3_PHY_PRIM_BCR] = { 0x1c000 },
+ [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x1c008 },
+};
+
+static const struct qcom_power_map sm6350_gdscs[] = {
+ [USB30_PRIM_GDSC] = { 0x1a004 },
+ [UFS_PHY_GDSC] = { 0x3a004 },
+ [HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC] = { 0xb7040 },
+ [HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC] = { 0xb7044 },
+};
+
+static struct msm_clk_data sm6350_gcc_data = {
+ .resets = sm6350_gcc_resets,
+ .num_resets = ARRAY_SIZE(sm6350_gcc_resets),
+ .clks = sm6350_clks,
+ .num_clks = ARRAY_SIZE(sm6350_clks),
+ .power_domains = sm6350_gdscs,
+ .num_power_domains = ARRAY_SIZE(sm6350_gdscs),
+
+ .enable = sm6350_enable,
+ .set_rate = sm6350_set_rate,
+};
+
+static const struct udevice_id gcc_sm6350_of_match[] = {
+ {
+ .compatible = "qcom,gcc-sm6350",
+ .data = (ulong)&sm6350_gcc_data,
+ },
+ {}
+};
+
+U_BOOT_DRIVER(gcc_sm6350) = {
+ .name = "gcc_sm6350",
+ .id = UCLASS_NOP,
+ .of_match = gcc_sm6350_of_match,
+ .bind = qcom_cc_bind,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/qcom/clock-sm7150.c b/drivers/clk/qcom/clock-sm7150.c
new file mode 100644
index 00000000000..8fe2076e55e
--- /dev/null
+++ b/drivers/clk/qcom/clock-sm7150.c
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Clock drivers for Qualcomm SM7150
+ *
+ * (C) Copyright 2025 Danila Tikhonov <danila@jiaxyga.com>
+ * (C) Copyright 2025 Jens Reidel <adrian@mainlining.org>
+ *
+ * Based on Linux Kernel driver
+ */
+
+#include <clk-uclass.h>
+#include <dm.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <linux/bug.h>
+#include <linux/bitops.h>
+#include <dt-bindings/clock/qcom,sm7150-gcc.h>
+
+#include "clock-qcom.h"
+
+#define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf01c
+#define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0xf034
+#define USB3_PRIM_PHY_AUX_CLK_CMD_RCGR 0xf060
+
+#define SE8_UART_APPS_CMD_RCGR 0x18278
+#define GCC_SDCC2_APPS_CLK_SRC_REG 0x1400c
+
+#define APCS_GPLL7_STATUS 0x27000
+#define APCS_GPLLX_ENA_REG 0x52000
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = {
+ F(7372800, CFG_CLK_SRC_GPLL0_EVEN, 1, 384, 15625),
+ F(14745600, CFG_CLK_SRC_GPLL0_EVEN, 1, 768, 15625),
+ F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0),
+ F(29491200, CFG_CLK_SRC_GPLL0_EVEN, 1, 1536, 15625),
+ F(32000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 75),
+ F(48000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 25),
+ F(64000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 16, 75),
+ F(80000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 15),
+ F(96000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 25),
+ F(100000000, CFG_CLK_SRC_GPLL0_EVEN, 3, 0, 0),
+ F(102400000, CFG_CLK_SRC_GPLL0_EVEN, 1, 128, 375),
+ F(112000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 28, 75),
+ F(117964800, CFG_CLK_SRC_GPLL0_EVEN, 1, 6144, 15625),
+ F(120000000, CFG_CLK_SRC_GPLL0_EVEN, 2.5, 0, 0),
+ F(128000000, CFG_CLK_SRC_GPLL0, 1, 16, 75),
+ { }
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = {
+ F(400000, CFG_CLK_SRC_CXO, 12, 1, 4),
+ F(9600000, CFG_CLK_SRC_CXO, 2, 0, 0),
+ F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0),
+ F(25000000, CFG_CLK_SRC_GPLL0_EVEN, 12, 0, 0),
+ F(50000000, CFG_CLK_SRC_GPLL0_EVEN, 6, 0, 0),
+ F(100000000, CFG_CLK_SRC_GPLL0, 6, 0, 0),
+ F(208000000, CFG_CLK_SRC_GPLL7, 4, 0, 0),
+ { }
+};
+
+static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = {
+ F(66666667, CFG_CLK_SRC_GPLL0, 4.5, 0, 0),
+ F(133333333, CFG_CLK_SRC_GPLL0_EVEN, 4.5, 0, 0),
+ F(200000000, CFG_CLK_SRC_GPLL0, 3, 0, 0),
+ F(240000000, CFG_CLK_SRC_GPLL0, 2.5, 0, 0),
+ { }
+};
+
+static const struct freq_tbl ftbl_gcc_usb30_prim_mock_utmi_clk_src[] = {
+ F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0),
+ F(20000000, CFG_CLK_SRC_GPLL0_EVEN, 15, 0, 0),
+ F(40000000, CFG_CLK_SRC_GPLL0_EVEN, 7.5, 0, 0),
+ F(60000000, CFG_CLK_SRC_GPLL0, 10, 0, 0),
+ { }
+};
+
+static const struct freq_tbl ftbl_gcc_usb3_prim_phy_aux_clk_src[] = {
+ F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0),
+ { }
+};
+
+static ulong sm7150_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+ const struct freq_tbl *freq;
+
+ if (clk->id < priv->data->num_clks)
+ debug("%s: %s, requested rate=%ld\n", __func__, priv->data->clks[clk->id].name, rate);
+
+ switch (clk->id) {
+ case GCC_QUPV3_WRAP1_S2_CLK: /* UART8 */
+ freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s0_clk_src, rate);
+ clk_rcg_set_rate_mnd(priv->base, SE8_UART_APPS_CMD_RCGR,
+ freq->pre_div, freq->m, freq->n, freq->src, 16);
+ return freq->freq;
+ case GCC_USB30_PRIM_MASTER_CLK:
+ freq = qcom_find_freq(ftbl_gcc_usb30_prim_master_clk_src, rate);
+ clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR,
+ freq->pre_div, freq->m, freq->n, freq->src, 8);
+ return freq->freq;
+ case GCC_USB30_PRIM_MOCK_UTMI_CLK:
+ freq = qcom_find_freq(ftbl_gcc_usb30_prim_mock_utmi_clk_src, rate);
+ clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR,
+ freq->pre_div, freq->m, freq->n, freq->src, 0);
+ return freq->freq;
+ case GCC_USB3_PRIM_PHY_AUX_CLK_SRC:
+ freq = qcom_find_freq(ftbl_gcc_usb3_prim_phy_aux_clk_src, rate);
+ clk_rcg_set_rate_mnd(priv->base, USB3_PRIM_PHY_AUX_CLK_CMD_RCGR,
+ freq->pre_div, freq->m, freq->n, freq->src, 0);
+ return freq->freq;
+ case GCC_SDCC2_APPS_CLK:
+ freq = qcom_find_freq(ftbl_gcc_sdcc2_apps_clk_src, rate);
+ clk_rcg_set_rate_mnd(priv->base, GCC_SDCC2_APPS_CLK_SRC_REG,
+ freq->pre_div, freq->m, freq->n, freq->src, 8);
+ return freq->freq;
+ default:
+ return 0;
+ }
+}
+
+static const struct gate_clk sm7150_clks[] = {
+ GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x82024, BIT(0)),
+ GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0x8201c, BIT(0)),
+ GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x502c, BIT(0)),
+ GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x5200c, BIT(10)),
+ GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x5200c, BIT(11)),
+ GATE_CLK(GCC_QUPV3_WRAP0_S2_CLK, 0x5200c, BIT(12)),
+ GATE_CLK(GCC_QUPV3_WRAP0_S3_CLK, 0x5200c, BIT(13)),
+ GATE_CLK(GCC_QUPV3_WRAP0_S4_CLK, 0x5200c, BIT(14)),
+ GATE_CLK(GCC_QUPV3_WRAP0_S5_CLK, 0x5200c, BIT(15)),
+ GATE_CLK(GCC_QUPV3_WRAP0_S6_CLK, 0x5200c, BIT(16)),
+ GATE_CLK(GCC_QUPV3_WRAP0_S7_CLK, 0x5200c, BIT(17)),
+ GATE_CLK(GCC_QUPV3_WRAP1_S0_CLK, 0x5200c, BIT(22)),
+ GATE_CLK(GCC_QUPV3_WRAP1_S1_CLK, 0x5200c, BIT(23)),
+ GATE_CLK(GCC_QUPV3_WRAP1_S2_CLK, 0x5200c, BIT(24)),
+ GATE_CLK(GCC_QUPV3_WRAP1_S3_CLK, 0x5200c, BIT(25)),
+ GATE_CLK(GCC_QUPV3_WRAP1_S4_CLK, 0x5200c, BIT(26)),
+ GATE_CLK(GCC_QUPV3_WRAP1_S5_CLK, 0x5200c, BIT(27)),
+ GATE_CLK(GCC_QUPV3_WRAP1_S6_CLK, 0x5200c, BIT(28)),
+ GATE_CLK(GCC_QUPV3_WRAP1_S7_CLK, 0x5200c, BIT(29)),
+ GATE_CLK(GCC_QUPV3_WRAP_0_M_AHB_CLK, 0x5200c, BIT(6)),
+ GATE_CLK(GCC_QUPV3_WRAP_0_S_AHB_CLK, 0x5200c, BIT(7)),
+ GATE_CLK(GCC_QUPV3_WRAP_1_M_AHB_CLK, 0x5200c, BIT(20)),
+ GATE_CLK(GCC_QUPV3_WRAP_1_S_AHB_CLK, 0x5200c, BIT(21)),
+ GATE_CLK(GCC_SDCC1_AHB_CLK, 0x12008, BIT(0)),
+ GATE_CLK(GCC_SDCC1_APPS_CLK, 0x1200c, BIT(0)),
+ GATE_CLK(GCC_SDCC1_ICE_CORE_CLK, 0x12040, BIT(0)),
+ GATE_CLK(GCC_SDCC2_AHB_CLK, 0x14008, BIT(0)),
+ GATE_CLK(GCC_SDCC2_APPS_CLK, 0x14004, BIT(0)),
+ GATE_CLK(GCC_SDCC4_AHB_CLK, 0x16008, BIT(0)),
+ GATE_CLK(GCC_SDCC4_APPS_CLK, 0x16004, BIT(0)),
+ GATE_CLK(GCC_UFS_MEM_CLKREF_CLK, 0x8c000, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x77014, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x77038, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_ICE_CORE_CLK, 0x77090, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_PHY_AUX_CLK, 0x77094, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_0_CLK, 0x7701c, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_TX_SYMBOL_0_CLK, 0x77018, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x7708c, BIT(0)),
+ GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0x0f010, BIT(0)),
+ GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0x0f018, BIT(0)),
+ GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0x0f014, BIT(0)),
+ GATE_CLK(GCC_USB3_PRIM_CLKREF_CLK, 0x8c010, BIT(0)),
+ GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0x0f050, BIT(0)),
+ GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0x0f054, BIT(0)),
+ GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0x0f058, BIT(0)),
+ GATE_CLK(GCC_USB_PHY_CFG_AHB2PHY_CLK, 0x6a004, BIT(0)),
+};
+
+static int sm7150_clk_enable(struct clk *clk)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
+ if (priv->data->num_clks < clk->id) {
+ debug("%s: unknown clk id %lu\n", __func__, clk->id);
+ return 0;
+ }
+
+ debug("%s: clk %s\n", __func__, sm7150_clks[clk->id].name);
+
+ switch (clk->id) {
+ case GCC_AGGRE_USB3_PRIM_AXI_CLK:
+ qcom_gate_clk_en(priv, GCC_USB30_PRIM_MASTER_CLK);
+ fallthrough;
+ case GCC_USB30_PRIM_MASTER_CLK:
+ qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_AUX_CLK);
+ qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_COM_AUX_CLK);
+ break;
+ }
+
+ return qcom_gate_clk_en(priv, clk->id);
+}
+
+static const struct qcom_reset_map sm7150_gcc_resets[] = {
+ [GCC_UFS_PHY_BCR] = { 0x77000 },
+ [GCC_USB30_PRIM_BCR] = { 0xf000 },
+ [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x50008 },
+ [GCC_USB3_DP_PHY_SEC_BCR] = { 0x50014 },
+ [GCC_USB3_PHY_PRIM_BCR] = { 0x50000 },
+ [GCC_USB3_PHY_SEC_BCR] = { 0x5000c },
+ [GCC_QUSB2PHY_PRIM_BCR] = { 0x26000 },
+};
+
+static const struct qcom_power_map sm7150_gdscs[] = {
+ [PCIE_0_GDSC] = { 0x6b004 },
+ [UFS_PHY_GDSC] = { 0x77004 },
+ [USB30_PRIM_GDSC] = { 0xf004 },
+};
+
+static const phys_addr_t sm7150_rcg_addrs[] = {
+ 0x10f01c, // USB30_PRIM_MASTER_CLK_CMD_RCGR
+ 0x10f034, // USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR
+ 0x10f060, // USB3_PRIM_PHY_AUX_CLK_CMD_RCGR,
+};
+
+static const char *const sm7150_rcg_names[] = {
+ "USB30_PRIM_MASTER_CLK",
+ "USB30_PRIM_MOCK_UTMI_CLK",
+ "USB3_PRIM_PHY_AUX_CLK",
+};
+
+static struct msm_clk_data sm7150_gcc_data = {
+ .resets = sm7150_gcc_resets,
+ .num_resets = ARRAY_SIZE(sm7150_gcc_resets),
+ .clks = sm7150_clks,
+ .num_clks = ARRAY_SIZE(sm7150_clks),
+
+ .power_domains = sm7150_gdscs,
+ .num_power_domains = ARRAY_SIZE(sm7150_gdscs),
+
+ .enable = sm7150_clk_enable,
+ .set_rate = sm7150_clk_set_rate,
+
+ .dbg_rcg_addrs = sm7150_rcg_addrs,
+ .num_rcgs = ARRAY_SIZE(sm7150_rcg_addrs),
+ .dbg_rcg_names = sm7150_rcg_names,
+};
+
+static const struct udevice_id gcc_sm7150_of_match[] = {
+ { .compatible = "qcom,sm7150-gcc", .data = (ulong)&sm7150_gcc_data, },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(gcc_sm7150) = {
+ .name = "gcc_sm7150",
+ .id = UCLASS_NOP,
+ .of_match = gcc_sm7150_of_match,
+ .bind = qcom_cc_bind,
+ .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF,
+};
diff --git a/drivers/clk/qcom/clock-sm8250.c b/drivers/clk/qcom/clock-sm8250.c
index cc481258d22..37268c4eaf5 100644
--- a/drivers/clk/qcom/clock-sm8250.c
+++ b/drivers/clk/qcom/clock-sm8250.c
@@ -18,14 +18,9 @@
#define GCC_SE12_UART_RCG_REG 0x184D0
#define GCC_SDCC2_APPS_CLK_SRC_REG 0x1400c
-#define APCS_GPLL0_ENA_VOTE 0x79000
#define APCS_GPLL9_STATUS 0x1c000
#define APCS_GPLLX_ENA_REG 0x52018
-#define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf020
-#define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0xf038
-#define USB3_PRIM_PHY_AUX_CMD_RCGR 0xf064
-
static const struct freq_tbl ftbl_gcc_qupv3_wrap1_s4_clk_src[] = {
F(7372800, CFG_CLK_SRC_GPLL0_EVEN, 1, 384, 15625),
F(14745600, CFG_CLK_SRC_GPLL0_EVEN, 1, 768, 15625),
diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig
index 12966d02a22..51c87cc3606 100644
--- a/drivers/clk/renesas/Kconfig
+++ b/drivers/clk/renesas/Kconfig
@@ -51,8 +51,8 @@ config CLK_R8A7794
Enable this to support the clocks on Renesas R8A7794 SoC.
config CLK_RCAR_GEN3
- bool "Renesas R-Car Gen3 and Gen4 clock driver"
- def_bool y if RCAR_64
+ bool "Renesas R-Car Gen3, Gen4, RZ/G2L clock driver"
+ def_bool y if RCAR_GEN3 || RCAR_GEN4 || RZG2L
depends on CLK_RENESAS
select CLK_RCAR
select CLK_RCAR_CPG_LIB
diff --git a/drivers/clk/rockchip/clk_px30.c b/drivers/clk/rockchip/clk_px30.c
index ad7e1c0f246..b5054e84c32 100644
--- a/drivers/clk/rockchip/clk_px30.c
+++ b/drivers/clk/rockchip/clk_px30.c
@@ -1360,6 +1360,9 @@ static ulong px30_clk_set_rate(struct clk *clk, ulong rate)
case SCLK_GMAC_RMII:
ret = px30_mac_set_speed_clk(priv, rate);
break;
+ /* Might occur in cru assigned-clocks, can be ignored here */
+ case SCLK_GPU:
+ break;
#endif
default:
return -ENOENT;
@@ -1726,6 +1729,9 @@ static ulong px30_pmuclk_set_rate(struct clk *clk, ulong rate)
case SCLK_UART0_PMU:
ret = px30_pmu_uart0_set_clk(priv, rate);
break;
+ /* Might occur in pmucru assigned-clocks, can be ignored here */
+ case SCLK_WIFI_PMU:
+ break;
default:
return -ENOENT;
}
diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig
index 20fc004b59e..01e4f33415e 100644
--- a/drivers/clk/sifive/Kconfig
+++ b/drivers/clk/sifive/Kconfig
@@ -2,7 +2,7 @@
config CLK_SIFIVE
bool "SiFive SoC driver support"
- depends on CLK
+ depends on CLK && RISCV
help
SoC drivers for SiFive Linux-capable SoCs.
diff --git a/drivers/clk/sophgo/clk-common.h b/drivers/clk/sophgo/clk-common.h
index a9e83d0d689..a18673f397c 100644
--- a/drivers/clk/sophgo/clk-common.h
+++ b/drivers/clk/sophgo/clk-common.h
@@ -70,7 +70,7 @@ cv1800b_clk_setfield(void *base, struct cv1800b_clk_regfield *field, u32 val)
u32 new_val = (readl(base + field->offset) & ~mask) |
((val << field->shift) & mask);
- return writel(new_val, base + field->offset);
+ writel(new_val, base + field->offset);
}
#endif /* __CLK_SOPHGO_COMMON_H__ */
diff --git a/drivers/clk/ti/Kconfig b/drivers/clk/ti/Kconfig
index fbcdefd889a..fdda283d6d3 100644
--- a/drivers/clk/ti/Kconfig
+++ b/drivers/clk/ti/Kconfig
@@ -5,14 +5,14 @@
config CLK_TI_AM3_DPLL
bool "TI AM33XX Digital Phase-Locked Loop (DPLL) clock drivers"
- depends on CLK && OF_CONTROL
+ depends on CLK && OF_CONTROL && ARCH_OMAP2PLUS
help
This enables the DPLL clock drivers support on AM33XX SoCs. The DPLL
provides all interface clocks and functional clocks to the processor.
config CLK_TI_CTRL
bool "TI OMAP4 clock controller"
- depends on CLK && OF_CONTROL
+ depends on CLK && OF_CONTROL && ARCH_OMAP2PLUS
help
This enables the clock controller driver support on TI's SoCs.
@@ -49,7 +49,7 @@ config CLK_K3_PLL
Enables PLL clock support for K3 SoC family of devices.
config SPL_CLK_K3_PLL
- bool "PLL clock support for K3 SoC family of devices"
+ bool "PLL clock support for K3 SoC family of devices in SPL"
depends on CLK && LIB_RATIONAL && SPL
help
Enables PLL clock support for K3 SoC family of devices.
@@ -61,7 +61,7 @@ config CLK_K3
Enables the clock translation layer from DT to device clocks.
config SPL_CLK_K3
- bool "Clock support for K3 SoC family of devices"
+ bool "Clock support for K3 SoC family of devices in SPL"
depends on CLK && SPL
help
Enables the clock translation layer from DT to device clocks.
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index e040e3f2806..cf1cf8abfbe 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -1221,13 +1221,16 @@ int ofnode_decode_display_timing(ofnode parent, int index,
int ret = 0;
timings = ofnode_find_subnode(parent, "display-timings");
- if (!ofnode_valid(timings))
- return -EINVAL;
-
- i = 0;
- ofnode_for_each_subnode(node, timings) {
- if (i++ == index)
- break;
+ if (ofnode_valid(timings)) {
+ i = 0;
+ ofnode_for_each_subnode(node, timings) {
+ if (i++ == index)
+ break;
+ }
+ } else {
+ if (index != 0)
+ return -EINVAL;
+ node = ofnode_find_subnode(parent, "panel-timing");
}
if (!ofnode_valid(node))
@@ -1629,18 +1632,6 @@ bool ofnode_pre_reloc(ofnode node)
ofnode_read_bool(node, "bootph-pre-sram"))
return gd->flags & GD_FLG_RELOC;
- if (IS_ENABLED(CONFIG_OF_TAG_MIGRATE)) {
- /* detect and handle old tags */
- if (ofnode_read_bool(node, "u-boot,dm-pre-reloc") ||
- ofnode_read_bool(node, "u-boot,dm-pre-proper") ||
- ofnode_read_bool(node, "u-boot,dm-spl") ||
- ofnode_read_bool(node, "u-boot,dm-tpl") ||
- ofnode_read_bool(node, "u-boot,dm-vpl")) {
- gd->flags |= GD_FLG_OF_TAG_MIGRATE;
- return true;
- }
- }
-
return false;
#endif
}
diff --git a/drivers/cpu/imx8_cpu.c b/drivers/cpu/imx8_cpu.c
index 950630453f9..5f17122c36c 100644
--- a/drivers/cpu/imx8_cpu.c
+++ b/drivers/cpu/imx8_cpu.c
@@ -113,6 +113,8 @@ static const char *get_imx_type_str(u32 imxtype)
return "91(01)";/* iMX91 9x9 Specific feature */
case MXC_CPU_IMX95:
return "95";
+ case MXC_CPU_IMX94:
+ return "94";
default:
return "??";
}
@@ -190,7 +192,7 @@ static int cpu_imx_get_temp(struct cpu_imx_plat *plat)
return 0xdeadbeef;
}
- return cpu_tmp;
+ return cpu_tmp / 1000;
}
#else
static int cpu_imx_get_temp(struct cpu_imx_plat *plat)
diff --git a/drivers/crypto/fsl/jr.c b/drivers/crypto/fsl/jr.c
index 8f7a821ebf3..07d336c074a 100644
--- a/drivers/crypto/fsl/jr.c
+++ b/drivers/crypto/fsl/jr.c
@@ -642,7 +642,7 @@ static int rng_init(uint8_t sec_idx, ccsr_sec_t *sec)
*/
if (!inst_handles) {
kick_trng(ent_delay, sec);
- ent_delay += 400;
+ ent_delay = ent_delay * 2;
}
/*
* if instantiate_rng(...) fails, the loop will rerun
diff --git a/drivers/crypto/tegra/Kconfig b/drivers/crypto/tegra/Kconfig
index b027609307b..0f2acaaade1 100644
--- a/drivers/crypto/tegra/Kconfig
+++ b/drivers/crypto/tegra/Kconfig
@@ -1,6 +1,6 @@
config TEGRA_AES
bool "Support the Tegra AES"
- depends on DM_AES
+ depends on ARCH_TEGRA && DM_AES
help
This provides a means to encrypt and decrypt data using the Tegra
Bit Stream Engine for Video/Audio. Also may provide a mean to
diff --git a/drivers/ddr/altera/iossm_mailbox.c b/drivers/ddr/altera/iossm_mailbox.c
index 21f94959a04..2a2f86a650e 100644
--- a/drivers/ddr/altera/iossm_mailbox.c
+++ b/drivers/ddr/altera/iossm_mailbox.c
@@ -38,6 +38,8 @@
#define IOSSM_STATUS_CMD_RESPONSE_ERROR(n) FIELD_GET(IOSSM_STATUS_CMD_RESPONSE_ERROR_MASK, n)
#define IOSSM_STATUS_GENERAL_ERROR_MASK GENMASK(4, 1)
#define IOSSM_STATUS_GENERAL_ERROR(n) FIELD_GET(IOSSM_STATUS_GENERAL_ERROR_MASK, n)
+#define IOSSM_MAILBOX_SPEC_VERSION_MASK GENMASK(2, 0)
+#define IOSSM_MAILBOX_SPEC_VERSION(n) FIELD_GET(IOSSM_MAILBOX_SPEC_VERSION_MASK, n)
/* Offset of Mailbox Read-only Registers */
#define IOSSM_MAILBOX_HEADER_OFFSET 0x0
@@ -383,6 +385,23 @@ err:
return ret;
}
+static bool is_mailbox_spec_compatible(struct io96b_info *io96b_ctrl)
+{
+ u32 mailbox_header;
+ u8 mailbox_spec_ver;
+
+ mailbox_header = readl(io96b_ctrl->io96b[0].io96b_csr_addr +
+ IOSSM_MAILBOX_HEADER_OFFSET);
+ mailbox_spec_ver = IOSSM_MAILBOX_SPEC_VERSION(mailbox_header);
+ printf("%s: IOSSM mailbox version: %d\n", __func__, mailbox_spec_ver);
+
+ /* for now there are two mailbox spec versions, 0 and 1; only version 1 is compatible */
+ if (!mailbox_spec_ver)
+ return false;
+
+ return true;
+}
+
/*
* Initial function to be called to set memory interface IP type and instance ID
* IP type and instance ID need to be determined before sending mailbox command
@@ -392,6 +411,11 @@ void io96b_mb_init(struct io96b_info *io96b_ctrl)
int i, j;
u32 mem_intf_info_0, mem_intf_info_1;
+ if (!is_mailbox_spec_compatible(io96b_ctrl)) {
+ printf("DDR: Failed to get compatible mailbox version\n");
+ hang();
+ }
+
debug("%s: num_instance %d\n", __func__, io96b_ctrl->num_instance);
for (i = 0; i < io96b_ctrl->num_instance; i++) {
diff --git a/drivers/ddr/altera/sdram_soc64.c b/drivers/ddr/altera/sdram_soc64.c
index f8fc92060db..2d0093c591c 100644
--- a/drivers/ddr/altera/sdram_soc64.c
+++ b/drivers/ddr/altera/sdram_soc64.c
@@ -85,11 +85,11 @@ int emif_reset(struct altera_sdram_plat *plat)
debug("DDR: Triggerring emif reset\n");
hmc_ecc_writel(plat, DDR_HMC_CORE2SEQ_INT_REQ, RSTHANDSHAKECTRL);
- /* if seq2core[3] = 0, we are good */
+ /* if seq2core[2:0] = 0b0000_0111, we are good */
ret = wait_for_bit_le32((const void *)(plat->hmc +
RSTHANDSHAKESTAT),
- DDR_HMC_SEQ2CORE_INT_RESP_MASK,
- false, 1000, false);
+ DDR_HMC_SEQ2CORE_INT_REQ_ACK_MASK,
+ true, 1000, false);
if (ret) {
printf("DDR: failed to get ack from EMIF\n");
return ret;
diff --git a/drivers/ddr/altera/sdram_soc64.h b/drivers/ddr/altera/sdram_soc64.h
index 6031cef560e..6fe0653922c 100644
--- a/drivers/ddr/altera/sdram_soc64.h
+++ b/drivers/ddr/altera/sdram_soc64.h
@@ -77,7 +77,7 @@ struct altera_sdram_plat {
#define DDR_HMC_INTMODE_INTMODE_SET_MSK BIT(0)
#define DDR_HMC_RSTHANDSHAKE_MASK 0x0000000f
#define DDR_HMC_CORE2SEQ_INT_REQ 0x0000000f
-#define DDR_HMC_SEQ2CORE_INT_RESP_MASK BIT(3)
+#define DDR_HMC_SEQ2CORE_INT_REQ_ACK_MASK GENMASK(2, 0)
#define DDR_HMC_HPSINTFCSEL_ENABLE_MASK 0x001f1f1f
#define DDR_HMC_ERRINTEN_INTMASK \
diff --git a/drivers/dfu/Kconfig b/drivers/dfu/Kconfig
index e33b0056d0b..2cf4289b448 100644
--- a/drivers/dfu/Kconfig
+++ b/drivers/dfu/Kconfig
@@ -98,6 +98,7 @@ config DFU_SCSI
config SET_DFU_ALT_INFO
bool "Dynamic set of DFU alternate information"
+ depends on !COMPILE_TEST
help
This option allows to call the function set_dfu_alt_info to
dynamically build dfu_alt_info in board.
diff --git a/drivers/fastboot/fb_nand.c b/drivers/fastboot/fb_nand.c
index afc64fd5280..6df3917e129 100644
--- a/drivers/fastboot/fb_nand.c
+++ b/drivers/fastboot/fb_nand.c
@@ -157,8 +157,13 @@ int fastboot_nand_get_part_info(const char *part_name,
struct part_info **part_info, char *response)
{
struct mtd_info *mtd = NULL;
+ int ret;
+
+ ret = fb_nand_lookup(part_name, &mtd, part_info, response);
+ if (ret)
+ return -ENOENT;
- return fb_nand_lookup(part_name, &mtd, part_info, response);
+ return ret;
}
/**
diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c
index e07ec3929b2..3742467caee 100644
--- a/drivers/firmware/firmware-zynqmp.c
+++ b/drivers/firmware/firmware-zynqmp.c
@@ -3,6 +3,7 @@
* Xilinx Zynq MPSoC Firmware driver
*
* Copyright (C) 2018-2019 Xilinx, Inc.
+ * Copyright (C) 2022 - 2025, Advanced Micro Devices, Inc.
*/
#include <asm/arch/hardware.h>
@@ -158,7 +159,7 @@ unsigned int zynqmp_firmware_version(void)
if (pm_api_version == ZYNQMP_PM_VERSION_INVALID) {
ret = xilinx_pm_request(PM_GET_API_VERSION, 0, 0, 0, 0,
- ret_payload);
+ 0, 0, ret_payload);
if (ret)
panic("PMUFW is not found - Please load it!\n");
@@ -202,7 +203,7 @@ int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config, u32 value
int ret;
ret = xilinx_pm_request(PM_IOCTL, node, IOCTL_SET_GEM_CONFIG,
- config, value, NULL);
+ config, value, 0, 0, NULL);
if (ret)
printf("%s: node %d: set_gem_config %d failed\n",
__func__, node, config);
@@ -215,7 +216,7 @@ int zynqmp_pm_set_sd_config(u32 node, enum pm_sd_config_type config, u32 value)
int ret;
ret = xilinx_pm_request(PM_IOCTL, node, IOCTL_SET_SD_CONFIG,
- config, value, NULL);
+ config, value, 0, 0, NULL);
if (ret)
printf("%s: node %d: set_sd_config %d failed\n",
__func__, node, config);
@@ -236,7 +237,7 @@ u32 zynqmp_pm_get_bootmode_reg(void)
}
ret = xilinx_pm_request(PM_IOCTL, CRP_BOOT_MODE_REG_NODE, IOCTL_READ_REG,
- CRP_BOOT_MODE_REG_OFFSET, 0, ret_payload);
+ CRP_BOOT_MODE_REG_OFFSET, 0, 0, 0, ret_payload);
if (ret) {
printf("%s: node 0x%x: get_bootmode 0x%x failed\n",
__func__, CRP_BOOT_MODE_REG_NODE, CRP_BOOT_MODE_REG_OFFSET);
@@ -259,7 +260,8 @@ u32 zynqmp_pm_get_pmc_multi_boot_reg(void)
}
ret = xilinx_pm_request(PM_IOCTL, PM_REG_PMC_GLOBAL_NODE, IOCTL_READ_REG,
- PMC_MULTI_BOOT_MODE_REG_OFFSET, 0, ret_payload);
+ PMC_MULTI_BOOT_MODE_REG_OFFSET, 0, 0, 0,
+ ret_payload);
if (ret) {
printf("%s: node 0x%x: get_bootmode 0x%x failed\n",
__func__, PM_REG_PMC_GLOBAL_NODE, PMC_MULTI_BOOT_MODE_REG_OFFSET);
@@ -276,7 +278,7 @@ int zynqmp_pm_feature(const u32 api_id)
/* Check feature check API version */
ret = xilinx_pm_request(PM_FEATURE_CHECK, api_id, 0, 0, 0,
- ret_payload);
+ 0, 0, ret_payload);
if (ret)
return ret;
@@ -296,7 +298,7 @@ int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id)
/* Check feature check API version */
ret = xilinx_pm_request(PM_FEATURE_CHECK, PM_FEATURE_CHECK, 0, 0, 0,
- ret_payload);
+ 0, 0, ret_payload);
if (ret)
return ret;
@@ -308,7 +310,7 @@ int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id)
*/
ret = xilinx_pm_request(PM_FEATURE_CHECK, api_id, 0, 0, 0,
- ret_payload);
+ 0, 0, ret_payload);
if (ret)
return ret;
@@ -340,7 +342,7 @@ int zynqmp_pmufw_load_config_object(const void *cfg_obj, size_t size)
flush_dcache_range((ulong)cfg_obj, (ulong)(cfg_obj + size));
err = xilinx_pm_request(PM_SET_CONFIGURATION, (u32)(u64)cfg_obj, 0, 0,
- 0, ret_payload);
+ 0, 0, 0, ret_payload);
if (err == XST_PM_NO_ACCESS) {
return -EACCES;
}
@@ -425,13 +427,14 @@ U_BOOT_DRIVER(zynqmp_power) = {
smc_call_handler_t __data smc_call_handler;
static int smc_call_legacy(u32 api_id, u32 arg0, u32 arg1, u32 arg2,
- u32 arg3, u32 *ret_payload)
+ u32 arg3, u32 arg4, u32 arg5, u32 *ret_payload)
{
struct pt_regs regs;
regs.regs[0] = PM_SIP_SVC | api_id;
regs.regs[1] = ((u64)arg1 << 32) | arg0;
regs.regs[2] = ((u64)arg3 << 32) | arg2;
+ regs.regs[3] = arg4;
smc_call(&regs);
@@ -441,16 +444,18 @@ static int smc_call_legacy(u32 api_id, u32 arg0, u32 arg1, u32 arg2,
ret_payload[2] = (u32)regs.regs[1];
ret_payload[3] = upper_32_bits(regs.regs[1]);
ret_payload[4] = (u32)regs.regs[2];
+ ret_payload[5] = upper_32_bits((u32)regs.regs[2]);
+ ret_payload[6] = (u32)regs.regs[3];
}
return (ret_payload) ? ret_payload[0] : 0;
}
int __maybe_unused xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2,
- u32 arg3, u32 *ret_payload)
+ u32 arg3, u32 arg4, u32 arg5, u32 *ret_payload)
{
- debug("%s at EL%d, API ID: 0x%0x, 0x%0x, 0x%0x, 0x%0x, 0x%0x\n",
- __func__, current_el(), api_id, arg0, arg1, arg2, arg3);
+ debug("%s at EL%d, API ID: 0x%0x, 0x%0x, 0x%0x, 0x%0x, 0x%0x, 0x%0x, 0x%0x\n",
+ __func__, current_el(), api_id, arg0, arg1, arg2, arg3, arg4, arg5);
if (IS_ENABLED(CONFIG_XPL_BUILD) || current_el() == 3) {
#if defined(CONFIG_ZYNQMP_IPI)
@@ -459,7 +464,7 @@ int __maybe_unused xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2,
* is capable to handle PMUFW_PAYLOAD_ARG_CNT bytes but the
* firmware API is limited by the SMC call size
*/
- u32 regs[] = {api_id, arg0, arg1, arg2, arg3};
+ u32 regs[] = {api_id, arg0, arg1, arg2, arg3, arg4, arg5};
int ret;
if (api_id == PM_FPGA_LOAD) {
@@ -481,7 +486,8 @@ int __maybe_unused xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2,
#endif
}
- return smc_call_handler(api_id, arg0, arg1, arg2, arg3, ret_payload);
+ return smc_call_handler(api_id, arg0, arg1, arg2, arg3, arg4,
+ arg5, ret_payload);
}
static const struct udevice_id zynqmp_firmware_ids[] = {
diff --git a/drivers/firmware/scmi/Kconfig b/drivers/firmware/scmi/Kconfig
index 8cf85f0d7a1..33e089c460b 100644
--- a/drivers/firmware/scmi/Kconfig
+++ b/drivers/firmware/scmi/Kconfig
@@ -41,3 +41,11 @@ config SCMI_AGENT_OPTEE
help
Enable the SCMI communication channel based on OP-TEE transport
for compatible "linaro,scmi-optee".
+
+config SCMI_ID_VENDOR_80
+ bool
+
+config SCMI_ID_VENDOR_82
+ bool
+
+source "drivers/firmware/scmi/vendors/imx/Kconfig"
diff --git a/drivers/firmware/scmi/Makefile b/drivers/firmware/scmi/Makefile
index dae42863589..6129726f817 100644
--- a/drivers/firmware/scmi/Makefile
+++ b/drivers/firmware/scmi/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_SCMI_AGENT_MAILBOX) += mailbox_agent.o
obj-$(CONFIG_SCMI_AGENT_OPTEE) += optee_agent.o
obj-$(CONFIG_SCMI_POWER_DOMAIN) += pwdom.o
obj-$(CONFIG_SANDBOX) += sandbox-scmi_agent.o sandbox-scmi_devices.o
+obj-y += vendors/imx/
diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c
index 74a87832dcb..5b242a039c2 100644
--- a/drivers/firmware/scmi/sandbox-scmi_agent.c
+++ b/drivers/firmware/scmi/sandbox-scmi_agent.c
@@ -828,7 +828,7 @@ static int sandbox_scmi_clock_rate_get(struct udevice *dev,
static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg)
{
- struct scmi_clk_state_in *in = NULL;
+ struct scmi_clk_state_in_v1 *in = NULL;
struct scmi_clk_state_out *out = NULL;
struct sandbox_scmi_clk *clk_state = NULL;
@@ -836,7 +836,7 @@ static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg)
!msg->out_msg || msg->out_msg_sz < sizeof(*out))
return -EINVAL;
- in = (struct scmi_clk_state_in *)msg->in_msg;
+ in = (struct scmi_clk_state_in_v1 *)msg->in_msg;
out = (struct scmi_clk_state_out *)msg->out_msg;
clk_state = get_scmi_clk_state(in->clock_id);
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c
index 69a277e8786..ad825d66da2 100644
--- a/drivers/firmware/scmi/scmi_agent-uclass.c
+++ b/drivers/firmware/scmi/scmi_agent-uclass.c
@@ -86,21 +86,41 @@ struct udevice *scmi_get_protocol(struct udevice *dev,
case SCMI_PROTOCOL_ID_BASE:
proto = priv->base_dev;
break;
+#if IS_ENABLED(CONFIG_SCMI_POWER_DOMAIN)
case SCMI_PROTOCOL_ID_POWER_DOMAIN:
proto = priv->pwdom_dev;
break;
+#endif
+#if IS_ENABLED(CONFIG_CLK_SCMI)
case SCMI_PROTOCOL_ID_CLOCK:
proto = priv->clock_dev;
break;
+#endif
+#if IS_ENABLED(CONFIG_RESET_SCMI)
case SCMI_PROTOCOL_ID_RESET_DOMAIN:
proto = priv->resetdom_dev;
break;
+#endif
+#if IS_ENABLED(CONFIG_DM_REGULATOR_SCMI)
case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
proto = priv->voltagedom_dev;
break;
+#endif
+#if IS_ENABLED(CONFIG_PINCTRL_IMX_SCMI)
case SCMI_PROTOCOL_ID_PINCTRL:
proto = priv->pinctrl_dev;
break;
+#endif
+#if IS_ENABLED(CONFIG_SCMI_ID_VENDOR_80)
+ case SCMI_PROTOCOL_ID_VENDOR_80:
+ proto = priv->vendor_dev_80;
+ break;
+#endif
+#if IS_ENABLED(CONFIG_SCMI_ID_VENDOR_82)
+ case SCMI_PROTOCOL_ID_VENDOR_82:
+ proto = priv->vendor_dev_82;
+ break;
+#endif
default:
dev_err(dev, "Protocol not supported\n");
proto = NULL;
@@ -139,21 +159,41 @@ static int scmi_add_protocol(struct udevice *dev,
case SCMI_PROTOCOL_ID_BASE:
priv->base_dev = proto;
break;
+#if IS_ENABLED(CONFIG_SCMI_POWER_DOMAIN)
case SCMI_PROTOCOL_ID_POWER_DOMAIN:
priv->pwdom_dev = proto;
break;
+#endif
+#if IS_ENABLED(CONFIG_CLK_SCMI)
case SCMI_PROTOCOL_ID_CLOCK:
priv->clock_dev = proto;
break;
+#endif
+#if IS_ENABLED(CONFIG_RESET_SCMI)
case SCMI_PROTOCOL_ID_RESET_DOMAIN:
priv->resetdom_dev = proto;
break;
+#endif
+#if IS_ENABLED(CONFIG_DM_REGULATOR_SCMI)
case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
priv->voltagedom_dev = proto;
break;
+#endif
+#if IS_ENABLED(CONFIG_PINCTRL_IMX_SCMI)
case SCMI_PROTOCOL_ID_PINCTRL:
priv->pinctrl_dev = proto;
break;
+#endif
+#if IS_ENABLED(CONFIG_SCMI_ID_VENDOR_80)
+ case SCMI_PROTOCOL_ID_VENDOR_80:
+ priv->vendor_dev_80 = proto;
+ break;
+#endif
+#if IS_ENABLED(CONFIG_SCMI_ID_VENDOR_82)
+ case SCMI_PROTOCOL_ID_VENDOR_82:
+ priv->vendor_dev_82 = proto;
+ break;
+#endif
default:
dev_err(dev, "Protocol not supported\n");
return -EPROTO;
diff --git a/drivers/firmware/scmi/smt.c b/drivers/firmware/scmi/smt.c
index 237871559f0..cd1c0801f72 100644
--- a/drivers/firmware/scmi/smt.c
+++ b/drivers/firmware/scmi/smt.c
@@ -61,20 +61,6 @@ int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt)
if (device_is_compatible(dev, "arm,scmi") && ofnode_has_property(dev_ofnode(dev), "mboxes"))
scmi_smt_enable_intr(smt, true);
-#ifdef CONFIG_ARM
- if (dcache_status()) {
- u32 align_size;
-
- if (IS_ENABLED(CONFIG_ARM64))
- align_size = PAGE_SIZE;
- else
- align_size = MMU_SECTION_SIZE;
-
- mmu_set_region_dcache_behaviour(ALIGN_DOWN((uintptr_t)smt->buf, align_size),
- ALIGN(smt->size, align_size), DCACHE_OFF);
- }
-#endif
-
return 0;
}
diff --git a/drivers/firmware/scmi/vendors/imx/Kconfig b/drivers/firmware/scmi/vendors/imx/Kconfig
new file mode 100644
index 00000000000..16850502bbb
--- /dev/null
+++ b/drivers/firmware/scmi/vendors/imx/Kconfig
@@ -0,0 +1,15 @@
+config IMX_SM_CPU
+ bool "Enable i.MX System Manager CPU API"
+ depends on ARCH_IMX9 && SCMI_FIRMWARE
+ select SCMI_ID_VENDOR_82
+ help
+ If you say Y here to enable i.MX System Manager CPU
+ API to work on some NXP i.MX processors.
+
+config IMX_SM_LMM
+ bool "Enable i.MX System Manager Logical Machine API"
+ depends on ARCH_IMX9 && SCMI_FIRMWARE
+ select SCMI_ID_VENDOR_80
+ help
+ If you say Y here to enable i.MX System Manager Logical Machine
+ API to work on some NXP i.MX processors.
diff --git a/drivers/firmware/scmi/vendors/imx/Makefile b/drivers/firmware/scmi/vendors/imx/Makefile
new file mode 100644
index 00000000000..59ff8640dc1
--- /dev/null
+++ b/drivers/firmware/scmi/vendors/imx/Makefile
@@ -0,0 +1,8 @@
+#
+# Copyright 2025 NXP
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_IMX_SM_CPU) += imx-sm-cpu.o
+obj-$(CONFIG_IMX_SM_LMM) += imx-sm-lmm.o
diff --git a/drivers/firmware/scmi/vendors/imx/imx-sm-cpu.c b/drivers/firmware/scmi/vendors/imx/imx-sm-cpu.c
new file mode 100644
index 00000000000..28dfac642ec
--- /dev/null
+++ b/drivers/firmware/scmi/vendors/imx/imx-sm-cpu.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * i.MX SCMI CPU protocol
+ *
+ * Copyright 2025 NXP
+ */
+
+#include <compiler.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <misc.h>
+#include <scmi_agent.h>
+#include <scmi_agent-uclass.h>
+#include <scmi_protocols.h>
+#include <scmi_nxp_protocols.h>
+
+enum scmi_imx_cpu_protocol_cmd {
+ SCMI_IMX_CPU_ATTRIBUTES = 0x3,
+ SCMI_IMX_CPU_START = 0x4,
+ SCMI_IMX_CPU_STOP = 0x5,
+ SCMI_IMX_CPU_RESET_VECTOR_SET = 0x6,
+ SCMI_IMX_CPU_INFO_GET = 0xC,
+};
+
+struct scmi_imx_cpu_priv {
+ u32 nr_cpu;
+};
+
+struct scmi_imx_cpu_reset_vector_set_in {
+ __le32 cpuid;
+#define CPU_VEC_FLAGS_RESUME BIT(31)
+#define CPU_VEC_FLAGS_START BIT(30)
+#define CPU_VEC_FLAGS_BOOT BIT(29)
+ __le32 flags;
+ __le32 resetvectorlow;
+ __le32 resetvectorhigh;
+};
+
+struct scmi_imx_cpu_info_get_out {
+ __le32 status;
+#define CPU_RUN_MODE_START 0
+#define CPU_RUN_MODE_HOLD 1
+#define CPU_RUN_MODE_STOP 2
+#define CPU_RUN_MODE_SLEEP 3
+ __le32 runmode;
+ __le32 sleepmode;
+ __le32 resetvectorlow;
+ __le32 resetvectorhigh;
+};
+
+int scmi_imx_cpu_start(struct udevice *dev, u32 cpuid, bool start)
+{
+ s32 status;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_VENDOR_82,
+ .message_id = SCMI_IMX_CPU_STOP,
+ .in_msg = (u8 *)&cpuid,
+ .in_msg_sz = sizeof(cpuid),
+ .out_msg = (u8 *)&status,
+ .out_msg_sz = sizeof(status),
+ };
+ int ret;
+
+ if (!dev)
+ return -EINVAL;
+
+ if (start)
+ msg.message_id = SCMI_IMX_CPU_START;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+
+ if (status)
+ return scmi_to_linux_errno(status);
+
+ return 0;
+}
+
+int scmi_imx_cpu_reset_vector_set(struct udevice *dev, u32 cpuid, u32 flags, u64 vector,
+ bool start, bool boot, bool resume)
+{
+ struct scmi_imx_cpu_reset_vector_set_in in;
+ s32 status;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_VENDOR_82,
+ .message_id = SCMI_IMX_CPU_RESET_VECTOR_SET,
+ .in_msg = (u8 *)&in,
+ .in_msg_sz = sizeof(in),
+ .out_msg = (u8 *)&status,
+ .out_msg_sz = sizeof(status),
+ };
+ int ret;
+
+ if (!dev)
+ return -EINVAL;
+
+ in.cpuid = cpu_to_le32(cpuid);
+ in.flags = cpu_to_le32(0);
+ if (start)
+ in.flags |= CPU_VEC_FLAGS_START;
+ if (boot)
+ in.flags |= CPU_VEC_FLAGS_BOOT;
+ if (resume)
+ in.flags |= CPU_VEC_FLAGS_RESUME;
+ in.resetvectorlow = cpu_to_le32(lower_32_bits(vector));
+ in.resetvectorhigh = cpu_to_le32(upper_32_bits(vector));
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+
+ if (status)
+ return scmi_to_linux_errno(status);
+
+ return 0;
+}
+
+int scmi_imx_cpu_started(struct udevice *dev, u32 cpuid, bool *started)
+{
+ struct scmi_imx_cpu_info_get_out out;
+ u32 mode;
+ s32 status;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_VENDOR_82,
+ .message_id = SCMI_IMX_CPU_INFO_GET,
+ .in_msg = (u8 *)&cpuid,
+ .in_msg_sz = sizeof(cpuid),
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int ret;
+
+ if (!dev)
+ return -EINVAL;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+
+ status = cpu_to_le32(out.status);
+ if (status)
+ return scmi_to_linux_errno(status);
+
+ mode = le32_to_cpu(out.runmode);
+ if (mode == CPU_RUN_MODE_START || mode == CPU_RUN_MODE_SLEEP)
+ *started = true;
+
+ return 0;
+}
+
+static int scmi_imx_cpu_probe(struct udevice *dev)
+{
+ int ret;
+
+ ret = devm_scmi_of_get_channel(dev);
+ if (ret) {
+ dev_err(dev, "failed to get channel (%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+U_BOOT_DRIVER(scmi_imx_cpu) = {
+ .name = "scmi_imx_cpu",
+ .id = UCLASS_SCMI_BASE,
+ .probe = scmi_imx_cpu_probe,
+ .priv_auto = sizeof(struct scmi_imx_cpu_priv),
+};
+
+static struct scmi_proto_match match[] = {
+ { .proto_id = SCMI_PROTOCOL_ID_VENDOR_82},
+ { /* Sentinel */ }
+};
+
+U_BOOT_SCMI_PROTO_DRIVER(scmi_imx_cpu, match);
diff --git a/drivers/firmware/scmi/vendors/imx/imx-sm-lmm.c b/drivers/firmware/scmi/vendors/imx/imx-sm-lmm.c
new file mode 100644
index 00000000000..2fd791ca853
--- /dev/null
+++ b/drivers/firmware/scmi/vendors/imx/imx-sm-lmm.c
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * i.MX SCMI LMM protocol
+ *
+ * Copyright 2025 NXP
+ */
+
+#include <compiler.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <linux/types.h>
+#include <misc.h>
+#include <scmi_agent.h>
+#include <scmi_agent-uclass.h>
+#include <scmi_protocols.h>
+#include <scmi_nxp_protocols.h>
+
+enum scmi_imx_lmm_protocol_cmd {
+ SCMI_IMX_LMM_ATTRIBUTES = 0x3,
+ SCMI_IMX_LMM_BOOT = 0x4,
+ SCMI_IMX_LMM_RESET = 0x5,
+ SCMI_IMX_LMM_SHUTDOWN = 0x6,
+ SCMI_IMX_LMM_WAKE = 0x7,
+ SCMI_IMX_LMM_SUSPEND = 0x8,
+ SCMI_IMX_LMM_NOTIFY = 0x9,
+ SCMI_IMX_LMM_RESET_REASON = 0xA,
+ SCMI_IMX_LMM_POWER_ON = 0xB,
+ SCMI_IMX_LMM_RESET_VECTOR_SET = 0xC,
+};
+
+struct scmi_imx_lmm_priv {
+ u32 nr_lmm;
+};
+
+struct scmi_msg_imx_lmm_attributes_out {
+ __le32 status;
+ __le32 lmid;
+ __le32 attributes;
+ __le32 state;
+ __le32 errstatus;
+ u8 name[LMM_MAX_NAME];
+};
+
+struct scmi_imx_lmm_reset_vector_set_in {
+ __le32 lmid;
+ __le32 cpuid;
+ __le32 flags; /* reserved for future extension */
+ __le32 resetvectorlow;
+ __le32 resetvectorhigh;
+};
+
+struct scmi_imx_lmm_shutdown_in {
+ __le32 lmid;
+#define SCMI_IMX_LMM_SHUTDOWN_GRACEFUL BIT(0)
+ __le32 flags;
+};
+
+int scmi_imx_lmm_info(struct udevice *dev, u32 lmid, struct scmi_imx_lmm_info *info)
+{
+ struct scmi_msg_imx_lmm_attributes_out out;
+ s32 status;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_VENDOR_80,
+ .message_id = SCMI_IMX_LMM_ATTRIBUTES,
+ .in_msg = (u8 *)&lmid,
+ .in_msg_sz = sizeof(lmid),
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int ret;
+
+ if (!dev)
+ return -EINVAL;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+
+ status = cpu_to_le32(out.status);
+ if (status)
+ return scmi_to_linux_errno(status);
+
+ info->lmid = le32_to_cpu(out.lmid);
+ info->state = le32_to_cpu(out.state);
+ info->errstatus = le32_to_cpu(out.errstatus);
+ strcpy(info->name, out.name);
+ dev_dbg(dev, "i.MX LMM: Logical Machine(%d), name: %s\n",
+ info->lmid, info->name);
+
+ return ret;
+}
+
+int scmi_imx_lmm_power_boot(struct udevice *dev, u32 lmid, bool boot)
+{
+ s32 status;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_VENDOR_80,
+ .message_id = SCMI_IMX_LMM_POWER_ON,
+ .in_msg = (u8 *)&lmid,
+ .in_msg_sz = sizeof(lmid),
+ .out_msg = (u8 *)&status,
+ .out_msg_sz = sizeof(status),
+ };
+ int ret;
+
+ if (!dev)
+ return -EINVAL;
+
+ if (boot)
+ msg.message_id = SCMI_IMX_LMM_BOOT;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+
+ if (status)
+ return scmi_to_linux_errno(status);
+
+ return 0;
+}
+
+int scmi_imx_lmm_reset_vector_set(struct udevice *dev, u32 lmid, u32 cpuid, u32 flags, u64 vector)
+{
+ struct scmi_imx_lmm_reset_vector_set_in in;
+ s32 status;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_VENDOR_80,
+ .message_id = SCMI_IMX_LMM_RESET_VECTOR_SET,
+ .in_msg = (u8 *)&in,
+ .in_msg_sz = sizeof(in),
+ .out_msg = (u8 *)&status,
+ .out_msg_sz = sizeof(status),
+ };
+ int ret;
+
+ if (!dev)
+ return -EINVAL;
+
+ in.lmid = lmid;
+ in.cpuid = cpuid;
+ in.flags = flags;
+ in.resetvectorlow = vector & 0xFFFFFFFF;
+ in.resetvectorhigh = vector >> 32;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+
+ if (status)
+ return scmi_to_linux_errno(status);
+
+ return 0;
+}
+
+int scmi_imx_lmm_shutdown(struct udevice *dev, u32 lmid, bool flags)
+{
+ struct scmi_imx_lmm_shutdown_in in;
+ s32 status;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_VENDOR_80,
+ .message_id = SCMI_IMX_LMM_SHUTDOWN,
+ .in_msg = (u8 *)&in,
+ .in_msg_sz = sizeof(in),
+ .out_msg = (u8 *)&status,
+ .out_msg_sz = sizeof(status),
+ };
+ int ret;
+
+ if (!dev)
+ return -EINVAL;
+
+ in.lmid = lmid;
+ if (flags & SCMI_IMX_LMM_SHUTDOWN_GRACEFUL)
+ in.flags = cpu_to_le32(SCMI_IMX_LMM_SHUTDOWN_GRACEFUL);
+ else
+ in.flags = cpu_to_le32(0);
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+
+ if (status)
+ return scmi_to_linux_errno(status);
+
+ return 0;
+}
+
+static int scmi_imx_lmm_probe(struct udevice *dev)
+{
+ int ret;
+
+ ret = devm_scmi_of_get_channel(dev);
+ if (ret) {
+ dev_err(dev, "failed to get channel (%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+U_BOOT_DRIVER(scmi_imx_lmm) = {
+ .name = "scmi_imx_lmm",
+ .id = UCLASS_SCMI_BASE,
+ .probe = scmi_imx_lmm_probe,
+ .priv_auto = sizeof(struct scmi_imx_lmm_priv),
+};
+
+static struct scmi_proto_match match[] = {
+ { .proto_id = SCMI_PROTOCOL_ID_VENDOR_80},
+ { /* Sentinel */ }
+};
+
+U_BOOT_SCMI_PROTO_DRIVER(scmi_imx_lmm, match);
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 8013afef304..6f57dcfe8de 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -191,9 +191,9 @@ static int ti_sci_get_response(struct ti_sci_info *info,
/* Sanity check for message response */
if (hdr->seq != info->seq) {
- dev_dbg(info->dev, "%s: Message for %d is not expected\n",
+ dev_err(info->dev, "%s: Message for %d is not expected\n",
__func__, hdr->seq);
- return ret;
+ return -EINVAL;
}
if (msg->len > info->desc->max_msg_size) {
@@ -1365,6 +1365,8 @@ static int ti_sci_cmd_clk_get_parent(const struct ti_sci_handle *handle,
if (ret)
return ret;
+ resp = (struct ti_sci_msg_resp_get_clock_parent *)xfer->tx_message.buf;
+
*parent_id = resp->parent_id;
return ret;
@@ -3083,7 +3085,10 @@ devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
dev_err(dev, "%s resource type ids not available\n", of_prop);
return ERR_PTR(sets);
}
- temp = malloc(sets);
+ temp = devm_kmalloc(dev, sets, GFP_KERNEL);
+ if (!temp)
+ return ERR_PTR(-ENOMEM);
+
sets /= sizeof(u32);
res->sets = sets;
@@ -3123,6 +3128,7 @@ devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
return ERR_PTR(-ENOMEM);
}
+ devm_kfree(dev, temp);
if (valid_set)
return res;
diff --git a/drivers/fpga/versalpl.c b/drivers/fpga/versalpl.c
index 624493ad838..630d1ecfea3 100644
--- a/drivers/fpga/versalpl.c
+++ b/drivers/fpga/versalpl.c
@@ -40,13 +40,12 @@ static int versal_load(xilinx_desc *desc, const void *buf, size_t bsize,
buf_lo = lower_32_bits(bin_buf);
buf_hi = upper_32_bits(bin_buf);
-
if (desc->family == xilinx_versal2) {
ret = xilinx_pm_request(VERSAL_PM_LOAD_PDI, VERSAL_PM_PDI_TYPE, buf_hi,
- buf_lo, 0, ret_payload);
+ buf_lo, 0, 0, 0, ret_payload);
} else {
ret = xilinx_pm_request(VERSAL_PM_LOAD_PDI, VERSAL_PM_PDI_TYPE, buf_lo,
- buf_hi, 0, ret_payload);
+ buf_hi, 0, 0, 0, ret_payload);
}
if (ret)
diff --git a/drivers/fpga/zynqmppl.c b/drivers/fpga/zynqmppl.c
index 1199b249e36..048d0d2e7a1 100644
--- a/drivers/fpga/zynqmppl.c
+++ b/drivers/fpga/zynqmppl.c
@@ -291,7 +291,7 @@ static int zynqmp_load(xilinx_desc *desc, const void *buf, size_t bsize,
buf_hi = upper_32_bits(bin_buf);
ret = xilinx_pm_request(PM_FPGA_LOAD, buf_lo, buf_hi,
- bsize_req, bstype, ret_payload);
+ bsize_req, bstype, 0, 0, ret_payload);
if (ret)
printf("PL FPGA LOAD failed with err: 0x%08x\n", ret);
@@ -335,11 +335,11 @@ static int zynqmp_loads(xilinx_desc *desc, const void *buf, size_t bsize,
ret = xilinx_pm_request(PM_FPGA_LOAD, buf_lo,
buf_hi,
(u32)(uintptr_t)fpga_sec_info->userkey_addr,
- flag, ret_payload);
+ flag, 0, 0, ret_payload);
else
ret = xilinx_pm_request(PM_FPGA_LOAD, buf_lo,
buf_hi, (u32)bsize,
- flag, ret_payload);
+ flag, 0, 0, ret_payload);
if (ret)
puts("PL FPGA LOAD fail\n");
@@ -356,7 +356,7 @@ static int zynqmp_pcap_info(xilinx_desc *desc)
u32 ret_payload[PAYLOAD_ARG_CNT];
ret = xilinx_pm_request(PM_FPGA_GET_STATUS, 0, 0, 0,
- 0, ret_payload);
+ 0, 0, 0, ret_payload);
if (!ret)
printf("PCAP status\t0x%x\n", ret_payload[1]);
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 58e464106a3..b5729a39774 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -340,6 +340,7 @@ config NPCM_SGPIO
config OMAP_GPIO
bool "TI OMAP GPIO driver"
depends on ARCH_OMAP2PLUS
+ select TI_SYSC if OF_CONTROL
default y
help
Support GPIO controllers on the TI OMAP3/4/5 and related (such as
@@ -695,12 +696,6 @@ config SLG7XL45106_I2C_GPO
8-bit gpo expander, all gpo lines are controlled by writing
value into data register.
-config FTGPIO010
- bool "Faraday Technology FTGPIO010 driver"
- depends on DM_GPIO
- help
- Support for GPIOs on Faraday Technology's FTGPIO010 controller.
-
config ADP5585_GPIO
bool "ADP5585 GPIO driver"
depends on DM_GPIO && DM_I2C
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 83e10c79b91..73c94329e36 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -77,7 +77,6 @@ obj-$(CONFIG_SL28CPLD_GPIO) += sl28cpld-gpio.o
obj-$(CONFIG_ADP5588_GPIO) += adp5588_gpio.o
obj-$(CONFIG_ZYNQMP_GPIO_MODEPIN) += zynqmp_gpio_modepin.o
obj-$(CONFIG_SLG7XL45106_I2C_GPO) += gpio_slg7xl45106.o
-obj-$(CONFIG_FTGPIO010) += ftgpio010.o
obj-$(CONFIG_$(PHASE_)ADP5585_GPIO) += adp5585_gpio.o
obj-$(CONFIG_RZG2L_GPIO) += rzg2l-gpio.o
obj-$(CONFIG_MPFS_GPIO) += mpfs_gpio.o
diff --git a/drivers/gpio/ftgpio010.c b/drivers/gpio/ftgpio010.c
deleted file mode 100644
index 4cb550a540c..00000000000
--- a/drivers/gpio/ftgpio010.c
+++ /dev/null
@@ -1,110 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Faraday Technology's FTGPIO010 controller.
- */
-
-#include <dm.h>
-#include <asm/io.h>
-#include <asm/gpio.h>
-
-struct ftgpio010_regs {
- u32 out;
- u32 in;
- u32 direction; // 1 - output
- u32 reserved;
- u32 set;
- u32 clear;
-};
-
-struct ftgpio010_plat {
- struct ftgpio010_regs __iomem *regs;
-};
-
-static int ftgpio010_direction_input(struct udevice *dev, unsigned int pin)
-{
- struct ftgpio010_plat *plat = dev_get_plat(dev);
- struct ftgpio010_regs *const regs = plat->regs;
-
- clrbits_le32(&regs->direction, 1 << pin);
- return 0;
-}
-
-static int ftgpio010_direction_output(struct udevice *dev, unsigned int pin,
- int val)
-{
- struct ftgpio010_plat *plat = dev_get_plat(dev);
- struct ftgpio010_regs *const regs = plat->regs;
-
- /* change the data first, then the direction. to avoid glitch */
- out_le32(val ? &regs->set : &regs->clear, 1 << pin);
- setbits_le32(&regs->direction, 1 << pin);
-
- return 0;
-}
-
-static int ftgpio010_get_value(struct udevice *dev, unsigned int pin)
-{
- struct ftgpio010_plat *plat = dev_get_plat(dev);
- struct ftgpio010_regs *const regs = plat->regs;
-
- return in_le32(&regs->in) >> pin & 1;
-}
-
-static int ftgpio010_set_value(struct udevice *dev, unsigned int pin, int val)
-{
- struct ftgpio010_plat *plat = dev_get_plat(dev);
- struct ftgpio010_regs *const regs = plat->regs;
-
- out_le32(val ? &regs->set : &regs->clear, 1 << pin);
- return 0;
-}
-
-static int ftgpio010_get_function(struct udevice *dev, unsigned int pin)
-{
- struct ftgpio010_plat *plat = dev_get_plat(dev);
- struct ftgpio010_regs *const regs = plat->regs;
-
- if (in_le32(&regs->direction) >> pin & 1)
- return GPIOF_OUTPUT;
- return GPIOF_INPUT;
-}
-
-static int ftgpio010_probe(struct udevice *dev)
-{
- struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
-
- uc_priv->gpio_count = ofnode_read_u32_default(dev_ofnode(dev),
- "nr-gpios", 32);
- return 0;
-}
-
-static int ftgpio010_of_to_plat(struct udevice *dev)
-{
- struct ftgpio010_plat *plat = dev_get_plat(dev);
-
- plat->regs = dev_read_addr_ptr(dev);
- return 0;
-}
-
-static const struct dm_gpio_ops ftgpio010_ops = {
- .direction_input = ftgpio010_direction_input,
- .direction_output = ftgpio010_direction_output,
- .get_value = ftgpio010_get_value,
- .set_value = ftgpio010_set_value,
- .get_function = ftgpio010_get_function,
-};
-
-static const struct udevice_id ftgpio010_ids[] = {
- { .compatible = "faraday,ftgpio010" },
- { }
-};
-
-U_BOOT_DRIVER(ftgpio010) = {
- .name = "ftgpio010",
- .id = UCLASS_GPIO,
- .of_match = ftgpio010_ids,
- .ops = &ftgpio010_ops,
- .of_to_plat = ftgpio010_of_to_plat,
- .plat_auto = sizeof(struct ftgpio010_plat),
- .probe = ftgpio010_probe,
-};
diff --git a/drivers/gpio/gpio-aspeed-g7.c b/drivers/gpio/gpio-aspeed-g7.c
index 4c6ab86203c..4607468ca05 100644
--- a/drivers/gpio/gpio-aspeed-g7.c
+++ b/drivers/gpio/gpio-aspeed-g7.c
@@ -141,7 +141,7 @@ static const struct udevice_id aspeed_gpio_ids[] = {
{ }
};
-U_BOOT_DRIVER(gpio_aspeed) = {
+U_BOOT_DRIVER(gpio_aspeed_g7) = {
.name = "gpio-aspeed",
.id = UCLASS_GPIO,
.of_match = aspeed_gpio_ids,
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index d1a39938809..c1ad20177f7 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -18,16 +18,13 @@
#define GPIO_IOINTSEL 0x00 /* General IO/Interrupt Switching Register */
#define GPIO_INOUTSEL 0x04 /* General Input/Output Switching Register */
#define GPIO_OUTDT 0x08 /* General Output Register */
-#define GPIO_INDT 0x0c /* General Input Register */
-#define GPIO_INTDT 0x10 /* Interrupt Display Register */
-#define GPIO_INTCLR 0x14 /* Interrupt Clear Register */
-#define GPIO_INTMSK 0x18 /* Interrupt Mask Register */
-#define GPIO_MSKCLR 0x1c /* Interrupt Mask Clear Register */
-#define GPIO_POSNEG 0x20 /* Positive/Negative Logic Select Register */
-#define GPIO_EDGLEVEL 0x24 /* Edge/level Select Register */
-#define GPIO_FILONOFF 0x28 /* Chattering Prevention On/Off Register */
-#define GPIO_BOTHEDGE 0x4c /* One Edge/Both Edge Select Register */
-#define GPIO_INEN 0x50 /* General Input Enable Register */
+#define GPIO_INDT_G2 0x0c /* General Input Register */
+#define GPIO_POSNEG_G2 0x20 /* Positive/Negative Logic Select Register */
+#define GPIO_INEN_G4 0x50 /* General Input Enable Register */
+
+#define GPIO_INDT_G5 0x1c /* General Input Register */
+#define GPIO_POSNEG_G5 0x90 /* Positive/Negative Logic Select Register */
+#define GPIO_INEN_G5 0x18 /* General Input Enable Register */
#define RCAR_MAX_GPIO_PER_BANK 32
@@ -35,15 +32,22 @@
DECLARE_GLOBAL_DATA_PTR;
+struct rcar_gpio_data {
+ u32 quirks;
+ u32 indt_offset;
+ u32 posneg_offset;
+ u32 inen_offset;
+};
+
struct rcar_gpio_priv {
- void __iomem *regs;
- u32 quirks;
- int pfc_offset;
+ void __iomem *regs;
+ const struct rcar_gpio_data *data;
};
static int rcar_gpio_get_value(struct udevice *dev, unsigned offset)
{
struct rcar_gpio_priv *priv = dev_get_priv(dev);
+ const struct rcar_gpio_data *data = priv->data;
const u32 bit = BIT(offset);
/*
@@ -53,7 +57,7 @@ static int rcar_gpio_get_value(struct udevice *dev, unsigned offset)
if (readl(priv->regs + GPIO_INOUTSEL) & bit)
return !!(readl(priv->regs + GPIO_OUTDT) & bit);
else
- return !!(readl(priv->regs + GPIO_INDT) & bit);
+ return !!(readl(priv->regs + data->indt_offset) & bit);
}
static int rcar_gpio_set_value(struct udevice *dev, unsigned offset,
@@ -73,6 +77,7 @@ static void rcar_gpio_set_direction(struct udevice *dev, unsigned offset,
bool output)
{
struct rcar_gpio_priv *priv = dev_get_priv(dev);
+ const struct rcar_gpio_data *data = priv->data;
void __iomem *regs = priv->regs;
/*
@@ -82,14 +87,14 @@ static void rcar_gpio_set_direction(struct udevice *dev, unsigned offset,
*/
/* Configure postive logic in POSNEG */
- clrbits_le32(regs + GPIO_POSNEG, BIT(offset));
+ clrbits_le32(regs + data->posneg_offset, BIT(offset));
/* Select "Input Enable/Disable" in INEN */
- if (priv->quirks & RCAR_GPIO_HAS_INEN) {
+ if (data->quirks & RCAR_GPIO_HAS_INEN) {
if (output)
- clrbits_le32(regs + GPIO_INEN, BIT(offset));
+ clrbits_le32(regs + data->inen_offset, BIT(offset));
else
- setbits_le32(regs + GPIO_INEN, BIT(offset));
+ setbits_le32(regs + data->inen_offset, BIT(offset));
}
/* Select "General Input/Output Mode" in IOINTSEL */
@@ -149,12 +154,11 @@ static int rcar_gpio_probe(struct udevice *dev)
int ret;
priv->regs = dev_read_addr_ptr(dev);
- priv->quirks = dev_get_driver_data(dev);
+ priv->data = (const struct rcar_gpio_data *)dev_get_driver_data(dev);
uc_priv->bank_name = dev->name;
ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, node, "gpio-ranges",
NULL, 3, 0, &args);
- priv->pfc_offset = ret == 0 ? args.args[1] : -1;
uc_priv->gpio_count = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK;
ret = clk_get_by_index(dev, 0, &clk);
@@ -172,17 +176,37 @@ static int rcar_gpio_probe(struct udevice *dev)
return 0;
}
+static const struct rcar_gpio_data rcar_gpio_gen2_data = {
+ .indt_offset = GPIO_INDT_G2,
+ .posneg_offset = GPIO_POSNEG_G2,
+};
+
+static const struct rcar_gpio_data rcar_gpio_gen3_data = {
+ .quirks = RCAR_GPIO_HAS_INEN,
+ .indt_offset = GPIO_INDT_G2,
+ .posneg_offset = GPIO_POSNEG_G2,
+ .inen_offset = GPIO_INEN_G4,
+};
+
+static const struct rcar_gpio_data rcar_gpio_gen5_data = {
+ .quirks = RCAR_GPIO_HAS_INEN,
+ .indt_offset = GPIO_INDT_G5,
+ .posneg_offset = GPIO_POSNEG_G5,
+ .inen_offset = GPIO_INEN_G5,
+};
+
static const struct udevice_id rcar_gpio_ids[] = {
- { .compatible = "renesas,gpio-r8a7795" },
- { .compatible = "renesas,gpio-r8a7796" },
- { .compatible = "renesas,gpio-r8a77965" },
- { .compatible = "renesas,gpio-r8a77970" },
- { .compatible = "renesas,gpio-r8a77990" },
- { .compatible = "renesas,gpio-r8a77995" },
- { .compatible = "renesas,gpio-r8a779a0", .data = RCAR_GPIO_HAS_INEN },
- { .compatible = "renesas,rcar-gen2-gpio" },
- { .compatible = "renesas,rcar-gen3-gpio" },
- { .compatible = "renesas,rcar-gen4-gpio", .data = RCAR_GPIO_HAS_INEN },
+ { .compatible = "renesas,gpio-r8a7795", .data = (ulong)&rcar_gpio_gen2_data },
+ { .compatible = "renesas,gpio-r8a7796", .data = (ulong)&rcar_gpio_gen2_data },
+ { .compatible = "renesas,gpio-r8a77965", .data = (ulong)&rcar_gpio_gen2_data },
+ { .compatible = "renesas,gpio-r8a77970", .data = (ulong)&rcar_gpio_gen2_data },
+ { .compatible = "renesas,gpio-r8a77990", .data = (ulong)&rcar_gpio_gen2_data },
+ { .compatible = "renesas,gpio-r8a77995", .data = (ulong)&rcar_gpio_gen2_data },
+ { .compatible = "renesas,gpio-r8a779a0", .data = (ulong)&rcar_gpio_gen3_data },
+ { .compatible = "renesas,rcar-gen2-gpio", .data = (ulong)&rcar_gpio_gen2_data },
+ { .compatible = "renesas,rcar-gen3-gpio", .data = (ulong)&rcar_gpio_gen2_data },
+ { .compatible = "renesas,rcar-gen4-gpio", .data = (ulong)&rcar_gpio_gen3_data },
+ { .compatible = "renesas,rcar-gen5-gpio", .data = (ulong)&rcar_gpio_gen5_data },
{ /* sentinel */ }
};
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 3d9f8b32b8d..7559b8dc7e2 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -378,7 +378,7 @@ U_BOOT_DRIVER(gpio_hog) = {
#else
int gpio_hog_lookup_name(const char *name, struct gpio_desc **desc)
{
- return 0;
+ return -ENODEV;
}
#endif
diff --git a/drivers/gpio/intel_gpio.c b/drivers/gpio/intel_gpio.c
index 0ab6e8a90bc..ac2fb8bc2cc 100644
--- a/drivers/gpio/intel_gpio.c
+++ b/drivers/gpio/intel_gpio.c
@@ -116,26 +116,26 @@ static int intel_gpio_set_flags(struct udevice *dev, unsigned int offset,
{
struct udevice *pinctrl = dev_get_parent(dev);
u32 bic0 = 0, bic1 = 0;
- u32 or0, or1;
+ u32 or0 = 0, or1 = 0;
uint config_offset;
config_offset = intel_pinctrl_get_config_reg_offset(pinctrl, offset);
if (flags & GPIOD_IS_OUT) {
- bic0 |= PAD_CFG0_MODE_MASK | PAD_CFG0_RX_STATE |
+ bic0 = PAD_CFG0_MODE_MASK | PAD_CFG0_RX_STATE |
PAD_CFG0_TX_DISABLE;
- or0 |= PAD_CFG0_MODE_GPIO | PAD_CFG0_RX_DISABLE;
+ or0 = PAD_CFG0_MODE_GPIO | PAD_CFG0_RX_DISABLE;
} else if (flags & GPIOD_IS_IN) {
- bic0 |= PAD_CFG0_MODE_MASK | PAD_CFG0_TX_STATE |
+ bic0 = PAD_CFG0_MODE_MASK | PAD_CFG0_TX_STATE |
PAD_CFG0_RX_DISABLE;
- or0 |= PAD_CFG0_MODE_GPIO | PAD_CFG0_TX_DISABLE;
+ or0 = PAD_CFG0_MODE_GPIO | PAD_CFG0_TX_DISABLE;
}
if (flags & GPIOD_PULL_UP) {
- bic1 |= PAD_CFG1_PULL_MASK;
- or1 |= PAD_CFG1_PULL_UP_20K;
+ bic1 = PAD_CFG1_PULL_MASK;
+ or1 = PAD_CFG1_PULL_UP_20K;
} else if (flags & GPIOD_PULL_DOWN) {
- bic1 |= PAD_CFG1_PULL_MASK;
- or1 |= PAD_CFG1_PULL_DN_20K;
+ bic1 = PAD_CFG1_PULL_MASK;
+ or1 = PAD_CFG1_PULL_DN_20K;
}
pcr_clrsetbits32(pinctrl, PAD_CFG0_OFFSET(config_offset), bic0, or0);
diff --git a/drivers/gpio/qcom_spmi_gpio.c b/drivers/gpio/qcom_spmi_gpio.c
index 22c8072534e..1a7c7c48dfc 100644
--- a/drivers/gpio/qcom_spmi_gpio.c
+++ b/drivers/gpio/qcom_spmi_gpio.c
@@ -743,6 +743,10 @@ static int qcom_spmi_pmic_gpio_probe(struct udevice *dev)
}
static const struct udevice_id qcom_spmi_pmic_gpio_ids[] = {
+ { .compatible = "qcom,pm6150l-gpio" },
+ { .compatible = "qcom,pm6350-gpio" },
+ { .compatible = "qcom,pm660l-gpio" },
+ { .compatible = "qcom,pm7325-gpio" },
{ .compatible = "qcom,pm8550-gpio" },
{ .compatible = "qcom,pm8550b-gpio" },
{ .compatible = "qcom,pm8550ve-gpio" },
diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c
index 3d1e18854f2..c61419ef980 100644
--- a/drivers/gpio/tegra_gpio.c
+++ b/drivers/gpio/tegra_gpio.c
@@ -182,21 +182,6 @@ static int tegra_gpio_get_value(struct udevice *dev, unsigned offset)
return (val >> GPIO_BIT(gpio)) & 1;
}
-/* write GPIO OUT value to pin 'gpio' */
-static int tegra_gpio_set_value(struct udevice *dev, unsigned offset, int value)
-{
- struct tegra_port_info *state = dev_get_priv(dev);
- int gpio = state->base_gpio + offset;
-
- debug("gpio_set_value: pin = %d (port %d:bit %d), value = %d\n",
- gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio), value);
-
- /* Configure GPIO output value. */
- set_level(gpio, value);
-
- return 0;
-}
-
void gpio_config_table(const struct tegra_gpio_config *config, int len)
{
int i;
@@ -258,11 +243,30 @@ static int tegra_gpio_rfree(struct udevice *dev, unsigned int offset)
return 0;
}
+static int tegra_gpio_set_flags(struct udevice *dev, unsigned int offset, ulong flags)
+{
+ struct tegra_port_info *state = dev_get_priv(dev);
+ int gpio = state->base_gpio + offset;
+
+ debug("gpio_set_flags: pin = %d (port %d:bit %d), flag = %lx\n",
+ gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio), flags);
+
+ if (flags & GPIOD_IS_AF) {
+ return tegra_gpio_rfree(dev, offset);
+ } else if (flags & GPIOD_IS_IN) {
+ return tegra_gpio_direction_input(dev, offset);
+ } else if (flags & GPIOD_IS_OUT) {
+ bool value = flags & GPIOD_IS_OUT_ACTIVE;
+
+ return tegra_gpio_direction_output(dev, offset, value);
+ }
+
+ return 0;
+}
+
static const struct dm_gpio_ops gpio_tegra_ops = {
- .direction_input = tegra_gpio_direction_input,
- .direction_output = tegra_gpio_direction_output,
+ .set_flags = tegra_gpio_set_flags,
.get_value = tegra_gpio_get_value,
- .set_value = tegra_gpio_set_value,
.get_function = tegra_gpio_get_function,
.xlate = tegra_gpio_xlate,
.rfree = tegra_gpio_rfree,
diff --git a/drivers/gpio/zynqmp_gpio_modepin.c b/drivers/gpio/zynqmp_gpio_modepin.c
index 8aaffaf37b3..4c5de9ba69b 100644
--- a/drivers/gpio/zynqmp_gpio_modepin.c
+++ b/drivers/gpio/zynqmp_gpio_modepin.c
@@ -23,14 +23,14 @@
static int get_gpio_modepin(u32 *ret_payload)
{
return xilinx_pm_request(PM_MMIO_READ, ZYNQMP_CRL_APB_BOOT_PIN_CTRL,
- 0, 0, 0, ret_payload);
+ 0, 0, 0, 0, 0, ret_payload);
}
static int set_gpio_modepin(int val)
{
return xilinx_pm_request(PM_MMIO_WRITE, ZYNQMP_CRL_APB_BOOT_PIN_CTRL,
ZYNQMP_CRL_APB_BOOTPIN_CTRL_MASK,
- val, 0, NULL);
+ val, 0, 0, 0, NULL);
}
static int modepin_gpio_direction_input(struct udevice *dev,
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 108b24b3dd2..55465dc1d46 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -308,6 +308,13 @@ config SYS_I2C_MTK
If you want to use MediaTek I2C interface, say Y here.
If unsure, say N.
+config SYS_I2C_MT7621
+ bool "Mediatek MT7621 I2C driver"
+ help
+ This selects the Mediatek MT7621 I2C driver.
+ If you want to use the MediaTek MT7621 I2C controller, say Y here.
+ If unsure, say N.
+
config SYS_I2C_MICROCHIP
bool "Microchip I2C driver"
help
@@ -661,7 +668,7 @@ config SYS_I2C_QUP
config SYS_I2C_GENI
bool "Qualcomm Generic Interface (GENI) I2C controller"
- depends on ARCH_SNAPDRAGON
+ depends on ARCH_SNAPDRAGON && QCOM_GENI
help
Support for the Qualcomm Generic Interface (GENI) I2C interface.
The Generic Interface (GENI) is a firmware based Qualcomm Universal
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 42326db85f6..5fe30d0df4f 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_SYS_I2C_MV) += mv_i2c.o
obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o
obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o
obj-$(CONFIG_SYS_I2C_MTK) += mtk_i2c.o
+obj-$(CONFIG_SYS_I2C_MT7621) += mt7621_i2c.o
obj-$(CONFIG_SYS_I2C_NEXELL) += nx_i2c.o
obj-$(CONFIG_SYS_I2C_NPCM) += npcm_i2c.o
obj-$(CONFIG_SYS_I2C_OCORES) += ocores_i2c.o
diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c
index a54976e7889..8ad716f410e 100644
--- a/drivers/i2c/designware_i2c.c
+++ b/drivers/i2c/designware_i2c.c
@@ -764,7 +764,7 @@ int designware_i2c_of_to_plat(struct udevice *bus)
ret = reset_get_bulk(bus, &priv->resets);
if (ret) {
- if (ret != -ENOTSUPP)
+ if (ret != -ENOTSUPP && ret != -ENOENT)
dev_warn(bus, "Can't get reset: %d\n", ret);
} else {
reset_deassert_bulk(&priv->resets);
diff --git a/drivers/i2c/geni_i2c.c b/drivers/i2c/geni_i2c.c
index eabf5c76c21..d29e00fdf41 100644
--- a/drivers/i2c/geni_i2c.c
+++ b/drivers/i2c/geni_i2c.c
@@ -22,6 +22,7 @@
#include <reset.h>
#include <time.h>
#include <soc/qcom/geni-se.h>
+#include <soc/qcom/qup-fw-load.h>
#define SE_I2C_TX_TRANS_LEN 0x26c
#define SE_I2C_RX_TRANS_LEN 0x270
@@ -331,15 +332,13 @@ static int geni_i2c_disable_clocks(struct udevice *dev, struct geni_i2c_priv *ge
if (geni->is_master_hub) {
ret = clk_disable(&geni->core);
if (ret) {
- dev_err(dev, "clk_enable core failed %d\n", ret);
- return ret;
+ dev_err(dev, "clk_disable core failed %d\n", ret);
}
}
ret = clk_disable(&geni->se);
if (ret) {
- dev_err(dev, "clk_enable se failed %d\n", ret);
- return ret;
+ dev_err(dev, "clk_disable se failed %d\n", ret);
}
return 0;
@@ -501,6 +500,13 @@ static int geni_i2c_probe(struct udevice *dev)
proto &= FW_REV_PROTOCOL_MSK;
proto >>= FW_REV_PROTOCOL_SHFT;
+ if (proto == GENI_SE_INVALID_PROTO) {
+ qcom_geni_load_firmware(geni->base, dev);
+ proto = readl(geni->base + GENI_FW_REVISION_RO);
+ proto &= FW_REV_PROTOCOL_MSK;
+ proto >>= FW_REV_PROTOCOL_SHFT;
+ }
+
if (proto != GENI_SE_I2C) {
dev_err(dev, "Invalid proto %d\n", proto);
geni_i2c_disable_clocks(dev, geni);
diff --git a/drivers/i2c/mt7621_i2c.c b/drivers/i2c/mt7621_i2c.c
new file mode 100644
index 00000000000..e162df49f67
--- /dev/null
+++ b/drivers/i2c/mt7621_i2c.c
@@ -0,0 +1,374 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * U-Boot driver for the MediaTek MT7621 I2C controller.
+ *
+ * Derived from the Linux kernel driver:
+ * drivers/i2c/busses/i2c-mt7621.c
+ *
+ * Copyright (C) 2013 Steven Liu <steven_liu@mediatek.com>
+ * Copyright (C) 2014 Sittisak <sittisaks@hotmail.com>
+ * Copyright (C) 2016 Michael Lee <igvtee@gmail.com>
+ * Copyright (C) 2018 Jan Breuer <jan.breuer@jaybee.cz>
+ * Copyright (C) 2025 Justin Swartz <justin.swartz@risingedge.co.za>
+ */
+
+#include <asm/io.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/printk.h>
+#include <dm.h>
+#include <clk.h>
+#include <i2c.h>
+#include <log.h>
+#include <reset.h>
+#include <time.h>
+
+#define REG_SM0CFG2 0x28
+#define REG_SM0CTL0 0x40
+#define REG_SM0CTL1 0x44
+#define REG_SM0D0 0x50
+#define REG_SM0D1 0x54
+
+#define SM0CFG2_MODE_MANUAL 0
+
+#define SM0CTL0_ODRAIN BIT(31)
+#define SM0CTL0_CLK_DIV_MASK (0x7ff << 16)
+#define SM0CTL0_CLK_DIV_MAX 0x7ff
+#define SM0CTL0_EN BIT(1)
+#define SM0CTL0_SCL_STRETCH BIT(0)
+
+#define SM0CTL1_TRI BIT(0)
+#define SM0CTL1_TRI_IDLE 0
+#define SM0CTL1_START (1 << 4)
+#define SM0CTL1_WRITE (2 << 4)
+#define SM0CTL1_STOP (3 << 4)
+#define SM0CTL1_READ_LAST (4 << 4)
+#define SM0CTL1_READ (5 << 4)
+#define SM0CTL1_PGLEN(x) ((((x) - 1) << 8) & SM0CTL1_PGLEN_MASK)
+#define SM0CTL1_PGLEN_MASK (0x7 << 8)
+#define SM0CTL1_ACK_MASK (0xff << 16)
+
+#define TIMEOUT_1SEC 1000
+#define I2C_MAX_STD_MODE_FREQ 100000
+
+struct mt7621_i2c_priv {
+ void __iomem *base;
+ uint speed;
+ u32 clk_div;
+ struct clk clk;
+ struct reset_ctl reset_ctl;
+};
+
+static int mt7621_i2c_wait_idle(struct udevice *dev)
+{
+ struct mt7621_i2c_priv *priv = dev_get_priv(dev);
+ ulong start_time = get_timer(0);
+ u32 value;
+
+ while (get_timer(start_time) < TIMEOUT_1SEC) {
+ value = readl(priv->base + REG_SM0CTL1);
+ if ((value & SM0CTL1_TRI) == SM0CTL1_TRI_IDLE)
+ return 0;
+
+ udelay(10);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int mt7621_i2c_reset(struct udevice *dev)
+{
+ struct mt7621_i2c_priv *priv = dev_get_priv(dev);
+ u32 value;
+
+ reset_assert(&priv->reset_ctl);
+ udelay(100);
+ reset_deassert(&priv->reset_ctl);
+
+ value = readl(priv->base + REG_SM0CTL0);
+ value &= ~SM0CTL0_CLK_DIV_MASK;
+ value |= (priv->clk_div << 16) & SM0CTL0_CLK_DIV_MASK;
+ value |= SM0CTL0_EN | SM0CTL0_SCL_STRETCH;
+ writel(value, priv->base + REG_SM0CTL0);
+
+ writel(SM0CFG2_MODE_MANUAL, priv->base + REG_SM0CFG2);
+ return 0;
+}
+
+static int mt7621_i2c_master_start(struct udevice *dev)
+{
+ struct mt7621_i2c_priv *priv = dev_get_priv(dev);
+
+ writel(SM0CTL1_START | SM0CTL1_TRI, priv->base + REG_SM0CTL1);
+ return mt7621_i2c_wait_idle(dev);
+}
+
+static int mt7621_i2c_master_stop(struct udevice *dev)
+{
+ struct mt7621_i2c_priv *priv = dev_get_priv(dev);
+
+ writel(SM0CTL1_STOP | SM0CTL1_TRI, priv->base + REG_SM0CTL1);
+ return mt7621_i2c_wait_idle(dev);
+}
+
+static int mt7621_i2c_master_cmd(struct udevice *dev, u32 cmd, int len)
+{
+ struct mt7621_i2c_priv *priv = dev_get_priv(dev);
+
+ writel(cmd | SM0CTL1_TRI | SM0CTL1_PGLEN(len),
+ priv->base + REG_SM0CTL1);
+
+ return mt7621_i2c_wait_idle(dev);
+}
+
+static int mt7621_i2c_7bit_address(struct udevice *dev, struct i2c_msg *msg)
+{
+ struct mt7621_i2c_priv *priv = dev_get_priv(dev);
+ u32 addr = msg->addr << 1;
+
+ if (msg->flags & I2C_M_RD)
+ addr |= 1;
+
+ writel(addr, priv->base + REG_SM0D0);
+ return mt7621_i2c_master_cmd(dev, SM0CTL1_WRITE, 1);
+}
+
+static int mt7621_i2c_10bit_address(struct udevice *dev, struct i2c_msg *msg)
+{
+ struct mt7621_i2c_priv *priv = dev_get_priv(dev);
+ u16 addr = 0xf0 | ((msg->addr >> 7) & 0x06) | (msg->addr & 0xff) << 8;
+
+ if (msg->flags & I2C_M_RD)
+ addr |= 1;
+
+ writel(addr, priv->base + REG_SM0D0);
+ return mt7621_i2c_master_cmd(dev, SM0CTL1_WRITE, 2);
+}
+
+static int mt7621_i2c_address(struct udevice *dev, struct i2c_msg *msg)
+{
+ int ret;
+
+ if (msg->flags & I2C_M_TEN) {
+ ret = mt7621_i2c_10bit_address(dev, msg);
+ if (ret)
+ return ret;
+ } else {
+ ret = mt7621_i2c_7bit_address(dev, msg);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mt7621_i2c_check_ack(struct udevice *dev, struct i2c_msg *msg,
+ u32 length)
+{
+ struct mt7621_i2c_priv *priv = dev_get_priv(dev);
+ u32 status = readl(priv->base + REG_SM0CTL1);
+ u32 expected = GENMASK(length - 1, 0);
+ u32 mask = (expected << 16) & SM0CTL1_ACK_MASK;
+
+ if (msg->flags & I2C_M_IGNORE_NAK)
+ return 0;
+
+ if ((status & mask) != mask)
+ return -ENXIO;
+
+ return 0;
+}
+
+static int mt7621_i2c_master_read(struct udevice *dev, struct i2c_msg *msg)
+{
+ struct mt7621_i2c_priv *priv = dev_get_priv(dev);
+ int offset, length, last, ret;
+ u32 cmd;
+ u32 data[2];
+
+ for (offset = 0; offset < msg->len; offset += 8) {
+ if (msg->len - offset >= 8)
+ length = 8;
+ else
+ length = msg->len - offset;
+
+ last = msg->len - offset <= 8;
+ cmd = last ? SM0CTL1_READ_LAST : SM0CTL1_READ;
+ ret = mt7621_i2c_master_cmd(dev, cmd, length);
+ if (ret)
+ return ret;
+
+ data[0] = readl(priv->base + REG_SM0D0);
+ data[1] = readl(priv->base + REG_SM0D1);
+ memcpy(&msg->buf[offset], data, length);
+ }
+
+ return 0;
+}
+
+static int mt7621_i2c_master_write(struct udevice *dev, struct i2c_msg *msg)
+{
+ struct mt7621_i2c_priv *priv = dev_get_priv(dev);
+ int offset, length, ret;
+ u32 data[2];
+
+ for (offset = 0; offset < msg->len; offset += 8) {
+ if (msg->len - offset >= 8)
+ length = 8;
+ else
+ length = msg->len - offset;
+
+ memcpy(data, &msg->buf[offset], length);
+ writel(data[0], priv->base + REG_SM0D0);
+ writel(data[1], priv->base + REG_SM0D1);
+
+ ret = mt7621_i2c_master_cmd(dev, SM0CTL1_WRITE, length);
+ if (ret)
+ return ret;
+
+ ret = mt7621_i2c_check_ack(dev, msg, length);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mt7621_i2c_xfer(struct udevice *dev, struct i2c_msg *msgs, int count)
+{
+ struct i2c_msg *msg;
+ int index, ret;
+
+ for (index = 0; index < count; index++) {
+ msg = &msgs[index];
+
+ ret = mt7621_i2c_wait_idle(dev);
+ if (ret)
+ goto reset;
+
+ ret = mt7621_i2c_master_start(dev);
+ if (ret)
+ goto reset;
+
+ ret = mt7621_i2c_address(dev, msg);
+ if (ret)
+ goto reset;
+
+ ret = mt7621_i2c_check_ack(dev, msg, 1);
+ if (ret)
+ goto stop;
+
+ if (msg->flags & I2C_M_RD) {
+ ret = mt7621_i2c_master_read(dev, msg);
+ if (ret)
+ goto reset;
+ } else {
+ ret = mt7621_i2c_master_write(dev, msg);
+ if (ret)
+ goto reset;
+ }
+ }
+
+ ret = mt7621_i2c_wait_idle(dev);
+ if (ret)
+ goto reset;
+
+ ret = mt7621_i2c_master_stop(dev);
+ if (ret)
+ goto reset;
+
+ return 0;
+
+stop:
+ ret = mt7621_i2c_master_stop(dev);
+ if (ret)
+ goto reset;
+ return -ENXIO;
+
+reset:
+ mt7621_i2c_reset(dev);
+ return ret;
+}
+
+static int mt7621_i2c_set_speed(struct udevice *dev, uint speed)
+{
+ struct mt7621_i2c_priv *priv = dev_get_priv(dev);
+ ulong clk_rate = clk_get_rate(&priv->clk);
+
+ priv->speed = speed;
+ priv->clk_div = clk_rate / priv->speed - 1;
+
+ if (priv->clk_div < 99)
+ priv->clk_div = 99;
+
+ if (priv->clk_div > SM0CTL0_CLK_DIV_MAX)
+ priv->clk_div = SM0CTL0_CLK_DIV_MAX;
+
+ return 0;
+}
+
+static const struct dm_i2c_ops mt7621_i2c_ops = {
+ .xfer = mt7621_i2c_xfer,
+ .set_bus_speed = mt7621_i2c_set_speed,
+ .deblock = mt7621_i2c_reset,
+};
+
+static int mt7621_i2c_of_to_plat(struct udevice *dev)
+{
+ struct mt7621_i2c_priv *priv = dev_get_priv(dev);
+
+ priv->base = dev_remap_addr(dev);
+ return 0;
+}
+
+int mt7621_i2c_probe(struct udevice *dev)
+{
+ struct mt7621_i2c_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->base = dev_remap_addr(dev);
+ if (!priv->base) {
+ dev_err(dev, "failed to get base address\n");
+ return -EINVAL;
+ }
+
+ ret = clk_get_by_name(dev, "sys_clock", &priv->clk);
+ if (ret) {
+ dev_err(dev, "failed to get clock source\n");
+ return ret;
+ }
+
+ ret = reset_get_by_name(dev, "i2c_reset", &priv->reset_ctl);
+ if (ret) {
+ dev_err(dev, "failed to get reset control\n");
+ return ret;
+ }
+
+ ret = clk_enable(&priv->clk);
+ if (ret) {
+ dev_err(dev, "failed to enable clock\n");
+ return ret;
+ }
+
+ mt7621_i2c_set_speed(dev, I2C_MAX_STD_MODE_FREQ);
+ mt7621_i2c_reset(dev);
+
+ return 0;
+}
+
+static const struct udevice_id mt7621_i2c_ids[] = {
+ { .compatible = "mediatek,mt7621-i2c" },
+ { }
+};
+
+U_BOOT_DRIVER(mt7621_i2c) = {
+ .name = "mt7621_i2c",
+ .id = UCLASS_I2C,
+ .of_match = mt7621_i2c_ids,
+ .of_to_plat = mt7621_i2c_of_to_plat,
+ .probe = mt7621_i2c_probe,
+ .priv_auto = sizeof(struct mt7621_i2c_priv),
+ .ops = &mt7621_i2c_ops,
+};
diff --git a/drivers/i2c/muxes/i2c-mux-uclass.c b/drivers/i2c/muxes/i2c-mux-uclass.c
index 012881de05b..7f4eb914af2 100644
--- a/drivers/i2c/muxes/i2c-mux-uclass.c
+++ b/drivers/i2c/muxes/i2c-mux-uclass.c
@@ -130,7 +130,7 @@ static int i2c_mux_post_probe(struct udevice *mux)
return 0;
}
-int i2c_mux_select(struct udevice *dev)
+static int i2c_mux_select(struct udevice *dev)
{
struct i2c_mux_bus *plat = dev_get_parent_plat(dev);
struct udevice *mux = dev->parent;
@@ -142,7 +142,7 @@ int i2c_mux_select(struct udevice *dev)
return ops->select(mux, dev, plat->channel);
}
-int i2c_mux_deselect(struct udevice *dev)
+static int i2c_mux_deselect(struct udevice *dev)
{
struct i2c_mux_bus *plat = dev_get_parent_plat(dev);
struct udevice *mux = dev->parent;
diff --git a/drivers/i2c/rcar_i2c.c b/drivers/i2c/rcar_i2c.c
index 3bd5108fd23..9562119bb5b 100644
--- a/drivers/i2c/rcar_i2c.c
+++ b/drivers/i2c/rcar_i2c.c
@@ -368,6 +368,7 @@ static const struct udevice_id rcar_i2c_ids[] = {
{ .compatible = "renesas,rcar-gen2-i2c", .data = RCAR_I2C_TYPE_GEN2 },
{ .compatible = "renesas,rcar-gen3-i2c", .data = RCAR_I2C_TYPE_GEN3 },
{ .compatible = "renesas,rcar-gen4-i2c", .data = RCAR_I2C_TYPE_GEN3 },
+ { .compatible = "renesas,rcar-gen5-i2c", .data = RCAR_I2C_TYPE_GEN3 },
{ }
};
diff --git a/drivers/iommu/qcom-hyp-smmu.c b/drivers/iommu/qcom-hyp-smmu.c
index 2e51ce4f242..5b37c21f66c 100644
--- a/drivers/iommu/qcom-hyp-smmu.c
+++ b/drivers/iommu/qcom-hyp-smmu.c
@@ -388,8 +388,10 @@ static struct iommu_ops qcom_smmu_ops = {
};
static const struct udevice_id qcom_smmu500_ids[] = {
- { .compatible = "qcom,sdm845-smmu-500" },
+ { .compatible = "qcom,sc7180-smmu-500" },
{ .compatible = "qcom,sc7280-smmu-500" },
+ { .compatible = "qcom,sdm845-smmu-500" },
+ { .compatible = "qcom,sm6350-smmu-500" },
{ .compatible = "qcom,smmu-500", },
{ /* sentinel */ }
};
diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig
index c98cbf92fab..1cd3638cb16 100644
--- a/drivers/led/Kconfig
+++ b/drivers/led/Kconfig
@@ -11,6 +11,7 @@ config LED
config LED_BOOT
bool "Enable LED boot support"
+ depends on LED
help
Enable LED boot support.
@@ -22,6 +23,7 @@ config LED_BOOT
config LED_ACTIVITY
bool "Enable LED activity support"
+ depends on LED
help
Enable LED activity support.
@@ -137,7 +139,8 @@ config SPL_LED_GPIO
See the help of LED_GPIO for details.
config LED_STATUS
- bool "Enable status LED API"
+ bool "Enable legacy status LED API"
+ depends on !LED
help
Allows common u-boot commands to use a board's leds to
provide status for activities like booting and downloading files.
diff --git a/drivers/led/led-uclass.c b/drivers/led/led-uclass.c
index edcdeee1e9a..1efdbe272c3 100644
--- a/drivers/led/led-uclass.c
+++ b/drivers/led/led-uclass.c
@@ -65,6 +65,9 @@ int led_get_by_label(const char *label, struct udevice **devp)
/* Ignore the top-level LED node */
if (uc_plat->label && !strcmp(label, uc_plat->label))
return uclass_get_device_tail(dev, 0, devp);
+
+ if (!strcmp(label, ofnode_get_name(dev_ofnode(dev))))
+ return uclass_get_device_tail(dev, 0, devp);
}
return -ENODEV;
diff --git a/drivers/mailbox/mailbox-uclass.c b/drivers/mailbox/mailbox-uclass.c
index 4bf4987ce0a..fef437a4281 100644
--- a/drivers/mailbox/mailbox-uclass.c
+++ b/drivers/mailbox/mailbox-uclass.c
@@ -132,6 +132,15 @@ int mbox_recv(struct mbox_chan *chan, void *data, ulong timeout_us)
debug("%s(chan=%p, data=%p, timeout_us=%ld)\n", __func__, chan, data,
timeout_us);
+ /*
+ * Some shared memory mailboxes may have empty receive operation,
+ * because the data are polled by upper layers directly from the
+ * shared memory region, and there is no completion interrupt or
+ * bit of any sort.
+ */
+ if (!ops->recv)
+ return 0;
+
start_time = timer_get_us();
/*
* Account for partial us ticks, but if timeout_us is 0, ensure we
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index eaee739c6aa..591d9d9c656 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -14,7 +14,7 @@ config MEMORY
For now this uclass has no methods yet.
config ATMEL_EBI
- bool "Support for Atmel EBI"
+ bool
help
Driver for Atmel EBI controller. This is a dummy
driver. Doesn't provide an access to EBI controller. Select
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 29b84430ff5..dde773ab6b1 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -83,6 +83,15 @@ config GATEWORKS_SC
boards to provide a boot watchdog, power control, temperature monitor,
voltage ADCs, and EEPROM.
+config QCOM_GENI
+ bool "Qualcomm Generic Interface (GENI) driver"
+ depends on MISC
+ select PARTITION_TYPE_GUID
+ help
+ Enable support for Qualcomm GENI and it's peripherals. GENI is responseible
+ for providing a common interface for various peripherals like UART, I2C, SPI,
+ etc.
+
config ROCKCHIP_EFUSE
bool "Rockchip e-fuse support"
depends on MISC
@@ -440,6 +449,7 @@ config STM32MP_FUSE
config K3_FUSE
bool "Enable TI K3 fuse wrapper providing the fuse API"
depends on MISC && CMD_FUSE && CMD_FUSE_WRITEBUFF
+ depends on ARCH_K3
help
If you say Y here, you will get support for the fuse API (OTP)
for TI K3 architecture.
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index dc5eb3af19c..1d950f7a0ab 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_QFW_MMIO) += qfw_mmio.o
obj-$(CONFIG_QFW_SMBIOS) += qfw_smbios.o
obj-$(CONFIG_SANDBOX) += qfw_sandbox.o
endif
+obj-$(CONFIG_QCOM_GENI) += qcom_geni.o
obj-$(CONFIG_$(PHASE_)ROCKCHIP_EFUSE) += rockchip-efuse.o
obj-$(CONFIG_$(PHASE_)ROCKCHIP_OTP) += rockchip-otp.o
obj-$(CONFIG_$(PHASE_)ROCKCHIP_IODOMAIN) += rockchip-io-domain.o
diff --git a/drivers/misc/fs_loader.c b/drivers/misc/fs_loader.c
index 32aff35835b..2928cf75f89 100644
--- a/drivers/misc/fs_loader.c
+++ b/drivers/misc/fs_loader.c
@@ -228,53 +228,6 @@ int request_firmware_into_buf(struct udevice *dev,
return ret;
}
-int request_firmware_into_buf_via_script(void **buf, size_t max_size,
- const char *script_name,
- size_t *retsize)
-{
- char *args[2] = { "run", (char *)script_name };
- int ret, repeatable;
- ulong addr, size;
-
- if (!buf || !script_name || !max_size)
- return -EINVAL;
-
- /* Run the firmware loading script */
- ret = cmd_process(0, 2, args, &repeatable, NULL);
- if (ret) {
- log_err("Firmware loading script '%s' not defined or failed.\n",
- script_name);
- return -EINVAL;
- }
-
- /* Find out where the firmware got loaded and how long it is */
- addr = env_get_hex("fw_addr", 0);
- size = env_get_hex("fw_size", 0);
-
- /* Clear the variables set by the firmware loading script */
- env_set("fw_addr", NULL);
- env_set("fw_size", NULL);
-
- if (!addr || !size) {
- log_err("Firmware address (0x%lx) or size (0x%lx) are invalid.\n",
- addr, size);
- return -EINVAL;
- }
-
- if (size > max_size) {
- log_err("Loaded firmware size 0x%lx exceeded maximum allowed size 0x%zx.\n",
- size, max_size);
- return -E2BIG;
- }
-
- if (retsize)
- *retsize = size;
-
- memcpy(*buf, (void *)addr, size);
-
- return 0;
-}
-
static int fs_loader_of_to_plat(struct udevice *dev)
{
u32 phandlepart[2];
diff --git a/drivers/misc/nuvoton_nct6102d.c b/drivers/misc/nuvoton_nct6102d.c
index a3ca037d25f..c4a8ecaa1b3 100644
--- a/drivers/misc/nuvoton_nct6102d.c
+++ b/drivers/misc/nuvoton_nct6102d.c
@@ -4,8 +4,8 @@
*/
#include <nuvoton_nct6102d.h>
+#include <pnp_def.h>
#include <asm/io.h>
-#include <asm/pnp_def.h>
static void superio_outb(int reg, int val)
{
diff --git a/drivers/misc/qcom_geni.c b/drivers/misc/qcom_geni.c
new file mode 100644
index 00000000000..a62ae6a2478
--- /dev/null
+++ b/drivers/misc/qcom_geni.c
@@ -0,0 +1,580 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2025, Linaro Ltd.
+ */
+
+#define pr_fmt(fmt) "GENI-SE: " fmt
+
+#include <blk.h>
+#include <part.h>
+#include <dm/device.h>
+#include <dm/read.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <elf.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <misc.h>
+#include <linux/printk.h>
+#include <soc/qcom/geni-se.h>
+#include <soc/qcom/qup-fw-load.h>
+#include <dm/device_compat.h>
+
+struct qup_se_rsc {
+ phys_addr_t base;
+ phys_addr_t wrapper_base;
+ struct udevice *dev;
+
+ enum geni_se_xfer_mode mode;
+ enum geni_se_protocol_type protocol;
+};
+
+struct geni_se_plat {
+ bool need_firmware_load;
+};
+
+/**
+ * geni_enable_interrupts() Enable interrupts.
+ * @rsc: Pointer to a structure representing SE-related resources.
+ *
+ * Enable the required interrupts during the firmware load process.
+ *
+ * Return: None.
+ */
+static void geni_enable_interrupts(struct qup_se_rsc *rsc)
+{
+ u32 reg_value;
+
+ /* Enable required interrupts. */
+ writel_relaxed(M_COMMON_GENI_M_IRQ_EN, rsc->base + GENI_M_IRQ_ENABLE);
+
+ reg_value = 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_relaxed(reg_value, rsc->base + GENI_S_IRQ_ENABLE);
+
+ /* DMA mode configuration. */
+ reg_value = DMA_TX_IRQ_EN_SET_RESET_DONE_EN_SET_BMSK |
+ DMA_TX_IRQ_EN_SET_SBE_EN_SET_BMSK |
+ DMA_TX_IRQ_EN_SET_DMA_DONE_EN_SET_BMSK;
+ writel_relaxed(reg_value, rsc->base + DMA_TX_IRQ_EN_SET);
+ reg_value = DMA_RX_IRQ_EN_SET_FLUSH_DONE_EN_SET_BMSK |
+ DMA_RX_IRQ_EN_SET_RESET_DONE_EN_SET_BMSK |
+ DMA_RX_IRQ_EN_SET_SBE_EN_SET_BMSK |
+ DMA_RX_IRQ_EN_SET_DMA_DONE_EN_SET_BMSK;
+ writel_relaxed(reg_value, rsc->base + DMA_RX_IRQ_EN_SET);
+}
+
+/**
+ * geni_flash_fw_revision() - Flash the firmware revision.
+ * @rsc: Pointer to a structure representing SE-related resources.
+ * @hdr: Pointer to the ELF header of the Serial Engine.
+ *
+ * Flash the firmware revision and protocol into the respective register.
+ *
+ * Return: None.
+ */
+static void geni_flash_fw_revision(struct qup_se_rsc *rsc, struct elf_se_hdr *hdr)
+{
+ u32 reg_value;
+
+ /* Flash firmware revision register. */
+ reg_value = (hdr->serial_protocol << FW_REV_PROTOCOL_SHFT) |
+ (hdr->fw_version & 0xFF << FW_REV_VERSION_SHFT);
+ writel_relaxed(reg_value, rsc->base + SE_GENI_FW_REVISION);
+
+ reg_value = (hdr->serial_protocol << FW_REV_PROTOCOL_SHFT) |
+ (hdr->fw_version & 0xFF << FW_REV_VERSION_SHFT);
+
+ writel_relaxed(reg_value, rsc->base + SE_S_FW_REVISION);
+}
+
+/**
+ * geni_configure_xfer_mode() - Set the transfer mode.
+ * @rsc: Pointer to a structure representing SE-related resources.
+ *
+ * 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 qup_se_rsc *rsc)
+{
+ /* Configure SE FIFO, DMA or GSI mode. */
+ switch (rsc->mode) {
+ case GENI_GPI_DMA:
+ geni_setbits32(rsc->base + QUPV3_SE_GENI_DMA_MODE_EN,
+ GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK);
+ writel_relaxed(0x0, rsc->base + SE_IRQ_EN);
+ writel_relaxed(SE_GSI_EVENT_EN_BMSK, rsc->base + SE_GSI_EVENT_EN);
+ break;
+
+ case GENI_SE_FIFO:
+ geni_clrbits32(rsc->base + QUPV3_SE_GENI_DMA_MODE_EN,
+ GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK);
+ writel_relaxed(SE_IRQ_EN_RMSK, rsc->base + SE_IRQ_EN);
+ writel_relaxed(0x0, rsc->base + SE_GSI_EVENT_EN);
+ break;
+
+ case GENI_SE_DMA:
+ geni_setbits32(rsc->base + QUPV3_SE_GENI_DMA_MODE_EN,
+ GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK);
+ writel_relaxed(SE_IRQ_EN_RMSK, rsc->base + SE_IRQ_EN);
+ writel_relaxed(0x0, rsc->base + SE_GSI_EVENT_EN);
+ break;
+
+ default:
+ dev_err(rsc->dev, "invalid se mode: %d\n", rsc->mode);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * geni_config_common_control() - Configure common CGC and disable high priority interrupt.
+ * @rsc: Pointer to a structure representing SE-related resources.
+ *
+ * Configure the common CGC and disable high priority interrupts until the current low priority
+ * interrupts are handled.
+ *
+ * Return: None.
+ */
+static void geni_config_common_control(struct qup_se_rsc *rsc)
+{
+ /*
+ * Disable high priority interrupt until current low priority interrupts are handled.
+ */
+ geni_setbits32(rsc->wrapper_base + QUPV3_COMMON_CFG,
+ FAST_SWITCH_TO_HIGH_DISABLE_BMASK);
+
+ /*
+ * Set AHB_M_CLK_CGC_ON to indicate hardware controls se-wrapper cgc clock.
+ */
+ geni_setbits32(rsc->wrapper_base + QUPV3_SE_AHB_M_CFG,
+ AHB_M_CLK_CGC_ON_BMASK);
+
+ /* Let hardware to control common cgc. */
+ geni_setbits32(rsc->wrapper_base + QUPV3_COMMON_CGC_CTRL,
+ COMMON_CSR_SLV_CLK_CGC_ON_BMASK);
+}
+
+static int load_se_firmware(struct qup_se_rsc *rsc, struct elf_se_hdr *hdr)
+{
+ const u32 *fw_val_arr, *cfg_val_arr;
+ const u8 *cfg_idx_arr;
+ u32 i, reg_value, mask, ramn_cnt;
+ int ret;
+
+ fw_val_arr = (const u32 *)((u8 *)hdr + hdr->fw_offset);
+ cfg_idx_arr = (const u8 *)hdr + hdr->cfg_idx_offset;
+ cfg_val_arr = (const u32 *)((u8 *)hdr + hdr->cfg_val_offset);
+
+ geni_config_common_control(rsc);
+
+ /* Allows to drive corresponding data according to hardware value. */
+ writel_relaxed(0x0, rsc->base + GENI_OUTPUT_CTRL);
+
+ /* Set SCLK and HCLK to program RAM */
+ geni_setbits32(rsc->base + GENI_CGC_CTRL, GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK |
+ GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK);
+ writel_relaxed(0x0, rsc->base + SE_GENI_CLK_CTRL);
+ geni_clrbits32(rsc->base + GENI_CGC_CTRL, GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK |
+ GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK);
+
+ /* Enable required clocks for DMA CSR, TX and RX. */
+ reg_value = DMA_GENERAL_CFG_AHB_SEC_SLV_CLK_CGC_ON_BMSK |
+ DMA_GENERAL_CFG_DMA_AHB_SLV_CLK_CGC_ON_BMSK |
+ DMA_GENERAL_CFG_DMA_TX_CLK_CGC_ON_BMSK |
+ DMA_GENERAL_CFG_DMA_RX_CLK_CGC_ON_BMSK;
+
+ geni_setbits32(rsc->base + DMA_GENERAL_CFG, reg_value);
+
+ /* Let hardware control CGC by default. */
+ writel_relaxed(DEFAULT_CGC_EN, rsc->base + GENI_CGC_CTRL);
+
+ /* Set version of the configuration register part of firmware. */
+ writel_relaxed(hdr->cfg_version, rsc->base + GENI_INIT_CFG_REVISION);
+ writel_relaxed(hdr->cfg_version, rsc->base + GENI_S_INIT_CFG_REVISION);
+
+ /* Configure GENI primitive table. */
+ for (i = 0; i < hdr->cfg_size_in_items; i++)
+ writel_relaxed(cfg_val_arr[i],
+ rsc->base + GENI_CFG_REG0 + (cfg_idx_arr[i] * sizeof(u32)));
+
+ /* Configure condition for assertion of RX_RFR_WATERMARK condition. */
+ reg_value = readl_relaxed(rsc->base + QUPV3_SE_HW_PARAM_1);
+ mask = (reg_value >> RX_FIFO_WIDTH_BIT) & RX_FIFO_WIDTH_MASK;
+ writel_relaxed(mask - 2, rsc->base + GENI_RX_RFR_WATERMARK_REG);
+
+ /* Let hardware control CGC */
+ geni_setbits32(rsc->base + GENI_OUTPUT_CTRL, DEFAULT_IO_OUTPUT_CTRL_MSK);
+
+ ret = geni_configure_xfer_mode(rsc);
+ if (ret) {
+ dev_err(rsc->dev, "failed to configure xfer mode: %d\n", ret);
+ return ret;
+ }
+
+ geni_enable_interrupts(rsc);
+
+ geni_flash_fw_revision(rsc, hdr);
+
+ ramn_cnt = hdr->fw_size_in_items;
+ if (hdr->fw_size_in_items % 2 != 0)
+ ramn_cnt++;
+
+ if (ramn_cnt >= MAX_GENI_CFG_RAMn_CNT) {
+ dev_err(rsc->dev, "firmware size is too large\n");
+ return -EINVAL;
+ }
+
+ /* Program RAM address space. */
+ for (i = 0; i < hdr->fw_size_in_items; i++)
+ writel_relaxed(fw_val_arr[i], rsc->base + SE_GENI_CFG_RAMN + i * sizeof(u32));
+
+ /* Put default values on GENI's output pads. */
+ writel_relaxed(0x1, rsc->base + GENI_FORCE_DEFAULT_REG);
+
+ /* High to low SCLK and HCLK to finish RAM. */
+ geni_setbits32(rsc->base + GENI_CGC_CTRL, GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK |
+ GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK);
+ geni_setbits32(rsc->base + SE_GENI_CLK_CTRL, GENI_CLK_CTRL_SER_CLK_SEL_BMSK);
+ geni_clrbits32(rsc->base + GENI_CGC_CTRL, GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK |
+ GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK);
+
+ /* Serial engine DMA interface is enabled. */
+ geni_setbits32(rsc->base + SE_DMA_IF_EN, DMA_IF_EN_DMA_IF_EN_BMSK);
+
+ /* Enable or disable FIFO interface of the serial engine. */
+ if (rsc->mode == GENI_SE_FIFO)
+ geni_clrbits32(rsc->base + SE_FIFO_IF_DISABLE, FIFO_IF_DISABLE);
+ else
+ geni_setbits32(rsc->base + SE_FIFO_IF_DISABLE, FIFO_IF_DISABLE);
+
+ return 0;
+}
+
+/**
+ * elf_phdr_valid() - Validate an ELF header.
+ * @phdr: Pointer to the ELF header.
+ *
+ * Validate the ELF header by comparing the fields stored in p_flags and the payload type.
+ *
+ * Return: true if the validation is successful, false otherwise.
+ */
+static bool elf_phdr_valid(const Elf32_Phdr *phdr)
+{
+ if (phdr->p_type != PT_LOAD || !phdr->p_memsz)
+ return false;
+
+ 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)
+ return true;
+
+ return false;
+}
+
+/**
+ * valid_seg_size() - Validate the segment size.
+ * @pelfseg: Pointer to the ELF header.
+ * @p_filesz: Pointer to the file size.
+ *
+ * Validate the ELF segment size by comparing the file size.
+ *
+ * Return: true if the segment is valid, false if the segment is invalid.
+ */
+static bool valid_seg_size(struct elf_se_hdr *pelfseg, Elf32_Word p_filesz)
+{
+ if (p_filesz >= pelfseg->fw_offset + pelfseg->fw_size_in_items * sizeof(u32) &&
+ p_filesz >= pelfseg->cfg_idx_offset + pelfseg->cfg_size_in_items * sizeof(u8) &&
+ p_filesz >= pelfseg->cfg_val_offset + pelfseg->cfg_size_in_items * sizeof(u32))
+ return true;
+ return false;
+}
+
+/**
+ * read_elf() - Read an ELF file.
+ * @rsc: Pointer to the SE resources structure.
+ * @fw: Pointer to the firmware buffer.
+ * @pelfseg: Pointer to the SE-specific ELF header.
+ * @phdr: Pointer to one of the valid headers from the list in the firmware buffer.
+ *
+ * Read the ELF file and output a pointer to the header data, which contains the firmware data and
+ * any other details.
+ *
+ * Return: 0 if successful, otherwise return an error value.
+ */
+static int read_elf(struct qup_se_rsc *rsc, const void *fw,
+ struct elf_se_hdr **pelfseg)
+{
+ Elf32_Phdr *phdr;
+ const Elf32_Ehdr *ehdr = (const Elf32_Ehdr *)fw;
+ Elf32_Phdr *phdrs = (Elf32_Phdr *)(ehdr + 1);
+ const u8 *addr;
+ int i;
+
+ ehdr = (Elf32_Ehdr *)fw;
+
+ if (ehdr->e_phnum < 2)
+ return -EINVAL;
+
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ phdr = &phdrs[i];
+ if (!elf_phdr_valid(phdr))
+ continue;
+
+ if (phdr->p_filesz >= sizeof(struct elf_se_hdr)) {
+ addr = fw + phdr->p_offset;
+ *pelfseg = (struct elf_se_hdr *)addr;
+
+ if ((*pelfseg)->magic == MAGIC_NUM_SE &&
+ (*pelfseg)->version == 1 &&
+ valid_seg_size(*pelfseg, phdr->p_filesz) &&
+ (*pelfseg)->serial_protocol == rsc->protocol &&
+ (*pelfseg)->serial_protocol != GENI_SE_NONE)
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+int qcom_geni_load_firmware(phys_addr_t qup_base,
+ struct udevice *dev)
+{
+ struct qup_se_rsc rsc;
+ struct elf_se_hdr *hdr;
+ int ret;
+ void *fw;
+
+ rsc.dev = dev;
+ rsc.base = qup_base;
+ rsc.wrapper_base = dev_read_addr(dev->parent);
+
+ /* FIXME: GSI DMA mode if device has property qcom,gsi-dma-allowed */
+ rsc.mode = GENI_SE_FIFO;
+
+ switch (device_get_uclass_id(dev)) {
+ case UCLASS_I2C:
+ rsc.protocol = GENI_SE_I2C;
+ break;
+ case UCLASS_SPI:
+ rsc.protocol = GENI_SE_SPI;
+ break;
+ case UCLASS_SERIAL:
+ rsc.protocol = GENI_SE_UART;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* The firmware blob is the private data of the GENI wrapper (parent) */
+ fw = dev_get_priv(dev->parent);
+
+ ret = read_elf(&rsc, fw, &hdr);
+ if (ret) {
+ dev_err(dev, "Failed to read ELF: %d\n", ret);
+ return ret;
+ }
+
+ dev_info(dev, "Loading QUP firmware...\n");
+
+ return load_se_firmware(&rsc, hdr);
+}
+
+/*
+ * We need to determine if firmware loading is necessary. Best way to do that is to check the FW
+ * revision of each QUP and see if it has already been loaded.
+ */
+static int geni_se_of_to_plat(struct udevice *dev)
+{
+ ofnode child;
+ struct resource res;
+ u32 proto;
+ struct geni_se_plat *plat = dev_get_plat(dev);
+
+ plat->need_firmware_load = false;
+
+ dev_for_each_subnode(child, dev) {
+ if (!ofnode_is_enabled(child))
+ continue;
+
+ if (ofnode_read_resource(child, 0, &res))
+ continue;
+
+ proto = readl(res.start + GENI_FW_REVISION_RO);
+ proto &= FW_REV_PROTOCOL_MSK;
+ proto >>= FW_REV_PROTOCOL_SHFT;
+
+ if (proto == GENI_SE_INVALID_PROTO)
+ plat->need_firmware_load = true;
+ }
+
+ return 0;
+}
+
+#define QUPFW_PART_TYPE_GUID "21d1219f-2ed1-4ab4-930a-41a16ae75f7f"
+
+static int find_qupfw_part(struct udevice **blk_dev, struct disk_partition *part_info)
+{
+ struct blk_desc *desc;
+ int ret, partnum;
+
+ uclass_foreach_dev_probe(UCLASS_BLK, *blk_dev) {
+ if (device_get_uclass_id(*blk_dev) != UCLASS_BLK)
+ continue;
+
+ desc = dev_get_uclass_plat(*blk_dev);
+ if (!desc || desc->part_type == PART_TYPE_UNKNOWN)
+ continue;
+ for (partnum = 1;; partnum++) {
+ ret = part_get_info(desc, partnum, part_info);
+ if (ret)
+ break;
+ if (!strcmp(part_info->type_guid, QUPFW_PART_TYPE_GUID))
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+static int probe_children_load_firmware(struct udevice *dev)
+{
+ struct geni_se_plat *plat;
+ ofnode child;
+ struct udevice *child_dev;
+ struct resource res;
+ u32 proto;
+ int ret;
+
+ plat = dev_get_plat(dev);
+
+ dev_for_each_subnode(child, dev) {
+ if (!ofnode_is_enabled(child))
+ continue;
+
+ if (ofnode_read_resource(child, 0, &res))
+ continue;
+
+ proto = readl(res.start + GENI_FW_REVISION_RO);
+ proto &= FW_REV_PROTOCOL_MSK;
+ proto >>= FW_REV_PROTOCOL_SHFT;
+
+ if (proto != GENI_SE_INVALID_PROTO)
+ continue;
+
+ ret = 0;
+ /* Find the device for this ofnode, or bind it */
+ if (device_find_global_by_ofnode(child, &child_dev))
+ ret = lists_bind_fdt(dev, child, &child_dev, NULL, false);
+ if (ret) {
+ /* Skip nodes that don't have drivers */
+ debug("Failed to probe child %s: %d\n", ofnode_get_name(child), ret);
+ continue;
+ }
+ debug("Probing child %s for fw loading\n", child_dev->name);
+ device_probe(child_dev);
+ }
+
+ return 0;
+}
+
+#define MAX_FW_BUF_SIZE (128 * 1024)
+
+/*
+ * Load firmware for QCOM GENI peripherals from the dedicated partition on storage and bind/probe
+ * all the peripheral devices that need firmware to be loaded.
+ */
+static int qcom_geni_fw_initialise(void)
+{
+ debug("Loading firmware for QCOM GENI SE\n");
+ struct udevice *geni_wrapper, *blk_dev;
+ struct disk_partition part_info;
+ int ret;
+ void *fw_buf;
+ size_t fw_size = MAX_FW_BUF_SIZE;
+ struct geni_se_plat *plat;
+
+ /* Find the first GENI SE wrapper that needs fw loading */
+ for (uclass_first_device(UCLASS_MISC, &geni_wrapper);
+ geni_wrapper;
+ uclass_next_device(&geni_wrapper)) {
+ if (device_get_uclass_id(geni_wrapper) == UCLASS_MISC &&
+ !strcmp(geni_wrapper->driver->name, "geni-se-qup")) {
+ plat = dev_get_plat(geni_wrapper);
+ if (plat->need_firmware_load)
+ break;
+ }
+ }
+ if (!geni_wrapper) {
+ pr_err("GENI SE wrapper not found\n");
+ return 0;
+ }
+
+ ret = find_qupfw_part(&blk_dev, &part_info);
+ if (ret) {
+ pr_err("QUP firmware partition not found\n");
+ return 0;
+ }
+
+ if (part_info.size * part_info.blksz > MAX_FW_BUF_SIZE) {
+ pr_err("Firmware partition too large\n");
+ return -EINVAL;
+ }
+ fw_size = part_info.size * part_info.blksz;
+
+ fw_buf = malloc(fw_size);
+ if (!fw_buf) {
+ pr_err("Failed to allocate buffer for firmware\n");
+ return -ENOMEM;
+ }
+ memset(fw_buf, 0, fw_size);
+
+ ret = blk_read(blk_dev, part_info.start, part_info.size, fw_buf);
+ if (ret < 0) {
+ pr_err("Failed to read firmware from partition\n");
+ free(fw_buf);
+ return 0;
+ }
+
+ /*
+ * OK! Firmware is loaded, now bind and probe remaining children. They will attempt to load
+ * firmware during probe. Do this for each GENI SE wrapper that needs firmware loading.
+ */
+ for (; geni_wrapper;
+ uclass_next_device(&geni_wrapper)) {
+ if (device_get_uclass_id(geni_wrapper) == UCLASS_MISC &&
+ !strcmp(geni_wrapper->driver->name, "geni-se-qup")) {
+ plat = dev_get_plat(geni_wrapper);
+ if (plat->need_firmware_load) {
+ dev_set_priv(geni_wrapper, fw_buf);
+ probe_children_load_firmware(geni_wrapper);
+ }
+ }
+ }
+
+ return 0;
+}
+
+EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, qcom_geni_fw_initialise);
+
+static const struct udevice_id geni_ids[] = {
+ { .compatible = "qcom,geni-se-qup" },
+ {}
+};
+
+U_BOOT_DRIVER(geni_se_qup) = {
+ .name = "geni-se-qup",
+ .id = UCLASS_MISC,
+ .of_match = geni_ids,
+ .of_to_plat = geni_se_of_to_plat,
+ .plat_auto = sizeof(struct geni_se_plat),
+ .flags = DM_FLAG_DEFAULT_PD_CTRL_OFF,
+};
diff --git a/drivers/misc/qfw_acpi.c b/drivers/misc/qfw_acpi.c
index c6c052ac6c3..721f42ecbc3 100644
--- a/drivers/misc/qfw_acpi.c
+++ b/drivers/misc/qfw_acpi.c
@@ -265,7 +265,6 @@ out:
struct acpi_rsdp *rsdp = ctx->rsdp;
rsdp->length = sizeof(*rsdp);
- rsdp->xsdt_address = 0;
rsdp->ext_checksum = table_compute_checksum((u8 *)rsdp, sizeof(*rsdp));
gd_set_acpi_start(acpi_get_rsdp_addr());
diff --git a/drivers/misc/smsc_lpc47m.c b/drivers/misc/smsc_lpc47m.c
index 1b15907b093..cc3d3f9de06 100644
--- a/drivers/misc/smsc_lpc47m.c
+++ b/drivers/misc/smsc_lpc47m.c
@@ -3,8 +3,8 @@
* Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
*/
+#include <pnp_def.h>
#include <asm/io.h>
-#include <asm/pnp_def.h>
static void pnp_enter_conf_state(u16 dev)
{
diff --git a/drivers/misc/winbond_w83627.c b/drivers/misc/winbond_w83627.c
index 87b9043e65c..8c5b121b8e9 100644
--- a/drivers/misc/winbond_w83627.c
+++ b/drivers/misc/winbond_w83627.c
@@ -3,8 +3,8 @@
* Copyright (C) 2016 Stefan Roese <sr@denx.de>
*/
+#include <pnp_def.h>
#include <asm/io.h>
-#include <asm/pnp_def.h>
#define WINBOND_ENTRY_KEY 0x87
#define WINBOND_EXIT_KEY 0xaa
diff --git a/drivers/mmc/cv1800b_sdhci.c b/drivers/mmc/cv1800b_sdhci.c
index 377e6a887df..036e798f374 100644
--- a/drivers/mmc/cv1800b_sdhci.c
+++ b/drivers/mmc/cv1800b_sdhci.c
@@ -19,6 +19,7 @@ struct cv1800b_sdhci_plat {
struct mmc mmc;
};
+#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING)
static void cv1800b_set_tap_delay(struct sdhci_host *host, u16 tap)
{
sdhci_writel(host, PHY_TX_SRC_INVERT | tap << 16, SDHCI_PHY_TX_RX_DLY);
@@ -31,7 +32,6 @@ static void cv1800b_sdhci_reset(struct sdhci_host *host, u8 mask)
udelay(10);
}
-#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING)
static int cv1800b_execute_tuning(struct mmc *mmc, u8 opcode)
{
struct sdhci_host *host = dev_get_priv(mmc->dev);
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index a51494380ce..d9c05b223d5 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -419,6 +419,10 @@ static int dwmci_send_cmd_common(struct dwmci_host *host, struct mmc_cmd *cmd,
if (cmd->resp_type & MMC_RSP_CRC)
flags |= DWMCI_CMD_CHECK_CRC;
+ host->volt_switching = (cmd->cmdidx == SD_CMD_SWITCH_UHS18V);
+ if (host->volt_switching)
+ flags |= DWMCI_CMD_VOLT_SWITCH;
+
flags |= cmd->cmdidx | DWMCI_CMD_START | DWMCI_CMD_USE_HOLD_REG;
debug("Sending CMD%d\n", cmd->cmdidx);
@@ -427,6 +431,10 @@ static int dwmci_send_cmd_common(struct dwmci_host *host, struct mmc_cmd *cmd,
for (i = 0; i < retry; i++) {
mask = dwmci_readl(host, DWMCI_RINTSTS);
+ if (host->volt_switching && (mask & DWMCI_INTMSK_VOLTSW)) {
+ dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_VOLTSW);
+ break;
+ }
if (mask & DWMCI_INTMSK_CDONE) {
if (!data)
dwmci_writel(host, DWMCI_RINTSTS, mask);
@@ -507,20 +515,24 @@ static int dwmci_control_clken(struct dwmci_host *host, bool on)
{
const u32 val = on ? DWMCI_CLKEN_ENABLE | DWMCI_CLKEN_LOW_PWR : 0;
const u32 cmd_only_clk = DWMCI_CMD_PRV_DAT_WAIT | DWMCI_CMD_UPD_CLK;
- int timeout = 10000;
- u32 status;
+ int i, timeout = 10000;
+ u32 flags, mask;
dwmci_writel(host, DWMCI_CLKENA, val);
/* Inform CIU */
- dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_START | cmd_only_clk);
- do {
- status = dwmci_readl(host, DWMCI_CMD);
- if (timeout-- < 0) {
- debug("%s: Timeout!\n", __func__);
- return -ETIMEDOUT;
+ flags = DWMCI_CMD_START | cmd_only_clk;
+ if (host->volt_switching)
+ flags |= DWMCI_CMD_VOLT_SWITCH;
+ dwmci_writel(host, DWMCI_CMD, flags);
+
+ for (i = 0; i < timeout; i++) {
+ mask = dwmci_readl(host, DWMCI_RINTSTS);
+ if (mask & DWMCI_INTMSK_CDONE) {
+ dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_CDONE);
+ break;
}
- } while (status & DWMCI_CMD_START);
+ }
return 0;
}
@@ -554,7 +566,7 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq)
unsigned long sclk;
int ret;
- if (freq == host->clock || freq == 0)
+ if (!freq)
return 0;
/*
@@ -632,17 +644,11 @@ static int dwmci_set_ios(struct mmc *mmc)
if (mmc->vqmmc_supply) {
int ret;
- ret = regulator_set_enable_if_allowed(mmc->vqmmc_supply, false);
- if (ret)
- return ret;
-
if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180)
- regulator_set_value(mmc->vqmmc_supply, 1800000);
+ ret = regulator_set_value(mmc->vqmmc_supply, 1800000);
else
- regulator_set_value(mmc->vqmmc_supply, 3300000);
-
- ret = regulator_set_enable_if_allowed(mmc->vqmmc_supply, true);
- if (ret)
+ ret = regulator_set_value(mmc->vqmmc_supply, 3300000);
+ if (ret && ret != -ENOSYS)
return ret;
}
#endif
diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c
index 12e37cb4b78..7ccd113bd79 100644
--- a/drivers/mmc/exynos_dw_mmc.c
+++ b/drivers/mmc/exynos_dw_mmc.c
@@ -18,15 +18,33 @@
#include <linux/printk.h>
#define DWMMC_MAX_CH_NUM 4
-#define DWMMC_MAX_FREQ 52000000
+#define DWMMC_MAX_FREQ 208000000
#define DWMMC_MIN_FREQ 400000
#define DWMMC_MMC0_SDR_TIMING_VAL 0x03030001
#define DWMMC_MMC2_SDR_TIMING_VAL 0x03020001
#define EXYNOS4412_FIXED_CIU_CLK_DIV 4
-/* Quirks */
+/* CLKSEL register defines */
+#define CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0)
+#define CLKSEL_UP_SAMPLE(x, y) (((x) & ~CLKSEL_CCLK_SAMPLE(7)) | \
+ CLKSEL_CCLK_SAMPLE(y))
+
+/**
+ * DOC: Quirk flags for different Exynos DW MMC blocks
+ *
+ * %DWMCI_QUIRK_DISABLE_SMU: DW MMC block has Security Management Unit (SMU)
+ * which has to be configured in non-encryption mode during driver's init.
+ *
+ * %DWMCI_QUIRK_DISABLE_FMP: DW MMC block has Flash Memory Protector (FMP) which
+ * has to be disabled during driver's init. This flag disables FMP encryption
+ * and lets external non-secure main CPUs access the SFR (peripheral memory
+ * region, i.e. registers) in MMC core. Although it's usually done by early
+ * bootloaders (before U-Boot), in some cases like during USB boot the FMP might
+ * be left unconfigured.
+ */
#define DWMCI_QUIRK_DISABLE_SMU BIT(0)
+#define DWMCI_QUIRK_DISABLE_FMP BIT(1)
#ifdef CONFIG_DM_MMC
#include <dm.h>
@@ -121,22 +139,6 @@ static int exynos_dwmmc_set_sclk(struct dwmci_host *host, unsigned long rate)
return 0;
}
-/* Configure CLKSEL register with chosen timing values */
-static int exynos_dwmci_clksel(struct dwmci_host *host)
-{
- struct dwmci_exynos_priv_data *priv = exynos_dwmmc_get_priv(host);
- u32 timing;
-
- if (host->mmc->selected_mode == MMC_DDR_52)
- timing = priv->ddr_timing;
- else
- timing = priv->sdr_timing;
-
- dwmci_writel(host, priv->chip->clksel, timing);
-
- return 0;
-}
-
/**
* exynos_dwmmc_get_ciu_div - Get internal clock divider value
* @host: MMC controller object
@@ -160,15 +162,45 @@ static u8 exynos_dwmmc_get_ciu_div(struct dwmci_host *host)
& DWMCI_DIVRATIO_MASK) + 1;
}
+/* Configure CLKSEL register with chosen timing values */
+static int exynos_dwmci_clksel(struct dwmci_host *host)
+{
+ struct dwmci_exynos_priv_data *priv = exynos_dwmmc_get_priv(host);
+ u8 clk_div = exynos_dwmmc_get_ciu_div(host) - 1;
+ u32 timing;
+
+ switch (host->mmc->selected_mode) {
+ case MMC_DDR_52:
+ timing = priv->ddr_timing;
+ break;
+ case UHS_SDR104:
+ case UHS_SDR50:
+ timing = (priv->sdr_timing & 0xfff8ffff) | (clk_div << 16);
+ break;
+ case UHS_DDR50:
+ timing = (priv->ddr_timing & 0xfff8ffff) | (clk_div << 16);
+ break;
+ default:
+ timing = priv->sdr_timing;
+ }
+
+ dwmci_writel(host, priv->chip->clksel, timing);
+
+ return 0;
+}
+
static unsigned int exynos_dwmci_get_clk(struct dwmci_host *host, uint freq)
{
unsigned long sclk;
u8 clk_div;
int err;
- /* Should be double rate for DDR mode */
- if (host->mmc->selected_mode == MMC_DDR_52 && host->mmc->bus_width == 8)
+ /* Should be double rate for DDR or HS mode */
+ if ((host->mmc->selected_mode == MMC_DDR_52 &&
+ host->mmc->bus_width == 8) ||
+ host->mmc->selected_mode == MMC_HS_400) {
freq *= 2;
+ }
clk_div = exynos_dwmmc_get_ciu_div(host);
err = exynos_dwmmc_set_sclk(host, freq * clk_div);
@@ -201,6 +233,18 @@ static void exynos_dwmci_board_init(struct dwmci_host *host)
MPSCTRL_NON_SECURE_WRITE_BIT | MPSCTRL_VALID);
}
+ if (priv->chip->quirks & DWMCI_QUIRK_DISABLE_FMP) {
+ u32 reg;
+
+ reg = dwmci_readl(host, EMMCP_MPSECURITY);
+ if (reg & MPSECURITY_FMP_ON ||
+ reg & MPSECURITY_MMC_SFR_PROT_ON) {
+ reg &= ~MPSECURITY_FMP_ON;
+ reg &= ~MPSECURITY_MMC_SFR_PROT_ON;
+ dwmci_writel(host, EMMCP_MPSECURITY, reg);
+ }
+ }
+
if (priv->sdr_timing)
exynos_dwmci_clksel(host);
}
@@ -282,6 +326,75 @@ static int exynos_dwmmc_of_to_plat(struct udevice *dev)
return 0;
}
+#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING)
+static int exynos_dwmmc_get_best_clksmpl(u8 candidates)
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ candidates = (candidates >> 1) | (candidates << 7); /* ror */
+ if ((candidates & 0xc7) == 0xc7)
+ return i;
+ }
+
+ for (i = 0; i < 8; i++) {
+ candidates = (candidates >> 1) | (candidates << 7); /* ror */
+ if ((candidates & 0x83) == 0x83)
+ return i;
+ }
+
+ /*
+ * If no valid clock sample values are found, use the first candidate
+ * bit for clock sample value.
+ */
+ for (i = 0; i < 8; i++) {
+ candidates = (candidates >> 1) | (candidates << 7); /* ror */
+ if ((candidates & 0x1) == 0x1)
+ return i;
+ }
+
+ return -EIO;
+}
+
+static int exynos_dwmmc_execute_tuning(struct udevice *dev, u32 opcode)
+{
+ struct dwmci_exynos_priv_data *priv = dev_get_priv(dev);
+ struct dwmci_host *host = &priv->host;
+ struct mmc *mmc = mmc_get_mmc_dev(dev);
+ u8 start_smpl, smpl, candidates = 0;
+ u32 clksel;
+ int ret;
+
+ clksel = dwmci_readl(host, priv->chip->clksel);
+ start_smpl = CLKSEL_CCLK_SAMPLE(clksel);
+
+ do {
+ dwmci_writel(host, DWMCI_TMOUT, ~0);
+
+ /* Move to the next clksmpl */
+ smpl = (clksel + 1) & 0x7;
+ clksel = CLKSEL_UP_SAMPLE(clksel, smpl);
+ dwmci_writel(host, priv->chip->clksel, clksel);
+
+ if (!mmc_send_tuning(mmc, opcode))
+ candidates |= (1 << smpl);
+
+ } while (start_smpl != smpl);
+
+ ret = exynos_dwmmc_get_best_clksmpl(candidates);
+ if (ret < 0) {
+ printf("DWMMC%d: No candidates for clksmpl\n", host->dev_index);
+ return ret;
+ }
+
+ dwmci_writel(host, priv->chip->clksel, CLKSEL_UP_SAMPLE(clksel, ret));
+
+ return 0;
+}
+#endif /* CONFIG_MMC_SUPPORTS_TUNING */
+
+struct dm_mmc_ops exynos_dwmmc_ops;
+
static int exynos_dwmmc_probe(struct udevice *dev)
{
struct exynos_mmc_plat *plat = dev_get_plat(dev);
@@ -291,6 +404,12 @@ static int exynos_dwmmc_probe(struct udevice *dev)
unsigned long freq;
int err;
+ /* Extend generic 'dm_dwmci_ops' with .execute_tuning implementation */
+ memcpy(&exynos_dwmmc_ops, &dm_dwmci_ops, sizeof(struct dm_mmc_ops));
+#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING)
+ exynos_dwmmc_ops.execute_tuning = exynos_dwmmc_execute_tuning;
+#endif
+
#ifndef CONFIG_CPU_V7A
err = clk_get_by_index(dev, 1, &priv->clk); /* ciu */
if (err)
@@ -303,7 +422,7 @@ static int exynos_dwmmc_probe(struct udevice *dev)
flag = host->buswidth == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE;
err = exynos_pinmux_config(host->dev_id, flag);
if (err) {
- printf("DWMMC%d not configure\n", host->dev_index);
+ printf("DWMMC%d not configured\n", host->dev_index);
return err;
}
#endif
@@ -321,7 +440,8 @@ static int exynos_dwmmc_probe(struct udevice *dev)
host->name = dev->name;
host->board_init = exynos_dwmci_board_init;
- host->caps = MMC_MODE_DDR_52MHz;
+ host->caps = MMC_MODE_DDR_52MHz | MMC_MODE_HS200 | MMC_MODE_HS400 |
+ UHS_CAPS;
host->clksel = exynos_dwmci_clksel;
host->get_mmc_clk = exynos_dwmci_get_clk;
@@ -368,6 +488,11 @@ static const struct exynos_dwmmc_variant exynos7_smu_drv_data = {
.quirks = DWMCI_QUIRK_DISABLE_SMU,
};
+static const struct exynos_dwmmc_variant exynos850_drv_data = {
+ .clksel = DWMCI_CLKSEL64,
+ .quirks = DWMCI_QUIRK_DISABLE_SMU | DWMCI_QUIRK_DISABLE_FMP,
+};
+
static const struct udevice_id exynos_dwmmc_ids[] = {
{
.compatible = "samsung,exynos4412-dw-mshc",
@@ -379,11 +504,20 @@ static const struct udevice_id exynos_dwmmc_ids[] = {
.compatible = "samsung,exynos5420-dw-mshc",
.data = (ulong)&exynos5_drv_data,
}, {
+ .compatible = "samsung,exynos5250-dw-mshc",
+ .data = (ulong)&exynos5_drv_data,
+ }, {
.compatible = "samsung,exynos-dwmmc",
.data = (ulong)&exynos5_drv_data,
}, {
.compatible = "samsung,exynos7-dw-mshc-smu",
.data = (ulong)&exynos7_smu_drv_data,
+ }, {
+ .compatible = "samsung,exynos7870-dw-mshc-smu",
+ .data = (ulong)&exynos7_smu_drv_data,
+ }, {
+ .compatible = "samsung,exynos850-dw-mshc-smu",
+ .data = (ulong)&exynos850_drv_data,
},
{ }
};
@@ -395,8 +529,8 @@ U_BOOT_DRIVER(exynos_dwmmc_drv) = {
.of_to_plat = exynos_dwmmc_of_to_plat,
.bind = exynos_dwmmc_bind,
.probe = exynos_dwmmc_probe,
- .ops = &dm_dwmci_ops,
+ .ops = &exynos_dwmmc_ops,
.priv_auto = sizeof(struct dwmci_exynos_priv_data),
.plat_auto = sizeof(struct exynos_mmc_plat),
};
-#endif
+#endif /* CONFIG_DM_MMC */
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index b1cfa3cd7c2..bf82c515600 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -643,6 +643,19 @@ static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage)
return 0;
}
+
+static bool mmc_sd_card_using_v18(struct mmc *mmc)
+{
+ /*
+ * According to the SD spec., the Bus Speed Mode (function group 1) bits
+ * 2 to 4 are zero if the card is initialized at 3.3V signal level. Thus
+ * they can be used to determine if the card has already switched to
+ * 1.8V signaling.
+ */
+ bool volt = mmc->sd3_bus_mode &
+ (SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR104 | SD_MODE_UHS_DDR50);
+ return volt;
+}
#endif
static int sd_send_op_cond(struct mmc *mmc, bool uhs_en)
@@ -1369,9 +1382,6 @@ static int sd_get_capabilities(struct mmc *mmc)
ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
struct mmc_data data;
int timeout;
-#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
- u32 sd3_bus_mode;
-#endif
mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY);
@@ -1451,16 +1461,16 @@ static int sd_get_capabilities(struct mmc *mmc)
if (mmc->version < SD_VERSION_3)
return 0;
- sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f;
- if (sd3_bus_mode & SD_MODE_UHS_SDR104)
+ mmc->sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f;
+ if (mmc->sd3_bus_mode & SD_MODE_UHS_SDR104)
mmc->card_caps |= MMC_CAP(UHS_SDR104);
- if (sd3_bus_mode & SD_MODE_UHS_SDR50)
+ if (mmc->sd3_bus_mode & SD_MODE_UHS_SDR50)
mmc->card_caps |= MMC_CAP(UHS_SDR50);
- if (sd3_bus_mode & SD_MODE_UHS_SDR25)
+ if (mmc->sd3_bus_mode & SD_MODE_UHS_SDR25)
mmc->card_caps |= MMC_CAP(UHS_SDR25);
- if (sd3_bus_mode & SD_MODE_UHS_SDR12)
+ if (mmc->sd3_bus_mode & SD_MODE_UHS_SDR12)
mmc->card_caps |= MMC_CAP(UHS_SDR12);
- if (sd3_bus_mode & SD_MODE_UHS_DDR50)
+ if (mmc->sd3_bus_mode & SD_MODE_UHS_DDR50)
mmc->card_caps |= MMC_CAP(UHS_DDR50);
#endif
@@ -1546,7 +1556,7 @@ static int sd_select_bus_width(struct mmc *mmc, int w)
}
#endif
-#if CONFIG_IS_ENABLED(MMC_WRITE)
+#if CONFIG_IS_ENABLED(MMC_WRITE) && !CONFIG_IS_ENABLED(MMC_TINY)
static int sd_read_ssr(struct mmc *mmc)
{
static const unsigned int sd_au_size[] = {
@@ -1830,7 +1840,11 @@ static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps)
uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
const struct mode_width_tuning *mwt;
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
- bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false;
+ /*
+ * Enable UHS mode if the card advertises 1.8V support (S18R in OCR)
+ * or is already operating at 1.8V signaling.
+ */
+ bool uhs_en = (mmc->ocr & OCR_S18R) || mmc_sd_card_using_v18(mmc);
#else
bool uhs_en = false;
#endif
@@ -2701,6 +2715,27 @@ static int mmc_startup(struct mmc *mmc)
err = sd_get_capabilities(mmc);
if (err)
return err;
+
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+ /*
+ * If the card has already switched to 1.8V signaling, then
+ * set the signal voltage to 1.8V.
+ */
+ if (mmc_sd_card_using_v18(mmc)) {
+ /*
+ * During a signal voltage level switch, the clock must be gated
+ * for 5 ms according to the SD spec.
+ */
+ mmc_set_clock(mmc, mmc->clock, MMC_CLK_DISABLE);
+ err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
+ if (err)
+ return err;
+ /* Keep clock gated for at least 10 ms, though spec only says 5 ms */
+ mdelay(10);
+ mmc_set_clock(mmc, mmc->clock, MMC_CLK_ENABLE);
+ }
+#endif
+
err = sd_select_mode_and_width(mmc, mmc->card_caps);
} else {
err = mmc_get_capabilities(mmc);
@@ -2844,6 +2879,16 @@ static int mmc_power_on(struct mmc *mmc)
return ret;
}
}
+
+ if (mmc->vqmmc_supply) {
+ int ret = regulator_set_enable_if_allowed(mmc->vqmmc_supply,
+ true);
+
+ if (ret && ret != -ENOSYS) {
+ printf("Error enabling VQMMC supply : %d\n", ret);
+ return ret;
+ }
+ }
#endif
return 0;
}
@@ -2861,6 +2906,16 @@ static int mmc_power_off(struct mmc *mmc)
return ret;
}
}
+
+ if (mmc->vqmmc_supply) {
+ int ret = regulator_set_enable_if_allowed(mmc->vqmmc_supply,
+ false);
+
+ if (ret && ret != -ENOSYS) {
+ pr_debug("Error disabling VQMMC supply : %d\n", ret);
+ return ret;
+ }
+ }
#endif
return 0;
}
diff --git a/drivers/mmc/octeontx_hsmmc.c b/drivers/mmc/octeontx_hsmmc.c
index 3b5e1221732..bb4fb29424b 100644
--- a/drivers/mmc/octeontx_hsmmc.c
+++ b/drivers/mmc/octeontx_hsmmc.c
@@ -1545,7 +1545,7 @@ static int octeontx_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
slot->is_acmd = (cmd->cmdidx == MMC_CMD_APP_CMD);
- if (!cmd->resp_type & MMC_RSP_PRESENT)
+ if (!(cmd->resp_type & MMC_RSP_PRESENT))
debug(" Response type: 0x%x, no response expected\n",
cmd->resp_type);
/* Get the response if present */
@@ -2828,9 +2828,6 @@ static void octeontx_mmc_io_drive_setup(struct mmc *mmc)
struct octeontx_mmc_slot *slot = mmc_to_slot(mmc);
union mio_emm_io_ctl io_ctl;
- if (slot->drive < 0 || slot->slew < 0)
- return;
-
io_ctl.u = 0;
io_ctl.s.drive = slot->drive;
io_ctl.s.slew = slot->slew;
diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
index 92bc72b267c..ae742080643 100644
--- a/drivers/mmc/omap_hsmmc.c
+++ b/drivers/mmc/omap_hsmmc.c
@@ -651,6 +651,7 @@ static int omap_hsmmc_execute_tuning(struct udevice *dev, uint opcode)
printf("Couldn't get temperature for tuning\n");
return ret;
}
+ temperature /= 1000;
val = readl(&mmc_base->dll);
val |= DLL_SWT;
writel(val, &mmc_base->dll);
diff --git a/drivers/mmc/owl_mmc.c b/drivers/mmc/owl_mmc.c
index bd4906f58e7..c18807b1f49 100644
--- a/drivers/mmc/owl_mmc.c
+++ b/drivers/mmc/owl_mmc.c
@@ -135,19 +135,19 @@ static void owl_mmc_prepare_data(struct owl_mmc_priv *priv,
setbits_le32(priv->reg_base + OWL_REG_SD_EN, OWL_SD_EN_BSEL);
- writel(data->blocks, priv->reg_base + OWL_REG_SD_BLK_NUM);
- writel(data->blocksize, priv->reg_base + OWL_REG_SD_BLK_SIZE);
- total = data->blocksize * data->blocks;
-
- if (total < 512)
- writel(total, priv->reg_base + OWL_REG_SD_BUF_SIZE);
- else
- writel(512, priv->reg_base + OWL_REG_SD_BUF_SIZE);
-
/* DMA STOP */
writel(0x0, SD_DMA_CHANNEL(priv->dma_channel, 0) + DMA_START);
if (data) {
+ writel(data->blocks, priv->reg_base + OWL_REG_SD_BLK_NUM);
+ writel(data->blocksize, priv->reg_base + OWL_REG_SD_BLK_SIZE);
+ total = data->blocksize * data->blocks;
+
+ if (total < 512)
+ writel(total, priv->reg_base + OWL_REG_SD_BUF_SIZE);
+ else
+ writel(512, priv->reg_base + OWL_REG_SD_BUF_SIZE);
+
if (data->flags == MMC_DATA_READ) {
buf = (ulong) (data->dest);
owl_dma_config(priv, (ulong) priv->reg_base +
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c
index 556f07eaf8f..14976a8d30d 100644
--- a/drivers/mmc/renesas-sdhi.c
+++ b/drivers/mmc/renesas-sdhi.c
@@ -864,6 +864,7 @@ static const struct udevice_id renesas_sdhi_match[] = {
{ .compatible = "renesas,sdhi-r8a77990", .data = RENESAS_GEN3_QUIRKS },
{ .compatible = "renesas,sdhi-r8a77995", .data = RENESAS_GEN3_QUIRKS },
{ .compatible = "renesas,rcar-gen4-sdhi", .data = RENESAS_GEN3_QUIRKS },
+ { .compatible = "renesas,rcar-gen5-sdhi", .data = RENESAS_GEN3_QUIRKS },
{ .compatible = "renesas,rzg2l-sdhi", .data = RENESAS_GEN3_QUIRKS },
{ /* sentinel */ }
};
diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
index 5e025d76a82..8116e464278 100644
--- a/drivers/mmc/rockchip_sdhci.c
+++ b/drivers/mmc/rockchip_sdhci.c
@@ -9,6 +9,7 @@
#include <dm.h>
#include <dm/ofnode.h>
#include <dt-structs.h>
+#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/libfdt.h>
@@ -86,6 +87,9 @@
#define DLL_CMDOUT_SRC_CLK_NEG BIT(28)
#define DLL_CMDOUT_EN_SRC_CLK_NEG BIT(29)
#define DLL_CMDOUT_BOTH_CLK_EDGE BIT(30)
+#define DLL_TAPVALUE_FROM_SW BIT(25)
+#define DLL_TAP_VALUE_PREP(x) FIELD_PREP(GENMASK(15, 8), (x))
+#define DLL_LOCK_VALUE_GET(x) FIELD_GET(GENMASK(7, 0), (x))
#define DLL_LOCK_WO_TMOUT(x) \
((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \
@@ -93,6 +97,7 @@
#define ROCKCHIP_MAX_CLKS 3
#define FLAG_INVERTER_FLAG_IN_RXCLK BIT(0)
+#define FLAG_TAPVALUE_FROM_SW BIT(1)
struct rockchip_sdhc_plat {
struct mmc_config cfg;
@@ -317,7 +322,7 @@ static int rk3568_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enab
struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(priv->dev);
struct mmc *mmc = host->mmc;
int val, ret;
- u32 extra, txclk_tapnum;
+ u32 extra, txclk_tapnum, dll_tap_value;
if (!enable) {
sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL);
@@ -347,7 +352,15 @@ static int rk3568_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enab
if (ret)
return ret;
- extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_RXCLK_ORI_GATE;
+ if (data->flags & FLAG_TAPVALUE_FROM_SW)
+ dll_tap_value = DLL_TAPVALUE_FROM_SW |
+ DLL_TAP_VALUE_PREP(DLL_LOCK_VALUE_GET(val) * 2);
+ else
+ dll_tap_value = 0;
+
+ extra = DWCMSHC_EMMC_DLL_DLYENA |
+ DLL_RXCLK_ORI_GATE |
+ dll_tap_value;
if (data->flags & FLAG_INVERTER_FLAG_IN_RXCLK)
extra |= DLL_RXCLK_NO_INVERTER;
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK);
@@ -361,19 +374,22 @@ static int rk3568_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enab
DLL_CMDOUT_BOTH_CLK_EDGE |
DWCMSHC_EMMC_DLL_DLYENA |
data->hs400_cmdout_tapnum |
- DLL_CMDOUT_TAPNUM_FROM_SW;
+ DLL_CMDOUT_TAPNUM_FROM_SW |
+ dll_tap_value;
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CMDOUT);
}
extra = DWCMSHC_EMMC_DLL_DLYENA |
DLL_TXCLK_TAPNUM_FROM_SW |
DLL_TXCLK_NO_INVERTER |
- txclk_tapnum;
+ txclk_tapnum |
+ dll_tap_value;
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK);
extra = DWCMSHC_EMMC_DLL_DLYENA |
data->hs400_strbin_tapnum |
- DLL_STRBIN_TAPNUM_FROM_SW;
+ DLL_STRBIN_TAPNUM_FROM_SW |
+ dll_tap_value;
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
} else {
/*
@@ -663,6 +679,7 @@ static const struct sdhci_data rk3528_data = {
.set_ios_post = rk3568_sdhci_set_ios_post,
.set_clock = rk3568_sdhci_set_clock,
.config_dll = rk3568_sdhci_config_dll,
+ .flags = FLAG_TAPVALUE_FROM_SW,
.hs200_txclk_tapnum = 0xc,
.hs400_txclk_tapnum = 0x6,
.hs400_cmdout_tapnum = 0x6,
diff --git a/drivers/mmc/sdhci-cadence6.c b/drivers/mmc/sdhci-cadence6.c
index 9a92b8437a6..ead96dc0c91 100644
--- a/drivers/mmc/sdhci-cadence6.c
+++ b/drivers/mmc/sdhci-cadence6.c
@@ -180,10 +180,8 @@ static int sdhci_cdns6_reset_phy_dll(struct sdhci_cdns_plat *plat, bool reset)
int sdhci_cdns6_phy_adj(struct udevice *dev, struct sdhci_cdns_plat *plat, u32 mode)
{
- DECLARE_GLOBAL_DATA_PTR;
struct sdhci_cdns6_phy_cfg *sdhci_cdns6_phy_cfgs;
struct sdhci_cdns6_ctrl_cfg *sdhci_cdns6_ctrl_cfgs;
- const fdt32_t *prop;
u32 tmp;
int i, ret;
@@ -216,19 +214,11 @@ int sdhci_cdns6_phy_adj(struct udevice *dev, struct sdhci_cdns_plat *plat, u32 m
return -EINVAL;
}
- for (i = 0; i < SDHCI_CDNS6_PHY_CFG_NUM; i++) {
- prop = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
- sdhci_cdns6_phy_cfgs[i].property, NULL);
- if (prop)
- sdhci_cdns6_phy_cfgs[i].val = *prop;
- }
+ for (i = 0; i < SDHCI_CDNS6_PHY_CFG_NUM; i++)
+ dev_read_u32(dev, sdhci_cdns6_phy_cfgs[i].property, &sdhci_cdns6_phy_cfgs[i].val);
- for (i = 0; i < SDHCI_CDNS6_CTRL_CFG_NUM; i++) {
- prop = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
- sdhci_cdns6_ctrl_cfgs[i].property, NULL);
- if (prop)
- sdhci_cdns6_ctrl_cfgs[i].val = *prop;
- }
+ for (i = 0; i < SDHCI_CDNS6_CTRL_CFG_NUM; i++)
+ dev_read_u32(dev, sdhci_cdns6_ctrl_cfgs[i].property, &sdhci_cdns6_ctrl_cfgs[i].val);
/* Switch On the DLL Reset */
sdhci_cdns6_reset_phy_dll(plat, true);
diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c
index 3b86bc9b18c..db4e0129c2e 100644
--- a/drivers/mmc/socfpga_dw_mmc.c
+++ b/drivers/mmc/socfpga_dw_mmc.c
@@ -29,7 +29,9 @@ struct socfpga_dwmci_plat {
/* socfpga implmentation specific driver private data */
struct dwmci_socfpga_priv_data {
+ struct udevice *dev;
struct dwmci_host host;
+ struct clk mmc_clk_ciu;
unsigned int drvsel;
unsigned int smplsel;
};
@@ -51,28 +53,23 @@ static void socfpga_dwmci_reset(struct udevice *dev)
static int socfpga_dwmci_clksel(struct dwmci_host *host)
{
struct dwmci_socfpga_priv_data *priv = host->priv;
+ int ret;
+
u32 sdmmc_mask = ((priv->smplsel & 0x7) << SYSMGR_SDMMC_SMPLSEL_SHIFT) |
((priv->drvsel & 0x7) << SYSMGR_SDMMC_DRVSEL_SHIFT);
- /* Get clock manager base address */
- struct udevice *clkmgr_dev;
- int ret = uclass_get_device_by_name(UCLASS_CLK, "clock-controller@ffd10000", &clkmgr_dev);
-
+ ret = clk_get_by_name(priv->dev, "ciu", &priv->mmc_clk_ciu);
if (ret) {
- printf("Failed to get clkmgr device: %d\n", ret);
+ debug("%s: Failed to get SDMMC clock from dts\n", __func__);
return ret;
}
- fdt_addr_t clkmgr_base = dev_read_addr(clkmgr_dev);
-
- if (clkmgr_base == FDT_ADDR_T_NONE) {
- printf("Failed to read base address from clkmgr DT node\n");
- return -EINVAL;
- }
-
/* Disable SDMMC clock. */
- clrbits_le32(clkmgr_base + CLKMGR_PERPLL_EN,
- CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK);
+ ret = clk_disable(&priv->mmc_clk_ciu);
+ if (ret) {
+ printf("%s: Failed to disable SDMMC clock\n", __func__);
+ return ret;
+ }
debug("%s: drvsel %d smplsel %d\n", __func__,
priv->drvsel, priv->smplsel);
@@ -92,8 +89,11 @@ static int socfpga_dwmci_clksel(struct dwmci_host *host)
#endif
/* Enable SDMMC clock */
- setbits_le32(clkmgr_base + CLKMGR_PERPLL_EN,
- CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK);
+ ret = clk_enable(&priv->mmc_clk_ciu);
+ if (ret) {
+ printf("%s: Failed to enable SDMMC clock\n", __func__);
+ return ret;
+ }
return 0;
}
@@ -169,6 +169,7 @@ static int socfpga_dwmmc_probe(struct udevice *dev)
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
struct dwmci_socfpga_priv_data *priv = dev_get_priv(dev);
struct dwmci_host *host = &priv->host;
+ priv->dev = dev;
int ret;
ret = socfpga_dwmmc_get_clk_rate(dev);
diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c
index 3b682918b03..eda95b72f49 100644
--- a/drivers/mmc/zynq_sdhci.c
+++ b/drivers/mmc/zynq_sdhci.c
@@ -125,7 +125,7 @@ __weak int zynqmp_mmio_write(const u32 address, const u32 mask, const u32 value)
}
__weak int xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2,
- u32 arg3, u32 *ret_payload)
+ u32 arg3, u32 arg4, u32 arg5, u32 *ret_payload)
{
return 0;
}
@@ -331,7 +331,8 @@ static inline int arasan_zynqmp_set_in_tapdelay(u32 node_id, u32 itap_delay)
} else {
return xilinx_pm_request(PM_IOCTL, node_id,
IOCTL_SET_SD_TAPDELAY,
- PM_TAPDELAY_INPUT, itap_delay, NULL);
+ PM_TAPDELAY_INPUT, itap_delay, 0, 0,
+ NULL);
}
return 0;
@@ -350,7 +351,8 @@ static inline int arasan_zynqmp_set_out_tapdelay(u32 node_id, u32 otap_delay)
} else {
return xilinx_pm_request(PM_IOCTL, node_id,
IOCTL_SET_SD_TAPDELAY,
- PM_TAPDELAY_OUTPUT, otap_delay, NULL);
+ PM_TAPDELAY_OUTPUT, otap_delay, 0, 0,
+ NULL);
}
}
@@ -367,7 +369,8 @@ static inline int zynqmp_dll_reset(u32 node_id, u32 type)
SD1_DLL_RST : 0);
} else {
return xilinx_pm_request(PM_IOCTL, node_id,
- IOCTL_SD_DLL_RESET, type, 0, NULL);
+ IOCTL_SD_DLL_RESET, type, 0, 0, 0,
+ NULL);
}
}
@@ -1021,7 +1024,7 @@ static int sdhci_zynqmp_set_dynamic_config(struct arasan_sdhci_priv *priv,
ret = xilinx_pm_request(PM_REQUEST_NODE, priv->node_id,
ZYNQMP_PM_CAPABILITY_ACCESS, ZYNQMP_PM_MAX_QOS,
- ZYNQMP_PM_REQUEST_ACK_NO, NULL);
+ ZYNQMP_PM_REQUEST_ACK_NO, 0, 0, NULL);
if (ret) {
dev_err(dev, "Request node failed for %d\n", priv->node_id);
return ret;
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index e76601a5545..86752b5926d 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -41,6 +41,7 @@ config MTD_BLOCK
config SYS_MTDPARTS_RUNTIME
bool "Allow MTDPARTS to be configured at runtime"
+ depends on !COMPILE_TEST
help
This option allows to call the function board_mtdparts_default to
dynamically build the variables mtdids and mtdparts at runtime.
@@ -166,7 +167,7 @@ config SYS_FLASH_QUIET_TEST
config SYS_FLASH_CHECKSUM
bool "Compute and print flash CRC if 'flashchecksum' is set in the environment"
- depends on MTD_NOR_FLASH
+ depends on (FLASH_CFI_DRIVER && !CFI_FLASH)
help
If the variable flashchecksum is set in the environment, perform a CRC
of the flash and print the value to console.
@@ -222,6 +223,7 @@ config SYS_MAX_FLASH_SECT
config SAMSUNG_ONENAND
bool "Samsung OneNAND driver support"
+ depends on S5P
config USE_SYS_MAX_FLASH_BANKS
bool "Enable Max number of Flash memory banks"
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index 9c8a32bb0a8..c76c10e1ef9 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -11,7 +11,6 @@ config SYS_NAND_SELF_INIT
config SPL_SYS_NAND_SELF_INIT
bool
- depends on !SPL_NAND_SIMPLE
help
This option, if enabled, provides more flexible and linux-like
NAND initialization process, in SPL.
@@ -50,6 +49,8 @@ config SYS_NAND_NO_SUBPAGE_WRITE
config DM_NAND_ATMEL
bool "Support Atmel NAND controller with DM support"
+ depends on ARCH_AT91
+ select ATMEL_EBI
select SYS_NAND_SELF_INIT
imply SYS_NAND_USE_FLASH_BBT
help
@@ -58,6 +59,7 @@ config DM_NAND_ATMEL
config NAND_ATMEL
bool "Support Atmel NAND controller"
+ depends on ARCH_AT91
select SYS_NAND_SELF_INIT
imply SYS_NAND_USE_FLASH_BBT
help
@@ -115,6 +117,7 @@ endif
config NAND_BRCMNAND
bool "Support Broadcom NAND controller"
depends on OF_CONTROL && DM && DM_MTD
+ depends on ARCH_BCMBCA || ARCH_BMIPS || TARGET_BCMNS || TARGET_BCMNS3
select SYS_NAND_SELF_INIT
help
Enable the driver for NAND flash on platforms using a Broadcom NAND
@@ -148,6 +151,7 @@ config NAND_BRCMNAND_IPROC
config NAND_DAVINCI
bool "Support TI Davinci NAND controller"
+ depends on ARCH_DAVINCI || ARCH_KEYSTONE
select SYS_NAND_SELF_INIT if TARGET_DA850EVM
help
Enable this driver for NAND flash controllers available in TI Davinci
@@ -192,7 +196,7 @@ config SPL_NAND_LOAD
config NAND_CADENCE
bool "Support Cadence NAND controller as a DT device"
- depends on OF_CONTROL && DM_MTD
+ depends on OF_CONTROL && DM_MTD && ARCH_SOCFPGA
select SYS_NAND_SELF_INIT
select SPL_SYS_NAND_SELF_INIT
select SPL_NAND_BASE
@@ -234,6 +238,7 @@ config NAND_FSL_ELBC_DT
config NAND_FSL_IFC
bool "Support Freescale Integrated Flash Controller NAND driver"
+ depends on ARCH_LS1021A || FSL_LSCH2 || FSL_LSCH3 || PPC
select TPL_SYS_NAND_SELF_INIT if TPL_NAND_SUPPORT
select TPL_NAND_INIT if TPL && !TPL_FRAMEWORK
select SPL_SYS_NAND_SELF_INIT
@@ -257,13 +262,14 @@ config NAND_KMETER1
config NAND_LPC32XX_MLC
bool "Support LPC32XX_MLC controller"
+ depends on ARCH_LPC32XX
select SYS_NAND_SELF_INIT
help
Enable the LPC32XX MLC NAND controller.
config NAND_OMAP_GPMC
bool "Support OMAP GPMC NAND controller"
- depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || ARCH_K3
+ depends on ARCH_OMAP2PLUS || ARCH_K3
select SYS_NAND_SELF_INIT if ARCH_K3
select SPL_NAND_INIT if ARCH_K3
select SPL_SYS_NAND_SELF_INIT if ARCH_K3
@@ -431,6 +437,7 @@ endif
config NAND_PXA3XX
bool "Support for NAND on PXA3xx and Armada 370/XP/38x"
+ depends on ARCH_MVEBU
select SYS_NAND_SELF_INIT
select DM_MTD
select REGMAP
@@ -446,7 +453,6 @@ config NAND_SANDBOX
select SYS_NAND_SELF_INIT
select SPL_SYS_NAND_SELF_INIT
select SPL_NAND_INIT
- select SYS_NAND_SOFT_ECC
select BCH
select NAND_ECC_BCH
imply CMD_NAND
@@ -490,7 +496,7 @@ endif
config NAND_ARASAN
bool "Configure Arasan Nand"
select SYS_NAND_SELF_INIT
- depends on DM_MTD
+ depends on DM_MTD && ARCH_ZYNQMP
imply CMD_NAND
help
This enables Nand driver support for Arasan nand flash
@@ -553,6 +559,7 @@ endif
config NAND_ZYNQ
bool "Support for Zynq Nand controller"
+ depends on ARCH_ZYNQ
select SPL_SYS_NAND_SELF_INIT
select SYS_NAND_SELF_INIT
select DM_MTD
@@ -662,7 +669,6 @@ config SYS_NAND_PAGE_SIZE
MVEBU_SPL_BOOT_DEVICE_NAND || \
(NAND_ATMEL && SPL_NAND_SUPPORT) || \
SPL_GENERATE_ATMEL_PMECC_HEADER || NAND_SANDBOX || NAND_CADENCE
- depends on !NAND_MXS && !NAND_DENALI_DT && !NAND_LPC32XX_MLC && !NAND_MT7621
help
Number of data bytes in one page for the NAND chip on the
board, not including the OOB area.
@@ -672,7 +678,6 @@ config SYS_NAND_OOBSIZE
depends on ARCH_SUNXI || NAND_OMAP_GPMC || \
SPL_NAND_SIMPLE || (NAND_MXC && SPL_NAND_SUPPORT) || \
(NAND_ATMEL && SPL_NAND_SUPPORT) || SPL_GENERATE_ATMEL_PMECC_HEADER
- depends on !NAND_MXS && !NAND_DENALI_DT && !NAND_LPC32XX_MLC
help
Number of bytes in the Out-Of-Band area for the NAND chip on
the board.
diff --git a/drivers/mtd/nand/raw/am335x_spl_bch.c b/drivers/mtd/nand/raw/am335x_spl_bch.c
index 4b50f351d35..a77206d3815 100644
--- a/drivers/mtd/nand/raw/am335x_spl_bch.c
+++ b/drivers/mtd/nand/raw/am335x_spl_bch.c
@@ -212,6 +212,8 @@ void nand_init(void)
if (nand_chip.select_chip)
nand_chip.select_chip(mtd, 0);
+ mtd->writesize = CONFIG_SYS_NAND_PAGE_SIZE;
+
/* NAND chip may require reset after power-on */
nand_command(0, 0, 0, NAND_CMD_RESET);
}
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index d3d1b93947b..48e3685d995 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -566,7 +566,7 @@ void nand_wait_ready(struct mtd_info *mtd)
break;
}
- if (!chip->dev_ready(mtd))
+ if (!chip->dev_ready || !chip->dev_ready(mtd))
pr_warn("timeout while waiting for chip to become ready\n");
}
EXPORT_SYMBOL_GPL(nand_wait_ready);
diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
index 65b836b34ca..a7a0b2cb4b9 100644
--- a/drivers/mtd/nand/spi/Makefile
+++ b/drivers/mtd/nand/spi/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
-spinand-objs := core.o esmt.o gigadevice.o macronix.o micron.o paragon.o
-spinand-objs += toshiba.o winbond.o xtx.o
+spinand-objs := core.o otp.o
+spinand-objs += alliancememory.o ato.o esmt.o fmsh.o foresee.o gigadevice.o macronix.o
+spinand-objs += micron.o paragon.o skyhigh.o toshiba.o winbond.o xtx.o
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
diff --git a/drivers/mtd/nand/spi/alliancememory.c b/drivers/mtd/nand/spi/alliancememory.c
new file mode 100644
index 00000000000..a3772b8c2f0
--- /dev/null
+++ b/drivers/mtd/nand/spi/alliancememory.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Author: Mario Kicherer <dev@kicherer.org>
+ */
+
+#ifndef __UBOOT__
+#include <linux/device.h>
+#include <linux/kernel.h>
+#endif
+#include <linux/mtd/spinand.h>
+
+#define SPINAND_MFR_ALLIANCEMEMORY 0x52
+
+#define AM_STATUS_ECC_BITMASK (3 << 4)
+
+#define AM_STATUS_ECC_NONE_DETECTED (0 << 4)
+#define AM_STATUS_ECC_CORRECTED (1 << 4)
+#define AM_STATUS_ECC_ERRORED (2 << 4)
+#define AM_STATUS_ECC_MAX_CORRECTED (3 << 4)
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
+
+static int am_get_eccsize(struct mtd_info *mtd)
+{
+ if (mtd->oobsize == 64)
+ return 0x20;
+ else if (mtd->oobsize == 128)
+ return 0x38;
+ else if (mtd->oobsize == 256)
+ return 0x70;
+ else
+ return -EINVAL;
+}
+
+static int am_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ int ecc_bytes;
+
+ ecc_bytes = am_get_eccsize(mtd);
+ if (ecc_bytes < 0)
+ return ecc_bytes;
+
+ region->offset = mtd->oobsize - ecc_bytes;
+ region->length = ecc_bytes;
+
+ return 0;
+}
+
+static int am_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ int ecc_bytes;
+
+ if (section)
+ return -ERANGE;
+
+ ecc_bytes = am_get_eccsize(mtd);
+ if (ecc_bytes < 0)
+ return ecc_bytes;
+
+ /*
+ * It is unclear how many bytes are used for the bad block marker. We
+ * reserve the common two bytes here.
+ *
+ * The free area in this kind of flash is divided into chunks where the
+ * first 4 bytes of each chunk are unprotected. The number of chunks
+ * depends on the specific model. The models with 4096+256 bytes pages
+ * have 8 chunks, the others 4 chunks.
+ */
+
+ region->offset = 2;
+ region->length = mtd->oobsize - 2 - ecc_bytes;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops am_ooblayout = {
+ .ecc = am_ooblayout_ecc,
+ .rfree = am_ooblayout_free,
+};
+
+static int am_ecc_get_status(struct spinand_device *spinand, u8 status)
+{
+ switch (status & AM_STATUS_ECC_BITMASK) {
+ case AM_STATUS_ECC_NONE_DETECTED:
+ return 0;
+
+ case AM_STATUS_ECC_CORRECTED:
+ /*
+ * use oobsize to determine the flash model and the maximum of
+ * correctable errors and return maximum - 1 by convention
+ */
+ if (spinand->base.mtd->oobsize == 64)
+ return 3;
+ else
+ return 7;
+
+ case AM_STATUS_ECC_ERRORED:
+ return -EBADMSG;
+
+ case AM_STATUS_ECC_MAX_CORRECTED:
+ /*
+ * use oobsize to determine the flash model and the maximum of
+ * correctable errors
+ */
+ if (spinand->base.mtd->oobsize == 64)
+ return 4;
+ else
+ return 8;
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static const struct spinand_info alliancememory_spinand_table[] = {
+ SPINAND_INFO("AS5F34G04SND",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x2f),
+ NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1),
+ NAND_ECCREQ(4, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&am_ooblayout,
+ am_ecc_get_status)),
+};
+
+static const struct spinand_manufacturer_ops alliancememory_spinand_manuf_ops = {
+};
+
+const struct spinand_manufacturer alliancememory_spinand_manufacturer = {
+ .id = SPINAND_MFR_ALLIANCEMEMORY,
+ .name = "AllianceMemory",
+ .chips = alliancememory_spinand_table,
+ .nchips = ARRAY_SIZE(alliancememory_spinand_table),
+ .ops = &alliancememory_spinand_manuf_ops,
+};
diff --git a/drivers/mtd/nand/spi/ato.c b/drivers/mtd/nand/spi/ato.c
new file mode 100644
index 00000000000..a726df3eb98
--- /dev/null
+++ b/drivers/mtd/nand/spi/ato.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 Aidan MacDonald
+ *
+ * Author: Aidan MacDonald <aidanmacdonald.0x0@gmail.com>
+ */
+
+#ifndef __UBOOT__
+#include <linux/device.h>
+#include <linux/kernel.h>
+#endif
+#include <linux/mtd/spinand.h>
+
+
+#define SPINAND_MFR_ATO 0x9b
+
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
+
+
+static int ato25d1ga_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 3)
+ return -ERANGE;
+
+ region->offset = (16 * section) + 8;
+ region->length = 8;
+ return 0;
+}
+
+static int ato25d1ga_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 3)
+ return -ERANGE;
+
+ if (section) {
+ region->offset = (16 * section);
+ region->length = 8;
+ } else {
+ /* first byte of section 0 is reserved for the BBM */
+ region->offset = 1;
+ region->length = 7;
+ }
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops ato25d1ga_ooblayout = {
+ .ecc = ato25d1ga_ooblayout_ecc,
+ .rfree = ato25d1ga_ooblayout_free,
+};
+
+
+static const struct spinand_info ato_spinand_table[] = {
+ SPINAND_INFO("ATO25D1GA",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x12),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(1, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&ato25d1ga_ooblayout, NULL)),
+};
+
+static const struct spinand_manufacturer_ops ato_spinand_manuf_ops = {
+};
+
+const struct spinand_manufacturer ato_spinand_manufacturer = {
+ .id = SPINAND_MFR_ATO,
+ .name = "ATO",
+ .chips = ato_spinand_table,
+ .nchips = ARRAY_SIZE(ato_spinand_table),
+ .ops = &ato_spinand_manuf_ops,
+};
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 3a1e7e18736..14af4264612 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -32,6 +32,7 @@
#include <linux/bug.h>
#include <linux/mtd/spinand.h>
#include <linux/printk.h>
+#include <linux/delay.h>
#endif
struct spinand_plat {
@@ -41,24 +42,9 @@ struct spinand_plat {
/* SPI NAND index visible in MTD names */
static int spi_nand_idx;
-static void spinand_cache_op_adjust_colum(struct spinand_device *spinand,
- const struct nand_page_io_req *req,
- u16 *column)
+int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
{
- struct nand_device *nand = spinand_to_nand(spinand);
- unsigned int shift;
-
- if (nand->memorg.planes_per_lun < 2)
- return;
-
- /* The plane number is passed in MSB just above the column address */
- shift = fls(nand->memorg.pagesize);
- *column |= req->pos.plane << shift;
-}
-
-static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
-{
- struct spi_mem_op op = SPINAND_GET_FEATURE_OP(reg,
+ struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(reg,
spinand->scratchbuf);
int ret;
@@ -70,9 +56,9 @@ static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
return 0;
}
-static int spinand_write_reg_op(struct spinand_device *spinand, u8 reg, u8 val)
+int spinand_write_reg_op(struct spinand_device *spinand, u8 reg, u8 val)
{
- struct spi_mem_op op = SPINAND_SET_FEATURE_OP(reg,
+ struct spi_mem_op op = SPINAND_SET_FEATURE_1S_1S_1S_OP(reg,
spinand->scratchbuf);
*spinand->scratchbuf = val;
@@ -174,20 +160,12 @@ int spinand_select_target(struct spinand_device *spinand, unsigned int target)
return 0;
}
-static int spinand_init_cfg_cache(struct spinand_device *spinand)
+static int spinand_read_cfg(struct spinand_device *spinand)
{
struct nand_device *nand = spinand_to_nand(spinand);
- struct udevice *dev = spinand->slave->dev;
unsigned int target;
int ret;
- spinand->cfg_cache = devm_kzalloc(dev,
- sizeof(*spinand->cfg_cache) *
- nand->memorg.ntargets,
- GFP_KERNEL);
- if (!spinand->cfg_cache)
- return -ENOMEM;
-
for (target = 0; target < nand->memorg.ntargets; target++) {
ret = spinand_select_target(spinand, target);
if (ret)
@@ -206,6 +184,21 @@ static int spinand_init_cfg_cache(struct spinand_device *spinand)
return 0;
}
+static int spinand_init_cfg_cache(struct spinand_device *spinand)
+{
+ struct nand_device *nand = spinand_to_nand(spinand);
+ struct udevice *dev = spinand->slave->dev;
+
+ spinand->cfg_cache = devm_kcalloc(dev,
+ nand->memorg.ntargets,
+ sizeof(*spinand->cfg_cache),
+ GFP_KERNEL);
+ if (!spinand->cfg_cache)
+ return -ENOMEM;
+
+ return 0;
+}
+
static int spinand_init_quad_enable(struct spinand_device *spinand)
{
bool enable = false;
@@ -229,9 +222,144 @@ static int spinand_ecc_enable(struct spinand_device *spinand,
enable ? CFG_ECC_ENABLE : 0);
}
-static int spinand_write_enable_op(struct spinand_device *spinand)
+
+static int spinand_cont_read_enable(struct spinand_device *spinand,
+ bool enable)
+{
+ return spinand->set_cont_read(spinand, enable);
+}
+
+static int spinand_check_ecc_status(struct spinand_device *spinand, u8 status)
+{
+ struct nand_device *nand = spinand_to_nand(spinand);
+
+ if (spinand->eccinfo.get_status)
+ return spinand->eccinfo.get_status(spinand, status);
+
+ switch (status & STATUS_ECC_MASK) {
+ case STATUS_ECC_NO_BITFLIPS:
+ return 0;
+
+ case STATUS_ECC_HAS_BITFLIPS:
+ /*
+ * We have no way to know exactly how many bitflips have been
+ * fixed, so let's return the maximum possible value so that
+ * wear-leveling layers move the data immediately.
+ */
+ return nanddev_get_ecc_conf(nand)->strength;
+
+ case STATUS_ECC_UNCOR_ERROR:
+ return -EBADMSG;
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int spinand_noecc_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ return -ERANGE;
+}
+
+static int spinand_noecc_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section)
+ return -ERANGE;
+
+ /* Reserve 2 bytes for the BBM. */
+ region->offset = 2;
+ region->length = 62;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops spinand_noecc_ooblayout = {
+ .ecc = spinand_noecc_ooblayout_ecc,
+ .rfree = spinand_noecc_ooblayout_free,
+};
+
+static int spinand_ondie_ecc_init_ctx(struct nand_device *nand)
+{
+ struct spinand_device *spinand = nand_to_spinand(nand);
+ struct mtd_info *mtd = nanddev_to_mtd(nand);
+
+ if (spinand->eccinfo.ooblayout)
+ mtd_set_ooblayout(mtd, spinand->eccinfo.ooblayout);
+ else
+ mtd_set_ooblayout(mtd, &spinand_noecc_ooblayout);
+
+ return 0;
+}
+
+static void spinand_ondie_ecc_cleanup_ctx(struct nand_device *nand)
+{
+}
+
+static int spinand_ondie_ecc_prepare_io_req(struct nand_device *nand,
+ struct nand_page_io_req *req)
+{
+ struct spinand_device *spinand = nand_to_spinand(nand);
+ bool enable = (req->mode != MTD_OPS_RAW);
+
+ if (!enable && spinand->flags & SPINAND_NO_RAW_ACCESS)
+ return -EOPNOTSUPP;
+
+ memset(spinand->oobbuf, 0xff, nanddev_per_page_oobsize(nand));
+
+ /* Only enable or disable the engine */
+ return spinand_ecc_enable(spinand, enable);
+}
+
+static int spinand_ondie_ecc_finish_io_req(struct nand_device *nand,
+ struct nand_page_io_req *req)
+{
+ struct spinand_device *spinand = nand_to_spinand(nand);
+ struct mtd_info *mtd = spinand_to_mtd(spinand);
+ int ret;
+
+ if (req->mode == MTD_OPS_RAW)
+ return 0;
+
+ /* Nothing to do when finishing a page write */
+ if (req->type == NAND_PAGE_WRITE)
+ return 0;
+
+ /* Finish a page read: check the status, report errors/bitflips */
+ ret = spinand_check_ecc_status(spinand, spinand->last_wait_status);
+ if (ret == -EBADMSG) {
+ mtd->ecc_stats.failed++;
+ } else if (ret > 0) {
+ unsigned int pages;
+
+ /*
+ * Continuous reads don't allow us to get the detail,
+ * so we may exagerate the actual number of corrected bitflips.
+ */
+ if (!req->continuous)
+ pages = 1;
+ else
+ pages = req->datalen / nanddev_page_size(nand);
+
+ mtd->ecc_stats.corrected += ret * pages;
+ }
+
+ return ret;
+}
+
+static void spinand_ondie_ecc_save_status(struct nand_device *nand, u8 status)
+{
+ struct spinand_device *spinand = nand_to_spinand(nand);
+
+ spinand->last_wait_status = status;
+}
+
+int spinand_write_enable_op(struct spinand_device *spinand)
{
- struct spi_mem_op op = SPINAND_WR_EN_DIS_OP(true);
+ struct spi_mem_op op = SPINAND_WR_EN_DIS_1S_0_0_OP(true);
return spi_mem_exec_op(spinand->slave, &op);
}
@@ -241,7 +369,7 @@ static int spinand_load_page_op(struct spinand_device *spinand,
{
struct nand_device *nand = spinand_to_nand(spinand);
unsigned int row = nanddev_pos_to_row(nand, &req->pos);
- struct spi_mem_op op = SPINAND_PAGE_READ_OP(row);
+ struct spi_mem_op op = SPINAND_PAGE_READ_1S_1S_0_OP(row);
return spi_mem_exec_op(spinand->slave, &op);
}
@@ -249,27 +377,25 @@ static int spinand_load_page_op(struct spinand_device *spinand,
static int spinand_read_from_cache_op(struct spinand_device *spinand,
const struct nand_page_io_req *req)
{
- struct spi_mem_op op = *spinand->op_templates.read_cache;
struct nand_device *nand = spinand_to_nand(spinand);
- struct mtd_info *mtd = nanddev_to_mtd(nand);
- struct nand_page_io_req adjreq = *req;
+ struct mtd_info *mtd = spinand_to_mtd(spinand);
+ struct spi_mem_dirmap_desc *rdesc;
unsigned int nbytes = 0;
void *buf = NULL;
u16 column = 0;
- int ret;
+ ssize_t ret;
if (req->datalen) {
- adjreq.datalen = nanddev_page_size(nand);
- adjreq.dataoffs = 0;
- adjreq.databuf.in = spinand->databuf;
buf = spinand->databuf;
- nbytes = adjreq.datalen;
+ if (!req->continuous)
+ nbytes = nanddev_page_size(nand);
+ else
+ nbytes = round_up(req->dataoffs + req->datalen,
+ nanddev_page_size(nand));
+ column = 0;
}
if (req->ooblen) {
- adjreq.ooblen = nanddev_per_page_oobsize(nand);
- adjreq.ooboffs = 0;
- adjreq.oobbuf.in = spinand->oobbuf;
nbytes += nanddev_per_page_oobsize(nand);
if (!buf) {
buf = spinand->oobbuf;
@@ -277,28 +403,40 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand,
}
}
- spinand_cache_op_adjust_colum(spinand, &adjreq, &column);
- op.addr.val = column;
+ if (req->mode == MTD_OPS_RAW)
+ rdesc = spinand->dirmaps[req->pos.plane].rdesc;
+ else
+ rdesc = spinand->dirmaps[req->pos.plane].rdesc_ecc;
+
+ if (spinand->flags & SPINAND_HAS_READ_PLANE_SELECT_BIT)
+ column |= req->pos.plane << fls(nanddev_page_size(nand));
- /*
- * Some controllers are limited in term of max RX data size. In this
- * case, just repeat the READ_CACHE operation after updating the
- * column.
- */
while (nbytes) {
- op.data.buf.in = buf;
- op.data.nbytes = nbytes;
- ret = spi_mem_adjust_op_size(spinand->slave, &op);
- if (ret)
+ ret = spi_mem_dirmap_read(rdesc, column, nbytes, buf);
+ if (ret < 0)
return ret;
- ret = spi_mem_exec_op(spinand->slave, &op);
- if (ret)
- return ret;
+ if (!ret || ret > nbytes)
+ return -EIO;
- buf += op.data.nbytes;
- nbytes -= op.data.nbytes;
- op.addr.val += op.data.nbytes;
+ nbytes -= ret;
+ column += ret;
+ buf += ret;
+
+ /*
+ * Dirmap accesses are allowed to toggle the CS.
+ * Toggling the CS during a continuous read is forbidden.
+ */
+ if (nbytes && req->continuous) {
+ /*
+ * Spi controller with broken support of continuous
+ * reading was detected. Disable future use of
+ * continuous reading and return -EAGAIN to retry
+ * reading within regular mode.
+ */
+ spinand->cont_read_possible = false;
+ return -EAGAIN;
+ }
}
if (req->datalen)
@@ -322,14 +460,12 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand,
static int spinand_write_to_cache_op(struct spinand_device *spinand,
const struct nand_page_io_req *req)
{
- struct spi_mem_op op = *spinand->op_templates.write_cache;
struct nand_device *nand = spinand_to_nand(spinand);
- struct mtd_info *mtd = nanddev_to_mtd(nand);
- struct nand_page_io_req adjreq = *req;
- unsigned int nbytes = 0;
- void *buf = NULL;
- u16 column = 0;
- int ret;
+ struct mtd_info *mtd = spinand_to_mtd(spinand);
+ struct spi_mem_dirmap_desc *wdesc;
+ unsigned int nbytes, column = 0;
+ void *buf = spinand->databuf;
+ ssize_t ret;
/*
* Looks like PROGRAM LOAD (AKA write cache) does not necessarily reset
@@ -337,20 +473,16 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand,
* must fill the page cache entirely even if we only want to program
* the data portion of the page, otherwise we might corrupt the BBM or
* user data previously programmed in OOB area.
+ *
+ * Only reset the data buffer manually, the OOB buffer is prepared by
+ * ECC engines ->prepare_io_req() callback.
*/
- memset(spinand->databuf, 0xff,
- nanddev_page_size(nand) +
- nanddev_per_page_oobsize(nand));
+ nbytes = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand);
+ memset(spinand->databuf, 0xff, nanddev_page_size(nand));
- if (req->datalen) {
+ if (req->datalen)
memcpy(spinand->databuf + req->dataoffs, req->databuf.out,
req->datalen);
- adjreq.dataoffs = 0;
- adjreq.datalen = nanddev_page_size(nand);
- adjreq.databuf.out = spinand->databuf;
- nbytes = adjreq.datalen;
- buf = spinand->databuf;
- }
if (req->ooblen) {
if (req->mode == MTD_OPS_AUTO_OOB)
@@ -361,52 +493,27 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand,
else
memcpy(spinand->oobbuf + req->ooboffs, req->oobbuf.out,
req->ooblen);
-
- adjreq.ooblen = nanddev_per_page_oobsize(nand);
- adjreq.ooboffs = 0;
- nbytes += nanddev_per_page_oobsize(nand);
- if (!buf) {
- buf = spinand->oobbuf;
- column = nanddev_page_size(nand);
- }
}
- spinand_cache_op_adjust_colum(spinand, &adjreq, &column);
+ if (req->mode == MTD_OPS_RAW)
+ wdesc = spinand->dirmaps[req->pos.plane].wdesc;
+ else
+ wdesc = spinand->dirmaps[req->pos.plane].wdesc_ecc;
- op = *spinand->op_templates.write_cache;
- op.addr.val = column;
+ if (spinand->flags & SPINAND_HAS_PROG_PLANE_SELECT_BIT)
+ column |= req->pos.plane << fls(nanddev_page_size(nand));
- /*
- * Some controllers are limited in term of max TX data size. In this
- * case, split the operation into one LOAD CACHE and one or more
- * LOAD RANDOM CACHE.
- */
while (nbytes) {
- op.data.buf.out = buf;
- op.data.nbytes = nbytes;
-
- ret = spi_mem_adjust_op_size(spinand->slave, &op);
- if (ret)
- return ret;
-
- ret = spi_mem_exec_op(spinand->slave, &op);
- if (ret)
+ ret = spi_mem_dirmap_write(wdesc, column, nbytes, buf);
+ if (ret < 0)
return ret;
- buf += op.data.nbytes;
- nbytes -= op.data.nbytes;
- op.addr.val += op.data.nbytes;
+ if (!ret || ret > nbytes)
+ return -EIO;
- /*
- * We need to use the RANDOM LOAD CACHE operation if there's
- * more than one iteration, because the LOAD operation resets
- * the cache to 0xff.
- */
- if (nbytes) {
- column = op.addr.val;
- op = *spinand->op_templates.update_cache;
- op.addr.val = column;
- }
+ nbytes -= ret;
+ column += ret;
+ buf += ret;
}
return 0;
@@ -417,7 +524,7 @@ static int spinand_program_op(struct spinand_device *spinand,
{
struct nand_device *nand = spinand_to_nand(spinand);
unsigned int row = nanddev_pos_to_row(nand, &req->pos);
- struct spi_mem_op op = SPINAND_PROG_EXEC_OP(row);
+ struct spi_mem_op op = SPINAND_PROG_EXEC_1S_1S_0_OP(row);
return spi_mem_exec_op(spinand->slave, &op);
}
@@ -425,28 +532,48 @@ static int spinand_program_op(struct spinand_device *spinand,
static int spinand_erase_op(struct spinand_device *spinand,
const struct nand_pos *pos)
{
- struct nand_device *nand = &spinand->base;
+ struct nand_device *nand = spinand_to_nand(spinand);
unsigned int row = nanddev_pos_to_row(nand, pos);
- struct spi_mem_op op = SPINAND_BLK_ERASE_OP(row);
+ struct spi_mem_op op = SPINAND_BLK_ERASE_1S_1S_0_OP(row);
return spi_mem_exec_op(spinand->slave, &op);
}
-static int spinand_wait(struct spinand_device *spinand, u8 *s)
+/**
+ * spinand_wait() - Poll memory device status
+ * @spinand: the spinand device
+ * @initial_delay_us: delay in us before starting to poll
+ * @poll_delay_us: time to sleep between reads in us
+ * @s: the pointer to variable to store the value of REG_STATUS
+ *
+ * This function polls a status register (REG_STATUS) and returns when
+ * the STATUS_READY bit is 0 or when the timeout has expired.
+ *
+ * Return: 0 on success, a negative error code otherwise.
+ */
+int spinand_wait(struct spinand_device *spinand,
+ unsigned long initial_delay_us,
+ unsigned long poll_delay_us,
+ u8 *s)
{
unsigned long start, stop;
u8 status;
int ret;
+ udelay(initial_delay_us);
start = get_timer(0);
- stop = 400;
+ stop = SPINAND_WAITRDY_TIMEOUT_MS;
do {
+ schedule();
+
ret = spinand_read_status(spinand, &status);
if (ret)
return ret;
if (!(status & STATUS_BUSY))
goto out;
+
+ udelay(poll_delay_us);
} while (get_timer(start) < stop);
/*
@@ -467,9 +594,8 @@ out:
static int spinand_read_id_op(struct spinand_device *spinand, u8 naddr,
u8 ndummy, u8 *buf)
{
- struct spi_mem_op op = SPINAND_READID_OP(naddr, ndummy,
- spinand->scratchbuf,
- SPINAND_MAX_ID_LEN);
+ struct spi_mem_op op = SPINAND_READID_1S_1S_1S_OP(
+ naddr, ndummy, spinand->scratchbuf, SPINAND_MAX_ID_LEN);
int ret;
ret = spi_mem_exec_op(spinand->slave, &op);
@@ -481,14 +607,17 @@ static int spinand_read_id_op(struct spinand_device *spinand, u8 naddr,
static int spinand_reset_op(struct spinand_device *spinand)
{
- struct spi_mem_op op = SPINAND_RESET_OP;
+ struct spi_mem_op op = SPINAND_RESET_1S_0_0_OP;
int ret;
ret = spi_mem_exec_op(spinand->slave, &op);
if (ret)
return ret;
- return spinand_wait(spinand, NULL);
+ return spinand_wait(spinand,
+ SPINAND_RESET_INITIAL_DELAY_US,
+ SPINAND_RESET_POLL_DELAY_US,
+ NULL);
}
static int spinand_lock_block(struct spinand_device *spinand, u8 lock)
@@ -496,66 +625,64 @@ static int spinand_lock_block(struct spinand_device *spinand, u8 lock)
return spinand_write_reg_op(spinand, REG_BLOCK_LOCK, lock);
}
-static int spinand_check_ecc_status(struct spinand_device *spinand, u8 status)
+/**
+ * spinand_read_page() - Read a page
+ * @spinand: the spinand device
+ * @req: the I/O request
+ *
+ * Return: 0 or a positive number of bitflips corrected on success.
+ * A negative error code otherwise.
+ */
+int spinand_read_page(struct spinand_device *spinand,
+ const struct nand_page_io_req *req)
{
struct nand_device *nand = spinand_to_nand(spinand);
-
- if (spinand->eccinfo.get_status)
- return spinand->eccinfo.get_status(spinand, status);
-
- switch (status & STATUS_ECC_MASK) {
- case STATUS_ECC_NO_BITFLIPS:
- return 0;
-
- case STATUS_ECC_HAS_BITFLIPS:
- /*
- * We have no way to know exactly how many bitflips have been
- * fixed, so let's return the maximum possible value so that
- * wear-leveling layers move the data immediately.
- */
- return nand->eccreq.strength;
-
- case STATUS_ECC_UNCOR_ERROR:
- return -EBADMSG;
-
- default:
- break;
- }
-
- return -EINVAL;
-}
-
-static int spinand_read_page(struct spinand_device *spinand,
- const struct nand_page_io_req *req,
- bool ecc_enabled)
-{
u8 status;
int ret;
+ ret = spinand_ondie_ecc_prepare_io_req(nand, (struct nand_page_io_req *)req);
+ if (ret)
+ return ret;
+
ret = spinand_load_page_op(spinand, req);
if (ret)
return ret;
- ret = spinand_wait(spinand, &status);
+ ret = spinand_wait(spinand,
+ SPINAND_READ_INITIAL_DELAY_US,
+ SPINAND_READ_POLL_DELAY_US,
+ &status);
if (ret < 0)
return ret;
+ spinand_ondie_ecc_save_status(nand, status);
+
ret = spinand_read_from_cache_op(spinand, req);
if (ret)
return ret;
- if (!ecc_enabled)
- return 0;
-
- return spinand_check_ecc_status(spinand, status);
+ return spinand_ondie_ecc_finish_io_req(nand, (struct nand_page_io_req *)req);
}
-static int spinand_write_page(struct spinand_device *spinand,
- const struct nand_page_io_req *req)
+/**
+ * spinand_write_page() - Write a page
+ * @spinand: the spinand device
+ * @req: the I/O request
+ *
+ * Return: 0 or a positive number of bitflips corrected on success.
+ * A negative error code otherwise.
+ */
+int spinand_write_page(struct spinand_device *spinand,
+ const struct nand_page_io_req *req)
{
+ struct nand_device *nand = spinand_to_nand(spinand);
u8 status;
int ret;
+ ret = spinand_ondie_ecc_prepare_io_req(nand, (struct nand_page_io_req *)req);
+ if (ret)
+ return ret;
+
ret = spinand_write_enable_op(spinand);
if (ret)
return ret;
@@ -568,63 +695,234 @@ static int spinand_write_page(struct spinand_device *spinand,
if (ret)
return ret;
- ret = spinand_wait(spinand, &status);
- if (!ret && (status & STATUS_PROG_FAILED))
- ret = -EIO;
+ ret = spinand_wait(spinand,
+ SPINAND_WRITE_INITIAL_DELAY_US,
+ SPINAND_WRITE_POLL_DELAY_US,
+ &status);
+ if (ret)
+ return ret;
- return ret;
+ if (status & STATUS_PROG_FAILED)
+ return -EIO;
+
+ return spinand_ondie_ecc_finish_io_req(nand, (struct nand_page_io_req *)req);
}
-static int spinand_mtd_read(struct mtd_info *mtd, loff_t from,
- struct mtd_oob_ops *ops)
+static int spinand_mtd_regular_page_read(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops,
+ unsigned int *max_bitflips)
{
struct spinand_device *spinand = mtd_to_spinand(mtd);
struct nand_device *nand = mtd_to_nanddev(mtd);
- unsigned int max_bitflips = 0;
+ struct mtd_ecc_stats old_stats;
struct nand_io_iter iter;
- bool enable_ecc = false;
+ bool disable_ecc = false;
bool ecc_failed = false;
- int ret = 0;
+ unsigned int retry_mode = 0;
+ int ret;
- if (ops->mode != MTD_OPS_RAW && spinand->eccinfo.ooblayout)
- enable_ecc = true;
+ old_stats = mtd->ecc_stats;
-#ifndef __UBOOT__
- mutex_lock(&spinand->lock);
-#endif
+ if (ops->mode == MTD_OPS_RAW || !mtd->ooblayout)
+ disable_ecc = true;
- nanddev_io_for_each_page(nand, from, ops, &iter) {
+ nanddev_io_for_each_page(nand, NAND_PAGE_READ, from, ops, &iter) {
schedule();
- ret = spinand_select_target(spinand, iter.req.pos.target);
- if (ret)
- break;
+ if (disable_ecc)
+ iter.req.mode = MTD_OPS_RAW;
- ret = spinand_ecc_enable(spinand, enable_ecc);
+ ret = spinand_select_target(spinand, iter.req.pos.target);
if (ret)
break;
- ret = spinand_read_page(spinand, &iter.req, enable_ecc);
+read_retry:
+ ret = spinand_read_page(spinand, &iter.req);
if (ret < 0 && ret != -EBADMSG)
break;
- if (ret == -EBADMSG) {
+ if (ret == -EBADMSG && spinand->set_read_retry) {
+ if (spinand->read_retries && (++retry_mode <= spinand->read_retries)) {
+ ret = spinand->set_read_retry(spinand, retry_mode);
+ if (ret < 0) {
+ spinand->set_read_retry(spinand, 0);
+ return ret;
+ }
+
+ /* Reset ecc_stats; retry */
+ mtd->ecc_stats = old_stats;
+ goto read_retry;
+ } else {
+ /* No more retry modes; real failure */
+ ecc_failed = true;
+ }
+ } else if (ret == -EBADMSG) {
ecc_failed = true;
- mtd->ecc_stats.failed++;
} else {
- mtd->ecc_stats.corrected += ret;
- max_bitflips = max_t(unsigned int, max_bitflips, ret);
+ *max_bitflips = max_t(unsigned int, *max_bitflips, ret);
}
ret = 0;
ops->retlen += iter.req.datalen;
ops->oobretlen += iter.req.ooblen;
+
+ /* Reset to retry mode 0 */
+ if (retry_mode) {
+ retry_mode = 0;
+ ret = spinand->set_read_retry(spinand, retry_mode);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ if (ecc_failed && !ret)
+ ret = -EBADMSG;
+
+ return ret;
+}
+
+static int spinand_mtd_continuous_page_read(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops,
+ unsigned int *max_bitflips)
+{
+ struct spinand_device *spinand = mtd_to_spinand(mtd);
+ struct nand_device *nand = mtd_to_nanddev(mtd);
+ struct nand_io_iter iter;
+ u8 status;
+ int ret;
+
+ ret = spinand_cont_read_enable(spinand, true);
+ if (ret)
+ return ret;
+
+ /*
+ * The cache is divided into two halves. While one half of the cache has
+ * the requested data, the other half is loaded with the next chunk of data.
+ * Therefore, the host can read out the data continuously from page to page.
+ * Each data read must be a multiple of 4-bytes and full pages should be read;
+ * otherwise, the data output might get out of sequence from one read command
+ * to another.
+ */
+ nanddev_io_for_each_block(nand, NAND_PAGE_READ, from, ops, &iter) {
+ schedule();
+ ret = spinand_select_target(spinand, iter.req.pos.target);
+ if (ret)
+ goto end_cont_read;
+
+ ret = spinand_ondie_ecc_prepare_io_req(nand, &iter.req);
+ if (ret)
+ goto end_cont_read;
+
+ ret = spinand_load_page_op(spinand, &iter.req);
+ if (ret)
+ goto end_cont_read;
+
+ ret = spinand_wait(spinand, SPINAND_READ_INITIAL_DELAY_US,
+ SPINAND_READ_POLL_DELAY_US, NULL);
+ if (ret < 0)
+ goto end_cont_read;
+
+ ret = spinand_read_from_cache_op(spinand, &iter.req);
+ if (ret)
+ goto end_cont_read;
+
+ ops->retlen += iter.req.datalen;
+
+ ret = spinand_read_status(spinand, &status);
+ if (ret)
+ goto end_cont_read;
+
+ spinand_ondie_ecc_save_status(nand, status);
+
+ ret = spinand_ondie_ecc_finish_io_req(nand, &iter.req);
+ if (ret < 0)
+ goto end_cont_read;
+
+ *max_bitflips = max_t(unsigned int, *max_bitflips, ret);
+ ret = 0;
+ }
+
+end_cont_read:
+ /*
+ * Once all the data has been read out, the host can either pull CS#
+ * high and wait for tRST or manually clear the bit in the configuration
+ * register to terminate the continuous read operation. We have no
+ * guarantee the SPI controller drivers will effectively deassert the CS
+ * when we expect them to, so take the register based approach.
+ */
+ spinand_cont_read_enable(spinand, false);
+
+ return ret;
+}
+
+static void spinand_cont_read_init(struct spinand_device *spinand)
+{
+ /* OOBs cannot be retrieved so external/on-host ECC engine won't work */
+ if (spinand->set_cont_read) {
+ spinand->cont_read_possible = true;
+ }
+}
+
+static bool spinand_use_cont_read(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
+{
+ struct nand_device *nand = mtd_to_nanddev(mtd);
+ struct spinand_device *spinand = nand_to_spinand(nand);
+ struct nand_pos start_pos, end_pos;
+
+ if (!spinand->cont_read_possible)
+ return false;
+
+ /* OOBs won't be retrieved */
+ if (ops->ooblen || ops->oobbuf)
+ return false;
+
+ nanddev_offs_to_pos(nand, from, &start_pos);
+ nanddev_offs_to_pos(nand, from + ops->len - 1, &end_pos);
+
+ /*
+ * Continuous reads never cross LUN boundaries. Some devices don't
+ * support crossing planes boundaries. Some devices don't even support
+ * crossing blocks boundaries. The common case being to read through UBI,
+ * we will very rarely read two consequent blocks or more, so it is safer
+ * and easier (can be improved) to only enable continuous reads when
+ * reading within the same erase block.
+ */
+ if (start_pos.target != end_pos.target ||
+ start_pos.plane != end_pos.plane ||
+ start_pos.eraseblock != end_pos.eraseblock)
+ return false;
+
+ return start_pos.page < end_pos.page;
+}
+
+static int spinand_mtd_read(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
+{
+ struct spinand_device *spinand = mtd_to_spinand(mtd);
+ unsigned int max_bitflips = 0;
+ int ret;
+
+#ifndef __UBOOT__
+ mutex_lock(&spinand->lock);
+#endif
+
+ if (spinand_use_cont_read(mtd, from, ops)) {
+ ret = spinand_mtd_continuous_page_read(mtd, from, ops, &max_bitflips);
+ if (ret == -EAGAIN && !spinand->cont_read_possible) {
+ /*
+ * Spi controller with broken support of continuous
+ * reading was detected (see spinand_read_from_cache_op()),
+ * repeat reading in regular mode.
+ */
+ ret = spinand_mtd_regular_page_read(mtd, from, ops, &max_bitflips);
+ }
+ } else {
+ ret = spinand_mtd_regular_page_read(mtd, from, ops, &max_bitflips);
}
#ifndef __UBOOT__
mutex_unlock(&spinand->lock);
#endif
- if (ecc_failed && !ret)
- ret = -EBADMSG;
return ret ? ret : max_bitflips;
}
@@ -635,23 +933,22 @@ static int spinand_mtd_write(struct mtd_info *mtd, loff_t to,
struct spinand_device *spinand = mtd_to_spinand(mtd);
struct nand_device *nand = mtd_to_nanddev(mtd);
struct nand_io_iter iter;
- bool enable_ecc = false;
+ bool disable_ecc = false;
int ret = 0;
- if (ops->mode != MTD_OPS_RAW && mtd->ooblayout)
- enable_ecc = true;
+ if (ops->mode == MTD_OPS_RAW || !mtd->ooblayout)
+ disable_ecc = true;
#ifndef __UBOOT__
mutex_lock(&spinand->lock);
#endif
- nanddev_io_for_each_page(nand, to, ops, &iter) {
+ nanddev_io_for_each_page(nand, NAND_PAGE_WRITE, to, ops, &iter) {
schedule();
- ret = spinand_select_target(spinand, iter.req.pos.target);
- if (ret)
- break;
+ if (disable_ecc)
+ iter.req.mode = MTD_OPS_RAW;
- ret = spinand_ecc_enable(spinand, enable_ecc);
+ ret = spinand_select_target(spinand, iter.req.pos.target);
if (ret)
break;
@@ -681,9 +978,17 @@ static bool spinand_isbad(struct nand_device *nand, const struct nand_pos *pos)
.oobbuf.in = marker,
.mode = MTD_OPS_RAW,
};
+ int ret;
spinand_select_target(spinand, pos->target);
- spinand_read_page(spinand, &req, false);
+
+ ret = spinand_read_page(spinand, &req);
+ if (ret == -EOPNOTSUPP) {
+ /* Retry with ECC in case raw access is not supported */
+ req.mode = MTD_OPS_PLACE_OOB;
+ spinand_read_page(spinand, &req);
+ }
+
if (marker[0] != 0xff || marker[1] != 0xff)
return true;
@@ -727,11 +1032,14 @@ static int spinand_markbad(struct nand_device *nand, const struct nand_pos *pos)
if (ret)
return ret;
- ret = spinand_write_enable_op(spinand);
- if (ret)
- return ret;
+ ret = spinand_write_page(spinand, &req);
+ if (ret == -EOPNOTSUPP) {
+ /* Retry with ECC in case raw access is not supported */
+ req.mode = MTD_OPS_PLACE_OOB;
+ ret = spinand_write_page(spinand, &req);
+ }
- return spinand_write_page(spinand, &req);
+ return ret;
}
static int spinand_mtd_block_markbad(struct mtd_info *mtd, loff_t offs)
@@ -751,6 +1059,7 @@ static int spinand_mtd_block_markbad(struct mtd_info *mtd, loff_t offs)
#ifndef __UBOOT__
mutex_unlock(&spinand->lock);
#endif
+
return ret;
}
@@ -772,7 +1081,11 @@ static int spinand_erase(struct nand_device *nand, const struct nand_pos *pos)
if (ret)
return ret;
- ret = spinand_wait(spinand, &status);
+ ret = spinand_wait(spinand,
+ SPINAND_ERASE_INITIAL_DELAY_US,
+ SPINAND_ERASE_POLL_DELAY_US,
+ &status);
+
if (!ret && (status & STATUS_ERASE_FAILED))
ret = -EIO;
@@ -819,6 +1132,91 @@ static int spinand_mtd_block_isreserved(struct mtd_info *mtd, loff_t offs)
return ret;
}
+static struct spi_mem_dirmap_desc *spinand_create_rdesc(
+ struct spinand_device *spinand,
+ struct spi_mem_dirmap_info *info)
+{
+ struct nand_device *nand = spinand_to_nand(spinand);
+ struct spi_mem_dirmap_desc *desc = NULL;
+
+ if (spinand->cont_read_possible) {
+ /*
+ * spi controller may return an error if info->length is
+ * too large
+ */
+ info->length = nanddev_eraseblock_size(nand);
+ desc = spi_mem_dirmap_create(spinand->slave, info);
+ }
+
+ if (IS_ERR_OR_NULL(desc)) {
+ /*
+ * continuous reading is not supported by flash or
+ * its spi controller, use regular reading
+ */
+ spinand->cont_read_possible = false;
+
+ info->length = nanddev_page_size(nand) +
+ nanddev_per_page_oobsize(nand);
+ desc = spi_mem_dirmap_create(spinand->slave, info);
+ }
+
+ return desc;
+}
+
+static int spinand_create_dirmap(struct spinand_device *spinand,
+ unsigned int plane)
+{
+ struct nand_device *nand = spinand_to_nand(spinand);
+ struct spi_mem_dirmap_info info = { 0 };
+ struct spi_mem_dirmap_desc *desc;
+
+ /* The plane number is passed in MSB just above the column address */
+ info.offset = plane << fls(nand->memorg.pagesize);
+
+ info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand);
+ info.op_tmpl = *spinand->op_templates.update_cache;
+ desc = spi_mem_dirmap_create(spinand->slave, &info);
+ if (IS_ERR(desc))
+ return PTR_ERR(desc);
+
+ spinand->dirmaps[plane].wdesc = desc;
+
+ info.op_tmpl = *spinand->op_templates.read_cache;
+ desc = spinand_create_rdesc(spinand, &info);
+ if (IS_ERR(desc)) {
+ spi_mem_dirmap_destroy(spinand->dirmaps[plane].wdesc);
+ return PTR_ERR(desc);
+ }
+
+ spinand->dirmaps[plane].rdesc = desc;
+
+ spinand->dirmaps[plane].wdesc_ecc = spinand->dirmaps[plane].wdesc;
+ spinand->dirmaps[plane].rdesc_ecc = spinand->dirmaps[plane].rdesc;
+
+ return 0;
+}
+
+static int spinand_create_dirmaps(struct spinand_device *spinand)
+{
+ struct nand_device *nand = spinand_to_nand(spinand);
+ int i, ret;
+
+ spinand->dirmaps = devm_kzalloc(spinand->slave->dev,
+ sizeof(*spinand->dirmaps) *
+ nand->memorg.planes_per_lun,
+ GFP_KERNEL);
+ if (!spinand->dirmaps)
+ return -ENOMEM;
+
+ for (i = 0; i < nand->memorg.planes_per_lun; i++) {
+ ret = spinand_create_dirmap(spinand, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static const struct nand_ops spinand_ops = {
.erase = spinand_erase,
.markbad = spinand_markbad,
@@ -826,13 +1224,18 @@ static const struct nand_ops spinand_ops = {
};
static const struct spinand_manufacturer *spinand_manufacturers[] = {
+ &alliancememory_spinand_manufacturer,
+ &ato_spinand_manufacturer,
+ &esmt_c8_spinand_manufacturer,
+ &fmsh_spinand_manufacturer,
+ &foresee_spinand_manufacturer,
&gigadevice_spinand_manufacturer,
&macronix_spinand_manufacturer,
&micron_spinand_manufacturer,
&paragon_spinand_manufacturer,
+ &skyhigh_spinand_manufacturer,
&toshiba_spinand_manufacturer,
&winbond_spinand_manufacturer,
- &esmt_c8_spinand_manufacturer,
&xtx_spinand_manufacturer,
};
@@ -860,7 +1263,7 @@ static int spinand_manufacturer_match(struct spinand_device *spinand,
spinand->manufacturer = manufacturer;
return 0;
}
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
}
static int spinand_id_detect(struct spinand_device *spinand)
@@ -894,8 +1297,19 @@ static int spinand_id_detect(struct spinand_device *spinand)
static int spinand_manufacturer_init(struct spinand_device *spinand)
{
- if (spinand->manufacturer->ops->init)
- return spinand->manufacturer->ops->init(spinand);
+ int ret;
+
+ if (spinand->manufacturer->ops->init) {
+ ret = spinand->manufacturer->ops->init(spinand);
+ if (ret)
+ return ret;
+ }
+
+ if (spinand->configure_chip) {
+ ret = spinand->configure_chip(spinand);
+ if (ret)
+ return ret;
+ }
return 0;
}
@@ -912,10 +1326,13 @@ spinand_select_op_variant(struct spinand_device *spinand,
const struct spinand_op_variants *variants)
{
struct nand_device *nand = spinand_to_nand(spinand);
+ const struct spi_mem_op *best_variant = NULL;
+ u64 best_op_duration_ns = ULLONG_MAX;
unsigned int i;
for (i = 0; i < variants->nops; i++) {
struct spi_mem_op op = variants->ops[i];
+ u64 op_duration_ns = 0;
unsigned int nbytes;
int ret;
@@ -932,13 +1349,17 @@ spinand_select_op_variant(struct spinand_device *spinand,
break;
nbytes -= op.data.nbytes;
+
+ op_duration_ns += spi_mem_calc_op_duration(&op);
}
- if (!nbytes)
- return &variants->ops[i];
+ if (!nbytes && op_duration_ns < best_op_duration_ns) {
+ best_op_duration_ns = op_duration_ns;
+ best_variant = &variants->ops[i];
+ }
}
- return NULL;
+ return best_variant;
}
static int spinand_setup_slave(struct spinand_device *spinand,
@@ -994,11 +1415,17 @@ int spinand_match_and_init(struct spinand_device *spinand,
return ret;
nand->memorg = table[i].memorg;
- nand->eccreq = table[i].eccreq;
+ nanddev_set_ecc_requirements(nand, &table[i].eccreq);
spinand->eccinfo = table[i].eccinfo;
spinand->flags = table[i].flags;
spinand->id.len = 1 + table[i].devid.len;
spinand->select_target = table[i].select_target;
+ spinand->configure_chip = table[i].configure_chip;
+ spinand->set_cont_read = table[i].set_cont_read;
+ spinand->fact_otp = &table[i].fact_otp;
+ spinand->user_otp = &table[i].user_otp;
+ spinand->read_retries = table[i].read_retries;
+ spinand->set_read_retry = table[i].set_read_retry;
op = spinand_select_op_variant(spinand,
info->op_variants.read_cache);
@@ -1057,35 +1484,55 @@ static int spinand_detect(struct spinand_device *spinand)
return 0;
}
-static int spinand_noecc_ooblayout_ecc(struct mtd_info *mtd, int section,
- struct mtd_oob_region *region)
+static int spinand_init_flash(struct spinand_device *spinand)
{
- return -ERANGE;
-}
+ struct udevice *dev = spinand->slave->dev;
+ struct nand_device *nand = spinand_to_nand(spinand);
+ int ret, i;
-static int spinand_noecc_ooblayout_free(struct mtd_info *mtd, int section,
- struct mtd_oob_region *region)
-{
- if (section)
- return -ERANGE;
+ ret = spinand_read_cfg(spinand);
+ if (ret)
+ return ret;
- /* Reserve 2 bytes for the BBM. */
- region->offset = 2;
- region->length = 62;
+ ret = spinand_init_quad_enable(spinand);
+ if (ret)
+ return ret;
- return 0;
-}
+ ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0);
+ if (ret)
+ return ret;
-static const struct mtd_ooblayout_ops spinand_noecc_ooblayout = {
- .ecc = spinand_noecc_ooblayout_ecc,
- .rfree = spinand_noecc_ooblayout_free,
-};
+ ret = spinand_manufacturer_init(spinand);
+ if (ret) {
+ dev_err(dev,
+ "Failed to initialize the SPI NAND chip (err = %d)\n",
+ ret);
+ return ret;
+ }
+
+ /* After power up, all blocks are locked, so unlock them here. */
+ for (i = 0; i < nand->memorg.ntargets; i++) {
+ ret = spinand_select_target(spinand, i);
+ if (ret)
+ break;
+
+ ret = spinand_lock_block(spinand, BL_ALL_UNLOCKED);
+ if (ret)
+ break;
+ }
+
+ if (ret)
+ spinand_manufacturer_cleanup(spinand);
+
+ return ret;
+}
static int spinand_init(struct spinand_device *spinand)
{
+ struct udevice *dev = spinand->slave->dev;
struct mtd_info *mtd = spinand_to_mtd(spinand);
struct nand_device *nand = mtd_to_nanddev(mtd);
- int ret, i;
+ int ret;
/*
* We need a scratch buffer because the spi_mem interface requires that
@@ -1104,9 +1551,8 @@ static int spinand_init(struct spinand_device *spinand)
* may use this buffer for DMA access.
* Memory allocated by devm_ does not guarantee DMA-safe alignment.
*/
- spinand->databuf = kzalloc(nanddev_page_size(nand) +
- nanddev_per_page_oobsize(nand),
- GFP_KERNEL);
+ spinand->databuf = kzalloc(nanddev_eraseblock_size(nand),
+ GFP_KERNEL);
if (!spinand->databuf) {
ret = -ENOMEM;
goto err_free_bufs;
@@ -1118,41 +1564,25 @@ static int spinand_init(struct spinand_device *spinand)
if (ret)
goto err_free_bufs;
- ret = spinand_init_quad_enable(spinand);
+ ret = spinand_init_flash(spinand);
if (ret)
goto err_free_bufs;
- ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0);
- if (ret)
- goto err_free_bufs;
-
- ret = spinand_manufacturer_init(spinand);
- if (ret) {
- dev_err(spinand->slave->dev,
- "Failed to initialize the SPI NAND chip (err = %d)\n",
- ret);
- goto err_free_bufs;
- }
-
- /* After power up, all blocks are locked, so unlock them here. */
- for (i = 0; i < nand->memorg.ntargets; i++) {
- ret = spinand_select_target(spinand, i);
- if (ret)
- goto err_manuf_cleanup;
-
- ret = spinand_lock_block(spinand, BL_ALL_UNLOCKED);
- if (ret)
- goto err_manuf_cleanup;
- }
-
ret = nanddev_init(nand, &spinand_ops, THIS_MODULE);
if (ret)
goto err_manuf_cleanup;
+ spinand_ecc_enable(spinand, false);
+ ret = spinand_ondie_ecc_init_ctx(nand);
+ if (ret)
+ goto err_cleanup_nanddev;
+
/*
- * Right now, we don't support ECC, so let the whole oob
- * area is available for user.
+ * Continuous read can only be enabled with an on-die ECC engine, so the
+ * ECC initialization must have happened previously.
*/
+ spinand_cont_read_init(spinand);
+
mtd->_read_oob = spinand_mtd_read;
mtd->_write_oob = spinand_mtd_write;
mtd->_block_isbad = spinand_mtd_block_isbad;
@@ -1160,19 +1590,36 @@ static int spinand_init(struct spinand_device *spinand)
mtd->_block_isreserved = spinand_mtd_block_isreserved;
mtd->_erase = spinand_mtd_erase;
- if (spinand->eccinfo.ooblayout)
- mtd_set_ooblayout(mtd, spinand->eccinfo.ooblayout);
- else
- mtd_set_ooblayout(mtd, &spinand_noecc_ooblayout);
+ if (spinand_user_otp_size(spinand) || spinand_fact_otp_size(spinand)) {
+ ret = spinand_set_mtd_otp_ops(spinand);
+ if (ret)
+ goto err_cleanup_ecc_engine;
+ }
ret = mtd_ooblayout_count_freebytes(mtd);
if (ret < 0)
- goto err_cleanup_nanddev;
+ goto err_cleanup_ecc_engine;
mtd->oobavail = ret;
+ /* Propagate ECC information to mtd_info */
+ mtd->ecc_strength = nanddev_get_ecc_conf(nand)->strength;
+ mtd->ecc_step_size = nanddev_get_ecc_conf(nand)->step_size;
+ mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4);
+
+ ret = spinand_create_dirmaps(spinand);
+ if (ret) {
+ dev_err(dev,
+ "Failed to create direct mappings for read/write operations (err = %d)\n",
+ ret);
+ goto err_cleanup_ecc_engine;
+ }
+
return 0;
+err_cleanup_ecc_engine:
+ spinand_ondie_ecc_cleanup_ctx(nand);
+
err_cleanup_nanddev:
nanddev_cleanup(nand);
@@ -1189,6 +1636,7 @@ static void spinand_cleanup(struct spinand_device *spinand)
{
struct nand_device *nand = spinand_to_nand(spinand);
+ spinand_ondie_ecc_cleanup_ctx(nand);
nanddev_cleanup(nand);
spinand_manufacturer_cleanup(spinand);
kfree(spinand->databuf);
@@ -1294,12 +1742,14 @@ static const struct spi_device_id spinand_ids[] = {
{ .name = "spi-nand" },
{ /* sentinel */ },
};
+MODULE_DEVICE_TABLE(spi, spinand_ids);
#ifdef CONFIG_OF
static const struct of_device_id spinand_of_ids[] = {
{ .compatible = "spi-nand" },
{ /* sentinel */ },
};
+MODULE_DEVICE_TABLE(of, spinand_of_ids);
#endif
static struct spi_mem_driver spinand_drv = {
diff --git a/drivers/mtd/nand/spi/esmt.c b/drivers/mtd/nand/spi/esmt.c
index 7e07b26827a..6a46f3a3bfc 100644
--- a/drivers/mtd/nand/spi/esmt.c
+++ b/drivers/mtd/nand/spi/esmt.c
@@ -8,25 +8,33 @@
#ifndef __UBOOT__
#include <linux/device.h>
#include <linux/kernel.h>
+#else
+#include <dm/device_compat.h>
+#include <spi-mem.h>
+#include <spi.h>
#endif
#include <linux/mtd/spinand.h>
/* ESMT uses GigaDevice 0xc8 JECDEC ID on some SPI NANDs */
#define SPINAND_MFR_ESMT_C8 0xc8
+#define ESMT_F50L1G41LB_CFG_OTP_PROTECT BIT(7)
+#define ESMT_F50L1G41LB_CFG_OTP_LOCK \
+ (CFG_OTP_ENABLE | ESMT_F50L1G41LB_CFG_OTP_PROTECT)
+
static SPINAND_OP_VARIANTS(read_cache_variants,
- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
static SPINAND_OP_VARIANTS(write_cache_variants,
- SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
- SPINAND_PROG_LOAD(true, 0, NULL, 0));
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
static SPINAND_OP_VARIANTS(update_cache_variants,
- SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
- SPINAND_PROG_LOAD(false, 0, NULL, 0));
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
/*
* OOB spare area map (64 bytes)
@@ -104,24 +112,117 @@ static const struct mtd_ooblayout_ops f50l1g41lb_ooblayout = {
.rfree = f50l1g41lb_ooblayout_free,
};
+static int f50l1g41lb_otp_info(struct spinand_device *spinand, size_t len,
+ struct otp_info *buf, size_t *retlen, bool user)
+{
+ if (len < sizeof(*buf))
+ return -EINVAL;
+
+ buf->locked = 0;
+ buf->start = 0;
+ buf->length = user ? spinand_user_otp_size(spinand) :
+ spinand_fact_otp_size(spinand);
+
+ *retlen = sizeof(*buf);
+ return 0;
+}
+
+static int f50l1g41lb_fact_otp_info(struct spinand_device *spinand, size_t len,
+ struct otp_info *buf, size_t *retlen)
+{
+ return f50l1g41lb_otp_info(spinand, len, buf, retlen, false);
+}
+
+static int f50l1g41lb_user_otp_info(struct spinand_device *spinand, size_t len,
+ struct otp_info *buf, size_t *retlen)
+{
+ return f50l1g41lb_otp_info(spinand, len, buf, retlen, true);
+}
+
+static int f50l1g41lb_otp_lock(struct spinand_device *spinand, loff_t from,
+ size_t len)
+{
+ struct spi_mem_op write_op = SPINAND_WR_EN_DIS_1S_0_0_OP(true);
+ struct spi_mem_op exec_op = SPINAND_PROG_EXEC_1S_1S_0_OP(0);
+ u8 status;
+ int ret;
+
+ ret = spinand_upd_cfg(spinand, ESMT_F50L1G41LB_CFG_OTP_LOCK,
+ ESMT_F50L1G41LB_CFG_OTP_LOCK);
+ if (!ret)
+ return ret;
+
+ ret = spi_mem_exec_op(spinand->slave, &write_op);
+ if (!ret)
+ goto out;
+
+ ret = spi_mem_exec_op(spinand->slave, &exec_op);
+ if (!ret)
+ goto out;
+
+ ret = spinand_wait(spinand,
+ SPINAND_WRITE_INITIAL_DELAY_US,
+ SPINAND_WRITE_POLL_DELAY_US,
+ &status);
+ if (!ret && (status & STATUS_PROG_FAILED))
+ ret = -EIO;
+
+out:
+ if (spinand_upd_cfg(spinand, ESMT_F50L1G41LB_CFG_OTP_LOCK, 0)) {
+ dev_warn(spinand->slave->dev,
+ "Can not disable OTP mode\n");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static const struct spinand_user_otp_ops f50l1g41lb_user_otp_ops = {
+ .info = f50l1g41lb_user_otp_info,
+ .lock = f50l1g41lb_otp_lock,
+ .read = spinand_user_otp_read,
+ .write = spinand_user_otp_write,
+};
+
+static const struct spinand_fact_otp_ops f50l1g41lb_fact_otp_ops = {
+ .info = f50l1g41lb_fact_otp_info,
+ .read = spinand_fact_otp_read,
+};
+
static const struct spinand_info esmt_c8_spinand_table[] = {
SPINAND_INFO("F50L1G41LB",
- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01),
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01, 0x7f,
+ 0x7f, 0x7f),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(1, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
- SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
+ SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL),
+ SPINAND_USER_OTP_INFO(28, 2, &f50l1g41lb_user_otp_ops),
+ SPINAND_FACT_OTP_INFO(2, 0, &f50l1g41lb_fact_otp_ops)),
SPINAND_INFO("F50D1G41LB",
- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x11),
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x11, 0x7f,
+ 0x7f),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(1, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
+ SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL),
+ SPINAND_USER_OTP_INFO(28, 2, &f50l1g41lb_user_otp_ops),
+ SPINAND_FACT_OTP_INFO(2, 0, &f50l1g41lb_fact_otp_ops)),
+ SPINAND_INFO("F50D2G41KA",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x51, 0x7f,
+ 0x7f, 0x7f),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
};
diff --git a/drivers/mtd/nand/spi/fmsh.c b/drivers/mtd/nand/spi/fmsh.c
new file mode 100644
index 00000000000..80837b7dd42
--- /dev/null
+++ b/drivers/mtd/nand/spi/fmsh.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd.
+ *
+ * Author: Dingqiang Lin <jon.lin@rock-chips.com>
+ */
+
+#ifndef __UBOOT__
+#include <linux/device.h>
+#include <linux/kernel.h>
+#endif
+#include <linux/mtd/spinand.h>
+
+#define SPINAND_MFR_FMSH 0xA1
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
+
+static int fm25s01a_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ return -ERANGE;
+}
+
+static int fm25s01a_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section)
+ return -ERANGE;
+
+ region->offset = 2;
+ region->length = 62;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops fm25s01a_ooblayout = {
+ .ecc = fm25s01a_ooblayout_ecc,
+ .rfree = fm25s01a_ooblayout_free,
+};
+
+static const struct spinand_info fmsh_spinand_table[] = {
+ SPINAND_INFO("FM25S01A",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(1, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&fm25s01a_ooblayout, NULL)),
+};
+
+static const struct spinand_manufacturer_ops fmsh_spinand_manuf_ops = {
+};
+
+const struct spinand_manufacturer fmsh_spinand_manufacturer = {
+ .id = SPINAND_MFR_FMSH,
+ .name = "Fudan Micro",
+ .chips = fmsh_spinand_table,
+ .nchips = ARRAY_SIZE(fmsh_spinand_table),
+ .ops = &fmsh_spinand_manuf_ops,
+};
diff --git a/drivers/mtd/nand/spi/foresee.c b/drivers/mtd/nand/spi/foresee.c
new file mode 100644
index 00000000000..370f8494fb5
--- /dev/null
+++ b/drivers/mtd/nand/spi/foresee.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2023, SberDevices. All Rights Reserved.
+ *
+ * Author: Martin Kurbanov <mmkurbanov@salutedevices.com>
+ */
+
+#ifndef __UBOOT__
+#include <linux/device.h>
+#include <linux/kernel.h>
+#endif
+#include <linux/mtd/spinand.h>
+
+#define SPINAND_MFR_FORESEE 0xCD
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
+
+static int f35sqa002g_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ return -ERANGE;
+}
+
+static int f35sqa002g_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section)
+ return -ERANGE;
+
+ /* Reserve 2 bytes for the BBM. */
+ region->offset = 2;
+ region->length = 62;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops f35sqa002g_ooblayout = {
+ .ecc = f35sqa002g_ooblayout_ecc,
+ .rfree = f35sqa002g_ooblayout_free,
+};
+
+static int f35sqa002g_ecc_get_status(struct spinand_device *spinand, u8 status)
+{
+ struct nand_device *nand = spinand_to_nand(spinand);
+
+ switch (status & STATUS_ECC_MASK) {
+ case STATUS_ECC_NO_BITFLIPS:
+ return 0;
+
+ case STATUS_ECC_HAS_BITFLIPS:
+ return nanddev_get_ecc_conf(nand)->strength;
+
+ default:
+ break;
+ }
+
+ /* More than 1-bit error was detected in one or more sectors and
+ * cannot be corrected.
+ */
+ return -EBADMSG;
+}
+
+static const struct spinand_info foresee_spinand_table[] = {
+ SPINAND_INFO("F35SQA002G",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x72, 0x72),
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(1, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&f35sqa002g_ooblayout,
+ f35sqa002g_ecc_get_status)),
+ SPINAND_INFO("F35SQA001G",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x71, 0x71),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(1, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&f35sqa002g_ooblayout,
+ f35sqa002g_ecc_get_status)),
+};
+
+static const struct spinand_manufacturer_ops foresee_spinand_manuf_ops = {
+};
+
+const struct spinand_manufacturer foresee_spinand_manufacturer = {
+ .id = SPINAND_MFR_FORESEE,
+ .name = "FORESEE",
+ .chips = foresee_spinand_table,
+ .nchips = ARRAY_SIZE(foresee_spinand_table),
+ .ops = &foresee_spinand_manuf_ops,
+};
diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c
index fe8c76acac6..32fbe11e908 100644
--- a/drivers/mtd/nand/spi/gigadevice.c
+++ b/drivers/mtd/nand/spi/gigadevice.c
@@ -28,44 +28,44 @@
#define GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR (7 << 4)
static SPINAND_OP_VARIANTS(read_cache_variants,
- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
static SPINAND_OP_VARIANTS(read_cache_variants_f,
- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP_3A(true, 0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP_3A(false, 0, 0, NULL, 0));
+ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_3A_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_1S_OP(0, 0, NULL, 0, 0));
static SPINAND_OP_VARIANTS(read_cache_variants_1gq5,
- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
static SPINAND_OP_VARIANTS(read_cache_variants_2gq5,
- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 4, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 2, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 4, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 2, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
static SPINAND_OP_VARIANTS(write_cache_variants,
- SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
- SPINAND_PROG_LOAD(true, 0, NULL, 0));
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
static SPINAND_OP_VARIANTS(update_cache_variants,
- SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
- SPINAND_PROG_LOAD(false, 0, NULL, 0));
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
static int gd5fxgq4xa_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
@@ -189,8 +189,8 @@ static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
u8 status)
{
u8 status2;
- struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2,
- &status2);
+ struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(GD5FXGQXXEXXG_REG_STATUS2,
+ spinand->scratchbuf);
int ret;
switch (status & STATUS_ECC_MASK) {
@@ -211,6 +211,7 @@ static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
* report the maximum of 4 in this case
*/
/* bits sorted this way (3...0): ECCS1,ECCS0,ECCSE1,ECCSE0 */
+ status2 = *(spinand->scratchbuf);
return ((status & STATUS_ECC_MASK) >> 2) |
((status2 & STATUS_ECC_MASK) >> 4);
@@ -231,8 +232,8 @@ static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand,
u8 status)
{
u8 status2;
- struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2,
- &status2);
+ struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(GD5FXGQXXEXXG_REG_STATUS2,
+ spinand->scratchbuf);
int ret;
switch (status & STATUS_ECC_MASK) {
@@ -252,6 +253,7 @@ static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand,
* 1 ... 4 bits are flipped (and corrected)
*/
/* bits sorted this way (1...0): ECCSE1, ECCSE0 */
+ status2 = *(spinand->scratchbuf);
return ((status2 & STATUS_ECC_MASK) >> 4) + 1;
case STATUS_ECC_UNCOR_ERROR:
@@ -535,6 +537,26 @@ static const struct spinand_info gigadevice_spinand_table[] = {
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
gd5fxgq4uexxg_ecc_get_status)),
+ SPINAND_INFO("GD5F1GM9UExxG",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x91, 0x01),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
+ gd5fxgq4uexxg_ecc_get_status)),
+ SPINAND_INFO("GD5F1GM9RExxG",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x81, 0x01),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
+ gd5fxgq4uexxg_ecc_get_status)),
};
static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = {
diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
index 86bffc2800b..f21103bb15a 100644
--- a/drivers/mtd/nand/spi/macronix.c
+++ b/drivers/mtd/nand/spi/macronix.c
@@ -5,6 +5,7 @@
* Author: Boris Brezillon <boris.brezillon@bootlin.com>
*/
+#include <linux/bitfield.h>
#ifndef __UBOOT__
#include <linux/device.h>
#include <linux/kernel.h>
@@ -13,21 +14,35 @@
#include <linux/mtd/spinand.h>
#define SPINAND_MFR_MACRONIX 0xC2
-#define MACRONIX_ECCSR_MASK 0x0F
+#define MACRONIX_ECCSR_BF_LAST_PAGE(eccsr) FIELD_GET(GENMASK(3, 0), eccsr)
+#define MACRONIX_ECCSR_BF_ACCUMULATED_PAGES(eccsr) FIELD_GET(GENMASK(7, 4), eccsr)
+#define MACRONIX_CFG_CONT_READ BIT(2)
+#define MACRONIX_FEATURE_ADDR_READ_RETRY 0x70
+#define MACRONIX_NUM_READ_RETRY_MODES 5
+
+#define STATUS_ECC_HAS_BITFLIPS_THRESHOLD (3 << 4)
+
+/* Bitflip theshold configuration register */
+#define REG_CFG_BFT 0x10
+#define CFG_BFT(x) FIELD_PREP(GENMASK(7, 4), (x))
+
+struct macronix_priv {
+ bool cont_read;
+};
static SPINAND_OP_VARIANTS(read_cache_variants,
- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
static SPINAND_OP_VARIANTS(write_cache_variants,
- SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
- SPINAND_PROG_LOAD(true, 0, NULL, 0));
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
static SPINAND_OP_VARIANTS(update_cache_variants,
- SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
- SPINAND_PROG_LOAD(false, 0, NULL, 0));
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
static int mx35lfxge4ab_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
@@ -52,8 +67,9 @@ static const struct mtd_ooblayout_ops mx35lfxge4ab_ooblayout = {
.rfree = mx35lfxge4ab_ooblayout_free,
};
-static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
+static int macronix_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
{
+ struct macronix_priv *priv = spinand->priv;
struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0x7c, 1),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_DUMMY(1, 1),
@@ -63,12 +79,21 @@ static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
if (ret)
return ret;
- *eccsr &= MACRONIX_ECCSR_MASK;
+ /*
+ * ECCSR exposes the number of bitflips for the last read page in bits [3:0].
+ * Continuous read compatible chips also expose the maximum number of
+ * bitflips for the whole (continuous) read operation in bits [7:4].
+ */
+ if (!priv->cont_read)
+ *eccsr = MACRONIX_ECCSR_BF_LAST_PAGE(*eccsr);
+ else
+ *eccsr = MACRONIX_ECCSR_BF_ACCUMULATED_PAGES(*eccsr);
+
return 0;
}
-static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
- u8 status)
+static int macronix_ecc_get_status(struct spinand_device *spinand,
+ u8 status)
{
struct nand_device *nand = spinand_to_nand(spinand);
u8 eccsr;
@@ -86,14 +111,14 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
* in order to avoid forcing the wear-leveling layer to move
* data around if it's not necessary.
*/
- if (mx35lf1ge4ab_get_eccsr(spinand, &eccsr))
- return nand->eccreq.strength;
+ if (macronix_get_eccsr(spinand, spinand->scratchbuf))
+ return nanddev_get_ecc_conf(nand)->strength;
- if (WARN_ON(eccsr > nand->eccreq.strength || !eccsr))
- return nand->eccreq.strength;
+ eccsr = *spinand->scratchbuf;
+ if (WARN_ON(eccsr > nanddev_get_ecc_conf(nand)->strength || !eccsr))
+ return nanddev_get_ecc_conf(nand)->strength;
return eccsr;
-
default:
break;
}
@@ -101,6 +126,38 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
return -EINVAL;
}
+static int macronix_set_cont_read(struct spinand_device *spinand, bool enable)
+{
+ struct macronix_priv *priv = spinand->priv;
+ int ret;
+
+ ret = spinand_upd_cfg(spinand, MACRONIX_CFG_CONT_READ,
+ enable ? MACRONIX_CFG_CONT_READ : 0);
+ if (ret)
+ return ret;
+
+ priv->cont_read = enable;
+
+ return 0;
+}
+
+/**
+ * macronix_set_read_retry - Set the retry mode
+ * @spinand: SPI NAND device
+ * @retry_mode: Specify which retry mode to set
+ *
+ * Return: 0 on success, a negative error code otherwise.
+ */
+static int macronix_set_read_retry(struct spinand_device *spinand,
+ unsigned int retry_mode)
+{
+ struct spi_mem_op op = SPINAND_SET_FEATURE_1S_1S_1S_OP(MACRONIX_FEATURE_ADDR_READ_RETRY,
+ spinand->scratchbuf);
+
+ *spinand->scratchbuf = retry_mode;
+ return spi_mem_exec_op(spinand->slave, &op);
+}
+
static const struct spinand_info macronix_spinand_table[] = {
SPINAND_INFO("MX35LF1GE4AB",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x12),
@@ -111,7 +168,7 @@ static const struct spinand_info macronix_spinand_table[] = {
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
- mx35lf1ge4ab_ecc_get_status)),
+ macronix_ecc_get_status)),
SPINAND_INFO("MX35LF2GE4AB",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x22),
NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
@@ -119,10 +176,12 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
- SPINAND_HAS_QE_BIT,
+ SPINAND_HAS_QE_BIT |
+ SPINAND_HAS_PROG_PLANE_SELECT_BIT |
+ SPINAND_HAS_READ_PLANE_SELECT_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
SPINAND_INFO("MX35LF2GE4AD",
- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x26),
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x26, 0x03),
NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -130,9 +189,12 @@ static const struct spinand_info macronix_spinand_table[] = {
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
- mx35lf1ge4ab_ecc_get_status)),
+ macronix_ecc_get_status),
+ SPINAND_CONT_READ(macronix_set_cont_read),
+ SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
+ macronix_set_read_retry)),
SPINAND_INFO("MX35LF4GE4AD",
- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x37),
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x37, 0x03),
NAND_MEMORG(1, 4096, 128, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -140,34 +202,67 @@ static const struct spinand_info macronix_spinand_table[] = {
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
- mx35lf1ge4ab_ecc_get_status)),
+ macronix_ecc_get_status),
+ SPINAND_CONT_READ(macronix_set_cont_read),
+ SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
+ macronix_set_read_retry)),
SPINAND_INFO("MX35LF1G24AD",
- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14, 0x03),
NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
- SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL),
+ SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
+ macronix_set_read_retry)),
SPINAND_INFO("MX35LF2G24AD",
- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24, 0x03),
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
+ SPINAND_HAS_QE_BIT |
+ SPINAND_HAS_PROG_PLANE_SELECT_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL),
+ SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
+ macronix_set_read_retry)),
+ SPINAND_INFO("MX35LF2G24AD-Z4I8",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x64, 0x03),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
SPINAND_HAS_QE_BIT,
- SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL),
+ SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
+ macronix_set_read_retry)),
SPINAND_INFO("MX35LF4G24AD",
- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35, 0x03),
NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
+ SPINAND_HAS_QE_BIT |
+ SPINAND_HAS_PROG_PLANE_SELECT_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL),
+ SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
+ macronix_set_read_retry)),
+ SPINAND_INFO("MX35LF4G24AD-Z4I8",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x75, 0x03),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
SPINAND_HAS_QE_BIT,
- SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL),
+ SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
+ macronix_set_read_retry)),
SPINAND_INFO("MX31LF1GE4BC",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x1e),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
@@ -177,7 +272,7 @@ static const struct spinand_info macronix_spinand_table[] = {
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
- mx35lf1ge4ab_ecc_get_status)),
+ macronix_ecc_get_status)),
SPINAND_INFO("MX31UF1GE4BC",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x9e),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
@@ -187,7 +282,7 @@ static const struct spinand_info macronix_spinand_table[] = {
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
- mx35lf1ge4ab_ecc_get_status)),
+ macronix_ecc_get_status)),
SPINAND_INFO("MX35LF2G14AC",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x20),
@@ -196,21 +291,38 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
- SPINAND_HAS_QE_BIT,
+ SPINAND_HAS_QE_BIT |
+ SPINAND_HAS_PROG_PLANE_SELECT_BIT |
+ SPINAND_HAS_READ_PLANE_SELECT_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
- mx35lf1ge4ab_ecc_get_status)),
+ macronix_ecc_get_status)),
SPINAND_INFO("MX35UF4G24AD",
- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb5),
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb5, 0x03),
NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
+ SPINAND_HAS_QE_BIT |
+ SPINAND_HAS_PROG_PLANE_SELECT_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ macronix_ecc_get_status),
+ SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
+ macronix_set_read_retry)),
+ SPINAND_INFO("MX35UF4G24AD-Z4I8",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xf5, 0x03),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
- mx35lf1ge4ab_ecc_get_status)),
+ macronix_ecc_get_status),
+ SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
+ macronix_set_read_retry)),
SPINAND_INFO("MX35UF4GE4AD",
- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb7),
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb7, 0x03),
NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -218,7 +330,10 @@ static const struct spinand_info macronix_spinand_table[] = {
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
- mx35lf1ge4ab_ecc_get_status)),
+ macronix_ecc_get_status),
+ SPINAND_CONT_READ(macronix_set_cont_read),
+ SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
+ macronix_set_read_retry)),
SPINAND_INFO("MX35UF2G14AC",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa0),
NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
@@ -226,21 +341,38 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
- SPINAND_HAS_QE_BIT,
+ SPINAND_HAS_QE_BIT |
+ SPINAND_HAS_PROG_PLANE_SELECT_BIT |
+ SPINAND_HAS_READ_PLANE_SELECT_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
- mx35lf1ge4ab_ecc_get_status)),
+ macronix_ecc_get_status)),
SPINAND_INFO("MX35UF2G24AD",
- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa4),
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa4, 0x03),
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
+ SPINAND_HAS_QE_BIT |
+ SPINAND_HAS_PROG_PLANE_SELECT_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ macronix_ecc_get_status),
+ SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
+ macronix_set_read_retry)),
+ SPINAND_INFO("MX35UF2G24AD-Z4I8",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xe4, 0x03),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
- mx35lf1ge4ab_ecc_get_status)),
+ macronix_ecc_get_status),
+ SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
+ macronix_set_read_retry)),
SPINAND_INFO("MX35UF2GE4AD",
- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa6),
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa6, 0x03),
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -248,9 +380,12 @@ static const struct spinand_info macronix_spinand_table[] = {
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
- mx35lf1ge4ab_ecc_get_status)),
+ macronix_ecc_get_status),
+ SPINAND_CONT_READ(macronix_set_cont_read),
+ SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
+ macronix_set_read_retry)),
SPINAND_INFO("MX35UF2GE4AC",
- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa2),
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa2, 0x01),
NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -258,7 +393,8 @@ static const struct spinand_info macronix_spinand_table[] = {
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
- mx35lf1ge4ab_ecc_get_status)),
+ macronix_ecc_get_status),
+ SPINAND_CONT_READ(macronix_set_cont_read)),
SPINAND_INFO("MX35UF1G14AC",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x90),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
@@ -268,9 +404,9 @@ static const struct spinand_info macronix_spinand_table[] = {
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
- mx35lf1ge4ab_ecc_get_status)),
+ macronix_ecc_get_status)),
SPINAND_INFO("MX35UF1G24AD",
- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x94),
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x94, 0x03),
NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -278,9 +414,11 @@ static const struct spinand_info macronix_spinand_table[] = {
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
- mx35lf1ge4ab_ecc_get_status)),
+ macronix_ecc_get_status),
+ SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
+ macronix_set_read_retry)),
SPINAND_INFO("MX35UF1GE4AD",
- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96),
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96, 0x03),
NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -288,9 +426,12 @@ static const struct spinand_info macronix_spinand_table[] = {
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
- mx35lf1ge4ab_ecc_get_status)),
+ macronix_ecc_get_status),
+ SPINAND_CONT_READ(macronix_set_cont_read),
+ SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
+ macronix_set_read_retry)),
SPINAND_INFO("MX35UF1GE4AC",
- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92),
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92, 0x01),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -298,11 +439,51 @@ static const struct spinand_info macronix_spinand_table[] = {
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
- mx35lf1ge4ab_ecc_get_status)),
-
+ macronix_ecc_get_status),
+ SPINAND_CONT_READ(macronix_set_cont_read)),
+ SPINAND_INFO("MX31LF2GE4BC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x2e),
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ macronix_ecc_get_status)),
+ SPINAND_INFO("MX3UF2GE4BC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xae),
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ macronix_ecc_get_status)),
};
+static int macronix_spinand_init(struct spinand_device *spinand)
+{
+ struct macronix_priv *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ spinand->priv = priv;
+
+ return 0;
+}
+
+static void macronix_spinand_cleanup(struct spinand_device *spinand)
+{
+ kfree(spinand->priv);
+}
+
static const struct spinand_manufacturer_ops macronix_spinand_manuf_ops = {
+ .init = macronix_spinand_init,
+ .cleanup = macronix_spinand_cleanup,
};
const struct spinand_manufacturer macronix_spinand_manufacturer = {
diff --git a/drivers/mtd/nand/spi/micron.c b/drivers/mtd/nand/spi/micron.c
index b538213ed8e..9af3e99664f 100644
--- a/drivers/mtd/nand/spi/micron.c
+++ b/drivers/mtd/nand/spi/micron.c
@@ -9,12 +9,18 @@
#ifndef __UBOOT__
#include <linux/device.h>
#include <linux/kernel.h>
+#include <linux/spi/spi-mem.h>
+#else
+#include <dm/device_compat.h>
+#include <spi-mem.h>
+#include <spi.h>
#endif
#include <linux/mtd/spinand.h>
+#include <linux/string.h>
#define SPINAND_MFR_MICRON 0x2c
-#define MICRON_STATUS_ECC_MASK GENMASK(7, 4)
+#define MICRON_STATUS_ECC_MASK GENMASK(6, 4)
#define MICRON_STATUS_ECC_NO_BITFLIPS (0 << 4)
#define MICRON_STATUS_ECC_1TO3_BITFLIPS (1 << 4)
#define MICRON_STATUS_ECC_4TO6_BITFLIPS (3 << 4)
@@ -30,34 +36,38 @@
#define MICRON_SELECT_DIE(x) ((x) << 6)
+#define MICRON_MT29F2G01ABAGD_CFG_OTP_STATE BIT(7)
+#define MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK \
+ (CFG_OTP_ENABLE | MICRON_MT29F2G01ABAGD_CFG_OTP_STATE)
+
static SPINAND_OP_VARIANTS(quadio_read_cache_variants,
- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
static SPINAND_OP_VARIANTS(x4_write_cache_variants,
- SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
- SPINAND_PROG_LOAD(true, 0, NULL, 0));
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
static SPINAND_OP_VARIANTS(x4_update_cache_variants,
- SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
- SPINAND_PROG_LOAD(false, 0, NULL, 0));
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
/* Micron MT29F2G01AAAED Device */
static SPINAND_OP_VARIANTS(x4_read_cache_variants,
- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
static SPINAND_OP_VARIANTS(x1_write_cache_variants,
- SPINAND_PROG_LOAD(true, 0, NULL, 0));
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
static SPINAND_OP_VARIANTS(x1_update_cache_variants,
- SPINAND_PROG_LOAD(false, 0, NULL, 0));
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
static int micron_8_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
@@ -133,7 +143,7 @@ static const struct mtd_ooblayout_ops micron_4_ooblayout = {
static int micron_select_target(struct spinand_device *spinand,
unsigned int target)
{
- struct spi_mem_op op = SPINAND_SET_FEATURE_OP(MICRON_DIE_SELECT_REG,
+ struct spi_mem_op op = SPINAND_SET_FEATURE_1S_1S_1S_OP(MICRON_DIE_SELECT_REG,
spinand->scratchbuf);
if (target > 1)
@@ -170,6 +180,136 @@ static int micron_8_ecc_get_status(struct spinand_device *spinand,
return -EINVAL;
}
+static inline bool mem_is_zero(const void *s, size_t n)
+{
+ return !memchr_inv(s, 0, n);
+}
+
+static int mt29f2g01abagd_otp_is_locked(struct spinand_device *spinand)
+{
+ size_t bufsize = spinand_otp_page_size(spinand);
+ size_t retlen;
+ u8 *buf;
+ int ret;
+
+ buf = kmalloc(bufsize, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = spinand_upd_cfg(spinand,
+ MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK,
+ MICRON_MT29F2G01ABAGD_CFG_OTP_STATE);
+ if (ret)
+ goto free_buf;
+
+ ret = spinand_user_otp_read(spinand, 0, bufsize, &retlen, buf);
+
+ if (spinand_upd_cfg(spinand, MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK,
+ 0)) {
+ dev_warn(spinand->slave->dev,
+ "Can not disable OTP mode\n");
+ ret = -EIO;
+ }
+
+ if (ret)
+ goto free_buf;
+
+ /* If all zeros, then the OTP area is locked. */
+ if (mem_is_zero(buf, bufsize))
+ ret = 1;
+
+free_buf:
+ kfree(buf);
+ return ret;
+}
+
+static int mt29f2g01abagd_otp_info(struct spinand_device *spinand, size_t len,
+ struct otp_info *buf, size_t *retlen,
+ bool user)
+{
+ int locked;
+
+ if (len < sizeof(*buf))
+ return -EINVAL;
+
+ locked = mt29f2g01abagd_otp_is_locked(spinand);
+ if (locked < 0)
+ return locked;
+
+ buf->locked = locked;
+ buf->start = 0;
+ buf->length = user ? spinand_user_otp_size(spinand) :
+ spinand_fact_otp_size(spinand);
+
+ *retlen = sizeof(*buf);
+ return 0;
+}
+
+static int mt29f2g01abagd_fact_otp_info(struct spinand_device *spinand,
+ size_t len, struct otp_info *buf,
+ size_t *retlen)
+{
+ return mt29f2g01abagd_otp_info(spinand, len, buf, retlen, false);
+}
+
+static int mt29f2g01abagd_user_otp_info(struct spinand_device *spinand,
+ size_t len, struct otp_info *buf,
+ size_t *retlen)
+{
+ return mt29f2g01abagd_otp_info(spinand, len, buf, retlen, true);
+}
+
+static int mt29f2g01abagd_otp_lock(struct spinand_device *spinand, loff_t from,
+ size_t len)
+{
+ struct spi_mem_op write_op = SPINAND_WR_EN_DIS_1S_0_0_OP(true);
+ struct spi_mem_op exec_op = SPINAND_PROG_EXEC_1S_1S_0_OP(0);
+ u8 status;
+ int ret;
+
+ ret = spinand_upd_cfg(spinand,
+ MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK,
+ MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK);
+ if (!ret)
+ return ret;
+
+ ret = spi_mem_exec_op(spinand->slave, &write_op);
+ if (!ret)
+ goto out;
+
+ ret = spi_mem_exec_op(spinand->slave, &exec_op);
+ if (!ret)
+ goto out;
+
+ ret = spinand_wait(spinand,
+ SPINAND_WRITE_INITIAL_DELAY_US,
+ SPINAND_WRITE_POLL_DELAY_US,
+ &status);
+ if (!ret && (status & STATUS_PROG_FAILED))
+ ret = -EIO;
+
+out:
+ if (spinand_upd_cfg(spinand, MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK, 0)) {
+ dev_warn(spinand->slave->dev,
+ "Can not disable OTP mode\n");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static const struct spinand_user_otp_ops mt29f2g01abagd_user_otp_ops = {
+ .info = mt29f2g01abagd_user_otp_info,
+ .lock = mt29f2g01abagd_otp_lock,
+ .read = spinand_user_otp_read,
+ .write = spinand_user_otp_write,
+};
+
+static const struct spinand_fact_otp_ops mt29f2g01abagd_fact_otp_ops = {
+ .info = mt29f2g01abagd_fact_otp_info,
+ .read = spinand_fact_otp_read,
+};
+
static const struct spinand_info micron_spinand_table[] = {
/* M79A 2Gb 3.3V */
SPINAND_INFO("MT29F2G01ABAGD",
@@ -181,7 +321,9 @@ static const struct spinand_info micron_spinand_table[] = {
&x4_update_cache_variants),
0,
SPINAND_ECCINFO(&micron_8_ooblayout,
- micron_8_ecc_get_status)),
+ micron_8_ecc_get_status),
+ SPINAND_USER_OTP_INFO(12, 2, &mt29f2g01abagd_user_otp_ops),
+ SPINAND_FACT_OTP_INFO(2, 0, &mt29f2g01abagd_fact_otp_ops)),
/* M79A 2Gb 1.8V */
SPINAND_INFO("MT29F2G01ABBGD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
diff --git a/drivers/mtd/nand/spi/otp.c b/drivers/mtd/nand/spi/otp.c
new file mode 100644
index 00000000000..e6ef78d9464
--- /dev/null
+++ b/drivers/mtd/nand/spi/otp.c
@@ -0,0 +1,369 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025, SaluteDevices. All Rights Reserved.
+ *
+ * Author: Martin Kurbanov <mmkurbanov@salutedevices.com>
+ */
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/spinand.h>
+#ifdef __UBOOT__
+#include <spi.h>
+#include <dm/device_compat.h>
+#endif
+
+/**
+ * spinand_otp_page_size() - Get SPI-NAND OTP page size
+ * @spinand: the spinand device
+ *
+ * Return: the OTP page size.
+ */
+size_t spinand_otp_page_size(struct spinand_device *spinand)
+{
+ struct nand_device *nand = spinand_to_nand(spinand);
+
+ return nanddev_page_size(nand) + nanddev_per_page_oobsize(nand);
+}
+
+static size_t spinand_otp_size(struct spinand_device *spinand,
+ const struct spinand_otp_layout *layout)
+{
+ return layout->npages * spinand_otp_page_size(spinand);
+}
+
+/**
+ * spinand_fact_otp_size() - Get SPI-NAND factory OTP area size
+ * @spinand: the spinand device
+ *
+ * Return: the OTP size.
+ */
+size_t spinand_fact_otp_size(struct spinand_device *spinand)
+{
+ return spinand_otp_size(spinand, &spinand->fact_otp->layout);
+}
+
+/**
+ * spinand_user_otp_size() - Get SPI-NAND user OTP area size
+ * @spinand: the spinand device
+ *
+ * Return: the OTP size.
+ */
+size_t spinand_user_otp_size(struct spinand_device *spinand)
+{
+ return spinand_otp_size(spinand, &spinand->user_otp->layout);
+}
+
+static int spinand_otp_check_bounds(struct spinand_device *spinand, loff_t ofs,
+ size_t len,
+ const struct spinand_otp_layout *layout)
+{
+ if (ofs < 0 || ofs + len > spinand_otp_size(spinand, layout))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int spinand_user_otp_check_bounds(struct spinand_device *spinand,
+ loff_t ofs, size_t len)
+{
+ return spinand_otp_check_bounds(spinand, ofs, len,
+ &spinand->user_otp->layout);
+}
+
+static int spinand_otp_rw(struct spinand_device *spinand, loff_t ofs,
+ size_t len, size_t *retlen, u8 *buf, bool is_write,
+ const struct spinand_otp_layout *layout)
+{
+ struct nand_page_io_req req = {};
+ unsigned long long page;
+ size_t copied = 0;
+ size_t otp_pagesize = spinand_otp_page_size(spinand);
+ int ret;
+
+ if (!len)
+ return 0;
+
+ ret = spinand_otp_check_bounds(spinand, ofs, len, layout);
+ if (ret)
+ return ret;
+
+ ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, CFG_OTP_ENABLE);
+ if (ret)
+ return ret;
+
+ page = ofs;
+ req.dataoffs = do_div(page, otp_pagesize);
+ req.pos.page = page + layout->start_page;
+ req.type = is_write ? NAND_PAGE_WRITE : NAND_PAGE_READ;
+ req.mode = MTD_OPS_RAW;
+ req.databuf.in = buf;
+
+ while (copied < len) {
+ req.datalen = min_t(unsigned int,
+ otp_pagesize - req.dataoffs,
+ len - copied);
+
+ if (is_write)
+ ret = spinand_write_page(spinand, &req);
+ else
+ ret = spinand_read_page(spinand, &req);
+
+ if (ret < 0)
+ break;
+
+ req.databuf.in += req.datalen;
+ req.pos.page++;
+ req.dataoffs = 0;
+ copied += req.datalen;
+ }
+
+ *retlen = copied;
+
+ if (spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0)) {
+ dev_warn(spinand->slave->dev,
+ "Can not disable OTP mode\n");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+/**
+ * spinand_fact_otp_read() - Read from OTP area
+ * @spinand: the spinand device
+ * @ofs: the offset to read
+ * @len: the number of data bytes to read
+ * @retlen: the pointer to variable to store the number of read bytes
+ * @buf: the buffer to store the read data
+ *
+ * Return: 0 on success, an error code otherwise.
+ */
+int spinand_fact_otp_read(struct spinand_device *spinand, loff_t ofs,
+ size_t len, size_t *retlen, u8 *buf)
+{
+ return spinand_otp_rw(spinand, ofs, len, retlen, buf, false,
+ &spinand->fact_otp->layout);
+}
+
+/**
+ * spinand_user_otp_read() - Read from OTP area
+ * @spinand: the spinand device
+ * @ofs: the offset to read
+ * @len: the number of data bytes to read
+ * @retlen: the pointer to variable to store the number of read bytes
+ * @buf: the buffer to store the read data
+ *
+ * Return: 0 on success, an error code otherwise.
+ */
+int spinand_user_otp_read(struct spinand_device *spinand, loff_t ofs,
+ size_t len, size_t *retlen, u8 *buf)
+{
+ return spinand_otp_rw(spinand, ofs, len, retlen, buf, false,
+ &spinand->user_otp->layout);
+}
+
+/**
+ * spinand_user_otp_write() - Write to OTP area
+ * @spinand: the spinand device
+ * @ofs: the offset to write to
+ * @len: the number of bytes to write
+ * @retlen: the pointer to variable to store the number of written bytes
+ * @buf: the buffer with data to write
+ *
+ * Return: 0 on success, an error code otherwise.
+ */
+int spinand_user_otp_write(struct spinand_device *spinand, loff_t ofs,
+ size_t len, size_t *retlen, const u8 *buf)
+{
+ return spinand_otp_rw(spinand, ofs, len, retlen, (u8 *)buf, true,
+ &spinand->user_otp->layout);
+}
+
+static int spinand_mtd_otp_info(struct mtd_info *mtd, size_t len,
+ size_t *retlen, struct otp_info *buf,
+ bool is_fact)
+{
+ struct spinand_device *spinand = mtd_to_spinand(mtd);
+ int ret;
+
+ *retlen = 0;
+
+ mutex_lock(&spinand->lock);
+
+ if (is_fact)
+ ret = spinand->fact_otp->ops->info(spinand, len, buf, retlen);
+ else
+ ret = spinand->user_otp->ops->info(spinand, len, buf, retlen);
+
+ mutex_unlock(&spinand->lock);
+
+ return ret;
+}
+
+static int spinand_mtd_fact_otp_info(struct mtd_info *mtd, size_t len,
+ size_t *retlen, struct otp_info *buf)
+{
+ return spinand_mtd_otp_info(mtd, len, retlen, buf, true);
+}
+
+static int spinand_mtd_user_otp_info(struct mtd_info *mtd, size_t len,
+ size_t *retlen, struct otp_info *buf)
+{
+ return spinand_mtd_otp_info(mtd, len, retlen, buf, false);
+}
+
+static int spinand_mtd_otp_read(struct mtd_info *mtd, loff_t ofs, size_t len,
+ size_t *retlen, u8 *buf, bool is_fact)
+{
+ struct spinand_device *spinand = mtd_to_spinand(mtd);
+ int ret;
+
+ *retlen = 0;
+
+ if (!len)
+ return 0;
+
+ ret = spinand_otp_check_bounds(spinand, ofs, len,
+ is_fact ? &spinand->fact_otp->layout :
+ &spinand->user_otp->layout);
+ if (ret)
+ return ret;
+
+ mutex_lock(&spinand->lock);
+
+ if (is_fact)
+ ret = spinand->fact_otp->ops->read(spinand, ofs, len, retlen,
+ buf);
+ else
+ ret = spinand->user_otp->ops->read(spinand, ofs, len, retlen,
+ buf);
+
+ mutex_unlock(&spinand->lock);
+
+ return ret;
+}
+
+static int spinand_mtd_fact_otp_read(struct mtd_info *mtd, loff_t ofs,
+ size_t len, size_t *retlen, u8 *buf)
+{
+ return spinand_mtd_otp_read(mtd, ofs, len, retlen, buf, true);
+}
+
+static int spinand_mtd_user_otp_read(struct mtd_info *mtd, loff_t ofs,
+ size_t len, size_t *retlen, u8 *buf)
+{
+ return spinand_mtd_otp_read(mtd, ofs, len, retlen, buf, false);
+}
+
+static int spinand_mtd_user_otp_write(struct mtd_info *mtd, loff_t ofs,
+ size_t len, size_t *retlen, u_char *buf)
+{
+ struct spinand_device *spinand = mtd_to_spinand(mtd);
+ const struct spinand_user_otp_ops *ops = spinand->user_otp->ops;
+ int ret;
+
+ *retlen = 0;
+
+ if (!len)
+ return 0;
+
+ ret = spinand_user_otp_check_bounds(spinand, ofs, len);
+ if (ret)
+ return ret;
+
+ mutex_lock(&spinand->lock);
+ ret = ops->write(spinand, ofs, len, retlen, buf);
+ mutex_unlock(&spinand->lock);
+
+ return ret;
+}
+
+#ifndef __UBOOT__
+static int spinand_mtd_user_otp_erase(struct mtd_info *mtd, loff_t ofs,
+ size_t len)
+{
+ struct spinand_device *spinand = mtd_to_spinand(mtd);
+ const struct spinand_user_otp_ops *ops = spinand->user_otp->ops;
+ int ret;
+
+ if (!len)
+ return 0;
+
+ ret = spinand_user_otp_check_bounds(spinand, ofs, len);
+ if (ret)
+ return ret;
+
+ mutex_lock(&spinand->lock);
+ ret = ops->erase(spinand, ofs, len);
+ mutex_unlock(&spinand->lock);
+
+ return ret;
+}
+#endif
+
+static int spinand_mtd_user_otp_lock(struct mtd_info *mtd, loff_t ofs,
+ size_t len)
+{
+ struct spinand_device *spinand = mtd_to_spinand(mtd);
+ const struct spinand_user_otp_ops *ops = spinand->user_otp->ops;
+ int ret;
+
+ if (!len)
+ return 0;
+
+ ret = spinand_user_otp_check_bounds(spinand, ofs, len);
+ if (ret)
+ return ret;
+
+ mutex_lock(&spinand->lock);
+ ret = ops->lock(spinand, ofs, len);
+ mutex_unlock(&spinand->lock);
+
+ return ret;
+}
+
+/**
+ * spinand_set_mtd_otp_ops() - Setup OTP methods
+ * @spinand: the spinand device
+ *
+ * Setup OTP methods.
+ *
+ * Return: 0 on success, a negative error code otherwise.
+ */
+int spinand_set_mtd_otp_ops(struct spinand_device *spinand)
+{
+ struct mtd_info *mtd = spinand_to_mtd(spinand);
+ const struct spinand_fact_otp_ops *fact_ops = spinand->fact_otp->ops;
+ const struct spinand_user_otp_ops *user_ops = spinand->user_otp->ops;
+
+ if (!user_ops && !fact_ops)
+ return -EINVAL;
+
+ if (user_ops) {
+ if (user_ops->info)
+ mtd->_get_user_prot_info = spinand_mtd_user_otp_info;
+
+ if (user_ops->read)
+ mtd->_read_user_prot_reg = spinand_mtd_user_otp_read;
+
+ if (user_ops->write)
+ mtd->_write_user_prot_reg = spinand_mtd_user_otp_write;
+
+ if (user_ops->lock)
+ mtd->_lock_user_prot_reg = spinand_mtd_user_otp_lock;
+#ifndef __UBOOT__
+ if (user_ops->erase)
+ mtd->_erase_user_prot_reg = spinand_mtd_user_otp_erase;
+#endif
+ }
+
+ if (fact_ops) {
+ if (fact_ops->info)
+ mtd->_get_fact_prot_info = spinand_mtd_fact_otp_info;
+
+ if (fact_ops->read)
+ mtd->_read_fact_prot_reg = spinand_mtd_fact_otp_read;
+ }
+
+ return 0;
+}
diff --git a/drivers/mtd/nand/spi/paragon.c b/drivers/mtd/nand/spi/paragon.c
index 079431cea8f..a7106ae194b 100644
--- a/drivers/mtd/nand/spi/paragon.c
+++ b/drivers/mtd/nand/spi/paragon.c
@@ -11,8 +11,10 @@
#endif
#include <linux/mtd/spinand.h>
+
#define SPINAND_MFR_PARAGON 0xa1
+
#define PN26G0XA_STATUS_ECC_BITMASK (3 << 4)
#define PN26G0XA_STATUS_ECC_NONE_DETECTED (0 << 4)
@@ -20,21 +22,23 @@
#define PN26G0XA_STATUS_ECC_ERRORED (2 << 4)
#define PN26G0XA_STATUS_ECC_8_CORRECTED (3 << 4)
+
static SPINAND_OP_VARIANTS(read_cache_variants,
- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
static SPINAND_OP_VARIANTS(write_cache_variants,
- SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
- SPINAND_PROG_LOAD(true, 0, NULL, 0));
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
static SPINAND_OP_VARIANTS(update_cache_variants,
- SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
- SPINAND_PROG_LOAD(false, 0, NULL, 0));
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
+
static int pn26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
diff --git a/drivers/mtd/nand/spi/skyhigh.c b/drivers/mtd/nand/spi/skyhigh.c
new file mode 100644
index 00000000000..5e9487bd27a
--- /dev/null
+++ b/drivers/mtd/nand/spi/skyhigh.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2024 SkyHigh Memory Limited
+ *
+ * Author: Takahiro Kuwano <takahiro.kuwano@infineon.com>
+ * Co-Author: KR Kim <kr.kim@skyhighmemory.com>
+ */
+
+#ifndef __UBOOT__
+#include <linux/device.h>
+#include <linux/kernel.h>
+#endif
+#include <linux/mtd/spinand.h>
+
+#define SPINAND_MFR_SKYHIGH 0x01
+#define SKYHIGH_STATUS_ECC_1TO2_BITFLIPS (1 << 4)
+#define SKYHIGH_STATUS_ECC_3TO6_BITFLIPS (2 << 4)
+#define SKYHIGH_STATUS_ECC_UNCOR_ERROR (3 << 4)
+#define SKYHIGH_CONFIG_PROTECT_EN BIT(1)
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 4, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 2, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
+
+static int skyhigh_spinand_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ /* ECC bytes are stored in hidden area. */
+ return -ERANGE;
+}
+
+static int skyhigh_spinand_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section)
+ return -ERANGE;
+
+ /* ECC bytes are stored in hidden area. Reserve 2 bytes for the BBM. */
+ region->offset = 2;
+ region->length = mtd->oobsize - 2;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops skyhigh_spinand_ooblayout = {
+ .ecc = skyhigh_spinand_ooblayout_ecc,
+ .rfree = skyhigh_spinand_ooblayout_free,
+};
+
+static int skyhigh_spinand_ecc_get_status(struct spinand_device *spinand,
+ u8 status)
+{
+ switch (status & STATUS_ECC_MASK) {
+ case STATUS_ECC_NO_BITFLIPS:
+ return 0;
+
+ case SKYHIGH_STATUS_ECC_UNCOR_ERROR:
+ return -EBADMSG;
+
+ case SKYHIGH_STATUS_ECC_1TO2_BITFLIPS:
+ return 2;
+
+ case SKYHIGH_STATUS_ECC_3TO6_BITFLIPS:
+ return 6;
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static const struct spinand_info skyhigh_spinand_table[] = {
+ SPINAND_INFO("S35ML01G301",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(6, 32),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_NO_RAW_ACCESS,
+ SPINAND_ECCINFO(&skyhigh_spinand_ooblayout,
+ skyhigh_spinand_ecc_get_status)),
+ SPINAND_INFO("S35ML01G300",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(6, 32),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_NO_RAW_ACCESS,
+ SPINAND_ECCINFO(&skyhigh_spinand_ooblayout,
+ skyhigh_spinand_ecc_get_status)),
+ SPINAND_INFO("S35ML02G300",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
+ NAND_ECCREQ(6, 32),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_NO_RAW_ACCESS,
+ SPINAND_ECCINFO(&skyhigh_spinand_ooblayout,
+ skyhigh_spinand_ecc_get_status)),
+ SPINAND_INFO("S35ML04G300",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
+ NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 2, 1, 1),
+ NAND_ECCREQ(6, 32),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_NO_RAW_ACCESS,
+ SPINAND_ECCINFO(&skyhigh_spinand_ooblayout,
+ skyhigh_spinand_ecc_get_status)),
+};
+
+static int skyhigh_spinand_init(struct spinand_device *spinand)
+{
+ /*
+ * Config_Protect_En (bit 1 in Block Lock register) must be set to 1
+ * before writing other bits. Do it here before core unlocks all blocks
+ * by writing block protection bits.
+ */
+ return spinand_write_reg_op(spinand, REG_BLOCK_LOCK,
+ SKYHIGH_CONFIG_PROTECT_EN);
+}
+
+static const struct spinand_manufacturer_ops skyhigh_spinand_manuf_ops = {
+ .init = skyhigh_spinand_init,
+};
+
+const struct spinand_manufacturer skyhigh_spinand_manufacturer = {
+ .id = SPINAND_MFR_SKYHIGH,
+ .name = "SkyHigh",
+ .chips = skyhigh_spinand_table,
+ .nchips = ARRAY_SIZE(skyhigh_spinand_table),
+ .ops = &skyhigh_spinand_manuf_ops,
+};
diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c
index b9908e79271..2e7572d72b4 100644
--- a/drivers/mtd/nand/spi/toshiba.c
+++ b/drivers/mtd/nand/spi/toshiba.c
@@ -18,28 +18,28 @@
#define TOSH_STATUS_ECC_HAS_BITFLIPS_T (3 << 4)
static SPINAND_OP_VARIANTS(read_cache_variants,
- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
static SPINAND_OP_VARIANTS(write_cache_x4_variants,
- SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
- SPINAND_PROG_LOAD(true, 0, NULL, 0));
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
static SPINAND_OP_VARIANTS(update_cache_x4_variants,
- SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
- SPINAND_PROG_LOAD(false, 0, NULL, 0));
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
/*
* Backward compatibility for 1st generation Serial NAND devices
* which don't support Quad Program Load operation.
*/
static SPINAND_OP_VARIANTS(write_cache_variants,
- SPINAND_PROG_LOAD(true, 0, NULL, 0));
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
static SPINAND_OP_VARIANTS(update_cache_variants,
- SPINAND_PROG_LOAD(false, 0, NULL, 0));
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
static int tx58cxgxsxraix_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
@@ -76,7 +76,7 @@ static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand,
{
struct nand_device *nand = spinand_to_nand(spinand);
u8 mbf = 0;
- struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf);
+ struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(0x30, spinand->scratchbuf);
switch (status & STATUS_ECC_MASK) {
case STATUS_ECC_NO_BITFLIPS:
@@ -93,12 +93,12 @@ static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand,
* data around if it's not necessary.
*/
if (spi_mem_exec_op(spinand->slave, &op))
- return nand->eccreq.strength;
+ return nanddev_get_ecc_conf(nand)->strength;
- mbf >>= 4;
+ mbf = *(spinand->scratchbuf) >> 4;
- if (WARN_ON(mbf > nand->eccreq.strength || !mbf))
- return nand->eccreq.strength;
+ if (WARN_ON(mbf > nanddev_get_ecc_conf(nand)->strength || !mbf))
+ return nanddev_get_ecc_conf(nand)->strength;
return mbf;
@@ -269,6 +269,39 @@ static const struct spinand_info toshiba_spinand_table[] = {
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
tx58cxgxsxraix_ecc_get_status)),
+ /* 1.8V 1Gb (1st generation) */
+ SPINAND_INFO("TC58NYG0S3HBAI4",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA1),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
+ tx58cxgxsxraix_ecc_get_status)),
+ /* 1.8V 4Gb (1st generation) */
+ SPINAND_INFO("TH58NYG2S3HBAI4",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xAC),
+ NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 2, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_x4_variants,
+ &update_cache_x4_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
+ tx58cxgxsxraix_ecc_get_status)),
+ /* 1.8V 8Gb (1st generation) */
+ SPINAND_INFO("TH58NYG3S0HBAI6",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA3),
+ NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_x4_variants,
+ &update_cache_x4_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
+ tx58cxgxsxraix_ecc_get_status)),
};
static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = {
diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 16abf89dbbf..a89aaec516b 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -14,28 +14,83 @@
#include <linux/bitfield.h>
#include <linux/bug.h>
#include <linux/mtd/spinand.h>
+#include <linux/delay.h>
+
+#define HZ_PER_MHZ 1000000UL
#define SPINAND_MFR_WINBOND 0xEF
#define WINBOND_CFG_BUF_READ BIT(3)
-#define W25N04KV_STATUS_ECC_5_8_BITFLIPS FIELD_PREP_CONST(STATUS_ECC_MASK, 0x3)
+#define W25N04KV_STATUS_ECC_5_8_BITFLIPS (3 << 4)
+
+#define W25N0XJW_SR4 0xD0
+#define W25N0XJW_SR4_HS BIT(2)
+
+#define W35N01JW_VCR_IO_MODE 0x00
+#define W35N01JW_VCR_IO_MODE_SINGLE_SDR 0xFF
+#define W35N01JW_VCR_IO_MODE_OCTAL_SDR 0xDF
+#define W35N01JW_VCR_IO_MODE_OCTAL_DDR_DS 0xE7
+#define W35N01JW_VCR_IO_MODE_OCTAL_DDR 0xC7
+#define W35N01JW_VCR_DUMMY_CLOCK_REG 0x01
+
+/*
+ * "X2" in the core is equivalent to "dual output" in the datasheets,
+ * "X4" in the core is equivalent to "quad output" in the datasheets.
+ * Quad and octal capable chips feature an absolute maximum frequency of 166MHz.
+ */
+
+static SPINAND_OP_VARIANTS(read_cache_octal_variants,
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1D_8D_OP(0, 3, NULL, 0, 120 * HZ_PER_MHZ),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1D_8D_OP(0, 2, NULL, 0, 105 * HZ_PER_MHZ),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(0, 20, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(0, 16, NULL, 0, 162 * HZ_PER_MHZ),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(0, 12, NULL, 0, 124 * HZ_PER_MHZ),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(0, 8, NULL, 0, 86 * HZ_PER_MHZ),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_8S_OP(0, 2, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_8S_OP(0, 1, NULL, 0, 133 * HZ_PER_MHZ),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_octal_variants,
+ SPINAND_PROG_LOAD_1S_8S_8S_OP(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_8S_OP(0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_octal_variants,
+ SPINAND_PROG_LOAD_1S_8S_8S_OP(false, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(read_cache_dual_quad_dtr_variants,
+ SPINAND_PAGE_READ_FROM_CACHE_1S_4D_4D_OP(0, 8, NULL, 0, 80 * HZ_PER_MHZ),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1D_4D_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 4, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 104 * HZ_PER_MHZ),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_2D_2D_OP(0, 4, NULL, 0, 80 * HZ_PER_MHZ),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1D_2D_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 2, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 104 * HZ_PER_MHZ),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1D_1D_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 54 * HZ_PER_MHZ));
static SPINAND_OP_VARIANTS(read_cache_variants,
- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
static SPINAND_OP_VARIANTS(write_cache_variants,
- SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
- SPINAND_PROG_LOAD(true, 0, NULL, 0));
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
static SPINAND_OP_VARIANTS(update_cache_variants,
- SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
- SPINAND_PROG_LOAD(false, 0, NULL, 0));
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
static int w25m02gv_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
@@ -80,6 +135,18 @@ static int w25m02gv_select_target(struct spinand_device *spinand,
return spi_mem_exec_op(spinand->slave, &op);
}
+static int w25n01kv_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 3)
+ return -ERANGE;
+
+ region->offset = 64 + (8 * section);
+ region->length = 7;
+
+ return 0;
+}
+
static int w25n02kv_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
@@ -104,17 +171,57 @@ static int w25n02kv_ooblayout_free(struct mtd_info *mtd, int section,
return 0;
}
+static const struct mtd_ooblayout_ops w25n01kv_ooblayout = {
+ .ecc = w25n01kv_ooblayout_ecc,
+ .rfree = w25n02kv_ooblayout_free,
+};
+
static const struct mtd_ooblayout_ops w25n02kv_ooblayout = {
.ecc = w25n02kv_ooblayout_ecc,
.rfree = w25n02kv_ooblayout_free,
};
+static int w35n01jw_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 7)
+ return -ERANGE;
+
+ region->offset = (16 * section) + 12;
+ region->length = 4;
+
+ return 0;
+}
+
+static int w35n01jw_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 7)
+ return -ERANGE;
+
+ region->offset = 16 * section;
+ region->length = 12;
+
+ /* Extract BBM */
+ if (!section) {
+ region->offset += 2;
+ region->length -= 2;
+ }
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops w35n01jw_ooblayout = {
+ .ecc = w35n01jw_ooblayout_ecc,
+ .rfree = w35n01jw_ooblayout_free,
+};
+
static int w25n02kv_ecc_get_status(struct spinand_device *spinand,
u8 status)
{
struct nand_device *nand = spinand_to_nand(spinand);
u8 mbf = 0;
- struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf);
+ struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(0x30, spinand->scratchbuf);
switch (status & STATUS_ECC_MASK) {
case STATUS_ECC_NO_BITFLIPS:
@@ -131,12 +238,12 @@ static int w25n02kv_ecc_get_status(struct spinand_device *spinand,
* data around if it's not necessary.
*/
if (spi_mem_exec_op(spinand->slave, &op))
- return nand->eccreq.strength;
+ return nanddev_get_ecc_conf(nand)->strength;
- mbf >>= 4;
+ mbf = *(spinand->scratchbuf) >> 4;
- if (WARN_ON(mbf > nand->eccreq.strength || !mbf))
- return nand->eccreq.strength;
+ if (WARN_ON(mbf > nanddev_get_ecc_conf(nand)->strength || !mbf))
+ return nanddev_get_ecc_conf(nand)->strength;
return mbf;
@@ -147,18 +254,126 @@ static int w25n02kv_ecc_get_status(struct spinand_device *spinand,
return -EINVAL;
}
+static int w25n0xjw_hs_cfg(struct spinand_device *spinand)
+{
+ const struct spi_mem_op *op;
+ bool hs;
+ u8 sr4;
+ int ret;
+
+ op = spinand->op_templates.read_cache;
+ if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
+ hs = false;
+ else if (op->cmd.buswidth == 1 && op->addr.buswidth == 1 &&
+ op->dummy.buswidth == 1 && op->data.buswidth == 1)
+ hs = false;
+ else if (!op->max_freq)
+ hs = true;
+ else
+ hs = false;
+
+ ret = spinand_read_reg_op(spinand, W25N0XJW_SR4, &sr4);
+ if (ret)
+ return ret;
+
+ if (hs)
+ sr4 |= W25N0XJW_SR4_HS;
+ else
+ sr4 &= ~W25N0XJW_SR4_HS;
+
+ ret = spinand_write_reg_op(spinand, W25N0XJW_SR4, sr4);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int w35n0xjw_write_vcr(struct spinand_device *spinand, u8 reg, u8 val)
+{
+ struct spi_mem_op op =
+ SPI_MEM_OP(SPI_MEM_OP_CMD(0x81, 1),
+ SPI_MEM_OP_ADDR(3, reg, 1),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_OUT(1, spinand->scratchbuf, 1));
+ int ret;
+
+ *spinand->scratchbuf = val;
+
+ ret = spinand_write_enable_op(spinand);
+ if (ret)
+ return ret;
+
+ ret = spi_mem_exec_op(spinand->slave, &op);
+ if (ret)
+ return ret;
+
+ /*
+ * Write VCR operation doesn't set the busy bit in SR, which means we
+ * cannot perform a status poll. Minimum time of 50ns is needed to
+ * complete the write.
+ */
+ ndelay(50);
+
+ return 0;
+}
+
+static int w35n0xjw_vcr_cfg(struct spinand_device *spinand)
+{
+ const struct spi_mem_op *op;
+ unsigned int dummy_cycles;
+ bool dtr, single;
+ u8 io_mode;
+ int ret;
+
+ op = spinand->op_templates.read_cache;
+
+ single = (op->cmd.buswidth == 1 && op->addr.buswidth == 1 && op->data.buswidth == 1);
+ dtr = (op->cmd.dtr || op->addr.dtr || op->data.dtr);
+ if (single && !dtr)
+ io_mode = W35N01JW_VCR_IO_MODE_SINGLE_SDR;
+ else if (!single && !dtr)
+ io_mode = W35N01JW_VCR_IO_MODE_OCTAL_SDR;
+ else if (!single && dtr)
+ io_mode = W35N01JW_VCR_IO_MODE_OCTAL_DDR;
+ else
+ return -EINVAL;
+
+ ret = w35n0xjw_write_vcr(spinand, W35N01JW_VCR_IO_MODE, io_mode);
+ if (ret)
+ return ret;
+
+ dummy_cycles = ((op->dummy.nbytes * 8) / op->dummy.buswidth) / (op->dummy.dtr ? 2 : 1);
+ switch (dummy_cycles) {
+ case 8:
+ case 12:
+ case 16:
+ case 20:
+ case 24:
+ case 28:
+ break;
+ default:
+ return -EINVAL;
+ }
+ ret = w35n0xjw_write_vcr(spinand, W35N01JW_VCR_DUMMY_CLOCK_REG, dummy_cycles);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static const struct spinand_info winbond_spinand_table[] = {
- SPINAND_INFO("W25M02GV",
- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21),
- NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2),
+ /* 512M-bit densities */
+ SPINAND_INFO("W25N512GW", /* 1.8V */
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x20),
+ NAND_MEMORG(1, 2048, 64, 64, 512, 10, 1, 1, 1),
NAND_ECCREQ(1, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
- SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
- SPINAND_SELECT_TARGET(w25m02gv_select_target)),
- SPINAND_INFO("W25N01GV",
+ SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
+ /* 1G-bit densities */
+ SPINAND_INFO("W25N01GV", /* 3.3V */
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x21),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(1, 512),
@@ -167,7 +382,86 @@ static const struct spinand_info winbond_spinand_table[] = {
&update_cache_variants),
0,
SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
- SPINAND_INFO("W25N02KV",
+ SPINAND_INFO("W25N01GW", /* 1.8V */
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x21),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(1, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
+ SPINAND_INFO("W25N01JW", /* high-speed 1.8V */
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbc, 0x21),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(1, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_dual_quad_dtr_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
+ SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg)),
+ SPINAND_INFO("W25N01KV", /* 3.3V */
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xae, 0x21),
+ NAND_MEMORG(1, 2048, 96, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(4, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&w25n01kv_ooblayout, w25n02kv_ecc_get_status)),
+ SPINAND_INFO("W35N01JW", /* 1.8V */
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdc, 0x21),
+ NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 1, 1),
+ NAND_ECCREQ(1, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants,
+ &write_cache_octal_variants,
+ &update_cache_octal_variants),
+ 0,
+ SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
+ SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
+ SPINAND_INFO("W35N02JW", /* 1.8V */
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdf, 0x22),
+ NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 2, 1),
+ NAND_ECCREQ(1, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants,
+ &write_cache_octal_variants,
+ &update_cache_octal_variants),
+ 0,
+ SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
+ SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
+ SPINAND_INFO("W35N04JW", /* 1.8V */
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdf, 0x23),
+ NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 4, 1),
+ NAND_ECCREQ(1, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants,
+ &write_cache_octal_variants,
+ &update_cache_octal_variants),
+ 0,
+ SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
+ SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
+ /* 2G-bit densities */
+ SPINAND_INFO("W25M02GV", /* 2x1G-bit 3.3V */
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2),
+ NAND_ECCREQ(1, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
+ SPINAND_SELECT_TARGET(w25m02gv_select_target)),
+ SPINAND_INFO("W25N02JW", /* high-speed 1.8V */
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbf, 0x22),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 2, 1),
+ NAND_ECCREQ(1, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_dual_quad_dtr_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
+ SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg)),
+ SPINAND_INFO("W25N02KV", /* 3.3V */
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22),
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
@@ -176,7 +470,17 @@ static const struct spinand_info winbond_spinand_table[] = {
&update_cache_variants),
0,
SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
- SPINAND_INFO("W25N04KV",
+ SPINAND_INFO("W25N02KW", /* 1.8V */
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x22),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
+ /* 4G-bit densities */
+ SPINAND_INFO("W25N04KV", /* 3.3V */
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x23),
NAND_MEMORG(1, 2048, 128, 64, 4096, 40, 2, 1, 1),
NAND_ECCREQ(8, 512),
@@ -185,6 +489,15 @@ static const struct spinand_info winbond_spinand_table[] = {
&update_cache_variants),
0,
SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
+ SPINAND_INFO("W25N04KW", /* 1.8V */
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x23),
+ NAND_MEMORG(1, 2048, 128, 64, 4096, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
};
static int winbond_spinand_init(struct spinand_device *spinand)
diff --git a/drivers/mtd/nand/spi/xtx.c b/drivers/mtd/nand/spi/xtx.c
index aee1849a71f..3e1f884fd89 100644
--- a/drivers/mtd/nand/spi/xtx.c
+++ b/drivers/mtd/nand/spi/xtx.c
@@ -25,20 +25,20 @@
#define XT26XXXD_STATUS_ECC_UNCOR_ERROR (2)
static SPINAND_OP_VARIANTS(read_cache_variants,
- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+ SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
static SPINAND_OP_VARIANTS(write_cache_variants,
- SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
- SPINAND_PROG_LOAD(true, 0, NULL, 0));
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
static SPINAND_OP_VARIANTS(update_cache_variants,
- SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
- SPINAND_PROG_LOAD(false, 0, NULL, 0));
+ SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
+ SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
static int xt26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
diff --git a/drivers/mtd/nvmxip/nvmxip.c b/drivers/mtd/nvmxip/nvmxip.c
index 594500f0c65..3d8597aca76 100644
--- a/drivers/mtd/nvmxip/nvmxip.c
+++ b/drivers/mtd/nvmxip/nvmxip.c
@@ -41,7 +41,7 @@ static ulong nvmxip_blk_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcn
if (!buffer)
return -EINVAL;
- log_debug("[%s]: reading from blknr: %lu , blkcnt: %lu\n", dev->name, blknr, blkcnt);
+ log_debug("[%s]: reading from blknr: " LBAF " , blkcnt: " LBAF "\n", dev->name, blknr, blkcnt);
virt_blkaddr = map_sysmem(blkaddr, 0);
@@ -86,7 +86,7 @@ static int nvmxip_blk_probe(struct udevice *dev)
desc->blksz = BIT(plat->lba_shift);
desc->bdev = dev;
- log_debug("[%s]: block storage layout\n lbas: %lu , log2blksz: %d, blksz: %lu\n",
+ log_debug("[%s]: block storage layout\n lbas: " LBAF " , log2blksz: %d, blksz: %lu\n",
dev->name, desc->lba, desc->log2blksz, desc->blksz);
return 0;
diff --git a/drivers/mtd/nvmxip/nvmxip_qspi.c b/drivers/mtd/nvmxip/nvmxip_qspi.c
index f14a822b5d5..1a109bee557 100644
--- a/drivers/mtd/nvmxip/nvmxip_qspi.c
+++ b/drivers/mtd/nvmxip/nvmxip_qspi.c
@@ -49,7 +49,7 @@ static int nvmxip_qspi_of_to_plat(struct udevice *dev)
return -EINVAL;
}
- log_debug("[%s]: XIP device base addr: 0x%p , lba_shift: %d , lbas: %lu\n",
+ log_debug("[%s]: XIP device base addr: 0x%p , lba_shift: %d , lbas: " LBAF "\n",
dev->name, (void *)(uintptr_t)plat->phys_base, plat->lba_shift, plat->lba);
return 0;
diff --git a/drivers/mtd/spi/sf_dataflash.c b/drivers/mtd/spi/sf_dataflash.c
index 438eb3698d5..9094e008f60 100644
--- a/drivers/mtd/spi/sf_dataflash.c
+++ b/drivers/mtd/spi/sf_dataflash.c
@@ -138,11 +138,11 @@ static int spi_dataflash_erase(struct udevice *dev, u32 offset, size_t len)
memset(dataflash->command, 0 , sizeof(dataflash->command));
command = dataflash->command;
- debug("%s: erase addr=0x%x len 0x%x\n", dev->name, offset, len);
+ debug("%s: erase addr=0x%x len 0x%zx\n", dev->name, offset, len);
div_u64_rem(len, spi_flash->page_size, &rem);
if (rem) {
- printf("%s: len(0x%x) isn't the multiple of page size(0x%x)\n",
+ printf("%s: len(0x%zx) isn't the multiple of page size(0x%x)\n",
dev->name, len, spi_flash->page_size);
return -EINVAL;
}
@@ -229,7 +229,7 @@ static int spi_dataflash_read(struct udevice *dev, u32 offset, size_t len,
memset(dataflash->command, 0 , sizeof(dataflash->command));
command = dataflash->command;
- debug("%s: erase addr=0x%x len 0x%x\n", dev->name, offset, len);
+ debug("%s: erase addr=0x%x len 0x%zx\n", dev->name, offset, len);
debug("READ: (%x) %x %x %x\n",
command[0], command[1], command[2], command[3]);
@@ -287,7 +287,7 @@ int spi_dataflash_write(struct udevice *dev, u32 offset, size_t len,
memset(dataflash->command, 0 , sizeof(dataflash->command));
command = dataflash->command;
- debug("%s: write 0x%x..0x%x\n", dev->name, offset, (offset + len));
+ debug("%s: write 0x%x..0x%zx\n", dev->name, offset, (offset + len));
pageaddr = ((unsigned)offset / spi_flash->page_size);
to = ((unsigned)offset % spi_flash->page_size);
diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
index 0383175beb5..b6a07fa9063 100644
--- a/drivers/mtd/spi/spi-nor-ids.c
+++ b/drivers/mtd/spi/spi-nor-ids.c
@@ -591,6 +591,12 @@ const struct flash_info spi_nor_ids[] = {
{ INFO("w25m512jw", 0xef6119, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ INFO("w25m512jv", 0xef7119, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ INFO("w25h02jv", 0xef9022, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { INFO("w25h512nw-am", 0xefa020, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { INFO("w25h01nw-am", 0xefa021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { INFO("w25h02nw-am", 0xefa022, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { INFO("w25q01nw-iq", 0xef6021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { INFO("w25q01nw-im", 0xef8021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { INFO("w25q02nw-im", 0xef8022, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ INFO("w77q51nw", 0xef8a1a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
#endif
#ifdef CONFIG_SPI_FLASH_XMC
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 45699b4a477..2ec968c85ff 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -936,12 +936,7 @@ static int validate_vid_hdr(const struct ubi_device *ubi,
ubi_err(ubi, "bad data_size");
goto bad;
}
- } else if (lnum == used_ebs - 1) {
- if (data_size == 0) {
- ubi_err(ubi, "bad data_size at last LEB");
- goto bad;
- }
- } else {
+ } else if (lnum != used_ebs - 1) {
ubi_err(ubi, "too high lnum");
goto bad;
}
diff --git a/drivers/mtd/ubispl/ubispl.c b/drivers/mtd/ubispl/ubispl.c
index 9face5fae15..0143caa051d 100644
--- a/drivers/mtd/ubispl/ubispl.c
+++ b/drivers/mtd/ubispl/ubispl.c
@@ -779,7 +779,7 @@ static int ubi_scan_fastmap(struct ubi_scan_info *ubi,
* that already so we merily copy it over.
*/
if (pnum == fm_anchor)
- memcpy(vh, ubi->blockinfo + pnum, sizeof(*fm));
+ memcpy(vh, ubi->blockinfo + pnum, sizeof(*vh));
if (i == 0) {
if (be32_to_cpu(vh->vol_id) != UBI_FM_SB_VOLUME_ID) {
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index d1cb69f85ad..544e302d600 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -179,7 +179,7 @@ config CALXEDA_XGMAC
machines.
config DWC_ETH_XGMAC
- bool "Synopsys DWC Ethernet XGMAC device support"
+ bool
select PHYLIB
help
This driver supports the Synopsys Designware Ethernet XGMAC (10G
@@ -190,7 +190,8 @@ config DWC_ETH_XGMAC_SOCFPGA
bool "Synopsys DWC Ethernet XGMAC device support for SOCFPGA"
select REGMAP
select SYSCON
- depends on DWC_ETH_XGMAC
+ select DWC_ETH_XGMAC
+ depends on ARCH_SOCFPGA
default y if TARGET_SOCFPGA_AGILEX5
help
The Synopsys Designware Ethernet XGMAC IP block with specific
@@ -376,7 +377,7 @@ config ETH_DESIGNWARE_SOCFPGA
select SYSCON
select DW_ALTDESCRIPTOR
bool "Altera SoCFPGA extras for Synopsys Designware Ethernet MAC"
- depends on ETH_DESIGNWARE
+ depends on ARCH_SOCFPGA && ETH_DESIGNWARE
help
The Altera SoCFPGA requires additional configuration of the
Altera system manager to correctly interface with the PHY.
@@ -662,7 +663,7 @@ config MII
config RMII
bool "Enable RMII"
help
- Enable support of the Reduced Media-Independent Interface (MII)
+ Enable support of the Reduced Media-Independent Interface (RMII)
config PCNET
bool "AMD PCnet series Ethernet controller driver"
@@ -841,11 +842,12 @@ config GMAC_ROCKCHIP
config RENESAS_ETHER_SWITCH
bool "Renesas Ethernet Switch support"
- depends on DM_ETH && R8A779F0
+ depends on DM_ETH && (R8A779F0 || R8A78000)
select PHYLIB
help
This driver implements support for the Renesas Ethernet Switch
- which is available on R-Car S4 SoC (r8a779f0).
+ which is available on R-Car S4 SoC (R8A779F0) and newer version
+ on R-Car X5H SoC (R8A78000).
config RENESAS_RAVB
bool "Renesas Ethernet AVB MAC"
@@ -966,6 +968,9 @@ config TSEC_ENET
This driver implements support for the (Enhanced) Three-Speed
Ethernet Controller found on Freescale SoCs.
+config MDIO_MT7531_MMIO
+ bool
+
source "drivers/net/mtk_eth/Kconfig"
config HIFEMAC_ETH
@@ -1002,8 +1007,9 @@ config FSL_ENETC
config FSL_ENETC_NETC_BLK_CTRL
bool "NXP ENETC NETC blocks control driver"
- depends on FSL_ENETC && IMX95
- default y if IMX95
+ depends on FSL_ENETC
+ depends on IMX95 || IMX94
+ default y if IMX95 || IMX94
help
This driver configures Integrated Endpoint Register Block (IERB) and
Privileged Register Block (PRB) of NETC. For i.MX platforms, it also
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index f8f9a71f815..a3c3420898c 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -63,6 +63,7 @@ obj-$(CONFIG_MACB) += macb.o
obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
obj-$(CONFIG_MDIO_IPQ4019) += mdio-ipq4019.o
obj-$(CONFIG_MDIO_GPIO_BITBANG) += mdio_gpio.o
+obj-$(CONFIG_MDIO_MT7531_MMIO) += mdio-mt7531-mmio.o
obj-$(CONFIG_MDIO_MUX_I2CREG) += mdio_mux_i2creg.o
obj-$(CONFIG_MDIO_MUX_MESON_G12A) += mdio_mux_meson_g12a.o
obj-$(CONFIG_MDIO_MUX_MESON_GXL) += mdio_mux_meson_gxl.o
diff --git a/drivers/net/airoha_eth.c b/drivers/net/airoha_eth.c
index 6588eb3a806..3234d875887 100644
--- a/drivers/net/airoha_eth.c
+++ b/drivers/net/airoha_eth.c
@@ -21,6 +21,7 @@
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/time.h>
+#include <asm/arch/scu-regmap.h>
#define AIROHA_MAX_NUM_GDM_PORTS 1
#define AIROHA_MAX_NUM_QDMA 1
@@ -312,6 +313,25 @@ struct airoha_eth {
struct airoha_gdm_port *ports[AIROHA_MAX_NUM_GDM_PORTS];
};
+struct airoha_eth_soc_data {
+ int num_xsi_rsts;
+ const char * const *xsi_rsts_names;
+ const char *switch_compatible;
+};
+
+static const char * const en7523_xsi_rsts_names[] = {
+ "hsi0-mac",
+ "hsi1-mac",
+ "hsi-mac",
+};
+
+static const char * const en7581_xsi_rsts_names[] = {
+ "hsi0-mac",
+ "hsi1-mac",
+ "hsi-mac",
+ "xfp-mac",
+};
+
static u32 airoha_rr(void __iomem *base, u32 offset)
{
return readl(base + offset);
@@ -449,14 +469,10 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q,
RX_RING_SIZE_MASK,
FIELD_PREP(RX_RING_SIZE_MASK, ndesc));
- /*
- * See arht_eth_free_pkt() for the reasons used to fill
- * REG_RX_CPU_IDX(qid) register.
- */
airoha_qdma_rmw(qdma, REG_RX_RING_SIZE(qid), RX_RING_THR_MASK,
FIELD_PREP(RX_RING_THR_MASK, 0));
airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK,
- FIELD_PREP(RX_RING_CPU_IDX_MASK, q->ndesc - 3));
+ FIELD_PREP(RX_RING_CPU_IDX_MASK, q->ndesc - 1));
airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK,
FIELD_PREP(RX_RING_DMA_IDX_MASK, q->head));
@@ -682,10 +698,12 @@ static int airoha_hw_init(struct udevice *dev,
static int airoha_switch_init(struct udevice *dev, struct airoha_eth *eth)
{
+ struct airoha_eth_soc_data *data = (void *)dev_get_driver_data(dev);
ofnode switch_node;
fdt_addr_t addr;
- switch_node = ofnode_by_compatible(ofnode_null(), "airoha,en7581-switch");
+ switch_node = ofnode_by_compatible(ofnode_null(),
+ data->switch_compatible);
if (!ofnode_valid(switch_node))
return -EINVAL;
@@ -722,16 +740,12 @@ static int airoha_switch_init(struct udevice *dev, struct airoha_eth *eth)
static int airoha_eth_probe(struct udevice *dev)
{
+ struct airoha_eth_soc_data *data = (void *)dev_get_driver_data(dev);
struct airoha_eth *eth = dev_get_priv(dev);
struct regmap *scu_regmap;
- ofnode scu_node;
- int ret;
+ int i, ret;
- scu_node = ofnode_by_compatible(ofnode_null(), "airoha,en7581-scu");
- if (!ofnode_valid(scu_node))
- return -EINVAL;
-
- scu_regmap = syscon_node_to_regmap(scu_node);
+ scu_regmap = airoha_get_scu_regmap();
if (IS_ERR(scu_regmap))
return PTR_ERR(scu_regmap);
@@ -751,11 +765,11 @@ static int airoha_eth_probe(struct udevice *dev)
return -ENOMEM;
eth->rsts.count = AIROHA_MAX_NUM_RSTS;
- eth->xsi_rsts.resets = devm_kcalloc(dev, AIROHA_MAX_NUM_XSI_RSTS,
+ eth->xsi_rsts.resets = devm_kcalloc(dev, data->num_xsi_rsts,
sizeof(struct reset_ctl), GFP_KERNEL);
if (!eth->xsi_rsts.resets)
return -ENOMEM;
- eth->xsi_rsts.count = AIROHA_MAX_NUM_XSI_RSTS;
+ eth->xsi_rsts.count = data->num_xsi_rsts;
ret = reset_get_by_name(dev, "fe", &eth->rsts.resets[0]);
if (ret)
@@ -769,21 +783,12 @@ static int airoha_eth_probe(struct udevice *dev)
if (ret)
return ret;
- ret = reset_get_by_name(dev, "hsi0-mac", &eth->xsi_rsts.resets[0]);
- if (ret)
- return ret;
-
- ret = reset_get_by_name(dev, "hsi1-mac", &eth->xsi_rsts.resets[1]);
- if (ret)
- return ret;
-
- ret = reset_get_by_name(dev, "hsi-mac", &eth->xsi_rsts.resets[2]);
- if (ret)
- return ret;
-
- ret = reset_get_by_name(dev, "xfp-mac", &eth->xsi_rsts.resets[3]);
- if (ret)
- return ret;
+ for (i = 0; i < data->num_xsi_rsts; i++) {
+ ret = reset_get_by_name(dev, data->xsi_rsts_names[i],
+ &eth->xsi_rsts.resets[i]);
+ if (ret)
+ return ret;
+ }
ret = airoha_hw_init(dev, eth);
if (ret)
@@ -920,7 +925,6 @@ static int arht_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
struct airoha_qdma *qdma = &eth->qdma[0];
struct airoha_queue *q;
int qid;
- u16 prev, pprev;
if (!packet)
return 0;
@@ -930,22 +934,29 @@ static int arht_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
/*
* Due to cpu cache issue the airoha_qdma_reset_rx_desc() function
- * will always touch 2 descriptors:
- * - if current descriptor is even, then the previous and the one
- * before previous descriptors will be touched (previous cacheline)
- * - if current descriptor is odd, then only current and previous
- * descriptors will be touched (current cacheline)
+ * will always touch 2 descriptors placed on the same cacheline:
+ * - if current descriptor is even, then current and next
+ * descriptors will be touched
+ * - if current descriptor is odd, then current and previous
+ * descriptors will be touched
*
- * Thus, to prevent possible destroying of rx queue, only (q->ndesc - 2)
- * descriptors might be used for packet receiving.
+ * Thus, to prevent possible destroying of rx queue, we should:
+ * - do nothing in the even descriptor case,
+ * - utilize 2 descriptors (current and previous one) in the
+ * odd descriptor case.
+ *
+ * WARNING: Observations shows that PKTBUFSRX must be even and
+ * larger than 7 for reliable driver operations.
*/
- prev = (q->head + q->ndesc - 1) % q->ndesc;
- pprev = (q->head + q->ndesc - 2) % q->ndesc;
- q->head = (q->head + 1) % q->ndesc;
+ if (q->head & 0x01) {
+ airoha_qdma_reset_rx_desc(q, q->head - 1);
+ airoha_qdma_reset_rx_desc(q, q->head);
- airoha_qdma_reset_rx_desc(q, prev);
- airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK,
- FIELD_PREP(RX_RING_CPU_IDX_MASK, pprev));
+ airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK,
+ FIELD_PREP(RX_RING_CPU_IDX_MASK, q->head));
+ }
+
+ q->head = (q->head + 1) % q->ndesc;
return 0;
}
@@ -971,8 +982,25 @@ static int arht_eth_write_hwaddr(struct udevice *dev)
return 0;
}
+static const struct airoha_eth_soc_data en7523_data = {
+ .xsi_rsts_names = en7523_xsi_rsts_names,
+ .num_xsi_rsts = ARRAY_SIZE(en7523_xsi_rsts_names),
+ .switch_compatible = "airoha,en7523-switch",
+};
+
+static const struct airoha_eth_soc_data en7581_data = {
+ .xsi_rsts_names = en7581_xsi_rsts_names,
+ .num_xsi_rsts = ARRAY_SIZE(en7581_xsi_rsts_names),
+ .switch_compatible = "airoha,en7581-switch",
+};
+
static const struct udevice_id airoha_eth_ids[] = {
- { .compatible = "airoha,en7581-eth" },
+ { .compatible = "airoha,en7523-eth",
+ .data = (ulong)&en7523_data,
+ },
+ { .compatible = "airoha,en7581-eth",
+ .data = (ulong)&en7581_data,
+ },
{ }
};
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 7ecedc3d7f0..6ed9c6d538a 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -125,6 +125,16 @@ static int dw_mdio_reset(struct mii_dev *bus)
return __dw_mdio_reset(dev);
}
+
+#if IS_ENABLED(CONFIG_BITBANGMII)
+static int dw_bb_mdio_reset(struct mii_dev *bus)
+{
+ struct dw_eth_dev *priv = bus->priv;
+
+ return __dw_mdio_reset(priv->dev);
+}
+#endif
+
#endif
#if IS_ENABLED(CONFIG_DM_MDIO)
@@ -348,7 +358,7 @@ static int dw_bb_mdio_init(const char *name, struct udevice *dev)
bus->read = dw_bb_miiphy_read;
bus->write = dw_bb_miiphy_write;
#if CONFIG_IS_ENABLED(DM_GPIO)
- bus->reset = dw_mdio_reset;
+ bus->reset = dw_bb_mdio_reset;
#endif
bus->priv = dwpriv;
@@ -894,7 +904,7 @@ int designware_eth_probe(struct udevice *dev)
if (ret) {
debug("%s: No phy supply\n", dev->name);
} else {
- ret = regulator_set_enable(phy_supply, true);
+ ret = regulator_set_enable_if_allowed(phy_supply, true);
if (ret) {
puts("Error enabling phy supply\n");
return ret;
diff --git a/drivers/net/fsl_enetc_mdio.c b/drivers/net/fsl_enetc_mdio.c
index c1d491f2c5a..3d76d92a62a 100644
--- a/drivers/net/fsl_enetc_mdio.c
+++ b/drivers/net/fsl_enetc_mdio.c
@@ -11,6 +11,8 @@
#include <asm/io.h>
#include <asm/processor.h>
#include <miiphy.h>
+#include <linux/delay.h>
+#include <power/regulator.h>
#include "fsl_enetc.h"
@@ -135,6 +137,8 @@ static int enetc_mdio_probe(struct udevice *dev)
struct pci_child_plat *pplat = dev_get_parent_plat(dev);
struct enetc_mdio_priv *priv = dev_get_priv(dev);
u16 cmd = PCI_COMMAND_MEMORY;
+ int ret;
+ struct udevice *supply = NULL;
priv->regs_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE, 0);
if (!priv->regs_base) {
@@ -144,6 +148,27 @@ static int enetc_mdio_probe(struct udevice *dev)
priv->regs_base += ENETC_MDIO_BASE;
+ if (CONFIG_IS_ENABLED(DM_REGULATOR)) {
+ ret = device_get_supply_regulator(dev, "phy-supply",
+ &supply);
+ if (ret && ret != -ENOENT) {
+ printf("%s: device_get_supply_regulator failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ if (supply) {
+ regulator_set_enable(supply, false);
+ mdelay(100);
+
+ ret = regulator_set_enable_if_allowed(supply, true);
+ if (ret) {
+ printf("%s: Error enabling phy supply\n", dev->name);
+ return ret;
+ }
+ }
+ }
+
if (pplat->vendor == PCI_VENDOR_ID_PHILIPS) /* i.MX95 */
cmd |= PCI_COMMAND_MASTER;
diff --git a/drivers/net/fsl_enetc_netc_blk_ctrl.c b/drivers/net/fsl_enetc_netc_blk_ctrl.c
index fecd66eb15a..8577bb75632 100644
--- a/drivers/net/fsl_enetc_netc_blk_ctrl.c
+++ b/drivers/net/fsl_enetc_netc_blk_ctrl.c
@@ -43,6 +43,18 @@
#define PCS_PROT_SFI BIT(4)
#define PCS_PROT_10G_SXGMII BIT(6)
+#define IMX94_MISC_SOC_CONTROL 0x0
+#define SEL_XPCS_1 BIT(1)
+#define IMX94_XPCS_PORT_0 0x0
+#define IMX94_XPCS_PORT_1 0x1
+
+#define IMX94_EXT_PIN_CONTROL 0x10
+#define MAC2_MAC3_SEL BIT(1)
+
+#define IMX94_NETC_LINK_CFG(a) (0x4c + (a) * 4)
+#define NETC_LINK_CFG_MII_PROT GENMASK(3, 0)
+#define NETC_LINK_CFG_IO_VAR GENMASK(19, 16)
+
/* NETC privileged register block register */
#define PRB_NETCRR 0x100
#define NETCRR_SR BIT(0)
@@ -55,6 +67,7 @@
/* NETC integrated endpoint register block register */
#define IERB_EMDIOFAUXR 0x344
#define IERB_T0FAUXR 0x444
+#define IERB_ETBCR(a) (0x300c + 0x100 * (a))
#define IERB_EFAUXR(a) (0x3044 + 0x100 * (a))
#define IERB_VFAUXR(a) (0x4004 + 0x40 * (a))
#define FAUXR_LDID GENMASK(3, 0)
@@ -64,6 +77,26 @@
#define IMX95_ENETC1_BUS_DEVFN 0x40
#define IMX95_ENETC2_BUS_DEVFN 0x80
+#define IMX94_ENETC3_BUS_DEVFN 0x0
+#define IMX94_TIMER0_BUS_DEVFN 0x1
+#define IMX94_SWITCH_BUS_DEVFN 0x2
+#define IMX94_ENETC0_BUS_DEVFN 0x100
+#define IMX94_TIMER1_BUS_DEVFN 0x101
+#define IMX94_ENETC1_BUS_DEVFN 0x140
+#define IMX94_ENETC2_BUS_DEVFN 0x180
+#define IMX94_TIMER2_BUS_DEVFN 0x181
+#define IMX94_ENETC0_LINK 3
+#define IMX94_ENETC1_LINK 4
+#define IMX94_ENETC2_LINK 5
+#define IMX94_ENETC0_OFFSET 0
+#define IMX94_ENETC1_OFFSET 1
+#define IMX94_ENETC2_OFFSET 2
+#define IMX94_SWITCH_PORT2 2
+#define IMX94_SWITCH_CPU_PORT 3
+#define IMX94_TIMER0_ID 0
+#define IMX94_TIMER1_ID 1
+#define IMX94_TIMER2_ID 2
+
/* Flags for different platforms */
#define NETC_HAS_NETCMIX BIT(0)
@@ -73,6 +106,15 @@ struct netc_blk_ctrl {
void __iomem *netcmix;
};
+struct netc_devinfo {
+ int (*netcmix_init)(struct udevice *dev);
+ int (*ierb_init)(struct udevice *dev);
+ void (*xpcs_port_init)(struct netc_blk_ctrl *priv, int port);
+};
+
+static struct netc_blk_ctrl *netc_bc;
+static struct netc_devinfo *netc_di;
+
static void netc_reg_write(void __iomem *base, u32 offset, u32 val)
{
writel(val, base + offset);
@@ -183,6 +225,142 @@ static int imx95_netcmix_init(struct udevice *dev)
return 0;
}
+static int imx94_enetc_get_link_num(ofnode np)
+{
+ int bus_devfn;
+
+ bus_devfn = netc_of_pci_get_bus_devfn(np);
+ if (bus_devfn < 0)
+ return -EINVAL;
+
+ /* Parse ENETC link number */
+ switch (bus_devfn) {
+ case IMX94_ENETC0_BUS_DEVFN:
+ return IMX94_ENETC0_LINK;
+ case IMX94_ENETC1_BUS_DEVFN:
+ return IMX94_ENETC1_LINK;
+ case IMX94_ENETC2_BUS_DEVFN:
+ return IMX94_ENETC2_LINK;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int imx94_link_config(struct netc_blk_ctrl *priv,
+ ofnode np, int link_id)
+{
+ phy_interface_t interface;
+ int mii_proto;
+ u32 val;
+
+ interface = ofnode_read_phy_mode(np);
+ if (interface == -1)
+ return -EINVAL;
+
+ mii_proto = netc_get_link_mii_protocol(interface);
+ if (mii_proto < 0)
+ return -EINVAL;
+
+ val = mii_proto & NETC_LINK_CFG_MII_PROT;
+ if (mii_proto == MII_PROT_SERIAL)
+ val = u32_replace_bits(val, IO_VAR_16FF_16G_SERDES,
+ NETC_LINK_CFG_IO_VAR);
+
+ netc_reg_write(priv->netcmix, IMX94_NETC_LINK_CFG(link_id), val);
+
+ if (link_id == IMX94_ENETC0_LINK) {
+ val = netc_reg_read(priv->netcmix, IMX94_EXT_PIN_CONTROL);
+ val |= MAC2_MAC3_SEL;
+ netc_reg_write(priv->netcmix, IMX94_EXT_PIN_CONTROL, val);
+ }
+
+ return 0;
+}
+
+static int imx94_enetc_link_config(struct netc_blk_ctrl *priv,
+ ofnode np, bool *enetc0_en)
+{
+ int link_id;
+
+ link_id = imx94_enetc_get_link_num(np);
+ if (link_id < 0)
+ return -EINVAL;
+
+ if (link_id == IMX94_ENETC0_LINK)
+ *enetc0_en = true;
+
+ return imx94_link_config(priv, np, link_id);
+}
+
+static int imx94_switch_link_config(struct netc_blk_ctrl *priv,
+ ofnode np, bool *swp2_en)
+{
+ ofnode ports, child;
+ int port_id, err = 0;
+
+ ports = ofnode_find_subnode(np, "ports");
+ if (!ofnode_valid(ports))
+ ports = ofnode_find_subnode(np, "ethernet-ports");
+ if (!ofnode_valid(ports))
+ return -ENODEV;
+
+ ofnode_for_each_subnode(child, ports) {
+ if (ofnode_read_u32(child, "reg", &port_id) < 0) {
+ err = -ENODEV;
+ goto end;
+ }
+
+ if (port_id == IMX94_SWITCH_CPU_PORT)
+ continue;
+
+ if (port_id == IMX94_SWITCH_PORT2)
+ *swp2_en = true;
+
+ err = imx94_link_config(priv, child, port_id);
+ if (err)
+ goto end;
+ }
+
+end:
+ return err;
+}
+
+static int imx94_netcmix_init(struct udevice *dev)
+{
+ struct netc_blk_ctrl *priv = dev_get_priv(dev);
+ ofnode child, gchild;
+ bool enetc0_en = false, swp2_en = false;
+ int err;
+
+ dev_for_each_subnode(child, dev) {
+ if (!ofnode_is_enabled(child))
+ continue;
+
+ ofnode_for_each_subnode(gchild, child) {
+ if (!ofnode_is_enabled(gchild))
+ continue;
+
+ if (ofnode_device_is_compatible(gchild, "pci1131,e101")) {
+ err = imx94_enetc_link_config(priv, gchild, &enetc0_en);
+ if (err)
+ return err;
+ } else if (ofnode_device_is_compatible(gchild, "pci1131,eef2")) {
+ err = imx94_switch_link_config(priv, gchild, &swp2_en);
+ if (err)
+ return err;
+ }
+ }
+ }
+
+ if (enetc0_en && swp2_en) {
+ dev_err(dev, "Cannot enable swp2 and enetc0 at the same time\n");
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static bool netc_ierb_is_locked(struct netc_blk_ctrl *priv)
{
return !!(netc_reg_read(priv->prb, PRB_NETCRR) & NETCRR_LOCK);
@@ -238,9 +416,99 @@ static int imx95_ierb_init(struct udevice *dev)
return 0;
}
+static int imx94_enetc_get_enetc_offset(ofnode np)
+{
+ int bus_devfn;
+
+ bus_devfn = netc_of_pci_get_bus_devfn(np);
+ if (bus_devfn < 0)
+ return -EINVAL;
+
+ /* Parse ENETC offset */
+ switch (bus_devfn) {
+ case IMX94_ENETC0_BUS_DEVFN:
+ return IMX94_ENETC0_OFFSET;
+ case IMX94_ENETC1_BUS_DEVFN:
+ return IMX94_ENETC1_OFFSET;
+ case IMX94_ENETC2_BUS_DEVFN:
+ return IMX94_ENETC2_OFFSET;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int imx94_enetc_get_timer_id(ofnode np)
+{
+ int bus_devfn;
+
+ bus_devfn = netc_of_pci_get_bus_devfn(np);
+ if (bus_devfn < 0)
+ return -EINVAL;
+
+ /* Parse ENETC PTP timer ID */
+ switch (bus_devfn) {
+ case IMX94_TIMER0_BUS_DEVFN:
+ return IMX94_TIMER0_ID;
+ case IMX94_TIMER1_BUS_DEVFN:
+ return IMX94_TIMER1_ID;
+ case IMX94_TIMER2_BUS_DEVFN:
+ return IMX94_TIMER2_ID;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int imx94_enetc_update_tid(struct netc_blk_ctrl *priv, ofnode pf_np)
+{
+ ofnode timer_np;
+ int offset, tid;
+
+ offset = imx94_enetc_get_enetc_offset(pf_np);
+ if (offset < 0) {
+ printf("Find unknown PF node.\n");
+ return offset;
+ }
+
+ timer_np = ofnode_parse_phandle(pf_np, "nxp,ptp-timer", 0);
+ if (!ofnode_valid(timer_np)) {
+ /*
+ * If nxp,ptp-timer is not set, the first timer of the bus
+ * where enetc is located will be used as the default timer.
+ */
+ tid = IMX94_TIMER1_ID;
+ goto update_reg;
+ }
+
+ tid = imx94_enetc_get_timer_id(timer_np);
+ if (tid < 0) {
+ printf("Incorrect bus/devfn of ptp-timer.\n");
+ return tid;
+ }
+
+update_reg:
+ netc_reg_write(priv->ierb, IERB_ETBCR(offset), tid);
+
+ return 0;
+}
+
+static int imx94_ierb_init(struct udevice *dev)
+{
+ struct netc_blk_ctrl *priv = dev_get_priv(dev);
+ ofnode bus_np, pf_np;
+ int ret = 0;
+
+ dev_for_each_subnode(bus_np, dev)
+ ofnode_for_each_subnode(pf_np, bus_np)
+ if (ofnode_device_is_compatible(pf_np, "pci1131,e101"))
+ ret = imx94_enetc_update_tid(priv, pf_np);
+
+ return ret;
+}
+
static int netc_ierb_init(struct udevice *dev)
{
struct netc_blk_ctrl *priv = dev_get_priv(dev);
+ struct netc_devinfo *devinfo = (struct netc_devinfo *)dev_get_driver_data(dev);
int err;
if (netc_ierb_is_locked(priv)) {
@@ -251,9 +519,11 @@ static int netc_ierb_init(struct udevice *dev)
}
}
- err = imx95_ierb_init(dev);
- if (err)
- return err;
+ if (devinfo->ierb_init) {
+ err = devinfo->ierb_init(dev);
+ if (err)
+ return err;
+ }
err = netc_lock_ierb(priv);
if (err) {
@@ -264,6 +534,31 @@ static int netc_ierb_init(struct udevice *dev)
return 0;
}
+static void imx94_netc_xpcs_port_init(struct netc_blk_ctrl *priv, int port)
+{
+ u32 val;
+
+ val = netc_reg_read(priv->netcmix, IMX94_MISC_SOC_CONTROL);
+ if (port == IMX94_XPCS_PORT_1)
+ val |= SEL_XPCS_1;
+ else
+ val &= ~SEL_XPCS_1;
+ netc_reg_write(priv->netcmix, IMX94_MISC_SOC_CONTROL, val);
+}
+
+void netc_xpcs_port_init(int port)
+{
+ struct netc_blk_ctrl *priv = netc_bc;
+ struct netc_devinfo *devinfo;
+
+ if (!priv)
+ return;
+
+ devinfo = netc_di;
+ if (devinfo->xpcs_port_init)
+ devinfo->xpcs_port_init(priv, port);
+}
+
static int netc_prb_check_error(struct netc_blk_ctrl *priv)
{
if (netc_reg_read(priv->prb, PRB_NETCSR) & NETCSR_ERROR)
@@ -272,14 +567,27 @@ static int netc_prb_check_error(struct netc_blk_ctrl *priv)
return 0;
}
+static const struct netc_devinfo imx95_devinfo = {
+ .netcmix_init = imx95_netcmix_init,
+ .ierb_init = imx95_ierb_init,
+};
+
+static const struct netc_devinfo imx94_devinfo = {
+ .netcmix_init = imx94_netcmix_init,
+ .ierb_init = imx94_ierb_init,
+ .xpcs_port_init = imx94_netc_xpcs_port_init,
+};
+
static const struct udevice_id netc_blk_ctrl_match[] = {
- { .compatible = "nxp,imx95-netc-blk-ctrl" },
+ { .compatible = "nxp,imx95-netc-blk-ctrl", .data = (ulong)&imx95_devinfo },
+ { .compatible = "nxp,imx94-netc-blk-ctrl", .data = (ulong)&imx94_devinfo },
{},
};
static int netc_blk_ctrl_probe(struct udevice *dev)
{
struct netc_blk_ctrl *priv = dev_get_priv(dev);
+ struct netc_devinfo *devinfo = (struct netc_devinfo *)dev_get_driver_data(dev);
struct clk *ipg_clk;
fdt_addr_t regs;
int err;
@@ -318,10 +626,12 @@ static int netc_blk_ctrl_probe(struct udevice *dev)
priv->netcmix = (void __iomem *)regs;
- err = imx95_netcmix_init(dev);
- if (err) {
- dev_err(dev, "Initializing NETCMIX failed\n");
- return err;
+ if (devinfo->netcmix_init) {
+ err = devinfo->netcmix_init(dev);
+ if (err) {
+ dev_err(dev, "Initializing NETCMIX failed\n");
+ return err;
+ }
}
err = netc_ierb_init(dev);
@@ -333,6 +643,9 @@ static int netc_blk_ctrl_probe(struct udevice *dev)
if (netc_prb_check_error(priv) < 0)
dev_warn(dev, "The current IERB configuration is invalid\n");
+ netc_bc = priv;
+ netc_di = devinfo;
+
return 0;
}
diff --git a/drivers/net/mdio-mt7531-mmio.c b/drivers/net/mdio-mt7531-mmio.c
new file mode 100644
index 00000000000..3e325ca58da
--- /dev/null
+++ b/drivers/net/mdio-mt7531-mmio.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <asm/io.h>
+#include <dm.h>
+#include <linux/bitfield.h>
+#include <linux/iopoll.h>
+#include <miiphy.h>
+
+#define MT7531_PHY_IAC 0x701c
+#define MT7531_PHY_ACS_ST BIT(31)
+#define MT7531_MDIO_REG_ADDR_CL22 GENMASK(29, 25)
+#define MT7531_MDIO_DEV_ADDR MT7531_MDIO_REG_ADDR_CL22
+#define MT7531_MDIO_PHY_ADDR GENMASK(24, 20)
+#define MT7531_MDIO_CMD GENMASK(19, 18)
+#define MT7531_MDIO_CMD_READ_CL45 FIELD_PREP_CONST(MT7531_MDIO_CMD, 0x3)
+#define MT7531_MDIO_CMD_READ_CL22 FIELD_PREP_CONST(MT7531_MDIO_CMD, 0x2)
+#define MT7531_MDIO_CMD_WRITE FIELD_PREP_CONST(MT7531_MDIO_CMD, 0x1)
+#define MT7531_MDIO_CMD_ADDR FIELD_PREP_CONST(MT7531_MDIO_CMD, 0x0)
+#define MT7531_MDIO_ST GENMASK(17, 16)
+#define MT7531_MDIO_ST_CL22 FIELD_PREP_CONST(MT7531_MDIO_ST, 0x1)
+#define MT7531_MDIO_ST_CL45 FIELD_PREP_CONST(MT7531_MDIO_ST, 0x0)
+#define MT7531_MDIO_RW_DATA GENMASK(15, 0)
+#define MT7531_MDIO_REG_ADDR_CL45 MT7531_MDIO_RW_DATA
+
+#define MT7531_MDIO_TIMEOUT 100000
+#define MT7531_MDIO_SLEEP 20
+
+struct mt7531_mdio_priv {
+ phys_addr_t switch_regs;
+};
+
+static int mt7531_mdio_wait_busy(struct mt7531_mdio_priv *priv)
+{
+ unsigned int busy;
+
+ return readl_poll_sleep_timeout(priv->switch_regs + MT7531_PHY_IAC,
+ busy, (busy & MT7531_PHY_ACS_ST) == 0,
+ MT7531_MDIO_SLEEP, MT7531_MDIO_TIMEOUT);
+}
+
+static int mt7531_mdio_read(struct mt7531_mdio_priv *priv, int addr, int devad, int reg)
+{
+ u32 val;
+
+ if (devad != MDIO_DEVAD_NONE) {
+ if (mt7531_mdio_wait_busy(priv))
+ return -ETIMEDOUT;
+
+ val = MT7531_PHY_ACS_ST |
+ MT7531_MDIO_ST_CL45 | MT7531_MDIO_CMD_ADDR |
+ FIELD_PREP(MT7531_MDIO_PHY_ADDR, addr) |
+ FIELD_PREP(MT7531_MDIO_DEV_ADDR, devad) |
+ FIELD_PREP(MT7531_MDIO_REG_ADDR_CL45, reg);
+
+ writel(val, priv->switch_regs + MT7531_PHY_IAC);
+ }
+
+ if (mt7531_mdio_wait_busy(priv))
+ return -ETIMEDOUT;
+
+ val = MT7531_PHY_ACS_ST | FIELD_PREP(MT7531_MDIO_PHY_ADDR, addr);
+ if (devad != MDIO_DEVAD_NONE)
+ val |= MT7531_MDIO_ST_CL45 | MT7531_MDIO_CMD_READ_CL45 |
+ FIELD_PREP(MT7531_MDIO_DEV_ADDR, devad);
+ else
+ val |= MT7531_MDIO_ST_CL22 | MT7531_MDIO_CMD_READ_CL22 |
+ FIELD_PREP(MT7531_MDIO_REG_ADDR_CL22, reg);
+
+ writel(val, priv->switch_regs + MT7531_PHY_IAC);
+
+ if (mt7531_mdio_wait_busy(priv))
+ return -ETIMEDOUT;
+
+ val = readl(priv->switch_regs + MT7531_PHY_IAC);
+ return val & MT7531_MDIO_RW_DATA;
+}
+
+static int mt7531_mdio_write(struct mt7531_mdio_priv *priv, int addr, int devad,
+ int reg, u16 value)
+{
+ u32 val;
+
+ if (devad != MDIO_DEVAD_NONE) {
+ if (mt7531_mdio_wait_busy(priv))
+ return -ETIMEDOUT;
+
+ val = MT7531_PHY_ACS_ST |
+ MT7531_MDIO_ST_CL45 | MT7531_MDIO_CMD_ADDR |
+ FIELD_PREP(MT7531_MDIO_PHY_ADDR, addr) |
+ FIELD_PREP(MT7531_MDIO_DEV_ADDR, devad) |
+ FIELD_PREP(MT7531_MDIO_REG_ADDR_CL45, reg);
+
+ writel(val, priv->switch_regs + MT7531_PHY_IAC);
+ }
+
+ if (mt7531_mdio_wait_busy(priv))
+ return -ETIMEDOUT;
+
+ val = MT7531_PHY_ACS_ST | FIELD_PREP(MT7531_MDIO_PHY_ADDR, addr) |
+ MT7531_MDIO_CMD_WRITE | FIELD_PREP(MT7531_MDIO_RW_DATA, value);
+ if (devad != MDIO_DEVAD_NONE)
+ val |= MT7531_MDIO_ST_CL45 |
+ FIELD_PREP(MT7531_MDIO_DEV_ADDR, devad);
+ else
+ val |= MT7531_MDIO_ST_CL22 |
+ FIELD_PREP(MT7531_MDIO_REG_ADDR_CL22, reg);
+
+ writel(val, priv->switch_regs + MT7531_PHY_IAC);
+
+ if (mt7531_mdio_wait_busy(priv))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+int mt7531_mdio_mmio_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+ struct mt7531_mdio_priv *priv = bus->priv;
+
+ return mt7531_mdio_read(priv, addr, devad, reg);
+}
+
+int mt7531_mdio_mmio_write(struct mii_dev *bus, int addr, int devad,
+ int reg, u16 value)
+{
+ struct mt7531_mdio_priv *priv = bus->priv;
+
+ return mt7531_mdio_write(priv, addr, devad, reg, value);
+}
+
+static int dm_mt7531_mdio_read(struct udevice *dev, int addr, int devad, int reg)
+{
+ struct mt7531_mdio_priv *priv = dev_get_priv(dev);
+
+ return mt7531_mdio_read(priv, addr, devad, reg);
+}
+
+static int dm_mt7531_mdio_write(struct udevice *dev, int addr, int devad,
+ int reg, u16 value)
+{
+ struct mt7531_mdio_priv *priv = dev_get_priv(dev);
+
+ return mt7531_mdio_write(priv, addr, devad, reg, value);
+}
+
+static const struct mdio_ops mt7531_mdio_ops = {
+ .read = dm_mt7531_mdio_read,
+ .write = dm_mt7531_mdio_write,
+};
+
+static int mt7531_mdio_probe(struct udevice *dev)
+{
+ struct mt7531_mdio_priv *priv = dev_get_priv(dev);
+
+ priv->switch_regs = dev_read_addr(dev);
+ if (priv->switch_regs == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(mt7531_mdio) = {
+ .name = "mt7531-mdio-mmio",
+ .id = UCLASS_MDIO,
+ .probe = mt7531_mdio_probe,
+ .ops = &mt7531_mdio_ops,
+ .priv_auto = sizeof(struct mt7531_mdio_priv),
+};
diff --git a/drivers/net/mdio-mt7531-mmio.h b/drivers/net/mdio-mt7531-mmio.h
new file mode 100644
index 00000000000..f98102cb939
--- /dev/null
+++ b/drivers/net/mdio-mt7531-mmio.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+struct mt7531_mdio_mmio_priv {
+ phys_addr_t switch_regs;
+};
+
+int mt7531_mdio_mmio_read(struct mii_dev *bus, int addr, int devad, int reg);
+int mt7531_mdio_mmio_write(struct mii_dev *bus, int addr, int devad,
+ int reg, u16 value);
diff --git a/drivers/net/mdio_mux_meson_gxl.c b/drivers/net/mdio_mux_meson_gxl.c
index 8ef3ae598b7..31898ed437e 100644
--- a/drivers/net/mdio_mux_meson_gxl.c
+++ b/drivers/net/mdio_mux_meson_gxl.c
@@ -19,6 +19,7 @@
#define REG2_LEDACT GENMASK(23, 22)
#define REG2_LEDLINK GENMASK(25, 24)
#define REG2_DIV4SEL BIT(27)
+#define REG2_REVERSED BIT(28)
#define REG2_ADCBYPASS BIT(30)
#define REG2_CLKINSEL BIT(31)
#define ETH_REG3 0x4
@@ -66,7 +67,7 @@ static int meson_gxl_enable_internal_mdio(struct mdio_mux_meson_gxl_priv *priv)
* The only constraint is that it must match the one in
* drivers/net/phy/meson-gxl.c to properly match the PHY.
*/
- writel(FIELD_PREP(REG2_PHYID, EPHY_GXL_ID),
+ writel(REG2_REVERSED | FIELD_PREP(REG2_PHYID, EPHY_GXL_ID),
priv->regs + ETH_REG2);
/* Enable the internal phy */
diff --git a/drivers/net/mtk_eth/Kconfig b/drivers/net/mtk_eth/Kconfig
index e8cdf408237..5d4e54ab90e 100644
--- a/drivers/net/mtk_eth/Kconfig
+++ b/drivers/net/mtk_eth/Kconfig
@@ -1,6 +1,7 @@
config MEDIATEK_ETH
bool "MediaTek Ethernet GMAC Driver"
+ depends on ARCH_MEDIATEK || ARCH_MTMIPS
select PHYLIB
select DM_GPIO
select DM_RESET
@@ -30,6 +31,7 @@ config MTK_ETH_SWITCH_MT7531
config MTK_ETH_SWITCH_MT7988
bool "Support for MediaTek MT7988 built-in ethernet switch"
depends on TARGET_MT7988
+ select MDIO_MT7531_MMIO
default y
config MTK_ETH_SWITCH_AN8855
diff --git a/drivers/net/mtk_eth/mt7531.c b/drivers/net/mtk_eth/mt7531.c
index 32d6bebbbdb..965bc3cb7e9 100644
--- a/drivers/net/mtk_eth/mt7531.c
+++ b/drivers/net/mtk_eth/mt7531.c
@@ -22,17 +22,13 @@
static int mt7531_core_reg_read(struct mt753x_switch_priv *priv, u32 reg)
{
- u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0);
-
- return mt7531_mmd_read(priv, phy_addr, 0x1f, reg);
+ return mt7531_mmd_read(priv, 0, 0x1f, reg);
}
static void mt7531_core_reg_write(struct mt753x_switch_priv *priv, u32 reg,
u32 val)
{
- u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0);
-
- mt7531_mmd_write(priv, phy_addr, 0x1f, reg, val);
+ mt7531_mmd_write(priv, 0, 0x1f, reg, val);
}
static void mt7531_core_pll_setup(struct mt753x_switch_priv *priv)
@@ -171,7 +167,7 @@ static int mt7531_setup(struct mtk_eth_switch_priv *swpriv)
{
struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
u32 i, val, pmcr, port5_sgmii;
- u16 phy_addr, phy_val;
+ u16 phy_val;
priv->smi_addr = MT753X_DFL_SMI_ADDR;
priv->phy_base = (priv->smi_addr + 1) & MT753X_SMI_ADDR_MASK;
@@ -180,10 +176,9 @@ static int mt7531_setup(struct mtk_eth_switch_priv *swpriv)
/* Turn off PHYs */
for (i = 0; i < MT753X_NUM_PHYS; i++) {
- phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
- phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
+ phy_val = mt7531_mii_read(priv, i, MII_BMCR);
phy_val |= BMCR_PDOWN;
- mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
+ mt7531_mii_write(priv, i, MII_BMCR, phy_val);
}
/* Force MAC link down before reset */
@@ -239,10 +234,9 @@ static int mt7531_setup(struct mtk_eth_switch_priv *swpriv)
/* Turn on PHYs */
for (i = 0; i < MT753X_NUM_PHYS; i++) {
- phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
- phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
+ phy_val = mt7531_mii_read(priv, i, MII_BMCR);
phy_val &= ~BMCR_PDOWN;
- mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
+ mt7531_mii_write(priv, i, MII_BMCR, phy_val);
}
mt7531_phy_setting(priv);
diff --git a/drivers/net/mtk_eth/mt7988.c b/drivers/net/mtk_eth/mt7988.c
index a416d87840c..29b6363cbd7 100644
--- a/drivers/net/mtk_eth/mt7988.c
+++ b/drivers/net/mtk_eth/mt7988.c
@@ -6,6 +6,7 @@
* Author: Mark Lee <mark-mc.lee@mediatek.com>
*/
+#include <malloc.h>
#include <miiphy.h>
#include <linux/delay.h>
#include <linux/mdio.h>
@@ -14,6 +15,8 @@
#include "mtk_eth.h"
#include "mt753x.h"
+#include "../mdio-mt7531-mmio.h"
+
static int mt7988_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data)
{
*data = readl(priv->epriv.ethsys_base + GSW_BASE + reg);
@@ -30,20 +33,34 @@ static int mt7988_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data)
static void mt7988_phy_setting(struct mt753x_switch_priv *priv)
{
+ struct mii_dev *mdio_bus = priv->mdio_bus;
u16 val;
u32 i;
for (i = 0; i < MT753X_NUM_PHYS; i++) {
+ u16 addr = MT753X_PHY_ADDR(priv->phy_base, i);
+
+ /* Set PHY to PHY page 1 */
+ mt7531_mdio_mmio_write(mdio_bus, addr, MDIO_DEVAD_NONE,
+ 0x1f, 0x1);
+
/* Enable HW auto downshift */
- mt7531_mii_write(priv, i, 0x1f, 0x1);
- val = mt7531_mii_read(priv, i, PHY_EXT_REG_14);
+ val = mt7531_mdio_mmio_read(mdio_bus, addr, MDIO_DEVAD_NONE,
+ PHY_EXT_REG_14);
val |= PHY_EN_DOWN_SHFIT;
- mt7531_mii_write(priv, i, PHY_EXT_REG_14, val);
+ mt7531_mdio_mmio_write(mdio_bus, addr, MDIO_DEVAD_NONE,
+ PHY_EXT_REG_14, val);
/* PHY link down power saving enable */
- val = mt7531_mii_read(priv, i, PHY_EXT_REG_17);
+ val = mt7531_mdio_mmio_read(mdio_bus, addr, MDIO_DEVAD_NONE,
+ PHY_EXT_REG_17);
val |= PHY_LINKDOWN_POWER_SAVING_EN;
- mt7531_mii_write(priv, i, PHY_EXT_REG_17, val);
+ mt7531_mdio_mmio_write(mdio_bus, addr, MDIO_DEVAD_NONE,
+ PHY_EXT_REG_17, val);
+
+ /* Restore PHY to PHY page 0 */
+ mt7531_mdio_mmio_write(mdio_bus, addr, MDIO_DEVAD_NONE,
+ 0x1f, 0x0);
}
}
@@ -58,24 +75,66 @@ static void mt7988_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable)
mt7988_reg_write(priv, PMCR_REG(6), pmcr);
}
+static int mt7988_mdio_register(struct mt753x_switch_priv *priv)
+{
+ struct mt7531_mdio_mmio_priv *mdio_priv;
+ struct mii_dev *mdio_bus = mdio_alloc();
+ int ret;
+
+ if (!mdio_bus)
+ return -ENOMEM;
+
+ mdio_priv = malloc(sizeof(*mdio_priv));
+ if (!mdio_priv)
+ return -ENOMEM;
+
+ mdio_priv->switch_regs = (phys_addr_t)priv->epriv.ethsys_base + GSW_BASE;
+
+ mdio_bus->read = mt7531_mdio_mmio_read;
+ mdio_bus->write = mt7531_mdio_mmio_write;
+ snprintf(mdio_bus->name, sizeof(mdio_bus->name), priv->epriv.sw->name);
+
+ mdio_bus->priv = mdio_priv;
+
+ ret = mdio_register(mdio_bus);
+ if (ret) {
+ free(mdio_bus->priv);
+ mdio_free(mdio_bus);
+ return ret;
+ }
+
+ priv->mdio_bus = mdio_bus;
+
+ return 0;
+}
+
static int mt7988_setup(struct mtk_eth_switch_priv *swpriv)
{
struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
+ struct mii_dev *mdio_bus;
u16 phy_addr, phy_val;
+ int ret, i;
u32 pmcr;
- int i;
priv->smi_addr = MT753X_DFL_SMI_ADDR;
priv->phy_base = (priv->smi_addr + 1) & MT753X_SMI_ADDR_MASK;
priv->reg_read = mt7988_reg_read;
priv->reg_write = mt7988_reg_write;
+ ret = mt7988_mdio_register(priv);
+ if (ret)
+ return ret;
+
+ mdio_bus = priv->mdio_bus;
+
/* Turn off PHYs */
for (i = 0; i < MT753X_NUM_PHYS; i++) {
phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
- phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
+ phy_val = mt7531_mdio_mmio_read(mdio_bus, phy_addr,
+ MDIO_DEVAD_NONE, MII_BMCR);
phy_val |= BMCR_PDOWN;
- mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
+ mt7531_mdio_mmio_write(mdio_bus, phy_addr, MDIO_DEVAD_NONE,
+ MII_BMCR, phy_val);
}
switch (priv->epriv.phy_interface) {
@@ -129,21 +188,26 @@ static int mt7988_setup(struct mtk_eth_switch_priv *swpriv)
/* Turn on PHYs */
for (i = 0; i < MT753X_NUM_PHYS; i++) {
phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
- phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
+ phy_val = mt7531_mdio_mmio_read(mdio_bus, phy_addr,
+ MDIO_DEVAD_NONE, MII_BMCR);
phy_val &= ~BMCR_PDOWN;
- mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
+ mt7531_mdio_mmio_write(mdio_bus, phy_addr, MDIO_DEVAD_NONE,
+ MII_BMCR, phy_val);
}
mt7988_phy_setting(priv);
- return mt7531_mdio_register(priv);
+ return 0;
}
-static int mt7531_cleanup(struct mtk_eth_switch_priv *swpriv)
+static int mt7988_cleanup(struct mtk_eth_switch_priv *swpriv)
{
struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
+ struct mii_dev *mdio_bus = priv->mdio_bus;
- mdio_unregister(priv->mdio_bus);
+ mdio_unregister(mdio_bus);
+ free(mdio_bus->priv);
+ mdio_free(mdio_bus);
return 0;
}
@@ -155,6 +219,6 @@ MTK_ETH_SWITCH(mt7988) = {
.reset_wait_time = 50,
.setup = mt7988_setup,
- .cleanup = mt7531_cleanup,
+ .cleanup = mt7988_cleanup,
.mac_control = mt7988_mac_control,
};
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 185c6a3156e..018be98705a 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -56,6 +56,7 @@ endif # B53_SWITCH
config MV88E61XX_SWITCH
bool "Marvell MV88E61xx Ethernet switch PHY support."
+ depends on !COMPILE_TEST
if MV88E61XX_SWITCH
@@ -119,6 +120,7 @@ config PHY_BROADCOM
config PHY_CORTINA
bool "Cortina Ethernet PHYs support"
+ depends on !COMPILE_TEST
config SYS_CORTINA_NO_FW_UPLOAD
bool "Cortina firmware loading support"
diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c
index f63a13824ca..903fcd667f6 100644
--- a/drivers/net/phy/aquantia.c
+++ b/drivers/net/phy/aquantia.c
@@ -338,7 +338,7 @@ static int aquantia_set_proto(struct phy_device *phydev,
static int aquantia_dts_config(struct phy_device *phydev)
{
- ofnode node = phydev->node;
+ ofnode node = phy_get_ofnode(phydev);
u32 prop;
u16 reg;
diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig
index bbda951e7d9..933271f01fa 100644
--- a/drivers/net/phy/mediatek/Kconfig
+++ b/drivers/net/phy/mediatek/Kconfig
@@ -6,8 +6,8 @@ config MTK_NET_PHYLIB
config PHY_MEDIATEK_2P5GE
bool "MediaTek built-in 2.5Gb ethernet PHYs"
depends on OF_CONTROL && (TARGET_MT7987 || TARGET_MT7988)
+ select FW_LOADER
select MTK_NET_PHYLIB
- select FS_LOADER
help
Supports MediaTek SoC built-in 2.5Gb ethernet PHYs.
diff --git a/drivers/net/phy/mediatek/mtk-2p5ge.c b/drivers/net/phy/mediatek/mtk-2p5ge.c
index ab5007389a9..4090db0b474 100644
--- a/drivers/net/phy/mediatek/mtk-2p5ge.c
+++ b/drivers/net/phy/mediatek/mtk-2p5ge.c
@@ -10,7 +10,7 @@
#include <dm/of_access.h>
#include <dm/pinctrl.h>
#include <dm/ofnode.h>
-#include <fs_loader.h>
+#include <fw_loader.h>
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/iopoll.h>
@@ -249,7 +249,7 @@ int __weak mt7987_i2p5ge_get_fw(void **fw, size_t *fwsize,
return -ENOMEM;
ret = request_firmware_into_buf_via_script(
- &pmb, MT7987_2P5GE_PMB_FW_SIZE,
+ pmb, MT7987_2P5GE_PMB_FW_SIZE,
"mt7987_i2p5ge_load_pmb_firmware", fwsize);
if (ret) {
free(pmb);
@@ -263,7 +263,7 @@ int __weak mt7987_i2p5ge_get_fw(void **fw, size_t *fwsize,
}
ret = request_firmware_into_buf_via_script(
- &dsp, MT7987_2P5GE_DSPBITTB_SIZE,
+ dsp, MT7987_2P5GE_DSPBITTB_SIZE,
"mt7987_i2p5ge_load_dspbit_firmware", dspfwsize);
if (ret) {
free(pmb);
@@ -476,7 +476,7 @@ int __weak mt7988_i2p5ge_get_fw(void **fw, size_t *size)
return -ENOMEM;
ret = request_firmware_into_buf_via_script(
- &pmb, MT7988_2P5GE_PMB_FW_SIZE,
+ pmb, MT7988_2P5GE_PMB_FW_SIZE,
"mt7988_i2p5ge_load_pmb_firmware", size);
if (ret) {
free(pmb);
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 9702d042296..b58283fe3d5 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -1250,3 +1250,116 @@ bool phy_interface_is_ncsi(void)
return 0;
#endif
}
+
+/**
+ * __phy_read_page() - read the current page
+ * @phydev: a pointer to a &struct phy_device
+ *
+ * Returns page index or < 0 on error
+ */
+static int __phy_read_page(struct phy_device *phydev)
+{
+ struct phy_driver *drv = phydev->drv;
+
+ if (!drv->read_page) {
+ debug("read_page callback not available, PHY driver not loaded?\n");
+ return -EOPNOTSUPP;
+ }
+
+ return drv->read_page(phydev);
+}
+
+/**
+ * __phy_write_page() - Write a new page
+ * @phydev: a pointer to a &struct phy_device
+ * @page: page index to select
+ *
+ * Returns 0 or < 0 on error.
+ */
+static int __phy_write_page(struct phy_device *phydev, int page)
+{
+ struct phy_driver *drv = phydev->drv;
+
+ if (!drv->write_page) {
+ debug("write_page callback not available, PHY driver not loaded?\n");
+ return -EOPNOTSUPP;
+ }
+
+ return drv->write_page(phydev, page);
+}
+
+/**
+ * phy_save_page() - save the current page
+ * @phydev: a pointer to a &struct phy_device
+ *
+ * Return the current page number. On error,
+ * returns a negative errno. phy_restore_page() must always be called
+ * after this, irrespective of success or failure of this call.
+ */
+int phy_save_page(struct phy_device *phydev)
+{
+ return __phy_read_page(phydev);
+}
+
+/**
+ * phy_select_page - Switch to a PHY page and return the previous page
+ * @phydev: a pointer to a &struct phy_device
+ * @page: desired page
+ *
+ * NOTE: Save the current PHY page, and set the current page.
+ * On error, returns a negative errno, otherwise returns the previous page number.
+ * phy_restore_page() must always be called after this, irrespective
+ * of success or failure of this call.
+ */
+int phy_select_page(struct phy_device *phydev, int page)
+{
+ int ret, oldpage;
+
+ oldpage = ret = phy_save_page(phydev);
+ if (ret < 0)
+ return ret;
+
+ if (oldpage != page) {
+ ret = __phy_write_page(phydev, page);
+ if (ret < 0)
+ return ret;
+ }
+
+ return oldpage;
+}
+
+/**
+ * phy_restore_page - Restore a previously saved page and propagate status
+ * @phydev: a pointer to a &struct phy_device
+ * @oldpage: the old page, return value from phy_save_page() or phy_select_page()
+ * @ret: operation's return code
+ *
+ * Restoring @oldpage if it is a valid page.
+ * This function propagates the earliest error code from the group of
+ * operations.
+ *
+ * Returns:
+ * @oldpage if it was a negative value, otherwise
+ * @ret if it was a negative errno value, otherwise
+ * phy_write_page()'s negative value if it were in error, otherwise
+ * @ret.
+ */
+int phy_restore_page(struct phy_device *phydev, int oldpage, int ret)
+{
+ int r;
+
+ if (oldpage >= 0) {
+ r = __phy_write_page(phydev, oldpage);
+
+ /* Propagate the operation return code if the page write
+ * was successful.
+ */
+ if (ret >= 0 && r < 0)
+ ret = r;
+ } else {
+ /* Propagate the phy page selection error code */
+ ret = oldpage;
+ }
+
+ return ret;
+} \ No newline at end of file
diff --git a/drivers/net/rswitch.c b/drivers/net/rswitch.c
index f27587ac8bd..801c22bbdc7 100644
--- a/drivers/net/rswitch.c
+++ b/drivers/net/rswitch.c
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Driver for Renesas Ethernet RSwitch2 (Ethernet-TSN).
+ * Driver for Renesas Ethernet RSwitch2 and RSwitch3 (Ethernet-TSN).
*
- * Copyright (C) 2021 Renesas Electronics Corporation
+ * Copyright (C) 2021-2025 Renesas Electronics Corporation
*
* Based on the Renesas Ethernet AVB driver.
*/
@@ -27,68 +27,61 @@
#define RSWITCH_SLEEP_US 1000
#define RSWITCH_TIMEOUT_US 1000000
-#define RSWITCH_NUM_HW 5
-
-#define ETHA_TO_GWCA(i) ((i) % 2)
-#define GWCA_TO_HW_INDEX(i) ((i) + 3)
-#define HW_INDEX_TO_GWCA(i) ((i) - 3)
+#define GWCA_TO_HW_INDEX(i, pt) ((i) + (pt))
+#define HW_INDEX_TO_GWCA(i, pt) ((i) - (pt))
#define RSWITCH_MAX_CTAG_PCP 7
/* Registers */
-#define RSWITCH_COMA_OFFSET 0x00009000
-#define RSWITCH_ETHA_OFFSET 0x0000a000 /* with RMAC */
#define RSWITCH_ETHA_SIZE 0x00002000 /* with RMAC */
-#define RSWITCH_GWCA_OFFSET 0x00010000
#define RSWITCH_GWCA_SIZE 0x00002000
-#define FWRO 0
-#define CARO RSWITCH_COMA_OFFSET
-#define GWRO 0
-#define TARO 0
-#define RMRO 0x1000
-
/* List of TSNA registers (ETHA) */
-#define EAMC (TARO + 0x0000)
-#define EAMS (TARO + 0x0004)
-#define EATDQDCR (TARO + 0x0060)
-#define EATTFC (TARO + 0x0138)
-#define EATASRIRM (TARO + 0x03e4)
+#define EAMC 0x0000
+#define EAMS 0x0004
+#define EATDQDCR 0x0060
+#define EATTFC 0x0138
+#define EATASRIRM 0x03e4
/* Gateway CPU agent block (GWCA) */
-#define GWMC (GWRO + 0x0000)
-#define GWMS (GWRO + 0x0004)
-#define GWMTIRM (GWRO + 0x0100)
-#define GWVCC (GWRO + 0x0130)
-#define GWTTFC (GWRO + 0x0138)
-#define GWDCBAC0 (GWRO + 0x0194)
-#define GWDCBAC1 (GWRO + 0x0198)
-#define GWTRCR (GWRO + 0x0200)
-#define GWARIRM (GWRO + 0x0380)
-#define GWDCCR (GWRO + 0x0400)
+#define GWMC 0x0000
+#define GWMS 0x0004
+#define GWMTIRM 0x0100
+#define GWVCC 0x0130
+#define GWCKSC 0x013c
+#define GWTTFC 0x0138
+#define GWDCBAC0 0x0194
+#define GWDCBAC1 0x0198
+#define GWTRCR 0x0200
+#define GWARIRM 0x0380
+#define GWDCCR 0x0400
/* List of Common Agent registers (COMA) */
-#define RRC (CARO + 0x0004)
-#define RCEC (CARO + 0x0008)
-#define RCDC (CARO + 0x000c)
-#define CABPIRM (CARO + 0x0140)
+#define RRC 0x0004
+#define RCEC 0x0008
+#define RCDC 0x000c
+#define CABPIRM 0x0140
/* List of MFWD registers */
-#define FWPC (FWRO + 0x0100)
-#define FWPBFCR (FWRO + 0x4a00)
-#define FWPBFCSDCR (FWRO + 0x4a04)
+#define FWPC 0x0100
+#define FWPBFCR 0x4a00
+#define FWPBFCSDCR 0x4a04
/* List of RMAC registers (RMAC) */
-#define MPSM (RMRO + 0x0000)
-#define MPIC (RMRO + 0x0004)
-#define MRMAC0 (RMRO + 0x0084)
-#define MRMAC1 (RMRO + 0x0088)
-#define MRAFC (RMRO + 0x008c)
-#define MRSCE (RMRO + 0x0090)
-#define MRSCP (RMRO + 0x0094)
-#define MLVC (RMRO + 0x0180)
-#define MLBC (RMRO + 0x0188)
-#define MXGMIIC (RMRO + 0x0190)
-#define MPCH (RMRO + 0x0194)
-#define MANM (RMRO + 0x019c)
-#define MMIS0 (RMRO + 0x0210)
-#define MMIS1 (RMRO + 0x0220)
+#define MPSM 0x1000
+#define MPIC 0x1004
+#define MIOC 0x1010
+#define MRMAC0 0x1084
+#define MRMAC1 0x1088
+#define MRAFC 0x108c
+#define MRSCE 0x1090
+#define MRSCP 0x1094
+#define MLVC 0x1180
+#define MLBC 0x1188
+#define MXGMIIC 0x1190
+#define MPCH 0x1194
+#define MANM 0x119c
+#define MMIS0 0x1210
+#define MMIS1 0x1220
+
+/* MIOC */
+#define MIOC_BIT3_SET BIT(3)
/* COMA */
#define RRC_RR BIT(0)
@@ -117,8 +110,9 @@
FWPC0_IPDSA | FWPC0_IPHLA | FWPC0_MACSDA | \
FWPC0_MACHLA | FWPC0_MACHMA | FWPC0_VLANSA)
-#define FWPBFC(i) (FWPBFCR + (i) * 0x10)
-#define FWPBFCSDC(j, i) (FWPBFCSDCR + (i) * 0x10 + (j) * 0x04)
+#define FWPBFC(i) (FWPBFCR + (i) * 0x10)
+#define FWPBFCSDC(regoff, gwcaidx, ethaidx, ethaincr) \
+ (FWPBFCSDCR + (regoff) + (ethaidx) * (ethaincr) + (gwcaidx) * 0x04)
/* ETHA */
#define EATASRIRM_TASRIOG BIT(0)
@@ -138,7 +132,6 @@
#define MPIC_PSMCS_MASK (0x7f << 16)
#define MPIC_PSMHT_MASK (0x06 << 24)
-#define MPIC_MDC_CLK_SET (0x06050000)
#define MPSM_MFF_C45 BIT(2)
#define MPSM_MFF_C22 0x0
@@ -192,13 +185,20 @@ enum rswitch_gwca_mode {
#define GWDCC(i) (GWDCCR + (i) * 0x04)
#define GWDCC_DQT BIT(11)
#define GWDCC_BALR BIT(24)
+#define GWCKSC_USMFSPE BIT(31)
-struct rswitch_etha {
+struct rswitch_etha_io {
int index;
void __iomem *addr;
+};
+
+struct rswitch_etha {
+ struct rswitch_etha_io mii;
+ struct rswitch_etha_io serdes;
struct phy_device *phydev;
struct mii_dev *bus;
unsigned char *enetaddr;
+ bool xpcs;
};
struct rswitch_gwca {
@@ -207,11 +207,6 @@ struct rswitch_gwca {
int num_chain;
};
-/* Setting value */
-#define LINK_SPEED_100 100
-#define LINK_SPEED_1000 1000
-#define LINK_SPEED_2500 2500
-
/* Decriptor */
#define RSWITCH_NUM_BASE_DESC 2
#define RSWITCH_TX_CHAIN_INDEX 0
@@ -220,43 +215,43 @@ struct rswitch_gwca {
#define RSWITCH_NUM_RX_DESC 8
enum RX_DS_CC_BIT {
- RX_DS = 0x0fff, /* Data size */
- RX_TR = 0x1000, /* Truncation indication */
- RX_EI = 0x2000, /* Error indication */
- RX_PS = 0xc000, /* Padding selection */
+ RX_DS = 0x0fff, /* Data size */
+ RX_TR = 0x1000, /* Truncation indication */
+ RX_EI = 0x2000, /* Error indication */
+ RX_PS = 0xc000, /* Padding selection */
};
enum DIE_DT {
/* Frame data */
- DT_FSINGLE = 0x80,
- DT_FSTART = 0x90,
- DT_FMID = 0xa0,
- DT_FEND = 0xb8,
+ DT_FSINGLE = 0x80,
+ DT_FSTART = 0x90,
+ DT_FMID = 0xa0,
+ DT_FEND = 0xb8,
/* Chain control */
- DT_LEMPTY = 0xc0,
- DT_EEMPTY = 0xd0,
- DT_LINKFIX = 0x00,
- DT_LINK = 0xe0,
- DT_EOS = 0xf0,
+ DT_LEMPTY = 0xc0,
+ DT_EEMPTY = 0xd0,
+ DT_LINKFIX = 0x00,
+ DT_LINK = 0xe0,
+ DT_EOS = 0xf0,
/* HW/SW arbitration */
- DT_FEMPTY = 0x40,
- DT_FEMPTY_IS = 0x10,
- DT_FEMPTY_IC = 0x20,
- DT_FEMPTY_ND = 0x38,
+ DT_FEMPTY = 0x40,
+ DT_FEMPTY_IS = 0x10,
+ DT_FEMPTY_IC = 0x20,
+ DT_FEMPTY_ND = 0x38,
DT_FEMPTY_START = 0x50,
- DT_FEMPTY_MID = 0x60,
- DT_FEMPTY_END = 0x70,
+ DT_FEMPTY_MID = 0x60,
+ DT_FEMPTY_END = 0x70,
- DT_MASK = 0xf0,
- DIE = 0x08, /* Descriptor Interrupt Enable */
+ DT_MASK = 0xf0,
+ DIE = 0x08, /* Descriptor Interrupt Enable */
};
struct rswitch_desc {
__le16 info_ds; /* Descriptor size */
- u8 die_dt; /* Descriptor interrupt enable and type */
- __u8 dptrh; /* Descriptor pointer MSB */
- __le32 dptrl; /* Descriptor pointer LSW */
+ u8 die_dt; /* Descriptor interrupt enable and type */
+ __u8 dptrh; /* Descriptor pointer MSB */
+ __le32 dptrl; /* Descriptor pointer LSW */
} __packed;
struct rswitch_rxdesc {
@@ -268,6 +263,7 @@ struct rswitch_rxdesc {
struct rswitch_port_priv {
void __iomem *addr;
+ struct rswitch_drv_data *drv_data;
struct phy serdes;
struct rswitch_etha etha;
struct rswitch_gwca gwca;
@@ -280,7 +276,20 @@ struct rswitch_port_priv {
struct rswitch_priv {
void __iomem *addr;
- struct clk *rsw_clk;
+ struct clk_bulk rsw_clk;
+};
+
+struct rswitch_drv_data {
+ u32 coma_offset;
+ u32 etha_offset;
+ u32 gwca_offset;
+ u32 mpid_mdc_clk;
+ u8 etha_incr;
+ u8 gwdcbac_offset;
+ u8 fwpbfcsdc_offset;
+ u8 cabpirm_offset;
+ int ports;
+ bool is_rsw3;
};
static inline void rswitch_flush_dcache(u32 addr, u32 len)
@@ -298,36 +307,39 @@ static inline void rswitch_invalidate_dcache(u32 addr, u32 len)
static void rswitch_agent_clock_ctrl(struct rswitch_port_priv *priv, int port, int enable)
{
+ struct rswitch_drv_data *drv_data = priv->drv_data;
u32 val;
if (enable) {
- val = readl(priv->addr + RCEC);
- if ((val & (RCEC_RCE | BIT(port))) != (RCEC_RCE | BIT(port)))
- writel(val | RCEC_RCE | BIT(port), priv->addr + RCEC);
+ val = readl(priv->addr + drv_data->coma_offset + RCEC);
+ if ((val & (RCEC_RCE | BIT(port))) != (RCEC_RCE | BIT(port))) {
+ writel(val | RCEC_RCE | BIT(port),
+ priv->addr + drv_data->coma_offset + RCEC);
+ }
} else {
- setbits_le32(priv->addr + RCDC, BIT(port));
+ setbits_le32(priv->addr + drv_data->coma_offset + RCDC, BIT(port));
}
}
static int rswitch_etha_change_mode(struct rswitch_port_priv *priv,
+ struct rswitch_etha_io *etha_io,
enum rswitch_etha_mode mode)
{
- struct rswitch_etha *etha = &priv->etha;
u32 pval;
int ret;
/* Enable clock */
- rswitch_agent_clock_ctrl(priv, etha->index, 1);
+ rswitch_agent_clock_ctrl(priv, etha_io->index, 1);
- writel(mode, etha->addr + EAMC);
+ writel(mode, etha_io->addr + EAMC);
- ret = readl_poll_sleep_timeout(etha->addr + EAMS, pval,
+ ret = readl_poll_sleep_timeout(etha_io->addr + EAMS, pval,
(pval & EAMS_OPS_MASK) == mode,
RSWITCH_SLEEP_US, RSWITCH_TIMEOUT_US);
/* Disable clock */
if (mode == EAMC_OPC_DISABLE)
- rswitch_agent_clock_ctrl(priv, etha->index, 0);
+ rswitch_agent_clock_ctrl(priv, etha_io->index, 0);
return ret;
}
@@ -355,7 +367,7 @@ static int rswitch_gwca_change_mode(struct rswitch_port_priv *priv,
return ret;
}
-static int rswitch_mii_access_c22(struct rswitch_etha *etha, bool read,
+static int rswitch_mii_access_c22(struct rswitch_etha_io *etha_io, bool read,
int phyad, int regad, int data)
{
const u32 pop = read ? MDIO_READ_C22 : MDIO_WRITE_C22;
@@ -363,18 +375,18 @@ static int rswitch_mii_access_c22(struct rswitch_etha *etha, bool read,
int ret;
/* Clear Station Management Mode : Clause 22 */
- clrbits_le32(etha->addr + MPSM, MPSM_MFF_C45);
+ clrbits_le32(etha_io->addr + MPSM, MPSM_MFF_C45);
/* Clear completion flags */
- writel(MMIS1_CLEAR_FLAGS, etha->addr + MMIS1);
+ writel(MMIS1_CLEAR_FLAGS, etha_io->addr + MMIS1);
/* Submit C22 access to PHY */
val = MPSM_PSME | (pop << 13) | (regad << 8) | (phyad << 3);
if (!read)
val |= data << 16;
- writel(val, etha->addr + MPSM);
+ writel(val, etha_io->addr + MPSM);
- ret = readl_poll_sleep_timeout(etha->addr + MPSM, pval,
+ ret = readl_poll_sleep_timeout(etha_io->addr + MPSM, pval,
!(pval & MPSM_PSME),
RSWITCH_SLEEP_US,
RSWITCH_TIMEOUT_US);
@@ -385,45 +397,45 @@ static int rswitch_mii_access_c22(struct rswitch_etha *etha, bool read,
return 0;
/* Read data */
- ret = (readl(etha->addr + MPSM) & MPSM_PRD_MASK) >> 16;
+ ret = (readl(etha_io->addr + MPSM) & MPSM_PRD_MASK) >> 16;
/* Clear read completion flag */
- setbits_le32(etha->addr + MMIS1, MMIS1_PRACS);
+ setbits_le32(etha_io->addr + MMIS1, MMIS1_PRACS);
return ret;
}
-static int rswitch_mii_access_c45(struct rswitch_etha *etha, bool read,
+static int rswitch_mii_access_c45(struct rswitch_etha_io *etha_io, bool read,
int phyad, int devad, int regad, int data)
{
u32 pval, val;
int ret;
/* Set Station Management Mode : Clause 45 */
- setbits_le32(etha->addr + MPSM, MPSM_MFF_C45);
+ setbits_le32(etha_io->addr + MPSM, MPSM_MFF_C45);
/* Clear completion flags */
- writel(MMIS1_CLEAR_FLAGS, etha->addr + MMIS1);
+ writel(MMIS1_CLEAR_FLAGS, etha_io->addr + MMIS1);
/* Submit address to PHY (MDIO_ADDR_C45 << 13) */
val = MPSM_PSME | MPSM_MFF_C45 | (devad << 8) | (phyad << 3);
- writel((regad << 16) | val, etha->addr + MPSM);
+ writel((regad << 16) | val, etha_io->addr + MPSM);
- ret = readl_poll_sleep_timeout(etha->addr + MMIS1, pval,
+ ret = readl_poll_sleep_timeout(etha_io->addr + MMIS1, pval,
pval & MMIS1_PAACS,
RSWITCH_SLEEP_US, RSWITCH_TIMEOUT_US);
if (ret)
return ret;
/* Clear address completion flag */
- setbits_le32(etha->addr + MMIS1, MMIS1_PAACS);
+ setbits_le32(etha_io->addr + MMIS1, MMIS1_PAACS);
/* Read/Write PHY register */
if (read) {
val |= MDIO_READ_C45 << 13;
- writel(val, etha->addr + MPSM);
+ writel(val, etha_io->addr + MPSM);
- ret = readl_poll_sleep_timeout(etha->addr + MMIS1, pval,
+ ret = readl_poll_sleep_timeout(etha_io->addr + MMIS1, pval,
pval & MMIS1_PRACS,
RSWITCH_SLEEP_US,
RSWITCH_TIMEOUT_US);
@@ -431,16 +443,16 @@ static int rswitch_mii_access_c45(struct rswitch_etha *etha, bool read,
return ret;
/* Read data */
- ret = (readl(etha->addr + MPSM) & MPSM_PRD_MASK) >> 16;
+ ret = (readl(etha_io->addr + MPSM) & MPSM_PRD_MASK) >> 16;
/* Clear read completion flag */
- setbits_le32(etha->addr + MMIS1, MMIS1_PRACS);
+ setbits_le32(etha_io->addr + MMIS1, MMIS1_PRACS);
} else {
val |= MDIO_WRITE_C45 << 13;
val |= data << 16;
- writel(val, etha->addr + MPSM);
+ writel(val, etha_io->addr + MPSM);
- ret = readl_poll_sleep_timeout(etha->addr + MMIS1, pval,
+ ret = readl_poll_sleep_timeout(etha_io->addr + MMIS1, pval,
pval & MMIS1_PWACS,
RSWITCH_SLEEP_US,
RSWITCH_TIMEOUT_US);
@@ -453,32 +465,33 @@ static int rswitch_mii_read_c45(struct mii_dev *miidev, int phyad, int devad, in
{
struct rswitch_port_priv *priv = miidev->priv;
struct rswitch_etha *etha = &priv->etha;
+ struct rswitch_etha_io *etha_mii = &etha->mii;
int val;
/* Change to disable mode */
- rswitch_etha_change_mode(priv, EAMC_OPC_DISABLE);
+ rswitch_etha_change_mode(priv, etha_mii, EAMC_OPC_DISABLE);
/* Change to config mode */
- rswitch_etha_change_mode(priv, EAMC_OPC_CONFIG);
+ rswitch_etha_change_mode(priv, etha_mii, EAMC_OPC_CONFIG);
/* Enable Station Management clock */
- clrsetbits_le32(etha->addr + MPIC,
+ clrsetbits_le32(etha_mii->addr + MPIC,
MPIC_PSMCS_MASK | MPIC_PSMHT_MASK,
- MPIC_MDC_CLK_SET);
+ priv->drv_data->mpid_mdc_clk);
/* Access PHY register */
if (devad != MDIO_DEVAD_NONE) /* Definitelly C45 */
- val = rswitch_mii_access_c45(etha, true, phyad, devad, regad, 0);
+ val = rswitch_mii_access_c45(etha_mii, true, phyad, devad, regad, 0);
else if (etha->phydev->is_c45) /* C22 access to C45 PHY */
- val = rswitch_mii_access_c45(etha, true, phyad, 1, regad, 0);
+ val = rswitch_mii_access_c45(etha_mii, true, phyad, 1, regad, 0);
else
- val = rswitch_mii_access_c22(etha, true, phyad, regad, 0);
+ val = rswitch_mii_access_c22(etha_mii, true, phyad, regad, 0);
/* Disable Station Management Clock */
- clrbits_le32(etha->addr + MPIC, MPIC_PSMCS_MASK);
+ clrbits_le32(etha_mii->addr + MPIC, MPIC_PSMCS_MASK);
/* Change to disable mode */
- rswitch_etha_change_mode(priv, EAMC_OPC_DISABLE);
+ rswitch_etha_change_mode(priv, etha_mii, EAMC_OPC_DISABLE);
return val;
}
@@ -487,45 +500,46 @@ int rswitch_mii_write_c45(struct mii_dev *miidev, int phyad, int devad, int rega
{
struct rswitch_port_priv *priv = miidev->priv;
struct rswitch_etha *etha = &priv->etha;
+ struct rswitch_etha_io *etha_mii = &etha->mii;
/* Change to disable mode */
- rswitch_etha_change_mode(priv, EAMC_OPC_DISABLE);
+ rswitch_etha_change_mode(priv, etha_mii, EAMC_OPC_DISABLE);
/* Change to config mode */
- rswitch_etha_change_mode(priv, EAMC_OPC_CONFIG);
+ rswitch_etha_change_mode(priv, etha_mii, EAMC_OPC_CONFIG);
/* Enable Station Management clock */
- clrsetbits_le32(etha->addr + MPIC,
+ clrsetbits_le32(etha_mii->addr + MPIC,
MPIC_PSMCS_MASK | MPIC_PSMHT_MASK,
- MPIC_MDC_CLK_SET);
+ priv->drv_data->mpid_mdc_clk);
/* Access PHY register */
if (devad != MDIO_DEVAD_NONE) /* Definitelly C45 */
- rswitch_mii_access_c45(etha, false, phyad, devad, regad, data);
+ rswitch_mii_access_c45(etha_mii, false, phyad, devad, regad, data);
else if (etha->phydev->is_c45) /* C22 access to C45 PHY */
- rswitch_mii_access_c45(etha, false, phyad, 1, regad, data);
+ rswitch_mii_access_c45(etha_mii, false, phyad, 1, regad, data);
else
- rswitch_mii_access_c22(etha, false, phyad, regad, data);
+ rswitch_mii_access_c22(etha_mii, false, phyad, regad, data);
/* Disable Station Management Clock */
- clrbits_le32(etha->addr + MPIC, MPIC_PSMCS_MASK);
+ clrbits_le32(etha_mii->addr + MPIC, MPIC_PSMCS_MASK);
/* Change to disable mode */
- rswitch_etha_change_mode(priv, EAMC_OPC_DISABLE);
+ rswitch_etha_change_mode(priv, etha_mii, EAMC_OPC_DISABLE);
return 0;
}
-static int rswitch_check_link(struct rswitch_etha *etha)
+static int rswitch_check_link(struct rswitch_etha_io *etha_serdes)
{
u32 pval;
int ret;
/* Request Link Verification */
- writel(MLVC_PLV, etha->addr + MLVC);
+ writel(MLVC_PLV, etha_serdes->addr + MLVC);
/* Complete Link Verification */
- ret = readl_poll_sleep_timeout(etha->addr + MLVC, pval,
+ ret = readl_poll_sleep_timeout(etha_serdes->addr + MLVC, pval,
!(pval & MLVC_PLV),
RSWITCH_SLEEP_US, RSWITCH_TIMEOUT_US);
if (ret) {
@@ -538,16 +552,21 @@ static int rswitch_check_link(struct rswitch_etha *etha)
static int rswitch_reset(struct rswitch_port_priv *priv)
{
+ struct rswitch_drv_data *drv_data = priv->drv_data;
int ret;
- setbits_le32(priv->addr + RRC, RRC_RR);
- clrbits_le32(priv->addr + RRC, RRC_RR);
+ setbits_le32(priv->addr + drv_data->coma_offset + RRC, RRC_RR);
+ clrbits_le32(priv->addr + drv_data->coma_offset + RRC, RRC_RR);
ret = rswitch_gwca_change_mode(priv, GWMC_OPC_DISABLE);
if (ret)
return ret;
- ret = rswitch_etha_change_mode(priv, EAMC_OPC_DISABLE);
+ ret = rswitch_etha_change_mode(priv, &priv->etha.serdes, EAMC_OPC_DISABLE);
+ if (ret)
+ return ret;
+
+ ret = rswitch_etha_change_mode(priv, &priv->etha.mii, EAMC_OPC_DISABLE);
if (ret)
return ret;
@@ -609,7 +628,7 @@ static void rswitch_rx_desc_init(struct rswitch_port_priv *priv)
priv->rx_desc_index = 0;
for (i = 0; i < RSWITCH_NUM_RX_DESC; i++) {
- priv->rx_desc[i].data.die_dt = DT_EEMPTY;
+ priv->rx_desc[i].data.die_dt = DT_FEMPTY;
priv->rx_desc[i].data.info_ds = PKTSIZE_ALIGN;
packet_addr = (uintptr_t)priv->rx_desc[i].packet;
priv->rx_desc[i].data.dptrl = lower_32_bits(packet_addr);
@@ -638,20 +657,26 @@ static void rswitch_rx_desc_init(struct rswitch_port_priv *priv)
static void rswitch_clock_enable(struct rswitch_port_priv *priv)
{
+ struct rswitch_drv_data *drv_data = priv->drv_data;
struct rswitch_etha *etha = &priv->etha;
struct rswitch_gwca *gwca = &priv->gwca;
+ int etha_index = etha->serdes.index;
- setbits_le32(priv->addr + RCEC, BIT(etha->index) | BIT(gwca->index) | RCEC_RCE);
+ setbits_le32(priv->addr + drv_data->coma_offset + RCEC,
+ BIT(etha_index) | BIT(gwca->index) | RCEC_RCE);
}
static int rswitch_bpool_init(struct rswitch_port_priv *priv)
{
+ struct rswitch_drv_data *drv_data = priv->drv_data;
u32 pval;
- writel(CABPIRM_BPIOG, priv->addr + CABPIRM);
+ writel(CABPIRM_BPIOG, priv->addr + drv_data->coma_offset +
+ CABPIRM + drv_data->cabpirm_offset);
- return readl_poll_sleep_timeout(priv->addr + CABPIRM, pval,
- pval & CABPIRM_BPR,
+ return readl_poll_sleep_timeout(priv->addr + drv_data->coma_offset +
+ CABPIRM + drv_data->cabpirm_offset,
+ pval, pval & CABPIRM_BPR,
RSWITCH_SLEEP_US, RSWITCH_TIMEOUT_US);
}
@@ -659,34 +684,39 @@ static void rswitch_mfwd_init(struct rswitch_port_priv *priv)
{
struct rswitch_etha *etha = &priv->etha;
struct rswitch_gwca *gwca = &priv->gwca;
+ int gwca_index = HW_INDEX_TO_GWCA(gwca->index, priv->drv_data->ports);
+ int etha_index = etha->serdes.index;
- writel(FWPC0_DEFAULT, priv->addr + FWPC0(etha->index));
+ writel(FWPC0_DEFAULT, priv->addr + FWPC0(etha_index));
writel(FWPC0_DEFAULT, priv->addr + FWPC0(gwca->index));
writel(RSWITCH_RX_CHAIN_INDEX,
- priv->addr + FWPBFCSDC(HW_INDEX_TO_GWCA(gwca->index), etha->index));
+ priv->addr + FWPBFCSDC(priv->drv_data->fwpbfcsdc_offset,
+ gwca_index, etha_index,
+ priv->drv_data->etha_incr));
writel(BIT(gwca->index),
- priv->addr + FWPBFC(etha->index));
+ priv->addr + FWPBFC(etha_index));
- writel(BIT(etha->index),
+ writel(BIT(etha_index),
priv->addr + FWPBFC(gwca->index));
}
static void rswitch_rmac_init(struct rswitch_etha *etha)
{
+ struct rswitch_etha_io *etha_serdes = &etha->serdes;
unsigned char *mac = etha->enetaddr;
/* Set MAC address */
- writel((mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5],
- etha->addr + MRMAC1);
+ writel((mac[0] << 8) | mac[1], etha_serdes->addr + MRMAC0);
- writel((mac[0] << 8) | mac[1], etha->addr + MRMAC0);
+ writel((mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5],
+ etha_serdes->addr + MRMAC1);
/* Set MIIx */
- writel(MPIC_PIS_GMII | MPIC_LSC_1000, etha->addr + MPIC);
+ writel(MPIC_PIS_GMII | MPIC_LSC_1000, etha_serdes->addr + MPIC);
- writel(0x07E707E7, etha->addr + MRAFC);
+ writel(0x07E707E7, etha_serdes->addr + MRAFC);
}
static int rswitch_gwca_mcast_table_reset(struct rswitch_gwca *gwca)
@@ -735,11 +765,17 @@ static int rswitch_gwca_init(struct rswitch_port_priv *priv)
/* Setting flow */
writel(GWVCC_VEM_SC_TAG, gwca->addr + GWVCC);
writel(0, gwca->addr + GWTTFC);
- writel(upper_32_bits((uintptr_t)priv->bat_desc) & GWDCBAC0_DCBAUP, gwca->addr + GWDCBAC0);
- writel(lower_32_bits((uintptr_t)priv->bat_desc), gwca->addr + GWDCBAC1);
+ writel(upper_32_bits((uintptr_t)priv->bat_desc) & GWDCBAC0_DCBAUP,
+ gwca->addr + GWDCBAC0 + priv->drv_data->gwdcbac_offset);
+ writel(lower_32_bits((uintptr_t)priv->bat_desc),
+ gwca->addr + GWDCBAC1 + priv->drv_data->gwdcbac_offset);
writel(GWDCC_DQT | GWDCC_BALR, gwca->addr + GWDCC(RSWITCH_TX_CHAIN_INDEX));
writel(GWDCC_BALR, gwca->addr + GWDCC(RSWITCH_RX_CHAIN_INDEX));
+ /* Enable Under Switch Minimum Frame Size Padding */
+ if (priv->drv_data->is_rsw3)
+ writel(GWCKSC_USMFSPE, gwca->addr + GWCKSC);
+
ret = rswitch_gwca_change_mode(priv, GWMC_OPC_DISABLE);
if (ret)
return ret;
@@ -751,13 +787,13 @@ static int rswitch_gwca_init(struct rswitch_port_priv *priv)
return 0;
}
-static int rswitch_etha_tas_ram_reset(struct rswitch_etha *etha)
+static int rswitch_etha_tas_ram_reset(struct rswitch_etha_io *etha_serdes)
{
u32 pval;
- writel(EATASRIRM_TASRIOG, etha->addr + EATASRIRM);
+ writel(EATASRIRM_TASRIOG, etha_serdes->addr + EATASRIRM);
- return readl_poll_sleep_timeout(etha->addr + EATASRIRM, pval,
+ return readl_poll_sleep_timeout(etha_serdes->addr + EATASRIRM, pval,
pval & EATASRIRM_TASRR,
RSWITCH_SLEEP_US, RSWITCH_TIMEOUT_US);
}
@@ -765,35 +801,43 @@ static int rswitch_etha_tas_ram_reset(struct rswitch_etha *etha)
static int rswitch_etha_init(struct rswitch_port_priv *priv)
{
struct rswitch_etha *etha = &priv->etha;
+ struct rswitch_etha_io *etha_serdes = &etha->serdes;
int ret;
u32 prio;
- ret = rswitch_etha_change_mode(priv, EAMC_OPC_DISABLE);
+ ret = rswitch_etha_change_mode(priv, etha_serdes, EAMC_OPC_DISABLE);
if (ret)
return ret;
- ret = rswitch_etha_change_mode(priv, EAMC_OPC_CONFIG);
+ ret = rswitch_etha_change_mode(priv, etha_serdes, EAMC_OPC_CONFIG);
if (ret)
return ret;
- ret = rswitch_etha_tas_ram_reset(etha);
+ ret = rswitch_etha_tas_ram_reset(etha_serdes);
if (ret)
return ret;
/* Setting flow */
- writel(0, etha->addr + EATTFC);
+ writel(0, etha_serdes->addr + EATTFC);
for (prio = 0; prio < RSWITCH_MAX_CTAG_PCP; prio++)
- writel(EATDQDC_DQD, etha->addr + EATDQDC(prio));
+ writel(EATDQDC_DQD, etha_serdes->addr + EATDQDC(prio));
rswitch_rmac_init(etha);
- ret = rswitch_etha_change_mode(priv, EAMC_OPC_OPERATION);
+ if (etha->xpcs) {
+ if (etha_serdes->index >= 5 && etha_serdes->index <= 7)
+ writel(MIOC_BIT3_SET, etha_serdes->addr + MIOC);
+ else
+ printf("RSW: Invalid port %d\n", etha_serdes->index);
+ }
+
+ ret = rswitch_etha_change_mode(priv, etha_serdes, EAMC_OPC_OPERATION);
if (ret)
return ret;
/* Link Verification */
- ret = rswitch_check_link(etha);
+ ret = rswitch_check_link(etha_serdes);
if (ret)
return ret;
@@ -958,13 +1002,14 @@ static int rswitch_write_hwaddr(struct udevice *dev)
{
struct rswitch_port_priv *priv = dev_get_priv(dev);
struct rswitch_etha *etha = &priv->etha;
+ struct rswitch_etha_io *etha_serdes = &etha->serdes;
struct eth_pdata *pdata = dev_get_plat(dev);
unsigned char *mac = pdata->enetaddr;
writel((mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5],
- etha->addr + MRMAC1);
+ etha_serdes->addr + MRMAC1);
- writel((mac[0] << 8) | mac[1], etha->addr + MRMAC0);
+ writel((mac[0] << 8) | mac[1], etha_serdes->addr + MRMAC0);
return 0;
}
@@ -1005,19 +1050,29 @@ static int rswitch_port_probe(struct udevice *dev)
int ret;
priv->addr = rpriv->addr;
+ priv->drv_data = (void *)dev_get_driver_data(dev->parent);
+
+ ret = generic_phy_get_by_index(dev, 0, &priv->serdes);
+ if (ret)
+ return ret;
+
+ if (priv->drv_data->is_rsw3) {
+ etha->xpcs = device_is_compatible(priv->serdes.dev,
+ "renesas,r8a78000-ether-pcs");
+ }
etha->enetaddr = pdata->enetaddr;
- etha->index = dev_read_u32_default(dev, "reg", 0);
- etha->addr = priv->addr + RSWITCH_ETHA_OFFSET + etha->index * RSWITCH_ETHA_SIZE;
+ etha->mii.index = dev_read_u32_default(dev, "reg", 0);
+ etha->serdes.index = priv->serdes.id;
+ etha->mii.addr = priv->addr + priv->drv_data->etha_offset +
+ etha->mii.index * RSWITCH_ETHA_SIZE;
+ etha->serdes.addr = priv->addr + priv->drv_data->etha_offset +
+ etha->serdes.index * RSWITCH_ETHA_SIZE;
gwca->index = 1;
- gwca->addr = priv->addr + RSWITCH_GWCA_OFFSET + gwca->index * RSWITCH_GWCA_SIZE;
- gwca->index = GWCA_TO_HW_INDEX(gwca->index);
-
- ret = generic_phy_get_by_index(dev, 0, &priv->serdes);
- if (ret)
- return ret;
+ gwca->addr = priv->addr + priv->drv_data->gwca_offset + gwca->index * RSWITCH_GWCA_SIZE;
+ gwca->index = GWCA_TO_HW_INDEX(gwca->index, priv->drv_data->ports);
/* Toggle the reset so we can access the PHYs */
ret = rswitch_reset(priv);
@@ -1109,13 +1164,11 @@ static int rswitch_probe(struct udevice *dev)
if (!priv->addr)
return -EINVAL;
- priv->rsw_clk = devm_clk_get(dev, NULL);
- if (IS_ERR(priv->rsw_clk)) {
- ret = PTR_ERR(priv->rsw_clk);
+ ret = clk_get_bulk(dev, &priv->rsw_clk);
+ if (ret < 0)
goto err_map;
- }
- ret = clk_prepare_enable(priv->rsw_clk);
+ ret = clk_enable_bulk(&priv->rsw_clk);
if (ret)
goto err_map;
@@ -1130,7 +1183,7 @@ static int rswitch_remove(struct udevice *dev)
{
struct rswitch_priv *priv = dev_get_plat(dev);
- clk_disable_unprepare(priv->rsw_clk);
+ clk_disable_bulk(&priv->rsw_clk);
unmap_physmem(priv->addr, MAP_NOCACHE);
return 0;
@@ -1166,8 +1219,34 @@ static int rswitch_bind(struct udevice *parent)
return 0;
}
+static const struct rswitch_drv_data r8a779f0_drv_data = {
+ .ports = 3,
+ .coma_offset = 0x9000,
+ .etha_offset = 0xa000,
+ .gwca_offset = 0x10000,
+ .mpid_mdc_clk = 0x06050000,
+ .etha_incr = 0x10,
+ .gwdcbac_offset = 0x0,
+ .fwpbfcsdc_offset = 0x0,
+ .cabpirm_offset = 0x0,
+};
+
+static const struct rswitch_drv_data r8a78000_drv_data = {
+ .ports = 13,
+ .coma_offset = 0x1c000,
+ .etha_offset = 0x1d000,
+ .gwca_offset = 0x37000,
+ .mpid_mdc_clk = 0x060c0000,
+ .etha_incr = 0x20,
+ .gwdcbac_offset = 0x50,
+ .fwpbfcsdc_offset = 0xfc,
+ .cabpirm_offset = 0x20,
+ .is_rsw3 = true,
+};
+
static const struct udevice_id rswitch_ids[] = {
- { .compatible = "renesas,r8a779f0-ether-switch" },
+ { .compatible = "renesas,r8a779f0-ether-switch", .data = (ulong)&r8a779f0_drv_data },
+ { .compatible = "renesas,r8a78000-ether-switch3", .data = (ulong)&r8a78000_drv_data },
{ }
};
diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
index 8433e7db265..41c52f56d7a 100644
--- a/drivers/net/sun8i_emac.c
+++ b/drivers/net/sun8i_emac.c
@@ -57,10 +57,9 @@
#define TX_TOTAL_BUFSIZE (CFG_ETH_BUFSIZE * CFG_TX_DESCR_NUM)
#define RX_TOTAL_BUFSIZE (CFG_ETH_BUFSIZE * CFG_RX_DESCR_NUM)
-#define H3_EPHY_DEFAULT_VALUE 0x58000
-#define H3_EPHY_DEFAULT_MASK GENMASK(31, 15)
#define H3_EPHY_ADDR_SHIFT 20
#define REG_PHY_ADDR_MASK GENMASK(4, 0)
+#define H3_EPHY_CLK_SEL BIT(18) /* 1: 24MHz, 0: 25MHz */
#define H3_EPHY_LED_POL BIT(17) /* 1: active low, 0: active high */
#define H3_EPHY_SHUTDOWN BIT(16) /* 1: shutdown, 0: power up */
#define H3_EPHY_SELECT BIT(15) /* 1: internal PHY, 0: external PHY */
@@ -176,6 +175,7 @@ struct sun8i_eth_pdata {
u32 reset_delays[3];
int tx_delay_ps;
int rx_delay_ps;
+ bool leds_active_low;
};
static int sun8i_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
@@ -287,34 +287,24 @@ static void sun8i_adjust_link(struct emac_eth_dev *priv,
writel(v, priv->mac_reg + EMAC_CTL0);
}
-static u32 sun8i_emac_set_syscon_ephy(struct emac_eth_dev *priv, u32 reg)
+static int sun8i_emac_set_syscon(struct sun8i_eth_pdata *pdata,
+ struct emac_eth_dev *priv)
{
+ u32 reg = 0;
+
if (priv->use_internal_phy) {
/* H3 based SoC's that has an Internal 100MBit PHY
* needs to be configured and powered up before use
*/
- reg &= ~H3_EPHY_DEFAULT_MASK;
- reg |= H3_EPHY_DEFAULT_VALUE;
reg |= priv->phyaddr << H3_EPHY_ADDR_SHIFT;
- reg &= ~H3_EPHY_SHUTDOWN;
- return reg | H3_EPHY_SELECT;
- }
-
- /* This is to select External Gigabit PHY on those boards with
- * an internal PHY. Does not hurt on other SoCs. Linux does
- * it as well.
- */
- return reg & ~H3_EPHY_SELECT;
-}
+ reg |= H3_EPHY_CLK_SEL;
+ reg |= H3_EPHY_SELECT;
-static int sun8i_emac_set_syscon(struct sun8i_eth_pdata *pdata,
- struct emac_eth_dev *priv)
-{
- u32 reg;
-
- reg = readl(priv->sysctl_reg);
-
- reg = sun8i_emac_set_syscon_ephy(priv, reg);
+ if (pdata->leds_active_low)
+ reg |= H3_EPHY_LED_POL;
+ } else {
+ reg |= H3_EPHY_SHUTDOWN;
+ }
reg &= ~(SC_ETCS_MASK | SC_EPIT);
if (priv->variant->support_rmii)
@@ -859,6 +849,10 @@ static int sun8i_emac_eth_of_to_plat(struct udevice *dev)
printf("%s: Invalid RX delay value %d\n", __func__,
sun8i_pdata->rx_delay_ps);
+ sun8i_pdata->leds_active_low =
+ fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
+ "allwinner,leds-active-low");
+
if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
"snps,reset-active-low"))
reset_flags |= GPIOD_ACTIVE_LOW;
diff --git a/drivers/net/ti/am65-cpsw-nuss.c b/drivers/net/ti/am65-cpsw-nuss.c
index 2aa7e5e3a30..7a88f76fd09 100644
--- a/drivers/net/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ti/am65-cpsw-nuss.c
@@ -234,14 +234,11 @@ out:
#define AM65_GMII_SEL_MODE_RGMII 2
#define AM65_GMII_SEL_MODE_SGMII 3
-#define AM65_GMII_SEL_RGMII_IDMODE BIT(4)
-
static int am65_cpsw_gmii_sel_k3(struct am65_cpsw_priv *priv,
phy_interface_t phy_mode)
{
struct udevice *dev = priv->dev;
u32 offset, reg, phandle;
- bool rgmii_id = false;
fdt_addr_t gmii_sel;
u32 mode = 0;
ofnode node;
@@ -278,12 +275,6 @@ static int am65_cpsw_gmii_sel_k3(struct am65_cpsw_priv *priv,
mode = AM65_GMII_SEL_MODE_RGMII;
break;
- case PHY_INTERFACE_MODE_RGMII_ID:
- case PHY_INTERFACE_MODE_RGMII_TXID:
- mode = AM65_GMII_SEL_MODE_RGMII;
- rgmii_id = true;
- break;
-
case PHY_INTERFACE_MODE_SGMII:
mode = AM65_GMII_SEL_MODE_SGMII;
break;
@@ -298,9 +289,6 @@ static int am65_cpsw_gmii_sel_k3(struct am65_cpsw_priv *priv,
break;
};
- if (rgmii_id)
- mode |= AM65_GMII_SEL_RGMII_IDMODE;
-
reg = mode;
dev_dbg(dev, "gmii_sel PHY mode: %u, new gmii_sel: %08x\n",
phy_mode, reg);
@@ -630,7 +618,7 @@ static int am65_cpsw_phy_init(struct udevice *dev)
u32 supported = PHY_GBIT_FEATURES;
int ret = 0;
- phydev = dm_eth_phy_connect(dev);
+ phydev = dm_eth_phy_connect_interface(dev, pdata->phy_interface);
if (!phydev) {
dev_err(dev, "phy_connect() failed\n");
return -ENODEV;
@@ -657,9 +645,28 @@ static int am65_cpsw_ofdata_parse_phy(struct udevice *dev)
dev_read_u32(dev, "reg", &priv->port_id);
pdata->phy_interface = dev_read_phy_mode(dev);
- if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) {
+
+ /* CPSW controllers supported by this driver have a fixed internal TX
+ * delay in RGMII mode. Fix up PHY mode to account for this and warn
+ * about Device Trees that claim to have a TX delay on the PCB.
+ */
+ switch (pdata->phy_interface) {
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ pdata->phy_interface = PHY_INTERFACE_MODE_RGMII_RXID;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ pdata->phy_interface = PHY_INTERFACE_MODE_RGMII;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ dev_warn(dev,
+ "RGMII mode without internal TX delay unsupported; please fix your Device Tree\n");
+ break;
+ case PHY_INTERFACE_MODE_NA:
dev_err(dev, "Invalid PHY mode, port %u\n", priv->port_id);
return -EINVAL;
+ default:
+ break;
}
dev_read_u32(dev, "max-speed", (u32 *)&pdata->max_speed);
diff --git a/drivers/net/xilinx_axi_emac.c b/drivers/net/xilinx_axi_emac.c
index 22e119370c8..fb48feb4469 100644
--- a/drivers/net/xilinx_axi_emac.c
+++ b/drivers/net/xilinx_axi_emac.c
@@ -619,11 +619,11 @@ static int axiemac_start(struct udevice *dev)
#endif
rx_bd.cntrl = sizeof(rxframe);
/* Flush the last BD so DMA core could see the updates */
- flush_cache((phys_addr_t)&rx_bd, sizeof(rx_bd));
+ flush_cache((phys_addr_t)(uintptr_t)&rx_bd, sizeof(rx_bd));
/* It is necessary to flush rxframe because if you don't do it
* then cache can contain uninitialized data */
- flush_cache((phys_addr_t)&rxframe, sizeof(rxframe));
+ flush_cache((phys_addr_t)(uintptr_t)&rxframe, sizeof(rxframe));
/* Start the hardware */
temp = readl(&priv->dmarx->control);
@@ -675,7 +675,7 @@ static int axiemac_send(struct udevice *dev, void *ptr, int len)
}
/* Flush packet to main memory to be trasfered by DMA */
- flush_cache((phys_addr_t)ptr, len);
+ flush_cache((phys_addr_t)(uintptr_t)ptr, len);
/* Setup Tx BD */
memset(&tx_bd, 0, sizeof(tx_bd));
@@ -691,7 +691,7 @@ static int axiemac_send(struct udevice *dev, void *ptr, int len)
XAXIDMA_BD_CTRL_TXEOF_MASK;
/* Flush the last BD so DMA core could see the updates */
- flush_cache((phys_addr_t)&tx_bd, sizeof(tx_bd));
+ flush_cache((phys_addr_t)(uintptr_t)&tx_bd, sizeof(tx_bd));
if (readl(&priv->dmatx->status) & XAXIDMA_HALTED_MASK) {
u32 temp;
@@ -791,11 +791,11 @@ static int axiemac_free_pkt(struct udevice *dev, uchar *packet, int length)
rx_bd.cntrl = sizeof(rxframe);
/* Write bd to HW */
- flush_cache((phys_addr_t)&rx_bd, sizeof(rx_bd));
+ flush_cache((phys_addr_t)(uintptr_t)&rx_bd, sizeof(rx_bd));
/* It is necessary to flush rxframe because if you don't do it
* then cache will contain previous packet */
- flush_cache((phys_addr_t)&rxframe, sizeof(rxframe));
+ flush_cache((phys_addr_t)(uintptr_t)&rxframe, sizeof(rxframe));
/* Rx BD is ready - start again */
axienet_dma_write(&rx_bd, &priv->dmarx->tail);
@@ -831,10 +831,10 @@ static int axi_emac_probe(struct udevice *dev)
struct axidma_priv *priv = dev_get_priv(dev);
int ret;
- priv->iobase = (struct axi_regs *)pdata->iobase;
+ priv->iobase = (struct axi_regs *)(uintptr_t)pdata->iobase;
priv->dmatx = plat->dmatx;
/* RX channel offset is 0x30 */
- priv->dmarx = (struct axidma_reg *)((phys_addr_t)priv->dmatx + 0x30);
+ priv->dmarx = (struct axidma_reg *)((uintptr_t)priv->dmatx + 0x30);
priv->mactype = plat->mactype;
if (priv->mactype == EMAC_1G) {
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c
index 703e22479d2..407b022508c 100644
--- a/drivers/net/zynq_gem.c
+++ b/drivers/net/zynq_gem.c
@@ -162,7 +162,9 @@ struct zynq_gem_regs {
u32 idr; /* 0x2c - Interrupt Disable reg */
u32 reserved3;
u32 phymntnc; /* 0x34 - Phy Maintaince reg */
- u32 reserved4[18];
+ u32 reserved4[6];
+ u32 hsmaccfg; /* 0x50 - HS MAC Config reg */
+ u32 reserved5[11];
u32 hashl; /* 0x80 - Hash Low address reg */
u32 hashh; /* 0x84 - Hash High address reg */
#define LADDR_LOW 0
@@ -185,6 +187,10 @@ struct zynq_gem_regs {
u32 upper_txqbase; /* 0x4C8 - Upper tx_q base addr */
u32 reserved11[2];
u32 upper_rxqbase; /* 0x4D4 - Upper rx_q base addr */
+ u32 reserved13[362];
+ u32 usxctrlreg; /* 0xA80 - Usx Control reg */
+ u32 reserved14;
+ u32 usxstatusreg; /* 0xA88 - Usx Status reg */
};
/* BD descriptors */
@@ -209,6 +215,27 @@ struct emac_bd {
/* Setup the first free TX descriptor */
#define TX_FREE_DESC 2
+#define HS_SPEED_1000M 1
+#define HS_SPEED_2500M 2
+#define HS_SPEED_5000M 3
+#define HS_SPEED_10000M 4
+#define MACB_SERDES_RATE_5G_2G5_1G 0
+#define MACB_SERDES_RATE_10G 1
+#define USX_BLOCK_LOCK BIT(0)
+#define TX_SCR_BYPASS BIT(8)
+#define RX_SCR_BYPASS BIT(9)
+#define RX_SYNC_RESET BIT(2)
+#define SPEED_5000 5000
+#define TX_EN BIT(1)
+#define SIGNAL_OK BIT(0)
+#define ENABLE_HS_MAC BIT(31)
+#define PCSSEL BIT(11)
+#define HS_MAC_SPEED_MASK 0x3
+#define USX_CONFIG_SERDES_RATE_MASK 0x3
+#define USX_CONFIG_SERDES_RATE_SHIFT 12
+#define USX_CONFIG_SPEED_MASK 0x3
+#define USX_CONFIG_SPEED_SHIFT 14
+
/* Initialized, rxbd_current, rx_first_buf must be 0 after init */
struct zynq_gem_priv {
struct emac_bd *tx_bd;
@@ -391,9 +418,11 @@ static int zynq_phy_init(struct udevice *dev)
static int zynq_gem_init(struct udevice *dev)
{
- u32 i, nwconfig, nwcfg;
int ret;
+ u32 i, nwconfig, nwcfg, ctrl, ncr;
unsigned long clk_rate = 0;
+ unsigned long speed_val, serdes_rate, config;
+ unsigned long clear_speed_val_mask, clear_serdes_rate_mask;
struct zynq_gem_priv *priv = dev_get_priv(dev);
struct zynq_gem_regs *regs = priv->iobase;
struct zynq_gem_regs *regs_mdio = priv->mdiobase;
@@ -499,6 +528,67 @@ static int zynq_gem_init(struct udevice *dev)
nwconfig = ZYNQ_GEM_NWCFG_INIT;
+ if (device_is_compatible(dev, "amd,versal2-10gbe")) {
+ if (priv->interface == PHY_INTERFACE_MODE_10GBASER) {
+ ctrl = readl(&regs->nwcfg);
+ ctrl |= PCSSEL;
+ writel(ctrl, &regs->nwcfg);
+ ncr = readl(&regs->nwctrl);
+ ncr |= ENABLE_HS_MAC;
+ writel(ncr, &regs->nwctrl);
+ }
+ switch (priv->phydev->speed) {
+ case SPEED_1000:
+ speed_val = HS_SPEED_1000M;
+ serdes_rate = MACB_SERDES_RATE_5G_2G5_1G;
+ break;
+ case SPEED_2500:
+ speed_val = HS_SPEED_2500M;
+ serdes_rate = MACB_SERDES_RATE_5G_2G5_1G;
+ break;
+ case SPEED_5000:
+ speed_val = HS_SPEED_5000M;
+ serdes_rate = MACB_SERDES_RATE_5G_2G5_1G;
+ break;
+ case SPEED_10000:
+ speed_val = HS_SPEED_10000M;
+ serdes_rate = MACB_SERDES_RATE_10G;
+ break;
+ default:
+ printf("Specified speed not supported =%d\n", priv->phydev->speed);
+ break;
+ }
+
+ config = readl(&regs->hsmaccfg);
+ config = (config & ~HS_MAC_SPEED_MASK) | speed_val;
+ writel(config, &regs->hsmaccfg);
+
+ config = readl(&regs->usxctrlreg);
+ config |= SIGNAL_OK;
+ clear_serdes_rate_mask = ~(USX_CONFIG_SERDES_RATE_MASK <<
+ USX_CONFIG_SERDES_RATE_SHIFT);
+ config = (config & clear_serdes_rate_mask) |
+ serdes_rate << USX_CONFIG_SERDES_RATE_SHIFT;
+
+ clear_speed_val_mask = ~(USX_CONFIG_SPEED_MASK <<
+ USX_CONFIG_SPEED_SHIFT);
+ config = (config & clear_speed_val_mask) |
+ speed_val << USX_CONFIG_SPEED_SHIFT;
+ config &= ~(TX_SCR_BYPASS | RX_SCR_BYPASS);
+ config |= RX_SYNC_RESET;
+ writel(config, &regs->usxctrlreg);
+
+ mdelay(250);
+ config &= ~(RX_SYNC_RESET);
+ config |= (TX_EN);
+ writel(config, &regs->usxctrlreg);
+
+ ret = wait_for_bit_le32(&regs->usxstatusreg, USX_BLOCK_LOCK,
+ true, 20000, true);
+ if (ret)
+ printf("usx block lock failed\n");
+ }
+
/*
* Set SGMII enable PCS selection only if internal PCS/PMA
* core is used and interface is SGMII.
@@ -997,6 +1087,7 @@ static int zynq_gem_of_to_plat(struct udevice *dev)
}
static const struct udevice_id zynq_gem_ids[] = {
+ { .compatible = "amd,versal2-10gbe" },
{ .compatible = "xlnx,versal-gem", .data = RXCLK_EN },
{ .compatible = "cdns,versal-gem", .data = RXCLK_EN },
{ .compatible = "xlnx,zynqmp-gem" },
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 6c2cda1a966..ea9868425d0 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -333,12 +333,6 @@ config PCIE_IMX
bool "i.MX PCIe support"
depends on ARCH_MX6
-config PCIE_INTEL_FPGA
- bool "Intel FPGA PCIe support"
- help
- Say Y here if you want to enable PCIe controller support on Intel
- FPGA, example Stratix 10.
-
config PCIE_IPROC
bool "Iproc PCIe support"
help
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index a0420e733ed..98f3c226f63 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -40,7 +40,6 @@ obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \
pcie_layerscape_fixup_common.o
obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o
obj-$(CONFIG_PCI_PHYTIUM) += pcie_phytium.o
-obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o
obj-$(CONFIG_PCIE_DW_COMMON) += pcie_dw_common.o
obj-$(CONFIG_PCI_KEYSTONE) += pcie_dw_ti.o
obj-$(CONFIG_PCIE_MEDIATEK) += pcie_mediatek.o
diff --git a/drivers/pci/pci-rcar-gen4.c b/drivers/pci/pci-rcar-gen4.c
index 41f0d958447..e165271f58c 100644
--- a/drivers/pci/pci-rcar-gen4.c
+++ b/drivers/pci/pci-rcar-gen4.c
@@ -243,7 +243,7 @@ static int rcar_gen4_pcie_ltssm_control(struct rcar_gen4_pcie *rcar, bool enable
clrbits_le32(rcar->app_base + PCIERSTCTRL1, APP_HOLD_PHY_RST);
- ret = readl_poll_timeout(rcar->phy_base + 0x0f8, val, !(val & BIT(18)), 10000);
+ ret = readl_poll_timeout(rcar->phy_base + 0x0f8, val, val & BIT(18), 10000);
if (ret < 0)
return ret;
@@ -306,6 +306,8 @@ static int rcar_gen4_pcie_common_init(struct rcar_gen4_pcie *rcar)
if (ret)
goto err_unprepare;
+ mdelay(1);
+
setbits_le32(rcar->app_base + PCIEMSR0,
DEVICE_TYPE_RC |
((rcar->num_lanes < 4) ? BIFUR_MOD_SET_ON : 0));
@@ -314,6 +316,9 @@ static int rcar_gen4_pcie_common_init(struct rcar_gen4_pcie *rcar)
if (ret)
goto err_unprepare;
+ reset_status(&rcar->pwr_rst);
+ mdelay(1);
+
rcar_gen4_pcie_additional_common_init(rcar);
return 0;
@@ -472,6 +477,10 @@ static int rcar_gen4_pcie_probe(struct udevice *dev)
if (!rcar_gen4_pcie_link_up(rcar)) {
printf("PCIE-%d: Link down\n", dev_seq(dev));
+ rcar_gen4_pcie_ltssm_control(rcar, false);
+ dm_gpio_set_value(&rcar->pe_rst, 1);
+ reset_assert(&rcar->pwr_rst);
+ clk_disable_unprepare(rcar->ref_clk);
return -ENODEV;
}
@@ -489,6 +498,26 @@ static int rcar_gen4_pcie_probe(struct udevice *dev)
}
/**
+ * rcar_gen4_pcie_remove() - Stop the PCIe bus active link
+ * @dev: A pointer to the device being operated on
+ *
+ * Stop an active link on the PCIe bus and deconfigure the controller.
+ *
+ * Return: 0 on success, else -ENODEV
+ */
+static int rcar_gen4_pcie_remove(struct udevice *dev)
+{
+ struct rcar_gen4_pcie *rcar = dev_get_priv(dev);
+
+ rcar_gen4_pcie_ltssm_control(rcar, false);
+ dm_gpio_set_value(&rcar->pe_rst, 1);
+ reset_assert(&rcar->pwr_rst);
+ clk_disable_unprepare(rcar->ref_clk);
+
+ return 0;
+}
+
+/**
* rcar_gen4_pcie_of_to_plat() - Translate from DT to device state
*
* @dev: A pointer to the device being operated on
@@ -561,5 +590,7 @@ U_BOOT_DRIVER(rcar_gen4_pcie) = {
.ops = &rcar_gen4_pcie_ops,
.of_to_plat = rcar_gen4_pcie_of_to_plat,
.probe = rcar_gen4_pcie_probe,
+ .remove = rcar_gen4_pcie_remove,
.priv_auto = sizeof(struct rcar_gen4_pcie),
+ .flags = DM_FLAG_ACTIVE_DMA,
};
diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c
index 77815513b76..3985bd59607 100644
--- a/drivers/pci/pci_mvebu.c
+++ b/drivers/pci/pci_mvebu.c
@@ -763,6 +763,7 @@ static int mvebu_pcie_bind(struct udevice *parent)
pcie->mem.start = mem.start;
pcie->mem.end = mem.start + SZ_128M - 1;
mem.start += SZ_128M;
+ mem.end = mem.start + SZ_128M - 1;
} else {
printf("%s: unable to assign mbus window for mem\n", pcie->name);
pcie->mem.start = 0;
@@ -773,6 +774,7 @@ static int mvebu_pcie_bind(struct udevice *parent)
pcie->io.start = io.start;
pcie->io.end = io.start + SZ_64K - 1;
io.start += SZ_64K;
+ io.end = io.start + SZ_64K - 1;
} else {
printf("%s: unable to assign mbus window for io\n", pcie->name);
pcie->io.start = 0;
diff --git a/drivers/pci/pcie_intel_fpga.c b/drivers/pci/pcie_intel_fpga.c
deleted file mode 100644
index 959fd369086..00000000000
--- a/drivers/pci/pcie_intel_fpga.c
+++ /dev/null
@@ -1,434 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Intel FPGA PCIe host controller driver
- *
- * Copyright (C) 2013-2018 Intel Corporation. All rights reserved
- *
- */
-
-#include <dm.h>
-#include <pci.h>
-#include <asm/global_data.h>
-#include <asm/io.h>
-#include <dm/device_compat.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-
-#define RP_TX_REG0 0x2000
-#define RP_TX_CNTRL 0x2004
-#define RP_TX_SOP BIT(0)
-#define RP_TX_EOP BIT(1)
-#define RP_RXCPL_STATUS 0x200C
-#define RP_RXCPL_SOP BIT(0)
-#define RP_RXCPL_EOP BIT(1)
-#define RP_RXCPL_REG 0x2008
-#define P2A_INT_STATUS 0x3060
-#define P2A_INT_STS_ALL 0xf
-#define P2A_INT_ENABLE 0x3070
-#define RP_CAP_OFFSET 0x70
-
-/* TLP configuration type 0 and 1 */
-#define TLP_FMTTYPE_CFGRD0 0x04 /* Configuration Read Type 0 */
-#define TLP_FMTTYPE_CFGWR0 0x44 /* Configuration Write Type 0 */
-#define TLP_FMTTYPE_CFGRD1 0x05 /* Configuration Read Type 1 */
-#define TLP_FMTTYPE_CFGWR1 0x45 /* Configuration Write Type 1 */
-#define TLP_PAYLOAD_SIZE 0x01
-#define TLP_READ_TAG 0x1d
-#define TLP_WRITE_TAG 0x10
-#define RP_DEVFN 0
-
-#define RP_CFG_ADDR(pcie, reg) \
- ((pcie->hip_base) + (reg) + (1 << 20))
-#define RP_SECONDARY(pcie) \
- readb(RP_CFG_ADDR(pcie, PCI_SECONDARY_BUS))
-#define TLP_REQ_ID(bus, devfn) (((bus) << 8) | (devfn))
-
-#define TLP_CFGRD_DW0(pcie, bus) \
- ((((bus > RP_SECONDARY(pcie)) ? TLP_FMTTYPE_CFGRD1 \
- : TLP_FMTTYPE_CFGRD0) << 24) | \
- TLP_PAYLOAD_SIZE)
-
-#define TLP_CFGWR_DW0(pcie, bus) \
- ((((bus > RP_SECONDARY(pcie)) ? TLP_FMTTYPE_CFGWR1 \
- : TLP_FMTTYPE_CFGWR0) << 24) | \
- TLP_PAYLOAD_SIZE)
-
-#define TLP_CFG_DW1(pcie, tag, be) \
- (((TLP_REQ_ID(pcie->first_busno, RP_DEVFN)) << 16) | (tag << 8) | (be))
-#define TLP_CFG_DW2(bus, dev, fn, offset) \
- (((bus) << 24) | ((dev) << 19) | ((fn) << 16) | (offset))
-
-#define TLP_COMP_STATUS(s) (((s) >> 13) & 7)
-#define TLP_BYTE_COUNT(s) (((s) >> 0) & 0xfff)
-#define TLP_HDR_SIZE 3
-#define TLP_LOOP 20000
-#define DWORD_MASK 3
-
-#define IS_ROOT_PORT(pcie, bdf) \
- ((PCI_BUS(bdf) == pcie->first_busno) ? true : false)
-
-/**
- * struct intel_fpga_pcie - Intel FPGA PCIe controller state
- * @bus: Pointer to the PCI bus
- * @cra_base: The base address of CRA register space
- * @hip_base: The base address of Rootport configuration space
- * @first_busno: This driver supports multiple PCIe controllers.
- * first_busno stores the bus number of the PCIe root-port
- * number which may vary depending on the PCIe setup.
- */
-struct intel_fpga_pcie {
- struct udevice *bus;
- void __iomem *cra_base;
- void __iomem *hip_base;
- int first_busno;
-};
-
-/**
- * Intel FPGA PCIe port uses BAR0 of RC's configuration space as the
- * translation from PCI bus to native BUS. Entire DDR region is mapped
- * into PCIe space using these registers, so it can be reached by DMA from
- * EP devices.
- * The BAR0 of bridge should be hidden during enumeration to avoid the
- * sizing and resource allocation by PCIe core.
- */
-static bool intel_fpga_pcie_hide_rc_bar(struct intel_fpga_pcie *pcie,
- pci_dev_t bdf, int offset)
-{
- if (IS_ROOT_PORT(pcie, bdf) && PCI_DEV(bdf) == 0 &&
- PCI_FUNC(bdf) == 0 && offset == PCI_BASE_ADDRESS_0)
- return true;
-
- return false;
-}
-
-static inline void cra_writel(struct intel_fpga_pcie *pcie, const u32 value,
- const u32 reg)
-{
- writel(value, pcie->cra_base + reg);
-}
-
-static inline u32 cra_readl(struct intel_fpga_pcie *pcie, const u32 reg)
-{
- return readl(pcie->cra_base + reg);
-}
-
-static bool intel_fpga_pcie_link_up(struct intel_fpga_pcie *pcie)
-{
- return !!(readw(RP_CFG_ADDR(pcie, RP_CAP_OFFSET + PCI_EXP_LNKSTA))
- & PCI_EXP_LNKSTA_DLLLA);
-}
-
-static bool intel_fpga_pcie_addr_valid(struct intel_fpga_pcie *pcie,
- pci_dev_t bdf)
-{
- /* If there is no link, then there is no device */
- if (!IS_ROOT_PORT(pcie, bdf) && !intel_fpga_pcie_link_up(pcie))
- return false;
-
- /* access only one slot on each root port */
- if (IS_ROOT_PORT(pcie, bdf) && PCI_DEV(bdf) > 0)
- return false;
-
- if ((PCI_BUS(bdf) == pcie->first_busno + 1) && PCI_DEV(bdf) > 0)
- return false;
-
- return true;
-}
-
-static void tlp_write_tx(struct intel_fpga_pcie *pcie, u32 reg0, u32 ctrl)
-{
- cra_writel(pcie, reg0, RP_TX_REG0);
- cra_writel(pcie, ctrl, RP_TX_CNTRL);
-}
-
-static int tlp_read_packet(struct intel_fpga_pcie *pcie, u32 *value)
-{
- int i;
- u32 ctrl;
- u32 comp_status;
- u32 dw[4];
- u32 count = 0;
-
- for (i = 0; i < TLP_LOOP; i++) {
- ctrl = cra_readl(pcie, RP_RXCPL_STATUS);
- if (!(ctrl & RP_RXCPL_SOP))
- continue;
-
- /* read first DW */
- dw[count++] = cra_readl(pcie, RP_RXCPL_REG);
-
- /* Poll for EOP */
- for (i = 0; i < TLP_LOOP; i++) {
- ctrl = cra_readl(pcie, RP_RXCPL_STATUS);
- dw[count++] = cra_readl(pcie, RP_RXCPL_REG);
- if (ctrl & RP_RXCPL_EOP) {
- comp_status = TLP_COMP_STATUS(dw[1]);
- if (comp_status) {
- *value = pci_get_ff(PCI_SIZE_32);
- return 0;
- }
-
- if (value &&
- TLP_BYTE_COUNT(dw[1]) == sizeof(u32) &&
- count >= 3)
- *value = dw[3];
-
- return 0;
- }
- }
-
- udelay(5);
- }
-
- dev_err(pcie->dev, "read TLP packet timed out\n");
- return -ENODEV;
-}
-
-static void tlp_write_packet(struct intel_fpga_pcie *pcie, u32 *headers,
- u32 data)
-{
- tlp_write_tx(pcie, headers[0], RP_TX_SOP);
-
- tlp_write_tx(pcie, headers[1], 0);
-
- tlp_write_tx(pcie, headers[2], 0);
-
- tlp_write_tx(pcie, data, RP_TX_EOP);
-}
-
-static int tlp_cfg_dword_read(struct intel_fpga_pcie *pcie, pci_dev_t bdf,
- int offset, u8 byte_en, u32 *value)
-{
- u32 headers[TLP_HDR_SIZE];
- u8 busno = PCI_BUS(bdf);
-
- headers[0] = TLP_CFGRD_DW0(pcie, busno);
- headers[1] = TLP_CFG_DW1(pcie, TLP_READ_TAG, byte_en);
- headers[2] = TLP_CFG_DW2(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset);
-
- tlp_write_packet(pcie, headers, 0);
-
- return tlp_read_packet(pcie, value);
-}
-
-static int tlp_cfg_dword_write(struct intel_fpga_pcie *pcie, pci_dev_t bdf,
- int offset, u8 byte_en, u32 value)
-{
- u32 headers[TLP_HDR_SIZE];
- u8 busno = PCI_BUS(bdf);
-
- headers[0] = TLP_CFGWR_DW0(pcie, busno);
- headers[1] = TLP_CFG_DW1(pcie, TLP_WRITE_TAG, byte_en);
- headers[2] = TLP_CFG_DW2(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset);
-
- tlp_write_packet(pcie, headers, value);
-
- return tlp_read_packet(pcie, NULL);
-}
-
-int intel_fpga_rp_conf_addr(const struct udevice *bus, pci_dev_t bdf,
- uint offset, void **paddress)
-{
- struct intel_fpga_pcie *pcie = dev_get_priv(bus);
-
- *paddress = RP_CFG_ADDR(pcie, offset);
-
- return 0;
-}
-
-static int intel_fpga_pcie_rp_rd_conf(struct udevice *bus, pci_dev_t bdf,
- uint offset, ulong *valuep,
- enum pci_size_t size)
-{
- return pci_generic_mmap_read_config(bus, intel_fpga_rp_conf_addr,
- bdf, offset, valuep, size);
-}
-
-static int intel_fpga_pcie_rp_wr_conf(struct udevice *bus, pci_dev_t bdf,
- uint offset, ulong value,
- enum pci_size_t size)
-{
- int ret;
- struct intel_fpga_pcie *pcie = dev_get_priv(bus);
-
- ret = pci_generic_mmap_write_config(bus, intel_fpga_rp_conf_addr,
- bdf, offset, value, size);
- if (!ret) {
- /* Monitor changes to PCI_PRIMARY_BUS register on root port
- * and update local copy of root bus number accordingly.
- */
- if (offset == PCI_PRIMARY_BUS)
- pcie->first_busno = (u8)(value);
- }
-
- return ret;
-}
-
-static u8 pcie_get_byte_en(uint offset, enum pci_size_t size)
-{
- switch (size) {
- case PCI_SIZE_8:
- return 1 << (offset & 3);
- case PCI_SIZE_16:
- return 3 << (offset & 3);
- default:
- return 0xf;
- }
-}
-
-static int _pcie_intel_fpga_read_config(struct intel_fpga_pcie *pcie,
- pci_dev_t bdf, uint offset,
- ulong *valuep, enum pci_size_t size)
-{
- int ret;
- u32 data;
- u8 byte_en;
-
- /* Uses memory mapped method to read rootport config registers */
- if (IS_ROOT_PORT(pcie, bdf))
- return intel_fpga_pcie_rp_rd_conf(pcie->bus, bdf,
- offset, valuep, size);
-
- byte_en = pcie_get_byte_en(offset, size);
- ret = tlp_cfg_dword_read(pcie, bdf, offset & ~DWORD_MASK,
- byte_en, &data);
- if (ret)
- return ret;
-
- dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08x)\n",
- offset, size, data);
- *valuep = pci_conv_32_to_size(data, offset, size);
-
- return 0;
-}
-
-static int _pcie_intel_fpga_write_config(struct intel_fpga_pcie *pcie,
- pci_dev_t bdf, uint offset,
- ulong value, enum pci_size_t size)
-{
- u32 data;
- u8 byte_en;
-
- dev_dbg(pcie->dev, "PCIE CFG write: (b.d.f)=(%02d.%02d.%02d)\n",
- PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
- dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08lx)\n",
- offset, size, value);
-
- /* Uses memory mapped method to read rootport config registers */
- if (IS_ROOT_PORT(pcie, bdf))
- return intel_fpga_pcie_rp_wr_conf(pcie->bus, bdf, offset,
- value, size);
-
- byte_en = pcie_get_byte_en(offset, size);
- data = pci_conv_size_to_32(0, value, offset, size);
-
- return tlp_cfg_dword_write(pcie, bdf, offset & ~DWORD_MASK,
- byte_en, data);
-}
-
-static int pcie_intel_fpga_read_config(const struct udevice *bus, pci_dev_t bdf,
- uint offset, ulong *valuep,
- enum pci_size_t size)
-{
- struct intel_fpga_pcie *pcie = dev_get_priv(bus);
-
- dev_dbg(pcie->dev, "PCIE CFG read: (b.d.f)=(%02d.%02d.%02d)\n",
- PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
-
- if (intel_fpga_pcie_hide_rc_bar(pcie, bdf, offset)) {
- *valuep = (u32)pci_get_ff(size);
- return 0;
- }
-
- if (!intel_fpga_pcie_addr_valid(pcie, bdf)) {
- *valuep = (u32)pci_get_ff(size);
- return 0;
- }
-
- return _pcie_intel_fpga_read_config(pcie, bdf, offset, valuep, size);
-}
-
-static int pcie_intel_fpga_write_config(struct udevice *bus, pci_dev_t bdf,
- uint offset, ulong value,
- enum pci_size_t size)
-{
- struct intel_fpga_pcie *pcie = dev_get_priv(bus);
-
- if (intel_fpga_pcie_hide_rc_bar(pcie, bdf, offset))
- return 0;
-
- if (!intel_fpga_pcie_addr_valid(pcie, bdf))
- return 0;
-
- return _pcie_intel_fpga_write_config(pcie, bdf, offset, value,
- size);
-}
-
-static int pcie_intel_fpga_probe(struct udevice *dev)
-{
- struct intel_fpga_pcie *pcie = dev_get_priv(dev);
-
- pcie->bus = pci_get_controller(dev);
- pcie->first_busno = dev_seq(dev);
-
- /* clear all interrupts */
- cra_writel(pcie, P2A_INT_STS_ALL, P2A_INT_STATUS);
- /* disable all interrupts */
- cra_writel(pcie, 0, P2A_INT_ENABLE);
-
- return 0;
-}
-
-static int pcie_intel_fpga_of_to_plat(struct udevice *dev)
-{
- struct intel_fpga_pcie *pcie = dev_get_priv(dev);
- struct fdt_resource reg_res;
- int node = dev_of_offset(dev);
- int ret;
-
- DECLARE_GLOBAL_DATA_PTR;
-
- ret = fdt_get_named_resource(gd->fdt_blob, node, "reg", "reg-names",
- "Cra", &reg_res);
- if (ret) {
- dev_err(dev, "resource \"Cra\" not found\n");
- return ret;
- }
-
- pcie->cra_base = map_physmem(reg_res.start,
- fdt_resource_size(&reg_res),
- MAP_NOCACHE);
-
- ret = fdt_get_named_resource(gd->fdt_blob, node, "reg", "reg-names",
- "Hip", &reg_res);
- if (ret) {
- dev_err(dev, "resource \"Hip\" not found\n");
- return ret;
- }
-
- pcie->hip_base = map_physmem(reg_res.start,
- fdt_resource_size(&reg_res),
- MAP_NOCACHE);
-
- return 0;
-}
-
-static const struct dm_pci_ops pcie_intel_fpga_ops = {
- .read_config = pcie_intel_fpga_read_config,
- .write_config = pcie_intel_fpga_write_config,
-};
-
-static const struct udevice_id pcie_intel_fpga_ids[] = {
- { .compatible = "altr,pcie-root-port-2.0" },
- {},
-};
-
-U_BOOT_DRIVER(pcie_intel_fpga) = {
- .name = "pcie_intel_fpga",
- .id = UCLASS_PCI,
- .of_match = pcie_intel_fpga_ids,
- .ops = &pcie_intel_fpga_ops,
- .of_to_plat = pcie_intel_fpga_of_to_plat,
- .probe = pcie_intel_fpga_probe,
- .priv_auto = sizeof(struct intel_fpga_pcie),
-};
diff --git a/drivers/pci_endpoint/pcie_cdns_ti_ep.c b/drivers/pci_endpoint/pcie_cdns_ti_ep.c
index 661b6ba5b55..021bd73a383 100644
--- a/drivers/pci_endpoint/pcie_cdns_ti_ep.c
+++ b/drivers/pci_endpoint/pcie_cdns_ti_ep.c
@@ -20,6 +20,7 @@
#include <regmap.h>
#include <syscon.h>
#include <pci_ep.h>
+#include <linux/delay.h>
#include "pcie-cadence.h"
@@ -90,15 +91,26 @@ static int pcie_cdns_reset(struct udevice *dev, struct power_domain *pci_pwrdmn)
dev_err(dev, "failed to power on: %d\n", ret);
return ret;
}
-
+ mdelay(1);
return 0;
}
static int pcie_cdns_config_serdes(struct udevice *dev)
{
+ int ret;
+
+ if (CONFIG_IS_ENABLED(MUX_MMIO)) {
+ struct udevice *mux;
+
+ ret = uclass_get_device_by_seq(UCLASS_MUX, 0, &mux);
+ if (ret) {
+ dev_err(dev, "unable to get mux\n");
+ return ret;
+ }
+ }
+
if (CONFIG_IS_ENABLED(PHY_CADENCE_TORRENT)) {
struct phy serdes;
- int ret = 7;
ret = generic_phy_get_by_name(dev, "pcie-phy", &serdes);
if (ret != 0 && ret != -EBUSY) {
@@ -263,9 +275,11 @@ static int pcie_cdns_ti_ep_probe(struct udevice *dev)
struct pcie_cdns_ti_ep *pcie = dev_get_priv(dev);
struct pcie_cdns_ti_ep_data *data;
struct power_domain pci_pwrdmn;
+ struct cdns_pcie pcie_dev;
struct clk *clk;
int ret;
+ pcie_dev.reg_base = pcie->reg_base;
pcie->dev = dev;
data = (struct pcie_cdns_ti_ep_data *)dev_get_driver_data(dev);
if (!data)
@@ -316,6 +330,13 @@ static int pcie_cdns_ti_ep_probe(struct udevice *dev)
return ret;
}
+ /*
+ * Disable all the functions except function 0 (anyway BIT(0) is
+ * hardwired to 1). This is required to avoid RC from enumerating
+ * those functions which are not even configured.
+ */
+ cdns_pcie_writel(&pcie_dev, CDNS_PCIE_LM_EP_FUNC_CFG, BIT(0));
+
return 0;
}
@@ -377,11 +398,19 @@ static const struct pcie_cdns_ti_ep_data am64_pcie_ep_data = {
.max_lanes = 1,
};
+static const struct pcie_cdns_ti_ep_data j784s4_pcie_ep_data = {
+ .max_lanes = 4,
+};
+
static const struct udevice_id pcie_cdns_ti_ep_ids[] = {
{
.compatible = "ti,am64-pcie-ep",
.data = (ulong)&am64_pcie_ep_data,
},
+ {
+ .compatible = "ti,j784s4-pcie-ep",
+ .data = (ulong)&j784s4_pcie_ep_data,
+ },
{},
};
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index d36a5f00ef8..420d7c7a44d 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -289,11 +289,19 @@ config PHY_NPCM_USB
Support the USB PHY in NPCM SoCs
config PHY_IMX8MQ_USB
- bool "NXP i.MX8MQ/i.MX8MP/i.MX95 USB PHY Driver"
+ bool "NXP i.MX8MQ/i.MX8MP/i.MX95/i.MX94 USB PHY Driver"
depends on PHY
- depends on IMX8MQ || IMX8MP || IMX95
+ depends on IMX8MQ || IMX8MP || IMX95 || IMX94
help
- Support the USB3.0 PHY in NXP i.MX8MQ, i.MX8MP, and i.MX95 SoC
+ Support the USB3.0 PHY in NXP i.MX8MQ, i.MX8MP, i.MX95, and i.MX94 SoCs.
+
+config SPL_PHY_IMX8MQ_USB
+ bool "Enable NXP i.MX8MQ/i.MX8MP/i.MX95/i.MX94 USB3.0 PHY Driver in SPL"
+ depends on SPL_PHY
+ depends on IMX8MQ || IMX8MP || IMX95 || IMX94
+ help
+ Enable support for the USB3.0 PHY in NXP i.MX8MQ, i.MX8MP, i.MX95, and
+ i.MX94 SoCs in SPL.
config PHY_IMX8M_PCIE
bool "NXP i.MX8MM/i.MX8MP PCIe PHY Driver"
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 98c1ef8683b..5a6df0ecfeb 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -38,7 +38,7 @@ obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o
obj-$(CONFIG_PHY_EXYNOS_USBDRD) += phy-exynos-usbdrd.o
obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o
obj-$(CONFIG_PHY_NPCM_USB) += phy-npcm-usb.o
-obj-$(CONFIG_PHY_IMX8MQ_USB) += phy-imx8mq-usb.o
+obj-$(CONFIG_$(PHASE_)PHY_IMX8MQ_USB) += phy-imx8mq-usb.o
obj-$(CONFIG_PHY_IMX8M_PCIE) += phy-imx8m-pcie.o
obj-$(CONFIG_PHY_XILINX_ZYNQMP) += phy-zynqmp.o
obj-y += cadence/
diff --git a/drivers/phy/marvell/Kconfig b/drivers/phy/marvell/Kconfig
index b5f69c0a96d..c66197de143 100644
--- a/drivers/phy/marvell/Kconfig
+++ b/drivers/phy/marvell/Kconfig
@@ -1,5 +1,6 @@
config MVEBU_COMPHY_SUPPORT
bool "ComPhy SerDes driver"
+ depends on ARMADA_3700 || ARMADA_8K
help
Choose this option to add support
for Comphy driver.
diff --git a/drivers/phy/qcom/Kconfig b/drivers/phy/qcom/Kconfig
index 61e5e2fca41..0dd69f7ffd0 100644
--- a/drivers/phy/qcom/Kconfig
+++ b/drivers/phy/qcom/Kconfig
@@ -1,8 +1,8 @@
config MSM8916_USB_PHY
- bool "Qualcomm MSM8916 USB PHY support"
- depends on PHY
+ bool
+ select PHY
help
- Support the USB PHY in msm8916
+ Support the Qualcomm MSM8916 USB PHY
This PHY is found on qualcomm dragonboard410c development board.
diff --git a/drivers/phy/qcom/phy-qcom-qmp-ufs.c b/drivers/phy/qcom/phy-qcom-qmp-ufs.c
index f3c606847fb..907f34744eb 100644
--- a/drivers/phy/qcom/phy-qcom-qmp-ufs.c
+++ b/drivers/phy/qcom/phy-qcom-qmp-ufs.c
@@ -221,6 +221,36 @@ static const struct qmp_ufs_init_tbl sm8150_ufsphy_hs_g4_rx[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH4, 0x3c),
};
+static const struct qmp_ufs_init_tbl sm7150_ufsphy_rx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_LVL, 0x24),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1e),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_INTERFACE_MODE, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_TERM_BW, 0x5b),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x1b),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_HALF, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_QUARTER, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x5b),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x81),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x80),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x59),
+};
+
+static const struct qmp_ufs_init_tbl sm7150_ufsphy_pcs[] = {
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_SIGDET_CTRL2, 0x6f),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_TX_SMALL_AMP_DRV_LVL, 0x02),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_SYM_RESYNC_CTRL, 0x03),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_TX_MID_TERM_CTRL1, 0x43),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_SIGDET_CTRL1, 0x0f),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_MIN_HIBERN8_TIME, 0xff),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
+};
+
static const struct qmp_ufs_init_tbl sm8150_ufsphy_serdes[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0xd9),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x11),
@@ -1018,6 +1048,36 @@ static const struct qmp_ufs_cfg sm8150_ufsphy_cfg = {
.no_pcs_sw_reset = false,
};
+static const struct qmp_ufs_cfg sm7150_ufsphy_cfg = {
+ .lanes = 1,
+
+ .offsets = &qmp_ufs_offsets,
+
+ .tbls = {
+ .serdes = sdm845_ufsphy_serdes,
+ .serdes_num = ARRAY_SIZE(sdm845_ufsphy_serdes),
+ .tx = sdm845_ufsphy_tx,
+ .tx_num = ARRAY_SIZE(sdm845_ufsphy_tx),
+ .rx = sm7150_ufsphy_rx,
+ .rx_num = ARRAY_SIZE(sm7150_ufsphy_rx),
+ .pcs = sm7150_ufsphy_pcs,
+ .pcs_num = ARRAY_SIZE(sm7150_ufsphy_pcs),
+ },
+ .tbls_hs_b = {
+ .serdes = sdm845_ufsphy_hs_b_serdes,
+ .serdes_num = ARRAY_SIZE(sdm845_ufsphy_hs_b_serdes),
+ },
+ .clk_list = sdm845_ufs_phy_clk_l,
+ .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
+ .vreg_list = qmp_ufs_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_ufs_vreg_l),
+ .reset_list = qmp_ufs_reset_l,
+ .num_resets = ARRAY_SIZE(qmp_ufs_reset_l),
+ .regs = ufsphy_v3_regs_layout,
+
+ .no_pcs_sw_reset = true,
+};
+
static const struct qmp_ufs_cfg sm8250_ufsphy_cfg = {
.lanes = 2,
@@ -1593,6 +1653,8 @@ static struct phy_ops qmp_ufs_ops = {
static const struct udevice_id qmp_ufs_ids[] = {
{ .compatible = "qcom,sa8775p-qmp-ufs-phy", .data = (ulong)&sa8775p_ufsphy_cfg, },
{ .compatible = "qcom,sdm845-qmp-ufs-phy", .data = (ulong)&sdm845_ufsphy_cfg },
+ { .compatible = "qcom,sm6350-qmp-ufs-phy", .data = (ulong)&sdm845_ufsphy_cfg },
+ { .compatible = "qcom,sm7150-qmp-ufs-phy", .data = (ulong)&sm7150_ufsphy_cfg },
{ .compatible = "qcom,sm8150-qmp-ufs-phy", .data = (ulong)&sm8150_ufsphy_cfg },
{ .compatible = "qcom,sm8250-qmp-ufs-phy", .data = (ulong)&sm8250_ufsphy_cfg },
{ .compatible = "qcom,qcs8300-qmp-ufs-phy", .data = (ulong)&sa8775p_ufsphy_cfg },
diff --git a/drivers/phy/renesas/Kconfig b/drivers/phy/renesas/Kconfig
index 0efb0f8f337..affbee0500c 100644
--- a/drivers/phy/renesas/Kconfig
+++ b/drivers/phy/renesas/Kconfig
@@ -7,3 +7,15 @@ config PHY_R8A779F0_ETHERNET_SERDES
depends on RCAR_64 && PHY
help
Support for Ethernet SERDES found on Renesas R-Car S4-8 SoCs.
+
+config PHY_R8A78000_ETHERNET_PCS
+ tristate "Renesas R-Car X5H Ethernet PCS driver"
+ depends on RCAR_64 && PHY
+ help
+ Support for Ethernet PCS found on Renesas R-Car X5H SoCs.
+
+config PHY_R8A78000_MP_PHY
+ tristate "Renesas R-Car X5H Multi-Protocol PHY driver"
+ depends on RCAR_64 && PHY
+ help
+ Support for Multi-Protocol PHY on Renesas R-Car X5H SoCs.
diff --git a/drivers/phy/renesas/Makefile b/drivers/phy/renesas/Makefile
index fd6b8d964e5..12585c21f58 100644
--- a/drivers/phy/renesas/Makefile
+++ b/drivers/phy/renesas/Makefile
@@ -1 +1,3 @@
obj-$(CONFIG_PHY_R8A779F0_ETHERNET_SERDES) += r8a779f0-ether-serdes.o
+obj-$(CONFIG_PHY_R8A78000_ETHERNET_PCS) += r8a78000-ether-pcs.o
+obj-$(CONFIG_PHY_R8A78000_MP_PHY) += r8a78000-mp-phy.o
diff --git a/drivers/phy/renesas/r8a78000-ether-pcs.c b/drivers/phy/renesas/r8a78000-ether-pcs.c
new file mode 100644
index 00000000000..6343f89313a
--- /dev/null
+++ b/drivers/phy/renesas/r8a78000-ether-pcs.c
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Renesas Ethernet PCS Device Driver
+ *
+ * Based on the Renesas Ethernet SERDES driver and updated for PCS support.
+ *
+ * Copyright (C) 2025 Renesas Electronics Corporation
+ */
+
+#include <asm/io.h>
+#include <clk-uclass.h>
+#include <clk.h>
+#include <div64.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <dm/of_access.h>
+#include <generic-phy.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <log.h>
+#include <reset.h>
+#include <syscon.h>
+
+#define R8A78000_ETH_PCS_NUM 8
+#define R8A78000_ETH_PCS_OFFSET 0x0400
+#define R8A78000_ETH_PCS_BANK_SELECT 0x03fc
+#define R8A78000_ETH_PCS_TIMEOUT_US 100000
+#define R8A78000_ETH_PCS_NUM_RETRY_LINKUP 8
+
+struct r8a78000_eth_pcs_drv_data;
+struct r8a78000_eth_pcs_channel {
+ struct r8a78000_eth_pcs_drv_data *dd;
+ struct phy *phy;
+ void __iomem *addr;
+ phy_interface_t phy_interface;
+ int speed;
+ int index;
+};
+
+struct r8a78000_eth_pcs_drv_data {
+ void __iomem *addr;
+ struct reset_ctl_bulk reset;
+ struct phy mpphy;
+ struct r8a78000_eth_pcs_channel channel[R8A78000_ETH_PCS_NUM];
+ struct clk_bulk clks;
+};
+
+/*
+ * The datasheet describes initialization procedure without any information
+ * about registers' name/bits. So, this is all black magic to initialize
+ * the hardware.
+ */
+static void r8a78000_eth_pcs_write32(void __iomem *addr, u32 offs, u32 bank, u32 data)
+{
+ writel(bank, addr + R8A78000_ETH_PCS_BANK_SELECT);
+ writel(data, addr + offs);
+}
+
+static int
+r8a78000_eth_pcs_reg_wait(struct r8a78000_eth_pcs_channel *channel,
+ u32 offs, u32 bank, u32 mask, u32 expected)
+{
+ u32 val = 0;
+ int ret;
+
+ writel(bank, channel->addr + R8A78000_ETH_PCS_BANK_SELECT);
+
+ ret = readl_poll_timeout(channel->addr + offs, val,
+ (val & mask) == expected,
+ R8A78000_ETH_PCS_TIMEOUT_US);
+ if (ret)
+ dev_dbg(channel->phy->dev,
+ "%s: index %d, offs %x, bank %x, mask %x, expected %x\n",
+ __func__, channel->index, offs, bank, mask, expected);
+
+ return ret;
+}
+
+static int
+r8a78000_eth_pcs_init_ram(struct r8a78000_eth_pcs_channel *channel, struct phy *mpphy)
+{
+ int ret;
+
+ ret = r8a78000_eth_pcs_reg_wait(channel, 0x026c, 0x180, BIT(0), 0x01);
+ if (ret)
+ return ret;
+
+ r8a78000_eth_pcs_write32(channel->addr, 0x026c, 0x180, 0x03);
+
+ ret = generic_phy_power_on(mpphy);
+ if (ret)
+ return ret;
+
+ ret = r8a78000_eth_pcs_reg_wait(channel, 0x0000, 0x300, BIT(15), 0);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int
+r8a78000_eth_pcs_common_setting(struct r8a78000_eth_pcs_channel *channel)
+{
+ int ret;
+
+ switch (channel->phy_interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ r8a78000_eth_pcs_write32(channel->addr, 0x001c, 0x300, 0x0001);
+ r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x380, 0x2000);
+ r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x1f00, 0x0140);
+ r8a78000_eth_pcs_write32(channel->addr, 0x0258, 0x180, 0x0018);
+ r8a78000_eth_pcs_write32(channel->addr, 0x01dc, 0x180, 0x000d);
+ r8a78000_eth_pcs_write32(channel->addr, 0x00f8, 0x180, 0x0016);
+ r8a78000_eth_pcs_write32(channel->addr, 0x0248, 0x180, 0x0016);
+ r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x300, 0x0c40);
+
+ ret = r8a78000_eth_pcs_reg_wait(channel, 0x0040, 0x380, GENMASK(4, 2), 0x06 << 2);
+ if (ret)
+ return ret;
+
+ r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x300, 0x0440);
+
+ ret = r8a78000_eth_pcs_reg_wait(channel, 0x0040, 0x380, GENMASK(4, 2), 0x04 << 2);
+ if (ret)
+ return ret;
+
+ r8a78000_eth_pcs_write32(channel->addr, 0x0014, 0x380, 0x0050);
+ r8a78000_eth_pcs_write32(channel->addr, 0x00d8, 0x180, 0x3000);
+ r8a78000_eth_pcs_write32(channel->addr, 0x00dc, 0x180, 0x0000);
+
+ return 0;
+ case PHY_INTERFACE_MODE_USXGMII:
+ r8a78000_eth_pcs_write32(channel->addr, 0x001c, 0x300, 0x0000);
+ r8a78000_eth_pcs_write32(channel->addr, 0x001c, 0x380, 0x0000);
+ r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x380, 0x2200);
+ r8a78000_eth_pcs_write32(channel->addr, 0x0258, 0x180, 0x0018);
+ r8a78000_eth_pcs_write32(channel->addr, 0x01dc, 0x180, 0x000d);
+ r8a78000_eth_pcs_write32(channel->addr, 0x00f8, 0x180, 0x001b);
+ r8a78000_eth_pcs_write32(channel->addr, 0x0248, 0x180, 0x001b);
+ r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x300, 0x0c40);
+
+ ret = r8a78000_eth_pcs_reg_wait(channel, 0x0040, 0x380, GENMASK(4, 2), 0x06 << 2);
+ if (ret)
+ return ret;
+
+ r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x300, 0x0440);
+
+ ret = r8a78000_eth_pcs_reg_wait(channel, 0x0040, 0x380, GENMASK(4, 2), 0x04 << 2);
+ if (ret)
+ return ret;
+
+ r8a78000_eth_pcs_write32(channel->addr, 0x0014, 0x380, 0x0050);
+ r8a78000_eth_pcs_write32(channel->addr, 0x00d8, 0x180, 0x1800);
+ r8a78000_eth_pcs_write32(channel->addr, 0x00dc, 0x180, 0x0012);
+
+ ret = r8a78000_eth_pcs_reg_wait(channel, 0x0080, 0x180, BIT(12), BIT(12));
+ if (ret)
+ return ret;
+
+ r8a78000_eth_pcs_write32(channel->addr, 0x0170, 0x180, 0x1000);
+
+ ret = r8a78000_eth_pcs_reg_wait(channel, 0x0260, 0x180, BIT(12), BIT(12));
+ if (ret)
+ return ret;
+
+ r8a78000_eth_pcs_write32(channel->addr, 0x0170, 0x180, 0x0000);
+
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int
+r8a78000_eth_pcs_chan_setting(struct r8a78000_eth_pcs_channel *channel)
+{
+ int ret;
+
+ switch (channel->phy_interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ /* For AN_ON */
+ r8a78000_eth_pcs_write32(channel->addr, 0x0004, 0x1f80, 0x0005);
+ r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x1f80, 0x2200);
+ r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x1f00, 0x3140);
+
+ ret = r8a78000_eth_pcs_reg_wait(channel, 0x0008, 0x1f80, BIT(0), BIT(0));
+ if (ret)
+ return ret;
+
+ break;
+ case PHY_INTERFACE_MODE_USXGMII:
+ /* For AN_ON */
+ r8a78000_eth_pcs_write32(channel->addr, 0x0004, 0x1f80, 0x0001);
+ r8a78000_eth_pcs_write32(channel->addr, 0x0028, 0x1f80, 0x0001);
+ r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x1f80, 0x2008);
+ r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x1f00, 0x3140);
+
+ ret = r8a78000_eth_pcs_reg_wait(channel, 0x0008, 0x1f80, BIT(0), BIT(0));
+ if (ret)
+ return ret;
+
+ r8a78000_eth_pcs_write32(channel->addr, 0x0008, 0x1f80, 0x0000);
+
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int
+r8a78000_eth_pcs_chan_speed(struct r8a78000_eth_pcs_channel *channel)
+{
+ int ret;
+
+ switch (channel->phy_interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ /* Do nothing */
+ break;
+ case PHY_INTERFACE_MODE_USXGMII:
+ if (channel->speed == 10000)
+ r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x1f00, 0x2140);
+ else if (channel->speed == 2500)
+ r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x1f00, 0x0120);
+ else
+ return -EOPNOTSUPP;
+
+ r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x380, 0x2600);
+
+ ret = r8a78000_eth_pcs_reg_wait(channel, 0x0000, 0x380, BIT(10), 0);
+ if (ret)
+ return ret;
+
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int r8a78000_eth_pcs_monitor_linkup(struct r8a78000_eth_pcs_channel *channel)
+{
+ int i, ret;
+
+ for (i = 0; i < R8A78000_ETH_PCS_NUM_RETRY_LINKUP; i++) {
+ ret = r8a78000_eth_pcs_reg_wait(channel, 0x0004, 0x300,
+ BIT(2), BIT(2));
+ if (!ret)
+ break;
+
+ /* restart */
+ r8a78000_eth_pcs_write32(channel->addr, 0x0144, 0x180, 0x0010);
+ udelay(1);
+ r8a78000_eth_pcs_write32(channel->addr, 0x0144, 0x180, 0x0000);
+ }
+
+ return ret;
+}
+
+static int r8a78000_eth_pcs_init(struct phy *p)
+{
+ struct r8a78000_eth_pcs_drv_data *dd = dev_get_priv(p->dev);
+ struct r8a78000_eth_pcs_channel *channel = dd->channel + p->id;
+ int ret;
+
+ ret = generic_phy_init(&dd->mpphy);
+ if (ret) {
+ dev_dbg(channel->phy->dev, "XPCS: Failed to init MPPHY\n");
+ return ret;
+ }
+
+ ret = r8a78000_eth_pcs_init_ram(channel, &dd->mpphy);
+ if (ret)
+ return ret;
+
+ ret = r8a78000_eth_pcs_common_setting(channel);
+
+ return ret;
+}
+
+static int r8a78000_eth_pcs_hw_init_late(struct r8a78000_eth_pcs_channel *channel)
+{
+ int ret;
+
+ ret = r8a78000_eth_pcs_chan_setting(channel);
+ if (ret)
+ return ret;
+
+ ret = r8a78000_eth_pcs_chan_speed(channel);
+ if (ret)
+ return ret;
+
+ r8a78000_eth_pcs_write32(channel->addr, 0x03c0, 0x380, 0x0000);
+
+ r8a78000_eth_pcs_write32(channel->addr, 0x03d0, 0x380, 0x0000);
+
+ return r8a78000_eth_pcs_monitor_linkup(channel);
+}
+
+static int r8a78000_eth_pcs_power_on(struct phy *p)
+{
+ struct r8a78000_eth_pcs_drv_data *dd = dev_get_priv(p->dev);
+ struct r8a78000_eth_pcs_channel *channel = dd->channel + p->id;
+
+ return r8a78000_eth_pcs_hw_init_late(channel);
+}
+
+static int r8a78000_eth_pcs_set_mode(struct phy *p, enum phy_mode mode,
+ int submode)
+{
+ struct r8a78000_eth_pcs_drv_data *dd = dev_get_priv(p->dev);
+ struct r8a78000_eth_pcs_channel *channel = dd->channel + p->id;
+
+ if (mode != PHY_MODE_ETHERNET)
+ return -EOPNOTSUPP;
+
+ switch (submode) {
+ case PHY_INTERFACE_MODE_GMII:
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_USXGMII:
+ channel->phy_interface = submode;
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int r8a78000_eth_pcs_set_speed(struct phy *p, int speed)
+{
+ struct r8a78000_eth_pcs_drv_data *dd = dev_get_priv(p->dev);
+ struct r8a78000_eth_pcs_channel *channel = dd->channel + p->id;
+
+ channel->speed = speed;
+
+ return 0;
+}
+
+static int r8a78000_eth_pcs_of_xlate(struct phy *phy,
+ struct ofnode_phandle_args *args)
+{
+ if (args->args_count < 1)
+ return -ENODEV;
+
+ if (args->args[0] >= R8A78000_ETH_PCS_NUM)
+ return -ENODEV;
+
+ phy->id = args->args[0];
+
+ return 0;
+}
+
+static const struct phy_ops r8a78000_eth_pcs_ops = {
+ .init = r8a78000_eth_pcs_init,
+ .power_on = r8a78000_eth_pcs_power_on,
+ .set_mode = r8a78000_eth_pcs_set_mode,
+ .set_speed = r8a78000_eth_pcs_set_speed,
+ .of_xlate = r8a78000_eth_pcs_of_xlate,
+};
+
+static const struct udevice_id r8a78000_eth_pcs_of_table[] = {
+ { .compatible = "renesas,r8a78000-ether-pcs", },
+ { }
+};
+
+static int r8a78000_eth_pcs_probe(struct udevice *dev)
+{
+ struct r8a78000_eth_pcs_drv_data *dd = dev_get_priv(dev);
+ int i, ret;
+
+ dd->addr = dev_read_addr_ptr(dev);
+ if (!dd->addr)
+ return -EINVAL;
+
+ ret = reset_get_bulk(dev, &dd->reset);
+ if (ret)
+ return ret;
+
+ ret = clk_get_bulk(dev, &dd->clks);
+ if (ret < 0)
+ goto err_clk_get;
+
+ ret = clk_enable_bulk(&dd->clks);
+ if (ret)
+ goto err_clk_enable;
+
+ reset_assert_bulk(&dd->reset);
+ reset_deassert_bulk(&dd->reset);
+
+ ret = generic_phy_get_by_index(dev, 0, &dd->mpphy);
+ if (ret)
+ goto err_phy_get;
+
+ for (i = 0; i < R8A78000_ETH_PCS_NUM; i++) {
+ struct r8a78000_eth_pcs_channel *channel = &dd->channel[i];
+
+ channel->addr = dd->addr + R8A78000_ETH_PCS_OFFSET * i;
+ channel->dd = dd;
+ channel->index = i;
+ }
+
+ return 0;
+
+err_phy_get:
+ clk_disable_bulk(&dd->clks);
+err_clk_enable:
+ clk_release_bulk(&dd->clks);
+err_clk_get:
+ reset_release_bulk(&dd->reset);
+ return ret;
+}
+
+U_BOOT_DRIVER(r8a78000_eth_pcs_driver_platform) = {
+ .name = "r8a78000_eth_pcs",
+ .id = UCLASS_PHY,
+ .of_match = r8a78000_eth_pcs_of_table,
+ .probe = r8a78000_eth_pcs_probe,
+ .ops = &r8a78000_eth_pcs_ops,
+ .priv_auto = sizeof(struct r8a78000_eth_pcs_drv_data),
+};
diff --git a/drivers/phy/renesas/r8a78000-mp-phy.c b/drivers/phy/renesas/r8a78000-mp-phy.c
new file mode 100644
index 00000000000..fba130a65a1
--- /dev/null
+++ b/drivers/phy/renesas/r8a78000-mp-phy.c
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Renesas Multi-Protocol PHY device driver
+ *
+ * Copyright (C) 2025 Renesas Electronics Corporation
+ */
+
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <generic-phy.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <reset.h>
+
+/* Common registers */
+#define MPPHY_CMNCNT1 0x80000
+#define MPPHY_CMNCNT2 0x80004
+#define MPPHY_PCS0REG1 0x85000
+#define MPPHY_PCS0REG5 0x85010
+
+/* Channel register base and offsets */
+#define MPPHY_CHAN_BASE(ch) (0x81000 + (ch) * 0x1000)
+#define MPPHY_PXTEST_OFFSET 0x00C
+#define MPPHY_RXCNT_OFFSET 0x038
+#define MPPHY_SRAMCNT_OFFSET 0x040
+#define MPPHY_REFCLK_OFFSET 0x014
+#define MPPHY_CNTXT1_OFFSET 0x004
+#define MPPHY_CNTXT2_OFFSET 0x008
+#define MPPHY_TXREQ_OFFSET 0x044
+
+/* Channel specific registers */
+#define MPPHY_PXTEST(ch) (MPPHY_CHAN_BASE(ch) + MPPHY_PXTEST_OFFSET)
+#define MPPHY_PXRXCNT(ch) (MPPHY_CHAN_BASE(ch) + MPPHY_RXCNT_OFFSET)
+#define MPPHY_PXSRAMCNT(ch) (MPPHY_CHAN_BASE(ch) + MPPHY_SRAMCNT_OFFSET)
+#define MPPHY_PXREFCLK(ch) (MPPHY_CHAN_BASE(ch) + MPPHY_REFCLK_OFFSET)
+#define MPPHY_PXCNTXT1(ch) (MPPHY_CHAN_BASE(ch) + MPPHY_CNTXT1_OFFSET)
+#define MPPHY_PXCNTXT2(ch) (MPPHY_CHAN_BASE(ch) + MPPHY_CNTXT2_OFFSET)
+#define MPPHY_PXTXREQ(ch) (MPPHY_CHAN_BASE(ch) + MPPHY_TXREQ_OFFSET)
+
+/* Channel enable bit masks for MPPHY_CMNCNT1 register */
+#define MPPHY_CMNCNT1_CH_MASK(ch) (0xFF << ((ch) * 8))
+
+/* Channel enable bits for MPPHY_CMNCNT1 register */
+#define MPPHY_CMNCNT1_CH_EN(ch) ((ch) == 0 ? BIT(1) : BIT((ch) * 8))
+
+/* PCS0REG5 register mask and values for each channel */
+#define MPPHY_PCS0REG5_CH(ch) (0x03 << (24 + (ch) * 2))
+
+/* PCS0REG1 register bits */
+#define MPPHY_PCS0REG1_VAL 0x00010000
+
+/* PXTEST register bit */
+#define MPPHY_PXTEST_BIT BIT(0)
+
+/* PXRXCNT register reset value */
+#define MPPHY_PXRXCNT_RESET_VAL 0x202
+
+/* PXSRAMCNT register bits */
+#define MPPHY_PXSRAMCNT_BYPASS BIT(0)
+#define MPPHY_PXSRAMCNT_BIT3 BIT(3)
+#define BOOTLOAD_BYPASS_MODE 0x3
+#define SRAM_BYPASS_MODE 0xc
+#define SRAM_EXT_LD_DONE 0x10
+#define SRAM_INIT_DONE 0x20
+
+#define SRAM_CONTROL_SET_BIT \
+ (BOOTLOAD_BYPASS_MODE | SRAM_BYPASS_MODE | \
+ SRAM_EXT_LD_DONE | SRAM_INIT_DONE)
+
+/* CMNCNT1/2 clock settings */
+#define MPPHY_CMNCNT2_CLK_CH(ch) (0x30003 << ((ch) * 4))
+
+/* PXREFCLK register value */
+#define MPPHY_PXREFCLK_VAL 0x35
+
+/* PXTXREQ register value */
+#define MPPHY_PXTXREQ_VAL 0x8
+
+/* Context settings */
+#define MPPHY_CNTXT1_VALUE 0x02010002
+#define MPPHY_CNTXT2_VALUE 0x02020202 /* For channels 1-3 */
+#define MPPHY_CNTXT2_CH0_VALUE 0x02020201 /* Special for channel 0 */
+
+/* struct mpphy_priv - Private data for the MPPHY driver */
+struct mp_phy_priv {
+ struct phy *phy;
+ struct clk_bulk clks;
+ struct reset_ctl_bulk resets;
+ void __iomem *base;
+};
+
+static int mp_phy_init(struct phy *phy)
+{
+ struct mp_phy_priv *priv = dev_get_priv(phy->dev);
+
+ if (phy->id > 3) {
+ printf("Invalid channel ID: %ld\n", phy->id);
+ return -EINVAL;
+ }
+
+ clrsetbits_le32(priv->base + MPPHY_CMNCNT1, MPPHY_CMNCNT1_CH_MASK(phy->id),
+ MPPHY_CMNCNT1_CH_EN(phy->id));
+ setbits_le32(priv->base + MPPHY_PCS0REG5, MPPHY_PCS0REG5_CH(phy->id));
+ setbits_le32(priv->base + MPPHY_PCS0REG1, MPPHY_PCS0REG1_VAL);
+ setbits_le32(priv->base + MPPHY_PXTEST(phy->id), MPPHY_PXTEST_BIT);
+ clrbits_le32(priv->base + MPPHY_PCS0REG5, MPPHY_PCS0REG5_CH(phy->id));
+ clrbits_le32(priv->base + MPPHY_PCS0REG1, MPPHY_PCS0REG1_VAL);
+ clrbits_le32(priv->base + MPPHY_PXTEST(phy->id), MPPHY_PXTEST_BIT);
+
+ /* Set PHY RX/TX reset and SRAM bypass mode */
+ writel(MPPHY_PXRXCNT_RESET_VAL, priv->base + MPPHY_PXRXCNT(phy->id));
+ writel(MPPHY_PXSRAMCNT_BYPASS, priv->base + MPPHY_PXSRAMCNT(phy->id));
+ setbits_le32(priv->base + MPPHY_PXSRAMCNT(phy->id), MPPHY_PXSRAMCNT_BIT3);
+
+ /* Clock supply settings */
+ setbits_le32(priv->base + MPPHY_CMNCNT2, MPPHY_CMNCNT2_CLK_CH(phy->id));
+
+ setbits_le32(priv->base + MPPHY_PXREFCLK(phy->id), MPPHY_PXREFCLK_VAL);
+
+ /* Release PHY RX/TX reset */
+ writel(0x0, priv->base + MPPHY_PXRXCNT(phy->id));
+
+ /* Setting Context Restore Registers and select PHY2/PHY3 protocol */
+ writel(MPPHY_CNTXT1_VALUE, priv->base + MPPHY_PXCNTXT1(phy->id));
+ writel((phy->id == 0) ? MPPHY_CNTXT2_CH0_VALUE : MPPHY_CNTXT2_VALUE,
+ priv->base + MPPHY_PXCNTXT2(phy->id));
+ writel(MPPHY_PXTXREQ_VAL, priv->base + MPPHY_PXTXREQ(phy->id));
+
+ return 0;
+}
+
+static int mp_phy_late_init(struct phy *phy)
+{
+ struct mp_phy_priv *priv = dev_get_priv(phy->dev);
+
+ writel(SRAM_CONTROL_SET_BIT, priv->base + MPPHY_PXSRAMCNT(phy->id));
+
+ return 0;
+}
+
+static int mp_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+ /* Current source code only supports Ethernet */
+ if (mode != PHY_MODE_ETHERNET)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static int mp_phy_of_xlate(struct phy *phy, struct ofnode_phandle_args *args)
+{
+ if (args->args_count > 2)
+ return -EINVAL;
+
+ /* Set channel ID from first argument if available */
+ if (args->args_count)
+ phy->id = args->args[0];
+ else
+ phy->id = 0;
+
+ return 0;
+}
+
+static const struct phy_ops mp_phy_ops = {
+ .init = mp_phy_init,
+ .power_on = mp_phy_late_init,
+ .set_mode = mp_phy_set_mode,
+ .of_xlate = mp_phy_of_xlate,
+};
+
+static int mp_phy_probe(struct udevice *dev)
+{
+ struct mp_phy_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ /* Get base address from device tree */
+ priv->base = dev_read_addr_ptr(dev);
+ if (!priv->base)
+ return -EINVAL;
+
+ ret = clk_get_bulk(dev, &priv->clks);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable_bulk(&priv->clks);
+ if (ret)
+ goto err_clk_enable;
+
+ ret = reset_get_bulk(dev, &priv->resets);
+ if (ret)
+ goto err_reset_get;
+
+ ret = reset_assert_bulk(&priv->resets);
+ if (ret)
+ goto err_reset_assert;
+
+ ret = reset_deassert_bulk(&priv->resets);
+ if (ret)
+ goto err_reset_assert;
+
+ return 0;
+
+err_reset_assert:
+ reset_release_bulk(&priv->resets);
+err_reset_get:
+ clk_disable_bulk(&priv->clks);
+err_clk_enable:
+ clk_release_bulk(&priv->clks);
+ return ret;
+}
+
+static const struct udevice_id mp_phy_ids[] = {
+ { .compatible = "renesas,r8a78000-multi-protocol-phy" },
+ { }
+};
+
+U_BOOT_DRIVER(renesas_mpphy) = {
+ .name = "renesas_mpphy",
+ .id = UCLASS_PHY,
+ .of_match = mp_phy_ids,
+ .probe = mp_phy_probe,
+ .ops = &mp_phy_ops,
+ .priv_auto = sizeof(struct mp_phy_priv),
+};
diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c
index 6e2d4bc2b05..eaf68d18f3a 100644
--- a/drivers/phy/ti/phy-j721e-wiz.c
+++ b/drivers/phy/ti/phy-j721e-wiz.c
@@ -1180,6 +1180,7 @@ static int j721e_wiz_probe(struct udevice *dev)
ofnode node;
struct regmap *regmap;
u32 num_lanes;
+ bool already_configured = false;
node = get_child_by_name(dev, "serdes");
@@ -1243,15 +1244,6 @@ static int j721e_wiz_probe(struct udevice *dev)
goto err_addr_to_resource;
}
- for (i = 0; i < wiz->num_lanes; i++) {
- regmap_field_read(wiz->p_enable[i], &val);
- if (val & (P_ENABLE | P_ENABLE_FORCE)) {
- dev_err(dev, "SERDES already configured\n");
- rc = -EBUSY;
- goto err_addr_to_resource;
- }
- }
-
rc = j721e_wiz_bind_of_clocks(wiz);
if (rc) {
dev_err(dev, "Failed to bind clocks\n");
@@ -1270,10 +1262,21 @@ static int j721e_wiz_probe(struct udevice *dev)
goto err_addr_to_resource;
}
- rc = wiz_init(wiz);
- if (rc) {
- dev_err(dev, "WIZ initialization failed\n");
- goto err_addr_to_resource;
+ for (i = 0; i < wiz->num_lanes; i++) {
+ regmap_field_read(wiz->p_enable[i], &val);
+ if (val & (P_ENABLE | P_ENABLE_FORCE)) {
+ dev_info(dev, "SERDES already configured, skipping wiz initialization\n");
+ already_configured = true;
+ break;
+ }
+ }
+
+ if (!already_configured) {
+ rc = wiz_init(wiz);
+ if (rc) {
+ dev_err(dev, "WIZ initialization failed\n");
+ goto err_addr_to_resource;
+ }
}
return 0;
diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
index babf1bccc96..7dbaf966f93 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.c
+++ b/drivers/pinctrl/meson/pinctrl-meson.c
@@ -117,8 +117,26 @@ int meson_gpio_get(struct udevice *dev, unsigned int offset)
struct meson_pinctrl *priv = dev_get_priv(dev->parent);
unsigned int reg, bit;
int ret;
+ enum gpio_func_t direction;
+ enum meson_reg_type reg_type;
- ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_IN, &reg,
+ direction = meson_gpio_get_direction(dev, offset);
+
+ switch (direction) {
+ case GPIOF_INPUT:
+ reg_type = REG_IN;
+ break;
+
+ case GPIOF_OUTPUT:
+ reg_type = REG_OUT;
+ break;
+
+ default:
+ dev_warn(dev, "Failed to get current direction of Pin %u\n", offset);
+ return -EINVAL;
+ }
+
+ ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, reg_type, &reg,
&bit);
if (ret)
return ret;
diff --git a/drivers/pinctrl/nxp/pinctrl-imx-scmi.c b/drivers/pinctrl/nxp/pinctrl-imx-scmi.c
index aed47be337d..781835c6852 100644
--- a/drivers/pinctrl/nxp/pinctrl-imx-scmi.c
+++ b/drivers/pinctrl/nxp/pinctrl-imx-scmi.c
@@ -16,6 +16,7 @@
#include "pinctrl-imx.h"
#define DAISY_OFFSET_IMX95 0x408
+#define DAISY_OFFSET_IMX94 0x608
/* SCMI pin control types */
#define PINCTRL_TYPE_MUX 192
@@ -133,6 +134,8 @@ static int imx_scmi_pinctrl_probe(struct udevice *dev)
if (IS_ENABLED(CONFIG_IMX95))
priv->daisy_offset = DAISY_OFFSET_IMX95;
+ else if (IS_ENABLED(CONFIG_IMX94))
+ priv->daisy_offset = DAISY_OFFSET_IMX94;
else
return -EINVAL;
@@ -141,7 +144,7 @@ static int imx_scmi_pinctrl_probe(struct udevice *dev)
static int imx_scmi_pinctrl_bind(struct udevice *dev)
{
- if (IS_ENABLED(CONFIG_IMX95))
+ if (IS_ENABLED(CONFIG_IMX95) || IS_ENABLED(CONFIG_IMX94))
return 0;
return -ENODEV;
diff --git a/drivers/pinctrl/pinctrl-zynqmp.c b/drivers/pinctrl/pinctrl-zynqmp.c
index 665b76a7d4d..7c11ac4c8b8 100644
--- a/drivers/pinctrl/pinctrl-zynqmp.c
+++ b/drivers/pinctrl/pinctrl-zynqmp.c
@@ -127,7 +127,8 @@ static int zynqmp_pm_query_data(enum pm_query_id qid, u32 arg1, u32 arg2, u32 *o
int ret;
u32 ret_payload[PAYLOAD_ARG_CNT];
- ret = xilinx_pm_request(PM_QUERY_DATA, qid, arg1, arg2, 0, ret_payload);
+ ret = xilinx_pm_request(PM_QUERY_DATA, qid, arg1, arg2, 0, 0,
+ 0, ret_payload);
if (ret)
return ret;
@@ -142,7 +143,8 @@ static int zynqmp_pm_pinctrl_get_config(const u32 pin, const u32 param, u32 *val
u32 ret_payload[PAYLOAD_ARG_CNT];
/* Get config for the pin */
- ret = xilinx_pm_request(PM_PINCTRL_CONFIG_PARAM_GET, pin, param, 0, 0, ret_payload);
+ ret = xilinx_pm_request(PM_PINCTRL_CONFIG_PARAM_GET, pin, param, 0, 0, 0,
+ 0, ret_payload);
if (ret) {
printf("%s failed\n", __func__);
return ret;
@@ -164,14 +166,15 @@ static int zynqmp_pm_pinctrl_set_config(const u32 pin, const u32 param, u32 valu
}
/* Request the pin first */
- ret = xilinx_pm_request(PM_PINCTRL_REQUEST, pin, 0, 0, 0, NULL);
+ ret = xilinx_pm_request(PM_PINCTRL_REQUEST, pin, 0, 0, 0, 0, 0, NULL);
if (ret) {
printf("%s: pin request failed\n", __func__);
return ret;
}
/* Set config for the pin */
- ret = xilinx_pm_request(PM_PINCTRL_CONFIG_PARAM_SET, pin, param, value, 0, NULL);
+ ret = xilinx_pm_request(PM_PINCTRL_CONFIG_PARAM_SET, pin, param, value,
+ 0, 0, 0, NULL);
if (ret) {
printf("%s failed\n", __func__);
return ret;
@@ -186,7 +189,7 @@ static int zynqmp_pinctrl_get_function_groups(u32 fid, u32 index, u16 *groups)
u32 ret_payload[PAYLOAD_ARG_CNT];
ret = xilinx_pm_request(PM_QUERY_DATA, PM_QID_PINCTRL_GET_FUNCTION_GROUPS,
- fid, index, 0, ret_payload);
+ fid, index, 0, 0, 0, ret_payload);
if (ret) {
printf("%s failed\n", __func__);
return ret;
@@ -242,7 +245,7 @@ static int zynqmp_pinctrl_get_pin_groups(u32 pin, u32 index, u16 *groups)
u32 ret_payload[PAYLOAD_ARG_CNT];
ret = xilinx_pm_request(PM_QUERY_DATA, PM_QID_PINCTRL_GET_PIN_GROUPS,
- pin, index, 0, ret_payload);
+ pin, index, 0, 0, 0, ret_payload);
if (ret) {
printf("%s failed to get pin groups\n", __func__);
return ret;
@@ -313,13 +316,13 @@ static int zynqmp_pinctrl_probe(struct udevice *dev)
for (i = 0; i < priv->nfuncs; i++) {
/* Get function name for the function and fill */
xilinx_pm_request(PM_QUERY_DATA, PM_QID_PINCTRL_GET_FUNCTION_NAME,
- i, 0, 0, ret_payload);
+ i, 0, 0, 0, 0, ret_payload);
memcpy((void *)priv->funcs[i].name, ret_payload, MAX_FUNC_NAME_LEN);
/* And fill number of groups available for certain function */
xilinx_pm_request(PM_QUERY_DATA, PM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS,
- i, 0, 0, ret_payload);
+ i, 0, 0, 0, 0, ret_payload);
priv->funcs[i].ngroups = ret_payload[1];
priv->ngroups += priv->funcs[i].ngroups;
@@ -370,7 +373,8 @@ static int zynqmp_pinmux_set(struct udevice *dev, unsigned int selector,
int ret;
/* Request the pin first */
- ret = xilinx_pm_request(PM_PINCTRL_REQUEST, selector, 0, 0, 0, NULL);
+ ret = xilinx_pm_request(PM_PINCTRL_REQUEST, selector, 0, 0, 0, 0,
+ 0, NULL);
if (ret) {
printf("%s: pin request failed\n", __func__);
return ret;
@@ -378,7 +382,7 @@ static int zynqmp_pinmux_set(struct udevice *dev, unsigned int selector,
/* Set the pin function */
ret = xilinx_pm_request(PM_PINCTRL_SET_FUNCTION, selector, func_selector,
- 0, 0, NULL);
+ 0, 0, 0, 0, NULL);
if (ret) {
printf("%s: Failed to set pinmux function\n", __func__);
return ret;
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index 21f81b66099..320aba33347 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -68,6 +68,13 @@ config PINCTRL_QCOM_SC7280
help
Say Y here to enable support for pinctrl on the Snapdragon SC7280 SoC,
+config PINCTRL_QCOM_SDM670
+ bool "Qualcomm SDM670 Pinctrl"
+ select PINCTRL_QCOM
+ help
+ Say Y here to enable support for pinctrl on the Snapdragon SDM670 SoC,
+ as well as the associated GPIO driver.
+
config PINCTRL_QCOM_SDM660
bool "Qualcomm SDM630/660 Pinctrl"
select PINCTRL_QCOM
@@ -89,6 +96,19 @@ config PINCTRL_QCOM_SM6115
Say Y here to enable support for pinctrl on the Snapdragon SM6115 SoC,
as well as the associated GPIO driver.
+config PINCTRL_QCOM_SM6350
+ bool "Qualcomm SM6350 Pinctrl"
+ select PINCTRL_QCOM
+ help
+ Say Y here to enable support for pinctrl on the Snapdragon SM6350 SoC,
+
+config PINCTRL_QCOM_SM7150
+ bool "Qualcomm SM7150 GCC"
+ select PINCTRL_QCOM
+ help
+ Say Y here to enable support for pinctrl on the Snapdragon SM7150 SoC,
+ as well as the associated GPIO driver.
+
config PINCTRL_QCOM_SM8150
bool "Qualcomm SM8150 Pinctrl"
select PINCTRL_QCOM
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index 6cb53838e71..06582ac2068 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -13,8 +13,11 @@ obj-$(CONFIG_PINCTRL_QCOM_QCS404) += pinctrl-qcs404.o
obj-$(CONFIG_PINCTRL_QCOM_SA8775P) += pinctrl-sa8775p.o
obj-$(CONFIG_PINCTRL_QCOM_SC7280) += pinctrl-sc7280.o
obj-$(CONFIG_PINCTRL_QCOM_SDM660) += pinctrl-sdm660.o
+obj-$(CONFIG_PINCTRL_QCOM_SDM670) += pinctrl-sdm670.o
obj-$(CONFIG_PINCTRL_QCOM_SDM845) += pinctrl-sdm845.o
obj-$(CONFIG_PINCTRL_QCOM_SM6115) += pinctrl-sm6115.o
+obj-$(CONFIG_PINCTRL_QCOM_SM6350) += pinctrl-sm6350.o
+obj-$(CONFIG_PINCTRL_QCOM_SM7150) += pinctrl-sm7150.o
obj-$(CONFIG_PINCTRL_QCOM_SM8150) += pinctrl-sm8150.o
obj-$(CONFIG_PINCTRL_QCOM_SM8250) += pinctrl-sm8250.o
obj-$(CONFIG_PINCTRL_QCOM_SM8550) += pinctrl-sm8550.o
diff --git a/drivers/pinctrl/qcom/pinctrl-sc7280.c b/drivers/pinctrl/qcom/pinctrl-sc7280.c
index fe87947fbbf..d62b2cc6fb6 100644
--- a/drivers/pinctrl/qcom/pinctrl-sc7280.c
+++ b/drivers/pinctrl/qcom/pinctrl-sc7280.c
@@ -10,10 +10,6 @@
#include "pinctrl-qcom.h"
-#define WEST 0x00000000
-#define SOUTH 0x00400000
-#define NORTH 0x00800000
-
#define MAX_PIN_NAME_LEN 32
static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
@@ -47,7 +43,7 @@ static const struct pinctrl_function msm_pinctrl_functions[] = {
}
static const struct msm_special_pin_data sc7280_special_pins_data[] = {
- [0] = UFS_RESET("ufs_reset", SOUTH + 0xbe000),
+ [0] = UFS_RESET("ufs_reset", 0xbe000),
[1] = SDC_PINGROUP("sdc1_rclk", 0xb3004, 0, 6),
[2] = SDC_PINGROUP("sdc1_clk", 0xb3000, 13, 6),
[3] = SDC_PINGROUP("sdc1_cmd", 0xb3000, 11, 3),
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm670.c b/drivers/pinctrl/qcom/pinctrl-sdm670.c
new file mode 100644
index 00000000000..830fe7d826f
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-sdm670.c
@@ -0,0 +1,247 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm SDM670 pinctrl
+ *
+ * (C) Copyright 2025 David Wronek <david.wronek@mainlining.org>
+ */
+
+#include <dm.h>
+#include "pinctrl-qcom.h"
+
+#define NORTH 0x00500000
+#define SOUTH 0x00900000
+#define WEST 0x00100000
+
+#define MAX_PIN_NAME_LEN 32
+static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
+
+static const struct pinctrl_function sdm670_pinctrl_functions[] = {
+ { "gpio", 0 },
+ { "blsp_uart2", 3 }, /* gpio 4 and 5, used for debug uart */
+};
+
+static const unsigned int sdm670_pin_offsets[] = {
+ [0] = SOUTH,
+ [1] = SOUTH,
+ [2] = SOUTH,
+ [3] = SOUTH,
+ [4] = NORTH,
+ [5] = NORTH,
+ [6] = NORTH,
+ [7] = NORTH,
+ [8] = WEST,
+ [9] = WEST,
+ [10] = NORTH,
+ [11] = NORTH,
+ [12] = SOUTH,
+ [13] = WEST,
+ [14] = WEST,
+ [15] = WEST,
+ [16] = WEST,
+ [17] = WEST,
+ [18] = WEST,
+ [19] = WEST,
+ [20] = WEST,
+ [21] = WEST,
+ [22] = WEST,
+ [23] = WEST,
+ [24] = WEST,
+ [25] = WEST,
+ [26] = WEST,
+ [27] = WEST,
+ [28] = WEST,
+ [29] = WEST,
+ [30] = WEST,
+ [31] = WEST,
+ [32] = WEST,
+ [33] = WEST,
+ [34] = WEST,
+ [35] = NORTH,
+ [36] = NORTH,
+ [37] = NORTH,
+ [38] = NORTH,
+ [39] = NORTH,
+ [40] = NORTH,
+ [41] = SOUTH,
+ [42] = SOUTH,
+ [43] = SOUTH,
+ [44] = SOUTH,
+ [45] = SOUTH,
+ [46] = SOUTH,
+ [47] = SOUTH,
+ [48] = SOUTH,
+ [49] = NORTH,
+ [50] = NORTH,
+ [51] = NORTH,
+ [52] = NORTH,
+ [53] = NORTH,
+ [54] = NORTH,
+ [55] = NORTH,
+ [56] = NORTH,
+ [57] = NORTH,
+ [65] = NORTH,
+ [66] = NORTH,
+ [67] = NORTH,
+ [68] = NORTH,
+ [75] = NORTH,
+ [76] = NORTH,
+ [77] = NORTH,
+ [78] = NORTH,
+ [79] = NORTH,
+ [80] = NORTH,
+ [81] = NORTH,
+ [82] = NORTH,
+ [83] = NORTH,
+ [84] = NORTH,
+ [85] = SOUTH,
+ [86] = SOUTH,
+ [87] = SOUTH,
+ [88] = SOUTH,
+ [89] = SOUTH,
+ [90] = SOUTH,
+ [91] = SOUTH,
+ [92] = SOUTH,
+ [93] = SOUTH,
+ [94] = SOUTH,
+ [95] = SOUTH,
+ [96] = SOUTH,
+ [97] = WEST,
+ [98] = WEST,
+ [99] = NORTH,
+ [100] = WEST,
+ [101] = WEST,
+ [102] = WEST,
+ [103] = WEST,
+ [105] = NORTH,
+ [106] = NORTH,
+ [107] = NORTH,
+ [108] = NORTH,
+ [109] = NORTH,
+ [110] = NORTH,
+ [111] = NORTH,
+ [112] = NORTH,
+ [113] = NORTH,
+ [114] = WEST,
+ [115] = WEST,
+ [116] = SOUTH,
+ [117] = NORTH,
+ [118] = NORTH,
+ [119] = NORTH,
+ [120] = NORTH,
+ [121] = NORTH,
+ [122] = NORTH,
+ [123] = NORTH,
+ [124] = NORTH,
+ [125] = NORTH,
+ [126] = NORTH,
+ [127] = WEST,
+ [128] = WEST,
+ [129] = WEST,
+ [130] = WEST,
+ [131] = WEST,
+ [132] = WEST,
+ [133] = NORTH,
+ [134] = NORTH,
+ [135] = WEST,
+ [136] = WEST,
+ [137] = WEST,
+ [138] = WEST,
+ [139] = WEST,
+ [140] = WEST,
+ [141] = WEST,
+ [142] = WEST,
+ [143] = WEST,
+ [144] = SOUTH,
+ [145] = SOUTH,
+ [146] = WEST,
+ [147] = WEST,
+ [148] = WEST,
+ [149] = WEST,
+};
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+{ \
+ .name = pg_name, \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+}
+
+#define UFS_RESET(pg_name, offset) \
+{ \
+ .name = pg_name, \
+ .ctl_reg = offset, \
+ .io_reg = offset + 0x4, \
+ .pull_bit = 3, \
+ .drv_bit = 0, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = 0, \
+}
+
+static const struct msm_special_pin_data sdm670_special_pins_data[] = {
+ UFS_RESET("ufs_reset", 0x99d000),
+ SDC_QDSD_PINGROUP("sdc1_rclk", NORTH + 0x99000, 15, 0),
+ SDC_QDSD_PINGROUP("sdc1_clk", NORTH + 0x99000, 13, 6),
+ SDC_QDSD_PINGROUP("sdc1_cmd", NORTH + 0x99000, 11, 3),
+ SDC_QDSD_PINGROUP("sdc1_data", NORTH + 0x99000, 9, 0),
+ SDC_QDSD_PINGROUP("sdc2_clk", NORTH + 0x9a000, 14, 6),
+ SDC_QDSD_PINGROUP("sdc2_cmd", NORTH + 0x9a000, 11, 3),
+ SDC_QDSD_PINGROUP("sdc2_data", NORTH + 0x9a000, 9, 0),
+};
+
+static const char *sdm670_get_function_name(struct udevice *dev, unsigned int selector)
+{
+ return sdm670_pinctrl_functions[selector].name;
+}
+
+static const char *sdm670_get_pin_name(struct udevice *dev, unsigned int selector)
+{
+ if (selector >= 150 && selector <= 157)
+ snprintf(pin_name, MAX_PIN_NAME_LEN,
+ sdm670_special_pins_data[selector - 150].name);
+ else
+ snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
+
+ return pin_name;
+}
+
+static int sdm670_get_function_mux(__maybe_unused unsigned int pin, unsigned int selector)
+{
+ if (selector >= 0 && selector < ARRAY_SIZE(sdm670_pinctrl_functions))
+ return sdm670_pinctrl_functions[selector].val;
+ return -EINVAL;
+}
+
+struct msm_pinctrl_data sdm670_data = {
+ .pin_data = {
+ .pin_offsets = sdm670_pin_offsets,
+ .pin_count = ARRAY_SIZE(sdm670_pin_offsets) + ARRAY_SIZE(sdm670_special_pins_data),
+ .special_pins_start = 150,
+ .special_pins_data = sdm670_special_pins_data,
+ },
+ .functions_count = ARRAY_SIZE(sdm670_pinctrl_functions),
+ .get_function_name = sdm670_get_function_name,
+ .get_function_mux = sdm670_get_function_mux,
+ .get_pin_name = sdm670_get_pin_name,
+};
+
+static const struct udevice_id msm_pinctrl_ids[] = {
+ {
+ .compatible = "qcom,sdm670-tlmm",
+ .data = (ulong)&sdm670_data
+ },
+ { /* Sentinel */ }
+};
+
+U_BOOT_DRIVER(pinctrl_ssdm670) = {
+ .name = "pinctrl_sdm670",
+ .id = UCLASS_NOP,
+ .of_match = msm_pinctrl_ids,
+ .ops = &msm_pinctrl_ops,
+ .bind = msm_pinctrl_bind,
+};
diff --git a/drivers/pinctrl/qcom/pinctrl-sm6350.c b/drivers/pinctrl/qcom/pinctrl-sm6350.c
new file mode 100644
index 00000000000..1cbed77b55f
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-sm6350.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm sm6350 pinctrl
+ *
+ * (C) Copyright 2024 Linaro Ltd.
+ * (C) Copyright 2025 Luca Weiss <luca.weiss@fairphone.com>
+ *
+ */
+
+#include <dm.h>
+
+#include "pinctrl-qcom.h"
+
+#define MAX_PIN_NAME_LEN 32
+static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
+
+static const struct pinctrl_function msm_pinctrl_functions[] = {
+ {"qup13_f2", 1},
+ {"gpio", 0},
+};
+
+#define SDC_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = pg_name, \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ }
+
+#define UFS_RESET(pg_name, offset) \
+ { \
+ .name = pg_name, \
+ .ctl_reg = offset, \
+ .io_reg = offset + 0x4, \
+ .pull_bit = 3, \
+ .drv_bit = 0, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = 0, \
+ }
+
+static const struct msm_special_pin_data sm6350_special_pins_data[] = {
+ [0] = UFS_RESET("ufs_reset", 0xae000),
+ [1] = SDC_PINGROUP("sdc1_rclk", 0xa1000, 15, 0),
+ [2] = SDC_PINGROUP("sdc1_clk", 0xa0000, 13, 6),
+ [3] = SDC_PINGROUP("sdc1_cmd", 0xa0000, 11, 3),
+ [4] = SDC_PINGROUP("sdc1_data", 0xa0000, 9, 0),
+ [5] = SDC_PINGROUP("sdc2_clk", 0xa2000, 14, 6),
+ [6] = SDC_PINGROUP("sdc2_cmd", 0xa2000, 11, 3),
+ [7] = SDC_PINGROUP("sdc2_data", 0xa2000, 9, 0),
+};
+
+static const char *sm6350_get_function_name(struct udevice *dev,
+ unsigned int selector)
+{
+ return msm_pinctrl_functions[selector].name;
+}
+
+static const char *sm6350_get_pin_name(struct udevice *dev,
+ unsigned int selector)
+{
+ if (selector >= 156 && selector <= 163)
+ snprintf(pin_name, MAX_PIN_NAME_LEN,
+ sm6350_special_pins_data[selector - 156].name);
+ else
+ snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
+
+ return pin_name;
+}
+
+static int sm6350_get_function_mux(__maybe_unused unsigned int pin,
+ unsigned int selector)
+{
+ return msm_pinctrl_functions[selector].val;
+}
+
+static struct msm_pinctrl_data sm6350_data = {
+ .pin_data = {
+ .pin_count = 164,
+ .special_pins_start = 156,
+ .special_pins_data = sm6350_special_pins_data,
+ },
+ .functions_count = ARRAY_SIZE(msm_pinctrl_functions),
+ .get_function_name = sm6350_get_function_name,
+ .get_function_mux = sm6350_get_function_mux,
+ .get_pin_name = sm6350_get_pin_name,
+};
+
+static const struct udevice_id msm_pinctrl_ids[] = {
+ { .compatible = "qcom,sm6350-tlmm", .data = (ulong)&sm6350_data },
+ { /* Sentinel */ }
+};
+
+U_BOOT_DRIVER(pinctrl_sm6350) = {
+ .name = "pinctrl_sm6350",
+ .id = UCLASS_NOP,
+ .of_match = msm_pinctrl_ids,
+ .ops = &msm_pinctrl_ops,
+ .bind = msm_pinctrl_bind,
+};
diff --git a/drivers/pinctrl/qcom/pinctrl-sm7150.c b/drivers/pinctrl/qcom/pinctrl-sm7150.c
new file mode 100644
index 00000000000..435ba39b1db
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-sm7150.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Pinctrl driver for Qualcomm SM7150
+ *
+ * (C) Copyright 2025 Danila Tikhonov <danila@jiaxyga.com>
+ * (C) Copyright 2025 Jens Reidel <adrian@mainlining.org>
+ *
+ * Based on Linux Kernel driver
+ */
+
+#include <dm.h>
+
+#include "pinctrl-qcom.h"
+
+#define WEST 0x00000000
+#define NORTH 0x00400000
+#define SOUTH 0x00800000
+
+#define MAX_PIN_NAME_LEN 32
+static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
+
+static const struct pinctrl_function msm_pinctrl_functions[] = {
+ { "qup12", 1 },
+ { "gpio", 0 },
+ { "sdc2_clk", 0 } /* special pin GPIO124 */
+};
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = pg_name, \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ }
+
+#define UFS_RESET(pg_name, offset) \
+ { \
+ .name = pg_name, \
+ .ctl_reg = offset, \
+ .io_reg = offset + 0x4, \
+ .pull_bit = 3, \
+ .drv_bit = 0, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = 0, \
+ }
+
+static const struct msm_special_pin_data msm_special_pins_data[] = {
+ [0] = UFS_RESET("ufs_reset", 0x9f000),
+ [1] = SDC_QDSD_PINGROUP("sdc1_rclk", WEST + 0x9a000, 15, 0),
+ [2] = SDC_QDSD_PINGROUP("sdc1_clk", WEST + 0x9a000, 13, 6),
+ [3] = SDC_QDSD_PINGROUP("sdc1_cmd", WEST + 0x9a000, 11, 3),
+ [4] = SDC_QDSD_PINGROUP("sdc1_data", WEST + 0x9a000, 9, 0),
+ [5] = SDC_QDSD_PINGROUP("sdc2_clk", SOUTH + 0x98000, 14, 6),
+ [6] = SDC_QDSD_PINGROUP("sdc2_cmd", SOUTH + 0x98000, 11, 3),
+ [7] = SDC_QDSD_PINGROUP("sdc2_data", SOUTH + 0x98000, 9, 0),
+};
+
+static const unsigned int sm7150_pin_offsets[] = {
+ [0] = SOUTH, [1] = SOUTH, [2] = SOUTH, [3] = SOUTH,
+ [4] = NORTH, [5] = NORTH, [6] = NORTH, [7] = NORTH,
+ [8] = NORTH, [9] = NORTH, [10] = NORTH, [11] = NORTH,
+ [12] = SOUTH, [13] = SOUTH, [14] = SOUTH, [15] = SOUTH,
+ [16] = SOUTH, [17] = SOUTH, [18] = SOUTH, [19] = SOUTH,
+ [20] = SOUTH, [21] = SOUTH, [22] = SOUTH, [23] = SOUTH,
+ [24] = SOUTH, [25] = SOUTH, [26] = SOUTH, [27] = SOUTH,
+ [28] = SOUTH, [29] = NORTH, [30] = SOUTH, [31] = WEST,
+ [32] = NORTH, [33] = NORTH, [34] = SOUTH, [35] = SOUTH,
+ [36] = SOUTH, [37] = SOUTH, [38] = SOUTH, [39] = SOUTH,
+ [40] = SOUTH, [41] = SOUTH, [42] = NORTH, [43] = NORTH,
+ [44] = NORTH, [45] = NORTH, [46] = NORTH, [47] = NORTH,
+ [48] = WEST, [49] = WEST, [50] = WEST, [51] = WEST,
+ [52] = WEST, [53] = WEST, [54] = WEST, [55] = WEST,
+ [56] = WEST, [57] = WEST, [58] = WEST, [59] = NORTH,
+ [60] = NORTH, [61] = NORTH, [62] = NORTH, [63] = NORTH,
+ [64] = NORTH, [65] = NORTH, [66] = NORTH, [67] = NORTH,
+ [68] = NORTH, [69] = NORTH, [70] = NORTH, [71] = NORTH,
+ [72] = NORTH, [73] = NORTH, [74] = WEST, [75] = WEST,
+ [76] = WEST, [77] = WEST, [78] = WEST, [79] = WEST,
+ [80] = WEST, [81] = WEST, [82] = WEST, [83] = WEST,
+ [84] = WEST, [85] = WEST, [86] = NORTH, [87] = NORTH,
+ [88] = NORTH, [89] = NORTH, [90] = NORTH, [91] = NORTH,
+ [92] = NORTH, [93] = NORTH, [94] = SOUTH, [95] = WEST,
+ [96] = WEST, [97] = WEST, [98] = WEST, [99] = WEST,
+ [100] = WEST, [101] = NORTH, [102] = NORTH, [103] = NORTH,
+ [104] = WEST, [105] = NORTH, [106] = NORTH, [107] = WEST,
+ [108] = SOUTH, [109] = SOUTH, [110] = NORTH, [111] = NORTH,
+ [112] = NORTH, [113] = NORTH, [114] = NORTH, [115] = NORTH,
+ [116] = NORTH, [117] = NORTH, [118] = NORTH,
+};
+
+static const char *sm7150_get_function_name(struct udevice *dev, unsigned int selector)
+{
+ return msm_pinctrl_functions[selector].name;
+}
+
+static const char *sm7150_get_pin_name(struct udevice *dev,
+ unsigned int selector)
+{
+ if (selector >= 119 && selector <= 126)
+ snprintf(pin_name, MAX_PIN_NAME_LEN,
+ msm_special_pins_data[selector - 119].name);
+ else
+ snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
+
+ return pin_name;
+}
+
+static int sm7150_get_function_mux(__maybe_unused unsigned int pin, unsigned int selector)
+{
+ return msm_pinctrl_functions[selector].val;
+}
+
+static struct msm_pinctrl_data sm7150_data = {
+ .pin_data = {
+ .pin_offsets = sm7150_pin_offsets,
+ .pin_count = 126,
+ .special_pins_start = 119,
+ .special_pins_data = msm_special_pins_data,
+ },
+ .functions_count = ARRAY_SIZE(msm_pinctrl_functions),
+ .get_function_name = sm7150_get_function_name,
+ .get_function_mux = sm7150_get_function_mux,
+ .get_pin_name = sm7150_get_pin_name,
+};
+
+static const struct udevice_id msm_pinctrl_ids[] = {
+ { .compatible = "qcom,sm7150-tlmm", .data = (ulong)&sm7150_data },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(pinctrl_sm7150) = {
+ .name = "pinctrl_sm7150",
+ .id = UCLASS_NOP,
+ .of_match = msm_pinctrl_ids,
+ .ops = &msm_pinctrl_ops,
+ .bind = msm_pinctrl_bind,
+};
diff --git a/drivers/pinctrl/renesas/Kconfig b/drivers/pinctrl/renesas/Kconfig
index 560f7275454..ac40b31dbfa 100644
--- a/drivers/pinctrl/renesas/Kconfig
+++ b/drivers/pinctrl/renesas/Kconfig
@@ -53,28 +53,28 @@ config PINCTRL_PFC_R8A7794
Support pin multiplexing control on Renesas R-Car Gen2 R8A7794 SoCs.
config PINCTRL_PFC_R8A774A1
- bool "Renesas RZ/G2 R8A774A1 pin control driver"
- depends on PINCTRL_PFC
- help
- Support pin multiplexing control on Renesas RZ/G2M R8A774A1 SoCs.
+ bool "Renesas RZ/G2 R8A774A1 pin control driver"
+ depends on PINCTRL_PFC
+ help
+ Support pin multiplexing control on Renesas RZ/G2M R8A774A1 SoCs.
config PINCTRL_PFC_R8A774B1
- bool "Renesas RZ/G2 R8A774B1 pin control driver"
- depends on PINCTRL_PFC
- help
- Support pin multiplexing control on Renesas RZ/G2N R8A774B1 SoCs.
+ bool "Renesas RZ/G2 R8A774B1 pin control driver"
+ depends on PINCTRL_PFC
+ help
+ Support pin multiplexing control on Renesas RZ/G2N R8A774B1 SoCs.
config PINCTRL_PFC_R8A774C0
- bool "Renesas RZ/G2 R8A774C0 pin control driver"
- depends on PINCTRL_PFC
- help
- Support pin multiplexing control on Renesas RZ/G2E R8A774C0 SoCs.
+ bool "Renesas RZ/G2 R8A774C0 pin control driver"
+ depends on PINCTRL_PFC
+ help
+ Support pin multiplexing control on Renesas RZ/G2E R8A774C0 SoCs.
config PINCTRL_PFC_R8A774E1
- bool "Renesas RZ/G2 R8A774E1 pin control driver"
- depends on PINCTRL_PFC
- help
- Support pin multiplexing control on Renesas RZ/G2H R8A774E1 SoCs.
+ bool "Renesas RZ/G2 R8A774E1 pin control driver"
+ depends on PINCTRL_PFC
+ help
+ Support pin multiplexing control on Renesas RZ/G2H R8A774E1 SoCs.
config PINCTRL_PFC_R8A77951
bool "Renesas R-Car Gen3 R8A7795 pin control driver"
@@ -148,6 +148,12 @@ config PINCTRL_PFC_R8A779H0
help
Support pin multiplexing control on Renesas R-Car Gen4 R8A779H0 SoCs.
+config PINCTRL_PFC_R8A78000
+ bool "Renesas R-Car Gen5 R8A78000 pin control driver"
+ depends on PINCTRL_PFC
+ help
+ Support pin multiplexing control on Renesas R-Car Gen5 R8A78000 SoCs.
+
config PINCTRL_RZA1
bool "Renesas RZ/A1 R7S72100 pin control driver"
depends on CPU_RZA1
diff --git a/drivers/pinctrl/renesas/Makefile b/drivers/pinctrl/renesas/Makefile
index a5810dc0f10..f9ac5eabf09 100644
--- a/drivers/pinctrl/renesas/Makefile
+++ b/drivers/pinctrl/renesas/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_PINCTRL_PFC_R8A779A0) += pfc-r8a779a0.o
obj-$(CONFIG_PINCTRL_PFC_R8A779F0) += pfc-r8a779f0.o
obj-$(CONFIG_PINCTRL_PFC_R8A779G0) += pfc-r8a779g0.o
obj-$(CONFIG_PINCTRL_PFC_R8A779H0) += pfc-r8a779h0.o
+obj-$(CONFIG_PINCTRL_PFC_R8A78000) += pfc-r8a78000.o
obj-$(CONFIG_PINCTRL_RZA1) += pinctrl-rza1.o
obj-$(CONFIG_PINCTRL_RZN1) += pinctrl-rzn1.o
obj-$(CONFIG_PINCTRL_RZG2L) += rzg2l-pfc.o
diff --git a/drivers/pinctrl/renesas/pfc-r8a7790.c b/drivers/pinctrl/renesas/pfc-r8a7790.c
index 4d6ce06cf16..e986c9fd6c1 100644
--- a/drivers/pinctrl/renesas/pfc-r8a7790.c
+++ b/drivers/pinctrl/renesas/pfc-r8a7790.c
@@ -6186,6 +6186,7 @@ static const struct sh_pfc_soc_operations r8a7790_pfc_ops = {
.pin_to_pocctrl = r8a7790_pin_to_pocctrl,
.get_bias = rcar_pinmux_get_bias,
.set_bias = rcar_pinmux_set_bias,
+ .set_drive_strength = rcar_pinconf_set_drive_strength,
};
#ifdef CONFIG_PINCTRL_PFC_R8A7742
diff --git a/drivers/pinctrl/renesas/pfc-r8a7791.c b/drivers/pinctrl/renesas/pfc-r8a7791.c
index c6d761bb378..90dedd02b69 100644
--- a/drivers/pinctrl/renesas/pfc-r8a7791.c
+++ b/drivers/pinctrl/renesas/pfc-r8a7791.c
@@ -6936,6 +6936,7 @@ static const struct sh_pfc_soc_operations r8a7791_pfc_ops = {
.pin_to_pocctrl = r8a7791_pin_to_pocctrl,
.get_bias = rcar_pinmux_get_bias,
.set_bias = rcar_pinmux_set_bias,
+ .set_drive_strength = rcar_pinconf_set_drive_strength,
};
#ifdef CONFIG_PINCTRL_PFC_R8A7743
diff --git a/drivers/pinctrl/renesas/pfc-r8a7792.c b/drivers/pinctrl/renesas/pfc-r8a7792.c
index d2ff1d9d1a6..fa44028724b 100644
--- a/drivers/pinctrl/renesas/pfc-r8a7792.c
+++ b/drivers/pinctrl/renesas/pfc-r8a7792.c
@@ -3145,6 +3145,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
static const struct sh_pfc_soc_operations r8a7792_pfc_ops = {
.get_bias = rcar_pinmux_get_bias,
.set_bias = rcar_pinmux_set_bias,
+ .set_drive_strength = rcar_pinconf_set_drive_strength,
};
const struct sh_pfc_soc_info r8a7792_pinmux_info = {
diff --git a/drivers/pinctrl/renesas/pfc-r8a7794.c b/drivers/pinctrl/renesas/pfc-r8a7794.c
index a1fa1776bae..1ee932f9c2e 100644
--- a/drivers/pinctrl/renesas/pfc-r8a7794.c
+++ b/drivers/pinctrl/renesas/pfc-r8a7794.c
@@ -5887,6 +5887,7 @@ static const struct sh_pfc_soc_operations r8a7794_pfc_ops = {
.pin_to_pocctrl = r8a7794_pin_to_pocctrl,
.get_bias = rcar_pinmux_get_bias,
.set_bias = rcar_pinmux_set_bias,
+ .set_drive_strength = rcar_pinconf_set_drive_strength,
};
#ifdef CONFIG_PINCTRL_PFC_R8A7745
diff --git a/drivers/pinctrl/renesas/pfc-r8a77951.c b/drivers/pinctrl/renesas/pfc-r8a77951.c
index 8ddcbfbbd64..99b90e6df0d 100644
--- a/drivers/pinctrl/renesas/pfc-r8a77951.c
+++ b/drivers/pinctrl/renesas/pfc-r8a77951.c
@@ -6184,6 +6184,7 @@ static const struct sh_pfc_soc_operations r8a77951_pfc_ops = {
.pin_to_pocctrl = r8a77951_pin_to_pocctrl,
.get_bias = rcar_pinmux_get_bias,
.set_bias = rcar_pinmux_set_bias,
+ .set_drive_strength = rcar_pinconf_set_drive_strength,
};
#ifdef CONFIG_PINCTRL_PFC_R8A774E1
diff --git a/drivers/pinctrl/renesas/pfc-r8a7796.c b/drivers/pinctrl/renesas/pfc-r8a7796.c
index 7bc9fb709ea..a587dfb89d4 100644
--- a/drivers/pinctrl/renesas/pfc-r8a7796.c
+++ b/drivers/pinctrl/renesas/pfc-r8a7796.c
@@ -6137,6 +6137,7 @@ static const struct sh_pfc_soc_operations r8a7796_pfc_ops = {
.pin_to_pocctrl = r8a7796_pin_to_pocctrl,
.get_bias = rcar_pinmux_get_bias,
.set_bias = rcar_pinmux_set_bias,
+ .set_drive_strength = rcar_pinconf_set_drive_strength,
};
#ifdef CONFIG_PINCTRL_PFC_R8A774A1
diff --git a/drivers/pinctrl/renesas/pfc-r8a77965.c b/drivers/pinctrl/renesas/pfc-r8a77965.c
index 97fde005de6..9049d762a59 100644
--- a/drivers/pinctrl/renesas/pfc-r8a77965.c
+++ b/drivers/pinctrl/renesas/pfc-r8a77965.c
@@ -6378,6 +6378,7 @@ static const struct sh_pfc_soc_operations r8a77965_pfc_ops = {
.pin_to_pocctrl = r8a77965_pin_to_pocctrl,
.get_bias = rcar_pinmux_get_bias,
.set_bias = rcar_pinmux_set_bias,
+ .set_drive_strength = rcar_pinconf_set_drive_strength,
};
#ifdef CONFIG_PINCTRL_PFC_R8A774B1
diff --git a/drivers/pinctrl/renesas/pfc-r8a77970.c b/drivers/pinctrl/renesas/pfc-r8a77970.c
index 3a0a310c5fe..c4fc6c8e09c 100644
--- a/drivers/pinctrl/renesas/pfc-r8a77970.c
+++ b/drivers/pinctrl/renesas/pfc-r8a77970.c
@@ -2567,6 +2567,7 @@ static const struct sh_pfc_soc_operations r8a77970_pfc_ops = {
.pin_to_pocctrl = r8a77970_pin_to_pocctrl,
.get_bias = rcar_pinmux_get_bias,
.set_bias = rcar_pinmux_set_bias,
+ .set_drive_strength = rcar_pinconf_set_drive_strength,
};
const struct sh_pfc_soc_info r8a77970_pinmux_info = {
diff --git a/drivers/pinctrl/renesas/pfc-r8a77980.c b/drivers/pinctrl/renesas/pfc-r8a77980.c
index 59f4bdde202..8fd7e165bbe 100644
--- a/drivers/pinctrl/renesas/pfc-r8a77980.c
+++ b/drivers/pinctrl/renesas/pfc-r8a77980.c
@@ -3084,6 +3084,7 @@ static const struct sh_pfc_soc_operations r8a77980_pfc_ops = {
.pin_to_pocctrl = r8a77980_pin_to_pocctrl,
.get_bias = rcar_pinmux_get_bias,
.set_bias = rcar_pinmux_set_bias,
+ .set_drive_strength = rcar_pinconf_set_drive_strength,
};
const struct sh_pfc_soc_info r8a77980_pinmux_info = {
diff --git a/drivers/pinctrl/renesas/pfc-r8a77990.c b/drivers/pinctrl/renesas/pfc-r8a77990.c
index 75b7429bc0d..3607a559c6d 100644
--- a/drivers/pinctrl/renesas/pfc-r8a77990.c
+++ b/drivers/pinctrl/renesas/pfc-r8a77990.c
@@ -5336,6 +5336,7 @@ static const struct sh_pfc_soc_operations r8a77990_pfc_ops = {
.pin_to_pocctrl = r8a77990_pin_to_pocctrl,
.get_bias = rcar_pinmux_get_bias,
.set_bias = rcar_pinmux_set_bias,
+ .set_drive_strength = rcar_pinconf_set_drive_strength,
};
#ifdef CONFIG_PINCTRL_PFC_R8A774C0
diff --git a/drivers/pinctrl/renesas/pfc-r8a77995.c b/drivers/pinctrl/renesas/pfc-r8a77995.c
index 6fe2d743418..8f2bda5d6d3 100644
--- a/drivers/pinctrl/renesas/pfc-r8a77995.c
+++ b/drivers/pinctrl/renesas/pfc-r8a77995.c
@@ -3210,6 +3210,7 @@ static const struct sh_pfc_soc_operations r8a77995_pfc_ops = {
.pin_to_pocctrl = r8a77995_pin_to_pocctrl,
.get_bias = r8a77995_pinmux_get_bias,
.set_bias = r8a77995_pinmux_set_bias,
+ .set_drive_strength = rcar_pinconf_set_drive_strength,
};
const struct sh_pfc_soc_info r8a77995_pinmux_info = {
diff --git a/drivers/pinctrl/renesas/pfc-r8a779a0.c b/drivers/pinctrl/renesas/pfc-r8a779a0.c
index 39690bd5d07..82d39a3b366 100644
--- a/drivers/pinctrl/renesas/pfc-r8a779a0.c
+++ b/drivers/pinctrl/renesas/pfc-r8a779a0.c
@@ -4382,6 +4382,7 @@ static const struct sh_pfc_soc_operations r8a779a0_pfc_ops = {
.pin_to_pocctrl = r8a779a0_pin_to_pocctrl,
.get_bias = rcar_pinmux_get_bias,
.set_bias = rcar_pinmux_set_bias,
+ .set_drive_strength = rcar_pinconf_set_drive_strength,
};
const struct sh_pfc_soc_info r8a779a0_pinmux_info = {
diff --git a/drivers/pinctrl/renesas/pfc-r8a779f0.c b/drivers/pinctrl/renesas/pfc-r8a779f0.c
index 2b629135f69..78659eaa187 100644
--- a/drivers/pinctrl/renesas/pfc-r8a779f0.c
+++ b/drivers/pinctrl/renesas/pfc-r8a779f0.c
@@ -2094,6 +2094,7 @@ static const struct sh_pfc_soc_operations r8a779f0_pfc_ops = {
.pin_to_pocctrl = r8a779f0_pin_to_pocctrl,
.get_bias = rcar_pinmux_get_bias,
.set_bias = rcar_pinmux_set_bias,
+ .set_drive_strength = rcar_pinconf_set_drive_strength,
};
const struct sh_pfc_soc_info r8a779f0_pinmux_info = {
diff --git a/drivers/pinctrl/renesas/pfc-r8a779g0.c b/drivers/pinctrl/renesas/pfc-r8a779g0.c
index f411be8b879..c63adedd297 100644
--- a/drivers/pinctrl/renesas/pfc-r8a779g0.c
+++ b/drivers/pinctrl/renesas/pfc-r8a779g0.c
@@ -354,7 +354,7 @@
#define IP1SR2_3_0 FM(TPU0TO0_A) FM(CANFD6_RX) F_(0, 0) FM(TCLK1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP1SR2_7_4 FM(CAN_CLK) FM(FXR_TXENA_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP1SR2_11_8 FM(CANFD0_TX) FM(FXR_TXENB_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP1SR2_15_12 FM(CANFD0_RX) FM(STPWT_EXTFXR) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR2_15_12 FM(CANFD0_RX) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP1SR2_19_16 FM(CANFD2_TX) FM(TPU0TO2_A) F_(0, 0) FM(TCLK3_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP1SR2_23_20 FM(CANFD2_RX) FM(TPU0TO3_A) FM(PWM1_B) FM(TCLK4_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP1SR2_27_24 FM(CANFD3_TX) F_(0, 0) FM(PWM2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
@@ -473,55 +473,55 @@
#define IP0SR6_7_4 FM(AVB1_MAGIC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP0SR6_11_8 FM(AVB1_MDC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP0SR6_15_12 FM(AVB1_PHY_INT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP0SR6_19_16 FM(AVB1_LINK) FM(AVB1_MII_TX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP0SR6_23_20 FM(AVB1_AVTP_MATCH) FM(AVB1_MII_RX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP0SR6_27_24 FM(AVB1_TXC) FM(AVB1_MII_TXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP0SR6_31_28 FM(AVB1_TX_CTL) FM(AVB1_MII_TX_EN) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR6_19_16 FM(AVB1_LINK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR6_23_20 FM(AVB1_AVTP_MATCH) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR6_27_24 FM(AVB1_TXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR6_31_28 FM(AVB1_TX_CTL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
/* IP1SR6 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
-#define IP1SR6_3_0 FM(AVB1_RXC) FM(AVB1_MII_RXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP1SR6_7_4 FM(AVB1_RX_CTL) FM(AVB1_MII_RX_DV) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP1SR6_11_8 FM(AVB1_AVTP_PPS) FM(AVB1_MII_COL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP1SR6_15_12 FM(AVB1_AVTP_CAPTURE) FM(AVB1_MII_CRS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP1SR6_19_16 FM(AVB1_TD1) FM(AVB1_MII_TD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP1SR6_23_20 FM(AVB1_TD0) FM(AVB1_MII_TD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP1SR6_27_24 FM(AVB1_RD1) FM(AVB1_MII_RD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP1SR6_31_28 FM(AVB1_RD0) FM(AVB1_MII_RD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR6_3_0 FM(AVB1_RXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR6_7_4 FM(AVB1_RX_CTL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR6_11_8 FM(AVB1_AVTP_PPS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR6_15_12 FM(AVB1_AVTP_CAPTURE) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR6_19_16 FM(AVB1_TD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR6_23_20 FM(AVB1_TD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR6_27_24 FM(AVB1_RD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR6_31_28 FM(AVB1_RD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
/* IP2SR6 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
-#define IP2SR6_3_0 FM(AVB1_TD2) FM(AVB1_MII_TD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP2SR6_7_4 FM(AVB1_RD2) FM(AVB1_MII_RD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP2SR6_11_8 FM(AVB1_TD3) FM(AVB1_MII_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP2SR6_15_12 FM(AVB1_RD3) FM(AVB1_MII_RD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR6_3_0 FM(AVB1_TD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR6_7_4 FM(AVB1_RD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR6_11_8 FM(AVB1_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR6_15_12 FM(AVB1_RD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP2SR6_19_16 FM(AVB1_TXCREFCLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
/* SR7 */
/* IP0SR7 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
-#define IP0SR7_3_0 FM(AVB0_AVTP_PPS) FM(AVB0_MII_COL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP0SR7_7_4 FM(AVB0_AVTP_CAPTURE) FM(AVB0_MII_CRS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP0SR7_11_8 FM(AVB0_AVTP_MATCH) FM(AVB0_MII_RX_ER) FM(CC5_OSCOUT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP0SR7_15_12 FM(AVB0_TD3) FM(AVB0_MII_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP0SR7_19_16 FM(AVB0_LINK) FM(AVB0_MII_TX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR7_3_0 FM(AVB0_AVTP_PPS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR7_7_4 FM(AVB0_AVTP_CAPTURE) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR7_11_8 FM(AVB0_AVTP_MATCH) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR7_15_12 FM(AVB0_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR7_19_16 FM(AVB0_LINK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP0SR7_23_20 FM(AVB0_PHY_INT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP0SR7_27_24 FM(AVB0_TD2) FM(AVB0_MII_TD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP0SR7_31_28 FM(AVB0_TD1) FM(AVB0_MII_TD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR7_27_24 FM(AVB0_TD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR7_31_28 FM(AVB0_TD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
/* IP1SR7 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
-#define IP1SR7_3_0 FM(AVB0_RD3) FM(AVB0_MII_RD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR7_3_0 FM(AVB0_RD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP1SR7_7_4 FM(AVB0_TXCREFCLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP1SR7_11_8 FM(AVB0_MAGIC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP1SR7_15_12 FM(AVB0_TD0) FM(AVB0_MII_TD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP1SR7_19_16 FM(AVB0_RD2) FM(AVB0_MII_RD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR7_15_12 FM(AVB0_TD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR7_19_16 FM(AVB0_RD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP1SR7_23_20 FM(AVB0_MDC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP1SR7_27_24 FM(AVB0_MDIO) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP1SR7_31_28 FM(AVB0_TXC) FM(AVB0_MII_TXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR7_31_28 FM(AVB0_TXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
/* IP2SR7 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
-#define IP2SR7_3_0 FM(AVB0_TX_CTL) FM(AVB0_MII_TX_EN) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP2SR7_7_4 FM(AVB0_RD1) FM(AVB0_MII_RD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP2SR7_11_8 FM(AVB0_RD0) FM(AVB0_MII_RD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP2SR7_15_12 FM(AVB0_RXC) FM(AVB0_MII_RXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP2SR7_19_16 FM(AVB0_RX_CTL) FM(AVB0_MII_RX_DV) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR7_3_0 FM(AVB0_TX_CTL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR7_7_4 FM(AVB0_RD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR7_11_8 FM(AVB0_RD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR7_15_12 FM(AVB0_RXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP2SR7_19_16 FM(AVB0_RX_CTL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
/* SR8 */
/* IP0SR8 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
@@ -927,7 +927,6 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_GPSR(IP1SR2_11_8, FXR_TXENB_N_B),
PINMUX_IPSR_GPSR(IP1SR2_15_12, CANFD0_RX),
- PINMUX_IPSR_GPSR(IP1SR2_15_12, STPWT_EXTFXR),
PINMUX_IPSR_GPSR(IP1SR2_19_16, CANFD2_TX),
PINMUX_IPSR_GPSR(IP1SR2_19_16, TPU0TO2_A),
@@ -1078,118 +1077,85 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_GPSR(IP0SR6_15_12, AVB1_PHY_INT),
PINMUX_IPSR_GPSR(IP0SR6_19_16, AVB1_LINK),
- PINMUX_IPSR_GPSR(IP0SR6_19_16, AVB1_MII_TX_ER),
PINMUX_IPSR_GPSR(IP0SR6_23_20, AVB1_AVTP_MATCH),
- PINMUX_IPSR_GPSR(IP0SR6_23_20, AVB1_MII_RX_ER),
PINMUX_IPSR_GPSR(IP0SR6_27_24, AVB1_TXC),
- PINMUX_IPSR_GPSR(IP0SR6_27_24, AVB1_MII_TXC),
PINMUX_IPSR_GPSR(IP0SR6_31_28, AVB1_TX_CTL),
- PINMUX_IPSR_GPSR(IP0SR6_31_28, AVB1_MII_TX_EN),
/* IP1SR6 */
PINMUX_IPSR_GPSR(IP1SR6_3_0, AVB1_RXC),
- PINMUX_IPSR_GPSR(IP1SR6_3_0, AVB1_MII_RXC),
PINMUX_IPSR_GPSR(IP1SR6_7_4, AVB1_RX_CTL),
- PINMUX_IPSR_GPSR(IP1SR6_7_4, AVB1_MII_RX_DV),
PINMUX_IPSR_GPSR(IP1SR6_11_8, AVB1_AVTP_PPS),
- PINMUX_IPSR_GPSR(IP1SR6_11_8, AVB1_MII_COL),
PINMUX_IPSR_GPSR(IP1SR6_15_12, AVB1_AVTP_CAPTURE),
- PINMUX_IPSR_GPSR(IP1SR6_15_12, AVB1_MII_CRS),
PINMUX_IPSR_GPSR(IP1SR6_19_16, AVB1_TD1),
- PINMUX_IPSR_GPSR(IP1SR6_19_16, AVB1_MII_TD1),
PINMUX_IPSR_GPSR(IP1SR6_23_20, AVB1_TD0),
- PINMUX_IPSR_GPSR(IP1SR6_23_20, AVB1_MII_TD0),
PINMUX_IPSR_GPSR(IP1SR6_27_24, AVB1_RD1),
- PINMUX_IPSR_GPSR(IP1SR6_27_24, AVB1_MII_RD1),
PINMUX_IPSR_GPSR(IP1SR6_31_28, AVB1_RD0),
- PINMUX_IPSR_GPSR(IP1SR6_31_28, AVB1_MII_RD0),
/* IP2SR6 */
PINMUX_IPSR_GPSR(IP2SR6_3_0, AVB1_TD2),
- PINMUX_IPSR_GPSR(IP2SR6_3_0, AVB1_MII_TD2),
PINMUX_IPSR_GPSR(IP2SR6_7_4, AVB1_RD2),
- PINMUX_IPSR_GPSR(IP2SR6_7_4, AVB1_MII_RD2),
PINMUX_IPSR_GPSR(IP2SR6_11_8, AVB1_TD3),
- PINMUX_IPSR_GPSR(IP2SR6_11_8, AVB1_MII_TD3),
PINMUX_IPSR_GPSR(IP2SR6_15_12, AVB1_RD3),
- PINMUX_IPSR_GPSR(IP2SR6_15_12, AVB1_MII_RD3),
PINMUX_IPSR_GPSR(IP2SR6_19_16, AVB1_TXCREFCLK),
/* IP0SR7 */
PINMUX_IPSR_GPSR(IP0SR7_3_0, AVB0_AVTP_PPS),
- PINMUX_IPSR_GPSR(IP0SR7_3_0, AVB0_MII_COL),
PINMUX_IPSR_GPSR(IP0SR7_7_4, AVB0_AVTP_CAPTURE),
- PINMUX_IPSR_GPSR(IP0SR7_7_4, AVB0_MII_CRS),
PINMUX_IPSR_GPSR(IP0SR7_11_8, AVB0_AVTP_MATCH),
- PINMUX_IPSR_GPSR(IP0SR7_11_8, AVB0_MII_RX_ER),
- PINMUX_IPSR_GPSR(IP0SR7_11_8, CC5_OSCOUT),
PINMUX_IPSR_GPSR(IP0SR7_15_12, AVB0_TD3),
- PINMUX_IPSR_GPSR(IP0SR7_15_12, AVB0_MII_TD3),
PINMUX_IPSR_GPSR(IP0SR7_19_16, AVB0_LINK),
- PINMUX_IPSR_GPSR(IP0SR7_19_16, AVB0_MII_TX_ER),
PINMUX_IPSR_GPSR(IP0SR7_23_20, AVB0_PHY_INT),
PINMUX_IPSR_GPSR(IP0SR7_27_24, AVB0_TD2),
- PINMUX_IPSR_GPSR(IP0SR7_27_24, AVB0_MII_TD2),
PINMUX_IPSR_GPSR(IP0SR7_31_28, AVB0_TD1),
- PINMUX_IPSR_GPSR(IP0SR7_31_28, AVB0_MII_TD1),
/* IP1SR7 */
PINMUX_IPSR_GPSR(IP1SR7_3_0, AVB0_RD3),
- PINMUX_IPSR_GPSR(IP1SR7_3_0, AVB0_MII_RD3),
PINMUX_IPSR_GPSR(IP1SR7_7_4, AVB0_TXCREFCLK),
PINMUX_IPSR_GPSR(IP1SR7_11_8, AVB0_MAGIC),
PINMUX_IPSR_GPSR(IP1SR7_15_12, AVB0_TD0),
- PINMUX_IPSR_GPSR(IP1SR7_15_12, AVB0_MII_TD0),
PINMUX_IPSR_GPSR(IP1SR7_19_16, AVB0_RD2),
- PINMUX_IPSR_GPSR(IP1SR7_19_16, AVB0_MII_RD2),
PINMUX_IPSR_GPSR(IP1SR7_23_20, AVB0_MDC),
PINMUX_IPSR_GPSR(IP1SR7_27_24, AVB0_MDIO),
PINMUX_IPSR_GPSR(IP1SR7_31_28, AVB0_TXC),
- PINMUX_IPSR_GPSR(IP1SR7_31_28, AVB0_MII_TXC),
/* IP2SR7 */
PINMUX_IPSR_GPSR(IP2SR7_3_0, AVB0_TX_CTL),
- PINMUX_IPSR_GPSR(IP2SR7_3_0, AVB0_MII_TX_EN),
PINMUX_IPSR_GPSR(IP2SR7_7_4, AVB0_RD1),
- PINMUX_IPSR_GPSR(IP2SR7_7_4, AVB0_MII_RD1),
PINMUX_IPSR_GPSR(IP2SR7_11_8, AVB0_RD0),
- PINMUX_IPSR_GPSR(IP2SR7_11_8, AVB0_MII_RD0),
PINMUX_IPSR_GPSR(IP2SR7_15_12, AVB0_RXC),
- PINMUX_IPSR_GPSR(IP2SR7_15_12, AVB0_MII_RXC),
PINMUX_IPSR_GPSR(IP2SR7_19_16, AVB0_RX_CTL),
- PINMUX_IPSR_GPSR(IP2SR7_19_16, AVB0_MII_RX_DV),
/* IP0SR8 */
PINMUX_IPSR_MSEL(IP0SR8_3_0, SCL0, SEL_SCL0_0),
@@ -4490,6 +4456,7 @@ static const struct sh_pfc_soc_operations r8a779g0_pin_ops = {
.pin_to_pocctrl = r8a779g0_pin_to_pocctrl,
.get_bias = rcar_pinmux_get_bias,
.set_bias = rcar_pinmux_set_bias,
+ .set_drive_strength = rcar_pinconf_set_drive_strength,
};
const struct sh_pfc_soc_info r8a779g0_pinmux_info = {
diff --git a/drivers/pinctrl/renesas/pfc-r8a779h0.c b/drivers/pinctrl/renesas/pfc-r8a779h0.c
index 87af037a8d3..2c6c901f3a4 100644
--- a/drivers/pinctrl/renesas/pfc-r8a779h0.c
+++ b/drivers/pinctrl/renesas/pfc-r8a779h0.c
@@ -342,7 +342,7 @@
#define IP1SR2_3_0 FM(TPU0TO0_A) F_(0, 0) F_(0, 0) FM(TCLK1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP1SR2_7_4 FM(CAN_CLK) FM(FXR_TXENA_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP1SR2_11_8 FM(CANFD0_TX) FM(FXR_TXENB_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP1SR2_15_12 FM(CANFD0_RX) FM(STPWT_EXTFXR) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP1SR2_15_12 FM(CANFD0_RX) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP1SR2_19_16 FM(CANFD2_TX) FM(TPU0TO2_A) F_(0, 0) FM(TCLK3_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP1SR2_23_20 FM(CANFD2_RX) FM(TPU0TO3_A) FM(PWM1_B) FM(TCLK4_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP1SR2_27_24 FM(CANFD3_TX) F_(0, 0) FM(PWM2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
@@ -481,7 +481,7 @@
/* IP0SR7 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
#define IP0SR7_3_0 FM(AVB0_AVTP_PPS) FM(AVB0_MII_COL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP0SR7_7_4 FM(AVB0_AVTP_CAPTURE) FM(AVB0_MII_CRS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
-#define IP0SR7_11_8 FM(AVB0_AVTP_MATCH) FM(AVB0_MII_RX_ER) FM(CC5_OSCOUT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define IP0SR7_11_8 FM(AVB0_AVTP_MATCH) FM(AVB0_MII_RX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP0SR7_15_12 FM(AVB0_TD3) FM(AVB0_MII_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP0SR7_19_16 FM(AVB0_LINK) FM(AVB0_MII_TX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
#define IP0SR7_23_20 FM(AVB0_PHY_INT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
@@ -868,7 +868,6 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_GPSR(IP1SR2_11_8, FXR_TXENB_N_B),
PINMUX_IPSR_GPSR(IP1SR2_15_12, CANFD0_RX),
- PINMUX_IPSR_GPSR(IP1SR2_15_12, STPWT_EXTFXR),
PINMUX_IPSR_GPSR(IP1SR2_19_16, CANFD2_TX),
PINMUX_IPSR_GPSR(IP1SR2_19_16, TPU0TO2_A),
@@ -1126,7 +1125,6 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_GPSR(IP0SR7_11_8, AVB0_AVTP_MATCH),
PINMUX_IPSR_GPSR(IP0SR7_11_8, AVB0_MII_RX_ER),
- PINMUX_IPSR_GPSR(IP0SR7_11_8, CC5_OSCOUT),
PINMUX_IPSR_GPSR(IP0SR7_15_12, AVB0_TD3),
PINMUX_IPSR_GPSR(IP0SR7_15_12, AVB0_MII_TD3),
@@ -4143,6 +4141,7 @@ static const struct sh_pfc_soc_operations r8a779h0_pin_ops = {
.pin_to_pocctrl = r8a779h0_pin_to_pocctrl,
.get_bias = rcar_pinmux_get_bias,
.set_bias = rcar_pinmux_set_bias,
+ .set_drive_strength = rcar_pinconf_set_drive_strength,
};
const struct sh_pfc_soc_info r8a779h0_pinmux_info = {
diff --git a/drivers/pinctrl/renesas/pfc-r8a78000.c b/drivers/pinctrl/renesas/pfc-r8a78000.c
new file mode 100644
index 00000000000..cb6a18ee229
--- /dev/null
+++ b/drivers/pinctrl/renesas/pfc-r8a78000.c
@@ -0,0 +1,5254 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * R8A78000 processor support - PFC hardware block.
+ *
+ * Copyright (C) 2025 Renesas Electronics Corp.
+ *
+ */
+
+#include <dm.h>
+#include <errno.h>
+#include <bitfield.h>
+#include <dm/pinctrl.h>
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+
+#include "sh_pfc.h"
+
+#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | SH_PFC_PIN_CFG_PULL_UP_DOWN)
+
+#define CPU_ALL_GP(fn, sfx) \
+ PORT_GP_CFG_28(0, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_22(1, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_29(2, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_17(3, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_16(4, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_23(5, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_31(6, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_31(7, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_16(8, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(8, 26, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(8, 27, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(8, 28, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(8, 29, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(8, 30, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_1(8, 31, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_17(9, fn, sfx, CFG_FLAGS), \
+ PORT_GP_CFG_14(10, fn, sfx, CFG_FLAGS)
+
+/*
+ * F_() : just information
+ * FM() : macro for FN_xxx / xxx_MARK
+ */
+
+/* GPSR0 */
+#define GPSR0_27 F_(DP2_HOTPLUG, GRP0_27_FUNC)
+#define GPSR0_26 F_(DP1_HOTPLUG, GRP0_26_FUNC)
+#define GPSR0_25 F_(DP0_HOTPLUG, GRP0_25_FUNC)
+#define GPSR0_24 F_(MSIOF1_SS2_A, GRP0_24_FUNC)
+#define GPSR0_23 F_(MSIOF1_SS1_A, GRP0_23_FUNC)
+#define GPSR0_22 F_(MSIOF1_SYNC_A, GRP0_22_FUNC)
+#define GPSR0_21 F_(MSIOF1_RXD_A, GRP0_21_FUNC)
+#define GPSR0_20 F_(MSIOF1_TXD_A, GRP0_20_FUNC)
+#define GPSR0_19 F_(MSIOF1_SCK_A, GRP0_19_FUNC)
+#define GPSR0_18 F_(MSIOF0_SS2, GRP0_18_FUNC)
+#define GPSR0_17 F_(MSIOF0_SS1, GRP0_17_FUNC)
+#define GPSR0_16 F_(MSIOF0_SYNC, GRP0_16_FUNC)
+#define GPSR0_15 F_(MSIOF0_RXD, GRP0_15_FUNC)
+#define GPSR0_14 F_(MSIOF0_TXD, GRP0_14_FUNC)
+#define GPSR0_13 F_(MSIOF0_SCK, GRP0_13_FUNC)
+#define GPSR0_12 F_(RXDB_EXTFXR_A, GRP0_12_FUNC)
+#define GPSR0_11 F_(FXR_TXENB_N_A, GRP0_11_FUNC)
+#define GPSR0_10 F_(FXR_TXDB_A, GRP0_10_FUNC)
+#define GPSR0_9 F_(RXDA_EXTFXR_A, GRP0_9_FUNC)
+#define GPSR0_8 F_(FXR_TXENA_N_A, GRP0_8_FUNC)
+#define GPSR0_7 F_(FXR_TXDA_A, GRP0_7_FUNC)
+#define GPSR0_6 F_(CLK_EXTFXR_A, GRP0_6_FUNC)
+#define GPSR0_5 F_(FXR_CLKOUT2_A, GRP0_5_FUNC)
+#define GPSR0_4 F_(FXR_CLKOUT1_A, GRP0_4_FUNC)
+#define GPSR0_3 F_(STPWT_EXTFXR_A, GRP0_3_FUNC)
+#define GPSR0_2 F_(GP0_02, GRP0_2_FUNC)
+#define GPSR0_1 F_(GP0_01, GRP0_1_FUNC)
+#define GPSR0_0 F_(GP0_00, GRP0_0_FUNC)
+
+/* GPSR1 */
+#define GPSR1_21 F_(RLIN33TX, GRP1_21_FUNC)
+#define GPSR1_20 F_(RLIN33RX_INTP19, GRP1_20_FUNC)
+#define GPSR1_19 F_(RLIN32TX, GRP1_19_FUNC)
+#define GPSR1_18 F_(RLIN32RX_INTP18, GRP1_18_FUNC)
+#define GPSR1_17 F_(RLIN31TX, GRP1_17_FUNC)
+#define GPSR1_16 F_(RLIN31RX_INTP17, GRP1_16_FUNC)
+#define GPSR1_15 F_(RLIN30TX, GRP1_15_FUNC)
+#define GPSR1_14 F_(RLIN30RX_INTP16, GRP1_14_FUNC)
+#define GPSR1_13 F_(CAN6TX, GRP1_13_FUNC)
+#define GPSR1_12 F_(CAN6RX_INTP6, GRP1_12_FUNC)
+#define GPSR1_11 F_(CAN5TX, GRP1_11_FUNC)
+#define GPSR1_10 F_(CAN5RX_INTP5, GRP1_10_FUNC)
+#define GPSR1_9 F_(CAN4TX, GRP1_9_FUNC)
+#define GPSR1_8 F_(CAN4RX_INTP4, GRP1_8_FUNC)
+#define GPSR1_7 F_(CAN3TX, GRP1_7_FUNC)
+#define GPSR1_6 F_(CAN3RX_INTP3, GRP1_6_FUNC)
+#define GPSR1_5 F_(CAN2TX, GRP1_5_FUNC)
+#define GPSR1_4 F_(CAN2RX_INTP2, GRP1_4_FUNC)
+#define GPSR1_3 F_(CAN1TX, GRP1_3_FUNC)
+#define GPSR1_2 F_(CAN1RX_INTP1, GRP1_2_FUNC)
+#define GPSR1_1 F_(CAN0TX, GRP1_1_FUNC)
+#define GPSR1_0 F_(CAN0RX_INTP0, GRP1_0_FUNC)
+
+/* GPSR2 */
+#define GPSR2_28 F_(INTP34_B, GRP2_28_FUNC)
+#define GPSR2_27 F_(TAUD1O3, GRP2_27_FUNC)
+#define GPSR2_26 F_(TAUD1O2, GRP2_26_FUNC)
+#define GPSR2_25 F_(TAUD1O1, GRP2_25_FUNC)
+#define GPSR2_24 F_(TAUD1O0, GRP2_24_FUNC)
+#define GPSR2_23 F_(EXTCLK0O_B, GRP2_23_FUNC)
+#define GPSR2_22 F_(AVS1, GRP2_22_FUNC)
+#define GPSR2_21 F_(AVS0, GRP2_21_FUNC)
+#define GPSR2_20 F_(SDA0, GRP2_20_FUNC)
+#define GPSR2_19 F_(SCL0, GRP2_19_FUNC)
+#define GPSR2_18 F_(INTP33_B, GRP2_18_FUNC)
+#define GPSR2_17 F_(INTP32_B, GRP2_17_FUNC)
+#define GPSR2_16 F_(CAN_CLK, GRP2_16_FUNC)
+#define GPSR2_15 F_(CAN15TX_B, GRP2_15_FUNC)
+#define GPSR2_14 F_(CAN15RX_INTP15_B, GRP2_14_FUNC)
+#define GPSR2_13 F_(CAN14TX_B, GRP2_13_FUNC)
+#define GPSR2_12 F_(CAN14RX_INTP14_B, GRP2_12_FUNC)
+#define GPSR2_11 F_(CAN13TX_B, GRP2_11_FUNC)
+#define GPSR2_10 F_(CAN13RX_INTP13_B, GRP2_10_FUNC)
+#define GPSR2_9 F_(CAN12TX_B, GRP2_9_FUNC)
+#define GPSR2_8 F_(CAN12RX_INTP12_B, GRP2_8_FUNC)
+#define GPSR2_7 F_(RLIN37TX_B, GRP2_7_FUNC)
+#define GPSR2_6 F_(RLIN37RX_INTP23_B, GRP2_6_FUNC)
+#define GPSR2_5 F_(RLIN36TX_B, GRP2_5_FUNC)
+#define GPSR2_4 F_(RLIN36RX_INTP22_B, GRP2_4_FUNC)
+#define GPSR2_3 F_(RLIN35TX_B, GRP2_3_FUNC)
+#define GPSR2_2 F_(RLIN35RX_INTP21_B, GRP2_2_FUNC)
+#define GPSR2_1 F_(RLIN34TX_B, GRP2_1_FUNC)
+#define GPSR2_0 F_(RLIN34RX_INTP20_B, GRP2_0_FUNC)
+
+/* GPSR3 */
+#define GPSR3_16 F_(ERRORIN_N, GRP3_16_FUNC)
+#define GPSR3_15 F_(ERROROUT_N, GRP3_15_FUNC)
+#define GPSR3_14 F_(QSPI1_SSL, GRP3_14_FUNC)
+#define GPSR3_13 F_(QSPI1_IO3, GRP3_13_FUNC)
+#define GPSR3_12 F_(QSPI1_IO2, GRP3_12_FUNC)
+#define GPSR3_11 F_(QSPI1_MISO_IO1, GRP3_11_FUNC)
+#define GPSR3_10 F_(QSPI1_MOSI_IO0, GRP3_10_FUNC)
+#define GPSR3_9 F_(QSPI1_SPCLK, GRP3_9_FUNC)
+#define GPSR3_8 F_(RPC_INT_N, GRP3_8_FUNC)
+#define GPSR3_7 F_(RPC_WP_N, GRP3_7_FUNC)
+#define GPSR3_6 F_(RPC_RESET_N, GRP3_6_FUNC)
+#define GPSR3_5 F_(QSPI0_SSL, GRP3_5_FUNC)
+#define GPSR3_4 F_(QSPI0_IO3, GRP3_4_FUNC)
+#define GPSR3_3 F_(QSPI0_IO2, GRP3_3_FUNC)
+#define GPSR3_2 F_(QSPI0_MISO_IO1, GRP3_2_FUNC)
+#define GPSR3_1 F_(QSPI0_MOSI_IO0, GRP3_1_FUNC)
+#define GPSR3_0 F_(QSPI0_SPCLK, GRP3_0_FUNC)
+
+/* GPSR4 */
+#define GPSR4_15 F_(PCIE61_CLKREQ_N, GRP4_15_FUNC)
+#define GPSR4_14 F_(PCIE60_CLKREQ_N, GRP4_14_FUNC)
+#define GPSR4_13 F_(ERRORIN_N, GRP4_13_FUNC)
+#define GPSR4_12 F_(SD0_CD, GRP4_12_FUNC)
+#define GPSR4_11 F_(SD0_WP, GRP4_11_FUNC)
+#define GPSR4_10 F_(MMC0_DS, GRP4_10_FUNC)
+#define GPSR4_9 F_(MMC0_D7, GRP4_9_FUNC)
+#define GPSR4_8 F_(MMC0_D6, GRP4_8_FUNC)
+#define GPSR4_7 F_(MMC0_D5, GRP4_7_FUNC)
+#define GPSR4_6 F_(MMC0_D4, GRP4_6_FUNC)
+#define GPSR4_5 F_(MMC0_SD_D3, GRP4_5_FUNC)
+#define GPSR4_4 F_(MMC0_SD_D2, GRP4_4_FUNC)
+#define GPSR4_3 F_(MMC0_SD_D1, GRP4_3_FUNC)
+#define GPSR4_2 F_(MMC0_SD_D0, GRP4_2_FUNC)
+#define GPSR4_1 F_(MMC0_SD_CMD, GRP4_1_FUNC)
+#define GPSR4_0 F_(MMC0_SD_CLK, GRP4_0_FUNC)
+
+/* GPSR5 */
+#define GPSR5_22 F_(TPU0TO3, GRP5_22_FUNC)
+#define GPSR5_21 F_(TPU0TO2, GRP5_21_FUNC)
+#define GPSR5_20 F_(TPU0TO1, GRP5_20_FUNC)
+#define GPSR5_19 F_(TPU0TO0, GRP5_19_FUNC)
+#define GPSR5_18 F_(TCLK4, GRP5_18_FUNC)
+#define GPSR5_17 F_(TCLK3, GRP5_17_FUNC)
+#define GPSR5_16 F_(TCLK2, GRP5_16_FUNC)
+#define GPSR5_15 F_(TCLK1, GRP5_15_FUNC)
+#define GPSR5_14 F_(IRQ3_A, GRP5_14_FUNC)
+#define GPSR5_13 F_(IRQ2_A, GRP5_13_FUNC)
+#define GPSR5_12 F_(IRQ1_A, GRP5_12_FUNC)
+#define GPSR5_11 F_(IRQ0_A, GRP5_11_FUNC)
+#define GPSR5_10 F_(HSCK1, GRP5_10_FUNC)
+#define GPSR5_9 F_(HCTS1_N, GRP5_9_FUNC)
+#define GPSR5_8 F_(HRTS1_N, GRP5_8_FUNC)
+#define GPSR5_7 F_(HRX1, GRP5_7_FUNC)
+#define GPSR5_6 F_(HTX1, GRP5_6_FUNC)
+#define GPSR5_5 F_(SCIF_CLK, GRP5_5_FUNC)
+#define GPSR5_4 F_(HSCK0, GRP5_4_FUNC)
+#define GPSR5_3 F_(HCTS0_N, GRP5_3_FUNC)
+#define GPSR5_2 F_(HRTS0_N, GRP5_2_FUNC)
+#define GPSR5_1 F_(HRX0, GRP5_1_FUNC)
+#define GPSR5_0 F_(HTX0, GRP5_0_FUNC)
+
+/* GPSR6 */
+#define GPSR6_30 F_(AUDIO1_CLKOUT1, GRP6_30_FUNC)
+#define GPSR6_29 F_(AUDIO1_CLKOUT0, GRP6_29_FUNC)
+#define GPSR6_28 F_(SSI2_SD, GRP6_28_FUNC)
+#define GPSR6_27 F_(SSI2_WS, GRP6_27_FUNC)
+#define GPSR6_26 F_(SSI2_SCK, GRP6_26_FUNC)
+#define GPSR6_25 F_(AUDIO0_CLKOUT3, GRP6_25_FUNC)
+#define GPSR6_24 F_(AUDIO0_CLKOUT2, GRP6_24_FUNC)
+#define GPSR6_23 F_(SSI1_SD, GRP6_23_FUNC)
+#define GPSR6_22 F_(SSI1_WS, GRP6_22_FUNC)
+#define GPSR6_21 F_(SSI1_SCK, GRP6_21_FUNC)
+#define GPSR6_20 F_(AUDIO0_CLKOUT1, GRP6_20_FUNC)
+#define GPSR6_19 F_(AUDIO0_CLKOUT0, GRP6_19_FUNC)
+#define GPSR6_18 F_(SSI0_SD, GRP6_18_FUNC)
+#define GPSR6_17 F_(SSI0_WS, GRP6_17_FUNC)
+#define GPSR6_16 F_(SSI0_SCK, GRP6_16_FUNC)
+#define GPSR6_15 F_(MSIOF4_SS2_B, GRP6_15_FUNC)
+#define GPSR6_14 F_(MSIOF4_SS1_B, GRP6_14_FUNC)
+#define GPSR6_13 F_(MSIOF4_SYNC_B, GRP6_13_FUNC)
+#define GPSR6_12 F_(MSIOF4_RXD_B, GRP6_12_FUNC)
+#define GPSR6_11 F_(MSIOF4_TXD_B, GRP6_11_FUNC)
+#define GPSR6_10 F_(MSIOF4_SCK_B, GRP6_10_FUNC)
+#define GPSR6_9 F_(MSIOF7_SS2_A, GRP6_9_FUNC)
+#define GPSR6_8 F_(MSIOF7_SS1_A, GRP6_8_FUNC)
+#define GPSR6_7 F_(MSIOF7_SYNC_A, GRP6_7_FUNC)
+#define GPSR6_6 F_(MSIOF7_RXD_A, GRP6_6_FUNC)
+#define GPSR6_5 F_(MSIOF7_TXD_A, GRP6_5_FUNC)
+#define GPSR6_4 F_(MSIOF7_SCK_A, GRP6_4_FUNC)
+#define GPSR6_3 F_(RIF6_CLK, GRP6_3_FUNC)
+#define GPSR6_2 F_(RIF6_SYNC, GRP6_2_FUNC)
+#define GPSR6_1 F_(RIF6_D1, GRP6_1_FUNC)
+#define GPSR6_0 F_(RIF6_D0, GRP6_0_FUNC)
+
+/* GPSR7 */
+#define GPSR7_30 F_(MSIOF6_SS2_B, GRP7_30_FUNC)
+#define GPSR7_29 F_(MSIOF6_SS1_B, GRP7_29_FUNC)
+#define GPSR7_28 F_(MSIOF6_SYNC_B, GRP7_28_FUNC)
+#define GPSR7_27 F_(MSIOF6_RXD_B, GRP7_27_FUNC)
+#define GPSR7_26 F_(MSIOF6_TXD_B, GRP7_26_FUNC)
+#define GPSR7_25 F_(MSIOF6_SCK_B, GRP7_25_FUNC)
+#define GPSR7_24 F_(MSIOF5_SS2, GRP7_24_FUNC)
+#define GPSR7_23 F_(MSIOF5_SS1, GRP7_23_FUNC)
+#define GPSR7_22 F_(MSIOF5_SYNC, GRP7_22_FUNC)
+#define GPSR7_21 F_(MSIOF5_RXD, GRP7_21_FUNC)
+#define GPSR7_20 F_(MSIOF5_TXD, GRP7_20_FUNC)
+#define GPSR7_19 F_(GP07_19, GRP7_19_FUNC)
+#define GPSR7_18 F_(GP07_18, GRP7_18_FUNC)
+#define GPSR7_17 F_(MSIOF5_SCK, GRP7_17_FUNC)
+#define GPSR7_16 F_(AUDIO_CLKC_A, GRP7_16_FUNC)
+#define GPSR7_15 F_(SSI6_SD, GRP7_15_FUNC)
+#define GPSR7_14 F_(SSI6_WS, GRP7_14_FUNC)
+#define GPSR7_13 F_(SSI6_SCK, GRP7_13_FUNC)
+#define GPSR7_12 F_(AUDIO_CLKB_A, GRP7_12_FUNC)
+#define GPSR7_11 F_(SSI5_SD, GRP7_11_FUNC)
+#define GPSR7_10 F_(SSI5_WS, GRP7_10_FUNC)
+#define GPSR7_9 F_(SSI5_SCK, GRP7_9_FUNC)
+#define GPSR7_8 F_(AUDIO_CLKA_A, GRP7_8_FUNC)
+#define GPSR7_7 F_(SSI4_SD, GRP7_7_FUNC)
+#define GPSR7_6 F_(SSI4_WS, GRP7_6_FUNC)
+#define GPSR7_5 F_(SSI4_SCK, GRP7_5_FUNC)
+#define GPSR7_4 F_(AUDIO1_CLKOUT3, GRP7_4_FUNC)
+#define GPSR7_3 F_(AUDIO1_CLKOUT2, GRP7_3_FUNC)
+#define GPSR7_2 F_(SSI3_SD, GRP7_2_FUNC)
+#define GPSR7_1 F_(SSI3_WS, GRP7_1_FUNC)
+#define GPSR7_0 F_(SSI3_SCK, GRP7_0_FUNC)
+
+/* GPSR8 */
+#define GPSR8_31 F_(S3DA2, GRP8_31_FUNC)
+#define GPSR8_30 F_(S3CL2, GRP8_30_FUNC)
+#define GPSR8_29 F_(S3DA1, GRP8_29_FUNC)
+#define GPSR8_28 F_(S3CL1, GRP8_28_FUNC)
+#define GPSR8_27 F_(S3DA0, GRP8_27_FUNC)
+#define GPSR8_26 F_(S3CL0, GRP8_26_FUNC)
+#define GPSR8_15 F_(SDA8, GRP8_15_FUNC)
+#define GPSR8_14 F_(SCL8, GRP8_14_FUNC)
+#define GPSR8_13 F_(SDA7, GRP8_13_FUNC)
+#define GPSR8_12 F_(SCL7, GRP8_12_FUNC)
+#define GPSR8_11 F_(SDA6, GRP8_11_FUNC)
+#define GPSR8_10 F_(SCL6, GRP8_10_FUNC)
+#define GPSR8_9 F_(SDA5, GRP8_9_FUNC)
+#define GPSR8_8 F_(SCL5, GRP8_8_FUNC)
+#define GPSR8_7 F_(SDA4, GRP8_7_FUNC)
+#define GPSR8_6 F_(SCL4, GRP8_6_FUNC)
+#define GPSR8_5 F_(SDA3, GRP8_5_FUNC)
+#define GPSR8_4 F_(SCL3, GRP8_4_FUNC)
+#define GPSR8_3 F_(SDA2, GRP8_3_FUNC)
+#define GPSR8_2 F_(SCL2, GRP8_2_FUNC)
+#define GPSR8_1 F_(SDA1, GRP8_1_FUNC)
+#define GPSR8_0 F_(SCL1, GRP8_0_FUNC)
+
+/* GPSR9 */
+#define GPSR9_16 F_(RSW3_MATCH, GRP9_16_FUNC)
+#define GPSR9_15 F_(RSW3_CAPTURE, GRP9_15_FUNC)
+#define GPSR9_14 F_(RSW3_PPS, GRP9_14_FUNC)
+#define GPSR9_13 F_(ETH10G0_PHYINT, GRP9_13_FUNC)
+#define GPSR9_12 F_(ETH10G0_LINK, GRP9_12_FUNC)
+#define GPSR9_11 F_(ETH10G0_MDC, GRP9_11_FUNC)
+#define GPSR9_10 F_(ETH10G0_MDIO, GRP9_10_FUNC)
+#define GPSR9_9 F_(ETH25G0_PHYINT, GRP9_9_FUNC)
+#define GPSR9_8 F_(ETH25G0_LINK, GRP9_8_FUNC)
+#define GPSR9_7 F_(ETH25G0_MDC, GRP9_7_FUNC)
+#define GPSR9_6 F_(ETH25G0_MDIO, GRP9_6_FUNC)
+#define GPSR9_5 F_(ETHES4_MATCH, GRP9_5_FUNC)
+#define GPSR9_4 F_(ETHES4_CAPTURE, GRP9_4_FUNC)
+#define GPSR9_3 F_(ETHES4_PPS, GRP9_3_FUNC)
+#define GPSR9_2 F_(ETHES0_MATCH, GRP9_2_FUNC)
+#define GPSR9_1 F_(ETHES0_CAPTURE, GRP9_1_FUNC)
+#define GPSR9_0 F_(ETHES0_PPS, GRP9_0_FUNC)
+
+/* GPSR10 */
+#define GPSR10_13 F_(PCIE41_CLKREQ_N, GRP10_13_FUNC)
+#define GPSR10_12 F_(PCIE40_CLKREQ_N, GRP10_12_FUNC)
+#define GPSR10_11 F_(USB3_VBUS_VALID, GRP10_11_FUNC)
+#define GPSR10_10 F_(USB3_OVC, GRP10_10_FUNC)
+#define GPSR10_9 F_(USB3_PWEN, GRP10_9_FUNC)
+#define GPSR10_8 F_(USB2_VBUS_VALID, GRP10_8_FUNC)
+#define GPSR10_7 F_(USB2_OVC, GRP10_7_FUNC)
+#define GPSR10_6 F_(USB2_PWEN, GRP10_6_FUNC)
+#define GPSR10_5 F_(USB1_VBUS_VALID, GRP10_5_FUNC)
+#define GPSR10_4 F_(USB1_OVC, GRP10_4_FUNC)
+#define GPSR10_3 F_(USB1_PWEN, GRP10_3_FUNC)
+#define GPSR10_2 F_(USB0_VBUS_VALID, GRP10_2_FUNC)
+#define GPSR10_1 F_(USB0_OVC, GRP10_1_FUNC)
+#define GPSR10_0 F_(USB0_PWEN, GRP10_0_FUNC)
+
+/* Group0 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define GRP0_27_FUNC FM(DP2_HOTPLUG) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_26_FUNC FM(DP1_HOTPLUG) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_25_FUNC FM(DP0_HOTPLUG) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_24_FUNC FM(MSIOF1_SS2_A) FM(TAUD0O13) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_23_FUNC FM(MSIOF1_SS1_A) FM(TAUD0O12) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_22_FUNC FM(MSIOF1_SYNC_A) FM(TAUD0O11) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_21_FUNC FM(MSIOF1_RXD_A) FM(TAUD0O10) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_20_FUNC FM(MSIOF1_TXD_A) FM(TAUD0O9) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_19_FUNC FM(MSIOF1_SCK_A) FM(TAUD0O8) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_18_FUNC FM(MSIOF0_SS2) FM(TAUD0O7) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_17_FUNC FM(MSIOF0_SS1) FM(TAUD0O6) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_16_FUNC FM(MSIOF0_SYNC) FM(TAUD0O5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_15_FUNC FM(MSIOF0_RXD) FM(TAUD0O4) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_14_FUNC FM(MSIOF0_TXD) FM(TAUD0O3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_13_FUNC FM(MSIOF0_SCK) FM(TAUD0O2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_12_FUNC FM(RXDB_EXTFXR_A) FM(CAN11TX) FM(RLIN311TX) FM(RTCA0OUT_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_11_FUNC FM(FXR_TXENB_N_A) FM(CAN11RX_INTP11) FM(RLIN311RX_INTP27) FM(EXTCLK0O_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_10_FUNC FM(FXR_TXDB_A) FM(CAN10TX) FM(RLIN310TX) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_9_FUNC FM(RXDA_EXTFXR_A) FM(CAN10RX_INTP10) FM(RLIN310RX_INTP26) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_8_FUNC FM(FXR_TXENA_N_A) FM(CAN9TX) FM(RLIN39TX) FM(TAUD1O15) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_7_FUNC FM(FXR_TXDA_A) FM(CAN9RX_INTP9) FM(RLIN39RX_INTP25) FM(TAUD1O14) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_6_FUNC FM(CLK_EXTFXR_A) FM(CAN8TX) FM(RLIN38TX) FM(TAUD1O13) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_5_FUNC FM(FXR_CLKOUT2_A) FM(CAN8RX_INTP8) FM(RLIN38RX_INTP24) FM(TAUD1O12) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_4_FUNC FM(FXR_CLKOUT1_A) FM(CAN7TX) FM(RLIN315TX_A) FM(TAUD1O11) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_3_FUNC FM(STPWT_EXTFXR_A) FM(CAN7RX_INTP7) FM(RLIN315RX_INTP31_A) FM(TAUD1O10) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_2_FUNC F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_1_FUNC F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP0_0_FUNC F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* Group1 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define GRP1_21_FUNC FM(RLIN33TX) FM(TAUJ1I3_TAUJ1O3) FM(CAN15TX_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP1_20_FUNC FM(RLIN33RX_INTP19) FM(TAUJ1I2_TAUJ1O2) FM(CAN15RX_INTP15_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP1_19_FUNC FM(RLIN32TX) FM(TAUJ1I1_TAUJ1O1) FM(CAN14TX_A) FM(NMI1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP1_18_FUNC FM(RLIN32RX_INTP18) FM(TAUJ1I0_TAUJ1O0) FM(CAN14RX_INTP14_A) FM(INTP34_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP1_17_FUNC FM(RLIN31TX) FM(TAUJ3I3_TAUJ3O3) FM(CAN13TX_A) FM(INTP33_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP1_16_FUNC FM(RLIN31RX_INTP17) FM(TAUJ3I2_TAUJ3O2) FM(CAN13RX_INTP13_A) FM(INTP32_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP1_15_FUNC FM(RLIN30TX) FM(TAUJ3I1_TAUJ3O1) FM(CAN12TX_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP1_14_FUNC FM(RLIN30RX_INTP16) FM(TAUJ3I0_TAUJ3O0) FM(CAN12RX_INTP12_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP1_13_FUNC FM(CAN6TX) FM(RLIN314TX_A) FM(TAUD1O9) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP1_12_FUNC FM(CAN6RX_INTP6) FM(RLIN314RX_INTP30_A) FM(TAUD1O8) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP1_11_FUNC FM(CAN5TX) FM(RLIN313TX_A) FM(MSIOF3_SS2) FM(RXDB_EXTFXR_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP1_10_FUNC FM(CAN5RX_INTP5) FM(RLIN313RX_INTP29_A) FM(MSIOF3_SS1) FM(FXR_TXENB_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP1_9_FUNC FM(CAN4TX) FM(RLIN312TX_A) FM(MSIOF3_SYNC) FM(FXR_TXDB_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP1_8_FUNC FM(CAN4RX_INTP4) FM(RLIN312RX_INTP28_A) FM(MSIOF3_RXD) FM(RXDA_EXTFXR_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP1_7_FUNC FM(CAN3TX) FM(RLIN37TX_A) FM(MSIOF3_TXD) FM(FXR_TXENA_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP1_6_FUNC FM(CAN3RX_INTP3) FM(RLIN37RX_INTP23_A) FM(MSIOF3_SCK) FM(FXR_TXDA_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP1_5_FUNC FM(CAN2TX) FM(RLIN36TX_A) FM(MSIOF2_SS2) FM(CLK_EXTFXR_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP1_4_FUNC FM(CAN2RX_INTP2) FM(RLIN36RX_INTP22_A) FM(MSIOF2_SS1) FM(FXR_CLKOUT2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP1_3_FUNC FM(CAN1TX) FM(RLIN35TX_A) FM(MSIOF2_SYNC) FM(FXR_CLKOUT1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP1_2_FUNC FM(CAN1RX_INTP1) FM(RLIN35RX_INTP21_A) FM(MSIOF2_RXD) FM(STPWT_EXTFXR_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP1_1_FUNC FM(CAN0TX) FM(RLIN34TX_A) FM(MSIOF2_TXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP1_0_FUNC FM(CAN0RX_INTP0) FM(RLIN34RX_INTP20_A) FM(MSIOF2_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* Group2 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define GRP2_28_FUNC FM(INTP34_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_27_FUNC FM(TAUD1O3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_26_FUNC FM(TAUD1O2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_25_FUNC FM(TAUD1O1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_24_FUNC FM(TAUD1O0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_23_FUNC FM(EXTCLK0O_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_22_FUNC FM(AVS1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_21_FUNC FM(AVS0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_20_FUNC FM(SDA0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_19_FUNC FM(SCL0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_18_FUNC FM(INTP33_B) FM(TAUD0O1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_17_FUNC FM(INTP32_B) FM(TAUD0O0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_16_FUNC FM(CAN_CLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_15_FUNC FM(CAN15TX_B) FM(RLIN315TX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_14_FUNC FM(CAN15RX_B_INTP15) FM(RLIN315RX_INTP31_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_13_FUNC FM(CAN14TX_B) FM(RLIN314TX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_12_FUNC FM(CAN14RX_B_INTP14) FM(RLIN314RX_INTP30_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_11_FUNC FM(CAN13TX_B) FM(RLIN313TX) F_(0, 0) FM(CANXL1_TX) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_10_FUNC FM(CAN13RX_B_INTP13) FM(RLIN313RX_INTP29_B) F_(0, 0) FM(CANXL1_RX) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_9_FUNC FM(CAN12TX_B) FM(RLIN312TX) FM(TAUD1O7) FM(CANXL0_TX) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_8_FUNC FM(CAN12RX_B_INTP12) FM(RLIN312RX_INTP28_B) FM(TAUD1O6) FM(CANXL0_RX) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_7_FUNC FM(RLIN37TX_B) FM(RTCA0OUT_B) FM(TAUD1O5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_6_FUNC FM(RLIN37RX_B_INTP23) F_(0, 0) FM(TAUD1O4) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_5_FUNC FM(RLIN36TX_B) FM(MSIOF1_SS2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_4_FUNC FM(RLIN36RX_B_INTP22) FM(MSIOF1_SS1_B) F_(0, 0) FM(CTIACK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_3_FUNC FM(RLIN35TX_B) FM(MSIOF1_SYN_B) F_(0, 0) FM(CTIREQ) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_2_FUNC FM(RLIN35RX_B_INTP21) FM(MSIOF1_RXD_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_1_FUNC FM(RLIN34TX_B) FM(MSIOF1_TXD_B) FM(TAUD0O15) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP2_0_FUNC FM(RLIN34RX_B_INTP20) FM(MSIOF1_SCK_B) FM(TAUD0O14) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+
+/* Group3 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define GRP3_16_FUNC FM(ERRORIN0_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP3_15_FUNC FM(ERROROUT_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP3_14_FUNC FM(QSPI1_SSL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP3_13_FUNC FM(QSPI1_IO3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP3_12_FUNC FM(QSPI1_IO2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP3_11_FUNC FM(QSPI1_MISO_IO1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP3_10_FUNC FM(QSPI1_MOSI_IO0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP3_9_FUNC FM(QSPI1_SPCLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP3_8_FUNC FM(RPC_INT_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP3_7_FUNC FM(RPC_WP_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP3_6_FUNC FM(RPC_RESET_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP3_5_FUNC FM(QSPI0_SSL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP3_4_FUNC FM(QSPI0_IO3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP3_3_FUNC FM(QSPI0_IO2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP3_2_FUNC FM(QSPI0_MISO_IO1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP3_1_FUNC FM(QSPI0_MOSI_IO0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP3_0_FUNC FM(QSPI0_SPCLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* Group4 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define GRP4_15_FUNC FM(PCIE61_CLKREQ_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP4_14_FUNC FM(PCIE60_CLKREQ_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP4_13_FUNC FM(ERRORIN1_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP4_12_FUNC FM(SD0_CD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP4_11_FUNC FM(SD0_WP) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP4_10_FUNC FM(MMC0_DS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP4_9_FUNC FM(MMC0_D7) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP4_8_FUNC FM(MMC0_D6) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP4_7_FUNC FM(MMC0_D5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP4_6_FUNC FM(MMC0_D4) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP4_5_FUNC FM(MMC0_SD_D3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP4_4_FUNC FM(MMC0_SD_D2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP4_3_FUNC FM(MMC0_SD_D1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP4_2_FUNC FM(MMC0_SD_D0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP4_1_FUNC FM(MMC0_SD_CMD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP4_0_FUNC FM(MMC0_SD_CLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* Group5 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define GRP5_22_FUNC FM(TPU0TO3) FM(SSI9_WS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_21_FUNC FM(TPU0TO2) FM(SSI9_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_20_FUNC FM(TPU0TO1) FM(PWM5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_19_FUNC FM(TPU0TO0) FM(PWM4) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_18_FUNC FM(TCLK4) FM(PWM3) FM(SSI19_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_17_FUNC FM(TCLK3) FM(PWM2) FM(SSI19_WS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_16_FUNC FM(TCLK2) FM(PWM1) FM(SSI19_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_15_FUNC FM(TCLK1) FM(PWM0_A) FM(SSI18_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_14_FUNC FM(IRQ3_A) F_(0, 0) F_(0, 0) FM(RIF7_D1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_13_FUNC FM(IRQ2_A) FM(SSI17_SD) F_(0, 0) FM(RIF7_D0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_12_FUNC FM(IRQ1_A) FM(SSI17_WS) F_(0, 0) FM(RIF7_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_11_FUNC FM(IRQ0_A) FM(SSI17_SCK) F_(0, 0) FM(RIF7_CLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_10_FUNC FM(HSCK1) FM(SCK1) FM(SSI13_SCK) FM(RIF0_CLK_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_9_FUNC FM(HCTS1_N) FM(CTS1_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_8_FUNC FM(HRTS1_N) FM(RTS1_N) FM(RIF0_SYNC_B) FM(SSI16_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_7_FUNC FM(HRX1) FM(RX1) F_(0, 0) FM(SSI16_WS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_6_FUNC FM(HTX1) FM(TX1) F_(0, 0) FM(SSI16_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_5_FUNC FM(SCIF_CLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_4_FUNC FM(HSCK0) FM(SCK0) F_(0, 0) FM(SSI15_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_3_FUNC FM(HCTS0_N) FM(CTS0_N) FM(IRQ1_B) FM(SSI15_WS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_2_FUNC FM(HRTS0_N) FM(RTS0_N) FM(IRQ0_B) FM(SSI15_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_1_FUNC FM(HRX0) FM(RX0) FM(SSI13_SD) FM(RIF0_D1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP5_0_FUNC FM(HTX0) FM(TX0) FM(SSI13_WS) FM(RIF0_D0_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* Group6 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define GRP6_30_FUNC FM(AUDIO1_CLKOUT1) FM(MSIOF7_RXD_B) FM(RIF5_CLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_29_FUNC FM(AUDIO1_CLKOUT0) FM(MSIOF7_TXD_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_28_FUNC FM(SSI2_SD) FM(MSIOF7_SCK_B) FM(RIF5_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_27_FUNC FM(SSI2_WS) F_(0, 0) FM(RIF1_D1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_26_FUNC FM(SSI2_SCK) F_(0, 0) FM(RIF1_D0_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_25_FUNC FM(AUDIO0_CLKOUT3) F_(0, 0) FM(RIF1_CLK_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_24_FUNC FM(AUDIO0_CLKOUT2) F_(0, 0) FM(RIF2_D1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_23_FUNC FM(SSI1_SD) F_(0, 0) FM(HCTS3_N) FM(CTS3_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_22_FUNC FM(SSI1_WS) F_(0, 0) FM(HRTS3_N) FM(RTS3_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_21_FUNC FM(SSI1_SCK) FM(MSIOF4_SS2_A) FM(HSCK3) FM(SCK3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_20_FUNC FM(AUDIO0_CLKOUT1) FM(MSIOF4_SS1_A) FM(RIF2_D0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_19_FUNC FM(AUDIO0_CLKOUT0) FM(MSIOF4_SYNC_A) FM(RIF2_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_18_FUNC FM(SSI0_SD) FM(MSIOF4_RXD_A) FM(HRX3) FM(RX3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_17_FUNC FM(SSI0_WS) FM(MSIOF4_TXD_A) FM(HTX3) FM(TX3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_16_FUNC FM(SSI0_SCK) FM(MSIOF4_SCK_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_15_FUNC FM(MSIOF4_SS2_B) FM(SSI14_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_14_FUNC FM(MSIOF4_SS1_B) FM(SSI12_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_13_FUNC FM(MSIOF4_SYNC_B) FM(SSI12_WS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_12_FUNC FM(MSIOF4_RXD_B) F_(0, 0) FM(AUDIO_CLKC_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_11_FUNC FM(MSIOF4_TXD_B) FM(SSI12_SCK) F_(0, 0) FM(RIF1_SYNC_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_10_FUNC FM(MSIOF4_SCK_B) F_(0, 0) FM(AUDIO_CLKB_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_9_FUNC FM(MSIOF7_SS2_A) FM(SSI14_WS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_8_FUNC FM(MSIOF7_SS1_A) FM(SSI14_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_7_FUNC FM(MSIOF7_SYNC_A) FM(RIF1_D1_B) FM(SSI11_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_6_FUNC FM(MSIOF7_RXD_A) FM(RIF1_D0_B) FM(SSI11_WS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_5_FUNC FM(MSIOF7_TXD_A) FM(RIF1_SYNC_B) FM(SSI11_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_4_FUNC FM(MSIOF7_SCK_A) FM(RIF1_CLK_B) FM(AUDIO_CLKA_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_3_FUNC FM(RIF6_CLK) FM(SSI10_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_2_FUNC FM(RIF6_SYNC) FM(SSI10_WS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_1_FUNC FM(RIF6_D1) FM(SSI10_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP6_0_FUNC FM(RIF6_D0) FM(SSI9_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* Group7 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define GRP7_30_FUNC FM(MSIOF6_SS2_B) FM(HRX2_B) FM(RX4_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_29_FUNC FM(MSIOF6_SS1_B) FM(SSI7_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_28_FUNC FM(MSIOF6_SYNC_B) FM(SSI7_WS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_27_FUNC FM(MSIOF6_RXD_B) FM(SSI7_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_26_FUNC FM(MSIOF6_TXD_B) FM(HTX2_B) FM(TX4_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_25_FUNC FM(MSIOF6_SCK_B) FM(SSI8_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_24_FUNC FM(MSIOF5_SS2) FM(HCTS2_N_B) FM(CTS4_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_23_FUNC FM(MSIOF5_SS1) FM(RIF0_SYNC_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_22_FUNC FM(MSIOF5_SYNC) FM(HRTS2_N_B) FM(RTS4_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_21_FUNC FM(MSIOF5_RXD) FM(RIF0_D1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_20_FUNC FM(MSIOF5_TXD) FM(HSCK2_B) FM(SCK4_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_19_FUNC F_(0, 0) FM(MSIOF6_SS2_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_18_FUNC F_(0, 0) FM(MSIOF6_SS1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_17_FUNC FM(MSIOF5_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_16_FUNC FM(AUDIO_CLKC_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_15_FUNC FM(SSI6_SD) FM(MSIOF6_RXD_A) FM(RIF4_D1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_14_FUNC FM(SSI6_WS) FM(MSIOF6_TXD_A) FM(RIF4_D0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_13_FUNC FM(SSI6_SCK) FM(MSIOF6_SCK_A) FM(RIF4_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_12_FUNC FM(AUDIO_CLKB_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_11_FUNC FM(SSI5_SD) FM(MSIOF6_SYNC_A) FM(RIF4_CLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_10_FUNC FM(SSI5_WS) FM(RIF3_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_9_FUNC FM(SSI5_SCK) FM(RIF3_CLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_8_FUNC FM(AUDIO_CLKA_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_7_FUNC FM(SSI4_SD) FM(RIF3_D1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_6_FUNC FM(SSI4_WS) FM(RIF3_D0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_5_FUNC FM(SSI4_SCK) FM(RIF2_CLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_4_FUNC FM(AUDIO1_CLKOUT3) FM(RIF0_D0_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_3_FUNC FM(AUDIO1_CLKOUT2) FM(RIF0_CLK_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_2_FUNC FM(SSI3_SD) FM(MSIOF7_SS2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_1_FUNC FM(SSI3_WS) FM(MSIOF7_SS1_B) FM(RIF5_D1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP7_0_FUNC FM(SSI3_SCK) FM(MSIOF7_SYNC_B) FM(RIF5_D0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* Group8 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define GRP8_31_FUNC FM(S3DA2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP8_30_FUNC FM(S3CL2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP8_29_FUNC FM(S3DA1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP8_28_FUNC FM(S3CL1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP8_27_FUNC FM(S3DA0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP8_26_FUNC FM(S3CL0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP8_15_FUNC FM(SDA8) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP8_14_FUNC FM(SCL8) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP8_13_FUNC FM(SDA7) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP8_12_FUNC FM(SCL7) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP8_11_FUNC FM(SDA6) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP8_10_FUNC FM(SCL6) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP8_9_FUNC FM(SDA5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP8_8_FUNC FM(SCL5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP8_7_FUNC FM(SDA4) FM(HCTS2_N_A) FM(CTS4_N_A) FM(PWM7_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP8_6_FUNC FM(SCL4) FM(HRTS2_N_A) FM(RTS4_N_A) FM(PWM9_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP8_5_FUNC FM(SDA3) FM(HRX2_A) FM(RX4_A) FM(PWM8_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP8_4_FUNC FM(SCL3) FM(HTX2_A) FM(TX4_A) FM(PWM6_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP8_3_FUNC FM(SDA2) FM(HSCK2_A) FM(SCK4_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP8_2_FUNC FM(SCL2) FM(PWM0_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP8_1_FUNC FM(SDA1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP8_0_FUNC FM(SCL1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* Group9 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define GRP9_16_FUNC FM(RSW3_MATCH) F_(0, 0) F_(0, 0) FM(PWM9_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP9_15_FUNC FM(RSW3_CAPTURE) F_(0, 0) F_(0, 0) FM(PWM8_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP9_14_FUNC FM(RSW3_PPS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP9_13_FUNC FM(ETH10G0_PHYINT) FM(ETH10G1_PHYINT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP9_12_FUNC FM(ETH10G0_LINK) FM(ETH10G1_LINK) F_(0, 0) FM(PWM7_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP9_11_FUNC FM(ETH10G0_MDC) FM(ETH10G1_MDC) F_(0, 0) FM(IRQ3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP9_10_FUNC FM(ETH10G0_MDIO) FM(ETH10G1_MDIO) F_(0, 0) FM(IRQ2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP9_9_FUNC FM(ETH25G0_PHYINT) FM(ETH25G1_PHYINT) FM(ETH25G2_PHYINT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP9_8_FUNC FM(ETH25G0_LINK) FM(ETH25G1_LINK) FM(ETH25G2_LINK) FM(PWM6_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP9_7_FUNC FM(ETH25G0_MDC) FM(ETH25G1_MDC) FM(ETH25G2_MDC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP9_6_FUNC FM(ETH25G0_MDIO) FM(ETH25G1_MDIO) FM(ETH25G2_MDIO) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP9_5_FUNC FM(ETHES4_MATCH) FM(ETHES5_MATCH) FM(ETHES6_MATCH) FM(ETHES7_MATCH) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP9_4_FUNC FM(ETHES4_CAPTURE) FM(ETHES5_CAPTURE) FM(ETHES6_CAPTURE) FM(ETHES7_CAPTURE) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP9_3_FUNC FM(ETHES4_PPS) FM(ETHES5_PPS) FM(ETHES6_PPS) FM(ETHES7_PPS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP9_2_FUNC FM(ETHES0_MATCH) FM(ETHES1_MATCH) FM(ETHES2_MATCH) FM(ETHES3_MATCH) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP9_1_FUNC FM(ETHES0_CAPTURE) FM(ETHES1_CAPTURE) FM(ETHES2_CAPTURE) FM(ETHES3_CAPTURE) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP9_0_FUNC FM(ETHES0_PPS) FM(ETHES1_PPS) FM(ETHES2_PPS) FM(ETHES3_PPS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+/* Group10 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
+#define GRP10_13_FUNC FM(PCIE41_CLKREQ_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP10_12_FUNC FM(PCIE40_CLKREQ_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP10_11_FUNC FM(USB3_VBUS_VALID) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP10_10_FUNC FM(USB3_OVC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP10_9_FUNC FM(USB3_PWEN) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP10_8_FUNC FM(USB2_VBUS_VALID) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP10_7_FUNC FM(USB2_OVC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP10_6_FUNC FM(USB2_PWEN) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP10_5_FUNC FM(USB1_VBUS_VALID) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP10_4_FUNC FM(USB1_OVC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP10_3_FUNC FM(USB1_PWEN) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP10_2_FUNC FM(USB0_VBUS_VALID) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP10_1_FUNC FM(USB0_OVC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+#define GRP10_0_FUNC FM(USB0_PWEN) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0)
+
+#define PINMUX_GPSR \
+/* GPSR0 */ /* GPSR1 */ /* GPSR2 */ /* GPSR3 */ /* GPSR4 */ /* GPSR5 */ /* GPSR6 */ /* GPSR7 */ /* GPSR8 */ /* GPSR9 */ /* GPSR10 */ \
+ GPSR8_31 \
+ GPSR6_30 GPSR7_30 GPSR8_30 \
+ GPSR6_29 GPSR7_29 GPSR8_29 \
+ GPSR2_28 GPSR6_28 GPSR7_28 GPSR8_28 \
+GPSR0_27 GPSR2_27 GPSR6_27 GPSR7_27 GPSR8_27 \
+GPSR0_26 GPSR2_26 GPSR6_26 GPSR7_26 GPSR8_26 \
+GPSR0_25 GPSR2_25 GPSR6_25 GPSR7_25 \
+GPSR0_24 GPSR2_24 GPSR6_24 GPSR7_24 \
+GPSR0_23 GPSR2_23 GPSR6_23 GPSR7_23 \
+GPSR0_22 GPSR2_22 GPSR5_22 GPSR6_22 GPSR7_22 \
+GPSR0_21 GPSR1_21 GPSR2_21 GPSR5_21 GPSR6_21 GPSR7_21 \
+GPSR0_20 GPSR1_20 GPSR2_20 GPSR5_20 GPSR6_20 GPSR7_20 \
+GPSR0_19 GPSR1_19 GPSR2_19 GPSR5_19 GPSR6_19 GPSR7_19 \
+GPSR0_18 GPSR1_18 GPSR2_18 GPSR5_18 GPSR6_18 GPSR7_18 \
+GPSR0_17 GPSR1_17 GPSR2_17 GPSR5_17 GPSR6_17 GPSR7_17 \
+GPSR0_16 GPSR1_16 GPSR2_16 GPSR3_16 GPSR5_16 GPSR6_16 GPSR7_16 GPSR9_16 \
+GPSR0_15 GPSR1_15 GPSR2_15 GPSR3_15 GPSR4_15 GPSR5_15 GPSR6_15 GPSR7_15 GPSR8_15 GPSR9_15 \
+GPSR0_14 GPSR1_14 GPSR2_14 GPSR3_14 GPSR4_14 GPSR5_14 GPSR6_14 GPSR7_14 GPSR8_14 GPSR9_14 \
+GPSR0_13 GPSR1_13 GPSR2_13 GPSR3_13 GPSR4_13 GPSR5_13 GPSR6_13 GPSR7_13 GPSR8_13 GPSR9_13 GPSR4_13 \
+GPSR0_12 GPSR1_12 GPSR2_12 GPSR3_12 GPSR4_12 GPSR5_12 GPSR6_12 GPSR7_12 GPSR8_12 GPSR9_12 GPSR4_12 \
+GPSR0_11 GPSR1_11 GPSR2_11 GPSR3_11 GPSR4_11 GPSR5_11 GPSR6_11 GPSR7_11 GPSR8_11 GPSR9_11 GPSR4_11 \
+GPSR0_10 GPSR1_10 GPSR2_10 GPSR3_10 GPSR4_10 GPSR5_10 GPSR6_10 GPSR7_10 GPSR8_10 GPSR9_10 GPSR4_10 \
+GPSR0_9 GPSR1_9 GPSR2_9 GPSR3_9 GPSR4_9 GPSR5_9 GPSR6_9 GPSR7_9 GPSR8_9 GPSR9_9 GPSR4_9 \
+GPSR0_8 GPSR1_8 GPSR2_8 GPSR3_8 GPSR4_8 GPSR5_8 GPSR6_8 GPSR7_8 GPSR8_8 GPSR9_8 GPSR4_8 \
+GPSR0_7 GPSR1_7 GPSR2_7 GPSR3_7 GPSR4_7 GPSR5_7 GPSR6_7 GPSR7_7 GPSR8_7 GPSR9_7 GPSR4_7 \
+GPSR0_6 GPSR1_6 GPSR2_6 GPSR3_6 GPSR4_6 GPSR5_6 GPSR6_6 GPSR7_6 GPSR8_6 GPSR9_6 GPSR4_6 \
+GPSR0_5 GPSR1_5 GPSR2_5 GPSR3_5 GPSR4_5 GPSR5_5 GPSR6_5 GPSR7_5 GPSR8_5 GPSR9_5 GPSR4_5 \
+GPSR0_4 GPSR1_4 GPSR2_4 GPSR3_4 GPSR4_4 GPSR5_4 GPSR6_4 GPSR7_4 GPSR8_4 GPSR9_4 GPSR4_4 \
+GPSR0_3 GPSR1_3 GPSR2_3 GPSR3_3 GPSR4_3 GPSR5_3 GPSR6_3 GPSR7_3 GPSR8_3 GPSR9_3 GPSR4_3 \
+GPSR0_2 GPSR1_2 GPSR2_2 GPSR3_2 GPSR4_2 GPSR5_2 GPSR6_2 GPSR7_2 GPSR8_2 GPSR9_2 GPSR4_2 \
+GPSR0_1 GPSR1_1 GPSR2_1 GPSR3_1 GPSR4_1 GPSR5_1 GPSR6_1 GPSR7_1 GPSR8_1 GPSR9_1 GPSR4_1 \
+GPSR0_0 GPSR1_0 GPSR2_0 GPSR3_0 GPSR4_0 GPSR5_0 GPSR6_0 GPSR7_0 GPSR8_0 GPSR9_0 GPSR4_0
+
+/* GRP0_FUNC */
+#define GRP0_FUNC \
+FM(GRP0_27_FUNC) GRP0_27_FUNC \
+FM(GRP0_26_FUNC) GRP0_26_FUNC \
+FM(GRP0_25_FUNC) GRP0_25_FUNC \
+FM(GRP0_24_FUNC) GRP0_24_FUNC \
+FM(GRP0_23_FUNC) GRP0_23_FUNC \
+FM(GRP0_22_FUNC) GRP0_22_FUNC \
+FM(GRP0_21_FUNC) GRP0_21_FUNC \
+FM(GRP0_20_FUNC) GRP0_20_FUNC \
+FM(GRP0_19_FUNC) GRP0_19_FUNC \
+FM(GRP0_18_FUNC) GRP0_18_FUNC \
+FM(GRP0_17_FUNC) GRP0_17_FUNC \
+FM(GRP0_16_FUNC) GRP0_16_FUNC \
+FM(GRP0_15_FUNC) GRP0_15_FUNC \
+FM(GRP0_14_FUNC) GRP0_14_FUNC \
+FM(GRP0_13_FUNC) GRP0_13_FUNC \
+FM(GRP0_12_FUNC) GRP0_12_FUNC \
+FM(GRP0_11_FUNC) GRP0_11_FUNC \
+FM(GRP0_10_FUNC) GRP0_10_FUNC \
+FM(GRP0_9_FUNC) GRP0_9_FUNC \
+FM(GRP0_8_FUNC) GRP0_8_FUNC \
+FM(GRP0_7_FUNC) GRP0_7_FUNC \
+FM(GRP0_6_FUNC) GRP0_6_FUNC \
+FM(GRP0_5_FUNC) GRP0_5_FUNC \
+FM(GRP0_4_FUNC) GRP0_4_FUNC \
+FM(GRP0_3_FUNC) GRP0_3_FUNC \
+FM(GRP0_2_FUNC) GRP0_2_FUNC \
+FM(GRP0_1_FUNC) GRP0_1_FUNC \
+FM(GRP0_0_FUNC) GRP0_0_FUNC
+
+/* GRP1_FUNC */
+#define GRP1_FUNC \
+FM(GRP1_21_FUNC) GRP1_21_FUNC \
+FM(GRP1_20_FUNC) GRP1_20_FUNC \
+FM(GRP1_19_FUNC) GRP1_19_FUNC \
+FM(GRP1_18_FUNC) GRP1_18_FUNC \
+FM(GRP1_17_FUNC) GRP1_17_FUNC \
+FM(GRP1_16_FUNC) GRP1_16_FUNC \
+FM(GRP1_15_FUNC) GRP1_15_FUNC \
+FM(GRP1_14_FUNC) GRP1_14_FUNC \
+FM(GRP1_13_FUNC) GRP1_13_FUNC \
+FM(GRP1_12_FUNC) GRP1_12_FUNC \
+FM(GRP1_11_FUNC) GRP1_11_FUNC \
+FM(GRP1_10_FUNC) GRP1_10_FUNC \
+FM(GRP1_9_FUNC) GRP1_9_FUNC \
+FM(GRP1_8_FUNC) GRP1_8_FUNC \
+FM(GRP1_7_FUNC) GRP1_7_FUNC \
+FM(GRP1_6_FUNC) GRP1_6_FUNC \
+FM(GRP1_5_FUNC) GRP1_5_FUNC \
+FM(GRP1_4_FUNC) GRP1_4_FUNC \
+FM(GRP1_3_FUNC) GRP1_3_FUNC \
+FM(GRP1_2_FUNC) GRP1_2_FUNC \
+FM(GRP1_1_FUNC) GRP1_1_FUNC \
+FM(GRP1_0_FUNC) GRP1_0_FUNC
+
+/* GRP2_FUNC */
+#define GRP2_FUNC \
+FM(GRP2_28_FUNC) GRP2_28_FUNC \
+FM(GRP2_27_FUNC) GRP2_27_FUNC \
+FM(GRP2_26_FUNC) GRP2_26_FUNC \
+FM(GRP2_25_FUNC) GRP2_25_FUNC \
+FM(GRP2_24_FUNC) GRP2_24_FUNC \
+FM(GRP2_23_FUNC) GRP2_23_FUNC \
+FM(GRP2_22_FUNC) GRP2_22_FUNC \
+FM(GRP2_21_FUNC) GRP2_21_FUNC \
+FM(GRP2_20_FUNC) GRP2_20_FUNC \
+FM(GRP2_19_FUNC) GRP2_19_FUNC \
+FM(GRP2_18_FUNC) GRP2_18_FUNC \
+FM(GRP2_17_FUNC) GRP2_17_FUNC \
+FM(GRP2_16_FUNC) GRP2_16_FUNC \
+FM(GRP2_15_FUNC) GRP2_15_FUNC \
+FM(GRP2_14_FUNC) GRP2_14_FUNC \
+FM(GRP2_13_FUNC) GRP2_13_FUNC \
+FM(GRP2_12_FUNC) GRP2_12_FUNC \
+FM(GRP2_11_FUNC) GRP2_11_FUNC \
+FM(GRP2_10_FUNC) GRP2_10_FUNC \
+FM(GRP2_9_FUNC) GRP2_9_FUNC \
+FM(GRP2_8_FUNC) GRP2_8_FUNC \
+FM(GRP2_7_FUNC) GRP2_7_FUNC \
+FM(GRP2_6_FUNC) GRP2_6_FUNC \
+FM(GRP2_5_FUNC) GRP2_5_FUNC \
+FM(GRP2_4_FUNC) GRP2_4_FUNC \
+FM(GRP2_3_FUNC) GRP2_3_FUNC \
+FM(GRP2_2_FUNC) GRP2_2_FUNC \
+FM(GRP2_1_FUNC) GRP2_1_FUNC \
+FM(GRP2_0_FUNC) GRP2_0_FUNC
+
+/* GRP3_FUNC */
+#define GRP3_FUNC \
+FM(GRP3_16_FUNC) GRP3_16_FUNC \
+FM(GRP3_15_FUNC) GRP3_15_FUNC \
+FM(GRP3_14_FUNC) GRP3_14_FUNC \
+FM(GRP3_13_FUNC) GRP3_13_FUNC \
+FM(GRP3_12_FUNC) GRP3_12_FUNC \
+FM(GRP3_11_FUNC) GRP3_11_FUNC \
+FM(GRP3_10_FUNC) GRP3_10_FUNC \
+FM(GRP3_9_FUNC) GRP3_9_FUNC \
+FM(GRP3_8_FUNC) GRP3_8_FUNC \
+FM(GRP3_7_FUNC) GRP3_7_FUNC \
+FM(GRP3_6_FUNC) GRP3_6_FUNC \
+FM(GRP3_5_FUNC) GRP3_5_FUNC \
+FM(GRP3_4_FUNC) GRP3_4_FUNC \
+FM(GRP3_3_FUNC) GRP3_3_FUNC \
+FM(GRP3_2_FUNC) GRP3_2_FUNC \
+FM(GRP3_1_FUNC) GRP3_1_FUNC \
+FM(GRP3_0_FUNC) GRP3_0_FUNC
+
+/* GRP4_FUNC */
+#define GRP4_FUNC \
+FM(GRP4_15_FUNC) GRP4_15_FUNC \
+FM(GRP4_14_FUNC) GRP4_14_FUNC \
+FM(GRP4_13_FUNC) GRP4_13_FUNC \
+FM(GRP4_12_FUNC) GRP4_12_FUNC \
+FM(GRP4_11_FUNC) GRP4_11_FUNC \
+FM(GRP4_10_FUNC) GRP4_10_FUNC \
+FM(GRP4_9_FUNC) GRP4_9_FUNC \
+FM(GRP4_8_FUNC) GRP4_8_FUNC \
+FM(GRP4_7_FUNC) GRP4_7_FUNC \
+FM(GRP4_6_FUNC) GRP4_6_FUNC \
+FM(GRP4_5_FUNC) GRP4_5_FUNC \
+FM(GRP4_4_FUNC) GRP4_4_FUNC \
+FM(GRP4_3_FUNC) GRP4_3_FUNC \
+FM(GRP4_2_FUNC) GRP4_2_FUNC \
+FM(GRP4_1_FUNC) GRP4_1_FUNC \
+FM(GRP4_0_FUNC) GRP4_0_FUNC
+
+/* GRP5_FUNC */
+#define GRP5_FUNC \
+FM(GRP5_22_FUNC) GRP5_22_FUNC \
+FM(GRP5_21_FUNC) GRP5_21_FUNC \
+FM(GRP5_20_FUNC) GRP5_20_FUNC \
+FM(GRP5_19_FUNC) GRP5_19_FUNC \
+FM(GRP5_18_FUNC) GRP5_18_FUNC \
+FM(GRP5_17_FUNC) GRP5_17_FUNC \
+FM(GRP5_16_FUNC) GRP5_16_FUNC \
+FM(GRP5_15_FUNC) GRP5_15_FUNC \
+FM(GRP5_14_FUNC) GRP5_14_FUNC \
+FM(GRP5_13_FUNC) GRP5_13_FUNC \
+FM(GRP5_12_FUNC) GRP5_12_FUNC \
+FM(GRP5_11_FUNC) GRP5_11_FUNC \
+FM(GRP5_10_FUNC) GRP5_10_FUNC \
+FM(GRP5_9_FUNC) GRP5_9_FUNC \
+FM(GRP5_8_FUNC) GRP5_8_FUNC \
+FM(GRP5_7_FUNC) GRP5_7_FUNC \
+FM(GRP5_6_FUNC) GRP5_6_FUNC \
+FM(GRP5_5_FUNC) GRP5_5_FUNC \
+FM(GRP5_4_FUNC) GRP5_4_FUNC \
+FM(GRP5_3_FUNC) GRP5_3_FUNC \
+FM(GRP5_2_FUNC) GRP5_2_FUNC \
+FM(GRP5_1_FUNC) GRP5_1_FUNC \
+FM(GRP5_0_FUNC) GRP5_0_FUNC
+
+/* GRP6_FUNC */
+#define GRP6_FUNC \
+FM(GRP6_30_FUNC) GRP6_30_FUNC \
+FM(GRP6_29_FUNC) GRP6_29_FUNC \
+FM(GRP6_28_FUNC) GRP6_28_FUNC \
+FM(GRP6_27_FUNC) GRP6_27_FUNC \
+FM(GRP6_26_FUNC) GRP6_26_FUNC \
+FM(GRP6_25_FUNC) GRP6_25_FUNC \
+FM(GRP6_24_FUNC) GRP6_24_FUNC \
+FM(GRP6_23_FUNC) GRP6_23_FUNC \
+FM(GRP6_22_FUNC) GRP6_22_FUNC \
+FM(GRP6_21_FUNC) GRP6_21_FUNC \
+FM(GRP6_20_FUNC) GRP6_20_FUNC \
+FM(GRP6_19_FUNC) GRP6_19_FUNC \
+FM(GRP6_18_FUNC) GRP6_18_FUNC \
+FM(GRP6_17_FUNC) GRP6_17_FUNC \
+FM(GRP6_16_FUNC) GRP6_16_FUNC \
+FM(GRP6_15_FUNC) GRP6_15_FUNC \
+FM(GRP6_14_FUNC) GRP6_14_FUNC \
+FM(GRP6_13_FUNC) GRP6_13_FUNC \
+FM(GRP6_12_FUNC) GRP6_12_FUNC \
+FM(GRP6_11_FUNC) GRP6_11_FUNC \
+FM(GRP6_10_FUNC) GRP6_10_FUNC \
+FM(GRP6_9_FUNC) GRP6_9_FUNC \
+FM(GRP6_8_FUNC) GRP6_8_FUNC \
+FM(GRP6_7_FUNC) GRP6_7_FUNC \
+FM(GRP6_6_FUNC) GRP6_6_FUNC \
+FM(GRP6_5_FUNC) GRP6_5_FUNC \
+FM(GRP6_4_FUNC) GRP6_4_FUNC \
+FM(GRP6_3_FUNC) GRP6_3_FUNC \
+FM(GRP6_2_FUNC) GRP6_2_FUNC \
+FM(GRP6_1_FUNC) GRP6_1_FUNC \
+FM(GRP6_0_FUNC) GRP6_0_FUNC
+
+/* GRP7_FUNC */
+#define GRP7_FUNC \
+FM(GRP7_30_FUNC) GRP7_30_FUNC \
+FM(GRP7_29_FUNC) GRP7_29_FUNC \
+FM(GRP7_28_FUNC) GRP7_28_FUNC \
+FM(GRP7_27_FUNC) GRP7_27_FUNC \
+FM(GRP7_26_FUNC) GRP7_26_FUNC \
+FM(GRP7_25_FUNC) GRP7_25_FUNC \
+FM(GRP7_24_FUNC) GRP7_24_FUNC \
+FM(GRP7_23_FUNC) GRP7_23_FUNC \
+FM(GRP7_22_FUNC) GRP7_22_FUNC \
+FM(GRP7_21_FUNC) GRP7_21_FUNC \
+FM(GRP7_20_FUNC) GRP7_20_FUNC \
+FM(GRP7_19_FUNC) GRP7_19_FUNC \
+FM(GRP7_18_FUNC) GRP7_18_FUNC \
+FM(GRP7_17_FUNC) GRP7_17_FUNC \
+FM(GRP7_16_FUNC) GRP7_16_FUNC \
+FM(GRP7_15_FUNC) GRP7_15_FUNC \
+FM(GRP7_14_FUNC) GRP7_14_FUNC \
+FM(GRP7_13_FUNC) GRP7_13_FUNC \
+FM(GRP7_12_FUNC) GRP7_12_FUNC \
+FM(GRP7_11_FUNC) GRP7_11_FUNC \
+FM(GRP7_10_FUNC) GRP7_10_FUNC \
+FM(GRP7_9_FUNC) GRP7_9_FUNC \
+FM(GRP7_8_FUNC) GRP7_8_FUNC \
+FM(GRP7_7_FUNC) GRP7_7_FUNC \
+FM(GRP7_6_FUNC) GRP7_6_FUNC \
+FM(GRP7_5_FUNC) GRP7_5_FUNC \
+FM(GRP7_4_FUNC) GRP7_4_FUNC \
+FM(GRP7_3_FUNC) GRP7_3_FUNC \
+FM(GRP7_2_FUNC) GRP7_2_FUNC \
+FM(GRP7_1_FUNC) GRP7_1_FUNC \
+FM(GRP7_0_FUNC) GRP7_0_FUNC
+
+/* GRP8_FUNC */
+#define GRP8_FUNC \
+FM(GRP8_31_FUNC) GRP8_31_FUNC \
+FM(GRP8_30_FUNC) GRP8_30_FUNC \
+FM(GRP8_29_FUNC) GRP8_29_FUNC \
+FM(GRP8_28_FUNC) GRP8_28_FUNC \
+FM(GRP8_27_FUNC) GRP8_27_FUNC \
+FM(GRP8_26_FUNC) GRP8_26_FUNC \
+FM(GRP8_15_FUNC) GRP8_15_FUNC \
+FM(GRP8_14_FUNC) GRP8_14_FUNC \
+FM(GRP8_13_FUNC) GRP8_13_FUNC \
+FM(GRP8_12_FUNC) GRP8_12_FUNC \
+FM(GRP8_11_FUNC) GRP8_11_FUNC \
+FM(GRP8_10_FUNC) GRP8_10_FUNC \
+FM(GRP8_9_FUNC) GRP8_9_FUNC \
+FM(GRP8_8_FUNC) GRP8_8_FUNC \
+FM(GRP8_7_FUNC) GRP8_7_FUNC \
+FM(GRP8_6_FUNC) GRP8_6_FUNC \
+FM(GRP8_5_FUNC) GRP8_5_FUNC \
+FM(GRP8_4_FUNC) GRP8_4_FUNC \
+FM(GRP8_3_FUNC) GRP8_3_FUNC \
+FM(GRP8_2_FUNC) GRP8_2_FUNC \
+FM(GRP8_1_FUNC) GRP8_1_FUNC \
+FM(GRP8_0_FUNC) GRP8_0_FUNC
+
+/* GRP9_FUNC */
+#define GRP9_FUNC \
+FM(GRP9_16_FUNC) GRP9_16_FUNC \
+FM(GRP9_15_FUNC) GRP9_15_FUNC \
+FM(GRP9_14_FUNC) GRP9_14_FUNC \
+FM(GRP9_13_FUNC) GRP9_13_FUNC \
+FM(GRP9_12_FUNC) GRP9_12_FUNC \
+FM(GRP9_11_FUNC) GRP9_11_FUNC \
+FM(GRP9_10_FUNC) GRP9_10_FUNC \
+FM(GRP9_9_FUNC) GRP9_9_FUNC \
+FM(GRP9_8_FUNC) GRP9_8_FUNC \
+FM(GRP9_7_FUNC) GRP9_7_FUNC \
+FM(GRP9_6_FUNC) GRP9_6_FUNC \
+FM(GRP9_5_FUNC) GRP9_5_FUNC \
+FM(GRP9_4_FUNC) GRP9_4_FUNC \
+FM(GRP9_3_FUNC) GRP9_3_FUNC \
+FM(GRP9_2_FUNC) GRP9_2_FUNC \
+FM(GRP9_1_FUNC) GRP9_1_FUNC \
+FM(GRP9_0_FUNC) GRP9_0_FUNC
+
+/* GRP10_FUNC */
+#define GRP10_FUNC \
+FM(GRP10_13_FUNC) GRP10_13_FUNC \
+FM(GRP10_12_FUNC) GRP10_12_FUNC \
+FM(GRP10_11_FUNC) GRP10_11_FUNC \
+FM(GRP10_10_FUNC) GRP10_10_FUNC \
+FM(GRP10_9_FUNC) GRP10_9_FUNC \
+FM(GRP10_8_FUNC) GRP10_8_FUNC \
+FM(GRP10_7_FUNC) GRP10_7_FUNC \
+FM(GRP10_6_FUNC) GRP10_6_FUNC \
+FM(GRP10_5_FUNC) GRP10_5_FUNC \
+FM(GRP10_4_FUNC) GRP10_4_FUNC \
+FM(GRP10_3_FUNC) GRP10_3_FUNC \
+FM(GRP10_2_FUNC) GRP10_2_FUNC \
+FM(GRP10_1_FUNC) GRP10_1_FUNC \
+FM(GRP10_0_FUNC) GRP10_0_FUNC
+
+/* Mux all groups functions */
+#define PINMUX_GRP_FUNC \
+GRP0_FUNC \
+GRP1_FUNC \
+GRP2_FUNC \
+GRP3_FUNC \
+GRP4_FUNC \
+GRP5_FUNC \
+GRP6_FUNC \
+GRP7_FUNC \
+GRP8_FUNC \
+GRP9_FUNC \
+GRP10_FUNC
+
+#define GP_ALTSEL(id, bank, pin) \
+GP##bank##_ALTSEL##id##_##pin##_0, \
+GP##bank##_ALTSEL##id##_##pin##_1,
+
+#define GP_ALTSEL_TYPE(id, bank) \
+ GP_ALTSEL(id, bank, 31) \
+ GP_ALTSEL(id, bank, 30) \
+ GP_ALTSEL(id, bank, 29) \
+ GP_ALTSEL(id, bank, 28) \
+ GP_ALTSEL(id, bank, 27) \
+ GP_ALTSEL(id, bank, 26) \
+ GP_ALTSEL(id, bank, 25) \
+ GP_ALTSEL(id, bank, 24) \
+ GP_ALTSEL(id, bank, 23) \
+ GP_ALTSEL(id, bank, 22) \
+ GP_ALTSEL(id, bank, 21) \
+ GP_ALTSEL(id, bank, 20) \
+ GP_ALTSEL(id, bank, 19) \
+ GP_ALTSEL(id, bank, 18) \
+ GP_ALTSEL(id, bank, 17) \
+ GP_ALTSEL(id, bank, 16) \
+ GP_ALTSEL(id, bank, 15) \
+ GP_ALTSEL(id, bank, 14) \
+ GP_ALTSEL(id, bank, 13) \
+ GP_ALTSEL(id, bank, 12) \
+ GP_ALTSEL(id, bank, 11) \
+ GP_ALTSEL(id, bank, 10) \
+ GP_ALTSEL(id, bank, 9) \
+ GP_ALTSEL(id, bank, 8) \
+ GP_ALTSEL(id, bank, 7) \
+ GP_ALTSEL(id, bank, 6) \
+ GP_ALTSEL(id, bank, 5) \
+ GP_ALTSEL(id, bank, 4) \
+ GP_ALTSEL(id, bank, 3) \
+ GP_ALTSEL(id, bank, 2) \
+ GP_ALTSEL(id, bank, 1) \
+ GP_ALTSEL(id, bank, 0)
+
+#define GP_ALTSEL0(bank) GP_ALTSEL_TYPE(0, bank)
+#define GP_ALTSEL1(bank) GP_ALTSEL_TYPE(1, bank)
+#define GP_ALTSEL2(bank) GP_ALTSEL_TYPE(2, bank)
+#define GP_ALTSEL3(bank) GP_ALTSEL_TYPE(3, bank)
+
+#define PINMUX_ALTSEL \
+GP_ALTSEL0(0) GP_ALTSEL0(1) GP_ALTSEL0(2) GP_ALTSEL0(3) GP_ALTSEL0(4) GP_ALTSEL0(5) GP_ALTSEL0(6) GP_ALTSEL0(7) GP_ALTSEL0(8) GP_ALTSEL0(9) GP_ALTSEL0(10) \
+GP_ALTSEL1(0) GP_ALTSEL1(1) GP_ALTSEL1(2) GP_ALTSEL1(3) GP_ALTSEL1(4) GP_ALTSEL1(5) GP_ALTSEL1(6) GP_ALTSEL1(7) GP_ALTSEL1(8) GP_ALTSEL1(9) GP_ALTSEL1(10) \
+GP_ALTSEL2(0) GP_ALTSEL2(1) GP_ALTSEL2(2) GP_ALTSEL2(3) GP_ALTSEL2(4) GP_ALTSEL2(5) GP_ALTSEL2(6) GP_ALTSEL2(7) GP_ALTSEL2(8) GP_ALTSEL2(9) GP_ALTSEL2(10) \
+GP_ALTSEL3(0) GP_ALTSEL3(1) GP_ALTSEL3(2) GP_ALTSEL3(3) GP_ALTSEL3(4) GP_ALTSEL3(5) GP_ALTSEL3(6) GP_ALTSEL3(7) GP_ALTSEL3(8) GP_ALTSEL3(9) GP_ALTSEL3(10)
+
+/* GP1_MODSEL */ /* 0 */ /* 1 */
+#define GP1_MODSEL_21 FM(SEL_TAUJ13_OUTPUT) FM(SEL_TAUJ13_INPUT)
+#define GP1_MODSEL_20 FM(SEL_TAUJ12_OUTPUT) FM(SEL_TAUJ12_INPUT)
+#define GP1_MODSEL_19 FM(SEL_TAUJ11_OUTPUT) FM(SEL_TAUJ11_INPUT)
+#define GP1_MODSEL_18 FM(SEL_TAUJ10_OUTPUT) FM(SEL_TAUJ10_INPUT)
+#define GP1_MODSEL_17 FM(SEL_TAUJ33_OUTPUT) FM(SEL_TAUJ33_INPUT)
+#define GP1_MODSEL_16 FM(SEL_TAUJ32_OUTPUT) FM(SEL_TAUJ32_INPUT)
+#define GP1_MODSEL_15 FM(SEL_TAUJ31_OUTPUT) FM(SEL_TAUJ31_INPUT)
+#define GP1_MODSEL_14 FM(SEL_TAUJ30_OUTPUT) FM(SEL_TAUJ30_INPUT)
+
+#define GP1_MODSEL \
+GP1_MODSEL_21 \
+GP1_MODSEL_20 \
+GP1_MODSEL_19 \
+GP1_MODSEL_18 \
+GP1_MODSEL_17 \
+GP1_MODSEL_16 \
+GP1_MODSEL_15 \
+GP1_MODSEL_14
+
+/* GP2_MODSEL */ /* 0 */ /* 1 */
+#define GP2_MODSEL_20 FM(SEL_SDA0_0) FM(SEL_SDA0_1)
+#define GP2_MODSEL_19 FM(SEL_SCL0_0) FM(SEL_SCL0_1)
+
+#define GP2_MODSEL \
+GP2_MODSEL_20 \
+GP2_MODSEL_19
+
+/* GP8_MODSEL */ /* 0 */ /* 1 */
+#define GP8_MODSEL_15 FM(SEL_SDA8_0) FM(SEL_SDA8_1)
+#define GP8_MODSEL_14 FM(SEL_SCL8_0) FM(SEL_SCL8_1)
+#define GP8_MODSEL_13 FM(SEL_SDA7_0) FM(SEL_SDA7_1)
+#define GP8_MODSEL_12 FM(SEL_SCL7_0) FM(SEL_SCL7_1)
+#define GP8_MODSEL_11 FM(SEL_SDA6_0) FM(SEL_SDA6_1)
+#define GP8_MODSEL_10 FM(SEL_SCL6_0) FM(SEL_SCL6_1)
+#define GP8_MODSEL_9 FM(SEL_SDA5_0) FM(SEL_SDA5_1)
+#define GP8_MODSEL_8 FM(SEL_SCL5_0) FM(SEL_SCL5_1)
+#define GP8_MODSEL_7 FM(SEL_SDA4_0) FM(SEL_SDA4_1)
+#define GP8_MODSEL_6 FM(SEL_SCL4_0) FM(SEL_SCL4_1)
+#define GP8_MODSEL_5 FM(SEL_SDA3_0) FM(SEL_SDA3_1)
+#define GP8_MODSEL_4 FM(SEL_SCL3_0) FM(SEL_SCL3_1)
+#define GP8_MODSEL_3 FM(SEL_SDA2_0) FM(SEL_SDA2_1)
+#define GP8_MODSEL_2 FM(SEL_SCL2_0) FM(SEL_SCL2_1)
+#define GP8_MODSEL_1 FM(SEL_SDA1_0) FM(SEL_SDA1_1)
+#define GP8_MODSEL_0 FM(SEL_SCL1_0) FM(SEL_SCL1_1)
+
+#define GP8_MODSEL \
+GP8_MODSEL_15 \
+GP8_MODSEL_14 \
+GP8_MODSEL_13 \
+GP8_MODSEL_12 \
+GP8_MODSEL_11 \
+GP8_MODSEL_10 \
+GP8_MODSEL_9 \
+GP8_MODSEL_8 \
+GP8_MODSEL_7 \
+GP8_MODSEL_6 \
+GP8_MODSEL_5 \
+GP8_MODSEL_4 \
+GP8_MODSEL_3 \
+GP8_MODSEL_2 \
+GP8_MODSEL_1 \
+GP8_MODSEL_0
+
+#define PINMUX_MODSELS \
+GP8_MODSEL \
+GP2_MODSEL \
+GP1_MODSEL
+
+enum {
+ PINMUX_RESERVED = 0,
+
+ PINMUX_DATA_BEGIN,
+ GP_ALL(DATA),
+ PINMUX_DATA_END,
+
+#define F_(x, y)
+#define FM(x) FN_##x,
+ PINMUX_FUNCTION_BEGIN,
+ GP_ALL(FN),
+ PINMUX_GPSR
+ PINMUX_GRP_FUNC
+ PINMUX_ALTSEL
+ PINMUX_MODSELS
+ PINMUX_FUNCTION_END,
+#undef F_
+#undef FM
+
+#define F_(x, y)
+#define FM(x) x##_MARK,
+ PINMUX_MARK_BEGIN,
+ PINMUX_GPSR
+ PINMUX_GRP_FUNC
+ PINMUX_MODSELS
+ PINMUX_MARK_END,
+#undef F_
+#undef FM
+};
+
+#define GP_ALTSEL_FUNC_0(bank, pin) \
+ GP##bank##_ALTSEL0_##pin##_0, \
+ GP##bank##_ALTSEL1_##pin##_0, \
+ GP##bank##_ALTSEL2_##pin##_0, \
+ GP##bank##_ALTSEL3_##pin##_0
+
+#define GP_ALTSEL_FUNC_1(bank, pin) \
+ GP##bank##_ALTSEL0_##pin##_1, \
+ GP##bank##_ALTSEL1_##pin##_0, \
+ GP##bank##_ALTSEL2_##pin##_0, \
+ GP##bank##_ALTSEL3_##pin##_0
+
+#define GP_ALTSEL_FUNC_2(bank, pin) \
+ GP##bank##_ALTSEL0_##pin##_0, \
+ GP##bank##_ALTSEL1_##pin##_1, \
+ GP##bank##_ALTSEL2_##pin##_0, \
+ GP##bank##_ALTSEL3_##pin##_0
+
+#define GP_ALTSEL_FUNC_3(bank, pin) \
+ GP##bank##_ALTSEL0_##pin##_1, \
+ GP##bank##_ALTSEL1_##pin##_1, \
+ GP##bank##_ALTSEL2_##pin##_0, \
+ GP##bank##_ALTSEL3_##pin##_0
+
+#define GP_ALTSEL_FUNC_4(bank, pin) \
+ GP##bank##_ALTSEL0_##pin##_0, \
+ GP##bank##_ALTSEL1_##pin##_0, \
+ GP##bank##_ALTSEL2_##pin##_1, \
+ GP##bank##_ALTSEL3_##pin##_0
+
+#define GP_ALTSEL_FUNC_5(bank, pin) \
+ GP##bank##_ALTSEL0_##pin##_1, \
+ GP##bank##_ALTSEL1_##pin##_0, \
+ GP##bank##_ALTSEL2_##pin##_1, \
+ GP##bank##_ALTSEL3_##pin##_0
+
+#define GP_ALTSEL_FUNC_6(bank, pin) \
+ GP##bank##_ALTSEL0_##pin##_0, \
+ GP##bank##_ALTSEL1_##pin##_1, \
+ GP##bank##_ALTSEL2_##pin##_1, \
+ GP##bank##_ALTSEL3_##pin##_0
+
+#define GP_ALTSEL_FUNC_7(bank, pin) \
+ GP##bank##_ALTSEL0_##pin##_1, \
+ GP##bank##_ALTSEL1_##pin##_1, \
+ GP##bank##_ALTSEL2_##pin##_1, \
+ GP##bank##_ALTSEL3_##pin##_0
+
+#define GP_ALTSEL_FUNC_8(bank, pin) \
+ GP##bank##_ALTSEL0_##pin##_0, \
+ GP##bank##_ALTSEL1_##pin##_0, \
+ GP##bank##_ALTSEL2_##pin##_0, \
+ GP##bank##_ALTSEL3_##pin##_1
+
+#define GP_ALTSEL_FUNC_9(bank, pin) \
+ GP##bank##_ALTSEL0_##pin##_1, \
+ GP##bank##_ALTSEL1_##pin##_0, \
+ GP##bank##_ALTSEL2_##pin##_0, \
+ GP##bank##_ALTSEL3_##pin##_1
+
+#define GP_ALTSEL_FUNC_10(bank, pin) \
+ GP##bank##_ALTSEL0_##pin##_0, \
+ GP##bank##_ALTSEL1_##pin##_1, \
+ GP##bank##_ALTSEL2_##pin##_0, \
+ GP##bank##_ALTSEL3_##pin##_1
+
+#define GP_ALTSEL_FUNC_11(bank, pin) \
+ GP##bank##_ALTSEL0_##pin##_1, \
+ GP##bank##_ALTSEL1_##pin##_1, \
+ GP##bank##_ALTSEL2_##pin##_0, \
+ GP##bank##_ALTSEL3_##pin##_1
+
+#define GP_ALTSEL_FUNC_12(bank, pin) \
+ GP##bank##_ALTSEL0_##pin##_0, \
+ GP##bank##_ALTSEL1_##pin##_0, \
+ GP##bank##_ALTSEL2_##pin##_1, \
+ GP##bank##_ALTSEL3_##pin##_1
+
+#define GP_ALTSEL_FUNC_13(bank, pin) \
+ GP##bank##_ALTSEL0_##pin##_1, \
+ GP##bank##_ALTSEL1_##pin##_0, \
+ GP##bank##_ALTSEL2_##pin##_1, \
+ GP##bank##_ALTSEL3_##pin##_1
+
+#define GP_ALTSEL_FUNC_14(bank, pin) \
+ GP##bank##_ALTSEL0_##pin##_0, \
+ GP##bank##_ALTSEL1_##pin##_1, \
+ GP##bank##_ALTSEL2_##pin##_1, \
+ GP##bank##_ALTSEL3_##pin##_1
+
+#define GP_ALTSEL_FUNC_15(bank, pin) \
+ GP##bank##_ALTSEL0_##pin##_1, \
+ GP##bank##_ALTSEL1_##pin##_1, \
+ GP##bank##_ALTSEL2_##pin##_1, \
+ GP##bank##_ALTSEL3_##pin##_1
+
+#define GP_ALTSEL_FUNC(bank, pin, func) \
+ GP_ALTSEL_FUNC_##func(bank, pin)
+
+/* GP0 ALTSEL function 0 */
+#define ALT_DP2_HOTPLUG GP_ALTSEL_FUNC(0, 27, 0)
+#define ALT_DP1_HOTPLUG GP_ALTSEL_FUNC(0, 26, 0)
+#define ALT_DP0_HOTPLUG GP_ALTSEL_FUNC(0, 25, 0)
+#define ALT_MSIOF1_SS2_A GP_ALTSEL_FUNC(0, 24, 0)
+#define ALT_MSIOF1_SS1_A GP_ALTSEL_FUNC(0, 23, 0)
+#define ALT_MSIOF1_SYNC_A GP_ALTSEL_FUNC(0, 22, 0)
+#define ALT_MSIOF1_RXD_A GP_ALTSEL_FUNC(0, 21, 0)
+#define ALT_MSIOF1_TXD_A GP_ALTSEL_FUNC(0, 20, 0)
+#define ALT_MSIOF1_SCK_A GP_ALTSEL_FUNC(0, 19, 0)
+#define ALT_MSIOF0_SS2 GP_ALTSEL_FUNC(0, 18, 0)
+#define ALT_MSIOF0_SS1 GP_ALTSEL_FUNC(0, 17, 0)
+#define ALT_MSIOF0_SYNC GP_ALTSEL_FUNC(0, 16, 0)
+#define ALT_MSIOF0_RXD GP_ALTSEL_FUNC(0, 15, 0)
+#define ALT_MSIOF0_TXD GP_ALTSEL_FUNC(0, 14, 0)
+#define ALT_MSIOF0_SCK GP_ALTSEL_FUNC(0, 13, 0)
+#define ALT_RXDB_EXTFXR_A GP_ALTSEL_FUNC(0, 12, 0)
+#define ALT_FXR_TXENB_N_A GP_ALTSEL_FUNC(0, 11, 0)
+#define ALT_FXR_TXDB_A GP_ALTSEL_FUNC(0, 10, 0)
+#define ALT_RXDA_EXTFXR_A GP_ALTSEL_FUNC(0, 9, 0)
+#define ALT_FXR_TXENA_N_A GP_ALTSEL_FUNC(0, 8, 0)
+#define ALT_FXR_TXDA_A GP_ALTSEL_FUNC(0, 7, 0)
+#define ALT_CLK_EXTFXR_A GP_ALTSEL_FUNC(0, 6, 0)
+#define ALT_FXR_CLKOUT2_A GP_ALTSEL_FUNC(0, 5, 0)
+#define ALT_FXR_CLKOUT1_A GP_ALTSEL_FUNC(0, 4, 0)
+#define ALT_STPWT_EXTFXR_A GP_ALTSEL_FUNC(0, 3, 0)
+
+/* GP0 ALTSEL function 1 */
+#define ALT_TAUD0O13 GP_ALTSEL_FUNC(0, 24, 1)
+#define ALT_TAUD0O12 GP_ALTSEL_FUNC(0, 23, 1)
+#define ALT_TAUD0O11 GP_ALTSEL_FUNC(0, 22, 1)
+#define ALT_TAUD0O10 GP_ALTSEL_FUNC(0, 21, 1)
+#define ALT_TAUD0O9 GP_ALTSEL_FUNC(0, 20, 1)
+#define ALT_TAUD0O8 GP_ALTSEL_FUNC(0, 19, 1)
+#define ALT_TAUD0O7 GP_ALTSEL_FUNC(0, 18, 1)
+#define ALT_TAUD0O6 GP_ALTSEL_FUNC(0, 17, 1)
+#define ALT_TAUD0O5 GP_ALTSEL_FUNC(0, 16, 1)
+#define ALT_TAUD0O4 GP_ALTSEL_FUNC(0, 15, 1)
+#define ALT_TAUD0O3 GP_ALTSEL_FUNC(0, 14, 1)
+#define ALT_TAUD0O2 GP_ALTSEL_FUNC(0, 13, 1)
+#define ALT_CAN11TX GP_ALTSEL_FUNC(0, 12, 1)
+#define ALT_CAN11RX_INTP11 GP_ALTSEL_FUNC(0, 11, 1)
+#define ALT_CAN10TX GP_ALTSEL_FUNC(0, 10, 1)
+#define ALT_CAN10RX_INTP10 GP_ALTSEL_FUNC(0, 9, 1)
+#define ALT_CAN9TX GP_ALTSEL_FUNC(0, 8, 1)
+#define ALT_CAN9RX_INTP9 GP_ALTSEL_FUNC(0, 7, 1)
+#define ALT_CAN8TX GP_ALTSEL_FUNC(0, 6, 1)
+#define ALT_CAN8RX_INTP8 GP_ALTSEL_FUNC(0, 5, 1)
+#define ALT_CAN7TX GP_ALTSEL_FUNC(0, 4, 1)
+#define ALT_CAN7RX_INTP7 GP_ALTSEL_FUNC(0, 3, 1)
+
+/* GP0 ALTSEL function 2 */
+#define ALT_RLIN311TX GP_ALTSEL_FUNC(0, 12, 2)
+#define ALT_RLIN311RX_INTP27 GP_ALTSEL_FUNC(0, 11, 2)
+#define ALT_RLIN310TX GP_ALTSEL_FUNC(0, 10, 2)
+#define ALT_RLIN310RX_INTP26 GP_ALTSEL_FUNC(0, 9, 2)
+#define ALT_RLIN39TX GP_ALTSEL_FUNC(0, 8, 2)
+#define ALT_RLIN39RX_INTP25 GP_ALTSEL_FUNC(0, 7, 2)
+#define ALT_RLIN38TX GP_ALTSEL_FUNC(0, 6, 2)
+#define ALT_RLIN38RX_INTP24 GP_ALTSEL_FUNC(0, 5, 2)
+#define ALT_RLIN315TX_A GP_ALTSEL_FUNC(0, 4, 2)
+#define ALT_RLIN315RX_INTP31_A GP_ALTSEL_FUNC(0, 3, 2)
+
+/* GP0 ALTSEL function 3 */
+#define ALT_RTCA0OUT_A GP_ALTSEL_FUNC(0, 12, 3)
+#define ALT_EXTCLK0O_A GP_ALTSEL_FUNC(0, 11, 3)
+#define ALT_TAUD1O15 GP_ALTSEL_FUNC(0, 8, 3)
+#define ALT_TAUD1O14 GP_ALTSEL_FUNC(0, 7, 3)
+#define ALT_TAUD1O13 GP_ALTSEL_FUNC(0, 6, 3)
+#define ALT_TAUD1O12 GP_ALTSEL_FUNC(0, 5, 3)
+#define ALT_TAUD1O11 GP_ALTSEL_FUNC(0, 4, 3)
+#define ALT_TAUD1O10 GP_ALTSEL_FUNC(0, 3, 3)
+
+/* GP1 ALTSEL function 0 */
+#define ALT_RLIN33TX GP_ALTSEL_FUNC(1, 21, 0)
+#define ALT_RLIN33RX_INTP19 GP_ALTSEL_FUNC(1, 20, 0)
+#define ALT_RLIN32TX GP_ALTSEL_FUNC(1, 19, 0)
+#define ALT_RLIN32RX_INTP18 GP_ALTSEL_FUNC(1, 18, 0)
+#define ALT_RLIN31TX GP_ALTSEL_FUNC(1, 17, 0)
+#define ALT_RLIN31RX_INTP17 GP_ALTSEL_FUNC(1, 16, 0)
+#define ALT_RLIN30TX GP_ALTSEL_FUNC(1, 15, 0)
+#define ALT_RLIN30RX_INTP16 GP_ALTSEL_FUNC(1, 14, 0)
+#define ALT_CAN6TX GP_ALTSEL_FUNC(1, 13, 0)
+#define ALT_CAN6RX_INTP6 GP_ALTSEL_FUNC(1, 12, 0)
+#define ALT_CAN5TX GP_ALTSEL_FUNC(1, 11, 0)
+#define ALT_CAN5RX_INTP5 GP_ALTSEL_FUNC(1, 10, 0)
+#define ALT_CAN4TX GP_ALTSEL_FUNC(1, 9, 0)
+#define ALT_CAN4RX_INTP4 GP_ALTSEL_FUNC(1, 8, 0)
+#define ALT_CAN3TX GP_ALTSEL_FUNC(1, 7, 0)
+#define ALT_CAN3RX_INTP3 GP_ALTSEL_FUNC(1, 6, 0)
+#define ALT_CAN2TX GP_ALTSEL_FUNC(1, 5, 0)
+#define ALT_CAN2RX_INTP2 GP_ALTSEL_FUNC(1, 4, 0)
+#define ALT_CAN1TX GP_ALTSEL_FUNC(1, 3, 0)
+#define ALT_CAN1RX_INTP1 GP_ALTSEL_FUNC(1, 2, 0)
+#define ALT_CAN0TX GP_ALTSEL_FUNC(1, 1, 0)
+#define ALT_CAN0RX_INTP0 GP_ALTSEL_FUNC(1, 0, 0)
+
+/* GP1 ALTSEL function 1 */
+#define ALT_TAUJ1I3_TAUJ1O3 GP_ALTSEL_FUNC(1, 21, 1)
+#define ALT_TAUJ1I2_TAUJ1O2 GP_ALTSEL_FUNC(1, 20, 1)
+#define ALT_TAUJ1I1_TAUJ1O1 GP_ALTSEL_FUNC(1, 19, 1)
+#define ALT_TAUJ1I0_TAUJ1O0 GP_ALTSEL_FUNC(1, 18, 1)
+#define ALT_TAUJ3I3_TAUJ3O3 GP_ALTSEL_FUNC(1, 17, 1)
+#define ALT_TAUJ3I2_TAUJ3O2 GP_ALTSEL_FUNC(1, 16, 1)
+#define ALT_TAUJ3I1_TAUJ3O1 GP_ALTSEL_FUNC(1, 15, 1)
+#define ALT_TAUJ3I0_TAUJ3O0 GP_ALTSEL_FUNC(1, 14, 1)
+#define ALT_RLIN314TX_A GP_ALTSEL_FUNC(1, 13, 1)
+#define ALT_RLIN314RX_INTP30_A GP_ALTSEL_FUNC(1, 12, 1)
+#define ALT_RLIN313TX_A GP_ALTSEL_FUNC(1, 11, 1)
+#define ALT_RLIN313RX_INTP29_A GP_ALTSEL_FUNC(1, 10, 1)
+#define ALT_RLIN312TX_A GP_ALTSEL_FUNC(1, 9, 1)
+#define ALT_RLIN312RX_INTP28_A GP_ALTSEL_FUNC(1, 8, 1)
+#define ALT_RLIN37TX_A GP_ALTSEL_FUNC(1, 7, 1)
+#define ALT_RLIN37RX_INTP23_A GP_ALTSEL_FUNC(1, 6, 1)
+#define ALT_RLIN36TX_A GP_ALTSEL_FUNC(1, 5, 1)
+#define ALT_RLIN36RX_INTP22_A GP_ALTSEL_FUNC(1, 4, 1)
+#define ALT_RLIN35TX_A GP_ALTSEL_FUNC(1, 3, 1)
+#define ALT_RLIN35RX_INTP21_A GP_ALTSEL_FUNC(1, 2, 1)
+#define ALT_RLIN34TX_A GP_ALTSEL_FUNC(1, 1, 1)
+#define ALT_RLIN34RX_INTP20_A GP_ALTSEL_FUNC(1, 0, 1)
+
+/* GP1 ALTSEL function 2 */
+#define ALT_CAN15TX_A GP_ALTSEL_FUNC(1, 21, 2)
+#define ALT_CAN15RX_INTP15_A GP_ALTSEL_FUNC(1, 20, 2)
+#define ALT_CAN14TX_A GP_ALTSEL_FUNC(1, 19, 2)
+#define ALT_CAN14RX_INTP14_A GP_ALTSEL_FUNC(1, 18, 2)
+#define ALT_CAN13TX_A GP_ALTSEL_FUNC(1, 17, 2)
+#define ALT_CAN13RX_INTP13_A GP_ALTSEL_FUNC(1, 16, 2)
+#define ALT_CAN12TX_A GP_ALTSEL_FUNC(1, 15, 2)
+#define ALT_CAN12RX_INTP12_A GP_ALTSEL_FUNC(1, 14, 2)
+#define ALT_TAUD1O9 GP_ALTSEL_FUNC(1, 13, 2)
+#define ALT_TAUD1O8 GP_ALTSEL_FUNC(1, 12, 2)
+#define ALT_MSIOF3_SS2 GP_ALTSEL_FUNC(1, 11, 2)
+#define ALT_MSIOF3_SS1 GP_ALTSEL_FUNC(1, 10, 2)
+#define ALT_MSIOF3_SYNC GP_ALTSEL_FUNC(1, 9, 2)
+#define ALT_MSIOF3_RXD GP_ALTSEL_FUNC(1, 8, 2)
+#define ALT_MSIOF3_TXD GP_ALTSEL_FUNC(1, 7, 2)
+#define ALT_MSIOF3_SCK GP_ALTSEL_FUNC(1, 6, 2)
+#define ALT_MSIOF2_SS2 GP_ALTSEL_FUNC(1, 5, 2)
+#define ALT_MSIOF2_SS1 GP_ALTSEL_FUNC(1, 4, 2)
+#define ALT_MSIOF2_SYNC GP_ALTSEL_FUNC(1, 3, 2)
+#define ALT_MSIOF2_RXD GP_ALTSEL_FUNC(1, 2, 2)
+#define ALT_MSIOF2_TXD GP_ALTSEL_FUNC(1, 1, 2)
+#define ALT_MSIOF2_SCK GP_ALTSEL_FUNC(1, 0, 2)
+
+/* GP1 ALTSEL function 3 */
+#define ALT_NMI1_A GP_ALTSEL_FUNC(1, 19, 3)
+#define ALT_INTP34_A GP_ALTSEL_FUNC(1, 18, 3)
+#define ALT_INTP33_A GP_ALTSEL_FUNC(1, 17, 3)
+#define ALT_INTP32_A GP_ALTSEL_FUNC(1, 16, 3)
+#define ALT_RXDB_EXTFXR_B GP_ALTSEL_FUNC(1, 11, 3)
+#define ALT_FXR_TXENB_N_B GP_ALTSEL_FUNC(1, 10, 3)
+#define ALT_FXR_TXDB_B GP_ALTSEL_FUNC(1, 9, 3)
+#define ALT_RXDA_EXTFXR_B GP_ALTSEL_FUNC(1, 8, 3)
+#define ALT_FXR_TXENA_N_B GP_ALTSEL_FUNC(1, 7, 3)
+#define ALT_FXR_TXDA_B GP_ALTSEL_FUNC(1, 6, 3)
+#define ALT_CLK_EXTFXR_B GP_ALTSEL_FUNC(1, 5, 3)
+#define ALT_FXR_CLKOUT2_B GP_ALTSEL_FUNC(1, 4, 3)
+#define ALT_FXR_CLKOUT1_B GP_ALTSEL_FUNC(1, 3, 3)
+#define ALT_STPWT_EXTFXR_B GP_ALTSEL_FUNC(1, 2, 3)
+
+/* GP2 ALTSEL function 0 */
+#define ALT_INTP34_B GP_ALTSEL_FUNC(2, 28, 0)
+#define ALT_TAUD1O3 GP_ALTSEL_FUNC(2, 27, 0)
+#define ALT_TAUD1O2 GP_ALTSEL_FUNC(2, 26, 0)
+#define ALT_TAUD1O1 GP_ALTSEL_FUNC(2, 25, 0)
+#define ALT_TAUD1O0 GP_ALTSEL_FUNC(2, 24, 0)
+#define ALT_EXTCLK0O_B GP_ALTSEL_FUNC(2, 23, 0)
+#define ALT_AVS1 GP_ALTSEL_FUNC(2, 22, 0)
+#define ALT_AVS0 GP_ALTSEL_FUNC(2, 21, 0)
+#define ALT_SDA0 GP_ALTSEL_FUNC(2, 20, 0)
+#define ALT_SCL0 GP_ALTSEL_FUNC(2, 19, 0)
+#define ALT_INTP33_B GP_ALTSEL_FUNC(2, 18, 0)
+#define ALT_INTP32_B GP_ALTSEL_FUNC(2, 17, 0)
+#define ALT_CAN_CLK GP_ALTSEL_FUNC(2, 16, 0)
+#define ALT_CAN15TX_B GP_ALTSEL_FUNC(2, 15, 0)
+#define ALT_CAN15RX_B_INTP15 GP_ALTSEL_FUNC(2, 14, 0)
+#define ALT_CAN14TX_B GP_ALTSEL_FUNC(2, 13, 0)
+#define ALT_CAN14RX_B_INTP14 GP_ALTSEL_FUNC(2, 12, 0)
+#define ALT_CAN13TX_B GP_ALTSEL_FUNC(2, 11, 0)
+#define ALT_CAN13RX_B_INTP13 GP_ALTSEL_FUNC(2, 10, 0)
+#define ALT_CAN12TX_B GP_ALTSEL_FUNC(2, 9, 0)
+#define ALT_CAN12RX_B_INTP12 GP_ALTSEL_FUNC(2, 8, 0)
+#define ALT_RLIN37TX_B GP_ALTSEL_FUNC(2, 7, 0)
+#define ALT_RLIN37RX_B_INTP23 GP_ALTSEL_FUNC(2, 6, 0)
+#define ALT_RLIN36TX_B GP_ALTSEL_FUNC(2, 5, 0)
+#define ALT_RLIN36RX_B_INTP22 GP_ALTSEL_FUNC(2, 4, 0)
+#define ALT_RLIN35TX_B GP_ALTSEL_FUNC(2, 3, 0)
+#define ALT_RLIN35RX_B_INTP21 GP_ALTSEL_FUNC(2, 2, 0)
+#define ALT_RLIN34TX_B GP_ALTSEL_FUNC(2, 1, 0)
+#define ALT_RLIN34RX_B_INTP20 GP_ALTSEL_FUNC(2, 0, 0)
+
+/* GP2 ALTSEL function 1 */
+#define ALT_TAUD0O1 GP_ALTSEL_FUNC(2, 18, 1)
+#define ALT_TAUD0O0 GP_ALTSEL_FUNC(2, 17, 1)
+#define ALT_RLIN315TX_B GP_ALTSEL_FUNC(2, 15, 1)
+#define ALT_RLIN315RX_INTP31_B GP_ALTSEL_FUNC(2, 14, 1)
+#define ALT_RLIN314TX_B GP_ALTSEL_FUNC(2, 13, 1)
+#define ALT_RLIN314RX_INTP30_B GP_ALTSEL_FUNC(2, 12, 1)
+#define ALT_RLIN313TX GP_ALTSEL_FUNC(2, 11, 1)
+#define ALT_RLIN313RX_INTP29_B GP_ALTSEL_FUNC(2, 10, 1)
+#define ALT_RLIN312TX GP_ALTSEL_FUNC(2, 9, 1)
+#define ALT_RLIN312RX_INTP28_B GP_ALTSEL_FUNC(2, 8, 1)
+#define ALT_RTCA0OUT_B GP_ALTSEL_FUNC(2, 7, 1)
+#define ALT_MSIOF1_SS2_B GP_ALTSEL_FUNC(2, 5, 1)
+#define ALT_MSIOF1_SS1_B GP_ALTSEL_FUNC(2, 4, 1)
+#define ALT_MSIOF1_SYN_B GP_ALTSEL_FUNC(2, 3, 1)
+#define ALT_MSIOF1_RXD_B GP_ALTSEL_FUNC(2, 2, 1)
+#define ALT_MSIOF1_TXD_B GP_ALTSEL_FUNC(2, 1, 1)
+#define ALT_MSIOF1_SCK_B GP_ALTSEL_FUNC(2, 0, 1)
+
+/* GP2 ALTSEL function 2 */
+#define ALT_TAUD1O7 GP_ALTSEL_FUNC(2, 9, 2)
+#define ALT_TAUD1O6 GP_ALTSEL_FUNC(2, 8, 2)
+#define ALT_TAUD1O5 GP_ALTSEL_FUNC(2, 7, 2)
+#define ALT_TAUD1O4 GP_ALTSEL_FUNC(2, 6, 2)
+#define ALT_TAUD0O15 GP_ALTSEL_FUNC(2, 1, 2)
+#define ALT_TAUD0O14 GP_ALTSEL_FUNC(2, 0, 2)
+
+/* GP2 ALTSEL function 3 */
+#define ALT_CANXL1_TX GP_ALTSEL_FUNC(2, 11, 3)
+#define ALT_CANXL1_RX GP_ALTSEL_FUNC(2, 10, 3)
+#define ALT_CANXL0_TX GP_ALTSEL_FUNC(2, 9, 3)
+#define ALT_CANXL0_RX GP_ALTSEL_FUNC(2, 8, 3)
+#define ALT_CTIACK GP_ALTSEL_FUNC(2, 4, 3)
+#define ALT_CTIREQ GP_ALTSEL_FUNC(2, 3, 3)
+
+/* GP3 ALTSEL function 0 */
+#define ALT_ERRORIN0_N GP_ALTSEL_FUNC(3, 16, 0)
+#define ALT_ERROROUT_N GP_ALTSEL_FUNC(3, 15, 0)
+#define ALT_QSPI1_SSL GP_ALTSEL_FUNC(3, 14, 0)
+#define ALT_QSPI1_IO3 GP_ALTSEL_FUNC(3, 13, 0)
+#define ALT_QSPI1_IO2 GP_ALTSEL_FUNC(3, 12, 0)
+#define ALT_QSPI1_MISO_IO1 GP_ALTSEL_FUNC(3, 11, 0)
+#define ALT_QSPI1_MOSI_IO0 GP_ALTSEL_FUNC(3, 10, 0)
+#define ALT_QSPI1_SPCLK GP_ALTSEL_FUNC(3, 9, 0)
+#define ALT_RPC_INT_N GP_ALTSEL_FUNC(3, 8, 0)
+#define ALT_RPC_WP_N GP_ALTSEL_FUNC(3, 7, 0)
+#define ALT_RPC_RESET_N GP_ALTSEL_FUNC(3, 6, 0)
+#define ALT_QSPI0_SSL GP_ALTSEL_FUNC(3, 5, 0)
+#define ALT_QSPI0_IO3 GP_ALTSEL_FUNC(3, 4, 0)
+#define ALT_QSPI0_IO2 GP_ALTSEL_FUNC(3, 3, 0)
+#define ALT_QSPI0_MISO_IO1 GP_ALTSEL_FUNC(3, 2, 0)
+#define ALT_QSPI0_MOSI_IO0 GP_ALTSEL_FUNC(3, 1, 0)
+#define ALT_QSPI0_SPCLK GP_ALTSEL_FUNC(3, 0, 0)
+
+/* GP4 ALTSEL function 0 */
+#define ALT_PCIE61_CLKREQ_N GP_ALTSEL_FUNC(4, 15, 0)
+#define ALT_PCIE60_CLKREQ_N GP_ALTSEL_FUNC(4, 14, 0)
+#define ALT_ERRORIN1_N GP_ALTSEL_FUNC(4, 13, 0)
+#define ALT_SD0_CD GP_ALTSEL_FUNC(4, 12, 0)
+#define ALT_SD0_WP GP_ALTSEL_FUNC(4, 11, 0)
+#define ALT_MMC0_DS GP_ALTSEL_FUNC(4, 10, 0)
+#define ALT_MMC0_D7 GP_ALTSEL_FUNC(4, 9, 0)
+#define ALT_MMC0_D6 GP_ALTSEL_FUNC(4, 8, 0)
+#define ALT_MMC0_D5 GP_ALTSEL_FUNC(4, 7, 0)
+#define ALT_MMC0_D4 GP_ALTSEL_FUNC(4, 6, 0)
+#define ALT_MMC0_SD_D3 GP_ALTSEL_FUNC(4, 5, 0)
+#define ALT_MMC0_SD_D2 GP_ALTSEL_FUNC(4, 4, 0)
+#define ALT_MMC0_SD_D1 GP_ALTSEL_FUNC(4, 3, 0)
+#define ALT_MMC0_SD_D0 GP_ALTSEL_FUNC(4, 2, 0)
+#define ALT_MMC0_SD_CMD GP_ALTSEL_FUNC(4, 1, 0)
+#define ALT_MMC0_SD_CLK GP_ALTSEL_FUNC(4, 0, 0)
+
+/* GP5 ALTSEL function 0 */
+#define ALT_TPU0TO3 GP_ALTSEL_FUNC(5, 22, 0)
+#define ALT_TPU0TO2 GP_ALTSEL_FUNC(5, 21, 0)
+#define ALT_TPU0TO1 GP_ALTSEL_FUNC(5, 20, 0)
+#define ALT_TPU0TO0 GP_ALTSEL_FUNC(5, 19, 0)
+#define ALT_TCLK4 GP_ALTSEL_FUNC(5, 18, 0)
+#define ALT_TCLK3 GP_ALTSEL_FUNC(5, 17, 0)
+#define ALT_TCLK2 GP_ALTSEL_FUNC(5, 16, 0)
+#define ALT_TCLK1 GP_ALTSEL_FUNC(5, 15, 0)
+#define ALT_IRQ3_A GP_ALTSEL_FUNC(5, 14, 0)
+#define ALT_IRQ2_A GP_ALTSEL_FUNC(5, 13, 0)
+#define ALT_IRQ1_A GP_ALTSEL_FUNC(5, 12, 0)
+#define ALT_IRQ0_A GP_ALTSEL_FUNC(5, 11, 0)
+#define ALT_HSCK1 GP_ALTSEL_FUNC(5, 10, 0)
+#define ALT_HCTS1_N GP_ALTSEL_FUNC(5, 9, 0)
+#define ALT_HRTS1_N GP_ALTSEL_FUNC(5, 8, 0)
+#define ALT_HRX1 GP_ALTSEL_FUNC(5, 7, 0)
+#define ALT_HTX1 GP_ALTSEL_FUNC(5, 6, 0)
+#define ALT_SCIF_CLK GP_ALTSEL_FUNC(5, 5, 0)
+#define ALT_HSCK0 GP_ALTSEL_FUNC(5, 4, 0)
+#define ALT_HCTS0_N GP_ALTSEL_FUNC(5, 3, 0)
+#define ALT_HRTS0_N GP_ALTSEL_FUNC(5, 2, 0)
+#define ALT_HRX0 GP_ALTSEL_FUNC(5, 1, 0)
+#define ALT_HTX0 GP_ALTSEL_FUNC(5, 0, 0)
+
+/* GP5 ALTSEL function 1 */
+#define ALT_SSI9_WS GP_ALTSEL_FUNC(5, 22, 1)
+#define ALT_SSI9_SCK GP_ALTSEL_FUNC(5, 21, 1)
+#define ALT_PWM5 GP_ALTSEL_FUNC(5, 20, 1)
+#define ALT_PWM4 GP_ALTSEL_FUNC(5, 19, 1)
+#define ALT_PWM3 GP_ALTSEL_FUNC(5, 18, 1)
+#define ALT_PWM2 GP_ALTSEL_FUNC(5, 17, 1)
+#define ALT_PWM1 GP_ALTSEL_FUNC(5, 16, 1)
+#define ALT_PWM0_A GP_ALTSEL_FUNC(5, 15, 1)
+#define ALT_SSI17_SD GP_ALTSEL_FUNC(5, 13, 1)
+#define ALT_SSI17_WS GP_ALTSEL_FUNC(5, 12, 1)
+#define ALT_SSI17_SCK GP_ALTSEL_FUNC(5, 11, 1)
+#define ALT_SCK1 GP_ALTSEL_FUNC(5, 10, 1)
+#define ALT_CTS1_N GP_ALTSEL_FUNC(5, 9, 1)
+#define ALT_RTS1_N GP_ALTSEL_FUNC(5, 8, 1)
+#define ALT_RX1 GP_ALTSEL_FUNC(5, 7, 1)
+#define ALT_TX1 GP_ALTSEL_FUNC(5, 6, 1)
+#define ALT_SCK0 GP_ALTSEL_FUNC(5, 4, 1)
+#define ALT_CTS0_N GP_ALTSEL_FUNC(5, 3, 1)
+#define ALT_RTS0_N GP_ALTSEL_FUNC(5, 2, 1)
+#define ALT_RX0 GP_ALTSEL_FUNC(5, 1, 1)
+#define ALT_TX0 GP_ALTSEL_FUNC(5, 0, 1)
+
+/* GP5 ALTSEL function 2 */
+#define ALT_SSI19_SD GP_ALTSEL_FUNC(5, 18, 2)
+#define ALT_SSI19_WS GP_ALTSEL_FUNC(5, 17, 2)
+#define ALT_SSI19_SCK GP_ALTSEL_FUNC(5, 16, 2)
+#define ALT_SSI18_SD GP_ALTSEL_FUNC(5, 15, 2)
+#define ALT_SSI13_SCK GP_ALTSEL_FUNC(5, 10, 2)
+#define ALT_RIF0_SYNC_B GP_ALTSEL_FUNC(5, 8, 2)
+#define ALT_IRQ1_B GP_ALTSEL_FUNC(5, 3, 2)
+#define ALT_IRQ0_B GP_ALTSEL_FUNC(5, 2, 2)
+#define ALT_SSI13_SD GP_ALTSEL_FUNC(5, 1, 2)
+#define ALT_SSI13_WS GP_ALTSEL_FUNC(5, 0, 2)
+
+/* GP5 ALTSEL function 3*/
+#define ALT_RIF7_D1 GP_ALTSEL_FUNC(5, 14, 3)
+#define ALT_RIF7_D0 GP_ALTSEL_FUNC(5, 13, 3)
+#define ALT_RIF7_SYNC GP_ALTSEL_FUNC(5, 12, 3)
+#define ALT_RIF7_CLK GP_ALTSEL_FUNC(5, 11, 3)
+#define ALT_RIF0_CLK_B GP_ALTSEL_FUNC(5, 10, 3)
+#define ALT_SSI16_SD GP_ALTSEL_FUNC(5, 8, 3)
+#define ALT_SSI16_WS GP_ALTSEL_FUNC(5, 7, 3)
+#define ALT_SSI16_SCK GP_ALTSEL_FUNC(5, 6, 3)
+#define ALT_SSI15_SD GP_ALTSEL_FUNC(5, 4, 3)
+#define ALT_SSI15_WS GP_ALTSEL_FUNC(5, 3, 3)
+#define ALT_SSI15_SCK GP_ALTSEL_FUNC(5, 2, 3)
+#define ALT_RIF0_D1_B GP_ALTSEL_FUNC(5, 1, 3)
+#define ALT_RIF0_D0_B GP_ALTSEL_FUNC(5, 0, 3)
+
+/* GP6 ALTSEL function 0 */
+#define ALT_AUDIO1_CLKOUT1 GP_ALTSEL_FUNC(6, 30, 0)
+#define ALT_AUDIO1_CLKOUT0 GP_ALTSEL_FUNC(6, 29, 0)
+#define ALT_SSI2_SD GP_ALTSEL_FUNC(6, 28, 0)
+#define ALT_SSI2_WS GP_ALTSEL_FUNC(6, 27, 0)
+#define ALT_SSI2_SCK GP_ALTSEL_FUNC(6, 26, 0)
+#define ALT_AUDIO0_CLKOUT3 GP_ALTSEL_FUNC(6, 25, 0)
+#define ALT_AUDIO0_CLKOUT2 GP_ALTSEL_FUNC(6, 24, 0)
+#define ALT_SSI1_SD GP_ALTSEL_FUNC(6, 23, 0)
+#define ALT_SSI1_WS GP_ALTSEL_FUNC(6, 22, 0)
+#define ALT_SSI1_SCK GP_ALTSEL_FUNC(6, 21, 0)
+#define ALT_AUDIO0_CLKOUT1 GP_ALTSEL_FUNC(6, 20, 0)
+#define ALT_AUDIO0_CLKOUT0 GP_ALTSEL_FUNC(6, 19, 0)
+#define ALT_SSI0_SD GP_ALTSEL_FUNC(6, 18, 0)
+#define ALT_SSI0_WS GP_ALTSEL_FUNC(6, 17, 0)
+#define ALT_SSI0_SCK GP_ALTSEL_FUNC(6, 16, 0)
+#define ALT_MSIOF4_SS2_B GP_ALTSEL_FUNC(6, 15, 0)
+#define ALT_MSIOF4_SS1_B GP_ALTSEL_FUNC(6, 14, 0)
+#define ALT_MSIOF4_SYNC_B GP_ALTSEL_FUNC(6, 13, 0)
+#define ALT_MSIOF4_RXD_B GP_ALTSEL_FUNC(6, 12, 0)
+#define ALT_MSIOF4_TXD_B GP_ALTSEL_FUNC(6, 11, 0)
+#define ALT_MSIOF4_SCK_B GP_ALTSEL_FUNC(6, 10, 0)
+#define ALT_MSIOF7_SS2_A GP_ALTSEL_FUNC(6, 9, 0)
+#define ALT_MSIOF7_SS1_A GP_ALTSEL_FUNC(6, 8, 0)
+#define ALT_MSIOF7_SYNC_A GP_ALTSEL_FUNC(6, 7, 0)
+#define ALT_MSIOF7_RXD_A GP_ALTSEL_FUNC(6, 6, 0)
+#define ALT_MSIOF7_TXD_A GP_ALTSEL_FUNC(6, 5, 0)
+#define ALT_MSIOF7_SCK_A GP_ALTSEL_FUNC(6, 4, 0)
+#define ALT_RIF6_CLK GP_ALTSEL_FUNC(6, 3, 0)
+#define ALT_RIF6_SYNC GP_ALTSEL_FUNC(6, 2, 0)
+#define ALT_RIF6_D1 GP_ALTSEL_FUNC(6, 1, 0)
+#define ALT_RIF6_D0 GP_ALTSEL_FUNC(6, 0, 0)
+
+/* GP6 ALTSEL function 1 */
+#define ALT_MSIOF7_RXD_B GP_ALTSEL_FUNC(6, 30, 1)
+#define ALT_MSIOF7_TXD_B GP_ALTSEL_FUNC(6, 29, 1)
+#define ALT_MSIOF7_SCK_B GP_ALTSEL_FUNC(6, 28, 1)
+#define ALT_MSIOF4_SS2_A GP_ALTSEL_FUNC(6, 21, 1)
+#define ALT_MSIOF4_SS1_A GP_ALTSEL_FUNC(6, 20, 1)
+#define ALT_MSIOF4_SYNC_A GP_ALTSEL_FUNC(6, 19, 1)
+#define ALT_MSIOF4_RXD_A GP_ALTSEL_FUNC(6, 18, 1)
+#define ALT_MSIOF4_TXD_A GP_ALTSEL_FUNC(6, 17, 1)
+#define ALT_MSIOF4_SCK_A GP_ALTSEL_FUNC(6, 16, 1)
+#define ALT_SSI14_SD GP_ALTSEL_FUNC(6, 15, 1)
+#define ALT_SSI12_SD GP_ALTSEL_FUNC(6, 14, 1)
+#define ALT_SSI12_WS GP_ALTSEL_FUNC(6, 13, 1)
+#define ALT_SSI12_SCK GP_ALTSEL_FUNC(6, 11, 1)
+#define ALT_SSI14_WS GP_ALTSEL_FUNC(6, 9, 1)
+#define ALT_SSI14_SCK GP_ALTSEL_FUNC(6, 8, 1)
+#define ALT_RIF1_D1_B GP_ALTSEL_FUNC(6, 7, 1)
+#define ALT_RIF1_D0_B GP_ALTSEL_FUNC(6, 6, 1)
+#define ALT_RIF1_SYNC_B GP_ALTSEL_FUNC(6, 5, 1)
+#define ALT_RIF1_CLK_B GP_ALTSEL_FUNC(6, 4, 1)
+#define ALT_SSI10_SD GP_ALTSEL_FUNC(6, 3, 1)
+#define ALT_SSI10_WS GP_ALTSEL_FUNC(6, 2, 1)
+#define ALT_SSI10_SCK GP_ALTSEL_FUNC(6, 1, 1)
+#define ALT_SSI9_SD GP_ALTSEL_FUNC(6, 0, 1)
+
+/* GP6 ALTSEL function 2 */
+#define ALT_RIF5_CLK GP_ALTSEL_FUNC(6, 30, 2)
+#define ALT_RIF5_SYNC GP_ALTSEL_FUNC(6, 28, 2)
+#define ALT_RIF1_D1_A GP_ALTSEL_FUNC(6, 27, 2)
+#define ALT_RIF1_D0_A GP_ALTSEL_FUNC(6, 26, 2)
+#define ALT_RIF1_CLK_A GP_ALTSEL_FUNC(6, 25, 2)
+#define ALT_RIF2_D1 GP_ALTSEL_FUNC(6, 24, 2)
+#define ALT_HCTS3_N GP_ALTSEL_FUNC(6, 23, 2)
+#define ALT_HRTS3_N GP_ALTSEL_FUNC(6, 22, 2)
+#define ALT_HSCK3 GP_ALTSEL_FUNC(6, 21, 2)
+#define ALT_RIF2_D0 GP_ALTSEL_FUNC(6, 20, 2)
+#define ALT_RIF2_SYNC GP_ALTSEL_FUNC(6, 19, 2)
+#define ALT_HRX3 GP_ALTSEL_FUNC(6, 18, 2)
+#define ALT_HTX3 GP_ALTSEL_FUNC(6, 17, 2)
+#define ALT_AUDIO_CLKC_B GP_ALTSEL_FUNC(6, 12, 2)
+#define ALT_AUDIO_CLKB_B GP_ALTSEL_FUNC(6, 10, 2)
+#define ALT_SSI11_SD GP_ALTSEL_FUNC(6, 7, 2)
+#define ALT_SSI11_WS GP_ALTSEL_FUNC(6, 6, 2)
+#define ALT_SSI11_SCK GP_ALTSEL_FUNC(6, 5, 2)
+#define ALT_AUDIO_CLKA_B GP_ALTSEL_FUNC(6, 4, 2)
+
+/* GP6 ALTSEL function 3 */
+#define ALT_CTS3_N GP_ALTSEL_FUNC(6, 22, 3)
+#define ALT_RTS3_N GP_ALTSEL_FUNC(6, 22, 3)
+#define ALT_SCK3 GP_ALTSEL_FUNC(6, 21, 3)
+#define ALT_RX3 GP_ALTSEL_FUNC(6, 18, 3)
+#define ALT_TX3 GP_ALTSEL_FUNC(6, 17, 3)
+#define ALT_RIF1_SYNC_A GP_ALTSEL_FUNC(6, 11, 3)
+
+/* GP7 ALTSEL function 0 */
+#define ALT_MSIOF6_SS2_B GP_ALTSEL_FUNC(7, 30, 0)
+#define ALT_MSIOF6_SS1_B GP_ALTSEL_FUNC(7, 29, 0)
+#define ALT_MSIOF6_SYNC_B GP_ALTSEL_FUNC(7, 28, 0)
+#define ALT_MSIOF6_RXD_B GP_ALTSEL_FUNC(7, 27, 0)
+#define ALT_MSIOF6_TXD_B GP_ALTSEL_FUNC(7, 26, 0)
+#define ALT_MSIOF6_SCK_B GP_ALTSEL_FUNC(7, 25, 0)
+#define ALT_MSIOF5_SS2 GP_ALTSEL_FUNC(7, 24, 0)
+#define ALT_MSIOF5_SS1 GP_ALTSEL_FUNC(7, 23, 0)
+#define ALT_MSIOF5_SYNC GP_ALTSEL_FUNC(7, 22, 0)
+#define ALT_MSIOF5_RXD GP_ALTSEL_FUNC(7, 21, 0)
+#define ALT_MSIOF5_TXD GP_ALTSEL_FUNC(7, 20, 0)
+#define ALT_MSIOF5_SCK GP_ALTSEL_FUNC(7, 17, 0)
+#define ALT_AUDIO_CLKC_A GP_ALTSEL_FUNC(7, 16, 0)
+#define ALT_SSI6_SD GP_ALTSEL_FUNC(7, 15, 0)
+#define ALT_SSI6_WS GP_ALTSEL_FUNC(7, 14, 0)
+#define ALT_SSI6_SCK GP_ALTSEL_FUNC(7, 13, 0)
+#define ALT_AUDIO_CLKB_A GP_ALTSEL_FUNC(7, 12, 0)
+#define ALT_SSI5_SD GP_ALTSEL_FUNC(7, 11, 0)
+#define ALT_SSI5_WS GP_ALTSEL_FUNC(7, 10, 0)
+#define ALT_SSI5_SCK GP_ALTSEL_FUNC(7, 9, 0)
+#define ALT_AUDIO_CLKA_A GP_ALTSEL_FUNC(7, 8, 0)
+#define ALT_SSI4_SD GP_ALTSEL_FUNC(7, 7, 0)
+#define ALT_SSI4_WS GP_ALTSEL_FUNC(7, 6, 0)
+#define ALT_SSI4_SCK GP_ALTSEL_FUNC(7, 5, 0)
+#define ALT_AUDIO1_CLKOUT3 GP_ALTSEL_FUNC(7, 4, 0)
+#define ALT_AUDIO1_CLKOUT2 GP_ALTSEL_FUNC(7, 3, 0)
+#define ALT_SSI3_SD GP_ALTSEL_FUNC(7, 2, 0)
+#define ALT_SSI3_WS GP_ALTSEL_FUNC(7, 1, 0)
+#define ALT_SSI3_SCK GP_ALTSEL_FUNC(7, 0, 0)
+
+/* GP7 ALTSEL function 1 */
+#define ALT_HRX2_B GP_ALTSEL_FUNC(7, 30, 1)
+#define ALT_SSI7_SD GP_ALTSEL_FUNC(7, 29, 1)
+#define ALT_SSI7_WS GP_ALTSEL_FUNC(7, 28, 1)
+#define ALT_SSI7_SCK GP_ALTSEL_FUNC(7, 27, 1)
+#define ALT_HTX2_B GP_ALTSEL_FUNC(7, 26, 1)
+#define ALT_SSI8_SD GP_ALTSEL_FUNC(7, 25, 1)
+#define ALT_HCTS2_N_B GP_ALTSEL_FUNC(7, 24, 1)
+#define ALT_RIF0_SYNC_A GP_ALTSEL_FUNC(7, 23, 1)
+#define ALT_HRTS2_N_B GP_ALTSEL_FUNC(7, 22, 1)
+#define ALT_RIF0_D1_A GP_ALTSEL_FUNC(7, 21, 1)
+#define ALT_HSCK2_B GP_ALTSEL_FUNC(7, 20, 1)
+#define ALT_MSIOF6_SS2_A GP_ALTSEL_FUNC(7, 19, 1)
+#define ALT_MSIOF6_SS1_A GP_ALTSEL_FUNC(7, 18, 1)
+#define ALT_MSIOF6_RXD_A GP_ALTSEL_FUNC(7, 15, 1)
+#define ALT_MSIOF6_TXD_A GP_ALTSEL_FUNC(7, 14, 1)
+#define ALT_MSIOF6_SCK_A GP_ALTSEL_FUNC(7, 13, 1)
+#define ALT_MSIOF6_SYNC_A GP_ALTSEL_FUNC(7, 11, 1)
+#define ALT_RIF3_SYNC GP_ALTSEL_FUNC(7, 10, 1)
+#define ALT_RIF3_CLK GP_ALTSEL_FUNC(7, 9, 1)
+#define ALT_RIF3_D1 GP_ALTSEL_FUNC(7, 7, 1)
+#define ALT_RIF3_D0 GP_ALTSEL_FUNC(7, 6, 1)
+#define ALT_RIF2_CLK GP_ALTSEL_FUNC(7, 5, 1)
+#define ALT_RIF0_D0_A GP_ALTSEL_FUNC(7, 4, 1)
+#define ALT_RIF0_CLK_A GP_ALTSEL_FUNC(7, 3, 1)
+#define ALT_MSIOF7_SS2_B GP_ALTSEL_FUNC(7, 2, 1)
+#define ALT_MSIOF7_SS1_B GP_ALTSEL_FUNC(7, 1, 1)
+#define ALT_MSIOF7_SYNC_B GP_ALTSEL_FUNC(7, 0, 1)
+
+/* GP7 ALTSEL function 2 */
+#define ALT_RX4_B GP_ALTSEL_FUNC(7, 30, 2)
+#define ALT_TX4_B GP_ALTSEL_FUNC(7, 26, 2)
+#define ALT_CTS4_N_B GP_ALTSEL_FUNC(7, 24, 2)
+#define ALT_RTS4_N_B GP_ALTSEL_FUNC(7, 22, 2)
+#define ALT_SCK4_B GP_ALTSEL_FUNC(7, 20, 2)
+#define ALT_RIF4_D1 GP_ALTSEL_FUNC(7, 15, 2)
+#define ALT_RIF4_D0 GP_ALTSEL_FUNC(7, 14, 2)
+#define ALT_RIF4_SYNC GP_ALTSEL_FUNC(7, 13, 2)
+#define ALT_RIF4_CLK GP_ALTSEL_FUNC(7, 11, 2)
+#define ALT_RIF5_D1 GP_ALTSEL_FUNC(7, 1, 2)
+#define ALT_RIF5_D0 GP_ALTSEL_FUNC(7, 0, 2)
+
+/* GP8 ALTSEL function 0 */
+#define ALT_S3DA2 GP_ALTSEL_FUNC(8, 31, 0)
+#define ALT_S3CL2 GP_ALTSEL_FUNC(8, 30, 0)
+#define ALT_S3DA1 GP_ALTSEL_FUNC(8, 29, 0)
+#define ALT_S3CL1 GP_ALTSEL_FUNC(8, 28, 0)
+#define ALT_S3DA0 GP_ALTSEL_FUNC(8, 27, 0)
+#define ALT_S3CL0 GP_ALTSEL_FUNC(8, 26, 0)
+#define ALT_SDA8 GP_ALTSEL_FUNC(8, 15, 0)
+#define ALT_SCL8 GP_ALTSEL_FUNC(8, 14, 0)
+#define ALT_SDA7 GP_ALTSEL_FUNC(8, 13, 0)
+#define ALT_SCL7 GP_ALTSEL_FUNC(8, 12, 0)
+#define ALT_SDA6 GP_ALTSEL_FUNC(8, 11, 0)
+#define ALT_SCL6 GP_ALTSEL_FUNC(8, 10, 0)
+#define ALT_SDA5 GP_ALTSEL_FUNC(8, 9, 0)
+#define ALT_SCL5 GP_ALTSEL_FUNC(8, 8, 0)
+#define ALT_SDA4 GP_ALTSEL_FUNC(8, 7, 0)
+#define ALT_SCL4 GP_ALTSEL_FUNC(8, 6, 0)
+#define ALT_SDA3 GP_ALTSEL_FUNC(8, 5, 0)
+#define ALT_SCL3 GP_ALTSEL_FUNC(8, 4, 0)
+#define ALT_SDA2 GP_ALTSEL_FUNC(8, 3, 0)
+#define ALT_SCL2 GP_ALTSEL_FUNC(8, 2, 0)
+#define ALT_SDA1 GP_ALTSEL_FUNC(8, 1, 0)
+#define ALT_SCL1 GP_ALTSEL_FUNC(8, 0, 0)
+
+/* GP8 ALTSEL function 1 */
+#define ALT_HCTS2_N_A GP_ALTSEL_FUNC(8, 7, 1)
+#define ALT_HRTS2_N_A GP_ALTSEL_FUNC(8, 6, 1)
+#define ALT_HRX2_A GP_ALTSEL_FUNC(8, 5, 1)
+#define ALT_HTX2_A GP_ALTSEL_FUNC(8, 4, 1)
+#define ALT_HSCK2_A GP_ALTSEL_FUNC(8, 3, 1)
+#define ALT_PWM0_B GP_ALTSEL_FUNC(8, 2, 1)
+
+/* GP8 ALTSEL function 2 */
+#define ALT_CTS4_N_A GP_ALTSEL_FUNC(8, 7, 2)
+#define ALT_RTS4_N_A GP_ALTSEL_FUNC(8, 6, 2)
+#define ALT_RX4_A GP_ALTSEL_FUNC(8, 5, 2)
+#define ALT_TX4_A GP_ALTSEL_FUNC(8, 4, 2)
+#define ALT_SCK4_A GP_ALTSEL_FUNC(8, 3, 2)
+
+/* GP8 ALTSEL function 3 */
+#define ALT_PWM7_B GP_ALTSEL_FUNC(8, 7, 3)
+#define ALT_PWM9_B GP_ALTSEL_FUNC(8, 6, 3)
+#define ALT_PWM8_B GP_ALTSEL_FUNC(8, 5, 3)
+#define ALT_PWM6_B GP_ALTSEL_FUNC(8, 4, 3)
+
+/* GP9 ALTSEL function 0 */
+#define ALT_RSW3_MATCH GP_ALTSEL_FUNC(9, 16, 0)
+#define ALT_RSW3_CAPTURE GP_ALTSEL_FUNC(9, 15, 0)
+#define ALT_RSW3_PPS GP_ALTSEL_FUNC(9, 14, 0)
+#define ALT_ETH10G0_PHYINT GP_ALTSEL_FUNC(9, 13, 0)
+#define ALT_ETH10G0_LINK GP_ALTSEL_FUNC(9, 12, 0)
+#define ALT_ETH10G0_MDC GP_ALTSEL_FUNC(9, 11, 0)
+#define ALT_ETH10G0_MDIO GP_ALTSEL_FUNC(9, 10, 0)
+#define ALT_ETH25G0_PHYINT GP_ALTSEL_FUNC(9, 9, 0)
+#define ALT_ETH25G0_LINK GP_ALTSEL_FUNC(9, 8, 0)
+#define ALT_ETH25G0_MDC GP_ALTSEL_FUNC(9, 7, 0)
+#define ALT_ETH25G0_MDIO GP_ALTSEL_FUNC(9, 6, 0)
+#define ALT_ETHES4_MATCH GP_ALTSEL_FUNC(9, 5, 0)
+#define ALT_ETHES4_CAPTURE GP_ALTSEL_FUNC(9, 4, 0)
+#define ALT_ETHES4_PPS GP_ALTSEL_FUNC(9, 3, 0)
+#define ALT_ETHES0_MATCH GP_ALTSEL_FUNC(9, 2, 0)
+#define ALT_ETHES0_CAPTURE GP_ALTSEL_FUNC(9, 1, 0)
+#define ALT_ETHES0_PPS GP_ALTSEL_FUNC(9, 0, 0)
+
+/* GP9 ALTSEL function 1 */
+#define ALT_ETH10G1_PHYINT GP_ALTSEL_FUNC(9, 13, 1)
+#define ALT_ETH10G1_LINK GP_ALTSEL_FUNC(9, 12, 1)
+#define ALT_ETH10G1_MDC GP_ALTSEL_FUNC(9, 11, 1)
+#define ALT_ETH10G1_MDIO GP_ALTSEL_FUNC(9, 10, 1)
+#define ALT_ETH25G1_PHYINT GP_ALTSEL_FUNC(9, 9, 1)
+#define ALT_ETH25G1_LINK GP_ALTSEL_FUNC(9, 8, 1)
+#define ALT_ETH25G1_MDC GP_ALTSEL_FUNC(9, 7, 1)
+#define ALT_ETH25G1_MDIO GP_ALTSEL_FUNC(9, 6, 1)
+#define ALT_ETHES5_MATCH GP_ALTSEL_FUNC(9, 5, 1)
+#define ALT_ETHES5_CAPTURE GP_ALTSEL_FUNC(9, 4, 1)
+#define ALT_ETHES5_PPS GP_ALTSEL_FUNC(9, 3, 1)
+#define ALT_ETHES1_MATCH GP_ALTSEL_FUNC(9, 2, 1)
+#define ALT_ETHES1_CAPTURE GP_ALTSEL_FUNC(9, 1, 1)
+#define ALT_ETHES1_PPS GP_ALTSEL_FUNC(9, 0, 1)
+
+/* GP9 ALTSEL function 2 */
+#define ALT_ETH25G2_PHYINT GP_ALTSEL_FUNC(9, 9, 2)
+#define ALT_ETH25G2_LINK GP_ALTSEL_FUNC(9, 8, 2)
+#define ALT_ETH25G2_MDC GP_ALTSEL_FUNC(9, 7, 2)
+#define ALT_ETH25G2_MDIO GP_ALTSEL_FUNC(9, 6, 2)
+#define ALT_ETHES6_MATCH GP_ALTSEL_FUNC(9, 5, 2)
+#define ALT_ETHES6_CAPTURE GP_ALTSEL_FUNC(9, 4, 2)
+#define ALT_ETHES6_PPS GP_ALTSEL_FUNC(9, 3, 2)
+#define ALT_ETHES2_MATCH GP_ALTSEL_FUNC(9, 2, 2)
+#define ALT_ETHES2_CAPTURE GP_ALTSEL_FUNC(9, 1, 2)
+#define ALT_ETHES2_PPS GP_ALTSEL_FUNC(9, 0, 2)
+
+/* GP9 ALTSEL function 3 */
+#define ALT_PWM9_A GP_ALTSEL_FUNC(9, 16, 0)
+#define ALT_PWM8_A GP_ALTSEL_FUNC(9, 15, 0)
+#define ALT_PWM7_A GP_ALTSEL_FUNC(9, 12, 0)
+#define ALT_IRQ3_B GP_ALTSEL_FUNC(9, 11, 0)
+#define ALT_IRQ2_B GP_ALTSEL_FUNC(9, 10, 0)
+#define ALT_PWM6_A GP_ALTSEL_FUNC(9, 8, 0)
+#define ALT_ETHES7_MATCH GP_ALTSEL_FUNC(9, 5, 0)
+#define ALT_ETHES7_CAPTURE GP_ALTSEL_FUNC(9, 4, 0)
+#define ALT_ETHES7_PPS GP_ALTSEL_FUNC(9, 3, 0)
+#define ALT_ETHES3_MATCH GP_ALTSEL_FUNC(9, 2, 0)
+#define ALT_ETHES3_CAPTURE GP_ALTSEL_FUNC(9, 1, 0)
+#define ALT_ETHES3_PPS GP_ALTSEL_FUNC(9, 0, 0)
+
+/* GP10 ALTSEL function 0 */
+#define ALT_PCIE41_CLKREQ_N GP_ALTSEL_FUNC(10, 13, 0)
+#define ALT_PCIE40_CLKREQ_N GP_ALTSEL_FUNC(10, 12, 0)
+#define ALT_USB3_VBUS_VALID GP_ALTSEL_FUNC(10, 11, 0)
+#define ALT_USB3_OVC GP_ALTSEL_FUNC(10, 10, 0)
+#define ALT_USB3_PWEN GP_ALTSEL_FUNC(10, 9, 0)
+#define ALT_USB2_VBUS_VALID GP_ALTSEL_FUNC(10, 8, 0)
+#define ALT_USB2_OVC GP_ALTSEL_FUNC(10, 7, 0)
+#define ALT_USB2_PWEN GP_ALTSEL_FUNC(10, 6, 0)
+#define ALT_USB1_VBUS_VALID GP_ALTSEL_FUNC(10, 5, 0)
+#define ALT_USB1_OVC GP_ALTSEL_FUNC(10, 4, 0)
+#define ALT_USB1_PWEN GP_ALTSEL_FUNC(10, 3, 0)
+#define ALT_USB0_VBUS_VALID GP_ALTSEL_FUNC(10, 2, 0)
+#define ALT_USB0_OVC GP_ALTSEL_FUNC(10, 1, 0)
+#define ALT_USB0_PWEN GP_ALTSEL_FUNC(10, 0, 0)
+
+#define PINMUX_GFUNC_GPSR(grp_func, fn) \
+fn##_MARK, ALT_##fn, FN_##grp_func, 0
+
+#define PINMUX_GFUNC_MSEL_GPSR(grp_func, fn, msel) \
+fn##_MARK, ALT_##fn, FN_##msel, FN_##grp_func, 0
+
+#define PINMUX_GFUNC_MSELMARK_GPSR(grp_func, fn, msel) \
+msel##_MARK, ALT_##fn, FN_##msel, FN_##grp_func, 0
+
+static const u16 pinmux_data[] = {
+ PINMUX_DATA_GP_ALL(),
+
+ /* Group0 Functions */
+ PINMUX_GFUNC_GPSR(GRP0_27_FUNC, DP2_HOTPLUG),
+
+ PINMUX_GFUNC_GPSR(GRP0_26_FUNC, DP1_HOTPLUG),
+
+ PINMUX_GFUNC_GPSR(GRP0_25_FUNC, DP0_HOTPLUG),
+
+ PINMUX_GFUNC_GPSR(GRP0_24_FUNC, MSIOF1_SS2_A),
+ PINMUX_GFUNC_GPSR(GRP0_24_FUNC, TAUD0O13),
+
+ PINMUX_GFUNC_GPSR(GRP0_23_FUNC, MSIOF1_SS1_A),
+ PINMUX_GFUNC_GPSR(GRP0_23_FUNC, TAUD0O12),
+
+ PINMUX_GFUNC_GPSR(GRP0_22_FUNC, MSIOF1_SYNC_A),
+ PINMUX_GFUNC_GPSR(GRP0_22_FUNC, TAUD0O11),
+
+ PINMUX_GFUNC_GPSR(GRP0_21_FUNC, MSIOF1_RXD_A),
+ PINMUX_GFUNC_GPSR(GRP0_21_FUNC, TAUD0O10),
+
+ PINMUX_GFUNC_GPSR(GRP0_20_FUNC, MSIOF1_TXD_A),
+ PINMUX_GFUNC_GPSR(GRP0_20_FUNC, TAUD0O9),
+
+ PINMUX_GFUNC_GPSR(GRP0_19_FUNC, MSIOF1_SCK_A),
+ PINMUX_GFUNC_GPSR(GRP0_19_FUNC, TAUD0O8),
+
+ PINMUX_GFUNC_GPSR(GRP0_18_FUNC, MSIOF0_SS2),
+ PINMUX_GFUNC_GPSR(GRP0_18_FUNC, TAUD0O7),
+
+ PINMUX_GFUNC_GPSR(GRP0_17_FUNC, MSIOF0_SS1),
+ PINMUX_GFUNC_GPSR(GRP0_17_FUNC, TAUD0O6),
+
+ PINMUX_GFUNC_GPSR(GRP0_16_FUNC, MSIOF0_SYNC),
+ PINMUX_GFUNC_GPSR(GRP0_16_FUNC, TAUD0O5),
+
+ PINMUX_GFUNC_GPSR(GRP0_15_FUNC, MSIOF0_RXD),
+ PINMUX_GFUNC_GPSR(GRP0_15_FUNC, TAUD0O4),
+
+ PINMUX_GFUNC_GPSR(GRP0_14_FUNC, MSIOF0_TXD),
+ PINMUX_GFUNC_GPSR(GRP0_14_FUNC, TAUD0O3),
+
+ PINMUX_GFUNC_GPSR(GRP0_13_FUNC, MSIOF0_SCK),
+ PINMUX_GFUNC_GPSR(GRP0_13_FUNC, TAUD0O2),
+
+ PINMUX_GFUNC_GPSR(GRP0_12_FUNC, RXDB_EXTFXR_A),
+ PINMUX_GFUNC_GPSR(GRP0_12_FUNC, CAN11TX),
+ PINMUX_GFUNC_GPSR(GRP0_12_FUNC, RLIN311TX),
+ PINMUX_GFUNC_GPSR(GRP0_12_FUNC, RTCA0OUT_A),
+
+ PINMUX_GFUNC_GPSR(GRP0_11_FUNC, FXR_TXENB_N_A),
+ PINMUX_GFUNC_GPSR(GRP0_11_FUNC, CAN11RX_INTP11),
+ PINMUX_GFUNC_GPSR(GRP0_11_FUNC, RLIN311RX_INTP27),
+ PINMUX_GFUNC_GPSR(GRP0_11_FUNC, EXTCLK0O_A),
+
+ PINMUX_GFUNC_GPSR(GRP0_10_FUNC, FXR_TXDB_A),
+ PINMUX_GFUNC_GPSR(GRP0_10_FUNC, CAN10TX),
+ PINMUX_GFUNC_GPSR(GRP0_10_FUNC, RLIN310TX),
+
+ PINMUX_GFUNC_GPSR(GRP0_9_FUNC, RXDA_EXTFXR_A),
+ PINMUX_GFUNC_GPSR(GRP0_9_FUNC, CAN10RX_INTP10),
+ PINMUX_GFUNC_GPSR(GRP0_9_FUNC, RLIN310RX_INTP26),
+
+ PINMUX_GFUNC_GPSR(GRP0_8_FUNC, FXR_TXENA_N_A),
+ PINMUX_GFUNC_GPSR(GRP0_8_FUNC, CAN9TX),
+ PINMUX_GFUNC_GPSR(GRP0_8_FUNC, RLIN39TX),
+ PINMUX_GFUNC_GPSR(GRP0_8_FUNC, TAUD1O15),
+
+ PINMUX_GFUNC_GPSR(GRP0_7_FUNC, FXR_TXDA_A),
+ PINMUX_GFUNC_GPSR(GRP0_7_FUNC, CAN9RX_INTP9),
+ PINMUX_GFUNC_GPSR(GRP0_7_FUNC, RLIN39RX_INTP25),
+ PINMUX_GFUNC_GPSR(GRP0_7_FUNC, TAUD1O14),
+
+ PINMUX_GFUNC_GPSR(GRP0_6_FUNC, CLK_EXTFXR_A),
+ PINMUX_GFUNC_GPSR(GRP0_6_FUNC, CAN8TX),
+ PINMUX_GFUNC_GPSR(GRP0_6_FUNC, RLIN38TX),
+ PINMUX_GFUNC_GPSR(GRP0_6_FUNC, TAUD1O13),
+
+ PINMUX_GFUNC_GPSR(GRP0_5_FUNC, FXR_CLKOUT2_A),
+ PINMUX_GFUNC_GPSR(GRP0_5_FUNC, CAN8RX_INTP8),
+ PINMUX_GFUNC_GPSR(GRP0_5_FUNC, RLIN38RX_INTP24),
+ PINMUX_GFUNC_GPSR(GRP0_5_FUNC, TAUD1O12),
+
+ PINMUX_GFUNC_GPSR(GRP0_4_FUNC, FXR_CLKOUT1_A),
+ PINMUX_GFUNC_GPSR(GRP0_4_FUNC, CAN7TX),
+ PINMUX_GFUNC_GPSR(GRP0_4_FUNC, RLIN315TX_A),
+ PINMUX_GFUNC_GPSR(GRP0_4_FUNC, TAUD1O11),
+
+ PINMUX_GFUNC_GPSR(GRP0_3_FUNC, STPWT_EXTFXR_A),
+ PINMUX_GFUNC_GPSR(GRP0_3_FUNC, CAN7RX_INTP7),
+ PINMUX_GFUNC_GPSR(GRP0_3_FUNC, RLIN315RX_INTP31_A),
+ PINMUX_GFUNC_GPSR(GRP0_3_FUNC, TAUD1O10),
+
+ /* Group1 Functions */
+ PINMUX_GFUNC_GPSR(GRP1_21_FUNC, RLIN33TX),
+ PINMUX_GFUNC_MSELMARK_GPSR(GRP1_21_FUNC, TAUJ1I3_TAUJ1O3, SEL_TAUJ13_OUTPUT),
+ PINMUX_GFUNC_MSELMARK_GPSR(GRP1_21_FUNC, TAUJ1I3_TAUJ1O3, SEL_TAUJ13_INPUT),
+ PINMUX_GFUNC_GPSR(GRP1_21_FUNC, CAN15TX_A),
+
+ PINMUX_GFUNC_GPSR(GRP1_20_FUNC, RLIN33RX_INTP19),
+ PINMUX_GFUNC_MSELMARK_GPSR(GRP1_20_FUNC, TAUJ1I2_TAUJ1O2, SEL_TAUJ12_OUTPUT),
+ PINMUX_GFUNC_MSELMARK_GPSR(GRP1_20_FUNC, TAUJ1I2_TAUJ1O2, SEL_TAUJ12_INPUT),
+ PINMUX_GFUNC_GPSR(GRP1_20_FUNC, CAN15RX_INTP15_A),
+
+ PINMUX_GFUNC_GPSR(GRP1_19_FUNC, RLIN32TX),
+ PINMUX_GFUNC_MSELMARK_GPSR(GRP1_19_FUNC, TAUJ1I1_TAUJ1O1, SEL_TAUJ11_OUTPUT),
+ PINMUX_GFUNC_MSELMARK_GPSR(GRP1_19_FUNC, TAUJ1I1_TAUJ1O1, SEL_TAUJ11_INPUT),
+ PINMUX_GFUNC_GPSR(GRP1_19_FUNC, CAN14TX_A),
+ PINMUX_GFUNC_GPSR(GRP1_19_FUNC, NMI1_A),
+
+ PINMUX_GFUNC_GPSR(GRP1_18_FUNC, RLIN32RX_INTP18),
+ PINMUX_GFUNC_MSELMARK_GPSR(GRP1_18_FUNC, TAUJ1I0_TAUJ1O0, SEL_TAUJ10_OUTPUT),
+ PINMUX_GFUNC_MSELMARK_GPSR(GRP1_18_FUNC, TAUJ1I0_TAUJ1O0, SEL_TAUJ10_INPUT),
+ PINMUX_GFUNC_GPSR(GRP1_18_FUNC, CAN14RX_INTP14_A),
+ PINMUX_GFUNC_GPSR(GRP1_18_FUNC, INTP34_A),
+
+ PINMUX_GFUNC_GPSR(GRP1_17_FUNC, RLIN31TX),
+ PINMUX_GFUNC_MSELMARK_GPSR(GRP1_17_FUNC, TAUJ3I3_TAUJ3O3, SEL_TAUJ33_OUTPUT),
+ PINMUX_GFUNC_MSELMARK_GPSR(GRP1_17_FUNC, TAUJ3I3_TAUJ3O3, SEL_TAUJ33_INPUT),
+ PINMUX_GFUNC_GPSR(GRP1_17_FUNC, CAN13TX_A),
+ PINMUX_GFUNC_GPSR(GRP1_17_FUNC, INTP33_A),
+
+ PINMUX_GFUNC_GPSR(GRP1_16_FUNC, RLIN31RX_INTP17),
+ PINMUX_GFUNC_MSELMARK_GPSR(GRP1_16_FUNC, TAUJ3I2_TAUJ3O2, SEL_TAUJ32_OUTPUT),
+ PINMUX_GFUNC_MSELMARK_GPSR(GRP1_16_FUNC, TAUJ3I2_TAUJ3O2, SEL_TAUJ32_INPUT),
+ PINMUX_GFUNC_GPSR(GRP1_16_FUNC, CAN13RX_INTP13_A),
+ PINMUX_GFUNC_GPSR(GRP1_16_FUNC, INTP32_A),
+
+ PINMUX_GFUNC_GPSR(GRP1_15_FUNC, RLIN30TX),
+ PINMUX_GFUNC_MSELMARK_GPSR(GRP1_15_FUNC, TAUJ3I1_TAUJ3O1, SEL_TAUJ31_OUTPUT),
+ PINMUX_GFUNC_MSELMARK_GPSR(GRP1_15_FUNC, TAUJ3I1_TAUJ3O1, SEL_TAUJ31_INPUT),
+ PINMUX_GFUNC_GPSR(GRP1_15_FUNC, CAN12TX_A),
+
+ PINMUX_GFUNC_GPSR(GRP1_14_FUNC, RLIN30RX_INTP16),
+ PINMUX_GFUNC_MSELMARK_GPSR(GRP1_14_FUNC, TAUJ3I0_TAUJ3O0, SEL_TAUJ30_OUTPUT),
+ PINMUX_GFUNC_MSELMARK_GPSR(GRP1_14_FUNC, TAUJ3I0_TAUJ3O0, SEL_TAUJ30_INPUT),
+ PINMUX_GFUNC_GPSR(GRP1_14_FUNC, CAN12RX_INTP12_A),
+
+ PINMUX_GFUNC_GPSR(GRP1_13_FUNC, CAN6TX),
+ PINMUX_GFUNC_GPSR(GRP1_13_FUNC, RLIN314TX_A),
+ PINMUX_GFUNC_GPSR(GRP1_13_FUNC, TAUD1O9),
+
+ PINMUX_GFUNC_GPSR(GRP1_12_FUNC, CAN6RX_INTP6),
+ PINMUX_GFUNC_GPSR(GRP1_12_FUNC, RLIN314RX_INTP30_A),
+ PINMUX_GFUNC_GPSR(GRP1_12_FUNC, TAUD1O8),
+
+ PINMUX_GFUNC_GPSR(GRP1_11_FUNC, CAN5TX),
+ PINMUX_GFUNC_GPSR(GRP1_11_FUNC, RLIN313TX_A),
+ PINMUX_GFUNC_GPSR(GRP1_11_FUNC, MSIOF3_SS2),
+ PINMUX_GFUNC_GPSR(GRP1_11_FUNC, RXDB_EXTFXR_B),
+
+ PINMUX_GFUNC_GPSR(GRP1_10_FUNC, CAN5RX_INTP5),
+ PINMUX_GFUNC_GPSR(GRP1_10_FUNC, RLIN313RX_INTP29_A),
+ PINMUX_GFUNC_GPSR(GRP1_10_FUNC, MSIOF3_SS1),
+ PINMUX_GFUNC_GPSR(GRP1_10_FUNC, FXR_TXENB_N_B),
+
+ PINMUX_GFUNC_GPSR(GRP1_9_FUNC, CAN4TX),
+ PINMUX_GFUNC_GPSR(GRP1_9_FUNC, RLIN312TX_A),
+ PINMUX_GFUNC_GPSR(GRP1_9_FUNC, MSIOF3_SYNC),
+ PINMUX_GFUNC_GPSR(GRP1_9_FUNC, FXR_TXDB_B),
+
+ PINMUX_GFUNC_GPSR(GRP1_8_FUNC, CAN4RX_INTP4),
+ PINMUX_GFUNC_GPSR(GRP1_8_FUNC, RLIN312RX_INTP28_A),
+ PINMUX_GFUNC_GPSR(GRP1_8_FUNC, MSIOF3_RXD),
+ PINMUX_GFUNC_GPSR(GRP1_8_FUNC, RXDA_EXTFXR_B),
+
+ PINMUX_GFUNC_GPSR(GRP1_7_FUNC, CAN3TX),
+ PINMUX_GFUNC_GPSR(GRP1_7_FUNC, RLIN37TX_A),
+ PINMUX_GFUNC_GPSR(GRP1_7_FUNC, MSIOF3_TXD),
+ PINMUX_GFUNC_GPSR(GRP1_7_FUNC, FXR_TXENA_N_B),
+
+ PINMUX_GFUNC_GPSR(GRP1_6_FUNC, CAN3RX_INTP3),
+ PINMUX_GFUNC_GPSR(GRP1_6_FUNC, RLIN37RX_INTP23_A),
+ PINMUX_GFUNC_GPSR(GRP1_6_FUNC, MSIOF3_SCK),
+ PINMUX_GFUNC_GPSR(GRP1_6_FUNC, FXR_TXDA_B),
+
+ PINMUX_GFUNC_GPSR(GRP1_5_FUNC, CAN2TX),
+ PINMUX_GFUNC_GPSR(GRP1_5_FUNC, RLIN36TX_A),
+ PINMUX_GFUNC_GPSR(GRP1_5_FUNC, MSIOF2_SS2),
+ PINMUX_GFUNC_GPSR(GRP1_5_FUNC, CLK_EXTFXR_B),
+
+ PINMUX_GFUNC_GPSR(GRP1_4_FUNC, CAN2RX_INTP2),
+ PINMUX_GFUNC_GPSR(GRP1_4_FUNC, RLIN36RX_INTP22_A),
+ PINMUX_GFUNC_GPSR(GRP1_4_FUNC, MSIOF2_SS1),
+ PINMUX_GFUNC_GPSR(GRP1_4_FUNC, FXR_CLKOUT2_B),
+
+ PINMUX_GFUNC_GPSR(GRP1_3_FUNC, CAN1TX),
+ PINMUX_GFUNC_GPSR(GRP1_3_FUNC, RLIN35TX_A),
+ PINMUX_GFUNC_GPSR(GRP1_3_FUNC, MSIOF2_SYNC),
+ PINMUX_GFUNC_GPSR(GRP1_3_FUNC, FXR_CLKOUT1_B),
+
+ PINMUX_GFUNC_GPSR(GRP1_2_FUNC, CAN1RX_INTP1),
+ PINMUX_GFUNC_GPSR(GRP1_2_FUNC, RLIN35RX_INTP21_A),
+ PINMUX_GFUNC_GPSR(GRP1_2_FUNC, MSIOF2_RXD),
+ PINMUX_GFUNC_GPSR(GRP1_2_FUNC, STPWT_EXTFXR_B),
+
+ PINMUX_GFUNC_GPSR(GRP1_1_FUNC, CAN0TX),
+ PINMUX_GFUNC_GPSR(GRP1_1_FUNC, RLIN34TX_A),
+ PINMUX_GFUNC_GPSR(GRP1_1_FUNC, MSIOF2_TXD),
+
+ PINMUX_GFUNC_GPSR(GRP1_0_FUNC, CAN0RX_INTP0),
+ PINMUX_GFUNC_GPSR(GRP1_0_FUNC, RLIN34RX_INTP20_A),
+ PINMUX_GFUNC_GPSR(GRP1_0_FUNC, MSIOF2_SCK),
+
+ /* Group2 Functions */
+ PINMUX_GFUNC_GPSR(GRP2_28_FUNC, INTP34_B),
+
+ PINMUX_GFUNC_GPSR(GRP2_27_FUNC, TAUD1O3),
+
+ PINMUX_GFUNC_GPSR(GRP2_26_FUNC, TAUD1O2),
+
+ PINMUX_GFUNC_GPSR(GRP2_25_FUNC, TAUD1O1),
+
+ PINMUX_GFUNC_GPSR(GRP2_24_FUNC, TAUD1O0),
+
+ PINMUX_GFUNC_GPSR(GRP2_23_FUNC, EXTCLK0O_B),
+
+ PINMUX_GFUNC_GPSR(GRP2_22_FUNC, AVS1),
+
+ PINMUX_GFUNC_GPSR(GRP2_21_FUNC, AVS0),
+
+ PINMUX_GFUNC_MSEL_GPSR(GRP2_20_FUNC, SDA0, SEL_SDA0_1),
+
+ PINMUX_GFUNC_MSEL_GPSR(GRP2_19_FUNC, SCL0, SEL_SCL0_1),
+
+ PINMUX_GFUNC_GPSR(GRP2_18_FUNC, INTP33_B),
+ PINMUX_GFUNC_GPSR(GRP2_18_FUNC, TAUD0O1),
+
+ PINMUX_GFUNC_GPSR(GRP2_17_FUNC, INTP32_B),
+ PINMUX_GFUNC_GPSR(GRP2_17_FUNC, TAUD0O0),
+
+ PINMUX_GFUNC_GPSR(GRP2_16_FUNC, CAN_CLK),
+
+ PINMUX_GFUNC_GPSR(GRP2_15_FUNC, CAN15TX_B),
+ PINMUX_GFUNC_GPSR(GRP2_15_FUNC, RLIN315TX_B),
+
+ PINMUX_GFUNC_GPSR(GRP2_14_FUNC, CAN15RX_B_INTP15),
+ PINMUX_GFUNC_GPSR(GRP2_14_FUNC, RLIN315RX_INTP31_B),
+
+ PINMUX_GFUNC_GPSR(GRP2_13_FUNC, CAN14TX_B),
+ PINMUX_GFUNC_GPSR(GRP2_13_FUNC, RLIN314TX_B),
+
+ PINMUX_GFUNC_GPSR(GRP2_12_FUNC, CAN14RX_B_INTP14),
+ PINMUX_GFUNC_GPSR(GRP2_12_FUNC, RLIN314RX_INTP30_B),
+
+ PINMUX_GFUNC_GPSR(GRP2_11_FUNC, CAN13TX_B),
+ PINMUX_GFUNC_GPSR(GRP2_11_FUNC, RLIN313TX),
+ PINMUX_GFUNC_GPSR(GRP2_11_FUNC, CANXL1_TX),
+
+ PINMUX_GFUNC_GPSR(GRP2_10_FUNC, CAN13RX_B_INTP13),
+ PINMUX_GFUNC_GPSR(GRP2_10_FUNC, RLIN313RX_INTP29_B),
+ PINMUX_GFUNC_GPSR(GRP2_10_FUNC, CANXL1_RX),
+
+ PINMUX_GFUNC_GPSR(GRP2_9_FUNC, CAN12TX_B),
+ PINMUX_GFUNC_GPSR(GRP2_9_FUNC, RLIN312TX),
+ PINMUX_GFUNC_GPSR(GRP2_9_FUNC, TAUD1O7),
+ PINMUX_GFUNC_GPSR(GRP2_9_FUNC, CANXL0_TX),
+
+ PINMUX_GFUNC_GPSR(GRP2_8_FUNC, CAN12RX_B_INTP12),
+ PINMUX_GFUNC_GPSR(GRP2_8_FUNC, RLIN312RX_INTP28_B),
+ PINMUX_GFUNC_GPSR(GRP2_8_FUNC, TAUD1O6),
+ PINMUX_GFUNC_GPSR(GRP2_8_FUNC, CANXL0_RX),
+
+ PINMUX_GFUNC_GPSR(GRP2_7_FUNC, RLIN37TX_B),
+ PINMUX_GFUNC_GPSR(GRP2_7_FUNC, RTCA0OUT_B),
+ PINMUX_GFUNC_GPSR(GRP2_7_FUNC, TAUD1O5),
+
+ PINMUX_GFUNC_GPSR(GRP2_6_FUNC, RLIN37RX_B_INTP23),
+ PINMUX_GFUNC_GPSR(GRP2_6_FUNC, TAUD1O4),
+
+ PINMUX_GFUNC_GPSR(GRP2_5_FUNC, RLIN36TX_B),
+ PINMUX_GFUNC_GPSR(GRP2_5_FUNC, MSIOF1_SS2_B),
+
+ PINMUX_GFUNC_GPSR(GRP2_4_FUNC, RLIN36RX_B_INTP22),
+ PINMUX_GFUNC_GPSR(GRP2_4_FUNC, MSIOF1_SS1_B),
+ PINMUX_GFUNC_GPSR(GRP2_4_FUNC, CTIACK),
+
+ PINMUX_GFUNC_GPSR(GRP2_3_FUNC, RLIN35TX_B),
+ PINMUX_GFUNC_GPSR(GRP2_3_FUNC, MSIOF1_SYN_B),
+ PINMUX_GFUNC_GPSR(GRP2_3_FUNC, CTIREQ),
+
+ PINMUX_GFUNC_GPSR(GRP2_2_FUNC, RLIN35RX_B_INTP21),
+ PINMUX_GFUNC_GPSR(GRP2_2_FUNC, MSIOF1_RXD_B),
+
+ PINMUX_GFUNC_GPSR(GRP2_1_FUNC, RLIN34TX_B),
+ PINMUX_GFUNC_GPSR(GRP2_1_FUNC, MSIOF1_TXD_B),
+ PINMUX_GFUNC_GPSR(GRP2_1_FUNC, TAUD0O15),
+
+ PINMUX_GFUNC_GPSR(GRP2_0_FUNC, RLIN34RX_B_INTP20),
+ PINMUX_GFUNC_GPSR(GRP2_0_FUNC, MSIOF1_SCK_B),
+ PINMUX_GFUNC_GPSR(GRP2_0_FUNC, TAUD0O14),
+
+ /* Group3 Functions */
+ PINMUX_GFUNC_GPSR(GRP3_16_FUNC, ERRORIN0_N),
+
+ PINMUX_GFUNC_GPSR(GRP3_15_FUNC, ERROROUT_N),
+
+ PINMUX_GFUNC_GPSR(GRP3_14_FUNC, QSPI1_SSL),
+
+ PINMUX_GFUNC_GPSR(GRP3_13_FUNC, QSPI1_IO3),
+
+ PINMUX_GFUNC_GPSR(GRP3_12_FUNC, QSPI1_IO2),
+
+ PINMUX_GFUNC_GPSR(GRP3_11_FUNC, QSPI1_MISO_IO1),
+
+ PINMUX_GFUNC_GPSR(GRP3_10_FUNC, QSPI1_MOSI_IO0),
+
+ PINMUX_GFUNC_GPSR(GRP3_9_FUNC, QSPI1_SPCLK),
+
+ PINMUX_GFUNC_GPSR(GRP3_8_FUNC, RPC_INT_N),
+
+ PINMUX_GFUNC_GPSR(GRP3_7_FUNC, RPC_WP_N),
+
+ PINMUX_GFUNC_GPSR(GRP3_6_FUNC, RPC_RESET_N),
+
+ PINMUX_GFUNC_GPSR(GRP3_5_FUNC, QSPI0_SSL),
+
+ PINMUX_GFUNC_GPSR(GRP3_4_FUNC, QSPI0_IO3),
+
+ PINMUX_GFUNC_GPSR(GRP3_3_FUNC, QSPI0_IO2),
+
+ PINMUX_GFUNC_GPSR(GRP3_2_FUNC, QSPI0_MISO_IO1),
+
+ PINMUX_GFUNC_GPSR(GRP3_1_FUNC, QSPI0_MOSI_IO0),
+
+ PINMUX_GFUNC_GPSR(GRP3_0_FUNC, QSPI0_SPCLK),
+
+ /* Group4 Functions */
+ PINMUX_GFUNC_GPSR(GRP4_15_FUNC, PCIE61_CLKREQ_N),
+
+ PINMUX_GFUNC_GPSR(GRP4_14_FUNC, PCIE60_CLKREQ_N),
+
+ PINMUX_GFUNC_GPSR(GRP4_13_FUNC, ERRORIN1_N),
+
+ PINMUX_GFUNC_GPSR(GRP4_12_FUNC, SD0_CD),
+
+ PINMUX_GFUNC_GPSR(GRP4_11_FUNC, SD0_WP),
+
+ PINMUX_GFUNC_GPSR(GRP4_10_FUNC, MMC0_DS),
+
+ PINMUX_GFUNC_GPSR(GRP4_9_FUNC, MMC0_D7),
+
+ PINMUX_GFUNC_GPSR(GRP4_8_FUNC, MMC0_D6),
+
+ PINMUX_GFUNC_GPSR(GRP4_7_FUNC, MMC0_D5),
+
+ PINMUX_GFUNC_GPSR(GRP4_6_FUNC, MMC0_D4),
+
+ PINMUX_GFUNC_GPSR(GRP4_5_FUNC, MMC0_SD_D3),
+
+ PINMUX_GFUNC_GPSR(GRP4_4_FUNC, MMC0_SD_D2),
+
+ PINMUX_GFUNC_GPSR(GRP4_3_FUNC, MMC0_SD_D1),
+
+ PINMUX_GFUNC_GPSR(GRP4_2_FUNC, MMC0_SD_D0),
+
+ PINMUX_GFUNC_GPSR(GRP4_1_FUNC, MMC0_SD_CMD),
+
+ PINMUX_GFUNC_GPSR(GRP4_0_FUNC, MMC0_SD_CLK),
+
+ /* Group5 Functions */
+ PINMUX_GFUNC_GPSR(GRP5_22_FUNC, TPU0TO3),
+ PINMUX_GFUNC_GPSR(GRP5_22_FUNC, SSI9_WS),
+
+ PINMUX_GFUNC_GPSR(GRP5_21_FUNC, TPU0TO2),
+ PINMUX_GFUNC_GPSR(GRP5_21_FUNC, SSI9_SCK),
+
+ PINMUX_GFUNC_GPSR(GRP5_20_FUNC, TPU0TO1),
+ PINMUX_GFUNC_GPSR(GRP5_20_FUNC, PWM5),
+
+ PINMUX_GFUNC_GPSR(GRP5_19_FUNC, TPU0TO0),
+ PINMUX_GFUNC_GPSR(GRP5_19_FUNC, PWM4),
+
+ PINMUX_GFUNC_GPSR(GRP5_18_FUNC, TCLK4),
+ PINMUX_GFUNC_GPSR(GRP5_18_FUNC, PWM3),
+ PINMUX_GFUNC_GPSR(GRP5_18_FUNC, SSI19_SD),
+
+ PINMUX_GFUNC_GPSR(GRP5_17_FUNC, TCLK3),
+ PINMUX_GFUNC_GPSR(GRP5_17_FUNC, PWM2),
+ PINMUX_GFUNC_GPSR(GRP5_17_FUNC, SSI19_WS),
+
+ PINMUX_GFUNC_GPSR(GRP5_16_FUNC, TCLK2),
+ PINMUX_GFUNC_GPSR(GRP5_16_FUNC, PWM1),
+ PINMUX_GFUNC_GPSR(GRP5_16_FUNC, SSI19_SCK),
+
+ PINMUX_GFUNC_GPSR(GRP5_15_FUNC, TCLK1),
+ PINMUX_GFUNC_GPSR(GRP5_15_FUNC, PWM0_A),
+ PINMUX_GFUNC_GPSR(GRP5_15_FUNC, SSI18_SD),
+
+ PINMUX_GFUNC_GPSR(GRP5_14_FUNC, IRQ3_A),
+ PINMUX_GFUNC_GPSR(GRP5_14_FUNC, RIF7_D1),
+
+ PINMUX_GFUNC_GPSR(GRP5_13_FUNC, IRQ2_A),
+ PINMUX_GFUNC_GPSR(GRP5_13_FUNC, SSI17_SD),
+ PINMUX_GFUNC_GPSR(GRP5_13_FUNC, RIF7_D0),
+
+ PINMUX_GFUNC_GPSR(GRP5_12_FUNC, IRQ1_A),
+ PINMUX_GFUNC_GPSR(GRP5_12_FUNC, SSI17_WS),
+ PINMUX_GFUNC_GPSR(GRP5_12_FUNC, RIF7_SYNC),
+
+ PINMUX_GFUNC_GPSR(GRP5_11_FUNC, IRQ0_A),
+ PINMUX_GFUNC_GPSR(GRP5_11_FUNC, SSI17_SCK),
+ PINMUX_GFUNC_GPSR(GRP5_11_FUNC, RIF7_CLK),
+
+ PINMUX_GFUNC_GPSR(GRP5_10_FUNC, HSCK1),
+ PINMUX_GFUNC_GPSR(GRP5_10_FUNC, SCK1),
+ PINMUX_GFUNC_GPSR(GRP5_10_FUNC, SSI13_SCK),
+ PINMUX_GFUNC_GPSR(GRP5_10_FUNC, RIF0_CLK_B),
+
+ PINMUX_GFUNC_GPSR(GRP5_9_FUNC, HCTS1_N),
+ PINMUX_GFUNC_GPSR(GRP5_9_FUNC, CTS1_N),
+
+ PINMUX_GFUNC_GPSR(GRP5_8_FUNC, HRTS1_N),
+ PINMUX_GFUNC_GPSR(GRP5_8_FUNC, RTS1_N),
+ PINMUX_GFUNC_GPSR(GRP5_8_FUNC, RIF0_SYNC_B),
+ PINMUX_GFUNC_GPSR(GRP5_8_FUNC, SSI16_SD),
+
+ PINMUX_GFUNC_GPSR(GRP5_7_FUNC, HRX1),
+ PINMUX_GFUNC_GPSR(GRP5_7_FUNC, RX1),
+ PINMUX_GFUNC_GPSR(GRP5_7_FUNC, SSI16_WS),
+
+ PINMUX_GFUNC_GPSR(GRP5_6_FUNC, HTX1),
+ PINMUX_GFUNC_GPSR(GRP5_6_FUNC, TX1),
+ PINMUX_GFUNC_GPSR(GRP5_6_FUNC, SSI16_SCK),
+
+ PINMUX_GFUNC_GPSR(GRP5_5_FUNC, SCIF_CLK),
+
+ PINMUX_GFUNC_GPSR(GRP5_4_FUNC, HSCK0),
+ PINMUX_GFUNC_GPSR(GRP5_4_FUNC, SCK0),
+ PINMUX_GFUNC_GPSR(GRP5_4_FUNC, SSI15_SD),
+
+ PINMUX_GFUNC_GPSR(GRP5_3_FUNC, HCTS0_N),
+ PINMUX_GFUNC_GPSR(GRP5_3_FUNC, CTS0_N),
+ PINMUX_GFUNC_GPSR(GRP5_3_FUNC, IRQ1_B),
+ PINMUX_GFUNC_GPSR(GRP5_3_FUNC, SSI15_WS),
+
+ PINMUX_GFUNC_GPSR(GRP5_2_FUNC, HRTS0_N),
+ PINMUX_GFUNC_GPSR(GRP5_2_FUNC, RTS0_N),
+ PINMUX_GFUNC_GPSR(GRP5_2_FUNC, IRQ0_B),
+ PINMUX_GFUNC_GPSR(GRP5_2_FUNC, SSI15_SCK),
+
+ PINMUX_GFUNC_GPSR(GRP5_1_FUNC, HRX0),
+ PINMUX_GFUNC_GPSR(GRP5_1_FUNC, RX0),
+ PINMUX_GFUNC_GPSR(GRP5_1_FUNC, SSI13_SD),
+ PINMUX_GFUNC_GPSR(GRP5_1_FUNC, RIF0_D1_B),
+
+ PINMUX_GFUNC_GPSR(GRP5_0_FUNC, HTX0),
+ PINMUX_GFUNC_GPSR(GRP5_0_FUNC, TX0),
+ PINMUX_GFUNC_GPSR(GRP5_0_FUNC, SSI13_WS),
+ PINMUX_GFUNC_GPSR(GRP5_0_FUNC, RIF0_D0_B),
+
+ /* Group6 Functions */
+ PINMUX_GFUNC_GPSR(GRP6_30_FUNC, AUDIO1_CLKOUT1),
+ PINMUX_GFUNC_GPSR(GRP6_30_FUNC, MSIOF7_RXD_B),
+ PINMUX_GFUNC_GPSR(GRP6_30_FUNC, RIF5_CLK),
+
+ PINMUX_GFUNC_GPSR(GRP6_29_FUNC, AUDIO1_CLKOUT0),
+ PINMUX_GFUNC_GPSR(GRP6_29_FUNC, MSIOF7_TXD_B),
+
+ PINMUX_GFUNC_GPSR(GRP6_28_FUNC, SSI2_SD),
+ PINMUX_GFUNC_GPSR(GRP6_28_FUNC, MSIOF7_SCK_B),
+ PINMUX_GFUNC_GPSR(GRP6_28_FUNC, RIF5_SYNC),
+
+ PINMUX_GFUNC_GPSR(GRP6_27_FUNC, SSI2_WS),
+ PINMUX_GFUNC_GPSR(GRP6_27_FUNC, RIF1_D1_A),
+
+ PINMUX_GFUNC_GPSR(GRP6_26_FUNC, SSI2_SCK),
+ PINMUX_GFUNC_GPSR(GRP6_26_FUNC, RIF1_D0_A),
+
+ PINMUX_GFUNC_GPSR(GRP6_25_FUNC, AUDIO0_CLKOUT3),
+ PINMUX_GFUNC_GPSR(GRP6_25_FUNC, RIF1_CLK_A),
+
+ PINMUX_GFUNC_GPSR(GRP6_24_FUNC, AUDIO0_CLKOUT2),
+ PINMUX_GFUNC_GPSR(GRP6_24_FUNC, RIF2_D1),
+
+ PINMUX_GFUNC_GPSR(GRP6_23_FUNC, SSI1_SD),
+ PINMUX_GFUNC_GPSR(GRP6_23_FUNC, HCTS3_N),
+ PINMUX_GFUNC_GPSR(GRP6_23_FUNC, CTS3_N),
+
+ PINMUX_GFUNC_GPSR(GRP6_22_FUNC, SSI1_WS),
+ PINMUX_GFUNC_GPSR(GRP6_22_FUNC, HRTS3_N),
+ PINMUX_GFUNC_GPSR(GRP6_22_FUNC, RTS3_N),
+
+ PINMUX_GFUNC_GPSR(GRP6_21_FUNC, SSI1_SCK),
+ PINMUX_GFUNC_GPSR(GRP6_21_FUNC, MSIOF4_SS2_A),
+ PINMUX_GFUNC_GPSR(GRP6_21_FUNC, HSCK3),
+ PINMUX_GFUNC_GPSR(GRP6_21_FUNC, SCK3),
+
+ PINMUX_GFUNC_GPSR(GRP6_20_FUNC, AUDIO0_CLKOUT1),
+ PINMUX_GFUNC_GPSR(GRP6_20_FUNC, MSIOF4_SS1_A),
+ PINMUX_GFUNC_GPSR(GRP6_20_FUNC, RIF2_D0),
+
+ PINMUX_GFUNC_GPSR(GRP6_19_FUNC, AUDIO0_CLKOUT0),
+ PINMUX_GFUNC_GPSR(GRP6_19_FUNC, MSIOF4_SYNC_A),
+ PINMUX_GFUNC_GPSR(GRP6_19_FUNC, RIF2_SYNC),
+
+ PINMUX_GFUNC_GPSR(GRP6_18_FUNC, SSI0_SD),
+ PINMUX_GFUNC_GPSR(GRP6_18_FUNC, MSIOF4_RXD_A),
+ PINMUX_GFUNC_GPSR(GRP6_18_FUNC, HRX3),
+ PINMUX_GFUNC_GPSR(GRP6_18_FUNC, RX3),
+
+ PINMUX_GFUNC_GPSR(GRP6_17_FUNC, SSI0_WS),
+ PINMUX_GFUNC_GPSR(GRP6_17_FUNC, MSIOF4_TXD_A),
+ PINMUX_GFUNC_GPSR(GRP6_17_FUNC, HTX3),
+ PINMUX_GFUNC_GPSR(GRP6_17_FUNC, TX3),
+
+ PINMUX_GFUNC_GPSR(GRP6_16_FUNC, SSI0_SCK),
+ PINMUX_GFUNC_GPSR(GRP6_16_FUNC, MSIOF4_SCK_A),
+
+ PINMUX_GFUNC_GPSR(GRP6_15_FUNC, MSIOF4_SS2_B),
+ PINMUX_GFUNC_GPSR(GRP6_15_FUNC, SSI14_SD),
+
+ PINMUX_GFUNC_GPSR(GRP6_14_FUNC, MSIOF4_SS1_B),
+ PINMUX_GFUNC_GPSR(GRP6_14_FUNC, SSI12_SD),
+
+ PINMUX_GFUNC_GPSR(GRP6_13_FUNC, MSIOF4_SYNC_B),
+ PINMUX_GFUNC_GPSR(GRP6_13_FUNC, SSI12_WS),
+
+ PINMUX_GFUNC_GPSR(GRP6_12_FUNC, MSIOF4_RXD_B),
+ PINMUX_GFUNC_GPSR(GRP6_12_FUNC, AUDIO_CLKC_B),
+
+ PINMUX_GFUNC_GPSR(GRP6_11_FUNC, MSIOF4_TXD_B),
+ PINMUX_GFUNC_GPSR(GRP6_11_FUNC, SSI12_SCK),
+ PINMUX_GFUNC_GPSR(GRP6_11_FUNC, RIF1_SYNC_A),
+
+ PINMUX_GFUNC_GPSR(GRP6_10_FUNC, MSIOF4_SCK_B),
+ PINMUX_GFUNC_GPSR(GRP6_10_FUNC, AUDIO_CLKB_B),
+
+ PINMUX_GFUNC_GPSR(GRP6_9_FUNC, MSIOF7_SS2_A),
+ PINMUX_GFUNC_GPSR(GRP6_9_FUNC, SSI14_WS),
+
+ PINMUX_GFUNC_GPSR(GRP6_8_FUNC, MSIOF7_SS1_A),
+ PINMUX_GFUNC_GPSR(GRP6_8_FUNC, SSI14_SCK),
+
+ PINMUX_GFUNC_GPSR(GRP6_7_FUNC, MSIOF7_SYNC_A),
+ PINMUX_GFUNC_GPSR(GRP6_7_FUNC, RIF1_D1_B),
+ PINMUX_GFUNC_GPSR(GRP6_7_FUNC, SSI11_SD),
+
+ PINMUX_GFUNC_GPSR(GRP6_6_FUNC, MSIOF7_RXD_A),
+ PINMUX_GFUNC_GPSR(GRP6_6_FUNC, RIF1_D0_B),
+ PINMUX_GFUNC_GPSR(GRP6_6_FUNC, SSI11_WS),
+
+ PINMUX_GFUNC_GPSR(GRP6_5_FUNC, MSIOF7_TXD_A),
+ PINMUX_GFUNC_GPSR(GRP6_5_FUNC, RIF1_SYNC_B),
+ PINMUX_GFUNC_GPSR(GRP6_5_FUNC, SSI11_SCK),
+
+ PINMUX_GFUNC_GPSR(GRP6_4_FUNC, MSIOF7_SCK_A),
+ PINMUX_GFUNC_GPSR(GRP6_4_FUNC, RIF1_CLK_B),
+ PINMUX_GFUNC_GPSR(GRP6_4_FUNC, AUDIO_CLKA_B),
+
+ PINMUX_GFUNC_GPSR(GRP6_3_FUNC, RIF6_CLK),
+ PINMUX_GFUNC_GPSR(GRP6_3_FUNC, SSI10_SD),
+
+ PINMUX_GFUNC_GPSR(GRP6_2_FUNC, RIF6_SYNC),
+ PINMUX_GFUNC_GPSR(GRP6_2_FUNC, SSI10_WS),
+
+ PINMUX_GFUNC_GPSR(GRP6_1_FUNC, RIF6_D1),
+ PINMUX_GFUNC_GPSR(GRP6_1_FUNC, SSI10_SCK),
+
+ PINMUX_GFUNC_GPSR(GRP6_0_FUNC, RIF6_D0),
+ PINMUX_GFUNC_GPSR(GRP6_0_FUNC, SSI9_SD),
+
+ /* Group7 Functions */
+ PINMUX_GFUNC_GPSR(GRP7_30_FUNC, MSIOF6_SS2_B),
+ PINMUX_GFUNC_GPSR(GRP7_30_FUNC, HRX2_B),
+ PINMUX_GFUNC_GPSR(GRP7_30_FUNC, RX4_B),
+
+ PINMUX_GFUNC_GPSR(GRP7_29_FUNC, MSIOF6_SS1_B),
+ PINMUX_GFUNC_GPSR(GRP7_29_FUNC, SSI7_SD),
+
+ PINMUX_GFUNC_GPSR(GRP7_28_FUNC, MSIOF6_SYNC_B),
+ PINMUX_GFUNC_GPSR(GRP7_28_FUNC, SSI7_WS),
+
+ PINMUX_GFUNC_GPSR(GRP7_27_FUNC, MSIOF6_RXD_B),
+ PINMUX_GFUNC_GPSR(GRP7_27_FUNC, SSI7_SCK),
+
+ PINMUX_GFUNC_GPSR(GRP7_26_FUNC, MSIOF6_TXD_B),
+ PINMUX_GFUNC_GPSR(GRP7_26_FUNC, HTX2_B),
+ PINMUX_GFUNC_GPSR(GRP7_26_FUNC, TX4_B),
+
+ PINMUX_GFUNC_GPSR(GRP7_25_FUNC, MSIOF6_SCK_B),
+ PINMUX_GFUNC_GPSR(GRP7_25_FUNC, SSI8_SD),
+
+ PINMUX_GFUNC_GPSR(GRP7_24_FUNC, MSIOF5_SS2),
+ PINMUX_GFUNC_GPSR(GRP7_24_FUNC, HCTS2_N_B),
+ PINMUX_GFUNC_GPSR(GRP7_24_FUNC, CTS4_N_B),
+
+ PINMUX_GFUNC_GPSR(GRP7_23_FUNC, MSIOF5_SS1),
+ PINMUX_GFUNC_GPSR(GRP7_23_FUNC, RIF0_SYNC_A),
+
+ PINMUX_GFUNC_GPSR(GRP7_22_FUNC, MSIOF5_SYNC),
+ PINMUX_GFUNC_GPSR(GRP7_22_FUNC, HRTS2_N_B),
+ PINMUX_GFUNC_GPSR(GRP7_22_FUNC, RTS4_N_B),
+
+ PINMUX_GFUNC_GPSR(GRP7_21_FUNC, MSIOF5_RXD),
+ PINMUX_GFUNC_GPSR(GRP7_21_FUNC, RIF0_D1_A),
+
+ PINMUX_GFUNC_GPSR(GRP7_20_FUNC, MSIOF5_TXD),
+ PINMUX_GFUNC_GPSR(GRP7_20_FUNC, HSCK2_B),
+ PINMUX_GFUNC_GPSR(GRP7_20_FUNC, SCK4_B),
+
+ PINMUX_GFUNC_GPSR(GRP7_19_FUNC, MSIOF6_SS2_A),
+
+ PINMUX_GFUNC_GPSR(GRP7_18_FUNC, MSIOF6_SS1_A),
+
+ PINMUX_GFUNC_GPSR(GRP7_17_FUNC, MSIOF5_SCK),
+
+ PINMUX_GFUNC_GPSR(GRP7_16_FUNC, AUDIO_CLKC_A),
+
+ PINMUX_GFUNC_GPSR(GRP7_15_FUNC, SSI6_SD),
+ PINMUX_GFUNC_GPSR(GRP7_15_FUNC, MSIOF6_RXD_A),
+ PINMUX_GFUNC_GPSR(GRP7_15_FUNC, RIF4_D1),
+
+ PINMUX_GFUNC_GPSR(GRP7_14_FUNC, SSI6_WS),
+ PINMUX_GFUNC_GPSR(GRP7_14_FUNC, MSIOF6_TXD_A),
+ PINMUX_GFUNC_GPSR(GRP7_14_FUNC, RIF4_D0),
+
+ PINMUX_GFUNC_GPSR(GRP7_13_FUNC, SSI6_SCK),
+ PINMUX_GFUNC_GPSR(GRP7_13_FUNC, MSIOF6_SCK_A),
+ PINMUX_GFUNC_GPSR(GRP7_13_FUNC, RIF4_SYNC),
+
+ PINMUX_GFUNC_GPSR(GRP7_12_FUNC, AUDIO_CLKB_A),
+
+ PINMUX_GFUNC_GPSR(GRP7_11_FUNC, SSI5_SD),
+ PINMUX_GFUNC_GPSR(GRP7_11_FUNC, MSIOF6_SYNC_A),
+ PINMUX_GFUNC_GPSR(GRP7_11_FUNC, RIF4_CLK),
+
+ PINMUX_GFUNC_GPSR(GRP7_10_FUNC, SSI5_WS),
+ PINMUX_GFUNC_GPSR(GRP7_10_FUNC, RIF3_SYNC),
+
+ PINMUX_GFUNC_GPSR(GRP7_9_FUNC, SSI5_SCK),
+ PINMUX_GFUNC_GPSR(GRP7_9_FUNC, RIF3_CLK),
+
+ PINMUX_GFUNC_GPSR(GRP7_8_FUNC, AUDIO_CLKA_A),
+
+ PINMUX_GFUNC_GPSR(GRP7_7_FUNC, SSI4_SD),
+ PINMUX_GFUNC_GPSR(GRP7_7_FUNC, RIF3_D1),
+
+ PINMUX_GFUNC_GPSR(GRP7_6_FUNC, SSI4_WS),
+ PINMUX_GFUNC_GPSR(GRP7_6_FUNC, RIF3_D0),
+
+ PINMUX_GFUNC_GPSR(GRP7_5_FUNC, SSI4_SCK),
+ PINMUX_GFUNC_GPSR(GRP7_5_FUNC, RIF2_CLK),
+
+ PINMUX_GFUNC_GPSR(GRP7_4_FUNC, AUDIO1_CLKOUT3),
+ PINMUX_GFUNC_GPSR(GRP7_4_FUNC, RIF0_D0_A),
+
+ PINMUX_GFUNC_GPSR(GRP7_3_FUNC, AUDIO1_CLKOUT2),
+ PINMUX_GFUNC_GPSR(GRP7_3_FUNC, RIF0_CLK_A),
+
+ PINMUX_GFUNC_GPSR(GRP7_2_FUNC, SSI3_SD),
+ PINMUX_GFUNC_GPSR(GRP7_2_FUNC, MSIOF7_SS2_B),
+
+ PINMUX_GFUNC_GPSR(GRP7_1_FUNC, SSI3_WS),
+ PINMUX_GFUNC_GPSR(GRP7_1_FUNC, MSIOF7_SS1_B),
+ PINMUX_GFUNC_GPSR(GRP7_1_FUNC, RIF5_D1),
+
+ PINMUX_GFUNC_GPSR(GRP7_0_FUNC, SSI3_SCK),
+ PINMUX_GFUNC_GPSR(GRP7_0_FUNC, MSIOF7_SYNC_B),
+ PINMUX_GFUNC_GPSR(GRP7_0_FUNC, RIF5_D0),
+
+ /* Group8 Functions */
+ PINMUX_GFUNC_GPSR(GRP8_31_FUNC, S3DA2),
+
+ PINMUX_GFUNC_GPSR(GRP8_30_FUNC, S3CL2),
+
+ PINMUX_GFUNC_GPSR(GRP8_29_FUNC, S3DA1),
+
+ PINMUX_GFUNC_GPSR(GRP8_28_FUNC, S3CL1),
+
+ PINMUX_GFUNC_GPSR(GRP8_27_FUNC, S3DA0),
+
+ PINMUX_GFUNC_GPSR(GRP8_26_FUNC, S3CL0),
+
+ PINMUX_GFUNC_MSEL_GPSR(GRP8_15_FUNC, SDA8, SEL_SDA8_1),
+
+ PINMUX_GFUNC_MSEL_GPSR(GRP8_14_FUNC, SCL8, SEL_SCL8_1),
+
+ PINMUX_GFUNC_MSEL_GPSR(GRP8_13_FUNC, SDA7, SEL_SDA7_1),
+
+ PINMUX_GFUNC_MSEL_GPSR(GRP8_12_FUNC, SCL7, SEL_SCL7_1),
+
+ PINMUX_GFUNC_MSEL_GPSR(GRP8_11_FUNC, SDA6, SEL_SDA6_1),
+
+ PINMUX_GFUNC_MSEL_GPSR(GRP8_10_FUNC, SCL6, SEL_SCL6_1),
+
+ PINMUX_GFUNC_MSEL_GPSR(GRP8_9_FUNC, SDA5, SEL_SDA5_1),
+
+ PINMUX_GFUNC_MSEL_GPSR(GRP8_8_FUNC, SCL5, SEL_SCL5_1),
+
+ PINMUX_GFUNC_MSEL_GPSR(GRP8_7_FUNC, SDA4, SEL_SDA4_1),
+ PINMUX_GFUNC_GPSR(GRP8_7_FUNC, HCTS2_N_A),
+ PINMUX_GFUNC_GPSR(GRP8_7_FUNC, CTS4_N_A),
+ PINMUX_GFUNC_GPSR(GRP8_7_FUNC, PWM7_B),
+
+ PINMUX_GFUNC_MSEL_GPSR(GRP8_6_FUNC, SCL4, SEL_SCL4_1),
+ PINMUX_GFUNC_GPSR(GRP8_6_FUNC, HRTS2_N_A),
+ PINMUX_GFUNC_GPSR(GRP8_6_FUNC, RTS4_N_A),
+ PINMUX_GFUNC_GPSR(GRP8_6_FUNC, PWM9_B),
+
+ PINMUX_GFUNC_MSEL_GPSR(GRP8_5_FUNC, SDA3, SEL_SDA3_1),
+ PINMUX_GFUNC_GPSR(GRP8_5_FUNC, HRX2_A),
+ PINMUX_GFUNC_GPSR(GRP8_5_FUNC, RX4_A),
+ PINMUX_GFUNC_GPSR(GRP8_5_FUNC, PWM8_B),
+
+ PINMUX_GFUNC_MSEL_GPSR(GRP8_4_FUNC, SCL3, SEL_SCL3_1),
+ PINMUX_GFUNC_GPSR(GRP8_4_FUNC, HTX2_A),
+ PINMUX_GFUNC_GPSR(GRP8_4_FUNC, TX4_A),
+ PINMUX_GFUNC_GPSR(GRP8_4_FUNC, PWM6_B),
+
+ PINMUX_GFUNC_MSEL_GPSR(GRP8_3_FUNC, SDA2, SEL_SDA2_1),
+ PINMUX_GFUNC_GPSR(GRP8_3_FUNC, HSCK2_A),
+ PINMUX_GFUNC_GPSR(GRP8_3_FUNC, SCK4_A),
+
+ PINMUX_GFUNC_MSEL_GPSR(GRP8_2_FUNC, SCL2, SEL_SCL2_1),
+ PINMUX_GFUNC_GPSR(GRP8_2_FUNC, PWM0_B),
+
+ PINMUX_GFUNC_MSEL_GPSR(GRP8_1_FUNC, SDA1, SEL_SDA1_1),
+
+ PINMUX_GFUNC_MSEL_GPSR(GRP8_0_FUNC, SCL1, SEL_SCL1_1),
+
+ /* Group9 Functions */
+ PINMUX_GFUNC_GPSR(GRP9_16_FUNC, RSW3_MATCH),
+ PINMUX_GFUNC_GPSR(GRP9_16_FUNC, PWM9_A),
+
+ PINMUX_GFUNC_GPSR(GRP9_15_FUNC, RSW3_CAPTURE),
+ PINMUX_GFUNC_GPSR(GRP9_15_FUNC, PWM8_A),
+
+ PINMUX_GFUNC_GPSR(GRP9_14_FUNC, RSW3_PPS),
+
+ PINMUX_GFUNC_GPSR(GRP9_13_FUNC, ETH10G0_PHYINT),
+ PINMUX_GFUNC_GPSR(GRP9_13_FUNC, ETH10G1_PHYINT),
+
+ PINMUX_GFUNC_GPSR(GRP9_12_FUNC, ETH10G0_LINK),
+ PINMUX_GFUNC_GPSR(GRP9_12_FUNC, ETH10G1_LINK),
+ PINMUX_GFUNC_GPSR(GRP9_12_FUNC, PWM7_A),
+
+ PINMUX_GFUNC_GPSR(GRP9_11_FUNC, ETH10G0_MDC),
+ PINMUX_GFUNC_GPSR(GRP9_11_FUNC, ETH10G1_MDC),
+ PINMUX_GFUNC_GPSR(GRP9_11_FUNC, IRQ3_B),
+
+ PINMUX_GFUNC_GPSR(GRP9_10_FUNC, ETH10G0_MDIO),
+ PINMUX_GFUNC_GPSR(GRP9_10_FUNC, ETH10G1_MDIO),
+ PINMUX_GFUNC_GPSR(GRP9_10_FUNC, IRQ2_B),
+
+ PINMUX_GFUNC_GPSR(GRP9_9_FUNC, ETH25G0_PHYINT),
+ PINMUX_GFUNC_GPSR(GRP9_9_FUNC, ETH25G1_PHYINT),
+ PINMUX_GFUNC_GPSR(GRP9_9_FUNC, ETH25G2_PHYINT),
+
+ PINMUX_GFUNC_GPSR(GRP9_8_FUNC, ETH25G0_LINK),
+ PINMUX_GFUNC_GPSR(GRP9_8_FUNC, ETH25G1_LINK),
+ PINMUX_GFUNC_GPSR(GRP9_8_FUNC, ETH25G2_LINK),
+ PINMUX_GFUNC_GPSR(GRP9_8_FUNC, PWM6_A),
+
+ PINMUX_GFUNC_GPSR(GRP9_7_FUNC, ETH25G0_MDC),
+ PINMUX_GFUNC_GPSR(GRP9_7_FUNC, ETH25G1_MDC),
+ PINMUX_GFUNC_GPSR(GRP9_7_FUNC, ETH25G2_MDC),
+
+ PINMUX_GFUNC_GPSR(GRP9_6_FUNC, ETH25G0_MDIO),
+ PINMUX_GFUNC_GPSR(GRP9_6_FUNC, ETH25G1_MDIO),
+ PINMUX_GFUNC_GPSR(GRP9_6_FUNC, ETH25G2_MDIO),
+
+ PINMUX_GFUNC_GPSR(GRP9_5_FUNC, ETHES4_MATCH),
+ PINMUX_GFUNC_GPSR(GRP9_5_FUNC, ETHES5_MATCH),
+ PINMUX_GFUNC_GPSR(GRP9_5_FUNC, ETHES6_MATCH),
+ PINMUX_GFUNC_GPSR(GRP9_5_FUNC, ETHES7_MATCH),
+
+ PINMUX_GFUNC_GPSR(GRP9_4_FUNC, ETHES4_CAPTURE),
+ PINMUX_GFUNC_GPSR(GRP9_4_FUNC, ETHES5_CAPTURE),
+ PINMUX_GFUNC_GPSR(GRP9_4_FUNC, ETHES6_CAPTURE),
+ PINMUX_GFUNC_GPSR(GRP9_4_FUNC, ETHES7_CAPTURE),
+
+ PINMUX_GFUNC_GPSR(GRP9_3_FUNC, ETHES4_PPS),
+ PINMUX_GFUNC_GPSR(GRP9_3_FUNC, ETHES5_PPS),
+ PINMUX_GFUNC_GPSR(GRP9_3_FUNC, ETHES6_PPS),
+ PINMUX_GFUNC_GPSR(GRP9_3_FUNC, ETHES7_PPS),
+
+ PINMUX_GFUNC_GPSR(GRP9_2_FUNC, ETHES0_MATCH),
+ PINMUX_GFUNC_GPSR(GRP9_2_FUNC, ETHES1_MATCH),
+ PINMUX_GFUNC_GPSR(GRP9_2_FUNC, ETHES2_MATCH),
+ PINMUX_GFUNC_GPSR(GRP9_2_FUNC, ETHES3_MATCH),
+
+ PINMUX_GFUNC_GPSR(GRP9_1_FUNC, ETHES0_CAPTURE),
+ PINMUX_GFUNC_GPSR(GRP9_1_FUNC, ETHES1_CAPTURE),
+ PINMUX_GFUNC_GPSR(GRP9_1_FUNC, ETHES2_CAPTURE),
+ PINMUX_GFUNC_GPSR(GRP9_1_FUNC, ETHES3_CAPTURE),
+
+ PINMUX_GFUNC_GPSR(GRP9_0_FUNC, ETHES0_PPS),
+ PINMUX_GFUNC_GPSR(GRP9_0_FUNC, ETHES1_PPS),
+ PINMUX_GFUNC_GPSR(GRP9_0_FUNC, ETHES2_PPS),
+ PINMUX_GFUNC_GPSR(GRP9_0_FUNC, ETHES3_PPS),
+
+ /* Group10 Functions */
+ PINMUX_GFUNC_GPSR(GRP10_13_FUNC, PCIE41_CLKREQ_N),
+
+ PINMUX_GFUNC_GPSR(GRP10_12_FUNC, PCIE40_CLKREQ_N),
+
+ PINMUX_GFUNC_GPSR(GRP10_11_FUNC, USB3_VBUS_VALID),
+
+ PINMUX_GFUNC_GPSR(GRP10_10_FUNC, USB3_OVC),
+
+ PINMUX_GFUNC_GPSR(GRP10_9_FUNC, USB3_PWEN),
+
+ PINMUX_GFUNC_GPSR(GRP10_8_FUNC, USB2_VBUS_VALID),
+
+ PINMUX_GFUNC_GPSR(GRP10_7_FUNC, USB2_OVC),
+
+ PINMUX_GFUNC_GPSR(GRP10_6_FUNC, USB2_PWEN),
+
+ PINMUX_GFUNC_GPSR(GRP10_5_FUNC, USB1_VBUS_VALID),
+
+ PINMUX_GFUNC_GPSR(GRP10_4_FUNC, USB1_OVC),
+
+ PINMUX_GFUNC_GPSR(GRP10_3_FUNC, USB1_PWEN),
+
+ PINMUX_GFUNC_GPSR(GRP10_2_FUNC, USB0_VBUS_VALID),
+
+ PINMUX_GFUNC_GPSR(GRP10_1_FUNC, USB0_OVC),
+
+ PINMUX_GFUNC_GPSR(GRP10_0_FUNC, USB0_PWEN),
+
+};
+
+/*
+ * Pins not associated with a GPIO port.
+ * TODO: Define for None GPIO pins.
+ */
+enum {
+ GP_ASSIGN_LAST(),
+ //NOGP_ALL(),
+};
+
+static const struct sh_pfc_pin pinmux_pins[] = {
+ PINMUX_GPIO_GP_ALL(),
+ // TODO: Define for None GPIO pins.
+ //PINMUX_NOGP_ALL(),
+};
+
+/* - HSCIF0 ----------------------------------------------------------------- */
+static const unsigned int hscif0_data_pins[] = {
+ /* HRX0, HTX0 */
+ RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 0),
+};
+static const unsigned int hscif0_data_mux[] = {
+ HRX0_MARK, HTX0_MARK,
+};
+static const unsigned int hscif0_clk_pins[] = {
+ /* HSCK0 */
+ RCAR_GP_PIN(5, 4),
+};
+static const unsigned int hscif0_clk_mux[] = {
+ HSCK0_MARK,
+};
+static const unsigned int hscif0_ctrl_pins[] = {
+ /* HRTS0_N, HCTS0_N */
+ RCAR_GP_PIN(5, 2), RCAR_GP_PIN(5, 3),
+};
+static const unsigned int hscif0_ctrl_mux[] = {
+ HRTS0_N_MARK, HCTS0_N_MARK,
+};
+
+/* - HSCIF1 ----------------------------------------------------------------- */
+static const unsigned int hscif1_data_pins[] = {
+ /* HRX1, HTX1 */
+ RCAR_GP_PIN(5, 7), RCAR_GP_PIN(5, 6),
+};
+static const unsigned int hscif1_data_mux[] = {
+ HRX1_MARK, HTX1_MARK,
+};
+static const unsigned int hscif1_clk_pins[] = {
+ /* HSCK1 */
+ RCAR_GP_PIN(5, 10),
+};
+static const unsigned int hscif1_clk_mux[] = {
+ HSCK1_MARK,
+};
+static const unsigned int hscif1_ctrl_pins[] = {
+ /* HRTS1_N, HCTS1_N */
+ RCAR_GP_PIN(5, 8), RCAR_GP_PIN(5, 9),
+};
+static const unsigned int hscif1_ctrl_mux[] = {
+ HRTS1_N_MARK, HCTS1_N_MARK,
+};
+
+/* - HSCIF2 ----------------------------------------------------------------- */
+static const unsigned int hscif2_data_a_pins[] = {
+ /* HRX2_A, HTX2_A */
+ RCAR_GP_PIN(8, 5), RCAR_GP_PIN(8, 4),
+};
+static const unsigned int hscif2_data_a_mux[] = {
+ HRX2_A_MARK, HTX2_A_MARK,
+};
+static const unsigned int hscif2_clk_a_pins[] = {
+ /* HSCK2_A */
+ RCAR_GP_PIN(8, 3),
+};
+static const unsigned int hscif2_clk_a_mux[] = {
+ HSCK2_A_MARK,
+};
+static const unsigned int hscif2_ctrl_a_pins[] = {
+ /* HRTS2_A_N, HCTS2_A_N */
+ RCAR_GP_PIN(8, 6), RCAR_GP_PIN(8, 7),
+};
+static const unsigned int hscif2_ctrl_a_mux[] = {
+ HRTS2_N_A_MARK, HCTS2_N_A_MARK,
+};
+
+static const unsigned int hscif2_data_b_pins[] = {
+ /* HRX2_B, HTX2_B */
+ RCAR_GP_PIN(7, 30), RCAR_GP_PIN(7, 26),
+};
+static const unsigned int hscif2_data_b_mux[] = {
+ HRX2_B_MARK, HTX2_B_MARK,
+};
+static const unsigned int hscif2_clk_b_pins[] = {
+ /* HSCK2_B */
+ RCAR_GP_PIN(7, 20),
+};
+static const unsigned int hscif2_clk_b_mux[] = {
+ HSCK2_B_MARK,
+};
+static const unsigned int hscif2_ctrl_b_pins[] = {
+ /* HRTS2_B_N, HCTS2_B_N */
+ RCAR_GP_PIN(7, 22), RCAR_GP_PIN(7, 24),
+};
+static const unsigned int hscif2_ctrl_b_mux[] = {
+ HRTS2_N_B_MARK, HCTS2_N_B_MARK,
+};
+
+/* - HSCIF3 ----------------------------------------------------------------- */
+static const unsigned int hscif3_data_pins[] = {
+ /* HRX3, HTX3 */
+ RCAR_GP_PIN(6, 18), RCAR_GP_PIN(8, 17),
+};
+static const unsigned int hscif3_data_mux[] = {
+ HRX3_MARK, HTX3_MARK,
+};
+static const unsigned int hscif3_clk_pins[] = {
+ /* HSCK3 */
+ RCAR_GP_PIN(6, 21),
+};
+static const unsigned int hscif3_clk_mux[] = {
+ HSCK3_MARK,
+};
+static const unsigned int hscif3_ctrl_pins[] = {
+ /* HRTS3_N, HCTS3_N */
+ RCAR_GP_PIN(6, 22), RCAR_GP_PIN(6, 23),
+};
+static const unsigned int hscif3_ctrl_mux[] = {
+ HRTS3_N_MARK, HCTS3_N_MARK,
+};
+
+/* - SCIF0 ----------------------------------------------------------------- */
+static const unsigned int scif0_data_pins[] = {
+ /* RX0, TX0 */
+ RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 0),
+};
+static const unsigned int scif0_data_mux[] = {
+ RX0_MARK, TX0_MARK,
+};
+static const unsigned int scif0_clk_pins[] = {
+ /* SCK0 */
+ RCAR_GP_PIN(5, 4),
+};
+static const unsigned int scif0_clk_mux[] = {
+ SCK0_MARK,
+};
+static const unsigned int scif0_ctrl_pins[] = {
+ /* RTS0_N, CTS0_N */
+ RCAR_GP_PIN(5, 2), RCAR_GP_PIN(5, 3),
+};
+static const unsigned int scif0_ctrl_mux[] = {
+ RTS0_N_MARK, CTS0_N_MARK,
+};
+
+/* - SCIF1 ----------------------------------------------------------------- */
+static const unsigned int scif1_data_pins[] = {
+ /* RX1, TX1 */
+ RCAR_GP_PIN(5, 7), RCAR_GP_PIN(5, 6),
+};
+static const unsigned int scif1_data_mux[] = {
+ RX1_MARK, TX1_MARK,
+};
+static const unsigned int scif1_clk_pins[] = {
+ /* SCK1 */
+ RCAR_GP_PIN(5, 10),
+};
+static const unsigned int scif1_clk_mux[] = {
+ SCK1_MARK,
+};
+static const unsigned int scif1_ctrl_pins[] = {
+ /* RTS1_N, CTS1_N */
+ RCAR_GP_PIN(5, 8), RCAR_GP_PIN(5, 9),
+};
+static const unsigned int scif1_ctrl_mux[] = {
+ RTS1_N_MARK, CTS1_N_MARK,
+};
+
+/* - SCIF3 ----------------------------------------------------------------- */
+static const unsigned int scif3_data_pins[] = {
+ /* RX3, TX3 */
+ RCAR_GP_PIN(6, 18), RCAR_GP_PIN(8, 17),
+};
+static const unsigned int scif3_data_mux[] = {
+ RX3_MARK, TX3_MARK,
+};
+static const unsigned int scif3_clk_pins[] = {
+ /* SCK3 */
+ RCAR_GP_PIN(6, 21),
+};
+static const unsigned int scif3_clk_mux[] = {
+ SCK3_MARK,
+};
+static const unsigned int scif3_ctrl_pins[] = {
+ /* RTS3_N, CTS3_N */
+ RCAR_GP_PIN(6, 22), RCAR_GP_PIN(6, 23),
+};
+static const unsigned int scif3_ctrl_mux[] = {
+ RTS3_N_MARK, CTS3_N_MARK,
+};
+
+/* - SCIF4 ----------------------------------------------------------------- */
+static const unsigned int scif4_data_a_pins[] = {
+ /* RX4_A, TX4_A */
+ RCAR_GP_PIN(8, 5), RCAR_GP_PIN(8, 4),
+};
+static const unsigned int scif4_data_a_mux[] = {
+ RX4_A_MARK, TX4_A_MARK,
+};
+static const unsigned int scif4_clk_a_pins[] = {
+ /* SCK4_A */
+ RCAR_GP_PIN(8, 3),
+};
+static const unsigned int scif4_clk_a_mux[] = {
+ SCK4_A_MARK,
+};
+static const unsigned int scif4_ctrl_a_pins[] = {
+ /* RTS4_A_N, CTS4_A_N */
+ RCAR_GP_PIN(8, 6), RCAR_GP_PIN(8, 7),
+};
+static const unsigned int scif4_ctrl_a_mux[] = {
+ RTS4_N_A_MARK, CTS4_N_A_MARK,
+};
+
+static const unsigned int scif4_data_b_pins[] = {
+ /* RX4_B, TX4_B */
+ RCAR_GP_PIN(7, 30), RCAR_GP_PIN(7, 26),
+};
+static const unsigned int scif4_data_b_mux[] = {
+ RX4_B_MARK, TX4_B_MARK,
+};
+static const unsigned int scif4_clk_b_pins[] = {
+ /* SCK4_B */
+ RCAR_GP_PIN(7, 20),
+};
+static const unsigned int scif4_clk_b_mux[] = {
+ SCK4_B_MARK,
+};
+static const unsigned int scif4_ctrl_b_pins[] = {
+ /* RTS4_B_N, CTS4_B_N */
+ RCAR_GP_PIN(7, 22), RCAR_GP_PIN(7, 24),
+};
+static const unsigned int scif4_ctrl_b_mux[] = {
+ RTS4_N_B_MARK, CTS4_N_B_MARK,
+};
+
+/* - SCIF Clock ------------------------------------------------------------- */
+static const unsigned int scif_clk_pins[] = {
+ /* SCIF_CLK */
+ RCAR_GP_PIN(5, 5),
+};
+static const unsigned int scif_clk_mux[] = {
+ SCIF_CLK_MARK,
+};
+
+/* - I2C0 ------------------------------------------------------------------- */
+static const unsigned int i2c0_pins[] = {
+ /* SDA0, SCL0 */
+ RCAR_GP_PIN(2, 20), RCAR_GP_PIN(2, 19),
+};
+static const unsigned int i2c0_mux[] = {
+ SDA0_MARK, SCL0_MARK,
+};
+
+/* - I2C1 ------------------------------------------------------------------- */
+static const unsigned int i2c1_pins[] = {
+ /* SDA1, SCL1 */
+ RCAR_GP_PIN(8, 1), RCAR_GP_PIN(8, 0),
+};
+static const unsigned int i2c1_mux[] = {
+ SDA1_MARK, SCL1_MARK,
+};
+
+/* - I2C2 ------------------------------------------------------------------- */
+static const unsigned int i2c2_pins[] = {
+ /* SDA2, SCL2 */
+ RCAR_GP_PIN(8, 3), RCAR_GP_PIN(8, 2),
+};
+static const unsigned int i2c2_mux[] = {
+ SDA2_MARK, SCL2_MARK,
+};
+
+/* - I2C3 ------------------------------------------------------------------- */
+static const unsigned int i2c3_pins[] = {
+ /* SDA3, SCL3 */
+ RCAR_GP_PIN(8, 5), RCAR_GP_PIN(8, 4),
+};
+static const unsigned int i2c3_mux[] = {
+ SDA3_MARK, SCL3_MARK,
+};
+
+/* - I2C4 ------------------------------------------------------------------- */
+static const unsigned int i2c4_pins[] = {
+ /* SDA4, SCL4 */
+ RCAR_GP_PIN(8, 7), RCAR_GP_PIN(8, 6),
+};
+static const unsigned int i2c4_mux[] = {
+ SDA4_MARK, SCL4_MARK,
+};
+
+/* - I2C5 ------------------------------------------------------------------- */
+static const unsigned int i2c5_pins[] = {
+ /* SDA5, SCL5 */
+ RCAR_GP_PIN(8, 9), RCAR_GP_PIN(8, 8),
+};
+static const unsigned int i2c5_mux[] = {
+ SDA5_MARK, SCL5_MARK,
+};
+
+/* - I2C6 ------------------------------------------------------------------- */
+static const unsigned int i2c6_pins[] = {
+ /* SDA6, SCL6 */
+ RCAR_GP_PIN(8, 11), RCAR_GP_PIN(8, 10),
+};
+static const unsigned int i2c6_mux[] = {
+ SDA6_MARK, SCL6_MARK,
+};
+
+/* - I2C7 ------------------------------------------------------------------- */
+static const unsigned int i2c7_pins[] = {
+ /* SDA7, SCL7 */
+ RCAR_GP_PIN(8, 13), RCAR_GP_PIN(8, 12),
+};
+static const unsigned int i2c7_mux[] = {
+ SDA7_MARK, SCL7_MARK,
+};
+
+/* - I2C8 ------------------------------------------------------------------- */
+static const unsigned int i2c8_pins[] = {
+ /* SDA8, SCL8 */
+ RCAR_GP_PIN(8, 15), RCAR_GP_PIN(8, 14),
+};
+static const unsigned int i2c8_mux[] = {
+ SDA8_MARK, SCL8_MARK,
+};
+
+/* - INTC-EX ---------------------------------------------------------------- */
+static const unsigned int intc_ex_irq0_pins[] = {
+ /* IRQ0_A, IRQ0_B */
+ RCAR_GP_PIN(5, 11), RCAR_GP_PIN(5, 2),
+};
+static const unsigned int intc_ex_irq0_mux[] = {
+ IRQ0_A_MARK, IRQ0_B_MARK,
+};
+static const unsigned int intc_ex_irq1_pins[] = {
+ /* IRQ1_A, IRQ1_B */
+ RCAR_GP_PIN(5, 12), RCAR_GP_PIN(5, 3),
+};
+static const unsigned int intc_ex_irq1_mux[] = {
+ IRQ1_A_MARK, IRQ1_B_MARK,
+};
+static const unsigned int intc_ex_irq2_pins[] = {
+ /* IRQ2_A, IRQ2_B */
+ RCAR_GP_PIN(5, 13), RCAR_GP_PIN(9, 10),
+};
+static const unsigned int intc_ex_irq2_mux[] = {
+ IRQ2_A_MARK, IRQ2_B_MARK,
+};
+static const unsigned int intc_ex_irq3_pins[] = {
+ /* IRQ3_A, IRQ3_B */
+ RCAR_GP_PIN(5, 14), RCAR_GP_PIN(9, 11),
+};
+static const unsigned int intc_ex_irq3_mux[] = {
+ IRQ3_A_MARK, IRQ3_B_MARK,
+};
+
+/* - PCIE4 ------------------------------------------------------------------- */
+static const unsigned int pcie40_clkreq_n_pins[] = {
+ /* PCIE40_CLKREQ_N */
+ RCAR_GP_PIN(10, 12),
+};
+
+static const unsigned int pcie40_clkreq_n_mux[] = {
+ PCIE40_CLKREQ_N_MARK,
+};
+
+static const unsigned int pcie41_clkreq_n_pins[] = {
+ /* PCIE41_CLKREQ_N */
+ RCAR_GP_PIN(10, 13),
+};
+
+static const unsigned int pcie41_clkreq_n_mux[] = {
+ PCIE41_CLKREQ_N_MARK,
+};
+
+/* - PCIE6 ------------------------------------------------------------------- */
+static const unsigned int pcie60_clkreq_n_pins[] = {
+ /* PCIE60_CLKREQ_N */
+ RCAR_GP_PIN(4, 14),
+};
+
+static const unsigned int pcie60_clkreq_n_mux[] = {
+ PCIE60_CLKREQ_N_MARK,
+};
+
+static const unsigned int pcie61_clkreq_n_pins[] = {
+ /* PCIE61_CLKREQ_N */
+ RCAR_GP_PIN(4, 15),
+};
+
+static const unsigned int pcie61_clkreq_n_mux[] = {
+ PCIE61_CLKREQ_N_MARK,
+};
+
+/* - QSPI0 ------------------------------------------------------------------ */
+static const unsigned int qspi0_ctrl_pins[] = {
+ /* SPCLK, SSL */
+ RCAR_GP_PIN(3, 0), RCAR_GP_PIN(3, 5),
+};
+static const unsigned int qspi0_ctrl_mux[] = {
+ QSPI0_SPCLK_MARK, QSPI0_SSL_MARK,
+};
+static const unsigned int qspi0_data_pins[] = {
+ /* MOSI_IO0, MISO_IO1, IO2, IO3 */
+ RCAR_GP_PIN(3, 1), RCAR_GP_PIN(3, 2),
+ RCAR_GP_PIN(3, 3), RCAR_GP_PIN(3, 4),
+};
+static const unsigned int qspi0_data_mux[] = {
+ QSPI0_MOSI_IO0_MARK, QSPI0_MISO_IO1_MARK,
+ QSPI0_IO2_MARK, QSPI0_IO3_MARK,
+};
+
+/* - QSPI1 ------------------------------------------------------------------ */
+static const unsigned int qspi1_ctrl_pins[] = {
+ /* SPCLK, SSL */
+ RCAR_GP_PIN(3, 9), RCAR_GP_PIN(3, 14),
+};
+static const unsigned int qspi1_ctrl_mux[] = {
+ QSPI1_SPCLK_MARK, QSPI1_SSL_MARK,
+};
+static const unsigned int qspi1_data_pins[] = {
+ /* MOSI_IO0, MISO_IO1, IO2, IO3 */
+ RCAR_GP_PIN(3, 10), RCAR_GP_PIN(3, 11),
+ RCAR_GP_PIN(3, 12), RCAR_GP_PIN(3, 13),
+};
+static const unsigned int qspi1_data_mux[] = {
+ QSPI1_MOSI_IO0_MARK, QSPI1_MISO_IO1_MARK,
+ QSPI1_IO2_MARK, QSPI1_IO3_MARK,
+};
+
+/* - SDHI/MMC0 --------------------------------------------------------------- */
+static const unsigned int mmc0_data_pins[] = {
+ /* MMC0_SD_D[0:3], MMC0_D[4:7] */
+ RCAR_GP_PIN(4, 2), RCAR_GP_PIN(4, 3),
+ RCAR_GP_PIN(4, 4), RCAR_GP_PIN(4, 5),
+ RCAR_GP_PIN(4, 6), RCAR_GP_PIN(4, 7),
+ RCAR_GP_PIN(4, 8), RCAR_GP_PIN(4, 9),
+};
+static const unsigned int mmc0_data_mux[] = {
+ MMC0_SD_D0_MARK, MMC0_SD_D1_MARK,
+ MMC0_SD_D2_MARK, MMC0_SD_D3_MARK,
+ MMC0_D4_MARK, MMC0_D5_MARK,
+ MMC0_D6_MARK, MMC0_D7_MARK,
+};
+static const unsigned int mmc0_ctrl_pins[] = {
+ /* MMC0_SD_CLK, MMC0_SD_CMD */
+ RCAR_GP_PIN(4, 0), RCAR_GP_PIN(4, 1),
+};
+static const unsigned int mmc0_ctrl_mux[] = {
+ MMC0_SD_CLK_MARK, MMC0_SD_CMD_MARK,
+};
+static const unsigned int mmc0_cd_pins[] = {
+ /* SD0_CD */
+ RCAR_GP_PIN(4, 12),
+};
+static const unsigned int mmc0_cd_mux[] = {
+ SD0_CD_MARK,
+};
+static const unsigned int mmc0_wp_pins[] = {
+ /* SD0_WP */
+ RCAR_GP_PIN(4, 11),
+};
+static const unsigned int mmc0_wp_mux[] = {
+ SD0_WP_MARK,
+};
+static const unsigned int mmc0_ds_pins[] = {
+ /* MMC0_DS */
+ RCAR_GP_PIN(4, 10),
+};
+static const unsigned int mmc0_ds_mux[] = {
+ MMC0_DS_MARK,
+};
+
+/* - RSW3 ------------------------------------------------------------------ */
+static const unsigned int rsw3_match_pins[] = {
+ /* RSW3_MATCH */
+ RCAR_GP_PIN(9, 16),
+};
+static const unsigned int rsw3_match_mux[] = {
+ RSW3_MATCH_MARK,
+};
+static const unsigned int rsw3_capture_pins[] = {
+ /* RSW3_CAPTURE */
+ RCAR_GP_PIN(9, 15),
+};
+static const unsigned int rsw3_capture_mux[] = {
+ RSW3_CAPTURE_MARK,
+};
+static const unsigned int rsw3_pps_pins[] = {
+ /* RSW3_PPS */
+ RCAR_GP_PIN(9, 14),
+};
+static const unsigned int rsw3_pps_mux[] = {
+ RSW3_PPS_MARK,
+};
+
+/* - TSN0 ------------------------------------------------ */
+static const unsigned int eth10g0_link_pins[] = {
+ /* ETH10G0_LINK */
+ RCAR_GP_PIN(9, 12),
+};
+static const unsigned int eth10g0_link_mux[] = {
+ ETH10G0_LINK_MARK,
+};
+static const unsigned int eth10g0_phyint_pins[] = {
+ /* ETH10G0_PHYINT */
+ RCAR_GP_PIN(9, 13),
+};
+static const unsigned int eth10g0_phyint_mux[] = {
+ ETH10G0_PHYINT_MARK,
+};
+static const unsigned int eth10g0_mdio_pins[] = {
+ /* ETH10G0_MDC, ETH10G0_MDIO */
+ RCAR_GP_PIN(9, 11), RCAR_GP_PIN(9, 10),
+};
+static const unsigned int eth10g0_mdio_mux[] = {
+ ETH10G0_MDC_MARK, ETH10G0_MDIO_MARK,
+};
+
+static const unsigned int eth25g0_link_pins[] = {
+ /* ETH25G0_LINK */
+ RCAR_GP_PIN(9, 8),
+};
+static const unsigned int eth25g0_link_mux[] = {
+ ETH25G0_LINK_MARK,
+};
+static const unsigned int eth25g0_phyint_pins[] = {
+ /* ETH25G0_PHYINT */
+ RCAR_GP_PIN(9, 9),
+};
+static const unsigned int eth25g0_phyint_mux[] = {
+ ETH25G0_PHYINT_MARK,
+};
+static const unsigned int eth25g0_mdio_pins[] = {
+ /* ETH25G0_MDC, ETH25G0_MDIO */
+ RCAR_GP_PIN(9, 7), RCAR_GP_PIN(9, 6),
+};
+static const unsigned int eth25g0_mdio_mux[] = {
+ ETH25G0_MDC_MARK, ETH25G0_MDIO_MARK,
+};
+
+/* - TSN1 ------------------------------------------------ */
+static const unsigned int eth10g1_link_pins[] = {
+ /* ETH10G1_LINK */
+ RCAR_GP_PIN(9, 12),
+};
+static const unsigned int eth10g1_link_mux[] = {
+ ETH10G1_LINK_MARK,
+};
+static const unsigned int eth10g1_phyint_pins[] = {
+ /* ETH10G1_PHYINT */
+ RCAR_GP_PIN(9, 13),
+};
+static const unsigned int eth10g1_phyint_mux[] = {
+ ETH10G1_PHYINT_MARK,
+};
+static const unsigned int eth10g1_mdio_pins[] = {
+ /* ETH10G1_MDC, ETH10G1_MDIO */
+ RCAR_GP_PIN(9, 11), RCAR_GP_PIN(9, 10),
+};
+static const unsigned int eth10g1_mdio_mux[] = {
+ ETH10G1_MDC_MARK, ETH10G1_MDIO_MARK,
+};
+
+static const unsigned int eth25g1_link_pins[] = {
+ /* ETH25G1_LINK */
+ RCAR_GP_PIN(9, 8),
+};
+static const unsigned int eth25g1_link_mux[] = {
+ ETH25G1_LINK_MARK,
+};
+static const unsigned int eth25g1_phyint_pins[] = {
+ /* ETH25G1_PHYINT */
+ RCAR_GP_PIN(9, 9),
+};
+static const unsigned int eth25g1_phyint_mux[] = {
+ ETH25G1_PHYINT_MARK,
+};
+static const unsigned int eth25g1_mdio_pins[] = {
+ /* ETH25G1_MDC, ETH25G1_MDIO */
+ RCAR_GP_PIN(9, 7), RCAR_GP_PIN(9, 6),
+};
+static const unsigned int eth25g1_mdio_mux[] = {
+ ETH25G1_MDC_MARK, ETH25G1_MDIO_MARK,
+};
+
+/* - TSN2 ------------------------------------------------ */
+static const unsigned int eth25g2_link_pins[] = {
+ /* ETH25G2_LINK */
+ RCAR_GP_PIN(9, 8),
+};
+static const unsigned int eth25g2_link_mux[] = {
+ ETH25G2_LINK_MARK,
+};
+static const unsigned int eth25g2_phyint_pins[] = {
+ /* ETH25G2_PHYINT */
+ RCAR_GP_PIN(9, 9),
+};
+static const unsigned int eth25g2_phyint_mux[] = {
+ ETH25G2_PHYINT_MARK,
+};
+static const unsigned int eth25g2_mdio_pins[] = {
+ /* ETH25G2_MDC, ETH25G2_MDIO */
+ RCAR_GP_PIN(9, 7), RCAR_GP_PIN(9, 6),
+};
+static const unsigned int eth25g2_mdio_mux[] = {
+ ETH25G2_MDC_MARK, ETH25G2_MDIO_MARK,
+};
+
+/* - gPTPa (TSN0) ---------------------------------------- */
+static const unsigned int ethes0_pps_pins[] = {
+ /* ETHES0_PPS */
+ RCAR_GP_PIN(9, 0),
+};
+static const unsigned int ethes0_pps_mux[] = {
+ ETHES0_PPS_MARK,
+};
+static const unsigned int ethes0_capture_pins[] = {
+ /* ETHES0_CAPTURE */
+ RCAR_GP_PIN(9, 1),
+};
+static const unsigned int ethes0_capture_mux[] = {
+ ETHES0_CAPTURE_MARK,
+};
+static const unsigned int ethes0_match_pins[] = {
+ /* ETHES0_MATCH */
+ RCAR_GP_PIN(9, 2),
+};
+static const unsigned int ethes0_match_mux[] = {
+ ETHES0_MATCH_MARK,
+};
+
+/* - gPTPb (TSN1-7) -------------------------------------- */
+static const unsigned int ethes1_pps_pins[] = {
+ /* ETHES1_PPS */
+ RCAR_GP_PIN(9, 0),
+};
+static const unsigned int ethes1_pps_mux[] = {
+ ETHES1_PPS_MARK,
+};
+static const unsigned int ethes1_capture_pins[] = {
+ /* ETHES1_CAPTURE */
+ RCAR_GP_PIN(9, 1),
+};
+static const unsigned int ethes1_capture_mux[] = {
+ ETHES1_CAPTURE_MARK,
+};
+static const unsigned int ethes1_match_pins[] = {
+ /* ETHES1_MATCH */
+ RCAR_GP_PIN(9, 2),
+};
+static const unsigned int ethes1_match_mux[] = {
+ ETHES1_MATCH_MARK,
+};
+
+static const unsigned int ethes2_pps_pins[] = {
+ /* ETHES2_PPS */
+ RCAR_GP_PIN(9, 0),
+};
+static const unsigned int ethes2_pps_mux[] = {
+ ETHES2_PPS_MARK,
+};
+static const unsigned int ethes2_capture_pins[] = {
+ /* ETHES2_CAPTURE */
+ RCAR_GP_PIN(9, 1),
+};
+static const unsigned int ethes2_capture_mux[] = {
+ ETHES2_CAPTURE_MARK,
+};
+static const unsigned int ethes2_match_pins[] = {
+ /* ETHES1_MATCH */
+ RCAR_GP_PIN(9, 2),
+};
+static const unsigned int ethes2_match_mux[] = {
+ ETHES2_MATCH_MARK,
+};
+
+static const unsigned int ethes3_pps_pins[] = {
+ /* ETHES3_PPS */
+ RCAR_GP_PIN(9, 0),
+};
+static const unsigned int ethes3_pps_mux[] = {
+ ETHES3_PPS_MARK,
+};
+static const unsigned int ethes3_capture_pins[] = {
+ /* ETHES3_CAPTURE */
+ RCAR_GP_PIN(9, 1),
+};
+static const unsigned int ethes3_capture_mux[] = {
+ ETHES3_CAPTURE_MARK,
+};
+static const unsigned int ethes3_match_pins[] = {
+ /* ETHES3_MATCH */
+ RCAR_GP_PIN(9, 2),
+};
+static const unsigned int ethes3_match_mux[] = {
+ ETHES3_MATCH_MARK,
+};
+
+static const unsigned int ethes4_pps_pins[] = {
+ /* ETHES4_PPS */
+ RCAR_GP_PIN(9, 3),
+};
+static const unsigned int ethes4_pps_mux[] = {
+ ETHES4_PPS_MARK,
+};
+static const unsigned int ethes4_capture_pins[] = {
+ /* ETHES4_CAPTURE */
+ RCAR_GP_PIN(9, 4),
+};
+static const unsigned int ethes4_capture_mux[] = {
+ ETHES4_CAPTURE_MARK,
+};
+static const unsigned int ethes4_match_pins[] = {
+ /* ETHES4_MATCH */
+ RCAR_GP_PIN(9, 5),
+};
+static const unsigned int ethes4_match_mux[] = {
+ ETHES4_MATCH_MARK,
+};
+
+static const unsigned int ethes5_pps_pins[] = {
+ /* ETHES5_PPS */
+ RCAR_GP_PIN(9, 3),
+};
+static const unsigned int ethes5_pps_mux[] = {
+ ETHES5_PPS_MARK,
+};
+static const unsigned int ethes5_capture_pins[] = {
+ /* ETHES5_CAPTURE */
+ RCAR_GP_PIN(9, 4),
+};
+static const unsigned int ethes5_capture_mux[] = {
+ ETHES5_CAPTURE_MARK,
+};
+static const unsigned int ethes5_match_pins[] = {
+ /* ETHES5_MATCH */
+ RCAR_GP_PIN(9, 5),
+};
+static const unsigned int ethes5_match_mux[] = {
+ ETHES5_MATCH_MARK,
+};
+
+static const unsigned int ethes6_pps_pins[] = {
+ /* ETHES6_PPS */
+ RCAR_GP_PIN(9, 3),
+};
+static const unsigned int ethes6_pps_mux[] = {
+ ETHES6_PPS_MARK,
+};
+static const unsigned int ethes6_capture_pins[] = {
+ /* ETHES6_CAPTURE */
+ RCAR_GP_PIN(9, 4),
+};
+static const unsigned int ethes6_capture_mux[] = {
+ ETHES6_CAPTURE_MARK,
+};
+static const unsigned int ethes6_match_pins[] = {
+ /* ETHES6_MATCH */
+ RCAR_GP_PIN(9, 5),
+};
+static const unsigned int ethes6_match_mux[] = {
+ ETHES6_MATCH_MARK,
+};
+
+static const unsigned int ethes7_pps_pins[] = {
+ /* ETHES7_PPS */
+ RCAR_GP_PIN(9, 3),
+};
+static const unsigned int ethes7_pps_mux[] = {
+ ETHES7_PPS_MARK,
+};
+static const unsigned int ethes7_capture_pins[] = {
+ /* ETHES7_CAPTURE */
+ RCAR_GP_PIN(9, 4),
+};
+static const unsigned int ethes7_capture_mux[] = {
+ ETHES7_CAPTURE_MARK,
+};
+static const unsigned int ethes7_match_pins[] = {
+ /* ETHES7_MATCH */
+ RCAR_GP_PIN(9, 5),
+};
+static const unsigned int ethes7_match_mux[] = {
+ ETHES7_MATCH_MARK,
+};
+
+static const struct sh_pfc_pin_group pinmux_groups[] = {
+ SH_PFC_PIN_GROUP(hscif0_data),
+ SH_PFC_PIN_GROUP(hscif0_clk),
+ SH_PFC_PIN_GROUP(hscif0_ctrl),
+ SH_PFC_PIN_GROUP(hscif1_data),
+ SH_PFC_PIN_GROUP(hscif1_clk),
+ SH_PFC_PIN_GROUP(hscif1_ctrl),
+ SH_PFC_PIN_GROUP(hscif2_data_a),
+ SH_PFC_PIN_GROUP(hscif2_clk_a),
+ SH_PFC_PIN_GROUP(hscif2_ctrl_a),
+ SH_PFC_PIN_GROUP(hscif2_data_b),
+ SH_PFC_PIN_GROUP(hscif2_clk_b),
+ SH_PFC_PIN_GROUP(hscif2_ctrl_b),
+ SH_PFC_PIN_GROUP(hscif3_data),
+ SH_PFC_PIN_GROUP(hscif3_clk),
+ SH_PFC_PIN_GROUP(hscif3_ctrl),
+
+ SH_PFC_PIN_GROUP(scif0_data),
+ SH_PFC_PIN_GROUP(scif0_clk),
+ SH_PFC_PIN_GROUP(scif0_ctrl),
+ SH_PFC_PIN_GROUP(scif1_data),
+ SH_PFC_PIN_GROUP(scif1_clk),
+ SH_PFC_PIN_GROUP(scif1_ctrl),
+ SH_PFC_PIN_GROUP(scif3_data),
+ SH_PFC_PIN_GROUP(scif3_clk),
+ SH_PFC_PIN_GROUP(scif3_ctrl),
+ SH_PFC_PIN_GROUP(scif4_data_a),
+ SH_PFC_PIN_GROUP(scif4_clk_a),
+ SH_PFC_PIN_GROUP(scif4_ctrl_a),
+ SH_PFC_PIN_GROUP(scif4_data_b),
+ SH_PFC_PIN_GROUP(scif4_clk_b),
+ SH_PFC_PIN_GROUP(scif4_ctrl_b),
+ SH_PFC_PIN_GROUP(scif_clk),
+
+ SH_PFC_PIN_GROUP(i2c0),
+ SH_PFC_PIN_GROUP(i2c1),
+ SH_PFC_PIN_GROUP(i2c2),
+ SH_PFC_PIN_GROUP(i2c3),
+ SH_PFC_PIN_GROUP(i2c4),
+ SH_PFC_PIN_GROUP(i2c5),
+ SH_PFC_PIN_GROUP(i2c6),
+ SH_PFC_PIN_GROUP(i2c7),
+ SH_PFC_PIN_GROUP(i2c8),
+
+ SH_PFC_PIN_GROUP(intc_ex_irq0),
+ SH_PFC_PIN_GROUP(intc_ex_irq1),
+ SH_PFC_PIN_GROUP(intc_ex_irq2),
+ SH_PFC_PIN_GROUP(intc_ex_irq3),
+
+ SH_PFC_PIN_GROUP(pcie40_clkreq_n),
+ SH_PFC_PIN_GROUP(pcie41_clkreq_n),
+ SH_PFC_PIN_GROUP(pcie60_clkreq_n),
+ SH_PFC_PIN_GROUP(pcie61_clkreq_n),
+
+ SH_PFC_PIN_GROUP(qspi0_ctrl),
+ BUS_DATA_PIN_GROUP(qspi0_data, 2),
+ BUS_DATA_PIN_GROUP(qspi0_data, 4),
+ SH_PFC_PIN_GROUP(qspi1_ctrl),
+ BUS_DATA_PIN_GROUP(qspi1_data, 2),
+ BUS_DATA_PIN_GROUP(qspi1_data, 4),
+
+ BUS_DATA_PIN_GROUP(mmc0_data, 1),
+ BUS_DATA_PIN_GROUP(mmc0_data, 4),
+ BUS_DATA_PIN_GROUP(mmc0_data, 8),
+ SH_PFC_PIN_GROUP(mmc0_ctrl),
+ SH_PFC_PIN_GROUP(mmc0_cd),
+ SH_PFC_PIN_GROUP(mmc0_wp),
+ SH_PFC_PIN_GROUP(mmc0_ds),
+
+ SH_PFC_PIN_GROUP(rsw3_match),
+ SH_PFC_PIN_GROUP(rsw3_capture),
+ SH_PFC_PIN_GROUP(rsw3_pps),
+
+ SH_PFC_PIN_GROUP(eth10g0_link),
+ SH_PFC_PIN_GROUP(eth10g0_phyint),
+ SH_PFC_PIN_GROUP(eth10g0_mdio),
+ SH_PFC_PIN_GROUP(eth25g0_link),
+ SH_PFC_PIN_GROUP(eth25g0_phyint),
+ SH_PFC_PIN_GROUP(eth25g0_mdio),
+
+ SH_PFC_PIN_GROUP(eth10g1_link),
+ SH_PFC_PIN_GROUP(eth10g1_phyint),
+ SH_PFC_PIN_GROUP(eth10g1_mdio),
+ SH_PFC_PIN_GROUP(eth25g1_link),
+ SH_PFC_PIN_GROUP(eth25g1_phyint),
+ SH_PFC_PIN_GROUP(eth25g1_mdio),
+
+ SH_PFC_PIN_GROUP(eth25g2_link),
+ SH_PFC_PIN_GROUP(eth25g2_phyint),
+ SH_PFC_PIN_GROUP(eth25g2_mdio),
+
+ SH_PFC_PIN_GROUP(ethes0_pps),
+ SH_PFC_PIN_GROUP(ethes0_capture),
+ SH_PFC_PIN_GROUP(ethes0_match),
+ SH_PFC_PIN_GROUP(ethes1_pps),
+ SH_PFC_PIN_GROUP(ethes1_capture),
+ SH_PFC_PIN_GROUP(ethes1_match),
+ SH_PFC_PIN_GROUP(ethes2_pps),
+ SH_PFC_PIN_GROUP(ethes2_capture),
+ SH_PFC_PIN_GROUP(ethes2_match),
+ SH_PFC_PIN_GROUP(ethes3_pps),
+ SH_PFC_PIN_GROUP(ethes3_capture),
+ SH_PFC_PIN_GROUP(ethes3_match),
+ SH_PFC_PIN_GROUP(ethes4_pps),
+ SH_PFC_PIN_GROUP(ethes4_capture),
+ SH_PFC_PIN_GROUP(ethes4_match),
+ SH_PFC_PIN_GROUP(ethes5_pps),
+ SH_PFC_PIN_GROUP(ethes5_capture),
+ SH_PFC_PIN_GROUP(ethes5_match),
+ SH_PFC_PIN_GROUP(ethes6_pps),
+ SH_PFC_PIN_GROUP(ethes6_capture),
+ SH_PFC_PIN_GROUP(ethes6_match),
+ SH_PFC_PIN_GROUP(ethes7_pps),
+ SH_PFC_PIN_GROUP(ethes7_capture),
+ SH_PFC_PIN_GROUP(ethes7_match),
+};
+
+static const char * const hscif0_groups[] = {
+ "hscif0_data",
+ "hscif0_clk",
+ "hscif0_ctrl",
+};
+
+static const char * const hscif1_groups[] = {
+ "hscif1_data",
+ "hscif1_clk",
+ "hscif1_ctrl",
+};
+
+static const char * const hscif2_groups[] = {
+ "hscif2_data_a",
+ "hscif2_clk_a",
+ "hscif2_ctrl_a",
+ "hscif2_data_b",
+ "hscif2_clk_b",
+ "hscif2_ctrl_b",
+};
+
+static const char * const hscif3_groups[] = {
+ "hscif3_data",
+ "hscif3_clk",
+ "hscif3_ctrl",
+};
+
+static const char * const scif0_groups[] = {
+ "scif0_data",
+ "scif0_clk",
+ "scif0_ctrl",
+};
+
+static const char * const scif1_groups[] = {
+ "scif1_data",
+ "scif1_clk",
+ "scif1_ctrl",
+};
+
+static const char * const scif3_groups[] = {
+ "scif3_data",
+ "scif3_clk",
+ "scif3_ctrl",
+};
+
+static const char * const scif4_groups[] = {
+ "scif4_data_a",
+ "scif4_clk_a",
+ "scif4_ctrl_a",
+ "scif4_data_b",
+ "scif4_clk_b",
+ "scif4_ctrl_b",
+};
+
+static const char * const scif_clk_groups[] = {
+ "scif_clk",
+};
+
+static const char * const i2c0_groups[] = {
+ "i2c0",
+};
+
+static const char * const i2c1_groups[] = {
+ "i2c1",
+};
+
+static const char * const i2c2_groups[] = {
+ "i2c2",
+};
+
+static const char * const i2c3_groups[] = {
+ "i2c3",
+};
+
+static const char * const i2c4_groups[] = {
+ "i2c4",
+};
+
+static const char * const i2c5_groups[] = {
+ "i2c5",
+};
+
+static const char * const i2c6_groups[] = {
+ "i2c6",
+};
+
+static const char * const i2c7_groups[] = {
+ "i2c7",
+};
+
+static const char * const i2c8_groups[] = {
+ "i2c8",
+};
+
+static const char * const intc_ex_groups[] = {
+ "intc_ex_irq0",
+ "intc_ex_irq1",
+ "intc_ex_irq2",
+ "intc_ex_irq3",
+};
+
+static const char * const pcie4_groups[] = {
+ "pcie40_clkreq_n",
+ "pcie41_clkreq_n",
+};
+
+static const char * const pcie6_groups[] = {
+ "pcie60_clkreq_n",
+ "pcie61_clkreq_n",
+};
+
+static const char * const qspi0_groups[] = {
+ "qspi0_ctrl",
+ "qspi0_data2",
+ "qspi0_data4",
+};
+
+static const char * const qspi1_groups[] = {
+ "qspi1_ctrl",
+ "qspi1_data2",
+ "qspi1_data4",
+};
+
+static const char * const mmc0_groups[] = {
+ "mmc0_data1",
+ "mmc0_data4",
+ "mmc0_data8",
+ "mmc0_ctrl",
+ "mmc0_cd",
+ "mmc0_wp",
+ "mmc0_ds",
+};
+
+static const char * const rsw3_groups[] = {
+ "rsw3_match",
+ "rsw3_capture",
+ "rsw3_pps",
+};
+
+static const char * const eth10g0_groups[] = {
+ "eth10g0_link",
+ "eth10g0_phyint",
+ "eth10g0_mdio",
+};
+
+static const char * const eth25g0_groups[] = {
+ "eth25g0_link",
+ "eth25g0_phyint",
+ "eth25g0_mdio",
+};
+
+static const char * const eth10g1_groups[] = {
+ "eth10g1_link",
+ "eth10g1_phyint",
+ "eth10g1_mdio",
+};
+
+static const char * const eth25g1_groups[] = {
+ "eth25g1_link",
+ "eth25g1_phyint",
+ "eth25g1_mdio",
+};
+
+static const char * const eth25g2_groups[] = {
+ "eth25g2_link",
+ "eth25g2_phyint",
+ "eth25g2_mdio",
+};
+
+static const char * const ethes0_groups[] = {
+ "ethes0_pps",
+ "ethes0_capture",
+ "ethes0_match",
+};
+
+static const char * const ethes1_groups[] = {
+ "ethes1_pps",
+ "ethes1_capture",
+ "ethes1_match",
+};
+
+static const char * const ethes2_groups[] = {
+ "ethes2_pps",
+ "ethes2_capture",
+ "ethes2_match",
+};
+
+static const char * const ethes3_groups[] = {
+ "ethes3_pps",
+ "ethes3_capture",
+ "ethes3_match",
+};
+
+static const char * const ethes4_groups[] = {
+ "ethes4_pps",
+ "ethes4_capture",
+ "ethes4_match",
+};
+
+static const char * const ethes5_groups[] = {
+ "ethes5_pps",
+ "ethes5_capture",
+ "ethes5_match",
+};
+
+static const char * const ethes6_groups[] = {
+ "ethes6_pps",
+ "ethes6_capture",
+ "ethes6_match",
+};
+
+static const char * const ethes7_groups[] = {
+ "ethes7_pps",
+ "ethes7_capture",
+ "ethes7_match",
+};
+
+static const struct sh_pfc_function pinmux_functions[] = {
+ SH_PFC_FUNCTION(hscif0),
+ SH_PFC_FUNCTION(hscif1),
+ SH_PFC_FUNCTION(hscif2),
+ SH_PFC_FUNCTION(hscif3),
+
+ SH_PFC_FUNCTION(scif0),
+ SH_PFC_FUNCTION(scif1),
+ SH_PFC_FUNCTION(scif3),
+ SH_PFC_FUNCTION(scif4),
+ SH_PFC_FUNCTION(scif_clk),
+
+ SH_PFC_FUNCTION(i2c0),
+ SH_PFC_FUNCTION(i2c1),
+ SH_PFC_FUNCTION(i2c2),
+ SH_PFC_FUNCTION(i2c3),
+ SH_PFC_FUNCTION(i2c4),
+ SH_PFC_FUNCTION(i2c5),
+ SH_PFC_FUNCTION(i2c6),
+ SH_PFC_FUNCTION(i2c7),
+ SH_PFC_FUNCTION(i2c8),
+
+ SH_PFC_FUNCTION(intc_ex),
+
+ SH_PFC_FUNCTION(pcie4),
+ SH_PFC_FUNCTION(pcie6),
+
+ SH_PFC_FUNCTION(qspi0),
+ SH_PFC_FUNCTION(qspi1),
+
+ SH_PFC_FUNCTION(mmc0),
+
+ SH_PFC_FUNCTION(rsw3),
+
+ SH_PFC_FUNCTION(eth10g0),
+ SH_PFC_FUNCTION(eth25g0),
+ SH_PFC_FUNCTION(eth10g1),
+ SH_PFC_FUNCTION(eth25g1),
+ SH_PFC_FUNCTION(eth25g2),
+
+ SH_PFC_FUNCTION(ethes0),
+ SH_PFC_FUNCTION(ethes1),
+ SH_PFC_FUNCTION(ethes2),
+ SH_PFC_FUNCTION(ethes3),
+ SH_PFC_FUNCTION(ethes4),
+ SH_PFC_FUNCTION(ethes5),
+ SH_PFC_FUNCTION(ethes6),
+ SH_PFC_FUNCTION(ethes7),
+};
+
+static const struct pinmux_cfg_reg pinmux_config_regs[] = {
+#define F_(x, y) FN_##y
+#define FM(x) FN_##x
+ { PINMUX_CFG_REG_VAR("GPSR0", 0xC1080040, 32,
+ GROUP(-4,
+ 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1),
+ GROUP(
+ /* GP0_31_28 RESERVED */
+ GP_0_27_FN, GPSR0_27,
+ GP_0_26_FN, GPSR0_26,
+ GP_0_25_FN, GPSR0_25,
+ GP_0_24_FN, GPSR0_24,
+ GP_0_23_FN, GPSR0_23,
+ GP_0_22_FN, GPSR0_22,
+ GP_0_21_FN, GPSR0_21,
+ GP_0_20_FN, GPSR0_20,
+ GP_0_19_FN, GPSR0_19,
+ GP_0_18_FN, GPSR0_18,
+ GP_0_17_FN, GPSR0_17,
+ GP_0_16_FN, GPSR0_16,
+ GP_0_15_FN, GPSR0_15,
+ GP_0_14_FN, GPSR0_14,
+ GP_0_13_FN, GPSR0_13,
+ GP_0_12_FN, GPSR0_12,
+ GP_0_11_FN, GPSR0_11,
+ GP_0_10_FN, GPSR0_10,
+ GP_0_9_FN, GPSR0_9,
+ GP_0_8_FN, GPSR0_8,
+ GP_0_7_FN, GPSR0_7,
+ GP_0_6_FN, GPSR0_6,
+ GP_0_5_FN, GPSR0_5,
+ GP_0_4_FN, GPSR0_4,
+ GP_0_3_FN, GPSR0_3,
+ GP_0_2_FN, GPSR0_2,
+ GP_0_1_FN, GPSR0_1,
+ GP_0_0_FN, GPSR0_0, ))
+ },
+ { PINMUX_CFG_REG_VAR("GPSR1", 0xC1080840, 32,
+ GROUP(-10,
+ 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1),
+ GROUP(
+ /* GP1_31_22 RESERVED */
+ GP_1_21_FN, GPSR1_21,
+ GP_1_20_FN, GPSR1_20,
+ GP_1_19_FN, GPSR1_19,
+ GP_1_18_FN, GPSR1_18,
+ GP_1_17_FN, GPSR1_17,
+ GP_1_16_FN, GPSR1_16,
+ GP_1_15_FN, GPSR1_15,
+ GP_1_14_FN, GPSR1_14,
+ GP_1_13_FN, GPSR1_13,
+ GP_1_12_FN, GPSR1_12,
+ GP_1_11_FN, GPSR1_11,
+ GP_1_10_FN, GPSR1_10,
+ GP_1_9_FN, GPSR1_9,
+ GP_1_8_FN, GPSR1_8,
+ GP_1_7_FN, GPSR1_7,
+ GP_1_6_FN, GPSR1_6,
+ GP_1_5_FN, GPSR1_5,
+ GP_1_4_FN, GPSR1_4,
+ GP_1_3_FN, GPSR1_3,
+ GP_1_2_FN, GPSR1_2,
+ GP_1_1_FN, GPSR1_1,
+ GP_1_0_FN, GPSR1_0, ))
+ },
+ { PINMUX_CFG_REG_VAR("GPSR2", 0xC1081040, 32,
+ GROUP(-3,
+ 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1),
+ GROUP(
+ /* GP2_31_29 RESERVED */
+ GP_2_28_FN, GPSR2_28,
+ GP_2_27_FN, GPSR2_27,
+ GP_2_26_FN, GPSR2_26,
+ GP_2_25_FN, GPSR2_25,
+ GP_2_24_FN, GPSR2_24,
+ GP_2_23_FN, GPSR2_23,
+ GP_2_22_FN, GPSR2_22,
+ GP_2_21_FN, GPSR2_21,
+ GP_2_20_FN, GPSR2_20,
+ GP_2_19_FN, GPSR2_19,
+ GP_2_18_FN, GPSR2_18,
+ GP_2_17_FN, GPSR2_17,
+ GP_2_16_FN, GPSR2_16,
+ GP_2_15_FN, GPSR2_15,
+ GP_2_14_FN, GPSR2_14,
+ GP_2_13_FN, GPSR2_13,
+ GP_2_12_FN, GPSR2_12,
+ GP_2_11_FN, GPSR2_11,
+ GP_2_10_FN, GPSR2_10,
+ GP_2_9_FN, GPSR2_9,
+ GP_2_8_FN, GPSR2_8,
+ GP_2_7_FN, GPSR2_7,
+ GP_2_6_FN, GPSR2_6,
+ GP_2_5_FN, GPSR2_5,
+ GP_2_4_FN, GPSR2_4,
+ GP_2_3_FN, GPSR2_3,
+ GP_2_2_FN, GPSR2_2,
+ GP_2_1_FN, GPSR2_1,
+ GP_2_0_FN, GPSR2_0, ))
+ },
+ { PINMUX_CFG_REG_VAR("GPSR3", 0xC0800040, 32,
+ GROUP(-15,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1),
+ GROUP(
+ /* GP3_31_17 RESERVED */
+ GP_3_16_FN, GPSR3_16,
+ GP_3_15_FN, GPSR3_15,
+ GP_3_14_FN, GPSR3_14,
+ GP_3_13_FN, GPSR3_13,
+ GP_3_12_FN, GPSR3_12,
+ GP_3_11_FN, GPSR3_11,
+ GP_3_10_FN, GPSR3_10,
+ GP_3_9_FN, GPSR3_9,
+ GP_3_8_FN, GPSR3_8,
+ GP_3_7_FN, GPSR3_7,
+ GP_3_6_FN, GPSR3_6,
+ GP_3_5_FN, GPSR3_5,
+ GP_3_4_FN, GPSR3_4,
+ GP_3_3_FN, GPSR3_3,
+ GP_3_2_FN, GPSR3_2,
+ GP_3_1_FN, GPSR3_1,
+ GP_3_0_FN, GPSR3_0, ))
+ },
+ { PINMUX_CFG_REG_VAR("GPSR4", 0xC0800840, 32,
+ GROUP(-16,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1),
+ GROUP(
+ /* GP4_31_16 RESERVED */
+ GP_4_15_FN, GPSR4_15,
+ GP_4_14_FN, GPSR4_14,
+ GP_4_13_FN, GPSR4_13,
+ GP_4_12_FN, GPSR4_12,
+ GP_4_11_FN, GPSR4_11,
+ GP_4_10_FN, GPSR4_10,
+ GP_4_9_FN, GPSR4_9,
+ GP_4_8_FN, GPSR4_8,
+ GP_4_7_FN, GPSR4_7,
+ GP_4_6_FN, GPSR4_6,
+ GP_4_5_FN, GPSR4_5,
+ GP_4_4_FN, GPSR4_4,
+ GP_4_3_FN, GPSR4_3,
+ GP_4_2_FN, GPSR4_2,
+ GP_4_1_FN, GPSR4_1,
+ GP_4_0_FN, GPSR4_0, ))
+ },
+ { PINMUX_CFG_REG_VAR("GPSR5", 0xC0400040, 32,
+ GROUP(-9,
+ 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1),
+ GROUP(
+ /* GP5_31_23 RESERVED */
+ GP_5_22_FN, GPSR5_22,
+ GP_5_21_FN, GPSR5_21,
+ GP_5_20_FN, GPSR5_20,
+ GP_5_19_FN, GPSR5_19,
+ GP_5_18_FN, GPSR5_18,
+ GP_5_17_FN, GPSR5_17,
+ GP_5_16_FN, GPSR5_16,
+ GP_5_15_FN, GPSR5_15,
+ GP_5_14_FN, GPSR5_14,
+ GP_5_13_FN, GPSR5_13,
+ GP_5_12_FN, GPSR5_12,
+ GP_5_11_FN, GPSR5_11,
+ GP_5_10_FN, GPSR5_10,
+ GP_5_9_FN, GPSR5_9,
+ GP_5_8_FN, GPSR5_8,
+ GP_5_7_FN, GPSR5_7,
+ GP_5_6_FN, GPSR5_6,
+ GP_5_5_FN, GPSR5_5,
+ GP_5_4_FN, GPSR5_4,
+ GP_5_3_FN, GPSR5_3,
+ GP_5_2_FN, GPSR5_2,
+ GP_5_1_FN, GPSR5_1,
+ GP_5_0_FN, GPSR5_0, ))
+ },
+ { PINMUX_CFG_REG("GPSR6", 0xC0400840, 32, 1, GROUP(
+ 0, 0,
+ GP_6_30_FN, GPSR6_30,
+ GP_6_29_FN, GPSR6_29,
+ GP_6_28_FN, GPSR6_28,
+ GP_6_27_FN, GPSR6_27,
+ GP_6_26_FN, GPSR6_26,
+ GP_6_25_FN, GPSR6_25,
+ GP_6_24_FN, GPSR6_24,
+ GP_6_23_FN, GPSR6_23,
+ GP_6_22_FN, GPSR6_22,
+ GP_6_21_FN, GPSR6_21,
+ GP_6_20_FN, GPSR6_20,
+ GP_6_19_FN, GPSR6_19,
+ GP_6_18_FN, GPSR6_18,
+ GP_6_17_FN, GPSR6_17,
+ GP_6_16_FN, GPSR6_16,
+ GP_6_15_FN, GPSR6_15,
+ GP_6_14_FN, GPSR6_14,
+ GP_6_13_FN, GPSR6_13,
+ GP_6_12_FN, GPSR6_12,
+ GP_6_11_FN, GPSR6_11,
+ GP_6_10_FN, GPSR6_10,
+ GP_6_9_FN, GPSR6_9,
+ GP_6_8_FN, GPSR6_8,
+ GP_6_7_FN, GPSR6_7,
+ GP_6_6_FN, GPSR6_6,
+ GP_6_5_FN, GPSR6_5,
+ GP_6_4_FN, GPSR6_4,
+ GP_6_3_FN, GPSR6_3,
+ GP_6_2_FN, GPSR6_2,
+ GP_6_1_FN, GPSR6_1,
+ GP_6_0_FN, GPSR6_0, ))
+ },
+ { PINMUX_CFG_REG("GPSR7", 0xC0401040, 32, 1, GROUP(
+ 0, 0,
+ GP_7_30_FN, GPSR7_30,
+ GP_7_29_FN, GPSR7_29,
+ GP_7_28_FN, GPSR7_28,
+ GP_7_27_FN, GPSR7_27,
+ GP_7_26_FN, GPSR7_26,
+ GP_7_25_FN, GPSR7_25,
+ GP_7_24_FN, GPSR7_24,
+ GP_7_23_FN, GPSR7_23,
+ GP_7_22_FN, GPSR7_22,
+ GP_7_21_FN, GPSR7_21,
+ GP_7_20_FN, GPSR7_20,
+ GP_7_19_FN, GPSR7_19,
+ GP_7_18_FN, GPSR7_18,
+ GP_7_17_FN, GPSR7_17,
+ GP_7_16_FN, GPSR7_16,
+ GP_7_15_FN, GPSR7_15,
+ GP_7_14_FN, GPSR7_14,
+ GP_7_13_FN, GPSR7_13,
+ GP_7_12_FN, GPSR7_12,
+ GP_7_11_FN, GPSR7_11,
+ GP_7_10_FN, GPSR7_10,
+ GP_7_9_FN, GPSR7_9,
+ GP_7_8_FN, GPSR7_8,
+ GP_7_7_FN, GPSR7_7,
+ GP_7_6_FN, GPSR7_6,
+ GP_7_5_FN, GPSR7_5,
+ GP_7_4_FN, GPSR7_4,
+ GP_7_3_FN, GPSR7_3,
+ GP_7_2_FN, GPSR7_2,
+ GP_7_1_FN, GPSR7_1,
+ GP_7_0_FN, GPSR7_0, ))
+ },
+ { PINMUX_CFG_REG_VAR("GPSR8", 0xC0401840, 32,
+ GROUP(1, 1, 1, 1, 1, 1,
+ -10,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1),
+ GROUP(
+ GP_8_31_FN, GPSR8_31,
+ GP_8_30_FN, GPSR8_30,
+ GP_8_29_FN, GPSR8_29,
+ GP_8_28_FN, GPSR8_28,
+ GP_8_27_FN, GPSR8_27,
+ GP_8_26_FN, GPSR8_26,
+ /* GP8_25_16 RESERVED */
+ GP_8_15_FN, GPSR8_15,
+ GP_8_14_FN, GPSR8_14,
+ GP_8_13_FN, GPSR8_13,
+ GP_8_12_FN, GPSR8_12,
+ GP_8_11_FN, GPSR8_11,
+ GP_8_10_FN, GPSR8_10,
+ GP_8_9_FN, GPSR8_9,
+ GP_8_8_FN, GPSR8_8,
+ GP_8_7_FN, GPSR8_7,
+ GP_8_6_FN, GPSR8_6,
+ GP_8_5_FN, GPSR8_5,
+ GP_8_4_FN, GPSR8_4,
+ GP_8_3_FN, GPSR8_3,
+ GP_8_2_FN, GPSR8_2,
+ GP_8_1_FN, GPSR8_1,
+ GP_8_0_FN, GPSR8_0, ))
+ },
+ { PINMUX_CFG_REG_VAR("GPSR9", 0xC9B00040, 32,
+ GROUP(-15,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1),
+ GROUP(
+ /* GP9_31_17 RESERVED */
+ GP_9_16_FN, GPSR9_16,
+ GP_9_15_FN, GPSR9_15,
+ GP_9_14_FN, GPSR9_14,
+ GP_9_13_FN, GPSR9_13,
+ GP_9_12_FN, GPSR9_12,
+ GP_9_11_FN, GPSR9_11,
+ GP_9_10_FN, GPSR9_10,
+ GP_9_9_FN, GPSR9_9,
+ GP_9_8_FN, GPSR9_8,
+ GP_9_7_FN, GPSR9_7,
+ GP_9_6_FN, GPSR9_6,
+ GP_9_5_FN, GPSR9_5,
+ GP_9_4_FN, GPSR9_4,
+ GP_9_3_FN, GPSR9_3,
+ GP_9_2_FN, GPSR9_2,
+ GP_9_1_FN, GPSR9_1,
+ GP_9_0_FN, GPSR9_0, ))
+ },
+ { PINMUX_CFG_REG_VAR("GPSR10", 0xC9B00840, 32,
+ GROUP(-18,
+ 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1),
+ GROUP(
+ /* GP10_31_14 RESERVED */
+ GP_10_13_FN, GPSR10_13,
+ GP_10_12_FN, GPSR10_12,
+ GP_10_11_FN, GPSR10_11,
+ GP_10_10_FN, GPSR10_10,
+ GP_10_9_FN, GPSR10_9,
+ GP_10_8_FN, GPSR10_8,
+ GP_10_7_FN, GPSR10_7,
+ GP_10_6_FN, GPSR10_6,
+ GP_10_5_FN, GPSR10_5,
+ GP_10_4_FN, GPSR10_4,
+ GP_10_3_FN, GPSR10_3,
+ GP_10_2_FN, GPSR10_2,
+ GP_10_1_FN, GPSR10_1,
+ GP_10_0_FN, GPSR10_0, ))
+ },
+#undef F_
+#undef FM
+
+#define F_(x, y) x,
+#define FM(x) FN_##x,
+ { PINMUX_CFG_REG("GP0_ALTSEL0", 0xC1080060, 32, 1, GROUP(
+ GP_ALTSEL0(0)
+ ))
+ },
+ { PINMUX_CFG_REG("GP0_ALTSEL1", 0xC1080064, 32, 1, GROUP(
+ GP_ALTSEL1(0)
+ ))
+ },
+ { PINMUX_CFG_REG("GP0_ALTSEL2", 0xC1080068, 32, 1, GROUP(
+ GP_ALTSEL2(0)
+ ))
+ },
+ { PINMUX_CFG_REG("GP0_ALTSEL3", 0xC108006C, 32, 1, GROUP(
+ GP_ALTSEL3(0)
+ ))
+ },
+ { PINMUX_CFG_REG("GP1_ALTSEL0", 0xC1080860, 32, 1, GROUP(
+ GP_ALTSEL0(1)
+ ))
+ },
+ { PINMUX_CFG_REG("GP1_ALTSEL1", 0xC1080864, 32, 1, GROUP(
+ GP_ALTSEL1(1)
+ ))
+ },
+ { PINMUX_CFG_REG("GP1_ALTSEL2", 0xC1080868, 32, 1, GROUP(
+ GP_ALTSEL2(1)
+ ))
+ },
+ { PINMUX_CFG_REG("GP1_ALTSEL3", 0xC108086C, 32, 1, GROUP(
+ GP_ALTSEL3(1)
+ ))
+ },
+ { PINMUX_CFG_REG("GP2_ALTSEL0", 0xC1081060, 32, 1, GROUP(
+ GP_ALTSEL0(2)
+ ))
+ },
+ { PINMUX_CFG_REG("GP2_ALTSEL1", 0xC1081064, 32, 1, GROUP(
+ GP_ALTSEL1(2)
+ ))
+ },
+ { PINMUX_CFG_REG("GP2_ALTSEL2", 0xC1081068, 32, 1, GROUP(
+ GP_ALTSEL2(2)
+ ))
+ },
+ { PINMUX_CFG_REG("GP2_ALTSEL3", 0xC108106C, 32, 1, GROUP(
+ GP_ALTSEL3(2)
+ ))
+ },
+ { PINMUX_CFG_REG("GP3_ALTSEL0", 0xC0800060, 32, 1, GROUP(
+ GP_ALTSEL0(3)
+ ))
+ },
+ { PINMUX_CFG_REG("GP3_ALTSEL1", 0xC0800064, 32, 1, GROUP(
+ GP_ALTSEL1(3)
+ ))
+ },
+ { PINMUX_CFG_REG("GP3_ALTSEL2", 0xC0800068, 32, 1, GROUP(
+ GP_ALTSEL2(3)
+ ))
+ },
+ { PINMUX_CFG_REG("GP3_ALTSEL3", 0xC080006C, 32, 1, GROUP(
+ GP_ALTSEL3(3)
+ ))
+ },
+ { PINMUX_CFG_REG("GP4_ALTSEL0", 0xC0800860, 32, 1, GROUP(
+ GP_ALTSEL0(4)
+ ))
+ },
+ { PINMUX_CFG_REG("GP4_ALTSEL1", 0xC0800864, 32, 1, GROUP(
+ GP_ALTSEL1(4)
+ ))
+ },
+ { PINMUX_CFG_REG("GP4_ALTSEL2", 0xC0800868, 32, 1, GROUP(
+ GP_ALTSEL2(4)
+ ))
+ },
+ { PINMUX_CFG_REG("GP4_ALTSEL3", 0xC080086C, 32, 1, GROUP(
+ GP_ALTSEL3(4)
+ ))
+ },
+ { PINMUX_CFG_REG("GP5_ALTSEL0", 0xC0400060, 32, 1, GROUP(
+ GP_ALTSEL0(5)
+ ))
+ },
+ { PINMUX_CFG_REG("GP5_ALTSEL1", 0xC0400064, 32, 1, GROUP(
+ GP_ALTSEL1(5)
+ ))
+ },
+ { PINMUX_CFG_REG("GP5_ALTSEL2", 0xC0400068, 32, 1, GROUP(
+ GP_ALTSEL2(5)
+ ))
+ },
+ { PINMUX_CFG_REG("GP5_ALTSEL3", 0xC040006C, 32, 1, GROUP(
+ GP_ALTSEL3(5)
+ ))
+ },
+ { PINMUX_CFG_REG("GP6_ALTSEL0", 0xC0400860, 32, 1, GROUP(
+ GP_ALTSEL0(6)
+ ))
+ },
+ { PINMUX_CFG_REG("GP6_ALTSEL1", 0xC0400864, 32, 1, GROUP(
+ GP_ALTSEL1(6)
+ ))
+ },
+ { PINMUX_CFG_REG("GP6_ALTSEL2", 0xC0400868, 32, 1, GROUP(
+ GP_ALTSEL2(6)
+ ))
+ },
+ { PINMUX_CFG_REG("GP6_ALTSEL3", 0xC040086C, 32, 1, GROUP(
+ GP_ALTSEL3(6)
+ ))
+ },
+ { PINMUX_CFG_REG("GP7_ALTSEL0", 0xC0401060, 32, 1, GROUP(
+ GP_ALTSEL0(7)
+ ))
+ },
+ { PINMUX_CFG_REG("GP7_ALTSEL1", 0xC0401064, 32, 1, GROUP(
+ GP_ALTSEL1(7)
+ ))
+ },
+ { PINMUX_CFG_REG("GP7_ALTSEL2", 0xC0401068, 32, 1, GROUP(
+ GP_ALTSEL2(7)
+ ))
+ },
+ { PINMUX_CFG_REG("GP7_ALTSEL3", 0xC040106C, 32, 1, GROUP(
+ GP_ALTSEL3(7)
+ ))
+ },
+ { PINMUX_CFG_REG("GP8_ALTSEL0", 0xC0401860, 32, 1, GROUP(
+ GP_ALTSEL0(8)
+ ))
+ },
+ { PINMUX_CFG_REG("GP8_ALTSEL1", 0xC0401864, 32, 1, GROUP(
+ GP_ALTSEL1(8)
+ ))
+ },
+ { PINMUX_CFG_REG("GP8_ALTSEL2", 0xC0401868, 32, 1, GROUP(
+ GP_ALTSEL2(8)
+ ))
+ },
+ { PINMUX_CFG_REG("GP8_ALTSEL3", 0xC040186C, 32, 1, GROUP(
+ GP_ALTSEL3(8)
+ ))
+ },
+ { PINMUX_CFG_REG("GP9_ALTSEL0", 0xC9B00060, 32, 1, GROUP(
+ GP_ALTSEL0(9)
+ ))
+ },
+ { PINMUX_CFG_REG("GP5_ALTSEL1", 0xC9B00064, 32, 1, GROUP(
+ GP_ALTSEL1(9)
+ ))
+ },
+ { PINMUX_CFG_REG("GP9_ALTSEL2", 0xC9B00068, 32, 1, GROUP(
+ GP_ALTSEL2(9)
+ ))
+ },
+ { PINMUX_CFG_REG("GP9_ALTSEL3", 0xC9B0006C, 32, 1, GROUP(
+ GP_ALTSEL3(9)
+ ))
+ },
+ { PINMUX_CFG_REG("GP10_ALTSEL0", 0xC9B00860, 32, 1, GROUP(
+ GP_ALTSEL0(10)
+ ))
+ },
+ { PINMUX_CFG_REG("GP10_ALTSEL1", 0xC9B00864, 32, 1, GROUP(
+ GP_ALTSEL1(10)
+ ))
+ },
+ { PINMUX_CFG_REG("GP10_ALTSEL2", 0xC9B00868, 32, 1, GROUP(
+ GP_ALTSEL2(10)
+ ))
+ },
+ { PINMUX_CFG_REG("GP10_ALTSEL3", 0xC9B0086C, 32, 1, GROUP(
+ GP_ALTSEL3(10)
+ ))
+ },
+#undef F_
+#undef FM
+
+#define F_(x, y) x,
+#define FM(x) FN_##x,
+ { PINMUX_CFG_REG_VAR("GP1_MODSEL", 0xC1080900, 32,
+ GROUP(-10,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ -14),
+ GROUP(
+ /* GP1_MODSEL_31_22 RESERVED */
+ GP1_MODSEL_21
+ GP1_MODSEL_20
+ GP1_MODSEL_19
+ GP1_MODSEL_18
+ GP1_MODSEL_17
+ GP1_MODSEL_16
+ GP1_MODSEL_15
+ GP1_MODSEL_14
+ /* GP1_MODSEL_13_0 RESERVED */
+ ))
+ },
+ { PINMUX_CFG_REG_VAR("GP2_MODSEL", 0xC1081100, 32,
+ GROUP(-11,
+ 1, 1,
+ -19),
+ GROUP(
+ /* GP2_MODSEL_31_21 RESERVED */
+ GP2_MODSEL_20
+ GP2_MODSEL_19
+ /* GP2_MODSEL_18_0 RESERVED */
+ ))
+ },
+ { PINMUX_CFG_REG_VAR("GP8_MODSEL", 0xC0401900, 32,
+ GROUP(-16,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1),
+ GROUP(
+ /* GP8_MODSEL_31_16 RESERVED */
+ GP8_MODSEL_15
+ GP8_MODSEL_14
+ GP8_MODSEL_13
+ GP8_MODSEL_12
+ GP8_MODSEL_11
+ GP8_MODSEL_10
+ GP8_MODSEL_9
+ GP8_MODSEL_8
+ GP8_MODSEL_7
+ GP8_MODSEL_6
+ GP8_MODSEL_5
+ GP8_MODSEL_4
+ GP8_MODSEL_3
+ GP8_MODSEL_2
+ GP8_MODSEL_1
+ GP8_MODSEL_0
+ ))
+ },
+ { },
+};
+
+#define RCAR5_PINMUX_DRIVE_REG(name1, r1, name2, r2, name3, r3) \
+ .drvctrl0 = r1, \
+ .drvctrl1 = r2, \
+ .drvctrl2 = r3, \
+ .pins =
+
+struct rcar5_pinmux_drive_reg {
+ u32 drvctrl0;
+ u32 drvctrl1;
+ u32 drvctrl2;
+ const u16 pins[32];
+};
+
+static const struct rcar5_pinmux_drive_reg pinmux_drive_regs[] = {
+ { RCAR5_PINMUX_DRIVE_REG("GP0_DRVCTRL0", 0xC1080080, "GP0_DRVCTRL1", 0xC1080084, "GP0_DRVCTRL2", 0xC1080088) {
+ [ 0] = RCAR_GP_PIN(0, 0), /* GP0_00 */
+ [ 1] = RCAR_GP_PIN(0, 1), /* GP0_01 */
+ [ 2] = RCAR_GP_PIN(0, 2), /* GP0_02 */
+ [ 3] = RCAR_GP_PIN(0, 3), /* STPWT_EXTFXR_A */
+ [ 4] = RCAR_GP_PIN(0, 4), /* FXR_CLKOUT1_A */
+ [ 5] = RCAR_GP_PIN(0, 5), /* FXR_CLKOUT2_A */
+ [ 6] = RCAR_GP_PIN(0, 6), /* CLK_EXTFXR_A */
+ [ 7] = RCAR_GP_PIN(0, 7), /* FXR_TXDA_A */
+ [ 8] = RCAR_GP_PIN(0, 8), /* FXR_TXENA_N_A */
+ [ 9] = RCAR_GP_PIN(0, 9), /* RXDA_EXTFXR_A */
+ [10] = RCAR_GP_PIN(0, 10), /* FXR_TXDB_A */
+ [11] = RCAR_GP_PIN(0, 11), /* FXR_TXENB_N_A */
+ [12] = RCAR_GP_PIN(0, 12), /* RXDB_EXTFXR_A */
+ [13] = RCAR_GP_PIN(0, 13), /* MSIOF0_SCK */
+ [14] = RCAR_GP_PIN(0, 14), /* MSIOF0_TXD */
+ [15] = RCAR_GP_PIN(0, 15), /* MSIOF0_RXD */
+ [16] = RCAR_GP_PIN(0, 16), /* MSIOF0_SYNC */
+ [17] = RCAR_GP_PIN(0, 17), /* MSIOF0_SS1 */
+ [18] = RCAR_GP_PIN(0, 18), /* MSIOF0_SS2 */
+ [19] = RCAR_GP_PIN(0, 19), /* MSIOF1_SCK_A */
+ [20] = RCAR_GP_PIN(0, 20), /* MSIOF1_TXD_A */
+ [21] = RCAR_GP_PIN(0, 21), /* MSIOF1_RXD_A */
+ [22] = RCAR_GP_PIN(0, 22), /* MSIOF1_SYNC_A */
+ [23] = RCAR_GP_PIN(0, 23), /* MSIOF1_SS1_A */
+ [24] = RCAR_GP_PIN(0, 24), /* MSIOF1_SS2_A */
+ [25] = RCAR_GP_PIN(0, 25), /* DP0_HOTPLUG */
+ [26] = RCAR_GP_PIN(0, 26), /* DP1_HOTPLUG */
+ [27] = RCAR_GP_PIN(0, 27), /* DP2_HOTPLUG */
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { RCAR5_PINMUX_DRIVE_REG("GP1_DRVCTRL0", 0xC1080880, "GP1_DRVCTRL1", 0xC1080884, "GP1_DRVCTRL2", 0xC1080888) {
+ [ 0] = RCAR_GP_PIN(1, 0), /* CAN0RX_INTP0 */
+ [ 1] = RCAR_GP_PIN(1, 1), /* CAN0TX */
+ [ 2] = RCAR_GP_PIN(1, 2), /* CAN1RX_INTP1 */
+ [ 3] = RCAR_GP_PIN(1, 3), /* CAN1TX */
+ [ 4] = RCAR_GP_PIN(1, 4), /* CAN2RX_INTP2 */
+ [ 5] = RCAR_GP_PIN(1, 5), /* CAN2TX */
+ [ 6] = RCAR_GP_PIN(1, 6), /* CAN3RX_INTP3 */
+ [ 7] = RCAR_GP_PIN(1, 7), /* CAN3TX */
+ [ 8] = RCAR_GP_PIN(1, 8), /* CAN4RX_INTP4 */
+ [ 9] = RCAR_GP_PIN(1, 9), /* CAN4TX */
+ [10] = RCAR_GP_PIN(1, 10), /* CAN5RX_INTP5 */
+ [11] = RCAR_GP_PIN(1, 11), /* CAN5TX */
+ [12] = RCAR_GP_PIN(1, 12), /* CAN6RX_INTP6 */
+ [13] = RCAR_GP_PIN(1, 13), /* CAN6TX */
+ [14] = RCAR_GP_PIN(1, 14), /* RLIN30RX_INTP16 */
+ [15] = RCAR_GP_PIN(1, 15), /* RLIN30TX */
+ [16] = RCAR_GP_PIN(1, 16), /* RLIN31RX_INTP17 */
+ [17] = RCAR_GP_PIN(1, 17), /* RLIN31TX */
+ [18] = RCAR_GP_PIN(1, 18), /* RLIN32RX_INTP18 */
+ [19] = RCAR_GP_PIN(1, 19), /* RLIN32TX */
+ [20] = RCAR_GP_PIN(1, 20), /* RLIN33RX_INTP19 */
+ [21] = RCAR_GP_PIN(1, 21), /* RLIN33TX */
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { RCAR5_PINMUX_DRIVE_REG("GP2_DRVCTRL0", 0xC1081080, "GP2_DRVCTRL1", 0xC1081084, "GP2_DRVCTRL2", 0xC1081088) {
+ [ 0] = RCAR_GP_PIN(2, 0), /* RLIN34RX_INTP20_B */
+ [ 1] = RCAR_GP_PIN(2, 1), /* RLIN34TX_B */
+ [ 2] = RCAR_GP_PIN(2, 2), /* RLIN35RX_INTP21_B */
+ [ 3] = RCAR_GP_PIN(2, 3), /* RLIN35TX_B */
+ [ 4] = RCAR_GP_PIN(2, 4), /* RLIN36RX_INTP22_B */
+ [ 5] = RCAR_GP_PIN(2, 5), /* RLIN36TX_B */
+ [ 6] = RCAR_GP_PIN(2, 6), /* RLIN37RX_INTP23_B */
+ [ 7] = RCAR_GP_PIN(2, 7), /* RLIN37TX_B */
+ [ 8] = RCAR_GP_PIN(2, 8), /* CAN12RX_INTP12_B */
+ [ 9] = RCAR_GP_PIN(2, 9), /* CAN12TX_B */
+ [10] = RCAR_GP_PIN(2, 10), /* CAN13RX_INTP13_B */
+ [11] = RCAR_GP_PIN(2, 11), /* CAN13TX_B */
+ [12] = RCAR_GP_PIN(2, 12), /* CAN14RX_INTP14_B */
+ [13] = RCAR_GP_PIN(2, 13), /* CAN14TX_B */
+ [14] = RCAR_GP_PIN(2, 14), /* CAN15RX_INTP15_B */
+ [15] = RCAR_GP_PIN(2, 15), /* CAN15TX_B */
+ [16] = RCAR_GP_PIN(2, 16), /* CAN_CLK */
+ [17] = RCAR_GP_PIN(2, 17), /* INTP32_B */
+ [18] = RCAR_GP_PIN(2, 18), /* INTP33_B */
+ [19] = RCAR_GP_PIN(2, 19), /* SCL0 */
+ [20] = RCAR_GP_PIN(2, 20), /* SDA0 */
+ [21] = RCAR_GP_PIN(2, 21), /* AVS0 */
+ [22] = RCAR_GP_PIN(2, 22), /* AVS1 */
+ [23] = RCAR_GP_PIN(2, 23), /* EXTCLK0O_B */
+ [24] = RCAR_GP_PIN(2, 24), /* TAUD1O0 */
+ [25] = RCAR_GP_PIN(2, 25), /* TAUD1O1 */
+ [26] = RCAR_GP_PIN(2, 26), /* TAUD1O2 */
+ [27] = RCAR_GP_PIN(2, 27), /* TAUD1O3 */
+ [28] = RCAR_GP_PIN(2, 28), /* INTP34_B */
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { RCAR5_PINMUX_DRIVE_REG("GP3_DRVCTRL0", 0xC0800080, "GP3_DRVCTRL1", 0xC0800084, "GP3_DRVCTRL2", 0xC0800088) {
+ [ 0] = RCAR_GP_PIN(3, 0), /* QSPI0_SPCLK */
+ [ 1] = RCAR_GP_PIN(3, 1), /* QSPI0_MOSI_IO0 */
+ [ 2] = RCAR_GP_PIN(3, 2), /* QSPI0_MISO_IO1 */
+ [ 3] = RCAR_GP_PIN(3, 3), /* QSPI0_IO2 */
+ [ 4] = RCAR_GP_PIN(3, 4), /* QSPI0_IO3 */
+ [ 5] = RCAR_GP_PIN(3, 5), /* QSPI0_SSL */
+ [ 6] = RCAR_GP_PIN(3, 6), /* RPC_RESET_N */
+ [ 7] = RCAR_GP_PIN(3, 7), /* RPC_WP_N */
+ [ 8] = RCAR_GP_PIN(3, 8), /* RPC_INT_N */
+ [ 9] = RCAR_GP_PIN(3, 9), /* QSPI1_SPCLK */
+ [10] = RCAR_GP_PIN(3, 10), /* QSPI1_MOSI_IO0 */
+ [11] = RCAR_GP_PIN(3, 11), /* QSPI1_MISO_IO1 */
+ [12] = RCAR_GP_PIN(3, 12), /* QSPI1_IO2 */
+ [13] = RCAR_GP_PIN(3, 13), /* QSPI1_IO3 */
+ [14] = RCAR_GP_PIN(3, 14), /* QSPI1_SSL */
+ [15] = RCAR_GP_PIN(3, 15), /* ERROROUT_N */
+ [16] = RCAR_GP_PIN(3, 16), /* ERRORIN_N */
+ [17] = SH_PFC_PIN_NONE,
+ [18] = SH_PFC_PIN_NONE,
+ [19] = SH_PFC_PIN_NONE,
+ [20] = SH_PFC_PIN_NONE,
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { RCAR5_PINMUX_DRIVE_REG("GP4_DRVCTRL0", 0xC0800880, "GP4_DRVCTRL1", 0xC0800884, "GP4_DRVCTRL2", 0xC0800888) {
+ [ 0] = RCAR_GP_PIN(4, 0), /* MMC0_SD_CLK */
+ [ 1] = RCAR_GP_PIN(4, 1), /* MMC0_SD_CMD */
+ [ 2] = RCAR_GP_PIN(4, 2), /* MMC0_SD_D0 */
+ [ 3] = RCAR_GP_PIN(4, 3), /* MMC0_SD_D1 */
+ [ 4] = RCAR_GP_PIN(4, 4), /* MMC0_SD_D2 */
+ [ 5] = RCAR_GP_PIN(4, 5), /* MMC0_SD_D3 */
+ [ 6] = RCAR_GP_PIN(4, 6), /* MMC0_D4 */
+ [ 7] = RCAR_GP_PIN(4, 7), /* MMC0_D5 */
+ [ 8] = RCAR_GP_PIN(4, 8), /* MMC0_D6 */
+ [ 9] = RCAR_GP_PIN(4, 9), /* MMC0_D7 */
+ [10] = RCAR_GP_PIN(4, 10), /* MMC0_DS */
+ [11] = RCAR_GP_PIN(4, 11), /* SD0_WP */
+ [12] = RCAR_GP_PIN(4, 12), /* SD0_CD */
+ [13] = RCAR_GP_PIN(4, 13), /* ERRORIN_N */
+ [14] = RCAR_GP_PIN(4, 14), /* PCIE60_CLKREQ_N */
+ [15] = RCAR_GP_PIN(4, 15), /* PCIE61_CLKREQ_N */
+ [16] = SH_PFC_PIN_NONE,
+ [17] = SH_PFC_PIN_NONE,
+ [18] = SH_PFC_PIN_NONE,
+ [19] = SH_PFC_PIN_NONE,
+ [20] = SH_PFC_PIN_NONE,
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { RCAR5_PINMUX_DRIVE_REG("GP5_DRVCTRL0", 0xC0400080, "GP5_DRVCTRL1", 0xC0400084, "GP5_DRVCTRL2", 0xC0400088) {
+ [ 0] = RCAR_GP_PIN(5, 0), /* HTX0 */
+ [ 1] = RCAR_GP_PIN(5, 1), /* HRX0 */
+ [ 2] = RCAR_GP_PIN(5, 2), /* HRTS0_N */
+ [ 3] = RCAR_GP_PIN(5, 3), /* HCTS0_N */
+ [ 4] = RCAR_GP_PIN(5, 4), /* HSCK0 */
+ [ 5] = RCAR_GP_PIN(5, 5), /* SCIF_CLK */
+ [ 6] = RCAR_GP_PIN(5, 6), /* HTX1 */
+ [ 7] = RCAR_GP_PIN(5, 7), /* HRX1 */
+ [ 8] = RCAR_GP_PIN(5, 8), /* HRTS1_N */
+ [ 9] = RCAR_GP_PIN(5, 9), /* HCTS1_N */
+ [10] = RCAR_GP_PIN(5, 10), /* HSCK1 */
+ [11] = RCAR_GP_PIN(5, 11), /* IRQ0_A */
+ [12] = RCAR_GP_PIN(5, 12), /* IRQ1_A */
+ [13] = RCAR_GP_PIN(5, 13), /* IRQ2_A */
+ [14] = RCAR_GP_PIN(5, 14), /* IRQ3_A */
+ [15] = RCAR_GP_PIN(5, 15), /* TCLK1 */
+ [16] = RCAR_GP_PIN(5, 16), /* TCLK2 */
+ [17] = RCAR_GP_PIN(5, 17), /* TCLK3 */
+ [18] = RCAR_GP_PIN(5, 18), /* TCLK4 */
+ [19] = RCAR_GP_PIN(5, 19), /* TPU0TO0 */
+ [20] = RCAR_GP_PIN(5, 20), /* TPU0TO1 */
+ [21] = RCAR_GP_PIN(5, 21), /* TPU0TO2 */
+ [22] = RCAR_GP_PIN(5, 22), /* TPU0TO3 */
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { RCAR5_PINMUX_DRIVE_REG("GP6_DRVCTRL0", 0xC0400880, "GP6_DRVCTRL1", 0xC0400884, "GP6_DRVCTRL2", 0xC0400888) {
+ [ 0] = RCAR_GP_PIN(6, 0), /* RIF6_D0 */
+ [ 1] = RCAR_GP_PIN(6, 1), /* RIF6_D1 */
+ [ 2] = RCAR_GP_PIN(6, 2), /* RIF6_SYNC */
+ [ 3] = RCAR_GP_PIN(6, 3), /* RIF6_CLK */
+ [ 4] = RCAR_GP_PIN(6, 4), /* MSIOF7_SCK_A */
+ [ 5] = RCAR_GP_PIN(6, 5), /* MSIOF7_TXD_A */
+ [ 6] = RCAR_GP_PIN(6, 6), /* MSIOF7_RXD_A */
+ [ 7] = RCAR_GP_PIN(6, 7), /* MSIOF7_SYNC_A */
+ [ 8] = RCAR_GP_PIN(6, 8), /* MSIOF7_SS1_A */
+ [ 9] = RCAR_GP_PIN(6, 9), /* MSIOF7_SS2_A */
+ [10] = RCAR_GP_PIN(6, 10), /* MSIOF4_SCK_B */
+ [11] = RCAR_GP_PIN(6, 11), /* MSIOF4_TXD_B */
+ [12] = RCAR_GP_PIN(6, 12), /* MSIOF4_RXD_B */
+ [13] = RCAR_GP_PIN(6, 13), /* MSIOF4_SYNC_B */
+ [14] = RCAR_GP_PIN(6, 14), /* MSIOF4_SS1_B */
+ [15] = RCAR_GP_PIN(6, 15), /* MSIOF4_SS2_B */
+ [16] = RCAR_GP_PIN(6, 16), /* SSI0_SCK */
+ [17] = RCAR_GP_PIN(6, 17), /* SSI0_WS */
+ [18] = RCAR_GP_PIN(6, 18), /* SSI0_SD */
+ [19] = RCAR_GP_PIN(6, 19), /* AUDIO0_CLKOUT0 */
+ [20] = RCAR_GP_PIN(6, 20), /* AUDIO0_CLKOUT1 */
+ [21] = RCAR_GP_PIN(6, 21), /* SSI1_SCK */
+ [22] = RCAR_GP_PIN(6, 22), /* SSI1_WS */
+ [23] = RCAR_GP_PIN(6, 23), /* SSI1_SD */
+ [24] = RCAR_GP_PIN(6, 24), /* AUDIO0_CLKOUT2 */
+ [25] = RCAR_GP_PIN(6, 25), /* AUDIO0_CLKOUT3 */
+ [26] = RCAR_GP_PIN(6, 26), /* SSI2_SCK */
+ [27] = RCAR_GP_PIN(6, 27), /* SSI2_WS */
+ [28] = RCAR_GP_PIN(6, 28), /* SSI2_SD */
+ [29] = RCAR_GP_PIN(6, 29), /* AUDIO1_CLKOUT0 */
+ [30] = RCAR_GP_PIN(6, 30), /* AUDIO1_CLKOUT1 */
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { RCAR5_PINMUX_DRIVE_REG("GP7_DRVCTRL0", 0xC0401080, "GP7_DRVCTRL1", 0xC0401084, "GP7_DRVCTRL2", 0xC0401088) {
+ [ 0] = RCAR_GP_PIN(7, 0), /* SSI3_SCK */
+ [ 1] = RCAR_GP_PIN(7, 1), /* SSI3_WS */
+ [ 2] = RCAR_GP_PIN(7, 2), /* SSI3_SD */
+ [ 3] = RCAR_GP_PIN(7, 3), /* AUDIO1_CLKOUT2 */
+ [ 4] = RCAR_GP_PIN(7, 4), /* AUDIO1_CLKOUT3 */
+ [ 5] = RCAR_GP_PIN(7, 5), /* SSI4_SCK */
+ [ 6] = RCAR_GP_PIN(7, 6), /* SSI4_WS */
+ [ 7] = RCAR_GP_PIN(7, 7), /* SSI4_SD */
+ [ 8] = RCAR_GP_PIN(7, 8), /* AUDIO_CLKA_A */
+ [ 9] = RCAR_GP_PIN(7, 9), /* SSI5_SCK */
+ [10] = RCAR_GP_PIN(7, 10), /* SSI5_WS */
+ [11] = RCAR_GP_PIN(7, 11), /* SSI5_SD */
+ [12] = RCAR_GP_PIN(7, 12), /* AUDIO_CLKB_A */
+ [13] = RCAR_GP_PIN(7, 13), /* SSI6_SCK */
+ [14] = RCAR_GP_PIN(7, 14), /* SSI6_WS */
+ [15] = RCAR_GP_PIN(7, 15), /* SSI6_SD */
+ [16] = RCAR_GP_PIN(7, 16), /* AUDIO_CLKC_A */
+ [17] = RCAR_GP_PIN(7, 17), /* MSIOF5_SCK */
+ [18] = RCAR_GP_PIN(7, 18), /* GP07_18 */
+ [19] = RCAR_GP_PIN(7, 19), /* GP07_19 */
+ [20] = RCAR_GP_PIN(7, 20), /* MSIOF5_TXD */
+ [21] = RCAR_GP_PIN(7, 21), /* MSIOF5_RXD */
+ [22] = RCAR_GP_PIN(7, 22), /* MSIOF5_SYNC */
+ [23] = RCAR_GP_PIN(7, 23), /* MSIOF5_SS1 */
+ [24] = RCAR_GP_PIN(7, 24), /* MSIOF5_SS2 */
+ [25] = RCAR_GP_PIN(7, 25), /* MSIOF6_SCK_B */
+ [26] = RCAR_GP_PIN(7, 26), /* MSIOF6_TXD_B */
+ [27] = RCAR_GP_PIN(7, 27), /* MSIOF6_RXD_B */
+ [28] = RCAR_GP_PIN(7, 28), /* MSIOF6_SYNC_B */
+ [29] = RCAR_GP_PIN(7, 29), /* MSIOF6_SS1_B */
+ [30] = RCAR_GP_PIN(7, 30), /* MSIOF6_SS2_B */
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { RCAR5_PINMUX_DRIVE_REG("GP8_DRVCTRL0", 0xC0401880, "GP8_DRVCTRL1", 0xC0401884, "GP8_DRVCTRL2", 0xC0401888) {
+ [ 0] = RCAR_GP_PIN(8, 0), /* SCL1 */
+ [ 1] = RCAR_GP_PIN(8, 1), /* SDA1 */
+ [ 2] = RCAR_GP_PIN(8, 2), /* SCL2 */
+ [ 3] = RCAR_GP_PIN(8, 3), /* SDA2 */
+ [ 4] = RCAR_GP_PIN(8, 4), /* SCL3 */
+ [ 5] = RCAR_GP_PIN(8, 5), /* SDA3 */
+ [ 6] = RCAR_GP_PIN(8, 6), /* SCL4 */
+ [ 7] = RCAR_GP_PIN(8, 7), /* SDA4 */
+ [ 8] = RCAR_GP_PIN(8, 8), /* SCL5 */
+ [ 9] = RCAR_GP_PIN(8, 9), /* SDA5 */
+ [10] = RCAR_GP_PIN(8, 10), /* SCL6 */
+ [11] = RCAR_GP_PIN(8, 11), /* SDA6 */
+ [12] = RCAR_GP_PIN(8, 12), /* SCL7 */
+ [13] = RCAR_GP_PIN(8, 13), /* SDA7 */
+ [14] = RCAR_GP_PIN(8, 14), /* SCL8 */
+ [15] = RCAR_GP_PIN(8, 15), /* SDA8 */
+ [16] = SH_PFC_PIN_NONE,
+ [17] = SH_PFC_PIN_NONE,
+ [18] = SH_PFC_PIN_NONE,
+ [19] = SH_PFC_PIN_NONE,
+ [20] = SH_PFC_PIN_NONE,
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = RCAR_GP_PIN(8, 26), /* S3CL0 */
+ [27] = RCAR_GP_PIN(8, 27), /* S3DA0 */
+ [28] = RCAR_GP_PIN(8, 28), /* S3CL1 */
+ [29] = RCAR_GP_PIN(8, 29), /* S3DA1 */
+ [30] = RCAR_GP_PIN(8, 30), /* S3CL2 */
+ [31] = RCAR_GP_PIN(8, 31), /* S3DA2 */
+ } },
+ { RCAR5_PINMUX_DRIVE_REG("GP9_DRVCTRL0", 0xC9B00080, "GP9_DRVCTRL1", 0xC9B00084, "GP9_DRVCTRL2", 0xC9B00088) {
+ [ 0] = RCAR_GP_PIN(9, 0), /* ETHES0_PPS */
+ [ 1] = RCAR_GP_PIN(9, 1), /* ETHES0_CAPTURE */
+ [ 2] = RCAR_GP_PIN(9, 2), /* ETHES0_MATCH */
+ [ 3] = RCAR_GP_PIN(9, 3), /* ETHES4_PPS */
+ [ 4] = RCAR_GP_PIN(9, 4), /* ETHES4_CAPTURE */
+ [ 5] = RCAR_GP_PIN(9, 5), /* ETHES4_MATCH */
+ [ 6] = RCAR_GP_PIN(9, 6), /* ETH25G0_MDIO */
+ [ 7] = RCAR_GP_PIN(9, 7), /* ETH25G0_MDC */
+ [ 8] = RCAR_GP_PIN(9, 8), /* ETH25G0_LINK */
+ [ 9] = RCAR_GP_PIN(9, 9), /* ETH25G0_PHYINT */
+ [10] = RCAR_GP_PIN(9, 10), /* ETH10G0_MDIO */
+ [11] = RCAR_GP_PIN(9, 11), /* ETH10G0_MDC */
+ [12] = RCAR_GP_PIN(9, 12), /* ETH10G0_LINK */
+ [13] = RCAR_GP_PIN(9, 13), /* ETH10G0_PHYINT */
+ [14] = RCAR_GP_PIN(9, 14), /* RSW3_PPS */
+ [15] = RCAR_GP_PIN(9, 15), /* RSW3_CAPTURE */
+ [16] = RCAR_GP_PIN(9, 16), /* RSW3_MATCH */
+ [17] = SH_PFC_PIN_NONE,
+ [18] = SH_PFC_PIN_NONE,
+ [19] = SH_PFC_PIN_NONE,
+ [20] = SH_PFC_PIN_NONE,
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { RCAR5_PINMUX_DRIVE_REG("GP10_DRVCTRL0", 0xC9B00880, "GP10_DRVCTRL1", 0xC9B00884, "GP10_DRVCTRL2", 0xC9B00888) {
+ [ 0] = RCAR_GP_PIN(10, 0), /* USB0_PWEN */
+ [ 1] = RCAR_GP_PIN(10, 1), /* USB0_OVC */
+ [ 2] = RCAR_GP_PIN(10, 2), /* USB0_VBUS_VALID */
+ [ 3] = RCAR_GP_PIN(10, 3), /* USB1_PWEN */
+ [ 4] = RCAR_GP_PIN(10, 4), /* USB1_OVC */
+ [ 5] = RCAR_GP_PIN(10, 5), /* USB1_VBUS_VALID */
+ [ 6] = RCAR_GP_PIN(10, 6), /* USB2_PWEN */
+ [ 7] = RCAR_GP_PIN(10, 7), /* USB2_OVC */
+ [ 8] = RCAR_GP_PIN(10, 8), /* USB2_VBUS_VALID */
+ [ 9] = RCAR_GP_PIN(10, 9), /* USB3_PWEN */
+ [10] = RCAR_GP_PIN(10, 10), /* USB3_OVC */
+ [11] = RCAR_GP_PIN(10, 11), /* USB3_VBUS_VALID */
+ [12] = RCAR_GP_PIN(10, 12), /* PCIE40_CLKREQ_N */
+ [13] = RCAR_GP_PIN(10, 13), /* PCIE41_CLKREQ_N */
+ [14] = SH_PFC_PIN_NONE,
+ [15] = SH_PFC_PIN_NONE,
+ [16] = SH_PFC_PIN_NONE,
+ [17] = SH_PFC_PIN_NONE,
+ [18] = SH_PFC_PIN_NONE,
+ [19] = SH_PFC_PIN_NONE,
+ [20] = SH_PFC_PIN_NONE,
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { /* sentinel */ },
+};
+
+enum ioctrl_regs {
+ GP0_TDSEL0,
+ GP0_TDSEL1,
+ GP1_TDSEL0,
+ GP1_TDSEL1,
+ GP2_TDSEL0,
+ GP2_TDSEL1,
+ GP3_TDSEL0,
+ GP3_TDSEL1,
+ GP4_TDSEL0,
+ GP4_TDSEL1,
+ GP5_TDSEL0,
+ GP5_TDSEL1,
+ GP6_TDSEL0,
+ GP6_TDSEL1,
+ GP7_TDSEL0,
+ GP7_TDSEL1,
+ GP8_TDSEL0,
+ GP8_TDSEL1,
+ GP9_TDSEL0,
+ GP9_TDSEL1,
+ GP10_TDSEL0,
+ GP10_TDSEL1,
+};
+
+static const struct pinmux_ioctrl_reg pinmux_ioctrl_regs[] = {
+ [GP0_TDSEL0] = { 0xC1080094, },
+ [GP0_TDSEL1] = { 0xC1080098, },
+ [GP1_TDSEL0] = { 0xC1080894, },
+ [GP1_TDSEL1] = { 0xC1080898, },
+ [GP2_TDSEL0] = { 0xC1081094, },
+ [GP2_TDSEL1] = { 0xC1081098, },
+ [GP3_TDSEL0] = { 0xC0800094, },
+ [GP3_TDSEL1] = { 0xC0800098, },
+ [GP4_TDSEL0] = { 0xC0800894, },
+ [GP4_TDSEL1] = { 0xC0800898, },
+ [GP5_TDSEL0] = { 0xC0400094, },
+ [GP5_TDSEL1] = { 0xC0400098, },
+ [GP6_TDSEL0] = { 0xC0400894, },
+ [GP6_TDSEL1] = { 0xC0400898, },
+ [GP7_TDSEL0] = { 0xC0401094, },
+ [GP7_TDSEL1] = { 0xC0401098, },
+ [GP8_TDSEL0] = { 0xC0401894, },
+ [GP8_TDSEL1] = { 0xC0401898, },
+ [GP9_TDSEL0] = { 0xC9B00094, },
+ [GP9_TDSEL1] = { 0xC9B00098, },
+ [GP10_TDSEL0] = { 0xC9B00894, },
+ [GP10_TDSEL1] = { 0xC9B00898, },
+ { /* sentinel */ }
+};
+
+static const struct pinmux_bias_reg pinmux_bias_regs[] = {
+ { PINMUX_BIAS_REG("GP0_PULLEN", 0xC10800C0, "GP0_PUDSEL", 0xC10800C4) {
+ [ 0] = RCAR_GP_PIN(0, 0), /* GP0_00 */
+ [ 1] = RCAR_GP_PIN(0, 1), /* GP0_01 */
+ [ 2] = RCAR_GP_PIN(0, 2), /* GP0_02 */
+ [ 3] = RCAR_GP_PIN(0, 3), /* STPWT_EXTFXR_A */
+ [ 4] = RCAR_GP_PIN(0, 4), /* FXR_CLKOUT1_A */
+ [ 5] = RCAR_GP_PIN(0, 5), /* FXR_CLKOUT2_A */
+ [ 6] = RCAR_GP_PIN(0, 6), /* CLK_EXTFXR_A */
+ [ 7] = RCAR_GP_PIN(0, 7), /* FXR_TXDA_A */
+ [ 8] = RCAR_GP_PIN(0, 8), /* FXR_TXENA_N_A */
+ [ 9] = RCAR_GP_PIN(0, 9), /* RXDA_EXTFXR_A */
+ [10] = RCAR_GP_PIN(0, 10), /* FXR_TXDB_A */
+ [11] = RCAR_GP_PIN(0, 11), /* FXR_TXENB_N_A */
+ [12] = RCAR_GP_PIN(0, 12), /* RXDB_EXTFXR_A */
+ [13] = RCAR_GP_PIN(0, 13), /* MSIOF0_SCK */
+ [14] = RCAR_GP_PIN(0, 14), /* MSIOF0_TXD */
+ [15] = RCAR_GP_PIN(0, 15), /* MSIOF0_RXD */
+ [16] = RCAR_GP_PIN(0, 16), /* MSIOF0_SYNC */
+ [17] = RCAR_GP_PIN(0, 17), /* MSIOF0_SS1 */
+ [18] = RCAR_GP_PIN(0, 18), /* MSIOF0_SS2 */
+ [19] = RCAR_GP_PIN(0, 19), /* MSIOF1_SCK_A */
+ [20] = RCAR_GP_PIN(0, 20), /* MSIOF1_TXD_A */
+ [21] = RCAR_GP_PIN(0, 21), /* MSIOF1_RXD_A */
+ [22] = RCAR_GP_PIN(0, 22), /* MSIOF1_SYNC_A */
+ [23] = RCAR_GP_PIN(0, 23), /* MSIOF1_SS1_A */
+ [24] = RCAR_GP_PIN(0, 24), /* MSIOF1_SS2_A */
+ [25] = RCAR_GP_PIN(0, 25), /* DP0_HOTPLUG */
+ [26] = RCAR_GP_PIN(0, 26), /* DP1_HOTPLUG */
+ [27] = RCAR_GP_PIN(0, 27), /* DP2_HOTPLUG */
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("GP1_PULLEN", 0xC10808C0, "GP1_PUDSEL", 0xC10808C4) {
+ [ 0] = RCAR_GP_PIN(1, 0), /* CAN0RX_INTP0 */
+ [ 1] = RCAR_GP_PIN(1, 1), /* CAN0TX */
+ [ 2] = RCAR_GP_PIN(1, 2), /* CAN1RX_INTP1 */
+ [ 3] = RCAR_GP_PIN(1, 3), /* CAN1TX */
+ [ 4] = RCAR_GP_PIN(1, 4), /* CAN2RX_INTP2 */
+ [ 5] = RCAR_GP_PIN(1, 5), /* CAN2TX */
+ [ 6] = RCAR_GP_PIN(1, 6), /* CAN3RX_INTP3 */
+ [ 7] = RCAR_GP_PIN(1, 7), /* CAN3TX */
+ [ 8] = RCAR_GP_PIN(1, 8), /* CAN4RX_INTP4 */
+ [ 9] = RCAR_GP_PIN(1, 9), /* CAN4TX */
+ [10] = RCAR_GP_PIN(1, 10), /* CAN5RX_INTP5 */
+ [11] = RCAR_GP_PIN(1, 11), /* CAN5TX */
+ [12] = RCAR_GP_PIN(1, 12), /* CAN6RX_INTP6 */
+ [13] = RCAR_GP_PIN(1, 13), /* CAN6TX */
+ [14] = RCAR_GP_PIN(1, 14), /* RLIN30RX_INTP16 */
+ [15] = RCAR_GP_PIN(1, 15), /* RLIN30TX */
+ [16] = RCAR_GP_PIN(1, 16), /* RLIN31RX_INTP17 */
+ [17] = RCAR_GP_PIN(1, 17), /* RLIN31TX */
+ [18] = RCAR_GP_PIN(1, 18), /* RLIN32RX_INTP18 */
+ [19] = RCAR_GP_PIN(1, 19), /* RLIN32TX */
+ [20] = RCAR_GP_PIN(1, 20), /* RLIN33RX_INTP19 */
+ [21] = RCAR_GP_PIN(1, 21), /* RLIN33TX */
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("GP2_PULLEN", 0xC10810C0, "GP2_PUDSEL", 0xC10810C4) {
+ [ 0] = RCAR_GP_PIN(2, 0), /* RLIN34RX_INTP20_B */
+ [ 1] = RCAR_GP_PIN(2, 1), /* RLIN34TX_B */
+ [ 2] = RCAR_GP_PIN(2, 2), /* RLIN35RX_INTP21_B */
+ [ 3] = RCAR_GP_PIN(2, 3), /* RLIN35TX_B */
+ [ 4] = RCAR_GP_PIN(2, 4), /* RLIN36RX_INTP22_B */
+ [ 5] = RCAR_GP_PIN(2, 5), /* RLIN36TX_B */
+ [ 6] = RCAR_GP_PIN(2, 6), /* RLIN37RX_INTP23_B */
+ [ 7] = RCAR_GP_PIN(2, 7), /* RLIN37TX_B */
+ [ 8] = RCAR_GP_PIN(2, 8), /* CAN12RX_INTP12_B */
+ [ 9] = RCAR_GP_PIN(2, 9), /* CAN12TX_B */
+ [10] = RCAR_GP_PIN(2, 10), /* CAN13RX_INTP13_B */
+ [11] = RCAR_GP_PIN(2, 11), /* CAN13TX_B */
+ [12] = RCAR_GP_PIN(2, 12), /* CAN14RX_INTP14_B */
+ [13] = RCAR_GP_PIN(2, 13), /* CAN14TX_B */
+ [14] = RCAR_GP_PIN(2, 14), /* CAN15RX_INTP15_B */
+ [15] = RCAR_GP_PIN(2, 15), /* CAN15TX_B */
+ [16] = RCAR_GP_PIN(2, 16), /* CAN_CLK */
+ [17] = RCAR_GP_PIN(2, 17), /* INTP32_B */
+ [18] = RCAR_GP_PIN(2, 18), /* INTP33_B */
+ [19] = RCAR_GP_PIN(2, 19), /* SCL0 */
+ [20] = RCAR_GP_PIN(2, 20), /* SDA0 */
+ [21] = RCAR_GP_PIN(2, 21), /* AVS0 */
+ [22] = RCAR_GP_PIN(2, 22), /* AVS1 */
+ [23] = RCAR_GP_PIN(2, 23), /* EXTCLK0O_B */
+ [24] = RCAR_GP_PIN(2, 24), /* TAUD1O0 */
+ [25] = RCAR_GP_PIN(2, 25), /* TAUD1O1 */
+ [26] = RCAR_GP_PIN(2, 26), /* TAUD1O2 */
+ [27] = RCAR_GP_PIN(2, 27), /* TAUD1O3 */
+ [28] = RCAR_GP_PIN(2, 28), /* INTP34_B */
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("GP3_PULLEN", 0xC08000C0, "GP3_PUDSEL", 0xC08000C4) {
+ [ 0] = RCAR_GP_PIN(3, 0), /* QSPI0_SPCLK */
+ [ 1] = RCAR_GP_PIN(3, 1), /* QSPI0_MOSI_IO0 */
+ [ 2] = RCAR_GP_PIN(3, 2), /* QSPI0_MISO_IO1 */
+ [ 3] = RCAR_GP_PIN(3, 3), /* QSPI0_IO2 */
+ [ 4] = RCAR_GP_PIN(3, 4), /* QSPI0_IO3 */
+ [ 5] = RCAR_GP_PIN(3, 5), /* QSPI0_SSL */
+ [ 6] = RCAR_GP_PIN(3, 6), /* RPC_RESET_N */
+ [ 7] = RCAR_GP_PIN(3, 7), /* RPC_WP_N */
+ [ 8] = RCAR_GP_PIN(3, 8), /* RPC_INT_N */
+ [ 9] = RCAR_GP_PIN(3, 9), /* QSPI1_SPCLK */
+ [10] = RCAR_GP_PIN(3, 10), /* QSPI1_MOSI_IO0 */
+ [11] = RCAR_GP_PIN(3, 11), /* QSPI1_MISO_IO1 */
+ [12] = RCAR_GP_PIN(3, 12), /* QSPI1_IO2 */
+ [13] = RCAR_GP_PIN(3, 13), /* QSPI1_IO3 */
+ [14] = RCAR_GP_PIN(3, 14), /* QSPI1_SSL */
+ [15] = RCAR_GP_PIN(3, 15), /* ERROROUT_N */
+ [16] = RCAR_GP_PIN(3, 16), /* ERRORIN_N */
+ [17] = SH_PFC_PIN_NONE,
+ [18] = SH_PFC_PIN_NONE,
+ [19] = SH_PFC_PIN_NONE,
+ [20] = SH_PFC_PIN_NONE,
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("GP4_PULLEN", 0xC08008C0, "GP4_PUDSEL", 0xC08008C4) {
+ [ 0] = RCAR_GP_PIN(4, 0), /* MMC0_SD_CLK */
+ [ 1] = RCAR_GP_PIN(4, 1), /* MMC0_SD_CMD */
+ [ 2] = RCAR_GP_PIN(4, 2), /* MMC0_SD_D0 */
+ [ 3] = RCAR_GP_PIN(4, 3), /* MMC0_SD_D1 */
+ [ 4] = RCAR_GP_PIN(4, 4), /* MMC0_SD_D2 */
+ [ 5] = RCAR_GP_PIN(4, 5), /* MMC0_SD_D3 */
+ [ 6] = RCAR_GP_PIN(4, 6), /* MMC0_D4 */
+ [ 7] = RCAR_GP_PIN(4, 7), /* MMC0_D5 */
+ [ 8] = RCAR_GP_PIN(4, 8), /* MMC0_D6 */
+ [ 9] = RCAR_GP_PIN(4, 9), /* MMC0_D7 */
+ [10] = RCAR_GP_PIN(4, 10), /* MMC0_DS */
+ [11] = RCAR_GP_PIN(4, 11), /* SD0_WP */
+ [12] = RCAR_GP_PIN(4, 12), /* SD0_CD */
+ [13] = RCAR_GP_PIN(4, 13), /* ERRORIN_N */
+ [14] = RCAR_GP_PIN(4, 14), /* PCIE60_CLKREQ_N */
+ [15] = RCAR_GP_PIN(4, 15), /* PCIE61_CLKREQ_N */
+ [16] = SH_PFC_PIN_NONE,
+ [17] = SH_PFC_PIN_NONE,
+ [18] = SH_PFC_PIN_NONE,
+ [19] = SH_PFC_PIN_NONE,
+ [20] = SH_PFC_PIN_NONE,
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("GP5_PULLEN", 0xC04000C0, "GP5_PUDSEL", 0xC04000C4) {
+ [ 0] = RCAR_GP_PIN(5, 0), /* HTX0 */
+ [ 1] = RCAR_GP_PIN(5, 1), /* HRX0 */
+ [ 2] = RCAR_GP_PIN(5, 2), /* HRTS0_N */
+ [ 3] = RCAR_GP_PIN(5, 3), /* HCTS0_N */
+ [ 4] = RCAR_GP_PIN(5, 4), /* HSCK0 */
+ [ 5] = RCAR_GP_PIN(5, 5), /* SCIF_CLK */
+ [ 6] = RCAR_GP_PIN(5, 6), /* HTX1 */
+ [ 7] = RCAR_GP_PIN(5, 7), /* HRX1 */
+ [ 8] = RCAR_GP_PIN(5, 8), /* HRTS1_N */
+ [ 9] = RCAR_GP_PIN(5, 9), /* HCTS1_N */
+ [10] = RCAR_GP_PIN(5, 10), /* HSCK1 */
+ [11] = RCAR_GP_PIN(5, 11), /* IRQ0_A */
+ [12] = RCAR_GP_PIN(5, 12), /* IRQ1_A */
+ [13] = RCAR_GP_PIN(5, 13), /* IRQ2_A */
+ [14] = RCAR_GP_PIN(5, 14), /* IRQ3_A */
+ [15] = RCAR_GP_PIN(5, 15), /* TCLK1 */
+ [16] = RCAR_GP_PIN(5, 16), /* TCLK2 */
+ [17] = RCAR_GP_PIN(5, 17), /* TCLK3 */
+ [18] = RCAR_GP_PIN(5, 18), /* TCLK4 */
+ [19] = RCAR_GP_PIN(5, 19), /* TPU0TO0 */
+ [20] = RCAR_GP_PIN(5, 20), /* TPU0TO1 */
+ [21] = RCAR_GP_PIN(5, 21), /* TPU0TO2 */
+ [22] = RCAR_GP_PIN(5, 22), /* TPU0TO3 */
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("GP6_PULLEN", 0xC04008C0, "GP6_PUDSEL", 0xC04008C4) {
+ [ 0] = RCAR_GP_PIN(6, 0), /* RIF6_D0 */
+ [ 1] = RCAR_GP_PIN(6, 1), /* RIF6_D1 */
+ [ 2] = RCAR_GP_PIN(6, 2), /* RIF6_SYNC */
+ [ 3] = RCAR_GP_PIN(6, 3), /* RIF6_CLK */
+ [ 4] = RCAR_GP_PIN(6, 4), /* MSIOF7_SCK_A */
+ [ 5] = RCAR_GP_PIN(6, 5), /* MSIOF7_TXD_A */
+ [ 6] = RCAR_GP_PIN(6, 6), /* MSIOF7_RXD_A */
+ [ 7] = RCAR_GP_PIN(6, 7), /* MSIOF7_SYNC_A */
+ [ 8] = RCAR_GP_PIN(6, 8), /* MSIOF7_SS1_A */
+ [ 9] = RCAR_GP_PIN(6, 9), /* MSIOF7_SS2_A */
+ [10] = RCAR_GP_PIN(6, 10), /* MSIOF4_SCK_B */
+ [11] = RCAR_GP_PIN(6, 11), /* MSIOF4_TXD_B */
+ [12] = RCAR_GP_PIN(6, 12), /* MSIOF4_RXD_B */
+ [13] = RCAR_GP_PIN(6, 13), /* MSIOF4_SYNC_B */
+ [14] = RCAR_GP_PIN(6, 14), /* MSIOF4_SS1_B */
+ [15] = RCAR_GP_PIN(6, 15), /* MSIOF4_SS2_B */
+ [16] = RCAR_GP_PIN(6, 16), /* SSI0_SCK */
+ [17] = RCAR_GP_PIN(6, 17), /* SSI0_WS */
+ [18] = RCAR_GP_PIN(6, 18), /* SSI0_SD */
+ [19] = RCAR_GP_PIN(6, 19), /* AUDIO0_CLKOUT0 */
+ [20] = RCAR_GP_PIN(6, 20), /* AUDIO0_CLKOUT1 */
+ [21] = RCAR_GP_PIN(6, 21), /* SSI1_SCK */
+ [22] = RCAR_GP_PIN(6, 22), /* SSI1_WS */
+ [23] = RCAR_GP_PIN(6, 23), /* SSI1_SD */
+ [24] = RCAR_GP_PIN(6, 24), /* AUDIO0_CLKOUT2 */
+ [25] = RCAR_GP_PIN(6, 25), /* AUDIO0_CLKOUT3 */
+ [26] = RCAR_GP_PIN(6, 26), /* SSI2_SCK */
+ [27] = RCAR_GP_PIN(6, 27), /* SSI2_WS */
+ [28] = RCAR_GP_PIN(6, 28), /* SSI2_SD */
+ [29] = RCAR_GP_PIN(6, 29), /* AUDIO1_CLKOUT0 */
+ [30] = RCAR_GP_PIN(6, 30), /* AUDIO1_CLKOUT1 */
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("GP7_PULLEN", 0xC04010C0, "GP7_PUDSEL", 0xC04010C4) {
+ [ 0] = RCAR_GP_PIN(7, 0), /* SSI3_SCK */
+ [ 1] = RCAR_GP_PIN(7, 1), /* SSI3_WS */
+ [ 2] = RCAR_GP_PIN(7, 2), /* SSI3_SD */
+ [ 3] = RCAR_GP_PIN(7, 3), /* AUDIO1_CLKOUT2 */
+ [ 4] = RCAR_GP_PIN(7, 4), /* AUDIO1_CLKOUT3 */
+ [ 5] = RCAR_GP_PIN(7, 5), /* SSI4_SCK */
+ [ 6] = RCAR_GP_PIN(7, 6), /* SSI4_WS */
+ [ 7] = RCAR_GP_PIN(7, 7), /* SSI4_SD */
+ [ 8] = RCAR_GP_PIN(7, 8), /* AUDIO_CLKA_A */
+ [ 9] = RCAR_GP_PIN(7, 9), /* SSI5_SCK */
+ [10] = RCAR_GP_PIN(7, 10), /* SSI5_WS */
+ [11] = RCAR_GP_PIN(7, 11), /* SSI5_SD */
+ [12] = RCAR_GP_PIN(7, 12), /* AUDIO_CLKB_A */
+ [13] = RCAR_GP_PIN(7, 13), /* SSI6_SCK */
+ [14] = RCAR_GP_PIN(7, 14), /* SSI6_WS */
+ [15] = RCAR_GP_PIN(7, 15), /* SSI6_SD */
+ [16] = RCAR_GP_PIN(7, 16), /* AUDIO_CLKC_A */
+ [17] = RCAR_GP_PIN(7, 17), /* MSIOF5_SCK */
+ [18] = RCAR_GP_PIN(7, 18), /* GP07_18 */
+ [19] = RCAR_GP_PIN(7, 19), /* GP07_19 */
+ [20] = RCAR_GP_PIN(7, 20), /* MSIOF5_TXD */
+ [21] = RCAR_GP_PIN(7, 21), /* MSIOF5_RXD */
+ [22] = RCAR_GP_PIN(7, 22), /* MSIOF5_SYNC */
+ [23] = RCAR_GP_PIN(7, 23), /* MSIOF5_SS1 */
+ [24] = RCAR_GP_PIN(7, 24), /* MSIOF5_SS2 */
+ [25] = RCAR_GP_PIN(7, 25), /* MSIOF6_SCK_B */
+ [26] = RCAR_GP_PIN(7, 26), /* MSIOF6_TXD_B */
+ [27] = RCAR_GP_PIN(7, 27), /* MSIOF6_RXD_B */
+ [28] = RCAR_GP_PIN(7, 28), /* MSIOF6_SYNC_B */
+ [29] = RCAR_GP_PIN(7, 29), /* MSIOF6_SS1_B */
+ [30] = RCAR_GP_PIN(7, 30), /* MSIOF6_SS2_B */
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("GP8_PULLEN", 0xC04018C0, "GP8_PUDSEL", 0xC04018C4) {
+ [ 0] = RCAR_GP_PIN(8, 0), /* SCL1 */
+ [ 1] = RCAR_GP_PIN(8, 1), /* SDA1 */
+ [ 2] = RCAR_GP_PIN(8, 2), /* SCL2 */
+ [ 3] = RCAR_GP_PIN(8, 3), /* SDA2 */
+ [ 4] = RCAR_GP_PIN(8, 4), /* SCL3 */
+ [ 5] = RCAR_GP_PIN(8, 5), /* SDA3 */
+ [ 6] = RCAR_GP_PIN(8, 6), /* SCL4 */
+ [ 7] = RCAR_GP_PIN(8, 7), /* SDA4 */
+ [ 8] = RCAR_GP_PIN(8, 8), /* SCL5 */
+ [ 9] = RCAR_GP_PIN(8, 9), /* SDA5 */
+ [10] = RCAR_GP_PIN(8, 10), /* SCL6 */
+ [11] = RCAR_GP_PIN(8, 11), /* SDA6 */
+ [12] = RCAR_GP_PIN(8, 12), /* SCL7 */
+ [13] = RCAR_GP_PIN(8, 13), /* SDA7 */
+ [14] = RCAR_GP_PIN(8, 14), /* SCL8 */
+ [15] = RCAR_GP_PIN(8, 15), /* SDA8 */
+ [16] = SH_PFC_PIN_NONE,
+ [17] = SH_PFC_PIN_NONE,
+ [18] = SH_PFC_PIN_NONE,
+ [19] = SH_PFC_PIN_NONE,
+ [20] = SH_PFC_PIN_NONE,
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = RCAR_GP_PIN(8, 26), /* S3CL0 */
+ [27] = RCAR_GP_PIN(8, 27), /* S3DA0 */
+ [28] = RCAR_GP_PIN(8, 28), /* S3CL1 */
+ [29] = RCAR_GP_PIN(8, 29), /* S3DA1 */
+ [30] = RCAR_GP_PIN(8, 30), /* S3CL2 */
+ [31] = RCAR_GP_PIN(8, 31), /* S3DA2 */
+ } },
+ { PINMUX_BIAS_REG("GP9_PULLEN", 0xC9B000C0, "GP9_PUDSEL", 0xC9B000C4) {
+ [ 0] = RCAR_GP_PIN(9, 0), /* ETHES0_PPS */
+ [ 1] = RCAR_GP_PIN(9, 1), /* ETHES0_CAPTURE */
+ [ 2] = RCAR_GP_PIN(9, 2), /* ETHES0_MATCH */
+ [ 3] = RCAR_GP_PIN(9, 3), /* ETHES4_PPS */
+ [ 4] = RCAR_GP_PIN(9, 4), /* ETHES4_CAPTURE */
+ [ 5] = RCAR_GP_PIN(9, 5), /* ETHES4_MATCH */
+ [ 6] = RCAR_GP_PIN(9, 6), /* ETH25G0_MDIO */
+ [ 7] = RCAR_GP_PIN(9, 7), /* ETH25G0_MDC */
+ [ 8] = RCAR_GP_PIN(9, 8), /* ETH25G0_LINK */
+ [ 9] = RCAR_GP_PIN(9, 9), /* ETH25G0_PHYINT */
+ [10] = RCAR_GP_PIN(9, 10), /* ETH10G0_MDIO */
+ [11] = RCAR_GP_PIN(9, 11), /* ETH10G0_MDC */
+ [12] = RCAR_GP_PIN(9, 12), /* ETH10G0_LINK */
+ [13] = RCAR_GP_PIN(9, 13), /* ETH10G0_PHYINT */
+ [14] = RCAR_GP_PIN(9, 14), /* RSW3_PPS */
+ [15] = RCAR_GP_PIN(9, 15), /* RSW3_CAPTURE */
+ [16] = RCAR_GP_PIN(9, 16), /* RSW3_MATCH */
+ [17] = SH_PFC_PIN_NONE,
+ [18] = SH_PFC_PIN_NONE,
+ [19] = SH_PFC_PIN_NONE,
+ [20] = SH_PFC_PIN_NONE,
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("GP10_PULLEN", 0xC9B008C0, "GP10_PUDSEL", 0xC9B008C4) {
+ [ 0] = RCAR_GP_PIN(10, 0), /* USB0_PWEN */
+ [ 1] = RCAR_GP_PIN(10, 1), /* USB0_OVC */
+ [ 2] = RCAR_GP_PIN(10, 2), /* USB0_VBUS_VALID */
+ [ 3] = RCAR_GP_PIN(10, 3), /* USB1_PWEN */
+ [ 4] = RCAR_GP_PIN(10, 4), /* USB1_OVC */
+ [ 5] = RCAR_GP_PIN(10, 5), /* USB1_VBUS_VALID */
+ [ 6] = RCAR_GP_PIN(10, 6), /* USB2_PWEN */
+ [ 7] = RCAR_GP_PIN(10, 7), /* USB2_OVC */
+ [ 8] = RCAR_GP_PIN(10, 8), /* USB2_VBUS_VALID */
+ [ 9] = RCAR_GP_PIN(10, 9), /* USB3_PWEN */
+ [10] = RCAR_GP_PIN(10, 10), /* USB3_OVC */
+ [11] = RCAR_GP_PIN(10, 11), /* USB3_VBUS_VALID */
+ [12] = RCAR_GP_PIN(10, 12), /* PCIE40_CLKREQ_N */
+ [13] = RCAR_GP_PIN(10, 13), /* PCIE41_CLKREQ_N */
+ [14] = SH_PFC_PIN_NONE,
+ [15] = SH_PFC_PIN_NONE,
+ [16] = SH_PFC_PIN_NONE,
+ [17] = SH_PFC_PIN_NONE,
+ [18] = SH_PFC_PIN_NONE,
+ [19] = SH_PFC_PIN_NONE,
+ [20] = SH_PFC_PIN_NONE,
+ [21] = SH_PFC_PIN_NONE,
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { /* sentinel */ },
+};
+
+static int rcar5_pinconf_write_bit(struct sh_pfc *pfc, unsigned int bit,
+ u16 value, u32 reg)
+{
+ u32 val = sh_pfc_read(pfc, reg);
+
+ val &= ~BIT(bit);
+ val |= value << bit;
+
+ sh_pfc_write(pfc, reg, val);
+
+ return 0;
+}
+
+static int rcar5_pinconf_set_drive_strength(struct sh_pfc *pfc,
+ unsigned int pin, u16 strength)
+{
+ unsigned int bank = pin / 32;
+ unsigned int bit = pin % 32;
+ const struct rcar5_pinmux_drive_reg *reg = &pinmux_drive_regs[bank];
+
+ if (reg->pins[bit] != pin)
+ return -EINVAL;
+
+ if (strength < 3 || strength > 24)
+ return -EINVAL;
+
+ /* Convert the value from mA based on a full drive strength value of
+ * 24mA. We can make the full value configurable later if needed.
+ */
+ strength = strength / 3 - 1;
+
+ rcar5_pinconf_write_bit(pfc, bit, bitfield_extract(strength, 0, 1), reg->drvctrl0);
+ rcar5_pinconf_write_bit(pfc, bit, bitfield_extract(strength, 1, 1), reg->drvctrl1);
+ rcar5_pinconf_write_bit(pfc, bit, bitfield_extract(strength, 2, 1), reg->drvctrl2);
+
+ return 0;
+}
+
+static const struct sh_pfc_soc_operations r8a78000_pin_ops = {
+ .get_bias = rcar_pinmux_get_bias,
+ .set_bias = rcar_pinmux_set_bias,
+ .set_drive_strength = rcar5_pinconf_set_drive_strength,
+};
+
+const struct sh_pfc_soc_info r8a78000_pinmux_info = {
+ .name = "r8a78000_pfc",
+ .ops = &r8a78000_pin_ops,
+ .unlock_reg = 0x1ff, /* PMMRn mask */
+
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .pins = pinmux_pins,
+ .nr_pins = ARRAY_SIZE(pinmux_pins),
+ .groups = pinmux_groups,
+ .nr_groups = ARRAY_SIZE(pinmux_groups),
+ .functions = pinmux_functions,
+ .nr_functions = ARRAY_SIZE(pinmux_functions),
+
+ .cfg_regs = pinmux_config_regs,
+ .bias_regs = pinmux_bias_regs,
+ .ioctrl_regs = pinmux_ioctrl_regs,
+
+ .pinmux_data = pinmux_data,
+ .pinmux_data_size = ARRAY_SIZE(pinmux_data),
+};
diff --git a/drivers/pinctrl/renesas/pfc.c b/drivers/pinctrl/renesas/pfc.c
index db6be39a528..1e0fc3f563d 100644
--- a/drivers/pinctrl/renesas/pfc.c
+++ b/drivers/pinctrl/renesas/pfc.c
@@ -45,6 +45,7 @@ enum sh_pfc_model {
SH_PFC_R8A779F0,
SH_PFC_R8A779G0,
SH_PFC_R8A779H0,
+ SH_PFC_R8A78000,
};
struct sh_pfc_pin_config {
@@ -188,9 +189,9 @@ static void sh_pfc_write_config_reg(struct sh_pfc *pfc,
sh_pfc_config_reg_helper(pfc, crp, field, &mapped_reg, &mask, &pos);
- dev_dbg(pfc->dev, "write_reg addr = %x, value = 0x%x, field = %u, "
- "r_width = %u, f_width = %u\n",
- crp->reg, value, field, crp->reg_width, crp->field_width);
+ dev_dbg(pfc->dev,
+ "write_reg addr = %x, value = 0x%x, field = %u, pos = %u, r_width = %u, f_width = %u\n",
+ crp->reg, value, field, pos, crp->reg_width, crp->field_width);
mask = ~(mask << pos);
value = value << pos;
@@ -743,8 +744,8 @@ sh_pfc_pinconf_find_drive_strength_reg(struct sh_pfc *pfc, unsigned int pin,
return NULL;
}
-static int sh_pfc_pinconf_set_drive_strength(struct sh_pfc *pfc,
- unsigned int pin, u16 strength)
+int rcar_pinconf_set_drive_strength(struct sh_pfc *pfc,
+ unsigned int pin, u16 strength)
{
unsigned int offset;
unsigned int size;
@@ -831,7 +832,10 @@ static int sh_pfc_pinconf_set(struct sh_pfc_pinctrl *pmx, unsigned _pin,
break;
case PIN_CONFIG_DRIVE_STRENGTH:
- ret = sh_pfc_pinconf_set_drive_strength(pfc, _pin, arg);
+ if (!pfc->info->ops || !pfc->info->ops->set_drive_strength)
+ return -ENOTSUPP;
+
+ ret = pfc->info->ops->set_drive_strength(pfc, _pin, arg);
if (ret < 0)
return ret;
@@ -1003,6 +1007,8 @@ static int sh_pfc_pinctrl_probe(struct udevice *dev)
priv->pfc.info = &r8a779g0_pinmux_info;
else if (IS_ENABLED(CONFIG_PINCTRL_PFC_R8A779H0) && model == SH_PFC_R8A779H0)
priv->pfc.info = &r8a779h0_pinmux_info;
+ else if (IS_ENABLED(CONFIG_PINCTRL_PFC_R8A78000) && model == SH_PFC_R8A78000)
+ priv->pfc.info = &r8a78000_pinmux_info;
else
return -ENODEV;
@@ -1140,6 +1146,12 @@ static const struct udevice_id sh_pfc_pinctrl_ids[] = {
.data = SH_PFC_R8A779H0,
},
#endif
+#if IS_ENABLED(CONFIG_PINCTRL_PFC_R8A78000)
+ {
+ .compatible = "renesas,pfc-r8a78000",
+ .data = SH_PFC_R8A78000,
+ },
+#endif
{ },
};
diff --git a/drivers/pinctrl/renesas/sh_pfc.h b/drivers/pinctrl/renesas/sh_pfc.h
index 79c6125a0d7..30d2e6a8e81 100644
--- a/drivers/pinctrl/renesas/sh_pfc.h
+++ b/drivers/pinctrl/renesas/sh_pfc.h
@@ -245,6 +245,8 @@ struct sh_pfc_soc_operations {
unsigned int bias);
int (*pin_to_pocctrl)(unsigned int pin, u32 *pocctrl);
int (*pin_to_portcr)(unsigned int pin);
+ int (*set_drive_strength)(struct sh_pfc *pfc, unsigned int pin,
+ u16 strength);
};
struct sh_pfc_soc_info {
@@ -308,6 +310,7 @@ extern const struct sh_pfc_soc_info r8a779a0_pinmux_info;
extern const struct sh_pfc_soc_info r8a779f0_pinmux_info;
extern const struct sh_pfc_soc_info r8a779g0_pinmux_info;
extern const struct sh_pfc_soc_info r8a779h0_pinmux_info;
+extern const struct sh_pfc_soc_info r8a78000_pinmux_info;
/* -----------------------------------------------------------------------------
* Helper macros to create pin and port lists
@@ -741,5 +744,7 @@ rcar_pin_to_bias_reg(const struct sh_pfc_soc_info *info, unsigned int pin,
unsigned int rcar_pinmux_get_bias(struct sh_pfc *pfc, unsigned int pin);
void rcar_pinmux_set_bias(struct sh_pfc *pfc, unsigned int pin,
unsigned int bias);
+int rcar_pinconf_set_drive_strength(struct sh_pfc *pfc,
+ unsigned int pin, u16 strength);
#endif /* __SH_PFC_H */
diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig
index ebf5d828cb0..0ad885c9e8b 100644
--- a/drivers/power/domain/Kconfig
+++ b/drivers/power/domain/Kconfig
@@ -20,7 +20,7 @@ config APPLE_PMGR_POWER_DOMAIN
config AGILEX5_PMGR_POWER_DOMAIN
bool "Enable the Agilex5 PMGR power domain driver"
- depends on SPL_POWER_DOMAIN
+ depends on SPL_POWER_DOMAIN && TARGET_SOCFPGA_SOC64
help
Enable support for power gating peripherals' SRAM specified in
the handoff data values obtained from the bitstream to reduce
diff --git a/drivers/power/domain/zynqmp-power-domain.c b/drivers/power/domain/zynqmp-power-domain.c
index ac93934eb42..a54de5c1439 100644
--- a/drivers/power/domain/zynqmp-power-domain.c
+++ b/drivers/power/domain/zynqmp-power-domain.c
@@ -17,7 +17,7 @@ static int zynqmp_pm_request_node(const u32 node, const u32 capabilities,
const u32 qos, const enum zynqmp_pm_request_ack ack)
{
return xilinx_pm_request(PM_REQUEST_NODE, node, capabilities,
- qos, ack, NULL);
+ qos, ack, 0, 0, NULL);
}
static int zynqmp_power_domain_request(struct power_domain *power_domain)
diff --git a/drivers/power/pmic/s2mps11.c b/drivers/power/pmic/s2mps11.c
index 6e819579030..5cf9d34ffaf 100644
--- a/drivers/power/pmic/s2mps11.c
+++ b/drivers/power/pmic/s2mps11.c
@@ -13,15 +13,28 @@
#include <power/pmic.h>
#include <power/s2mps11.h>
-static const struct pmic_child_info pmic_children_info[] = {
+static const struct pmic_child_info s2mps11_pmic_children_info[] = {
{ .prefix = S2MPS11_OF_LDO_PREFIX, .driver = S2MPS11_LDO_DRIVER },
{ .prefix = S2MPS11_OF_BUCK_PREFIX, .driver = S2MPS11_BUCK_DRIVER },
{ },
};
+static const struct pmic_child_info s2mpu05_pmic_children_info[] = {
+ { .prefix = S2MPU05_OF_LDO_PREFIX, .driver = S2MPS11_LDO_DRIVER },
+ { .prefix = S2MPU05_OF_BUCK_PREFIX, .driver = S2MPS11_BUCK_DRIVER },
+ { },
+};
+
static int s2mps11_reg_count(struct udevice *dev)
{
- return S2MPS11_REG_COUNT;
+ switch (dev_get_driver_data(dev)) {
+ case VARIANT_S2MPS11:
+ return S2MPS11_REG_COUNT;
+ case VARIANT_S2MPU05:
+ return S2MPU05_REG_COUNT;
+ default:
+ return -EINVAL;
+ }
}
static int s2mps11_write(struct udevice *dev, uint reg, const uint8_t *buff,
@@ -47,10 +60,11 @@ static int s2mps11_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
return ret;
}
-static int s2mps11_probe(struct udevice *dev)
+static int s2mps11_bind(struct udevice *dev)
{
ofnode regulators_node;
int children;
+ const struct pmic_child_info *pmic_children_info;
regulators_node = dev_read_subnode(dev, "regulators");
if (!ofnode_valid(regulators_node)) {
@@ -61,6 +75,18 @@ static int s2mps11_probe(struct udevice *dev)
debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+ switch (dev_get_driver_data(dev)) {
+ case VARIANT_S2MPS11:
+ pmic_children_info = s2mps11_pmic_children_info;
+ break;
+ case VARIANT_S2MPU05:
+ pmic_children_info = s2mpu05_pmic_children_info;
+ break;
+ default:
+ debug("%s: unknown device type\n", __func__);
+ return -EINVAL;
+ }
+
children = pmic_bind_children(dev, regulators_node, pmic_children_info);
if (!children)
debug("%s: %s - no child found\n", __func__, dev->name);
@@ -75,7 +101,8 @@ static struct dm_pmic_ops s2mps11_ops = {
};
static const struct udevice_id s2mps11_ids[] = {
- { .compatible = "samsung,s2mps11-pmic" },
+ { .compatible = "samsung,s2mps11-pmic", .data = VARIANT_S2MPS11 },
+ { .compatible = "samsung,s2mpu05-pmic", .data = VARIANT_S2MPU05 },
{ }
};
@@ -84,5 +111,5 @@ U_BOOT_DRIVER(pmic_s2mps11) = {
.id = UCLASS_PMIC,
.of_match = s2mps11_ids,
.ops = &s2mps11_ops,
- .probe = s2mps11_probe,
+ .bind = s2mps11_bind,
};
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
index 65b99e89656..1875e61967c 100644
--- a/drivers/power/regulator/Kconfig
+++ b/drivers/power/regulator/Kconfig
@@ -143,7 +143,7 @@ config REGULATOR_PWM
config SPL_REGULATOR_PWM
bool "Enable Driver for PWM regulators in SPL"
- depends on REGULATOR_PWM && SPL
+ depends on SPL_DM_REGULATOR && SPL && SPL_DM_PWM
help
This config enables implementation of driver-model regulator uclass
features for PWM regulators in SPL.
diff --git a/drivers/power/regulator/fixed.c b/drivers/power/regulator/fixed.c
index 996da41546a..1dd137f493e 100644
--- a/drivers/power/regulator/fixed.c
+++ b/drivers/power/regulator/fixed.c
@@ -13,7 +13,6 @@
#include <asm/gpio.h>
#include <power/pmic.h>
#include <power/regulator.h>
-#include "regulator_common.h"
#include "regulator_common.h"
diff --git a/drivers/power/regulator/gpio-regulator.c b/drivers/power/regulator/gpio-regulator.c
index 38b22535c3d..787f8170234 100644
--- a/drivers/power/regulator/gpio-regulator.c
+++ b/drivers/power/regulator/gpio-regulator.c
@@ -12,7 +12,6 @@
#include <linux/printk.h>
#include <power/pmic.h>
#include <power/regulator.h>
-#include "regulator_common.h"
#include "regulator_common.h"
diff --git a/drivers/power/regulator/qcom-rpmh-regulator.c b/drivers/power/regulator/qcom-rpmh-regulator.c
index 954deca5ed7..06466142560 100644
--- a/drivers/power/regulator/qcom-rpmh-regulator.c
+++ b/drivers/power/regulator/qcom-rpmh-regulator.c
@@ -456,6 +456,16 @@ static const struct rpmh_vreg_hw_data pmic5_pldo_lv = {
.n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo),
};
+static const struct rpmh_vreg_hw_data pmic5_nldo = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 123, 8000),
+ .n_voltages = 124,
+ .hpm_min_load_uA = 30000,
+ .pmic_mode_map = pmic_mode_map_pmic5_ldo,
+ .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo),
+};
+
static const struct rpmh_vreg_hw_data pmic5_nldo515 = {
.regulator_type = VRM,
.ops = &rpmh_regulator_vrm_drms_ops,
@@ -493,6 +503,23 @@ static const struct rpmh_vreg_hw_data pmic5_pldo515_mv = {
.supply_name = _supply_name, \
}
+static const struct rpmh_vreg_init_data pm6150l_vreg_data[] = {
+ /* smps1 - smps8 are not added to u-boot yet */
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_pldo_lv, "vdd-l1-l8"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l3"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l2-l3"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo, "vdd-l4-l5-l6"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l4-l5-l6"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l4-l5-l6"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-l11"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo, "vdd-l1-l8"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l9-l10"),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l9-l10"),
+ RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l7-l11"),
+ RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"),
+ {}
+};
+
static const struct rpmh_vreg_init_data pm8150_vreg_data[] = {
RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l13-l16-l17"),
{}
@@ -706,6 +733,10 @@ static int rpmh_regulators_bind(struct udevice *dev)
static const struct udevice_id rpmh_regulator_ids[] = {
{
+ .compatible = "qcom,pm6150l-rpmh-regulators",
+ .data = (ulong)pm6150l_vreg_data,
+ },
+ {
.compatible = "qcom,pm8150-rpmh-regulators",
.data = (ulong)pm8150_vreg_data,
},
diff --git a/drivers/power/regulator/regulator_common.c b/drivers/power/regulator/regulator_common.c
index c80f10c3aa3..685d8735fa5 100644
--- a/drivers/power/regulator/regulator_common.c
+++ b/drivers/power/regulator/regulator_common.c
@@ -9,7 +9,6 @@
#include <asm/gpio.h>
#include <linux/delay.h>
#include <power/regulator.h>
-#include "regulator_common.h"
#include "regulator_common.h"
@@ -45,16 +44,6 @@ int regulator_common_of_to_plat(struct udevice *dev,
dev_read_u32_default(dev, "u-boot,off-on-delay-us", 0);
}
- ret = device_get_supply_regulator(dev, "vin-supply", &plat->vin_supply);
- if (ret) {
- debug("Regulator vin regulator not defined: %d\n", ret);
- if (ret != -ENOENT)
- return ret;
- }
-
- if (plat->vin_supply)
- regulator_set_enable_if_allowed(plat->vin_supply, true);
-
return 0;
}
diff --git a/drivers/power/regulator/regulator_common.h b/drivers/power/regulator/regulator_common.h
index 799c968d0b6..d4962899d83 100644
--- a/drivers/power/regulator/regulator_common.h
+++ b/drivers/power/regulator/regulator_common.h
@@ -14,7 +14,6 @@ struct regulator_common_plat {
unsigned int startup_delay_us;
unsigned int off_on_delay_us;
unsigned int enable_count;
- struct udevice *vin_supply;
};
int regulator_common_of_to_plat(struct udevice *dev,
diff --git a/drivers/power/regulator/s2mps11_regulator.c b/drivers/power/regulator/s2mps11_regulator.c
index 96de55065fe..4b4353af639 100644
--- a/drivers/power/regulator/s2mps11_regulator.c
+++ b/drivers/power/regulator/s2mps11_regulator.c
@@ -13,6 +13,193 @@
#include <power/regulator.h>
#include <power/s2mps11.h>
+#define regulator_desc_s2mps11_buck(num, mask, min, step, max_hex) \
+ [num] = { \
+ .mode_reg = S2MPS11_REG_B##num##CTRL1, \
+ .mode_mask = S2MPS11_BUCK_MODE_MASK << S2MPS11_BUCK_MODE_SHIFT, \
+ .volt_reg = S2MPS11_REG_B##num##CTRL2, \
+ .volt_mask = mask, \
+ .volt_min = min, \
+ .volt_step = step, \
+ .volt_max_hex = max_hex, \
+ }
+
+#define regulator_desc_s2mps11_buck1_2_3_4_6(num) \
+ regulator_desc_s2mps11_buck(num, S2MPS11_BUCK_VOLT_MASK, \
+ S2MPS11_BUCK_UV_MIN, \
+ S2MPS11_BUCK_LSTEP, \
+ S2MPS11_BUCK_VOLT_MAX_HEX)
+
+#define regulator_desc_s2mps11_buck5 \
+ regulator_desc_s2mps11_buck(5, S2MPS11_BUCK_VOLT_MASK, \
+ S2MPS11_BUCK_UV_MIN, \
+ S2MPS11_BUCK_LSTEP, \
+ S2MPS11_BUCK5_VOLT_MAX_HEX)
+
+#define regulator_desc_s2mps11_buck7_8_10(num) \
+ regulator_desc_s2mps11_buck(num, S2MPS11_BUCK_VOLT_MASK, \
+ S2MPS11_BUCK_UV_HMIN, \
+ S2MPS11_BUCK_HSTEP, \
+ S2MPS11_BUCK7_8_10_VOLT_MAX_HEX)
+
+#define regulator_desc_s2mps11_buck9 \
+ regulator_desc_s2mps11_buck(9, S2MPS11_BUCK9_VOLT_MASK, \
+ S2MPS11_BUCK_UV_MIN, \
+ S2MPS11_BUCK9_STEP, \
+ S2MPS11_BUCK9_VOLT_MAX_HEX)
+
+static const struct sec_regulator_desc s2mps11_buck_desc[] = {
+ regulator_desc_s2mps11_buck1_2_3_4_6(1),
+ regulator_desc_s2mps11_buck1_2_3_4_6(2),
+ regulator_desc_s2mps11_buck1_2_3_4_6(3),
+ regulator_desc_s2mps11_buck1_2_3_4_6(4),
+ regulator_desc_s2mps11_buck5,
+ regulator_desc_s2mps11_buck1_2_3_4_6(6),
+ regulator_desc_s2mps11_buck7_8_10(7),
+ regulator_desc_s2mps11_buck7_8_10(8),
+ regulator_desc_s2mps11_buck9,
+ regulator_desc_s2mps11_buck7_8_10(10),
+};
+
+#define regulator_desc_s2mps11_ldo(num, step) \
+ [num] = { \
+ .mode_reg = S2MPS11_REG_L##num##CTRL, \
+ .mode_mask = S2MPS11_LDO_MODE_MASK << S2MPS11_LDO_MODE_SHIFT, \
+ .volt_reg = S2MPS11_REG_L##num##CTRL, \
+ .volt_mask = S2MPS11_LDO_VOLT_MASK, \
+ .volt_min = S2MPS11_LDO_UV_MIN, \
+ .volt_step = step, \
+ .volt_max_hex = S2MPS11_LDO_VOLT_MAX_HEX \
+ }
+
+#define regulator_desc_s2mps11_ldo_type1(num) \
+ regulator_desc_s2mps11_ldo(num, S2MPS11_LDO_STEP)
+
+#define regulator_desc_s2mps11_ldo_type2(num) \
+ regulator_desc_s2mps11_ldo(num, S2MPS11_LDO_STEP * 2)
+
+static const struct sec_regulator_desc s2mps11_ldo_desc[] = {
+ regulator_desc_s2mps11_ldo_type1(1),
+ regulator_desc_s2mps11_ldo_type2(2),
+ regulator_desc_s2mps11_ldo_type2(3),
+ regulator_desc_s2mps11_ldo_type2(4),
+ regulator_desc_s2mps11_ldo_type2(5),
+ regulator_desc_s2mps11_ldo_type1(6),
+ regulator_desc_s2mps11_ldo_type2(7),
+ regulator_desc_s2mps11_ldo_type2(8),
+ regulator_desc_s2mps11_ldo_type2(9),
+ regulator_desc_s2mps11_ldo_type2(10),
+ regulator_desc_s2mps11_ldo_type1(11),
+ regulator_desc_s2mps11_ldo_type2(12),
+ regulator_desc_s2mps11_ldo_type2(13),
+ regulator_desc_s2mps11_ldo_type2(14),
+ regulator_desc_s2mps11_ldo_type2(15),
+ regulator_desc_s2mps11_ldo_type2(16),
+ regulator_desc_s2mps11_ldo_type2(17),
+ regulator_desc_s2mps11_ldo_type2(18),
+ regulator_desc_s2mps11_ldo_type2(19),
+ regulator_desc_s2mps11_ldo_type2(20),
+ regulator_desc_s2mps11_ldo_type2(21),
+ regulator_desc_s2mps11_ldo_type1(22),
+ regulator_desc_s2mps11_ldo_type1(23),
+ regulator_desc_s2mps11_ldo_type2(24),
+ regulator_desc_s2mps11_ldo_type2(25),
+ regulator_desc_s2mps11_ldo_type2(26),
+ regulator_desc_s2mps11_ldo_type1(27),
+ regulator_desc_s2mps11_ldo_type2(28),
+ regulator_desc_s2mps11_ldo_type2(29),
+ regulator_desc_s2mps11_ldo_type2(30),
+ regulator_desc_s2mps11_ldo_type2(31),
+ regulator_desc_s2mps11_ldo_type2(32),
+ regulator_desc_s2mps11_ldo_type2(33),
+ regulator_desc_s2mps11_ldo_type2(34),
+ regulator_desc_s2mps11_ldo_type1(35),
+ regulator_desc_s2mps11_ldo_type2(36),
+ regulator_desc_s2mps11_ldo_type2(37),
+ regulator_desc_s2mps11_ldo_type2(38),
+};
+
+#define regulator_desc_s2mpu05_buck(num, which) \
+ [num] = { \
+ .mode_reg = S2MPU05_REG_B##num##CTRL1, \
+ .mode_mask = S2MPS11_BUCK_MODE_MASK << S2MPS11_BUCK_MODE_SHIFT, \
+ .volt_reg = S2MPU05_REG_B##num##CTRL2, \
+ .volt_mask = S2MPS11_BUCK_VOLT_MASK, \
+ .volt_min = S2MPU05_BUCK_MIN##which, \
+ .volt_step = S2MPU05_BUCK_STEP##which, \
+ .volt_max_hex = S2MPS11_BUCK_VOLT_MASK, \
+ }
+
+#define regulator_desc_s2mpu05_buck1_2_3(num) \
+ regulator_desc_s2mpu05_buck(num, 1)
+
+#define regulator_desc_s2mpu05_buck4_5(num) \
+ regulator_desc_s2mpu05_buck(num, 2)
+
+static const struct sec_regulator_desc s2mpu05_buck_desc[] = {
+ regulator_desc_s2mpu05_buck1_2_3(1),
+ regulator_desc_s2mpu05_buck1_2_3(2),
+ regulator_desc_s2mpu05_buck1_2_3(3),
+ regulator_desc_s2mpu05_buck4_5(4),
+ regulator_desc_s2mpu05_buck4_5(5),
+};
+
+#define regulator_desc_s2mpu05_ldo(num, reg, min, step) \
+ [num] = { \
+ .mode_reg = S2MPU05_REG_L##num##reg, \
+ .mode_mask = S2MPS11_LDO_MODE_MASK << S2MPS11_LDO_MODE_SHIFT, \
+ .volt_reg = S2MPU05_REG_L##num##reg, \
+ .volt_mask = S2MPS11_LDO_VOLT_MASK, \
+ .volt_min = min, \
+ .volt_step = step, \
+ .volt_max_hex = S2MPS11_LDO_VOLT_MAX_HEX, \
+ }
+
+#define regulator_desc_s2mpu05_ldo_type1(num) \
+ regulator_desc_s2mpu05_ldo(num, CTRL, S2MPU05_LDO_MIN1, \
+ S2MPU05_LDO_STEP1)
+
+#define regulator_desc_s2mpu05_ldo_type2(num) \
+ regulator_desc_s2mpu05_ldo(num, CTRL, S2MPU05_LDO_MIN1, \
+ S2MPU05_LDO_STEP2)
+
+#define regulator_desc_s2mpu05_ldo_type3(num) \
+ regulator_desc_s2mpu05_ldo(num, CTRL, S2MPU05_LDO_MIN2, \
+ S2MPU05_LDO_STEP2)
+
+#define regulator_desc_s2mpu05_ldo_type4(num) \
+ regulator_desc_s2mpu05_ldo(num, CTRL, S2MPU05_LDO_MIN3, \
+ S2MPU05_LDO_STEP2)
+
+#define regulator_desc_s2mpu05_ldo_type5(num) \
+ regulator_desc_s2mpu05_ldo(num, CTRL1, S2MPU05_LDO_MIN3, \
+ S2MPU05_LDO_STEP2)
+
+static const struct sec_regulator_desc s2mpu05_ldo_desc[] = {
+ regulator_desc_s2mpu05_ldo_type4(1),
+ regulator_desc_s2mpu05_ldo_type3(2),
+ regulator_desc_s2mpu05_ldo_type2(3),
+ regulator_desc_s2mpu05_ldo_type1(4),
+ regulator_desc_s2mpu05_ldo_type1(5),
+ regulator_desc_s2mpu05_ldo_type1(6),
+ regulator_desc_s2mpu05_ldo_type2(7),
+ regulator_desc_s2mpu05_ldo_type3(8),
+ regulator_desc_s2mpu05_ldo_type5(9),
+ regulator_desc_s2mpu05_ldo_type4(10),
+ /* LDOs 11-24 are used for CP. They aren't documented. */
+ regulator_desc_s2mpu05_ldo_type2(25),
+ regulator_desc_s2mpu05_ldo_type3(26),
+ regulator_desc_s2mpu05_ldo_type2(27),
+ regulator_desc_s2mpu05_ldo_type3(28),
+ regulator_desc_s2mpu05_ldo_type3(29),
+ regulator_desc_s2mpu05_ldo_type2(30),
+ regulator_desc_s2mpu05_ldo_type3(31),
+ regulator_desc_s2mpu05_ldo_type3(32),
+ regulator_desc_s2mpu05_ldo_type3(33),
+ regulator_desc_s2mpu05_ldo_type3(34),
+ regulator_desc_s2mpu05_ldo_type3(35),
+};
+
#define MODE(_id, _val, _name) { \
.id = _id, \
.register_value = _val, \
@@ -33,94 +220,46 @@ static struct dm_regulator_mode s2mps11_ldo_modes[] = {
MODE(OP_ON, S2MPS11_LDO_MODE_ON, "ON"),
};
-static const char s2mps11_buck_ctrl[] = {
- 0xff, 0x25, 0x27, 0x29, 0x2b, 0x2d, 0x33, 0x35, 0x37, 0x39, 0x3b
-};
-
-static const char s2mps11_buck_out[] = {
- 0xff, 0x26, 0x28, 0x2a, 0x2c, 0x2f, 0x34, 0x36, 0x38, 0x3a, 0x3c
+static struct dm_regulator_mode s2mpu05_regulator_modes[] = {
+ MODE(OP_OFF, S2MPS11_LDO_MODE_OFF, "OFF"),
+ MODE(OP_ON, S2MPS11_LDO_MODE_ON, "ON"),
};
-static int s2mps11_buck_hex2volt(int buck, int hex)
+static const ulong s2mps11_get_variant(struct udevice *dev)
{
- unsigned int uV = 0;
-
- if (hex < 0)
- goto bad;
-
- switch (buck) {
- case 7:
- case 8:
- case 10:
- if (hex > S2MPS11_BUCK7_8_10_VOLT_MAX_HEX)
- goto bad;
+ struct udevice *parent = dev_get_parent(dev);
- uV = hex * S2MPS11_BUCK_HSTEP + S2MPS11_BUCK_UV_HMIN;
- break;
- case 9:
- if (hex > S2MPS11_BUCK9_VOLT_MAX_HEX)
- goto bad;
- uV = hex * S2MPS11_BUCK9_STEP * 2 + S2MPS11_BUCK9_UV_MIN;
- break;
- default:
- if (buck == 5 && hex > S2MPS11_BUCK5_VOLT_MAX_HEX)
- goto bad;
- else if (buck != 5 && hex > S2MPS11_BUCK_VOLT_MAX_HEX)
- goto bad;
-
- uV = hex * S2MPS11_BUCK_LSTEP + S2MPS11_BUCK_UV_MIN;
- break;
+ if (!parent) {
+ pr_err("Parent is non-existent, this shouldn't happen!\n");
+ return VARIANT_NONE;
}
- return uV;
-bad:
- pr_err("Value: %#x is wrong for BUCK%d", hex, buck);
- return -EINVAL;
+ return dev_get_driver_data(parent);
}
-static int s2mps11_buck_volt2hex(int buck, int uV)
+static int s2mps11_buck_val(struct udevice *dev, int op, int *uV)
{
- int hex;
-
- switch (buck) {
- case 7:
- case 8:
- case 10:
- hex = (uV - S2MPS11_BUCK_UV_HMIN) / S2MPS11_BUCK_HSTEP;
- if (hex > S2MPS11_BUCK7_8_10_VOLT_MAX_HEX)
- goto bad;
+ const struct sec_regulator_desc *buck_desc;
+ int num_bucks, hex, buck, ret;
+ u32 addr;
+ u8 val;
+ switch (s2mps11_get_variant(dev)) {
+ case VARIANT_S2MPS11:
+ buck_desc = s2mps11_buck_desc;
+ num_bucks = ARRAY_SIZE(s2mps11_buck_desc);
break;
- case 9:
- hex = (uV - S2MPS11_BUCK9_UV_MIN) / S2MPS11_BUCK9_STEP;
- if (hex > S2MPS11_BUCK9_VOLT_MAX_HEX)
- goto bad;
+ case VARIANT_S2MPU05:
+ buck_desc = s2mpu05_buck_desc;
+ num_bucks = ARRAY_SIZE(s2mpu05_buck_desc);
break;
default:
- hex = (uV - S2MPS11_BUCK_UV_MIN) / S2MPS11_BUCK_LSTEP;
- if (buck == 5 && hex > S2MPS11_BUCK5_VOLT_MAX_HEX)
- goto bad;
- else if (buck != 5 && hex > S2MPS11_BUCK_VOLT_MAX_HEX)
- goto bad;
- break;
- };
-
- if (hex >= 0)
- return hex;
-
-bad:
- pr_err("Value: %d uV is wrong for BUCK%d", uV, buck);
- return -EINVAL;
-}
-
-static int s2mps11_buck_val(struct udevice *dev, int op, int *uV)
-{
- int hex, buck, ret;
- u32 mask, addr;
- u8 val;
+ pr_err("Unknown device type\n");
+ return -EINVAL;
+ }
buck = dev->driver_data;
- if (buck < 1 || buck > S2MPS11_BUCK_NUM) {
+ if (buck < 1 || buck > num_bucks) {
pr_err("Wrong buck number: %d\n", buck);
return -EINVAL;
}
@@ -128,35 +267,25 @@ static int s2mps11_buck_val(struct udevice *dev, int op, int *uV)
if (op == PMIC_OP_GET)
*uV = 0;
- addr = s2mps11_buck_out[buck];
-
- switch (buck) {
- case 9:
- mask = S2MPS11_BUCK9_VOLT_MASK;
- break;
- default:
- mask = S2MPS11_BUCK_VOLT_MASK;
- break;
- }
+ addr = buck_desc[buck].volt_reg;
ret = pmic_read(dev->parent, addr, &val, 1);
if (ret)
return ret;
if (op == PMIC_OP_GET) {
- val &= mask;
- ret = s2mps11_buck_hex2volt(buck, val);
- if (ret < 0)
- return ret;
- *uV = ret;
+ val &= buck_desc[buck].volt_mask;
+ *uV = val * buck_desc[buck].volt_step + buck_desc[buck].volt_min;
return 0;
}
- hex = s2mps11_buck_volt2hex(buck, *uV);
- if (hex < 0)
- return hex;
+ hex = (*uV - buck_desc[buck].volt_min) / buck_desc[buck].volt_step;
+ if (hex > buck_desc[buck].volt_max_hex) {
+ pr_err("Value: %d uV is wrong for LDO%d\n", *uV, buck);
+ return -EINVAL;
+ }
- val &= ~mask;
+ val &= ~buck_desc[buck].volt_mask;
val |= hex;
ret = pmic_write(dev->parent, addr, &val, 1);
@@ -165,60 +294,63 @@ static int s2mps11_buck_val(struct udevice *dev, int op, int *uV)
static int s2mps11_buck_mode(struct udevice *dev, int op, int *opmode)
{
+ struct dm_regulator_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
+ const struct sec_regulator_desc *buck_desc;
unsigned int addr, mode;
unsigned char val;
- int buck, ret;
+ int num_bucks, buck, ret, i;
+
+ switch (s2mps11_get_variant(dev)) {
+ case VARIANT_S2MPS11:
+ buck_desc = s2mps11_buck_desc;
+ num_bucks = ARRAY_SIZE(s2mps11_buck_desc);
+ break;
+ case VARIANT_S2MPU05:
+ buck_desc = s2mpu05_buck_desc;
+ num_bucks = ARRAY_SIZE(s2mpu05_buck_desc);
+ break;
+ default:
+ pr_err("Unknown device type\n");
+ return -EINVAL;
+ }
buck = dev->driver_data;
- if (buck < 1 || buck > S2MPS11_BUCK_NUM) {
+ if (buck < 1 || buck > num_bucks) {
pr_err("Wrong buck number: %d\n", buck);
return -EINVAL;
}
- addr = s2mps11_buck_ctrl[buck];
+ addr = buck_desc[buck].mode_reg;
ret = pmic_read(dev->parent, addr, &val, 1);
if (ret)
return ret;
if (op == PMIC_OP_GET) {
- val &= (S2MPS11_BUCK_MODE_MASK << S2MPS11_BUCK_MODE_SHIFT);
- switch (val) {
- case S2MPS11_BUCK_MODE_OFF:
- *opmode = OP_OFF;
- break;
- case S2MPS11_BUCK_MODE_STANDBY:
- *opmode = OP_STANDBY;
- break;
- case S2MPS11_BUCK_MODE_ON:
- *opmode = OP_ON;
- break;
- default:
- return -EINVAL;
+ val &= buck_desc[buck].mode_mask;
+ for (i = 0; i < uc_pdata->mode_count; i++) {
+ if (uc_pdata->mode[i].register_value != val)
+ continue;
+
+ *opmode = uc_pdata->mode[i].id;
+ return 0;
}
- return 0;
- }
- switch (*opmode) {
- case OP_OFF:
- mode = S2MPS11_BUCK_MODE_OFF;
- break;
- case OP_STANDBY:
- mode = S2MPS11_BUCK_MODE_STANDBY;
- break;
- case OP_ON:
- mode = S2MPS11_BUCK_MODE_ON;
- break;
- default:
- pr_err("Wrong mode: %d for buck: %d\n", *opmode, buck);
return -EINVAL;
}
- val &= ~(S2MPS11_BUCK_MODE_MASK << S2MPS11_BUCK_MODE_SHIFT);
- val |= mode;
- ret = pmic_write(dev->parent, addr, &val, 1);
+ for (i = 0; i < uc_pdata->mode_count; i++) {
+ if (uc_pdata->mode[i].id != *opmode)
+ continue;
- return ret;
+ mode = uc_pdata->mode[i].register_value;
+ val &= ~buck_desc[buck].mode_mask;
+ val |= mode;
+ return pmic_write(dev->parent, addr, &val, 1);
+ }
+
+ pr_err("Wrong mode: %d for buck: %d\n", *opmode, buck);
+ return -EINVAL;
}
static int s2mps11_buck_enable(struct udevice *dev, int op, bool *enable)
@@ -307,10 +439,21 @@ static int s2mps11_buck_probe(struct udevice *dev)
struct dm_regulator_uclass_plat *uc_pdata;
uc_pdata = dev_get_uclass_plat(dev);
-
uc_pdata->type = REGULATOR_TYPE_BUCK;
- uc_pdata->mode = s2mps11_buck_modes;
- uc_pdata->mode_count = ARRAY_SIZE(s2mps11_buck_modes);
+
+ switch (s2mps11_get_variant(dev)) {
+ case VARIANT_S2MPS11:
+ uc_pdata->mode = s2mps11_buck_modes;
+ uc_pdata->mode_count = ARRAY_SIZE(s2mps11_buck_modes);
+ break;
+ case VARIANT_S2MPU05:
+ uc_pdata->mode = s2mpu05_regulator_modes;
+ uc_pdata->mode_count = ARRAY_SIZE(s2mpu05_regulator_modes);
+ break;
+ default:
+ pr_err("Unknown device type\n");
+ return -EINVAL;
+ }
return 0;
}
@@ -331,95 +474,55 @@ U_BOOT_DRIVER(s2mps11_buck) = {
.probe = s2mps11_buck_probe,
};
-static int s2mps11_ldo_hex2volt(int ldo, int hex)
+static int s2mps11_ldo_val(struct udevice *dev, int op, int *uV)
{
- unsigned int uV = 0;
-
- if (hex > S2MPS11_LDO_VOLT_MAX_HEX) {
- pr_err("Value: %#x is wrong for LDO%d", hex, ldo);
- return -EINVAL;
- }
+ const struct sec_regulator_desc *ldo_desc;
+ unsigned int addr;
+ unsigned char val;
+ int num_ldos, hex, ldo, ret;
- switch (ldo) {
- case 1:
- case 6:
- case 11:
- case 22:
- case 23:
- case 27:
- case 35:
- uV = hex * S2MPS11_LDO_STEP + S2MPS11_LDO_UV_MIN;
- break;
- default:
- uV = hex * S2MPS11_LDO_STEP * 2 + S2MPS11_LDO_UV_MIN;
+ switch (s2mps11_get_variant(dev)) {
+ case VARIANT_S2MPS11:
+ ldo_desc = s2mps11_ldo_desc;
+ num_ldos = ARRAY_SIZE(s2mps11_ldo_desc);
break;
- }
-
- return uV;
-}
-
-static int s2mps11_ldo_volt2hex(int ldo, int uV)
-{
- int hex = 0;
-
- switch (ldo) {
- case 1:
- case 6:
- case 11:
- case 22:
- case 23:
- case 27:
- case 35:
- hex = (uV - S2MPS11_LDO_UV_MIN) / S2MPS11_LDO_STEP;
+ case VARIANT_S2MPU05:
+ ldo_desc = s2mpu05_ldo_desc;
+ num_ldos = ARRAY_SIZE(s2mpu05_ldo_desc);
break;
default:
- hex = (uV - S2MPS11_LDO_UV_MIN) / (S2MPS11_LDO_STEP * 2);
- break;
+ pr_err("Unknown device type\n");
+ return -EINVAL;
}
- if (hex >= 0 && hex <= S2MPS11_LDO_VOLT_MAX_HEX)
- return hex;
-
- pr_err("Value: %d uV is wrong for LDO%d", uV, ldo);
- return -EINVAL;
-
- return 0;
-}
-
-static int s2mps11_ldo_val(struct udevice *dev, int op, int *uV)
-{
- unsigned int addr;
- unsigned char val;
- int hex, ldo, ret;
-
ldo = dev->driver_data;
- if (ldo < 1 || ldo > S2MPS11_LDO_NUM) {
+ if (ldo < 1 || ldo > num_ldos) {
pr_err("Wrong ldo number: %d\n", ldo);
return -EINVAL;
}
- addr = S2MPS11_REG_L1CTRL + ldo - 1;
+ addr = ldo_desc[ldo].volt_reg;
+
+ if (op == PMIC_OP_GET)
+ *uV = 0;
ret = pmic_read(dev->parent, addr, &val, 1);
if (ret)
return ret;
if (op == PMIC_OP_GET) {
- *uV = 0;
- val &= S2MPS11_LDO_VOLT_MASK;
- ret = s2mps11_ldo_hex2volt(ldo, val);
- if (ret < 0)
- return ret;
-
- *uV = ret;
+ val &= ldo_desc[ldo].volt_mask;
+ *uV = val * ldo_desc[ldo].volt_step + ldo_desc[ldo].volt_min;
return 0;
}
- hex = s2mps11_ldo_volt2hex(ldo, *uV);
- if (hex < 0)
- return hex;
+ hex = (*uV - ldo_desc[ldo].volt_min) / ldo_desc[ldo].volt_step;
+ if (hex > ldo_desc[ldo].volt_max_hex) {
+ pr_err("Value: %d uV is wrong for LDO%d\n", *uV, ldo);
+ return -EINVAL;
+ }
- val &= ~S2MPS11_LDO_VOLT_MASK;
+ val &= ~ldo_desc[ldo].volt_mask;
val |= hex;
ret = pmic_write(dev->parent, addr, &val, 1);
@@ -428,65 +531,64 @@ static int s2mps11_ldo_val(struct udevice *dev, int op, int *uV)
static int s2mps11_ldo_mode(struct udevice *dev, int op, int *opmode)
{
+ struct dm_regulator_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
+ const struct sec_regulator_desc *ldo_desc;
unsigned int addr, mode;
unsigned char val;
- int ldo, ret;
+ int num_ldos, ldo, ret, i;
+
+ switch (s2mps11_get_variant(dev)) {
+ case VARIANT_S2MPS11:
+ ldo_desc = s2mps11_ldo_desc;
+ num_ldos = ARRAY_SIZE(s2mps11_ldo_desc);
+ break;
+ case VARIANT_S2MPU05:
+ ldo_desc = s2mpu05_ldo_desc;
+ num_ldos = ARRAY_SIZE(s2mpu05_ldo_desc);
+ break;
+ default:
+ pr_err("Unknown device type\n");
+ return -EINVAL;
+ }
ldo = dev->driver_data;
- if (ldo < 1 || ldo > S2MPS11_LDO_NUM) {
+ if (ldo < 1 || ldo > num_ldos) {
pr_err("Wrong ldo number: %d\n", ldo);
return -EINVAL;
}
- addr = S2MPS11_REG_L1CTRL + ldo - 1;
+
+ addr = ldo_desc[ldo].mode_reg;
ret = pmic_read(dev->parent, addr, &val, 1);
if (ret)
return ret;
if (op == PMIC_OP_GET) {
- val &= (S2MPS11_LDO_MODE_MASK << S2MPS11_LDO_MODE_SHIFT);
- switch (val) {
- case S2MPS11_LDO_MODE_OFF:
- *opmode = OP_OFF;
- break;
- case S2MPS11_LDO_MODE_STANDBY:
- *opmode = OP_STANDBY;
- break;
- case S2MPS11_LDO_MODE_STANDBY_LPM:
- *opmode = OP_STANDBY_LPM;
- break;
- case S2MPS11_LDO_MODE_ON:
- *opmode = OP_ON;
- break;
- default:
- return -EINVAL;
+ val &= ldo_desc[ldo].mode_mask;
+
+ for (i = 0; i < uc_pdata->mode_count; i++) {
+ if (uc_pdata->mode[i].register_value != val)
+ continue;
+
+ *opmode = uc_pdata->mode[i].id;
+ return 0;
}
- return 0;
- }
- switch (*opmode) {
- case OP_OFF:
- mode = S2MPS11_LDO_MODE_OFF;
- break;
- case OP_STANDBY:
- mode = S2MPS11_LDO_MODE_STANDBY;
- break;
- case OP_STANDBY_LPM:
- mode = S2MPS11_LDO_MODE_STANDBY_LPM;
- break;
- case OP_ON:
- mode = S2MPS11_LDO_MODE_ON;
- break;
- default:
- pr_err("Wrong mode: %d for ldo: %d\n", *opmode, ldo);
return -EINVAL;
}
- val &= ~(S2MPS11_LDO_MODE_MASK << S2MPS11_LDO_MODE_SHIFT);
- val |= mode;
- ret = pmic_write(dev->parent, addr, &val, 1);
+ for (i = 0; i < uc_pdata->mode_count; i++) {
+ if (uc_pdata->mode[i].id != *opmode)
+ continue;
- return ret;
+ mode = uc_pdata->mode[i].register_value;
+ val &= ~ldo_desc[ldo].mode_mask;
+ val |= mode;
+ return pmic_write(dev->parent, addr, &val, 1);
+ }
+
+ pr_err("Wrong mode: %d for ldo: %d\n", *opmode, ldo);
+ return -EINVAL;
}
static int s2mps11_ldo_enable(struct udevice *dev, int op, bool *enable)
@@ -584,8 +686,20 @@ static int s2mps11_ldo_probe(struct udevice *dev)
uc_pdata = dev_get_uclass_plat(dev);
uc_pdata->type = REGULATOR_TYPE_LDO;
- uc_pdata->mode = s2mps11_ldo_modes;
- uc_pdata->mode_count = ARRAY_SIZE(s2mps11_ldo_modes);
+
+ switch (s2mps11_get_variant(dev)) {
+ case VARIANT_S2MPS11:
+ uc_pdata->mode = s2mps11_ldo_modes;
+ uc_pdata->mode_count = ARRAY_SIZE(s2mps11_ldo_modes);
+ break;
+ case VARIANT_S2MPU05:
+ uc_pdata->mode = s2mpu05_regulator_modes;
+ uc_pdata->mode_count = ARRAY_SIZE(s2mpu05_regulator_modes);
+ break;
+ default:
+ pr_err("Unknown device type\n");
+ return -EINVAL;
+ }
return 0;
}
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 06f42f699de..a69fe37caff 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -1,3 +1,5 @@
+menu "Pulse-width modulation (PWM)"
+
config DM_PWM
bool "Enable support for pulse-width modulation devices (PWM)"
depends on DM
@@ -9,9 +11,21 @@ config DM_PWM
frequency/period can be controlled along with the proportion of that
time that the signal is high.
+config PWM_IMX
+ bool "Enable support for i.MX27 and later PWM"
+ depends on MACH_IMX
+ help
+ This PWM is found i.MX27 and later i.MX SoCs.
+
+config PWM_S5P
+ bool "Enable non-DM support for S5P PWM"
+ depends on (S5P || ARCH_NEXELL)
+ default y
+
+if DM_PWM
+
config PWM_ASPEED
bool "Enable support for the Aspeed PWM"
- depends on DM_PWM
select SYSCON
help
This PWM is found on Ast2600 SoCs. It supports a programmable period
@@ -20,20 +34,19 @@ config PWM_ASPEED
config PWM_AT91
bool "Enable support for PWM found on AT91 SoC's"
- depends on DM_PWM && ARCH_AT91
+ depends on ARCH_AT91
help
Support for PWM hardware on AT91 based SoC.
config PWM_CADENCE_TTC
bool "Enable support for the Cadence TTC PWM"
- depends on DM_PWM && !CADENCE_TTC_TIMER
+ depends on !CADENCE_TTC_TIMER
help
Cadence TTC can be configured as timer which is done via
CONFIG_CADENCE_TTC_TIMER or as PWM. This is covering only PWM now.
config PWM_CROS_EC
bool "Enable support for the Chrome OS EC PWM"
- depends on DM_PWM
help
This PWM is found on several Chrome OS devices and controlled by
the Chrome OS embedded controller. It may be used to control the
@@ -42,36 +55,28 @@ config PWM_CROS_EC
config PWM_EXYNOS
bool "Enable support for the Exynos PWM"
- depends on DM_PWM && ARCH_EXYNOS
+ depends on ARCH_EXYNOS
help
This PWM is found on Samsung Exynos 5250 and other Samsung SoCs. It
supports a programmable period and duty cycle. A 32-bit counter is
used. It provides 5 channels which can be independently
programmed. Channel 4 (the last) is normally used as a timer.
-config PWM_IMX
- bool "Enable support for i.MX27 and later PWM"
- depends on MACH_IMX
- help
- This PWM is found i.MX27 and later i.MX SoCs.
-
config PWM_MESON
bool "Enable support for Amlogic Meson SoCs PWM"
- depends on DM_PWM
help
This PWM is found on Amlogic Meson SoCs. It supports a
- programmable period and duty cycle for 2 independant channels.
+ programmable period and duty cycle for 2 independent channels.
config PWM_MTK
bool "Enable support for MediaTek PWM"
- depends on DM_PWM
help
This PWM is found on MT7622, MT7623, and MT7629. It supports a
programmable period and duty cycle.
config PWM_ROCKCHIP
bool "Enable support for the Rockchip PWM"
- depends on DM_PWM && ARCH_ROCKCHIP
+ depends on ARCH_ROCKCHIP
help
This PWM is found on RK3288 and other Rockchip SoCs. It supports a
programmable period and duty cycle. A 32-bit counter is used.
@@ -86,20 +91,14 @@ config PWM_SANDBOX
useful. The PWM can be enabled but is not connected to any outputs
so this is not very useful.
-config PWM_S5P
- bool "Enable non-DM support for S5P PWM"
- depends on (S5P || ARCH_NEXELL)
- default y
-
config PWM_SIFIVE
bool "Enable support for SiFive PWM"
- depends on DM_PWM
help
This PWM is found SiFive's FU540 and other SoCs.
config PWM_TEGRA
bool "Enable support for the Tegra PWM"
- depends on DM_PWM && ARCH_TEGRA
+ depends on ARCH_TEGRA
help
This PWM is found on Tegra 20 and other Nvidia SoCs. It supports
four channels with a programmable period and duty cycle. Only a
@@ -108,7 +107,7 @@ config PWM_TEGRA
config PWM_STM32
bool "Enable support for STM32 PWM"
- depends on DM_PWM && MFD_STM32_TIMERS
+ depends on MFD_STM32_TIMERS
help
This enables PWM driver for STMicroelectronics STM32 pulse width
modulation. It uses STM32 timer devices that can have up to 4 output
@@ -116,20 +115,23 @@ config PWM_STM32
config PWM_SUNXI
bool "Enable support for the Allwinner Sunxi PWM"
- depends on DM_PWM && ARCH_SUNXI
+ depends on ARCH_SUNXI
help
This PWM is found on H3, A64 and other Allwinner SoCs. It supports a
programmable period and duty cycle. A 16-bit counter is used.
config PWM_TI_EHRPWM
bool "Enable support for EHRPWM PWM"
- depends on DM_PWM && ARCH_OMAP2PLUS
+ depends on ARCH_OMAP2PLUS
default y
help
PWM driver support for the EHRPWM controller found on TI SOCs.
config PWM_TI_ECAP
bool "Enable support for ECAP PWM"
- depends on DM_PWM && ARCH_OMAP2PLUS
+ depends on ARCH_OMAP2PLUS
help
PWM driver support for the ECAP controller found on TI SOCs.
+
+endif
+endmenu
diff --git a/drivers/pwm/pwm-cadence-ttc.c b/drivers/pwm/pwm-cadence-ttc.c
index 767628833bc..fae6d5a1739 100644
--- a/drivers/pwm/pwm-cadence-ttc.c
+++ b/drivers/pwm/pwm-cadence-ttc.c
@@ -47,6 +47,8 @@
#define TTC_MATCH_1_COUNTER(reg, channel) \
TTC_REG((reg) + MATCH_1_COUNTER, (channel))
+#define TTC_PWM_CHANNELS 3
+
struct cadence_ttc_pwm_plat {
u8 *regs;
u32 timer_width;
@@ -57,7 +59,7 @@ struct cadence_ttc_pwm_priv {
u32 timer_width;
u32 timer_mask;
unsigned long frequency;
- bool invert[2];
+ bool invert[TTC_PWM_CHANNELS];
};
static int cadence_ttc_pwm_set_invert(struct udevice *dev, uint channel,
@@ -65,7 +67,7 @@ static int cadence_ttc_pwm_set_invert(struct udevice *dev, uint channel,
{
struct cadence_ttc_pwm_priv *priv = dev_get_priv(dev);
- if (channel > 2) {
+ if (channel >= TTC_PWM_CHANNELS) {
dev_err(dev, "Unsupported channel number %d(max 2)\n", channel);
return -EINVAL;
}
@@ -87,7 +89,7 @@ static int cadence_ttc_pwm_set_config(struct udevice *dev, uint channel,
dev_dbg(dev, "channel %d, duty %d/period %d ns\n", channel,
duty_ns, period_ns);
- if (channel > 2) {
+ if (channel >= TTC_PWM_CHANNELS) {
dev_err(dev, "Unsupported channel number %d(max 2)\n", channel);
return -EINVAL;
}
@@ -153,7 +155,7 @@ static int cadence_ttc_pwm_set_enable(struct udevice *dev, uint channel,
{
struct cadence_ttc_pwm_priv *priv = dev_get_priv(dev);
- if (channel > 2) {
+ if (channel >= TTC_PWM_CHANNELS) {
dev_err(dev, "Unsupported channel number %d(max 2)\n", channel);
return -EINVAL;
}
diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c
index c2597d8b669..caa7af085fa 100644
--- a/drivers/pwm/pwm-meson.c
+++ b/drivers/pwm/pwm-meson.c
@@ -359,8 +359,9 @@ static int meson_pwm_probe(struct udevice *dev)
/* We have our source clock, do not alter HW clock mux */
continue;
- } else
+ } else if (err) {
return err;
+ }
/* Get id in list */
for (p = 0 ; p < data->num_parents ; ++p) {
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index e9f19a69433..8056f210abc 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -33,6 +33,13 @@ config REMOTEPROC_ADI_SC5XX
Say 'y' here to add support for loading code onto SHARC cores in
an ADSP-SC5xx SoC from Analog Devices
+config REMOTEPROC_IMX
+ bool "Support for NXP i.MX remoteproc"
+ select REMOTEPROC
+ depends on DM && MACH_IMX && OF_CONTROL
+ help
+ Say 'y' here to add support for i.MX remoteproc.
+
config REMOTEPROC_RENESAS_APMU
bool "Support for Renesas R-Car Gen4 APMU start of CR52 processor"
select REMOTEPROC
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 47bd57c7890..7ea8023c50b 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_$(PHASE_)REMOTEPROC) += rproc-uclass.o rproc-elf-loader.o
# Remote proc drivers - Please keep this list alphabetically sorted.
obj-$(CONFIG_K3_SYSTEM_CONTROLLER) += k3_system_controller.o
obj-$(CONFIG_REMOTEPROC_ADI_SC5XX) += adi_sc5xx_rproc.o
+obj-$(CONFIG_REMOTEPROC_IMX) += imx_rproc.o
obj-$(CONFIG_REMOTEPROC_RENESAS_APMU) += renesas_apmu.o
obj-$(CONFIG_REMOTEPROC_SANDBOX) += sandbox_testproc.o
obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.o
diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
new file mode 100644
index 00000000000..9bb55327998
--- /dev/null
+++ b/drivers/remoteproc/imx_rproc.c
@@ -0,0 +1,370 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <asm/io.h>
+#include <dm.h>
+#include <errno.h>
+#include <dm/device_compat.h>
+#include <linux/arm-smccc.h>
+#include <linux/types.h>
+#include <regmap.h>
+#include <remoteproc.h>
+#include <syscon.h>
+
+#include "imx_rproc.h"
+
+#define IMX7D_SRC_SCR 0x0C
+#define IMX7D_ENABLE_M4 BIT(3)
+#define IMX7D_SW_M4P_RST BIT(2)
+#define IMX7D_SW_M4C_RST BIT(1)
+#define IMX7D_SW_M4C_NON_SCLR_RST BIT(0)
+
+#define IMX7D_M4_RST_MASK (IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \
+ | IMX7D_SW_M4C_RST \
+ | IMX7D_SW_M4C_NON_SCLR_RST)
+
+#define IMX7D_M4_START (IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \
+ | IMX7D_SW_M4C_RST)
+#define IMX7D_M4_STOP (IMX7D_ENABLE_M4 | IMX7D_SW_M4C_RST | \
+ IMX7D_SW_M4C_NON_SCLR_RST)
+
+#define IMX_RPROC_MEM_MAX 32
+
+#define IMX_SIP_RPROC 0xC2000005
+#define IMX_SIP_RPROC_START 0x00
+#define IMX_SIP_RPROC_STARTED 0x01
+#define IMX_SIP_RPROC_STOP 0x02
+
+struct imx_rproc {
+ const struct imx_rproc_dcfg *dcfg;
+ struct regmap *regmap;
+};
+
+/* att flags: lower 16 bits specifying core, higher 16 bits for flags */
+/* M4 own area. Can be mapped at probe */
+#define ATT_OWN BIT(31)
+#define ATT_IOMEM BIT(30)
+
+static int imx_rproc_arm_smc_start(struct udevice *dev)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_START, 0, 0, 0, 0, 0, 0, &res);
+
+ return res.a0;
+}
+
+static int imx_rproc_mmio_start(struct udevice *dev)
+{
+ struct imx_rproc *priv = dev_get_priv(dev);
+ const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+
+ return regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, dcfg->src_start);
+}
+
+static int imx_rproc_start(struct udevice *dev)
+{
+ struct imx_rproc *priv = dev_get_priv(dev);
+ const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+ int ret;
+
+ if (!dcfg->ops || !dcfg->ops->start)
+ return -EOPNOTSUPP;
+
+ ret = dcfg->ops->start(dev);
+ if (ret)
+ dev_err(dev, "Failed to enable remote core!\n");
+
+ return ret;
+}
+
+static int imx_rproc_arm_smc_stop(struct udevice *dev)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STOP, 0, 0, 0, 0, 0, 0, &res);
+ if (res.a1)
+ dev_info(dev, "Not in wfi, force stopped\n");
+
+ return res.a0;
+}
+
+static int imx_rproc_mmio_stop(struct udevice *dev)
+{
+ struct imx_rproc *priv = dev_get_priv(dev);
+ const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+
+ return regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, dcfg->src_stop);
+}
+
+static int imx_rproc_stop(struct udevice *dev)
+{
+ struct imx_rproc *priv = dev_get_priv(dev);
+ const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+ int ret;
+
+ if (!dcfg->ops || !dcfg->ops->stop)
+ return -EOPNOTSUPP;
+
+ ret = dcfg->ops->stop(dev);
+ if (ret)
+ dev_err(dev, "Failed to stop remote core\n");
+
+ return ret;
+}
+
+static int imx_rproc_arm_smc_is_running(struct udevice *dev)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STARTED, 0, 0, 0, 0, 0, 0, &res);
+ if (res.a0)
+ return 0;
+
+ return 1;
+}
+
+static int imx_rproc_mmio_is_running(struct udevice *dev)
+{
+ struct imx_rproc *priv = dev_get_priv(dev);
+ const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+ int ret;
+ u32 val;
+
+ ret = regmap_read(priv->regmap, dcfg->src_reg, &val);
+ if (ret) {
+ dev_err(dev, "Failed to read src\n");
+ return ret;
+ }
+
+ if ((val & dcfg->src_mask) != dcfg->src_stop)
+ return 0;
+
+ return 1;
+}
+
+static int imx_rproc_is_running(struct udevice *dev)
+{
+ struct imx_rproc *priv = dev_get_priv(dev);
+ const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+
+ if (!dcfg->ops || !dcfg->ops->is_running)
+ return 0;
+
+ return dcfg->ops->is_running(dev);
+}
+
+static int imx_rproc_init(struct udevice *dev)
+{
+ return 0;
+}
+
+static int imx_rproc_da_to_sys(struct udevice *dev, u64 da, size_t len, u64 *sys, bool *is_iomem)
+{
+ struct imx_rproc *priv = dev_get_priv(dev);
+ const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+ int i;
+
+ /* parse address translation table */
+ for (i = 0; i < dcfg->att_size; i++) {
+ const struct imx_rproc_att *att = &dcfg->att[i];
+
+ if (da >= att->da && da + len < att->da + att->size) {
+ unsigned int offset = da - att->da;
+
+ *sys = att->sa + offset;
+
+ if (is_iomem)
+ *is_iomem = att->flags & ATT_IOMEM;
+
+ return 0;
+ }
+ }
+
+ dev_err(dev, "Translation failed: da = 0x%llx len = 0x%zx\n", da, len);
+
+ return -ENOENT;
+}
+
+static void *imx_rproc_device_to_virt(struct udevice *dev, ulong da, ulong size, bool *is_iomem)
+{
+ u64 sys;
+
+ if (imx_rproc_da_to_sys(dev, da, size, &sys, is_iomem))
+ return NULL;
+
+ dev_dbg(dev, "da = 0x%lx len = 0x%lx sys = 0x%llx\n", da, size, sys);
+
+ return phys_to_virt(sys);
+}
+
+static int imx_rproc_load(struct udevice *dev, ulong addr, ulong size)
+{
+ return rproc_elf_load_image(dev, addr, size);
+}
+
+static const struct dm_rproc_ops imx_rproc_ops = {
+ .init = imx_rproc_init,
+ .start = imx_rproc_start,
+ .stop = imx_rproc_stop,
+ .load = imx_rproc_load,
+ .device_to_virt = imx_rproc_device_to_virt,
+ .is_running = imx_rproc_is_running,
+};
+
+static int imx_rproc_probe(struct udevice *dev)
+{
+ struct imx_rproc *priv = dev_get_priv(dev);
+ struct imx_rproc_dcfg *dcfg = (struct imx_rproc_dcfg *)dev_get_driver_data(dev);
+ ofnode node;
+
+ node = dev_ofnode(dev);
+
+ priv->dcfg = dcfg;
+
+ if (dcfg->method != IMX_RPROC_MMIO)
+ return 0;
+
+ priv->regmap = syscon_regmap_lookup_by_phandle(dev, "syscon");
+ if (IS_ERR(priv->regmap)) {
+ dev_err(dev, "No syscon: %ld\n", PTR_ERR(priv->regmap));
+ return PTR_ERR(priv->regmap);
+ }
+
+ return 0;
+}
+
+static const struct imx_rproc_att imx_rproc_att_imx8mn[] = {
+ /* dev addr , sys addr , size , flags */
+ /* ITCM */
+ { 0x00000000, 0x007E0000, 0x00020000, ATT_OWN | ATT_IOMEM },
+ /* OCRAM_S */
+ { 0x00180000, 0x00180000, 0x00009000, 0 },
+ /* OCRAM */
+ { 0x00900000, 0x00900000, 0x00020000, 0 },
+ /* OCRAM */
+ { 0x00920000, 0x00920000, 0x00020000, 0 },
+ /* OCRAM */
+ { 0x00940000, 0x00940000, 0x00050000, 0 },
+ /* QSPI Code - alias */
+ { 0x08000000, 0x08000000, 0x08000000, 0 },
+ /* DDR (Code) - alias */
+ { 0x10000000, 0x40000000, 0x0FFE0000, 0 },
+ /* DTCM */
+ { 0x20000000, 0x00800000, 0x00020000, ATT_OWN | ATT_IOMEM },
+ /* OCRAM_S - alias */
+ { 0x20180000, 0x00180000, 0x00008000, ATT_OWN },
+ /* OCRAM */
+ { 0x20200000, 0x00900000, 0x00020000, ATT_OWN },
+ /* OCRAM */
+ { 0x20220000, 0x00920000, 0x00020000, ATT_OWN },
+ /* OCRAM */
+ { 0x20240000, 0x00940000, 0x00040000, ATT_OWN },
+ /* DDR (Data) */
+ { 0x40000000, 0x40000000, 0x80000000, 0 },
+};
+
+static const struct imx_rproc_plat_ops imx_rproc_ops_arm_smc = {
+ .start = imx_rproc_arm_smc_start,
+ .stop = imx_rproc_arm_smc_stop,
+ .is_running = imx_rproc_arm_smc_is_running,
+};
+
+static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn = {
+ .att = imx_rproc_att_imx8mn,
+ .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn),
+ .method = IMX_RPROC_SMC,
+ .ops = &imx_rproc_ops_arm_smc,
+};
+
+static const struct imx_rproc_att imx_rproc_att_imx8mq[] = {
+ /* dev addr , sys addr , size , flags */
+ /* TCML - alias */
+ { 0x00000000, 0x007e0000, 0x00020000, ATT_IOMEM},
+ /* OCRAM_S */
+ { 0x00180000, 0x00180000, 0x00008000, 0 },
+ /* OCRAM */
+ { 0x00900000, 0x00900000, 0x00020000, 0 },
+ /* OCRAM */
+ { 0x00920000, 0x00920000, 0x00020000, 0 },
+ /* QSPI Code - alias */
+ { 0x08000000, 0x08000000, 0x08000000, 0 },
+ /* DDR (Code) - alias */
+ { 0x10000000, 0x40000000, 0x0FFE0000, 0 },
+ /* TCML/U */
+ { 0x1FFE0000, 0x007E0000, 0x00040000, ATT_OWN | ATT_IOMEM},
+ /* OCRAM_S */
+ { 0x20180000, 0x00180000, 0x00008000, ATT_OWN },
+ /* OCRAM */
+ { 0x20200000, 0x00900000, 0x00020000, ATT_OWN },
+ /* OCRAM */
+ { 0x20220000, 0x00920000, 0x00020000, ATT_OWN },
+ /* DDR (Data) */
+ { 0x40000000, 0x40000000, 0x80000000, 0 },
+};
+
+static const struct imx_rproc_plat_ops imx_rproc_ops_mmio = {
+ .start = imx_rproc_mmio_start,
+ .stop = imx_rproc_mmio_stop,
+ .is_running = imx_rproc_mmio_is_running,
+};
+
+static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = {
+ .src_reg = IMX7D_SRC_SCR,
+ .src_mask = IMX7D_M4_RST_MASK,
+ .src_start = IMX7D_M4_START,
+ .src_stop = IMX7D_M4_STOP,
+ .att = imx_rproc_att_imx8mq,
+ .att_size = ARRAY_SIZE(imx_rproc_att_imx8mq),
+ .method = IMX_RPROC_MMIO,
+ .ops = &imx_rproc_ops_mmio,
+};
+
+static const struct imx_rproc_att imx_rproc_att_imx93[] = {
+ /* dev addr , sys addr , size , flags */
+ /* TCM CODE NON-SECURE */
+ { 0x0FFC0000, 0x201C0000, 0x00040000, ATT_OWN | ATT_IOMEM },
+
+ /* TCM CODE SECURE */
+ { 0x1FFC0000, 0x201C0000, 0x00040000, ATT_OWN | ATT_IOMEM },
+
+ /* TCM SYS NON-SECURE*/
+ { 0x20000000, 0x20200000, 0x00040000, ATT_OWN | ATT_IOMEM },
+
+ /* TCM SYS SECURE*/
+ { 0x30000000, 0x20200000, 0x00040000, ATT_OWN | ATT_IOMEM },
+
+ /* DDR */
+ { 0x80000000, 0x80000000, 0x10000000, 0 },
+ { 0x90000000, 0x80000000, 0x10000000, 0 },
+
+ { 0xC0000000, 0xC0000000, 0x10000000, 0 },
+ { 0xD0000000, 0xC0000000, 0x10000000, 0 },
+};
+
+static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = {
+ .att = imx_rproc_att_imx93,
+ .att_size = ARRAY_SIZE(imx_rproc_att_imx93),
+ .method = IMX_RPROC_SMC,
+ .ops = &imx_rproc_ops_arm_smc,
+};
+
+static const struct udevice_id imx_rproc_ids[] = {
+ { .compatible = "fsl,imx8mm-cm4", .data = (ulong)&imx_rproc_cfg_imx8mq },
+ { .compatible = "fsl,imx8mn-cm7", .data = (ulong)&imx_rproc_cfg_imx8mn, },
+ { .compatible = "fsl,imx8mp-cm7", .data = (ulong)&imx_rproc_cfg_imx8mn, },
+ { .compatible = "fsl,imx8mq-cm4", .data = (ulong)&imx_rproc_cfg_imx8mq },
+ { .compatible = "fsl,imx93-cm33", .data = (ulong)&imx_rproc_cfg_imx93 },
+ {}
+};
+
+U_BOOT_DRIVER(imx_rproc) = {
+ .name = "imx_rproc",
+ .of_match = imx_rproc_ids,
+ .id = UCLASS_REMOTEPROC,
+ .ops = &imx_rproc_ops,
+ .probe = imx_rproc_probe,
+ .priv_auto = sizeof(struct imx_rproc),
+};
diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h
new file mode 100644
index 00000000000..7a82dc4a195
--- /dev/null
+++ b/drivers/remoteproc/imx_rproc.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
+ * Copyright 2021 NXP
+ */
+
+#ifndef _IMX_RPROC_H
+#define _IMX_RPROC_H
+
+/* address translation table */
+struct imx_rproc_att {
+ u32 da; /* device address (From Cortex M4 view)*/
+ u32 sa; /* system bus address */
+ u32 size; /* size of reg range */
+ int flags;
+};
+
+/* Remote core start/stop method */
+enum imx_rproc_method {
+ IMX_RPROC_NONE,
+ /* Through syscon regmap */
+ IMX_RPROC_MMIO,
+ /* Through ARM SMCCC */
+ IMX_RPROC_SMC,
+ /* Through System Control Unit API */
+ IMX_RPROC_SCU_API,
+ /* Through Reset Controller API */
+ IMX_RPROC_RESET_CONTROLLER,
+ /* Through System Manager */
+ IMX_RPROC_SM,
+};
+
+/* dcfg flags */
+#define IMX_RPROC_NEED_SYSTEM_OFF BIT(0)
+
+struct imx_rproc_plat_ops {
+ int (*start)(struct udevice *dev);
+ int (*stop)(struct udevice *dev);
+ int (*is_running)(struct udevice *dev);
+};
+
+struct imx_rproc_dcfg {
+ u32 src_reg;
+ u32 src_mask;
+ u32 src_start;
+ u32 src_stop;
+ u32 gpr_reg;
+ u32 gpr_wait;
+ const struct imx_rproc_att *att;
+ size_t att_size;
+ enum imx_rproc_method method;
+ u32 flags;
+ const struct imx_rproc_plat_ops *ops;
+};
+
+#endif /* _IMX_RPROC_H */
diff --git a/drivers/remoteproc/renesas_apmu.c b/drivers/remoteproc/renesas_apmu.c
index 1a50cd3289b..91586a99e0d 100644
--- a/drivers/remoteproc/renesas_apmu.c
+++ b/drivers/remoteproc/renesas_apmu.c
@@ -170,11 +170,12 @@ static int renesas_apmu_rproc_init(struct udevice *dev)
* @dev: corresponding remote processor device
* @da: device address
* @size: Size of the memory region @da is pointing to
+ * @is_iomem: optional pointer filled in to indicate if @da is iomapped memory
*
* Return: converted virtual address
*/
static void *renesas_apmu_rproc_device_to_virt(struct udevice *dev, ulong da,
- ulong size)
+ ulong size, bool *is_iomem)
{
/*
* The Cortex R52 and A76 share the same address space,
diff --git a/drivers/remoteproc/rproc-elf-loader.c b/drivers/remoteproc/rproc-elf-loader.c
index 0b3941b7798..83d70c2fb54 100644
--- a/drivers/remoteproc/rproc-elf-loader.c
+++ b/drivers/remoteproc/rproc-elf-loader.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
/*
* Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ * Copyright 2025 NXP
*/
#include <cpu_func.h>
#include <dm.h>
@@ -9,6 +10,7 @@
#include <mapmem.h>
#include <remoteproc.h>
#include <asm/cache.h>
+#include <asm/io.h>
#include <dm/device_compat.h>
#include <linux/compat.h>
#include <linux/printk.h>
@@ -181,27 +183,38 @@ int rproc_elf32_load_image(struct udevice *dev, unsigned long addr, ulong size)
for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
void *dst = (void *)(uintptr_t)phdr->p_paddr;
void *src = (void *)addr + phdr->p_offset;
+ bool is_iomem = false;
ulong dst_addr;
- if (phdr->p_type != PT_LOAD)
+ if (phdr->p_type != PT_LOAD || !phdr->p_memsz)
continue;
if (ops->device_to_virt)
dst = ops->device_to_virt(dev, (ulong)dst,
- phdr->p_memsz);
+ phdr->p_memsz, &is_iomem);
dev_dbg(dev, "Loading phdr %i to 0x%p (%i bytes)\n",
i, dst, phdr->p_filesz);
- if (phdr->p_filesz)
- memcpy(dst, src, phdr->p_filesz);
- if (phdr->p_filesz != phdr->p_memsz)
- memset(dst + phdr->p_filesz, 0x00,
- phdr->p_memsz - phdr->p_filesz);
+ if (phdr->p_filesz) {
+ if (is_iomem)
+ memcpy_toio(dst, src, phdr->p_filesz);
+ else
+ memcpy(dst, src, phdr->p_filesz);
+ }
+ if (phdr->p_filesz != phdr->p_memsz) {
+ if (is_iomem)
+ memset_io(dst + phdr->p_filesz, 0x00,
+ phdr->p_memsz - phdr->p_filesz);
+ else
+ memset(dst + phdr->p_filesz, 0x00,
+ phdr->p_memsz - phdr->p_filesz);
+ }
dst_addr = map_to_sysmem(dst);
- flush_cache(rounddown(dst_addr, ARCH_DMA_MINALIGN),
- roundup(dst_addr + phdr->p_filesz,
- ARCH_DMA_MINALIGN) -
- rounddown(dst_addr, ARCH_DMA_MINALIGN));
+ if (!is_iomem) {
+ flush_cache(rounddown(dst_addr, ARCH_DMA_MINALIGN),
+ roundup(dst_addr + phdr->p_filesz, ARCH_DMA_MINALIGN) -
+ rounddown(dst_addr, ARCH_DMA_MINALIGN));
+ }
}
return 0;
@@ -230,6 +243,7 @@ int rproc_elf64_load_image(struct udevice *dev, ulong addr, ulong size)
memsz = phdr->p_memsz;
filesz = phdr->p_filesz;
offset = phdr->p_offset;
+ bool is_iomem = false;
if (phdr->p_type != PT_LOAD)
continue;
@@ -239,7 +253,7 @@ int rproc_elf64_load_image(struct udevice *dev, ulong addr, ulong size)
ptr = (void *)(uintptr_t)da;
if (ops->device_to_virt) {
- ptr = ops->device_to_virt(dev, da, phdr->p_memsz);
+ ptr = ops->device_to_virt(dev, da, phdr->p_memsz, &is_iomem);
if (!ptr) {
dev_err(dev, "bad da 0x%llx mem 0x%llx\n", da,
memsz);
@@ -248,14 +262,24 @@ int rproc_elf64_load_image(struct udevice *dev, ulong addr, ulong size)
}
}
- if (filesz)
- memcpy(ptr, (void *)addr + offset, filesz);
- if (filesz != memsz)
- memset(ptr + filesz, 0x00, memsz - filesz);
+ if (filesz) {
+ if (is_iomem)
+ memcpy_toio(ptr, (void *)addr + offset, filesz);
+ else
+ memcpy(ptr, (void *)addr + offset, filesz);
+ }
+ if (filesz != memsz) {
+ if (is_iomem)
+ memset_io(ptr + filesz, 0x00, memsz - filesz);
+ else
+ memset(ptr + filesz, 0x00, memsz - filesz);
+ }
- flush_cache(rounddown((ulong)ptr, ARCH_DMA_MINALIGN),
- roundup((ulong)ptr + filesz, ARCH_DMA_MINALIGN) -
- rounddown((ulong)ptr, ARCH_DMA_MINALIGN));
+ if (!is_iomem) {
+ flush_cache(rounddown((ulong)ptr, ARCH_DMA_MINALIGN),
+ roundup((ulong)ptr + filesz, ARCH_DMA_MINALIGN) -
+ rounddown((ulong)ptr, ARCH_DMA_MINALIGN));
+ }
}
return ret;
@@ -381,6 +405,7 @@ int rproc_elf32_load_rsc_table(struct udevice *dev, ulong fw_addr,
Elf32_Shdr *shdr;
void *src, *dst;
ulong dst_addr;
+ bool is_iomem = false;
shdr = rproc_elf32_find_rsc_table(dev, fw_addr, fw_size);
if (!shdr)
@@ -394,18 +419,22 @@ int rproc_elf32_load_rsc_table(struct udevice *dev, ulong fw_addr,
src = (void *)fw_addr + shdr->sh_offset;
if (ops->device_to_virt)
- dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size);
+ dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size, &is_iomem);
else
dst = (void *)rsc_addr;
dev_dbg(dev, "Loading resource table to 0x%8lx (%ld bytes)\n",
(ulong)dst, *rsc_size);
- memcpy(dst, src, *rsc_size);
- dst_addr = map_to_sysmem(dst);
- flush_cache(rounddown(dst_addr, ARCH_DMA_MINALIGN),
- roundup(dst_addr + *rsc_size, ARCH_DMA_MINALIGN) -
- rounddown(dst_addr, ARCH_DMA_MINALIGN));
+ if (is_iomem) {
+ memcpy_toio(dst, src, *rsc_size);
+ } else {
+ memcpy(dst, src, *rsc_size);
+ dst_addr = map_to_sysmem(dst);
+ flush_cache(rounddown(dst_addr, ARCH_DMA_MINALIGN),
+ roundup(dst_addr + *rsc_size, ARCH_DMA_MINALIGN) -
+ rounddown(dst_addr, ARCH_DMA_MINALIGN));
+ }
return 0;
}
@@ -490,6 +519,7 @@ int rproc_elf64_load_rsc_table(struct udevice *dev, ulong fw_addr,
const struct dm_rproc_ops *ops;
Elf64_Shdr *shdr;
void *src, *dst;
+ bool is_iomem = false;
shdr = rproc_elf64_find_rsc_table(dev, fw_addr, fw_size);
if (!shdr)
@@ -503,18 +533,21 @@ int rproc_elf64_load_rsc_table(struct udevice *dev, ulong fw_addr,
src = (void *)fw_addr + shdr->sh_offset;
if (ops->device_to_virt)
- dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size);
+ dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size, &is_iomem);
else
dst = (void *)rsc_addr;
dev_dbg(dev, "Loading resource table to 0x%8lx (%ld bytes)\n",
(ulong)dst, *rsc_size);
- memcpy(dst, src, *rsc_size);
- flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
- roundup((unsigned long)dst + *rsc_size,
- ARCH_DMA_MINALIGN) -
- rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
+ if (is_iomem) {
+ memcpy_toio(dst, src, *rsc_size);
+ } else {
+ memcpy(dst, src, *rsc_size);
+ flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
+ roundup((unsigned long)dst + *rsc_size, ARCH_DMA_MINALIGN) -
+ rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
+ }
return 0;
}
diff --git a/drivers/remoteproc/sandbox_testproc.c b/drivers/remoteproc/sandbox_testproc.c
index ad575a7c10f..7ed38e8656c 100644
--- a/drivers/remoteproc/sandbox_testproc.c
+++ b/drivers/remoteproc/sandbox_testproc.c
@@ -308,10 +308,11 @@ static int sandbox_testproc_ping(struct udevice *dev)
* @dev: device to operate upon
* @da: device address
* @size: Size of the memory region @da is pointing to
+ * @is_iomem: optional pointer filled in to indicate if @da is iomapped memory
* Return: converted virtual address
*/
static void *sandbox_testproc_device_to_virt(struct udevice *dev, ulong da,
- ulong size)
+ ulong size, bool *is_iomem)
{
u64 paddr;
diff --git a/drivers/remoteproc/stm32_copro.c b/drivers/remoteproc/stm32_copro.c
index f45da9a68ac..bf721e78bb3 100644
--- a/drivers/remoteproc/stm32_copro.c
+++ b/drivers/remoteproc/stm32_copro.c
@@ -61,10 +61,11 @@ static int stm32_copro_probe(struct udevice *dev)
* @dev: corresponding STM32 remote processor device
* @da: device address
* @size: Size of the memory region @da is pointing to
+ * @is_iomem: optional pointer filled in to indicate if @da is iomapped memory
* Return: converted virtual address
*/
static void *stm32_copro_device_to_virt(struct udevice *dev, ulong da,
- ulong size)
+ ulong size, bool *is_iomem)
{
fdt32_t in_addr = cpu_to_be32(da), end_addr;
u64 paddr;
diff --git a/drivers/remoteproc/ti_k3_dsp_rproc.c b/drivers/remoteproc/ti_k3_dsp_rproc.c
index 5a7d6377283..9275e1b241d 100644
--- a/drivers/remoteproc/ti_k3_dsp_rproc.c
+++ b/drivers/remoteproc/ti_k3_dsp_rproc.c
@@ -261,7 +261,7 @@ static int k3_dsp_reset(struct udevice *dev)
return 0;
}
-static void *k3_dsp_da_to_va(struct udevice *dev, ulong da, ulong len)
+static void *k3_dsp_da_to_va(struct udevice *dev, ulong da, ulong len, bool *is_iomem)
{
struct k3_dsp_privdata *dsp = dev_get_priv(dev);
phys_addr_t bus_addr, dev_addr;
diff --git a/drivers/remoteproc/ti_k3_m4_rproc.c b/drivers/remoteproc/ti_k3_m4_rproc.c
index 31b9de71579..f358788f07f 100644
--- a/drivers/remoteproc/ti_k3_m4_rproc.c
+++ b/drivers/remoteproc/ti_k3_m4_rproc.c
@@ -181,7 +181,7 @@ static int k3_m4_stop(struct udevice *dev)
return 0;
}
-static void *k3_m4_da_to_va(struct udevice *dev, ulong da, ulong len)
+static void *k3_m4_da_to_va(struct udevice *dev, ulong da, ulong len, bool *is_iomem)
{
struct k3_m4_privdata *m4 = dev_get_priv(dev);
phys_addr_t bus_addr, dev_addr;
diff --git a/drivers/remoteproc/ti_k3_r5f_rproc.c b/drivers/remoteproc/ti_k3_r5f_rproc.c
index 48401bc6eb6..c738607c109 100644
--- a/drivers/remoteproc/ti_k3_r5f_rproc.c
+++ b/drivers/remoteproc/ti_k3_r5f_rproc.c
@@ -534,7 +534,7 @@ proc_release:
return ret;
}
-static void *k3_r5f_da_to_va(struct udevice *dev, ulong da, ulong size)
+static void *k3_r5f_da_to_va(struct udevice *dev, ulong da, ulong size, bool *is_iomem)
{
struct k3_r5f_core *core = dev_get_priv(dev);
void __iomem *va = NULL;
diff --git a/drivers/reset/reset-airoha.c b/drivers/reset/reset-airoha.c
index e878af6167c..ef8c47a067b 100644
--- a/drivers/reset/reset-airoha.c
+++ b/drivers/reset/reset-airoha.c
@@ -10,7 +10,10 @@
#include <dm.h>
#include <linux/io.h>
#include <reset-uclass.h>
+#include <regmap.h>
+#include <asm/arch/scu-regmap.h>
+#include <dt-bindings/reset/airoha,en7523-reset.h>
#include <dt-bindings/reset/airoha,en7581-reset.h>
#define RST_NR_PER_BANK 32
@@ -21,7 +24,8 @@
struct airoha_reset_priv {
const u16 *bank_ofs;
const u16 *idx_map;
- void __iomem *base;
+ int num_rsts;
+ struct regmap *map;
};
static const u16 en7581_rst_ofs[] = {
@@ -29,6 +33,53 @@ static const u16 en7581_rst_ofs[] = {
REG_RESET_CONTROL1,
};
+static const u16 en7523_rst_map[] = {
+ /* RST_CTRL2 */
+ [EN7523_XPON_PHY_RST] = 0,
+ [EN7523_XSI_MAC_RST] = 7,
+ [EN7523_XSI_PHY_RST] = 8,
+ [EN7523_NPU_RST] = 9,
+ [EN7523_I2S_RST] = 10,
+ [EN7523_TRNG_RST] = 11,
+ [EN7523_TRNG_MSTART_RST] = 12,
+ [EN7523_DUAL_HSI0_RST] = 13,
+ [EN7523_DUAL_HSI1_RST] = 14,
+ [EN7523_HSI_RST] = 15,
+ [EN7523_DUAL_HSI0_MAC_RST] = 16,
+ [EN7523_DUAL_HSI1_MAC_RST] = 17,
+ [EN7523_HSI_MAC_RST] = 18,
+ [EN7523_WDMA_RST] = 19,
+ [EN7523_WOE0_RST] = 20,
+ [EN7523_WOE1_RST] = 21,
+ [EN7523_HSDMA_RST] = 22,
+ [EN7523_I2C2RBUS_RST] = 23,
+ [EN7523_TDMA_RST] = 24,
+ /* RST_CTRL1 */
+ [EN7523_PCM1_ZSI_ISI_RST] = RST_NR_PER_BANK + 0,
+ [EN7523_FE_PDMA_RST] = RST_NR_PER_BANK + 1,
+ [EN7523_FE_QDMA_RST] = RST_NR_PER_BANK + 2,
+ [EN7523_PCM_SPIWP_RST] = RST_NR_PER_BANK + 4,
+ [EN7523_CRYPTO_RST] = RST_NR_PER_BANK + 6,
+ [EN7523_TIMER_RST] = RST_NR_PER_BANK + 8,
+ [EN7523_PCM1_RST] = RST_NR_PER_BANK + 11,
+ [EN7523_UART_RST] = RST_NR_PER_BANK + 12,
+ [EN7523_GPIO_RST] = RST_NR_PER_BANK + 13,
+ [EN7523_GDMA_RST] = RST_NR_PER_BANK + 14,
+ [EN7523_I2C_MASTER_RST] = RST_NR_PER_BANK + 16,
+ [EN7523_PCM2_ZSI_ISI_RST] = RST_NR_PER_BANK + 17,
+ [EN7523_SFC_RST] = RST_NR_PER_BANK + 18,
+ [EN7523_UART2_RST] = RST_NR_PER_BANK + 19,
+ [EN7523_GDMP_RST] = RST_NR_PER_BANK + 20,
+ [EN7523_FE_RST] = RST_NR_PER_BANK + 21,
+ [EN7523_USB_HOST_P0_RST] = RST_NR_PER_BANK + 22,
+ [EN7523_GSW_RST] = RST_NR_PER_BANK + 23,
+ [EN7523_SFC2_PCM_RST] = RST_NR_PER_BANK + 25,
+ [EN7523_PCIE0_RST] = RST_NR_PER_BANK + 26,
+ [EN7523_PCIE1_RST] = RST_NR_PER_BANK + 27,
+ [EN7523_PCIE_HB_RST] = RST_NR_PER_BANK + 29,
+ [EN7523_XPON_MAC_RST] = RST_NR_PER_BANK + 31,
+};
+
static const u16 en7581_rst_map[] = {
/* RST_CTRL2 */
[EN7581_XPON_PHY_RST] = 0,
@@ -90,17 +141,11 @@ static const u16 en7581_rst_map[] = {
static int airoha_reset_update(struct airoha_reset_priv *priv,
unsigned long id, bool assert)
{
- void __iomem *addr = priv->base + priv->bank_ofs[id / RST_NR_PER_BANK];
- u32 val;
-
- val = readl(addr);
- if (assert)
- val |= BIT(id % RST_NR_PER_BANK);
- else
- val &= ~BIT(id % RST_NR_PER_BANK);
- writel(val, addr);
+ u16 offset = priv->bank_ofs[id / RST_NR_PER_BANK];
- return 0;
+ return regmap_update_bits(priv->map, offset,
+ BIT(id % RST_NR_PER_BANK),
+ assert ? BIT(id % RST_NR_PER_BANK) : 0);
}
static int airoha_reset_assert(struct reset_ctl *reset_ctl)
@@ -123,11 +168,16 @@ static int airoha_reset_status(struct reset_ctl *reset_ctl)
{
struct airoha_reset_priv *priv = dev_get_priv(reset_ctl->dev);
int id = reset_ctl->id;
- void __iomem *addr;
+ u16 offset;
+ u32 val;
+ int ret;
- addr = priv->base + priv->bank_ofs[id / RST_NR_PER_BANK];
+ offset = priv->bank_ofs[id / RST_NR_PER_BANK];
+ ret = regmap_read(priv->map, offset, &val);
+ if (ret)
+ return ret;
- return !!(readl(addr) & BIT(id % RST_NR_PER_BANK));
+ return !!(val & BIT(id % RST_NR_PER_BANK));
}
static int airoha_reset_xlate(struct reset_ctl *reset_ctl,
@@ -135,7 +185,7 @@ static int airoha_reset_xlate(struct reset_ctl *reset_ctl,
{
struct airoha_reset_priv *priv = dev_get_priv(reset_ctl->dev);
- if (args->args[0] >= ARRAY_SIZE(en7581_rst_map))
+ if (args->args[0] >= priv->num_rsts)
return -EINVAL;
reset_ctl->id = priv->idx_map[args->args[0]];
@@ -150,20 +200,36 @@ static struct reset_ops airoha_reset_ops = {
.rst_status = airoha_reset_status,
};
-static int airoha_reset_probe(struct udevice *dev)
+static int reset_init(struct udevice *dev, const u16 *rst_map, int num_rsts)
{
struct airoha_reset_priv *priv = dev_get_priv(dev);
- priv->base = dev_remap_addr(dev);
- if (!priv->base)
- return -ENOMEM;
+ priv->map = airoha_get_scu_regmap();
+ if (IS_ERR(priv->map))
+ return PTR_ERR(priv->map);
priv->bank_ofs = en7581_rst_ofs;
- priv->idx_map = en7581_rst_map;
+ priv->idx_map = rst_map;
+ priv->num_rsts = num_rsts;
return 0;
}
+static int airoha_reset_probe(struct udevice *dev)
+{
+ if (ofnode_device_is_compatible(dev_ofnode(dev),
+ "airoha,en7523-scu"))
+ return reset_init(dev, en7523_rst_map,
+ ARRAY_SIZE(en7523_rst_map));
+
+ if (ofnode_device_is_compatible(dev_ofnode(dev),
+ "airoha,en7581-scu"))
+ return reset_init(dev, en7581_rst_map,
+ ARRAY_SIZE(en7581_rst_map));
+
+ return -ENODEV;
+}
+
U_BOOT_DRIVER(airoha_reset) = {
.name = "airoha-reset",
.id = UCLASS_RESET,
diff --git a/drivers/reset/reset-zynqmp.c b/drivers/reset/reset-zynqmp.c
index b9c4f09fdfd..d04e8eef3bb 100644
--- a/drivers/reset/reset-zynqmp.c
+++ b/drivers/reset/reset-zynqmp.c
@@ -22,7 +22,7 @@ static int zynqmp_pm_reset_assert(const u32 reset,
const enum zynqmp_pm_reset_action assert_flag)
{
return xilinx_pm_request(PM_RESET_ASSERT, reset, assert_flag, 0, 0,
- NULL);
+ 0, 0, NULL);
}
static int zynqmp_reset_assert(struct reset_ctl *rst)
diff --git a/drivers/rng/Kconfig b/drivers/rng/Kconfig
index b35d8c66b9c..19b2b707677 100644
--- a/drivers/rng/Kconfig
+++ b/drivers/rng/Kconfig
@@ -40,7 +40,7 @@ config RNG_MSM
config RNG_NPCM
bool "Nuvoton NPCM SoCs Random Number Generator support"
- depends on DM_RNG
+ depends on DM_RNG && !LIB_RAND
help
Enable random number generator on NPCM SoCs.
This unit can provide 750 to 1000 random bits per second
@@ -122,7 +122,7 @@ config RNG_TURRIS_RWTM
config RNG_EXYNOS
bool "Samsung Exynos True Random Number Generator support"
- depends on DM_RNG
+ depends on DM_RNG && ARM
help
Enable support for True Random Number Generator (TRNG) available on
Exynos SoCs.
diff --git a/drivers/rtc/ds1672.c b/drivers/rtc/ds1672.c
index 4705e5abc93..651b1dc950f 100644
--- a/drivers/rtc/ds1672.c
+++ b/drivers/rtc/ds1672.c
@@ -108,7 +108,7 @@ static const struct udevice_id ds1672_of_id[] = {
{ }
};
-U_BOOT_DRIVER(rtc_max313xx) = {
+U_BOOT_DRIVER(rtc_ds1672) = {
.name = "rtc-ds1672",
.id = UCLASS_RTC,
.probe = ds1672_probe,
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 05608399be1..b414d022f3f 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -584,7 +584,7 @@ static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose)
struct udevice *bdev;
struct blk_desc bd;
struct blk_desc *bdesc;
- char str[10], *name;
+ char str[10];
/*
* detect the scsi driver to get information about its geometry (block
@@ -600,10 +600,7 @@ static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose)
* block devices created
*/
snprintf(str, sizeof(str), "id%dlun%d", id, lun);
- name = strdup(str);
- if (!name)
- return log_msg_ret("nam", -ENOMEM);
- ret = blk_create_devicef(dev, "scsi_blk", name, UCLASS_SCSI, -1,
+ ret = blk_create_devicef(dev, "scsi_blk", str, UCLASS_SCSI, -1,
bd.blksz, bd.lba, &bdev);
if (ret) {
debug("Can't create device\n");
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index bc05d2f1508..371d7aa5bba 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -194,7 +194,7 @@ config TPL_DM_SERIAL
config VPL_DM_SERIAL
bool "Enable Driver Model for serial drivers in VPL"
- depends on DM_SERIAL
+ depends on DM_SERIAL && VPL_DM
default y if VPL && DM_SERIAL
help
Enable driver model for serial in VPL. This replaces
@@ -328,7 +328,7 @@ config DEBUG_UART_MSM
be available until the real driver-model serial is running.
config DEBUG_UART_MSM_GENI
- bool "Qualcomm snapdragon"
+ bool "Qualcomm GENI UART debug"
depends on ARCH_SNAPDRAGON
help
Select this to enable a debug UART using the serial_msm driver. You
@@ -1001,6 +1001,7 @@ config MSM_SERIAL
config MSM_GENI_SERIAL
bool "Qualcomm on-chip GENI UART"
+ depends on QCOM_GENI
help
Support UART based on Generic Interface (GENI) Serial Engine (SE),
used on Qualcomm Snapdragon SoCs. Should support all qualcomm SOCs
diff --git a/drivers/serial/serial_msm.c b/drivers/serial/serial_msm.c
index 757e5eaf974..18d15b7b15b 100644
--- a/drivers/serial/serial_msm.c
+++ b/drivers/serial/serial_msm.c
@@ -17,20 +17,17 @@
#include <asm/global_data.h>
#include <asm/io.h>
#include <linux/compiler.h>
-#include <linux/delay.h>
#include <dm/pinctrl.h>
/* Serial registers - this driver works in uartdm mode*/
-#define UARTDM_DMRX 0x34 /* Max RX transfer length */
-#define UARTDM_DMEN 0x3C /* DMA/data-packing mode */
-#define UARTDM_NCF_TX 0x40 /* Number of chars to TX */
+#define UARTDM_DMEN 0x3C /* DMA/data-packing mode */
+#define UARTDM_DMEN_TXRX_SC_ENABLE (BIT(4) | BIT(5))
-#define UARTDM_RXFS 0x50 /* RX channel status register */
-#define UARTDM_RXFS_BUF_SHIFT 0x7 /* Number of bytes in the packing buffer */
-#define UARTDM_RXFS_BUF_MASK 0x7
#define UARTDM_MR1 0x00
+#define UARTDM_MR1_RX_RDY_CTL BIT(7)
#define UARTDM_MR2 0x04
+#define UARTDM_MR2_8_N_1_MODE 0x34
/*
* This is documented on page 1817 of the apq8016e technical reference manual.
* section 6.2.5.3.26
@@ -44,119 +41,56 @@
#define UARTDM_CSR 0xA0
#define UARTDM_SR 0xA4 /* Status register */
-#define UARTDM_SR_RX_READY (1 << 0) /* Word is the receiver FIFO */
+#define UARTDM_SR_RX_READY (1 << 0) /* Receiver FIFO has data */
+#define UARTDM_SR_TX_READY (1 << 2) /* Transmitter FIFO has space */
#define UARTDM_SR_TX_EMPTY (1 << 3) /* Transmitter underrun */
-#define UARTDM_SR_UART_OVERRUN (1 << 4) /* Receive overrun */
#define UARTDM_CR 0xA8 /* Command register */
-#define UARTDM_CR_CMD_RESET_ERR (3 << 4) /* Clear overrun error */
-#define UARTDM_CR_CMD_RESET_STALE_INT (8 << 4) /* Clears stale irq */
-#define UARTDM_CR_CMD_RESET_TX_READY (3 << 8) /* Clears TX Ready irq*/
-#define UARTDM_CR_CMD_FORCE_STALE (4 << 8) /* Causes stale event */
-#define UARTDM_CR_CMD_STALE_EVENT_DISABLE (6 << 8) /* Disable stale event */
-
-#define UARTDM_IMR 0xB0 /* Interrupt mask register */
-#define UARTDM_ISR 0xB4 /* Interrupt status register */
-#define UARTDM_ISR_TX_READY 0x80 /* TX FIFO empty */
+#define UARTDM_CR_RX_ENABLE (1 << 0) /* Enable receiver */
+#define UARTDM_CR_TX_ENABLE (1 << 2) /* Enable transmitter */
+#define UARTDM_CR_CMD_RESET_RX (1 << 4) /* Reset receiver */
+#define UARTDM_CR_CMD_RESET_TX (2 << 4) /* Reset transmitter */
#define UARTDM_TF 0x100 /* UART Transmit FIFO register */
#define UARTDM_RF 0x140 /* UART Receive FIFO register */
-
-#define MSM_BOOT_UART_DM_8_N_1_MODE 0x34
-#define MSM_BOOT_UART_DM_CMD_RESET_RX 0x10
-#define MSM_BOOT_UART_DM_CMD_RESET_TX 0x20
-#define MSM_UART_MR1_RX_RDY_CTL BIT(7)
+#define UARTDM_RF_CHAR 0xff /* higher bits contain error information */
DECLARE_GLOBAL_DATA_PTR;
struct msm_serial_data {
phys_addr_t base;
- unsigned chars_cnt; /* number of buffered chars */
- uint32_t chars_buf; /* buffered chars */
uint32_t clk_rate; /* core clock rate */
};
-static int msm_serial_fetch(struct udevice *dev)
-{
- struct msm_serial_data *priv = dev_get_priv(dev);
- unsigned sr;
-
- if (priv->chars_cnt)
- return priv->chars_cnt;
-
- /* Clear error in case of buffer overrun */
- if (readl(priv->base + UARTDM_SR) & UARTDM_SR_UART_OVERRUN)
- writel(UARTDM_CR_CMD_RESET_ERR, priv->base + UARTDM_CR);
-
- /* We need to fetch new character */
- sr = readl(priv->base + UARTDM_SR);
-
- if (sr & UARTDM_SR_RX_READY) {
- /* There are at least 4 bytes in fifo */
- priv->chars_buf = readl(priv->base + UARTDM_RF);
- priv->chars_cnt = 4;
- } else {
- /* Check if there is anything in fifo */
- priv->chars_cnt = readl(priv->base + UARTDM_RXFS);
- /* Extract number of characters in UART packing buffer*/
- priv->chars_cnt = (priv->chars_cnt >>
- UARTDM_RXFS_BUF_SHIFT) &
- UARTDM_RXFS_BUF_MASK;
- if (!priv->chars_cnt)
- return 0;
-
- /* There is at least one charcter, move it to fifo */
- writel(UARTDM_CR_CMD_FORCE_STALE,
- priv->base + UARTDM_CR);
-
- priv->chars_buf = readl(priv->base + UARTDM_RF);
- writel(UARTDM_CR_CMD_RESET_STALE_INT,
- priv->base + UARTDM_CR);
- writel(0x7, priv->base + UARTDM_DMRX);
- }
-
- return priv->chars_cnt;
-}
-
static int msm_serial_getc(struct udevice *dev)
{
struct msm_serial_data *priv = dev_get_priv(dev);
- char c;
- if (!msm_serial_fetch(dev))
+ if (!(readl(priv->base + UARTDM_SR) & UARTDM_SR_RX_READY))
return -EAGAIN;
- c = priv->chars_buf & 0xFF;
- priv->chars_buf >>= 8;
- priv->chars_cnt--;
-
- return c;
+ return readl(priv->base + UARTDM_RF) & UARTDM_RF_CHAR;
}
static int msm_serial_putc(struct udevice *dev, const char ch)
{
struct msm_serial_data *priv = dev_get_priv(dev);
- if (!(readl(priv->base + UARTDM_SR) & UARTDM_SR_TX_EMPTY) &&
- !(readl(priv->base + UARTDM_ISR) & UARTDM_ISR_TX_READY))
+ if (!(readl(priv->base + UARTDM_SR) & UARTDM_SR_TX_READY))
return -EAGAIN;
- writel(UARTDM_CR_CMD_RESET_TX_READY, priv->base + UARTDM_CR);
-
- writel(1, priv->base + UARTDM_NCF_TX);
writel(ch, priv->base + UARTDM_TF);
-
return 0;
}
static int msm_serial_pending(struct udevice *dev, bool input)
{
- if (input) {
- if (msm_serial_fetch(dev))
- return 1;
- }
+ struct msm_serial_data *priv = dev_get_priv(dev);
- return 0;
+ if (input)
+ return !!(readl(priv->base + UARTDM_SR) & UARTDM_SR_RX_READY);
+ else
+ return !(readl(priv->base + UARTDM_SR) & UARTDM_SR_TX_EMPTY);
}
static const struct dm_serial_ops msm_serial_ops = {
@@ -207,8 +141,6 @@ static int calc_csr_bitrate(struct msm_serial_data *priv)
static void uart_dm_init(struct msm_serial_data *priv)
{
- /* Delay initialization for a bit to let pins stabilize if necessary */
- mdelay(5);
int bitrate = calc_csr_bitrate(priv);
if (bitrate < 0) {
log_warning("Couldn't calculate bit clock divider! Using default\n");
@@ -221,13 +153,16 @@ static void uart_dm_init(struct msm_serial_data *priv)
writel(bitrate, priv->base + UARTDM_CSR);
/* Enable RS232 flow control to support RS232 db9 connector */
- writel(MSM_UART_MR1_RX_RDY_CTL, priv->base + UARTDM_MR1);
- writel(MSM_BOOT_UART_DM_8_N_1_MODE, priv->base + UARTDM_MR2);
- writel(MSM_BOOT_UART_DM_CMD_RESET_RX, priv->base + UARTDM_CR);
- writel(MSM_BOOT_UART_DM_CMD_RESET_TX, priv->base + UARTDM_CR);
+ writel(UARTDM_MR1_RX_RDY_CTL, priv->base + UARTDM_MR1);
+ writel(UARTDM_MR2_8_N_1_MODE, priv->base + UARTDM_MR2);
- /* Make sure BAM/single character mode is disabled */
- writel(0x0, priv->base + UARTDM_DMEN);
+ /* Enable single character mode */
+ writel(UARTDM_DMEN_TXRX_SC_ENABLE, priv->base + UARTDM_DMEN);
+
+ writel(UARTDM_CR_CMD_RESET_RX, priv->base + UARTDM_CR);
+ writel(UARTDM_CR_CMD_RESET_TX, priv->base + UARTDM_CR);
+ writel(UARTDM_CR_RX_ENABLE, priv->base + UARTDM_CR);
+ writel(UARTDM_CR_TX_ENABLE, priv->base + UARTDM_CR);
}
static int msm_serial_probe(struct udevice *dev)
{
@@ -319,13 +254,9 @@ static inline void _debug_uart_putc(int ch)
{
struct msm_serial_data *priv = &init_serial_data;
- while (!(readl(priv->base + UARTDM_SR) & UARTDM_SR_TX_EMPTY) &&
- !(readl(priv->base + UARTDM_ISR) & UARTDM_ISR_TX_READY))
+ while (!(readl(priv->base + UARTDM_SR) & UARTDM_SR_TX_READY))
;
- writel(UARTDM_CR_CMD_RESET_TX_READY, priv->base + UARTDM_CR);
-
- writel(1, priv->base + UARTDM_NCF_TX);
writel(ch, priv->base + UARTDM_TF);
}
diff --git a/drivers/serial/serial_msm_geni.c b/drivers/serial/serial_msm_geni.c
index 0eb90f82a34..bb5a2cb4d2c 100644
--- a/drivers/serial/serial_msm_geni.c
+++ b/drivers/serial/serial_msm_geni.c
@@ -10,11 +10,14 @@
#include <asm/io.h>
#include <clk.h>
#include <dm.h>
+#include <dm/device_compat.h>
#include <errno.h>
#include <linux/delay.h>
#include <linux/time.h>
#include <misc.h>
#include <serial.h>
+#include <soc/qcom/qup-fw-load.h>
+#include <soc/qcom/geni-se.h>
#define UART_OVERSAMPLING 32
#define STALE_TIMEOUT 160
@@ -22,8 +25,6 @@
/* Registers*/
#define GENI_FORCE_DEFAULT_REG 0x20
#define GENI_SER_M_CLK_CFG 0x48
-#define GENI_SER_S_CLK_CFG 0x4C
-#define SE_HW_PARAM_0 0xE24
#define SE_GENI_STATUS 0x40
#define SE_GENI_S_CMD0 0x630
#define SE_GENI_S_CMD_CTRL_REG 0x634
@@ -39,7 +40,6 @@
#define SE_GENI_RX_FIFOn 0x780
#define SE_GENI_TX_FIFO_STATUS 0x800
#define SE_GENI_RX_FIFO_STATUS 0x804
-#define SE_GENI_TX_WATERMARK_REG 0x80C
#define SE_GENI_TX_PACKING_CFG0 0x260
#define SE_GENI_TX_PACKING_CFG1 0x264
#define SE_GENI_RX_PACKING_CFG0 0x284
@@ -54,59 +54,24 @@
#define SE_UART_RX_TRANS_CFG 0x280
#define SE_UART_RX_PARITY_CFG 0x2a8
-#define M_TX_FIFO_WATERMARK_EN (BIT(30))
#define DEF_TX_WM 2
/* GENI_FORCE_DEFAULT_REG fields */
-#define FORCE_DEFAULT (BIT(0))
-
-#define S_CMD_ABORT_EN (BIT(5))
#define UART_START_READ 0x1
-/* GENI_M_CMD_CTRL_REG */
-#define M_GENI_CMD_CANCEL (BIT(2))
-#define M_GENI_CMD_ABORT (BIT(1))
-#define M_GENI_DISABLE (BIT(0))
-
-#define M_CMD_ABORT_EN (BIT(5))
-#define M_CMD_DONE_EN (BIT(0))
#define M_CMD_DONE_DISABLE_MASK (~M_CMD_DONE_EN)
-#define S_GENI_CMD_ABORT (BIT(1))
-
-/* GENI_S_CMD0 fields */
-#define S_OPCODE_MSK (GENMASK(31, 27))
-#define S_PARAMS_MSK (GENMASK(26, 0))
-
-/* GENI_STATUS fields */
-#define M_GENI_CMD_ACTIVE (BIT(0))
-#define S_GENI_CMD_ACTIVE (BIT(12))
-#define M_CMD_DONE_EN (BIT(0))
-#define S_CMD_DONE_EN (BIT(0))
-
#define M_OPCODE_SHIFT 27
#define S_OPCODE_SHIFT 27
-#define M_TX_FIFO_WATERMARK_EN (BIT(30))
#define UART_START_TX 0x1
#define UART_CTS_MASK (BIT(1))
-#define M_SEC_IRQ_EN (BIT(31))
#define TX_FIFO_WC_MSK (GENMASK(27, 0))
-#define RX_FIFO_WC_MSK (GENMASK(24, 0))
-
-#define S_RX_FIFO_WATERMARK_EN (BIT(26))
-#define S_RX_FIFO_LAST_EN (BIT(27))
-#define M_RX_FIFO_WATERMARK_EN (BIT(26))
-#define M_RX_FIFO_LAST_EN (BIT(27))
/* GENI_SER_M_CLK_CFG/GENI_SER_S_CLK_CFG */
-#define SER_CLK_EN (BIT(0))
-#define CLK_DIV_MSK (GENMASK(15, 4))
#define CLK_DIV_SHFT 4
/* SE_HW_PARAM_0 fields */
-#define TX_FIFO_WIDTH_MSK (GENMASK(29, 24))
#define TX_FIFO_WIDTH_SHFT 24
-#define TX_FIFO_DEPTH_MSK (GENMASK(21, 16))
#define TX_FIFO_DEPTH_SHFT 16
/* GENI SE QUP Registers */
@@ -131,6 +96,7 @@ struct msm_serial_data {
phys_addr_t base;
u32 baud;
u32 oversampling;
+ struct clk *se;
};
unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200,
@@ -181,19 +147,6 @@ static int get_clk_div_rate(u32 baud, u64 sampling_rate, u32 *clk_div)
return ser_clk;
}
-static int geni_serial_set_clock_rate(struct udevice *dev, u64 rate)
-{
- struct clk *clk;
- int ret;
-
- clk = devm_clk_get(dev, NULL);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
-
- ret = clk_set_rate(clk, rate);
- return ret;
-}
-
/**
* geni_se_get_tx_fifo_depth() - Get the TX fifo depth of the serial engine
* @base: Pointer to the concerned serial engine.
@@ -256,7 +209,7 @@ static int msm_serial_setbrg(struct udevice *dev, int baud)
pr_err("%s: Couldn't get clock division rate\n", __func__);
return -EINVAL;
}
- ret = geni_serial_set_clock_rate(dev, clk_rate);
+ ret = clk_set_rate(priv->se, clk_rate);
if (ret < 0) {
pr_err("%s: Couldn't set clock rate: %d\n", __func__, ret);
return ret;
@@ -561,6 +514,42 @@ static int msm_serial_probe(struct udevice *dev)
{
struct msm_serial_data *priv = dev_get_priv(dev);
int ret;
+ u32 proto;
+ struct clk *clk;
+
+ clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ priv->se = clk;
+
+ /* Try enable clock */
+ ret = clk_enable(clk);
+
+ /* Check if firmware loading is needed (BT UART) */
+ proto = readl(priv->base + GENI_FW_REVISION_RO);
+ proto &= FW_REV_PROTOCOL_MSK;
+ proto >>= FW_REV_PROTOCOL_SHFT;
+
+ if (proto == GENI_SE_INVALID_PROTO) {
+ qcom_geni_load_firmware(priv->base, dev);
+ proto = readl(priv->base + GENI_FW_REVISION_RO);
+ proto &= FW_REV_PROTOCOL_MSK;
+ proto >>= FW_REV_PROTOCOL_SHFT;
+ }
+
+ if (proto != GENI_SE_UART) {
+ dev_err(dev, "Invalid proto %d\n", proto);
+ clk_disable(clk);
+ return -ENXIO;
+ }
+
+ /* Don't actually probe non-debug UARTs */
+ if (ofnode_device_is_compatible(dev_ofnode(dev), "qcom,geni-uart"))
+ return -ENOENT;
+
+ /* Now handle clock enable return value */
+ if (ret)
+ return ret;
ret = geni_set_oversampling(dev);
if (ret < 0)
@@ -591,6 +580,7 @@ static int msm_serial_ofdata_to_platdata(struct udevice *dev)
static const struct udevice_id msm_serial_ids[] = {
{ .compatible = "qcom,geni-debug-uart" },
+ { .compatible = "qcom,geni-uart" },
{ }
};
@@ -605,19 +595,6 @@ U_BOOT_DRIVER(serial_msm_geni) = {
.flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF,
};
-static const struct udevice_id geniqup_ids[] = {
- { .compatible = "qcom,geni-se-qup" },
- { }
-};
-
-U_BOOT_DRIVER(geni_se_qup) = {
- .name = "geni-se-qup",
- .id = UCLASS_NOP,
- .of_match = geniqup_ids,
- .bind = dm_scan_fdt_dev,
- .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF,
-};
-
#ifdef CONFIG_DEBUG_UART_MSM_GENI
static struct msm_serial_data init_serial_data = {
diff --git a/drivers/serial/serial_sh.c b/drivers/serial/serial_sh.c
index e4cc4ee4260..7ab62e0e90b 100644
--- a/drivers/serial/serial_sh.c
+++ b/drivers/serial/serial_sh.c
@@ -112,7 +112,16 @@ static int serial_raw_putc(struct uart_port *port, const char c)
static int serial_rx_fifo_level(struct uart_port *port)
{
- return scif_rxfill(port);
+ int ret;
+
+ ret = scif_rxfill(port);
+ if (ret)
+ return ret;
+
+ if (sci_in(port, SCxSR) & SCxSR_RDxF(port))
+ return 1;
+
+ return 0;
}
static int sh_serial_tstc_generic(struct uart_port *port)
diff --git a/drivers/soc/soc_amd_versal2.c b/drivers/soc/soc_amd_versal2.c
index 8507da0bd22..7f06c1e70bc 100644
--- a/drivers/soc/soc_amd_versal2.c
+++ b/drivers/soc/soc_amd_versal2.c
@@ -55,7 +55,7 @@ static int soc_amd_versal2_probe(struct udevice *dev)
if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) {
ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0,
- ret_payload);
+ 0, 0, ret_payload);
if (ret)
return ret;
} else {
diff --git a/drivers/soc/soc_xilinx_versal.c b/drivers/soc/soc_xilinx_versal.c
index 7427f8432c8..c43a80df1fc 100644
--- a/drivers/soc/soc_xilinx_versal.c
+++ b/drivers/soc/soc_xilinx_versal.c
@@ -51,7 +51,7 @@ static int soc_xilinx_versal_probe(struct udevice *dev)
if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) {
ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0,
- ret_payload);
+ 0, 0, ret_payload);
if (ret)
return ret;
} else {
diff --git a/drivers/soc/soc_xilinx_versal_net.c b/drivers/soc/soc_xilinx_versal_net.c
index d64fc366a6d..210f9f8f8fd 100644
--- a/drivers/soc/soc_xilinx_versal_net.c
+++ b/drivers/soc/soc_xilinx_versal_net.c
@@ -53,7 +53,7 @@ static int soc_xilinx_versal_net_probe(struct udevice *dev)
if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) {
ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0,
- ret_payload);
+ 0, 0, ret_payload);
if (ret)
return ret;
} else {
diff --git a/drivers/soc/soc_xilinx_zynqmp.c b/drivers/soc/soc_xilinx_zynqmp.c
index 4b69ff3de13..b97cd443c60 100644
--- a/drivers/soc/soc_xilinx_zynqmp.c
+++ b/drivers/soc/soc_xilinx_zynqmp.c
@@ -362,7 +362,7 @@ static int soc_xilinx_zynqmp_probe(struct udevice *dev)
ret = zynqmp_mmio_read(ZYNQMP_PS_VERSION, &ret_payload[2]);
else
ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0,
- ret_payload);
+ 0, 0, ret_payload);
if (ret < 0)
return ret;
diff --git a/drivers/sound/Kconfig b/drivers/sound/Kconfig
index 81de9b30f39..afcc08c27bc 100644
--- a/drivers/sound/Kconfig
+++ b/drivers/sound/Kconfig
@@ -12,9 +12,10 @@ config SOUND
audio codecs are called from the sound-i2s code. This could be
converted to driver model.
+if SOUND
+
config I2S
bool "Enable I2S support"
- depends on SOUND
help
I2S is a serial bus often used to transmit audio data from the
SoC to the audio codec. This option enables sound support using
@@ -42,7 +43,6 @@ config I2S_SAMSUNG
config SOUND_DA7219
bool "Dialog Semiconductor audio codec"
- depends on SOUND
help
The DA7219 is an ultra-low-power audio codec with Advanced Accessory
Detection (AAD). This driver only supports generation of ACPI tables.
@@ -51,7 +51,7 @@ config SOUND_DA7219
config SOUND_I8254
bool "Intel i8254 timer / beeper"
- depends on SOUND && X86
+ depends on X86
help
This enables support for a beeper that uses the i8254 timer chip.
This can emit beeps at a fixed frequency. It is possible to control
@@ -63,7 +63,6 @@ config SOUND_I8254
config SOUND_INTEL_HDA
bool "Intel HDA audio codec"
- depends on SOUND
help
Most Intel chips have an HDA (High-definition audio) codec which can
be used by U-Boot to play simple beeps. This is also sometimes called
@@ -72,7 +71,6 @@ config SOUND_INTEL_HDA
config SOUND_IVYBRIDGE
bool "Intel Ivybridge sound support"
- depends on SOUND
select SOUND_INTEL_HDA
help
Enable sound output on supported Intel Ivybridge-based boards. This
@@ -148,4 +146,6 @@ config SOUND_WM8994
audio data and I2C for codec control. At present it only works
with the Samsung I2S driver.
+endif
+
endmenu
diff --git a/drivers/sound/maxim_codec.c b/drivers/sound/maxim_codec.c
index 505a739ad7d..a3750e18f7d 100644
--- a/drivers/sound/maxim_codec.c
+++ b/drivers/sound/maxim_codec.c
@@ -18,8 +18,8 @@
* Writes value to a device register through i2c
*
* @param priv Private data for driver
- * @param reg reg number to be write
- * @param data data to be writen to the above registor
+ * @param reg reg number to be written
+ * @param data data to be written to the above registor
*
* Return: int value 1 for change, 0 for no change or negative error code.
*/
diff --git a/drivers/sound/maxim_codec.h b/drivers/sound/maxim_codec.h
index deaefd93eb1..23f8341e59c 100644
--- a/drivers/sound/maxim_codec.h
+++ b/drivers/sound/maxim_codec.h
@@ -31,8 +31,8 @@ struct maxim_priv {
* Writes value to a device register through i2c
*
* @param priv Private data for driver
- * @param reg reg number to be write
- * @param data data to be writen to the above registor
+ * @param reg reg number to be written
+ * @param data data to be written to the above registor
*
* Return: int value 1 for change, 0 for no change or negative error code.
*/
diff --git a/drivers/sound/wm8994.c b/drivers/sound/wm8994.c
index 42947357836..ae27947d43f 100644
--- a/drivers/sound/wm8994.c
+++ b/drivers/sound/wm8994.c
@@ -67,8 +67,8 @@ static int bclk_divs[] = {
* Writes value to a device register through i2c
*
* @param priv Private data for driver
- * @param reg reg number to be write
- * @param data data to be writen to the above registor
+ * @param reg reg number to be written
+ * @param data data to be written to the above registor
*
* Return: int value 1 for change, 0 for no change or negative error code.
*/
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 2960822211a..c88918606d2 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -452,6 +452,7 @@ config ROCKCHIP_SFC
config ROCKCHIP_SPI
bool "Rockchip SPI driver"
+ depends on ARCH_ROCKCHIP
help
Enable the Rockchip SPI driver, used to access SPI NOR flash and
other SPI peripherals (such as the Chrome OS EC) on Rockchip SoCs.
@@ -495,7 +496,7 @@ config SANDBOX_SPI_MAX_CS
config SPI_ASPEED_SMC
bool "ASPEED SPI flash controller driver"
- depends on DM_SPI && SPI_MEM
+ depends on DM_SPI && SPI_MEM && ARCH_ASPEED
help
Enable ASPEED SPI flash controller driver for AST2500
and AST2600 SoCs.
@@ -622,6 +623,7 @@ config ZYNQ_SPI
config ZYNQ_QSPI
bool "Zynq QSPI driver"
+ depends on ARCH_VERSAL || ARCH_VERSAL_NET || ARCH_VERSAL2 || ARCH_ZYNQ || ARCH_ZYNQMP
imply SPI_FLASH_BAR
help
Enable the Zynq Quad-SPI (QSPI) driver. This driver can be
@@ -631,6 +633,7 @@ config ZYNQ_QSPI
config ZYNQMP_GQSPI
bool "Configure ZynqMP Generic QSPI"
+ depends on ARCH_VERSAL || ARCH_VERSAL_NET || ARCH_VERSAL2 || ARCH_ZYNQ || ARCH_ZYNQMP
help
This option is used to enable ZynqMP QSPI controller driver which
is used to communicate with qspi flash devices.
diff --git a/drivers/spi/airoha_snfi_spi.c b/drivers/spi/airoha_snfi_spi.c
index 3ea25b293d1..769ec956793 100644
--- a/drivers/spi/airoha_snfi_spi.c
+++ b/drivers/spi/airoha_snfi_spi.c
@@ -141,12 +141,15 @@
#define SPI_NFI_CUS_SEC_SIZE_EN BIT(16)
#define REG_SPI_NFI_RD_CTL2 0x0510
+#define SPI_NFI_DATA_READ_CMD GENMASK(7, 0)
+
#define REG_SPI_NFI_RD_CTL3 0x0514
#define REG_SPI_NFI_PG_CTL1 0x0524
#define SPI_NFI_PG_LOAD_CMD GENMASK(15, 8)
#define REG_SPI_NFI_PG_CTL2 0x0528
+
#define REG_SPI_NFI_NOR_PROG_ADDR 0x052c
#define REG_SPI_NFI_NOR_RD_ADDR 0x0534
@@ -173,7 +176,9 @@
#define SPI_NAND_OP_READ_FROM_CACHE_SINGLE 0x03
#define SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST 0x0b
#define SPI_NAND_OP_READ_FROM_CACHE_DUAL 0x3b
+#define SPI_NAND_OP_READ_FROM_CACHE_DUALIO 0xbb
#define SPI_NAND_OP_READ_FROM_CACHE_QUAD 0x6b
+#define SPI_NAND_OP_READ_FROM_CACHE_QUADIO 0xeb
#define SPI_NAND_OP_WRITE_ENABLE 0x06
#define SPI_NAND_OP_WRITE_DISABLE 0x04
#define SPI_NAND_OP_PROGRAM_LOAD_SINGLE 0x02
@@ -186,6 +191,14 @@
#define SPI_NAND_OP_RESET 0xff
#define SPI_NAND_OP_DIE_SELECT 0xc2
+/* SNAND FIFO commands */
+#define SNAND_FIFO_TX_BUSWIDTH_SINGLE 0x08
+#define SNAND_FIFO_TX_BUSWIDTH_DUAL 0x09
+#define SNAND_FIFO_TX_BUSWIDTH_QUAD 0x0a
+#define SNAND_FIFO_RX_BUSWIDTH_SINGLE 0x0c
+#define SNAND_FIFO_RX_BUSWIDTH_DUAL 0x0e
+#define SNAND_FIFO_RX_BUSWIDTH_QUAD 0x0f
+
#define SPI_NAND_CACHE_SIZE (SZ_4K + SZ_256)
#define SPI_MAX_TRANSFER_SIZE 511
@@ -205,12 +218,8 @@ struct airoha_snand_priv {
struct regmap *regmap_nfi;
struct clk *spi_clk;
- struct {
- size_t page_size;
- size_t sec_size;
- u8 sec_num;
- u8 spare_size;
- } nfi_cfg;
+ u8 *txrx_buf;
+ int dma;
};
static int airoha_snand_set_fifo_op(struct airoha_snand_priv *priv,
@@ -380,10 +389,26 @@ static int airoha_snand_set_mode(struct airoha_snand_priv *priv,
return regmap_write(priv->regmap_ctrl, REG_SPI_CTRL_DUMMY, 0);
}
-static int airoha_snand_write_data(struct airoha_snand_priv *priv, u8 cmd,
- const u8 *data, int len)
+static int airoha_snand_write_data(struct airoha_snand_priv *priv,
+ const u8 *data, int len, int buswidth)
{
int i, data_len;
+ u8 cmd;
+
+ switch (buswidth) {
+ case 0:
+ case 1:
+ cmd = SNAND_FIFO_TX_BUSWIDTH_SINGLE;
+ break;
+ case 2:
+ cmd = SNAND_FIFO_TX_BUSWIDTH_DUAL;
+ break;
+ case 4:
+ cmd = SNAND_FIFO_TX_BUSWIDTH_QUAD;
+ break;
+ default:
+ return -EINVAL;
+ }
for (i = 0; i < len; i += data_len) {
int err;
@@ -402,16 +427,32 @@ static int airoha_snand_write_data(struct airoha_snand_priv *priv, u8 cmd,
return 0;
}
-static int airoha_snand_read_data(struct airoha_snand_priv *priv, u8 *data,
- int len)
+static int airoha_snand_read_data(struct airoha_snand_priv *priv,
+ u8 *data, int len, int buswidth)
{
int i, data_len;
+ u8 cmd;
+
+ switch (buswidth) {
+ case 0:
+ case 1:
+ cmd = SNAND_FIFO_RX_BUSWIDTH_SINGLE;
+ break;
+ case 2:
+ cmd = SNAND_FIFO_RX_BUSWIDTH_DUAL;
+ break;
+ case 4:
+ cmd = SNAND_FIFO_RX_BUSWIDTH_QUAD;
+ break;
+ default:
+ return -EINVAL;
+ }
for (i = 0; i < len; i += data_len) {
int err;
data_len = min(len - i, SPI_MAX_TRANSFER_SIZE);
- err = airoha_snand_set_fifo_op(priv, 0xc, data_len);
+ err = airoha_snand_set_fifo_op(priv, cmd, data_len);
if (err)
return err;
@@ -439,131 +480,498 @@ static int airoha_snand_nfi_init(struct airoha_snand_priv *priv)
SPI_NFI_ALL_IRQ_EN, SPI_NFI_AHB_DONE_EN);
}
-static int airoha_snand_nfi_config(struct airoha_snand_priv *priv)
+static bool airoha_snand_is_page_ops(const struct spi_mem_op *op)
+{
+ if (op->addr.nbytes != 2)
+ return false;
+
+ if (op->addr.buswidth != 1 && op->addr.buswidth != 2 &&
+ op->addr.buswidth != 4)
+ return false;
+
+ switch (op->data.dir) {
+ case SPI_MEM_DATA_IN:
+ if (op->dummy.nbytes * BITS_PER_BYTE / op->dummy.buswidth > 0xf)
+ return false;
+
+ /* quad in / quad out */
+ if (op->addr.buswidth == 4)
+ return op->data.buswidth == 4;
+
+ if (op->addr.buswidth == 2)
+ return op->data.buswidth == 2;
+
+ /* standard spi */
+ return op->data.buswidth == 4 || op->data.buswidth == 2 ||
+ op->data.buswidth == 1;
+ case SPI_MEM_DATA_OUT:
+ return !op->dummy.nbytes && op->addr.buswidth == 1 &&
+ (op->data.buswidth == 4 || op->data.buswidth == 1);
+ default:
+ return false;
+ }
+}
+
+static bool airoha_snand_supports_op(struct spi_slave *slave,
+ const struct spi_mem_op *op)
+{
+ if (!spi_mem_default_supports_op(slave, op))
+ return false;
+
+ if (op->cmd.buswidth != 1)
+ return false;
+
+ if (airoha_snand_is_page_ops(op))
+ return true;
+
+ return (!op->addr.nbytes || op->addr.buswidth == 1) &&
+ (!op->dummy.nbytes || op->dummy.buswidth == 1) &&
+ (!op->data.nbytes || op->data.buswidth == 1);
+}
+
+static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc)
+{
+ struct spi_slave *slave = desc->slave;
+ struct udevice *bus = slave->dev->parent;
+ struct airoha_snand_priv *priv = dev_get_priv(bus);
+
+ if (!priv->txrx_buf)
+ return -EINVAL;
+
+ if (desc->info.offset + desc->info.length > U32_MAX)
+ return -EINVAL;
+
+ /* continuous reading is not supported */
+ if (desc->info.length > SPI_NAND_CACHE_SIZE)
+ return -E2BIG;
+
+ if (!airoha_snand_supports_op(desc->slave, &desc->info.op_tmpl))
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
+ u64 offs, size_t len, void *buf)
{
+ struct spi_slave *slave = desc->slave;
+ struct udevice *bus = slave->dev->parent;
+ struct airoha_snand_priv *priv = dev_get_priv(bus);
+ u8 *txrx_buf = priv->txrx_buf;
+ dma_addr_t dma_addr;
+ u32 val, rd_mode, opcode;
+ size_t bytes;
int err;
- u32 val;
+ if (!priv->dma) {
+ /* simplified version of spi_mem_no_dirmap_read() */
+ struct spi_mem_op op = desc->info.op_tmpl;
+
+ op.addr.val = desc->info.offset + offs;
+ op.data.buf.in = buf;
+ op.data.nbytes = len;
+ err = spi_mem_exec_op(desc->slave, &op);
+ if (err)
+ return err;
+
+ return op.data.nbytes;
+ }
+
+ /* minimum oob size is 64 */
+ bytes = round_up(offs + len, 64);
+
+ /*
+ * DUALIO and QUADIO opcodes are not supported by the spi controller,
+ * replace them with supported opcodes.
+ */
+ opcode = desc->info.op_tmpl.cmd.opcode;
+ switch (opcode) {
+ case SPI_NAND_OP_READ_FROM_CACHE_SINGLE:
+ case SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST:
+ rd_mode = 0;
+ break;
+ case SPI_NAND_OP_READ_FROM_CACHE_DUAL:
+ case SPI_NAND_OP_READ_FROM_CACHE_DUALIO:
+ opcode = SPI_NAND_OP_READ_FROM_CACHE_DUAL;
+ rd_mode = 1;
+ break;
+ case SPI_NAND_OP_READ_FROM_CACHE_QUAD:
+ case SPI_NAND_OP_READ_FROM_CACHE_QUADIO:
+ opcode = SPI_NAND_OP_READ_FROM_CACHE_QUAD;
+ rd_mode = 2;
+ break;
+ default:
+ /* unknown opcode */
+ return -EOPNOTSUPP;
+ }
+
+ err = airoha_snand_set_mode(priv, SPI_MODE_DMA);
+ if (err < 0)
+ return err;
+
+ /* NFI reset */
err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_CON,
SPI_NFI_FIFO_FLUSH | SPI_NFI_RST);
if (err)
- return err;
+ goto error_dma_mode_off;
+
+ /* NFI configure:
+ * - No AutoFDM (custom sector size (SECCUS) register will be used)
+ * - No SoC's hardware ECC (flash internal ECC will be used)
+ * - Use burst mode (faster, but requires 16 byte alignment for addresses)
+ * - Setup for reading (SPI_NFI_READ_MODE)
+ * - Setup reading command: FIELD_PREP(SPI_NFI_OPMODE, 6)
+ * - Use DMA instead of PIO for data reading
+ */
+ err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_CNFG,
+ SPI_NFI_DMA_MODE |
+ SPI_NFI_READ_MODE |
+ SPI_NFI_DMA_BURST_EN |
+ SPI_NFI_HW_ECC_EN |
+ SPI_NFI_AUTO_FDM_EN |
+ SPI_NFI_OPMODE,
+ SPI_NFI_DMA_MODE |
+ SPI_NFI_READ_MODE |
+ SPI_NFI_DMA_BURST_EN |
+ FIELD_PREP(SPI_NFI_OPMODE, 6));
+ if (err)
+ goto error_dma_mode_off;
- /* auto FDM */
- err = regmap_clear_bits(priv->regmap_nfi, REG_SPI_NFI_CNFG,
- SPI_NFI_AUTO_FDM_EN);
+ /* Set number of sector will be read */
+ err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_CON,
+ SPI_NFI_SEC_NUM,
+ FIELD_PREP(SPI_NFI_SEC_NUM, 1));
if (err)
- return err;
+ goto error_dma_mode_off;
+
+ /* Set custom sector size */
+ err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE,
+ SPI_NFI_CUS_SEC_SIZE |
+ SPI_NFI_CUS_SEC_SIZE_EN,
+ FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, bytes) |
+ SPI_NFI_CUS_SEC_SIZE_EN);
+ if (err)
+ goto error_dma_mode_off;
+
+ dma_addr = dma_map_single(txrx_buf, SPI_NAND_CACHE_SIZE,
+ DMA_FROM_DEVICE);
- /* HW ECC */
- err = regmap_clear_bits(priv->regmap_nfi, REG_SPI_NFI_CNFG,
- SPI_NFI_HW_ECC_EN);
+ /* set dma addr */
+ err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_STRADDR,
+ dma_addr);
if (err)
- return err;
+ goto error_dma_unmap;
+
+ /*
+ * Setup transfer length
+ * ---------------------
+ * The following rule MUST be met:
+ * transfer_length =
+ * = NFI_SNF_MISC_CTL2.read_data_byte_number =
+ * = NFI_CON.sector_number * NFI_SECCUS.custom_sector_size
+ */
+ err = regmap_update_bits(priv->regmap_nfi,
+ REG_SPI_NFI_SNF_MISC_CTL2,
+ SPI_NFI_READ_DATA_BYTE_NUM,
+ FIELD_PREP(SPI_NFI_READ_DATA_BYTE_NUM, bytes));
+ if (err)
+ goto error_dma_unmap;
- /* DMA Burst */
- err = regmap_set_bits(priv->regmap_nfi, REG_SPI_NFI_CNFG,
- SPI_NFI_DMA_BURST_EN);
+ /* set read command */
+ err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_RD_CTL2,
+ FIELD_PREP(SPI_NFI_DATA_READ_CMD, opcode));
if (err)
- return err;
+ goto error_dma_unmap;
- /* page format */
- switch (priv->nfi_cfg.spare_size) {
- case 26:
- val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x1);
- break;
- case 27:
- val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x2);
- break;
- case 28:
- val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x3);
- break;
- default:
- val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x0);
- break;
- }
+ /* set read mode */
+ err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL,
+ FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, rd_mode));
+ if (err)
+ goto error_dma_unmap;
+
+ /* set read addr: zero page offset + descriptor read offset */
+ err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_RD_CTL3,
+ desc->info.offset);
+ if (err)
+ goto error_dma_unmap;
- err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_PAGEFMT,
- SPI_NFI_SPARE_SIZE, val);
+ err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_CMD, 0x0);
if (err)
+ goto error_dma_unmap;
+
+ /* trigger dma reading */
+ err = regmap_clear_bits(priv->regmap_nfi, REG_SPI_NFI_CON,
+ SPI_NFI_RD_TRIG);
+ if (err)
+ goto error_dma_unmap;
+
+ err = regmap_set_bits(priv->regmap_nfi, REG_SPI_NFI_CON,
+ SPI_NFI_RD_TRIG);
+ if (err)
+ goto error_dma_unmap;
+
+ err = regmap_read_poll_timeout(priv->regmap_nfi,
+ REG_SPI_NFI_SNF_STA_CTL1, val,
+ (val & SPI_NFI_READ_FROM_CACHE_DONE),
+ 0, 1 * MSEC_PER_SEC);
+ if (err)
+ goto error_dma_unmap;
+
+ /*
+ * SPI_NFI_READ_FROM_CACHE_DONE bit must be written at the end
+ * of dirmap_read operation even if it is already set.
+ */
+ err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1,
+ SPI_NFI_READ_FROM_CACHE_DONE,
+ SPI_NFI_READ_FROM_CACHE_DONE);
+ if (err)
+ goto error_dma_unmap;
+
+ err = regmap_read_poll_timeout(priv->regmap_nfi, REG_SPI_NFI_INTR,
+ val, (val & SPI_NFI_AHB_DONE), 0,
+ 1 * MSEC_PER_SEC);
+ if (err)
+ goto error_dma_unmap;
+
+ /* DMA read need delay for data ready from controller to DRAM */
+ udelay(1);
+
+ dma_unmap_single(dma_addr, SPI_NAND_CACHE_SIZE, DMA_FROM_DEVICE);
+
+ err = airoha_snand_set_mode(priv, SPI_MODE_MANUAL);
+ if (err < 0)
return err;
- switch (priv->nfi_cfg.page_size) {
- case 2048:
- val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x1);
+ memcpy(buf, txrx_buf + offs, len);
+
+ return len;
+
+error_dma_unmap:
+ dma_unmap_single(dma_addr, SPI_NAND_CACHE_SIZE, DMA_FROM_DEVICE);
+error_dma_mode_off:
+ airoha_snand_set_mode(priv, SPI_MODE_MANUAL);
+ return err;
+}
+
+static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
+ u64 offs, size_t len, const void *buf)
+{
+ struct spi_slave *slave = desc->slave;
+ struct udevice *bus = slave->dev->parent;
+ struct airoha_snand_priv *priv = dev_get_priv(bus);
+ u8 *txrx_buf = priv->txrx_buf;
+ dma_addr_t dma_addr;
+ u32 wr_mode, val, opcode;
+ size_t bytes;
+ int err;
+
+ if (!priv->dma) {
+ /* simplified version of spi_mem_no_dirmap_write() */
+ struct spi_mem_op op = desc->info.op_tmpl;
+
+ op.addr.val = desc->info.offset + offs;
+ op.data.buf.out = buf;
+ op.data.nbytes = len;
+ err = spi_mem_exec_op(desc->slave, &op);
+ if (err)
+ return err;
+
+ return op.data.nbytes;
+ }
+
+ /* minimum oob size is 64 */
+ bytes = round_up(offs + len, 64);
+
+ opcode = desc->info.op_tmpl.cmd.opcode;
+ switch (opcode) {
+ case SPI_NAND_OP_PROGRAM_LOAD_SINGLE:
+ case SPI_NAND_OP_PROGRAM_LOAD_RAMDOM_SINGLE:
+ wr_mode = 0;
break;
- case 4096:
- val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x2);
+ case SPI_NAND_OP_PROGRAM_LOAD_QUAD:
+ case SPI_NAND_OP_PROGRAM_LOAD_RAMDON_QUAD:
+ wr_mode = 2;
break;
default:
- val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x0);
- break;
+ /* unknown opcode */
+ return -EOPNOTSUPP;
}
- err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_PAGEFMT,
- SPI_NFI_PAGE_SIZE, val);
- if (err)
+ if (offs > 0)
+ memset(txrx_buf, 0xff, offs);
+ memcpy(txrx_buf + offs, buf, len);
+ if (bytes > offs + len)
+ memset(txrx_buf + offs + len, 0xff, bytes - offs - len);
+
+ err = airoha_snand_set_mode(priv, SPI_MODE_DMA);
+ if (err < 0)
return err;
- /* sec num */
- val = FIELD_PREP(SPI_NFI_SEC_NUM, priv->nfi_cfg.sec_num);
+ /* NFI reset */
+ err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_CON,
+ SPI_NFI_FIFO_FLUSH | SPI_NFI_RST);
+ if (err)
+ goto error_dma_mode_off;
+
+ /*
+ * NFI configure:
+ * - No AutoFDM (custom sector size (SECCUS) register will be used)
+ * - No SoC's hardware ECC (flash internal ECC will be used)
+ * - Use burst mode (faster, but requires 16 byte alignment for addresses)
+ * - Setup for writing (SPI_NFI_READ_MODE bit is cleared)
+ * - Setup writing command: FIELD_PREP(SPI_NFI_OPMODE, 3)
+ * - Use DMA instead of PIO for data writing
+ */
+ err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_CNFG,
+ SPI_NFI_DMA_MODE |
+ SPI_NFI_READ_MODE |
+ SPI_NFI_DMA_BURST_EN |
+ SPI_NFI_HW_ECC_EN |
+ SPI_NFI_AUTO_FDM_EN |
+ SPI_NFI_OPMODE,
+ SPI_NFI_DMA_MODE |
+ SPI_NFI_DMA_BURST_EN |
+ FIELD_PREP(SPI_NFI_OPMODE, 3));
+ if (err)
+ goto error_dma_mode_off;
+
+ /* Set number of sector will be written */
err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_CON,
- SPI_NFI_SEC_NUM, val);
+ SPI_NFI_SEC_NUM,
+ FIELD_PREP(SPI_NFI_SEC_NUM, 1));
if (err)
- return err;
+ goto error_dma_mode_off;
+
+ /* Set custom sector size */
+ err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE,
+ SPI_NFI_CUS_SEC_SIZE |
+ SPI_NFI_CUS_SEC_SIZE_EN,
+ FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, bytes) |
+ SPI_NFI_CUS_SEC_SIZE_EN);
+ if (err)
+ goto error_dma_mode_off;
- /* enable cust sec size */
- err = regmap_set_bits(priv->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE,
- SPI_NFI_CUS_SEC_SIZE_EN);
+ dma_addr = dma_map_single(txrx_buf, SPI_NAND_CACHE_SIZE,
+ DMA_TO_DEVICE);
+
+ /* set dma addr */
+ err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_STRADDR,
+ dma_addr);
if (err)
- return err;
+ goto error_dma_unmap;
+
+ /*
+ * Setup transfer length
+ * ---------------------
+ * The following rule MUST be met:
+ * transfer_length =
+ * = NFI_SNF_MISC_CTL2.write_data_byte_number =
+ * = NFI_CON.sector_number * NFI_SECCUS.custom_sector_size
+ */
+ err = regmap_update_bits(priv->regmap_nfi,
+ REG_SPI_NFI_SNF_MISC_CTL2,
+ SPI_NFI_PROG_LOAD_BYTE_NUM,
+ FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM, bytes));
+ if (err)
+ goto error_dma_unmap;
- /* set cust sec size */
- val = FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, priv->nfi_cfg.sec_size);
- return regmap_update_bits(priv->regmap_nfi,
- REG_SPI_NFI_SECCUS_SIZE,
- SPI_NFI_CUS_SEC_SIZE, val);
-}
+ /* set write command */
+ err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_PG_CTL1,
+ FIELD_PREP(SPI_NFI_PG_LOAD_CMD, opcode));
+ if (err)
+ goto error_dma_unmap;
-static int airoha_snand_adjust_op_size(struct spi_slave *slave,
- struct spi_mem_op *op)
-{
- size_t max_len;
+ /* set write mode */
+ err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL,
+ FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, wr_mode));
+ if (err)
+ goto error_dma_unmap;
- max_len = 1 + op->addr.nbytes + op->dummy.nbytes;
- if (max_len >= 160)
- return -EOPNOTSUPP;
+ /* set write addr: zero page offset + descriptor write offset */
+ err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_PG_CTL2,
+ desc->info.offset);
+ if (err)
+ goto error_dma_unmap;
- if (op->data.nbytes > 160 - max_len)
- op->data.nbytes = 160 - max_len;
+ err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_CMD, 0x80);
+ if (err)
+ goto error_dma_unmap;
- return 0;
-}
+ /* trigger dma writing */
+ err = regmap_clear_bits(priv->regmap_nfi, REG_SPI_NFI_CON,
+ SPI_NFI_WR_TRIG);
+ if (err)
+ goto error_dma_unmap;
-static bool airoha_snand_supports_op(struct spi_slave *slave,
- const struct spi_mem_op *op)
-{
- if (!spi_mem_default_supports_op(slave, op))
- return false;
+ err = regmap_set_bits(priv->regmap_nfi, REG_SPI_NFI_CON,
+ SPI_NFI_WR_TRIG);
+ if (err)
+ goto error_dma_unmap;
- if (op->cmd.buswidth != 1)
- return false;
+ err = regmap_read_poll_timeout(priv->regmap_nfi, REG_SPI_NFI_INTR,
+ val, (val & SPI_NFI_AHB_DONE), 0,
+ 1 * MSEC_PER_SEC);
+ if (err)
+ goto error_dma_unmap;
- return (!op->addr.nbytes || op->addr.buswidth == 1) &&
- (!op->dummy.nbytes || op->dummy.buswidth == 1) &&
- (!op->data.nbytes || op->data.buswidth == 1);
+ err = regmap_read_poll_timeout(priv->regmap_nfi,
+ REG_SPI_NFI_SNF_STA_CTL1, val,
+ (val & SPI_NFI_LOAD_TO_CACHE_DONE),
+ 0, 1 * MSEC_PER_SEC);
+ if (err)
+ goto error_dma_unmap;
+
+ /*
+ * SPI_NFI_LOAD_TO_CACHE_DONE bit must be written at the end
+ * of dirmap_write operation even if it is already set.
+ */
+ err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1,
+ SPI_NFI_LOAD_TO_CACHE_DONE,
+ SPI_NFI_LOAD_TO_CACHE_DONE);
+ if (err)
+ goto error_dma_unmap;
+
+ dma_unmap_single(dma_addr, SPI_NAND_CACHE_SIZE, DMA_TO_DEVICE);
+
+ err = airoha_snand_set_mode(priv, SPI_MODE_MANUAL);
+ if (err < 0)
+ return err;
+
+ return len;
+
+error_dma_unmap:
+ dma_unmap_single(dma_addr, SPI_NAND_CACHE_SIZE, DMA_TO_DEVICE);
+error_dma_mode_off:
+ airoha_snand_set_mode(priv, SPI_MODE_MANUAL);
+ return err;
}
static int airoha_snand_exec_op(struct spi_slave *slave,
const struct spi_mem_op *op)
{
- u8 data[8], cmd, opcode = op->cmd.opcode;
struct udevice *bus = slave->dev->parent;
struct airoha_snand_priv *priv;
+ int op_len, addr_len, dummy_len;
+ u8 buf[20], *data;
int i, err;
priv = dev_get_priv(bus);
+ op_len = op->cmd.nbytes;
+ addr_len = op->addr.nbytes;
+ dummy_len = op->dummy.nbytes;
+
+ if (op_len + dummy_len + addr_len > sizeof(buf))
+ return -EIO;
+
+ data = buf;
+ for (i = 0; i < op_len; i++)
+ *data++ = op->cmd.opcode >> (8 * (op_len - i - 1));
+ for (i = 0; i < addr_len; i++)
+ *data++ = op->addr.val >> (8 * (addr_len - i - 1));
+ for (i = 0; i < dummy_len; i++)
+ *data++ = 0xff;
+
/* switch to manual mode */
err = airoha_snand_set_mode(priv, SPI_MODE_MANUAL);
if (err < 0)
@@ -574,40 +982,40 @@ static int airoha_snand_exec_op(struct spi_slave *slave,
return err;
/* opcode */
- err = airoha_snand_write_data(priv, 0x8, &opcode, sizeof(opcode));
+ data = buf;
+ err = airoha_snand_write_data(priv, data, op_len,
+ op->cmd.buswidth);
if (err)
return err;
/* addr part */
- cmd = opcode == SPI_NAND_OP_GET_FEATURE ? 0x11 : 0x8;
- put_unaligned_be64(op->addr.val, data);
-
- for (i = ARRAY_SIZE(data) - op->addr.nbytes;
- i < ARRAY_SIZE(data); i++) {
- err = airoha_snand_write_data(priv, cmd, &data[i],
- sizeof(data[0]));
+ data += op_len;
+ if (addr_len) {
+ err = airoha_snand_write_data(priv, data, addr_len,
+ op->addr.buswidth);
if (err)
return err;
}
/* dummy */
- data[0] = 0xff;
- for (i = 0; i < op->dummy.nbytes; i++) {
- err = airoha_snand_write_data(priv, 0x8, &data[0],
- sizeof(data[0]));
+ data += addr_len;
+ if (dummy_len) {
+ err = airoha_snand_write_data(priv, data, dummy_len,
+ op->dummy.buswidth);
if (err)
return err;
}
/* data */
- if (op->data.dir == SPI_MEM_DATA_IN) {
- err = airoha_snand_read_data(priv, op->data.buf.in,
- op->data.nbytes);
- if (err)
- return err;
- } else {
- err = airoha_snand_write_data(priv, 0x8, op->data.buf.out,
- op->data.nbytes);
+ if (op->data.nbytes) {
+ if (op->data.dir == SPI_MEM_DATA_IN)
+ err = airoha_snand_read_data(priv, op->data.buf.in,
+ op->data.nbytes,
+ op->data.buswidth);
+ else
+ err = airoha_snand_write_data(priv, op->data.buf.out,
+ op->data.nbytes,
+ op->data.buswidth);
if (err)
return err;
}
@@ -619,6 +1027,13 @@ static int airoha_snand_probe(struct udevice *dev)
{
struct airoha_snand_priv *priv = dev_get_priv(dev);
int ret;
+ u32 sfc_strap;
+
+ priv->txrx_buf = memalign(ARCH_DMA_MINALIGN, SPI_NAND_CACHE_SIZE);
+ if (!priv->txrx_buf) {
+ dev_err(dev, "failed to alloacate memory for dirmap\n");
+ return -ENOMEM;
+ }
ret = regmap_init_mem_index(dev_ofnode(dev), &priv->regmap_ctrl, 0);
if (ret) {
@@ -639,6 +1054,25 @@ static int airoha_snand_probe(struct udevice *dev)
}
clk_enable(priv->spi_clk);
+ priv->dma = 1;
+ if (device_is_compatible(dev, "airoha,en7523-snand")){
+ ret = regmap_read(priv->regmap_ctrl, REG_SPI_CTRL_SFC_STRAP, &sfc_strap);
+ if (ret)
+ return ret;
+
+ if (!(sfc_strap & 0x04)) {
+ priv->dma = 0;
+ printf("\n"
+ "=== WARNING ======================================================\n"
+ "Detected booting in RESERVED mode (UART_TXD was short to GND).\n"
+ "This mode is known for incorrect DMA reading of some flashes.\n"
+ "Usage of DMA for flash operations will be disabled to prevent data\n"
+ "damage. Unplug your serial console and power cycle the board\n"
+ "to boot with full performance.\n"
+ "==================================================================\n\n");
+ }
+ }
+
return airoha_snand_nfi_init(priv);
}
@@ -659,48 +1093,18 @@ static int airoha_snand_nfi_set_mode(struct udevice *bus, uint mode)
return 0;
}
-static int airoha_snand_nfi_setup(struct spi_slave *slave,
- const struct spinand_info *spinand_info)
-{
- struct udevice *bus = slave->dev->parent;
- struct airoha_snand_priv *priv;
- u32 sec_size, sec_num;
- int pagesize, oobsize;
-
- priv = dev_get_priv(bus);
-
- pagesize = spinand_info->memorg.pagesize;
- oobsize = spinand_info->memorg.oobsize;
-
- if (pagesize == 2 * 1024)
- sec_num = 4;
- else if (pagesize == 4 * 1024)
- sec_num = 8;
- else
- sec_num = 1;
-
- sec_size = (pagesize + oobsize) / sec_num;
-
- /* init default value */
- priv->nfi_cfg.sec_size = sec_size;
- priv->nfi_cfg.sec_num = sec_num;
- priv->nfi_cfg.page_size = round_down(sec_size * sec_num, 1024);
- priv->nfi_cfg.spare_size = 16;
-
- return airoha_snand_nfi_config(priv);
-}
-
static const struct spi_controller_mem_ops airoha_snand_mem_ops = {
- .adjust_op_size = airoha_snand_adjust_op_size,
.supports_op = airoha_snand_supports_op,
.exec_op = airoha_snand_exec_op,
+ .dirmap_create = airoha_snand_dirmap_create,
+ .dirmap_read = airoha_snand_dirmap_read,
+ .dirmap_write = airoha_snand_dirmap_write,
};
static const struct dm_spi_ops airoha_snfi_spi_ops = {
.mem_ops = &airoha_snand_mem_ops,
.set_speed = airoha_snand_nfi_set_speed,
.set_mode = airoha_snand_nfi_set_mode,
- .setup_for_spinand = airoha_snand_nfi_setup,
};
static const struct udevice_id airoha_snand_ids[] = {
diff --git a/drivers/spi/altera_spi.c b/drivers/spi/altera_spi.c
index dafaf1130bb..a75d861bda4 100644
--- a/drivers/spi/altera_spi.c
+++ b/drivers/spi/altera_spi.c
@@ -12,6 +12,7 @@
#include <malloc.h>
#include <fdtdec.h>
#include <spi.h>
+#include <time.h>
#include <asm/io.h>
#include <linux/bitops.h>
diff --git a/drivers/spi/cadence_ospi_versal.c b/drivers/spi/cadence_ospi_versal.c
index 6dc6fbe5a5b..0efbbf56a5e 100644
--- a/drivers/spi/cadence_ospi_versal.c
+++ b/drivers/spi/cadence_ospi_versal.c
@@ -199,12 +199,12 @@ void cadence_qspi_apb_enable_linear_mode(bool enable)
/* ahb read mode */
xilinx_pm_request(PM_IOCTL, PM_DEV_OSPI,
IOCTL_OSPI_MUX_SELECT,
- PM_OSPI_MUX_SEL_LINEAR, 0, NULL);
+ PM_OSPI_MUX_SEL_LINEAR, 0, 0, 0, NULL);
else
/* DMA mode */
xilinx_pm_request(PM_IOCTL, PM_DEV_OSPI,
IOCTL_OSPI_MUX_SELECT,
- PM_OSPI_MUX_SEL_DMA, 0, NULL);
+ PM_OSPI_MUX_SEL_DMA, 0, 0, 0, NULL);
} else {
if (enable)
writel(readl(VERSAL_AXI_MUX_SEL) |
diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index 9edbfaa821b..9b45cab9c04 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -142,7 +142,7 @@ static int spi_calibration(struct udevice *bus, uint hz)
if (range_lo == -1) {
puts("SF: Calibration failed (low range)\n");
- return err;
+ return -EIO;
}
/* Disable QSPI for subsequent initialization */
@@ -230,7 +230,7 @@ static int cadence_spi_probe(struct udevice *bus)
if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE))
xilinx_pm_request(PM_REQUEST_NODE, PM_DEV_OSPI,
ZYNQMP_PM_CAPABILITY_ACCESS, ZYNQMP_PM_MAX_QOS,
- ZYNQMP_PM_REQUEST_ACK_NO, NULL);
+ ZYNQMP_PM_REQUEST_ACK_NO, 0, 0, NULL);
if (priv->ref_clk_hz == 0) {
ret = clk_get_by_index(bus, 0, &clk);
diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
index 4696c09f754..0d4bc685f5d 100644
--- a/drivers/spi/cadence_qspi_apb.c
+++ b/drivers/spi/cadence_qspi_apb.c
@@ -354,7 +354,7 @@ void cadence_qspi_apb_controller_init(struct cadence_spi_priv *priv)
int cadence_qspi_apb_exec_flash_cmd(void *reg_base, unsigned int reg)
{
- unsigned int retry = CQSPI_REG_RETRY;
+ int retry = CQSPI_REG_RETRY;
/* Write the CMDCTRL without start execution. */
writel(reg, reg_base + CQSPI_REG_CMDCTRL);
@@ -369,7 +369,7 @@ int cadence_qspi_apb_exec_flash_cmd(void *reg_base, unsigned int reg)
udelay(1);
}
- if (!retry) {
+ if (retry == -1) {
printf("QSPI: flash command execution timeout\n");
return -EIO;
}
diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c
index 2264ca83d66..733ff8ac777 100644
--- a/drivers/spi/ich.c
+++ b/drivers/spi/ich.c
@@ -256,7 +256,7 @@ static int ich_spi_exec_op_swseq(struct spi_slave *slave,
struct ich_spi_priv *ctlr = dev_get_priv(bus);
uint16_t control;
int16_t opcode_index;
- int with_address;
+ int with_address = 0;
int status;
struct spi_trans *trans = &ctlr->trans;
bool lock = spi_lock_status(plat, ctlr->base);
diff --git a/drivers/spi/npcm_fiu_spi.c b/drivers/spi/npcm_fiu_spi.c
index 7b8271c8bbc..761ef8c058b 100644
--- a/drivers/spi/npcm_fiu_spi.c
+++ b/drivers/spi/npcm_fiu_spi.c
@@ -273,8 +273,7 @@ static int npcm_fiu_uma_operation(struct npcm_fiu_priv *priv, const struct spi_m
if (op->data.dir == SPI_MEM_DATA_OUT && nbytes) {
memcpy(data_reg, tx, nbytes);
- if (nbytes)
- writel(data_reg[0], &regs->uma_dw0);
+ writel(data_reg[0], &regs->uma_dw0);
if (nbytes > DW_SIZE)
writel(data_reg[1], &regs->uma_dw1);
if (nbytes > DW_SIZE * 2)
diff --git a/drivers/spi/nxp_fspi.c b/drivers/spi/nxp_fspi.c
index 6d97b8eefc9..46de915c238 100644
--- a/drivers/spi/nxp_fspi.c
+++ b/drivers/spi/nxp_fspi.c
@@ -337,6 +337,33 @@ static struct nxp_fspi_devtype_data imxrt1170_data = {
.little_endian = true,
};
+static const struct nxp_fspi_devtype_data imx8qxp_data = {
+ .rxfifo = SZ_512, /* (64 * 64 bits) */
+ .txfifo = SZ_1K, /* (128 * 64 bits) */
+ .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */
+ .quirks = 0,
+ .lut_num = 32,
+ .little_endian = true, /* little-endian */
+};
+
+static const struct nxp_fspi_devtype_data imx8dxl_data = {
+ .rxfifo = SZ_512, /* (64 * 64 bits) */
+ .txfifo = SZ_1K, /* (128 * 64 bits) */
+ .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */
+ .quirks = FSPI_QUIRK_USE_IP_ONLY,
+ .lut_num = 32,
+ .little_endian = true, /* little-endian */
+};
+
+static const struct nxp_fspi_devtype_data imx8ulp_data = {
+ .rxfifo = SZ_1K, /* (128 * 64 bits) */
+ .txfifo = SZ_1K, /* (128 * 64 bits) */
+ .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */
+ .quirks = 0,
+ .lut_num = 16,
+ .little_endian = true, /* little-endian */
+};
+
struct nxp_fspi {
struct udevice *dev;
void __iomem *iobase;
@@ -539,6 +566,15 @@ static void nxp_fspi_prepare_lut(struct nxp_fspi *f,
fspi_writel(f, lutval[i], base + target_lut_reg);
}
+ if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_IN &&
+ op->addr.nbytes) {
+ lut_offset = (f->devtype_data->lut_num - 2) * 4 * 4;
+ for (i = 0; i < ARRAY_SIZE(lutval); i++) {
+ target_lut_reg = FSPI_LUT_BASE + lut_offset + i * 4;
+ fspi_writel(f, lutval[i], base + target_lut_reg);
+ }
+ }
+
dev_dbg(f->dev, "CMD[%x] lutval[0:%x \t 1:%x \t 2:%x \t 3:%x], size: 0x%08x\n",
op->cmd.opcode, lutval[0], lutval[1], lutval[2], lutval[3], op->data.nbytes);
@@ -846,9 +882,9 @@ static void erratum_err050568(struct nxp_fspi *f)
/* Check for LS1028A variants */
svr = SVR_SOC_VER(get_svr());
- if (svr != SVR_LS1017A ||
- svr != SVR_LS1018A ||
- svr != SVR_LS1027A ||
+ if (svr != SVR_LS1017A &&
+ svr != SVR_LS1018A &&
+ svr != SVR_LS1027A &&
svr != SVR_LS1028A) {
dev_dbg(f->dev, "Errata applicable only for LS1028A variants\n");
return;
@@ -943,9 +979,10 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f)
/*
* The driver only uses one single LUT entry, that is updated on
* each call of exec_op(). Index 0 is preset at boot with a basic
- * read operation, so let's use the last entry.
+ * read operation, last entry is used for dynamic lut, the second
+ * last entry is used for AHB read.
*/
- seqid_lut = f->devtype_data->lut_num - 1;
+ seqid_lut = f->devtype_data->lut_num - 2;
/* AHB Read - Set lut sequence ID for all CS. */
fspi_writel(f, seqid_lut, base + FSPI_FLSHA1CR2);
fspi_writel(f, seqid_lut, base + FSPI_FLSHA2CR2);
@@ -1071,6 +1108,9 @@ static const struct udevice_id nxp_fspi_ids[] = {
{ .compatible = "nxp,lx2160a-fspi", .data = (ulong)&lx2160a_data, },
{ .compatible = "nxp,imx8mm-fspi", .data = (ulong)&imx8mm_data, },
{ .compatible = "nxp,imx8mp-fspi", .data = (ulong)&imx8mm_data, },
+ { .compatible = "nxp,imx8qxp-fspi", .data = (ulong)&imx8qxp_data, },
+ { .compatible = "nxp,imx8dxl-fspi", .data = (ulong)&imx8dxl_data, },
+ { .compatible = "nxp,imx8ulp-fspi", .data = (ulong)&imx8ulp_data, },
{ .compatible = "nxp,imxrt1170-fspi", .data = (ulong)&imxrt1170_data, },
{ }
};
diff --git a/drivers/spi/rockchip_sfc.c b/drivers/spi/rockchip_sfc.c
index 73738ab26d3..60e74117057 100644
--- a/drivers/spi/rockchip_sfc.c
+++ b/drivers/spi/rockchip_sfc.c
@@ -108,6 +108,7 @@
#define SFC_VER_3 0x3
#define SFC_VER_4 0x4
#define SFC_VER_5 0x5
+#define SFC_VER_8 0x8
/* Delay line controller resiter */
#define SFC_DLL_CTRL0 0x3C
@@ -589,6 +590,16 @@ static int rockchip_sfc_adjust_op_size(struct spi_slave *mem, struct spi_mem_op
return 0;
}
+#if CONFIG_IS_ENABLED(CLK)
+static int rockchip_sfc_clk_set_rate(struct rockchip_sfc *sfc, uint speed)
+{
+ if (sfc->version >= SFC_VER_8)
+ return clk_set_rate(&sfc->clk, speed * 2);
+ else
+ return clk_set_rate(&sfc->clk, speed);
+}
+#endif
+
static int rockchip_sfc_set_speed(struct udevice *bus, uint speed)
{
struct rockchip_sfc *sfc = dev_get_plat(bus);
@@ -600,7 +611,7 @@ static int rockchip_sfc_set_speed(struct udevice *bus, uint speed)
return 0;
#if CONFIG_IS_ENABLED(CLK)
- int ret = clk_set_rate(&sfc->clk, speed);
+ int ret = rockchip_sfc_clk_set_rate(sfc, speed);
if (ret < 0) {
dev_err(sfc->dev, "set_freq=%dHz fail, check if it's the cru support level\n",
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index 3579b7d7db5..3fd2353af94 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -120,18 +120,21 @@ static int spi_check_buswidth_req(struct spi_slave *slave, u8 buswidth, bool tx)
return 0;
case 2:
- if ((tx && (mode & (SPI_TX_DUAL | SPI_TX_QUAD))) ||
- (!tx && (mode & (SPI_RX_DUAL | SPI_RX_QUAD))))
+ if ((tx &&
+ (mode & (SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL))) ||
+ (!tx &&
+ (mode & (SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL))))
return 0;
break;
case 4:
- if ((tx && (mode & SPI_TX_QUAD)) ||
- (!tx && (mode & SPI_RX_QUAD)))
+ if ((tx && (mode & (SPI_TX_QUAD | SPI_TX_OCTAL))) ||
+ (!tx && (mode & (SPI_RX_QUAD | SPI_RX_OCTAL))))
return 0;
break;
+
case 8:
if ((tx && (mode & SPI_TX_OCTAL)) ||
(!tx && (mode & SPI_RX_OCTAL)))
@@ -300,7 +303,7 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
* read path) and expect the core to use the regular SPI
* interface in other cases.
*/
- if (!ret || ret != -ENOTSUPP) {
+ if (!ret || (ret != -ENOTSUPP && ret != -EOPNOTSUPP)) {
spi_release_bus(slave);
return ret;
}
@@ -496,6 +499,71 @@ int spi_mem_adjust_op_size(struct spi_slave *slave, struct spi_mem_op *op)
}
EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size);
+static inline u64 spi_mem_bytes_to_ncycles(u32 nbytes, u8 buswidth, u8 dtr)
+{
+ u64 ncycles;
+ u32 divider = buswidth * (dtr ? 2 : 1);
+
+ /*
+ * Theoretically
+ *
+ * ncycles = (nbytes * 8) / (buswidth * (dtr ? 2 : 1));
+ *
+ * may lead to an integer overflow, if nbytes will be larger than
+ * 0x1fffffff. Lets split this operation on:
+ *
+ * 1) Operation with bits 0..28 (overflow will not happen),
+ *
+ * 2) Operation with bits 29..31. Here we'll take into account
+ * that buswidth is a small power of 2 (so whole divider is
+ * small power of 2). Hense we may divide first, then multiply.
+ */
+ ncycles = ((nbytes & 0x1fffffff) * 8) / divider;
+ ncycles += ((u64) ((nbytes & ~0x1fffffff) / divider)) * 8;
+
+ return ncycles;
+}
+
+/**
+ * spi_mem_calc_op_duration() - Derives the theoretical length (in cpu cycles)
+ * of an operation. This helps finding the best
+ * variant among a list of possible choices.
+ * @op: the operation to benchmark
+ *
+ * Some chips have per-op frequency limitations, PCBs usually have their own
+ * limitations as well, and controllers can support dual, quad or even octal
+ * modes, sometimes in DTR. All these combinations make it impossible to
+ * statically list the best combination for all situations. If we want something
+ * accurate, all these combinations should be rated (eg. with a time estimate)
+ * and the best pick should be taken based on these calculations.
+ *
+ * Returns a estimate for the time this op would take.
+ */
+u64 spi_mem_calc_op_duration(struct spi_mem_op *op)
+{
+ u64 ncycles = 0;
+
+ ncycles += spi_mem_bytes_to_ncycles(op->cmd.nbytes,
+ op->cmd.buswidth,
+ op->cmd.dtr);
+ ncycles += spi_mem_bytes_to_ncycles(op->addr.nbytes,
+ op->addr.buswidth,
+ op->addr.dtr);
+
+ /* Dummy bytes are optional for some SPI flash memory operations */
+ if (op->dummy.nbytes)
+ ncycles += spi_mem_bytes_to_ncycles(op->dummy.nbytes,
+ op->dummy.buswidth,
+ op->dummy.dtr);
+
+ ncycles += spi_mem_bytes_to_ncycles(op->data.nbytes,
+ op->data.buswidth,
+ op->data.dtr);
+
+ return ncycles;
+}
+EXPORT_SYMBOL_GPL(spi_mem_calc_op_duration);
+
static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len, void *buf)
{
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index d6049753740..49b584c648d 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -449,7 +449,8 @@ int _spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
#if CONFIG_IS_ENABLED(SPI_STACKED_PARALLEL)
if ((dev_read_bool(dev, "parallel-memories")) && !slave->multi_cs_cap) {
dev_err(dev, "controller doesn't support multi CS\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err;
}
#endif
/*
diff --git a/drivers/spmi/spmi-sandbox.c b/drivers/spmi/spmi-sandbox.c
index 992b08dd612..1a8561b3aea 100644
--- a/drivers/spmi/spmi-sandbox.c
+++ b/drivers/spmi/spmi-sandbox.c
@@ -144,7 +144,7 @@ static const struct udevice_id sandbox_spmi_ids[] = {
{ }
};
-U_BOOT_DRIVER(msm_spmi) = {
+U_BOOT_DRIVER(sandbox_spmi) = {
.name = "sandbox_spmi",
.id = UCLASS_SPMI,
.of_match = sandbox_spmi_ids,
diff --git a/drivers/tee/Makefile b/drivers/tee/Makefile
index ff844195ae1..5bc5df0d380 100644
--- a/drivers/tee/Makefile
+++ b/drivers/tee/Makefile
@@ -1,8 +1,6 @@
# SPDX-License-Identifier: GPL-2.0+
obj-y += tee-uclass.o
-obj-$(CONFIG_SANDBOX) += sandbox.o
-obj-$(CONFIG_OPTEE_TA_RPC_TEST) += optee/supplicant.o
-obj-$(CONFIG_OPTEE_TA_RPC_TEST) += optee/i2c.o
+obj-$(CONFIG_SANDBOX_TEE) += sandbox.o optee/
obj-$(CONFIG_OPTEE) += optee/
obj-y += broadcom/
diff --git a/drivers/tee/optee/Makefile b/drivers/tee/optee/Makefile
index 068c6e7aa1b..36ac085ef42 100644
--- a/drivers/tee/optee/Makefile
+++ b/drivers/tee/optee/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0+
-obj-y += core.o
+obj-$(CONFIG_OPTEE) += core.o
obj-y += supplicant.o
obj-$(CONFIG_DM_I2C) += i2c.o
obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 440eb64a566..91c39aa4dee 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -35,6 +35,14 @@ config IMX_TMU
The boot is hold to the cool device to throttle CPUs when the
passive trip is crossed
+config RCAR_GEN3_THERMAL
+ bool "Renesas R-Car Gen3/Gen4 and RZ/G2 thermal driver"
+ depends on ARCH_RENESAS
+ depends on RCAR_64
+ help
+ Enable this to plug the R-Car Gen3/Gen4 or RZ/G2 thermal sensor
+ driver into the U-Boot thermal framework.
+
config TI_DRA7_THERMAL
bool "Temperature sensor driver for TI dra7xx SOCs"
help
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 18ad453f9b1..b6f06c00ed9 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_DM_THERMAL) += thermal-uclass.o
obj-$(CONFIG_IMX_SCU_THERMAL) += imx_scu_thermal.o
obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o
obj-$(CONFIG_IMX_TMU) += imx_tmu.o
+obj-$(CONFIG_RCAR_GEN3_THERMAL) += rcar_gen3_thermal.o
obj-$(CONFIG_SANDBOX) += thermal_sandbox.o
obj-$(CONFIG_TI_DRA7_THERMAL) += ti-bandgap.o
obj-$(CONFIG_TI_LM74_THERMAL) += ti-lm74.o
diff --git a/drivers/thermal/imx_scu_thermal.c b/drivers/thermal/imx_scu_thermal.c
index fc2b0e227b2..6b0b1d10d9d 100644
--- a/drivers/thermal/imx_scu_thermal.c
+++ b/drivers/thermal/imx_scu_thermal.c
@@ -72,7 +72,7 @@ int imx_sc_thermal_get_temp(struct udevice *dev, int *temp)
break;
}
- *temp = cpu_temp / 1000;
+ *temp = cpu_temp;
return 0;
}
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index ea1fcc3dcb2..d04035950ee 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -223,7 +223,7 @@ int imx_thermal_get_temp(struct udevice *dev, int *temp)
cpu_tmp = read_cpu_temperature(dev);
}
- *temp = cpu_tmp;
+ *temp = cpu_tmp * 1000;
return 0;
}
diff --git a/drivers/thermal/imx_tmu.c b/drivers/thermal/imx_tmu.c
index 70d002aee25..c8389d507ee 100644
--- a/drivers/thermal/imx_tmu.c
+++ b/drivers/thermal/imx_tmu.c
@@ -245,7 +245,7 @@ int imx_tmu_get_temp(struct udevice *dev, int *temp)
return ret;
}
- *temp = cpu_tmp / 1000;
+ *temp = cpu_tmp;
return 0;
}
@@ -532,6 +532,16 @@ static int imx_tmu_enable_msite(struct udevice *dev)
return 0;
}
+static void imx_tmu_set_trips(struct imx_tmu_plat *pdata)
+{
+ int minc, maxc;
+
+ /* default alert/crit temps based on temp grade */
+ get_cpu_temp_grade(&minc, &maxc);
+ pdata->critical = maxc * 1000;
+ pdata->alert = (maxc - 10) * 1000;
+}
+
static int imx_tmu_bind(struct udevice *dev)
{
struct imx_tmu_plat *pdata = dev_get_plat(dev);
@@ -539,7 +549,6 @@ static int imx_tmu_bind(struct udevice *dev)
ofnode node, offset;
const char *name;
const void *prop;
- int minc, maxc;
dev_dbg(dev, "%s\n", __func__);
@@ -548,10 +557,7 @@ static int imx_tmu_bind(struct udevice *dev)
return 0;
pdata->zone_node = 1;
- /* default alert/crit temps based on temp grade */
- get_cpu_temp_grade(&minc, &maxc);
- pdata->critical = maxc * 1000;
- pdata->alert = (maxc - 10) * 1000;
+ imx_tmu_set_trips(pdata);
node = ofnode_path("/thermal-zones");
ofnode_for_each_subnode(offset, node) {
@@ -572,7 +578,7 @@ static int imx_tmu_parse_fdt(struct udevice *dev)
{
struct imx_tmu_plat *pdata = dev_get_plat(dev), *p_parent_data;
struct ofnode_phandle_args args;
- ofnode trips_np, cpu_thermal_np;
+ ofnode cpu_thermal_np;
int ret;
dev_dbg(dev, "%s\n", __func__);
@@ -612,20 +618,7 @@ static int imx_tmu_parse_fdt(struct udevice *dev)
pdata->polling_delay = dev_read_u32_default(dev, "polling-delay",
IMX_TMU_POLLING_DELAY_MS);
- trips_np = ofnode_path("/thermal-zones/cpu-thermal/trips");
- ofnode_for_each_subnode(trips_np, trips_np) {
- const char *type;
-
- type = ofnode_get_property(trips_np, "type", NULL);
- if (!type)
- continue;
- if (!strcmp(type, "critical"))
- pdata->critical = ofnode_read_u32_default(trips_np, "temperature", 85);
- else if (strcmp(type, "passive") == 0)
- pdata->alert = ofnode_read_u32_default(trips_np, "temperature", 80);
- else
- continue;
- }
+ imx_tmu_set_trips(pdata);
dev_dbg(dev, "id %d polling_delay %d, critical %d, alert %d\n",
pdata->id, pdata->polling_delay, pdata->critical, pdata->alert);
diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c
new file mode 100644
index 00000000000..45e590535a0
--- /dev/null
+++ b/drivers/thermal/rcar_gen3_thermal.c
@@ -0,0 +1,467 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * R-Car Gen3/Gen4 and RZ/G2 THS thermal sensor driver
+ * Based on rcar_thermal.c and work from Hien Dang and Khiem Nguyen.
+ *
+ * Copyright (C) 2016 Renesas Electronics Corporation.
+ * Copyright (C) 2016 Sang Engineering
+ */
+
+#include <asm/io.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <linux/delay.h>
+#include <thermal.h>
+
+/* Register offsets */
+#define REG_GEN3_IRQSTR 0x04
+#define REG_GEN3_IRQMSK 0x08
+#define REG_GEN3_IRQCTL 0x0c
+#define REG_GEN3_IRQEN 0x10
+#define REG_GEN3_IRQTEMP1 0x14
+#define REG_GEN3_IRQTEMP2 0x18
+#define REG_GEN3_IRQTEMP3 0x1c
+#define REG_GEN3_THCTR 0x20
+#define REG_GEN3_TEMP 0x28
+#define REG_GEN3_THCODE1 0x50
+#define REG_GEN3_THCODE2 0x54
+#define REG_GEN3_THCODE3 0x58
+#define REG_GEN3_PTAT1 0x5c
+#define REG_GEN3_PTAT2 0x60
+#define REG_GEN3_PTAT3 0x64
+#define REG_GEN3_THSCP 0x68
+#define REG_GEN4_THSFMON00 0x180
+#define REG_GEN4_THSFMON01 0x184
+#define REG_GEN4_THSFMON02 0x188
+#define REG_GEN4_THSFMON15 0x1bc
+#define REG_GEN4_THSFMON16 0x1c0
+#define REG_GEN4_THSFMON17 0x1c4
+
+/* IRQ{STR,MSK,EN} bits */
+#define IRQ_TEMP1 BIT(0)
+#define IRQ_TEMP2 BIT(1)
+#define IRQ_TEMP3 BIT(2)
+#define IRQ_TEMPD1 BIT(3)
+#define IRQ_TEMPD2 BIT(4)
+#define IRQ_TEMPD3 BIT(5)
+
+/* THCTR bits */
+#define THCTR_PONM BIT(6)
+#define THCTR_THSST BIT(0)
+
+/* THSCP bits */
+#define THSCP_COR_PARA_VLD (BIT(15) | BIT(14))
+
+#define CTEMP_MASK 0xfff
+
+#define MCELSIUS(temp) ((temp) * 1000)
+#define GEN3_FUSE_MASK 0xfff
+#define GEN4_FUSE_MASK 0xfff
+
+#define TSC_MAX_NUM 5
+
+struct rcar_gen3_thermal_priv;
+
+struct rcar_gen3_thermal_fuse_info {
+ u32 ptat[3];
+ u32 thcode[3];
+ u32 mask;
+};
+
+struct rcar_gen3_thermal_fuse_default {
+ u32 ptat[3];
+ u32 thcodes[TSC_MAX_NUM][3];
+};
+
+struct rcar_thermal_info {
+ int scale;
+ int adj_below;
+ int adj_above;
+ const struct rcar_gen3_thermal_fuse_info *fuses;
+ const struct rcar_gen3_thermal_fuse_default *fuse_defaults;
+};
+
+struct equation_set_coef {
+ int a;
+ int b;
+};
+
+struct rcar_gen3_thermal_tsc {
+ void __iomem *base;
+ /* Different coefficients are used depending on a threshold. */
+ struct {
+ struct equation_set_coef below;
+ struct equation_set_coef above;
+ } coef;
+ int thcode[3];
+};
+
+struct rcar_gen3_thermal_priv {
+ struct rcar_gen3_thermal_tsc tscs[TSC_MAX_NUM];
+ unsigned int num_tscs;
+ int ptat[3];
+};
+
+static inline u32 rcar_gen3_thermal_read(struct rcar_gen3_thermal_tsc *tsc,
+ u32 reg)
+{
+ return readl(tsc->base + reg);
+}
+
+static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc,
+ u32 reg, u32 data)
+{
+ writel(data, tsc->base + reg);
+}
+
+/*
+ * Linear approximation for temperature
+ *
+ * [temp] = ((thadj - [reg]) * a) / b + adj
+ * [reg] = thadj - ([temp] - adj) * b / a
+ *
+ * The constants a and b are calculated using two triplets of int values PTAT
+ * and THCODE. PTAT and THCODE can either be read from hardware or use hard
+ * coded values from the driver. The formula to calculate a and b are taken from
+ * the datasheet. Different calculations are needed for a and b depending on
+ * if the input variables ([temp] or [reg]) are above or below a threshold. The
+ * threshold is also calculated from PTAT and THCODE using formulas from the
+ * datasheet.
+ *
+ * The constant thadj is one of the THCODE values, which one to use depends on
+ * the threshold and input value.
+ *
+ * The constants adj is taken verbatim from the datasheet. Two values exists,
+ * which one to use depends on the input value and the calculated threshold.
+ * Furthermore different SoC models supported by the driver have different sets
+ * of values. The values for each model are stored in the device match data.
+ */
+static void rcar_gen3_thermal_tsc_coefs(struct udevice *dev,
+ struct rcar_gen3_thermal_tsc *tsc)
+{
+ struct rcar_thermal_info *info = (struct rcar_thermal_info *)dev_get_driver_data(dev);
+ struct rcar_gen3_thermal_priv *priv = dev_get_plat(dev);
+
+ tsc->coef.below.a = info->scale * (priv->ptat[2] - priv->ptat[1]);
+ tsc->coef.above.a = info->scale * (priv->ptat[0] - priv->ptat[1]);
+
+ tsc->coef.below.b = (priv->ptat[2] - priv->ptat[0]) * (tsc->thcode[2] - tsc->thcode[1]);
+ tsc->coef.above.b = (priv->ptat[0] - priv->ptat[2]) * (tsc->thcode[1] - tsc->thcode[0]);
+}
+
+static int rcar_gen3_thermal_get_temp(struct udevice *dev, int *temp)
+{
+ struct rcar_thermal_info *info = (struct rcar_thermal_info *)dev_get_driver_data(dev->parent);
+ struct rcar_gen3_thermal_priv *priv = dev_get_plat(dev->parent);
+ unsigned int tsc_id = dev_get_driver_data(dev);
+ struct rcar_gen3_thermal_tsc *tsc = &(priv->tscs[tsc_id]);
+ const struct equation_set_coef *coef;
+ int adj, decicelsius, reg, thcode;
+
+ /* Read register and convert to millidegree Celsius */
+ reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK;
+
+ if (reg < tsc->thcode[1]) {
+ adj = info->adj_below;
+ coef = &tsc->coef.below;
+ thcode = tsc->thcode[2];
+ } else {
+ adj = info->adj_above;
+ coef = &tsc->coef.above;
+ thcode = tsc->thcode[0];
+ }
+
+ /*
+ * The dividend can't be grown as it might overflow, instead shorten the
+ * divisor to convert to decidegree Celsius. If we convert after the
+ * division precision is lost as we will scale up from whole degrees
+ * Celsius.
+ */
+ decicelsius = DIV_ROUND_CLOSEST(coef->a * (thcode - reg), coef->b / 10);
+
+ /* Guaranteed operating range is -40C to 125C. */
+
+ /* Reporting is done in millidegree Celsius */
+ *temp = decicelsius * 100 + adj * 1000;
+
+ return 0;
+}
+
+static const struct dm_thermal_ops rcar_gen3_thermal_ops = {
+ .get_temp = rcar_gen3_thermal_get_temp,
+};
+
+static void rcar_gen3_thermal_fetch_fuses(struct udevice *dev)
+{
+ struct rcar_thermal_info *info = (struct rcar_thermal_info *)dev_get_driver_data(dev);
+ struct rcar_gen3_thermal_priv *priv = dev_get_plat(dev);
+ const struct rcar_gen3_thermal_fuse_info *fuses = info->fuses;
+
+ /*
+ * Set the pseudo calibration points with fused values.
+ * PTAT is shared between all TSCs but only fused for the first
+ * TSC while THCODEs are fused for each TSC.
+ */
+ priv->ptat[0] = rcar_gen3_thermal_read(&(priv->tscs[0]), fuses->ptat[0])
+ & fuses->mask;
+ priv->ptat[1] = rcar_gen3_thermal_read(&(priv->tscs[0]), fuses->ptat[1])
+ & fuses->mask;
+ priv->ptat[2] = rcar_gen3_thermal_read(&(priv->tscs[0]), fuses->ptat[2])
+ & fuses->mask;
+
+ for (unsigned int i = 0; i < priv->num_tscs; i++) {
+ struct rcar_gen3_thermal_tsc *tsc = &(priv->tscs[i]);
+
+ tsc->thcode[0] = rcar_gen3_thermal_read(tsc, fuses->thcode[0])
+ & fuses->mask;
+ tsc->thcode[1] = rcar_gen3_thermal_read(tsc, fuses->thcode[1])
+ & fuses->mask;
+ tsc->thcode[2] = rcar_gen3_thermal_read(tsc, fuses->thcode[2])
+ & fuses->mask;
+ }
+}
+
+static bool rcar_gen3_thermal_read_fuses(struct udevice *dev)
+{
+ struct rcar_thermal_info *info = (struct rcar_thermal_info *)dev_get_driver_data(dev);
+ struct rcar_gen3_thermal_priv *priv = dev_get_plat(dev);
+ const struct rcar_gen3_thermal_fuse_default *fuse_defaults = info->fuse_defaults;
+ unsigned int i;
+ u32 thscp;
+
+ /* If fuses are not set, fallback to pseudo values. */
+ thscp = rcar_gen3_thermal_read(&(priv->tscs[0]), REG_GEN3_THSCP);
+ if (!info->fuses ||
+ (thscp & THSCP_COR_PARA_VLD) != THSCP_COR_PARA_VLD) {
+ /* Default THCODE values in case FUSEs are not set. */
+ priv->ptat[0] = fuse_defaults->ptat[0];
+ priv->ptat[1] = fuse_defaults->ptat[1];
+ priv->ptat[2] = fuse_defaults->ptat[2];
+
+ for (i = 0; i < priv->num_tscs; i++) {
+ struct rcar_gen3_thermal_tsc *tsc = &(priv->tscs[i]);
+
+ tsc->thcode[0] = fuse_defaults->thcodes[i][0];
+ tsc->thcode[1] = fuse_defaults->thcodes[i][1];
+ tsc->thcode[2] = fuse_defaults->thcodes[i][2];
+ }
+
+ return false;
+ }
+
+ rcar_gen3_thermal_fetch_fuses(dev);
+
+ return true;
+}
+
+static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_priv *priv,
+ struct rcar_gen3_thermal_tsc *tsc)
+{
+ u32 reg_val;
+
+ reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR);
+ reg_val &= ~THCTR_PONM;
+ rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val);
+
+ udelay(1000);
+
+ rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0);
+ rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0);
+
+ reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR);
+ reg_val |= THCTR_THSST;
+ rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val);
+
+ udelay(1000);
+}
+
+static int rcar_gen3_thermal_probe(struct udevice *dev)
+{
+ struct rcar_gen3_thermal_priv *priv = dev_get_plat(dev);
+ unsigned int i;
+
+ if (!rcar_gen3_thermal_read_fuses(dev))
+ dev_dbg(dev, "No calibration values fused, fallback to driver values\n");
+
+ for (i = 0; i < priv->num_tscs; i++) {
+ struct rcar_gen3_thermal_tsc *tsc = &(priv->tscs[i]);
+
+ rcar_gen3_thermal_init(priv, tsc);
+ rcar_gen3_thermal_tsc_coefs(dev, tsc);
+ }
+
+ return 0;
+}
+
+static const struct rcar_gen3_thermal_fuse_info rcar_gen3_thermal_fuse_info_gen3 = {
+ .ptat = { REG_GEN3_PTAT1, REG_GEN3_PTAT2, REG_GEN3_PTAT3 },
+ .thcode = { REG_GEN3_THCODE1, REG_GEN3_THCODE2, REG_GEN3_THCODE3 },
+ .mask = GEN3_FUSE_MASK,
+};
+
+static const struct rcar_gen3_thermal_fuse_info rcar_gen3_thermal_fuse_info_gen4 = {
+ .ptat = { REG_GEN4_THSFMON16, REG_GEN4_THSFMON17, REG_GEN4_THSFMON15 },
+ .thcode = { REG_GEN4_THSFMON01, REG_GEN4_THSFMON02, REG_GEN4_THSFMON00 },
+ .mask = GEN4_FUSE_MASK,
+};
+
+static const struct rcar_gen3_thermal_fuse_default rcar_gen3_thermal_fuse_default_info_gen3 = {
+ .ptat = { 2631, 1509, 435 },
+ .thcodes = {
+ { 3397, 2800, 2221 },
+ { 3393, 2795, 2216 },
+ { 3389, 2805, 2237 },
+ { 3415, 2694, 2195 },
+ { 3356, 2724, 2244 },
+ },
+};
+
+static const struct rcar_gen3_thermal_fuse_default rcar_gen3_thermal_fuse_default_info_v4h = {
+ .ptat = { 3274, 2164, 985 },
+ .thcodes = { /* All four THS units share the same trimming */
+ { 3218, 2617, 1980 },
+ { 3218, 2617, 1980 },
+ { 3218, 2617, 1980 },
+ { 3218, 2617, 1980 },
+ }
+};
+
+static const struct rcar_thermal_info rcar_m3w_thermal_info = {
+ .scale = 157,
+ .adj_below = -41,
+ .adj_above = 116,
+ .fuses = &rcar_gen3_thermal_fuse_info_gen3,
+ .fuse_defaults = &rcar_gen3_thermal_fuse_default_info_gen3,
+};
+
+static const struct rcar_thermal_info rcar_gen3_thermal_info = {
+ .scale = 167,
+ .adj_below = -41,
+ .adj_above = 126,
+ .fuses = &rcar_gen3_thermal_fuse_info_gen3,
+ .fuse_defaults = &rcar_gen3_thermal_fuse_default_info_gen3,
+};
+
+static const struct rcar_thermal_info rcar_gen4_thermal_info = {
+ .scale = 167,
+ .adj_below = -41,
+ .adj_above = 126,
+ .fuses = &rcar_gen3_thermal_fuse_info_gen4,
+ .fuse_defaults = &rcar_gen3_thermal_fuse_default_info_gen3,
+};
+
+static const struct rcar_thermal_info rcar_v4h_thermal_info = {
+ .scale = 167,
+ .adj_below = -41,
+ .adj_above = 126,
+ .fuses = &rcar_gen3_thermal_fuse_info_gen4,
+ .fuse_defaults = &rcar_gen3_thermal_fuse_default_info_v4h,
+};
+
+static const struct udevice_id rcar_gen3_thermal_ids[] = {
+ {
+ .compatible = "renesas,r8a774a1-thermal",
+ .data = (ulong)&rcar_m3w_thermal_info,
+ },
+ {
+ .compatible = "renesas,r8a774b1-thermal",
+ .data = (ulong)&rcar_gen3_thermal_info,
+ },
+ {
+ .compatible = "renesas,r8a774e1-thermal",
+ .data = (ulong)&rcar_gen3_thermal_info,
+ },
+ {
+ .compatible = "renesas,r8a7795-thermal",
+ .data = (ulong)&rcar_gen3_thermal_info,
+ },
+ {
+ .compatible = "renesas,r8a7796-thermal",
+ .data = (ulong)&rcar_m3w_thermal_info,
+ },
+ {
+ .compatible = "renesas,r8a77961-thermal",
+ .data = (ulong)&rcar_m3w_thermal_info,
+ },
+ {
+ .compatible = "renesas,r8a77965-thermal",
+ .data = (ulong)&rcar_gen3_thermal_info,
+ },
+ {
+ .compatible = "renesas,r8a77980-thermal",
+ .data = (ulong)&rcar_gen3_thermal_info,
+ },
+ {
+ .compatible = "renesas,r8a779a0-thermal",
+ .data = (ulong)&rcar_gen3_thermal_info,
+ },
+ {
+ .compatible = "renesas,r8a779f0-thermal",
+ .data = (ulong)&rcar_gen4_thermal_info,
+ },
+ {
+ .compatible = "renesas,r8a779g0-thermal",
+ .data = (ulong)&rcar_v4h_thermal_info,
+ },
+ {
+ .compatible = "renesas,r8a779h0-thermal",
+ .data = (ulong)&rcar_gen4_thermal_info,
+ },
+ { }
+};
+
+U_BOOT_DRIVER(thermal_rcar_gen3_tsc) = {
+ .name = "thermal-rcar-gen3-tsc",
+ .id = UCLASS_THERMAL,
+ .ops = &rcar_gen3_thermal_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+static int rcar_gen3_thermal_bind(struct udevice *dev)
+{
+ /*
+ * We use dev_get_plat() here, because plat data are available
+ * in bind, while private data are not allocated yet.
+ */
+ struct rcar_gen3_thermal_priv *priv = dev_get_plat(dev);
+ struct udevice *tdev;
+ struct driver *tdrv;
+ char name[32];
+ void *addr;
+ int i, ret;
+
+ tdrv = lists_driver_lookup_name("thermal-rcar-gen3-tsc");
+ if (!tdrv)
+ return -ENOENT;
+
+ for (i = 0; i < TSC_MAX_NUM; i++) {
+ addr = dev_read_addr_index_ptr(dev, i);
+ if (!addr)
+ break;
+
+ priv->tscs[i].base = addr;
+
+ tdev = NULL;
+ snprintf(name, sizeof(name), "thermal-rcar-gen3-tsc.%d", i);
+ ret = device_bind_with_driver_data(dev, tdrv, strdup(name), i,
+ dev_ofnode(dev), &tdev);
+ if (ret)
+ return ret;
+ }
+
+ priv->num_tscs = i;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(thermal_rcar_gen3) = {
+ .name = "thermal-rcar-gen3",
+ .id = UCLASS_NOP,
+ .of_match = rcar_gen3_thermal_ids,
+ .bind = rcar_gen3_thermal_bind,
+ .probe = rcar_gen3_thermal_probe,
+ .plat_auto = sizeof(struct rcar_gen3_thermal_priv),
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/thermal/thermal_sandbox.c b/drivers/thermal/thermal_sandbox.c
index b7c567d76cd..2e1f1559e53 100644
--- a/drivers/thermal/thermal_sandbox.c
+++ b/drivers/thermal/thermal_sandbox.c
@@ -12,7 +12,7 @@
static int sandbox_thermal_get_temp(struct udevice *dev, int *temp)
{
/* Simply return 100 deg C */
- *temp = 100;
+ *temp = 100 * 1000;
return 0;
}
diff --git a/drivers/thermal/ti-bandgap.c b/drivers/thermal/ti-bandgap.c
index 0ea17a909dd..dc869f108e4 100644
--- a/drivers/thermal/ti-bandgap.c
+++ b/drivers/thermal/ti-bandgap.c
@@ -163,7 +163,7 @@ static int ti_bandgap_get_temp(struct udevice *dev, int *temp)
struct ti_bandgap *bgp = dev_get_priv(dev);
bgp->adc_val = 0x3ff & readl(bgp->base + CTRL_CORE_TEMP_SENSOR_MPU);
- *temp = dra752_adc_to_temp[bgp->adc_val - DRA752_ADC_START_VALUE];
+ *temp = dra752_adc_to_temp[bgp->adc_val - DRA752_ADC_START_VALUE] * 1000;
return 0;
}
diff --git a/drivers/thermal/ti-lm74.c b/drivers/thermal/ti-lm74.c
index 7d56f75df06..104c27429f4 100644
--- a/drivers/thermal/ti-lm74.c
+++ b/drivers/thermal/ti-lm74.c
@@ -28,7 +28,7 @@ static int ti_lm74_get_temp(struct udevice *dev, int *temp)
raw = ((buf[0] << 8) + buf[1]) >> 3;
- *temp = (((int)raw * 125) + 1000) / 2000;
+ *temp = (((int)raw * 125) + 1000) / 2;
return 0;
}
@@ -44,7 +44,7 @@ static const struct udevice_id of_ti_lm74_match[] = {
{},
};
-U_BOOT_DRIVER(ti_bandgap_thermal) = {
+U_BOOT_DRIVER(ti_lm74_thermal) = {
.name = "ti_lm74_thermal",
.id = UCLASS_THERMAL,
.ops = &ti_lm74_ops,
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index 81c154b378a..f9511503b02 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -147,7 +147,7 @@ config SPL_ATMEL_TCB_TIMER
config CADENCE_TTC_TIMER
bool "Cadence TTC (Triple Timer Counter)"
- depends on TIMER
+ depends on TIMER && ARCH_ZYNQMP_R5
help
Enables support for the cadence ttc driver. This driver is present
on Xilinx Zynq and ZynqMP SoCs.
@@ -312,7 +312,7 @@ config MTK_TIMER
config MCHP_PIT64B_TIMER
bool "Microchip 64-bit periodic interval timer support"
- depends on TIMER
+ depends on TIMER && ARCH_AT91
help
Select this to enable support for Microchip 64-bit periodic
interval timer.
diff --git a/drivers/timer/riscv_aclint_timer.c b/drivers/timer/riscv_aclint_timer.c
index 35da1ea2fd2..175956bcfd3 100644
--- a/drivers/timer/riscv_aclint_timer.c
+++ b/drivers/timer/riscv_aclint_timer.c
@@ -83,6 +83,7 @@ static int riscv_aclint_timer_probe(struct udevice *dev)
static const struct udevice_id riscv_aclint_timer_ids[] = {
{ .compatible = "riscv,clint0", .data = CLINT_MTIME_OFFSET },
{ .compatible = "sifive,clint0", .data = CLINT_MTIME_OFFSET },
+ { .compatible = "sifive,clint2", .data = CLINT_MTIME_OFFSET },
{ .compatible = "riscv,aclint-mtimer", .data = ACLINT_MTIME_OFFSET },
{ }
};
diff --git a/drivers/timer/tegra-timer.c b/drivers/timer/tegra-timer.c
index 3545424889d..778b65b6062 100644
--- a/drivers/timer/tegra-timer.c
+++ b/drivers/timer/tegra-timer.c
@@ -4,6 +4,7 @@
*/
#include <dm.h>
+#include <dm/lists.h>
#include <errno.h>
#include <timer.h>
@@ -106,6 +107,14 @@ static int tegra_timer_probe(struct udevice *dev)
return 0;
}
+static int tegra_timer_bind(struct udevice *dev)
+{
+ if (CONFIG_IS_ENABLED(WDT_TEGRA))
+ return device_bind_driver_to_node(dev, "tegra_wdt", "tegra-wdt",
+ dev_ofnode(dev), NULL);
+ return 0;
+}
+
static const struct timer_ops tegra_timer_ops = {
.get_count = tegra_timer_get_count,
};
@@ -123,6 +132,7 @@ U_BOOT_DRIVER(tegra_timer) = {
.name = "tegra_timer",
.id = UCLASS_TIMER,
.of_match = tegra_timer_ids,
+ .bind = tegra_timer_bind,
.probe = tegra_timer_probe,
.ops = &tegra_timer_ops,
.flags = DM_FLAG_PRE_RELOC,
diff --git a/drivers/tpm/tpm_tis_infineon.c b/drivers/tpm/tpm_tis_infineon.c
index 30f23f8610a..c1e7b98295c 100644
--- a/drivers/tpm/tpm_tis_infineon.c
+++ b/drivers/tpm/tpm_tis_infineon.c
@@ -626,7 +626,7 @@ static const struct udevice_id tpm_tis_i2c_ids[] = {
{ }
};
-U_BOOT_DRIVER(tpm_tis_i2c) = {
+U_BOOT_DRIVER(tpm_tis_infineon) = {
.name = "tpm_tis_infineon",
.id = UCLASS_TPM,
.of_match = tpm_tis_i2c_ids,
diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig
index b08ca08b07c..445270e8da1 100644
--- a/drivers/ufs/Kconfig
+++ b/drivers/ufs/Kconfig
@@ -15,17 +15,6 @@ config CADENCE_UFS
This selects the platform driver for the Cadence UFS host
controller present on present TI's J721e devices.
-config UFS_PCI
- bool "PCI bus based UFS Controller support"
- depends on PCI && UFS
- help
- This selects the PCI UFS Host Controller Interface. Select this if
- you have UFS Host Controller with PCI Interface.
-
- If you have a controller with this interface, say Y here.
-
- If unsure, say N.
-
config QCOM_UFS
bool "Qualcomm Host Controller driver for UFS"
depends on UFS && ARCH_SNAPDRAGON
@@ -33,21 +22,21 @@ config QCOM_UFS
This selects the platform driver for the UFS host
controller present on Qualcomm Snapdragon SoCs.
+config ROCKCHIP_UFS
+ bool "Rockchip specific hooks to UFS controller platform driver"
+ depends on UFS
+ help
+ This selects the Rockchip specific additions to UFSHCD platform driver.
+
+ Select this if you have UFS controller on Rockchip chipset.
+ If unsure, say N.
+
config TI_J721E_UFS
bool "Glue Layer driver for UFS on TI J721E devices"
help
This selects the glue layer driver for Cadence controller
present on TI's J721E devices.
-config UFS_RENESAS
- bool "Renesas specific hooks to UFS controller platform driver"
- depends on UFS
- select BOUNCE_BUFFER
- help
- This selects the Renesas specific additions to UFSHCD platform driver.
- UFS host on Renesas needs some vendor specific configuration before
- accessing the hardware.
-
config UFS_AMD_VERSAL2
bool "AMD Versal Gen 2 UFS controller platform driver"
depends on UFS && ZYNQMP_FIRMWARE
@@ -56,4 +45,47 @@ config UFS_AMD_VERSAL2
UFS host on AMD needs some vendor specific configuration before accessing
the hardware.
+config UFS_MEDIATEK
+ tristate "MediaTek UFS Host Controller Driver"
+ depends on UFS && ARCH_MEDIATEK
+ select PHY_MTK_UFS
+ help
+ This selects the MediaTek specific additions to UFSHCD platform driver.
+ UFS host on Mediatek needs some vendor specific configuration before
+ accessing the hardware which includes PHY configuration and vendor
+ specific registers.
+
+ Select this if you have UFS controller on MediaTek chipset.
+
+ If unsure, say N.
+
+config UFS_PCI
+ bool "PCI bus based UFS Controller support"
+ depends on PCI && UFS
+ help
+ This selects the PCI UFS Host Controller Interface. Select this if
+ you have UFS Host Controller with PCI Interface.
+
+ If you have a controller with this interface, say Y here.
+
+ If unsure, say N.
+
+config UFS_RENESAS
+ bool "Renesas R-Car S4 UFS Controller support"
+ depends on UFS
+ select BOUNCE_BUFFER
+ help
+ This selects the Renesas S4 specific additions to UFSHCD
+ platform driver. UFS host on Renesas needs some vendor
+ specific configuration before accessing the hardware.
+
+config UFS_RENESAS_GEN5
+ bool "Renesas R-Car X5H UFS Controller support"
+ depends on UFS
+ select BOUNCE_BUFFER
+ help
+ This selects the Renesas X5H specific additions to UFSHCD
+ platform driver. UFS host on Renesas needs some vendor
+ specific configuration before accessing the hardware.
+
endmenu
diff --git a/drivers/ufs/Makefile b/drivers/ufs/Makefile
index 2a378e45111..6b2f2ccc9fc 100644
--- a/drivers/ufs/Makefile
+++ b/drivers/ufs/Makefile
@@ -3,10 +3,13 @@
# Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com
#
-obj-$(CONFIG_UFS) += ufs.o ufs-uclass.o
+obj-$(CONFIG_UFS) += ufs-uclass.o
obj-$(CONFIG_CADENCE_UFS) += cdns-platform.o
obj-$(CONFIG_QCOM_UFS) += ufs-qcom.o
+obj-$(CONFIG_ROCKCHIP_UFS) += ufs-rockchip.o
obj-$(CONFIG_TI_J721E_UFS) += ti-j721e-ufs.o
+obj-$(CONFIG_UFS_AMD_VERSAL2) += ufs-amd-versal2.o ufshcd-dwc.o
+obj-$(CONFIG_UFS_MEDIATEK) += ufs-mediatek.o
obj-$(CONFIG_UFS_PCI) += ufs-pci.o
obj-$(CONFIG_UFS_RENESAS) += ufs-renesas.o
-obj-$(CONFIG_UFS_AMD_VERSAL2) += ufs-amd-versal2.o ufshcd-dwc.o
+obj-$(CONFIG_UFS_RENESAS_GEN5) += ufs-renesas-rcar-gen5.o
diff --git a/drivers/ufs/cdns-platform.c b/drivers/ufs/cdns-platform.c
index 510a6a6aa5d..87d9c5bad79 100644
--- a/drivers/ufs/cdns-platform.c
+++ b/drivers/ufs/cdns-platform.c
@@ -101,13 +101,6 @@ static int cdns_ufs_pltfm_probe(struct udevice *dev)
return err;
}
-static int cdns_ufs_pltfm_bind(struct udevice *dev)
-{
- struct udevice *scsi_dev;
-
- return ufs_scsi_bind(dev, &scsi_dev);
-}
-
static const struct udevice_id cdns_ufs_pltfm_ids[] = {
{
.compatible = "cdns,ufshc-m31-16nm",
@@ -120,5 +113,4 @@ U_BOOT_DRIVER(cdns_ufs_pltfm) = {
.id = UCLASS_UFS,
.of_match = cdns_ufs_pltfm_ids,
.probe = cdns_ufs_pltfm_probe,
- .bind = cdns_ufs_pltfm_bind,
};
diff --git a/drivers/ufs/ti-j721e-ufs.c b/drivers/ufs/ti-j721e-ufs.c
index c5c08610ffd..176d9b0e5c3 100644
--- a/drivers/ufs/ti-j721e-ufs.c
+++ b/drivers/ufs/ti-j721e-ufs.c
@@ -17,7 +17,7 @@
static int ti_j721e_ufs_probe(struct udevice *dev)
{
void __iomem *base;
- unsigned int clock;
+ unsigned long clock;
struct clk clk;
u32 reg = 0;
int ret;
@@ -29,9 +29,9 @@ static int ti_j721e_ufs_probe(struct udevice *dev)
}
clock = clk_get_rate(&clk);
- if (IS_ERR_VALUE(clock)) {
+ if ((long)clock <= 0) {
dev_err(dev, "failed to get rate\n");
- return ret;
+ return clock ? clock : -EIO;
}
base = dev_remap_addr_index(dev, 0);
diff --git a/drivers/ufs/ufs-amd-versal2.c b/drivers/ufs/ufs-amd-versal2.c
index 896dda2de4e..bf23439e59d 100644
--- a/drivers/ufs/ufs-amd-versal2.c
+++ b/drivers/ufs/ufs-amd-versal2.c
@@ -330,7 +330,7 @@ static int ufs_versal2_init(struct ufs_hba *hba)
return PTR_ERR(priv->rstphy);
}
- ret = zynqmp_pm_ufs_cal_reg(&cal);
+ ret = zynqmp_pm_ufs_cal_reg(&cal);
if (ret)
return ret;
@@ -552,13 +552,6 @@ static int ufs_versal2_probe(struct udevice *dev)
return ret;
}
-static int ufs_versal2_bind(struct udevice *dev)
-{
- struct udevice *scsi_dev;
-
- return ufs_scsi_bind(dev, &scsi_dev);
-}
-
static const struct udevice_id ufs_versal2_ids[] = {
{
.compatible = "amd,versal2-ufs",
@@ -567,9 +560,8 @@ static const struct udevice_id ufs_versal2_ids[] = {
};
U_BOOT_DRIVER(ufs_versal2_pltfm) = {
- .name = "ufs-versal2-pltfm",
- .id = UCLASS_UFS,
- .of_match = ufs_versal2_ids,
- .probe = ufs_versal2_probe,
- .bind = ufs_versal2_bind,
+ .name = "ufs-versal2-pltfm",
+ .id = UCLASS_UFS,
+ .of_match = ufs_versal2_ids,
+ .probe = ufs_versal2_probe,
};
diff --git a/drivers/ufs/ufs-mediatek-sip.h b/drivers/ufs/ufs-mediatek-sip.h
new file mode 100644
index 00000000000..6a61f7bac69
--- /dev/null
+++ b/drivers/ufs/ufs-mediatek-sip.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2022 MediaTek Inc.
+ * Copyright (c) 2025, Igor Belwon <igor.belwon@mentallysanemainliners.org>
+ *
+ * Slimmed down header from Linux: drivers/ufs/host/ufs-mediatek-sip.h
+ */
+
+#ifndef _UFS_MEDIATEK_SIP_H
+#define _UFS_MEDIATEK_SIP_H
+
+#include <linux/arm-smccc.h>
+
+/*
+ * SiP (Slicon Partner) commands
+ */
+#define MTK_SIP_UFS_CONTROL ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
+ ARM_SMCCC_SMC_64, \
+ ARM_SMCCC_OWNER_SIP, 0x276)
+#define UFS_MTK_SIP_DEVICE_RESET BIT(1)
+#define UFS_MTK_SIP_REF_CLK_NOTIFICATION BIT(3)
+
+/*
+ * SMC call wrapper function
+ */
+struct ufs_mtk_smc_arg {
+ unsigned long cmd;
+ struct arm_smccc_res *res;
+ unsigned long v1;
+ unsigned long v2;
+ unsigned long v3;
+ unsigned long v4;
+ unsigned long v5;
+ unsigned long v6;
+ unsigned long v7;
+};
+
+static inline void _ufs_mtk_smc(struct ufs_mtk_smc_arg s)
+{
+ arm_smccc_smc(MTK_SIP_UFS_CONTROL,
+ s.cmd,
+ s.v1, s.v2, s.v3, s.v4, s.v5, s.v6, s.res);
+}
+
+#define ufs_mtk_smc(...) \
+ _ufs_mtk_smc((struct ufs_mtk_smc_arg) {__VA_ARGS__})
+
+/* SIP interface */
+
+#define ufs_mtk_ref_clk_notify(on, stage, res) \
+ ufs_mtk_smc(UFS_MTK_SIP_REF_CLK_NOTIFICATION, &(res), on, stage)
+
+#define ufs_mtk_device_reset_ctrl(high, res) \
+ ufs_mtk_smc(UFS_MTK_SIP_DEVICE_RESET, &(res), high)
+
+#endif /* !_UFS_MEDIATEK_SIP_H */
diff --git a/drivers/ufs/ufs-mediatek.c b/drivers/ufs/ufs-mediatek.c
new file mode 100644
index 00000000000..e860d765eea
--- /dev/null
+++ b/drivers/ufs/ufs-mediatek.c
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2025, Igor Belwon <igor.belwon@mentallysanemainliners.org>
+ *
+ * Loosely based on Linux driver: drivers/ufs/host/ufs-mediatek.c
+ */
+
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <generic-phy.h>
+#include <ufs.h>
+#include <asm/gpio.h>
+#include <reset.h>
+
+#include <linux/arm-smccc.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#include "ufs.h"
+#include "ufs-mediatek.h"
+#include "ufs-mediatek-sip.h"
+
+static void ufs_mtk_advertise_quirks(struct ufs_hba *hba)
+{
+ hba->quirks |= UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL |
+ UFSHCD_QUIRK_MCQ_BROKEN_INTR |
+ UFSHCD_QUIRK_BROKEN_LSDBS_CAP;
+}
+
+static int ufs_mtk_hce_enable_notify(struct ufs_hba *hba,
+ enum ufs_notify_change_status status)
+{
+ struct ufs_mtk_host *host = dev_get_priv(hba->dev);
+
+ if (status == PRE_CHANGE) {
+ if (host->caps & UFS_MTK_CAP_DISABLE_AH8) {
+ ufshcd_writel(hba, 0,
+ REG_AUTO_HIBERNATE_IDLE_TIMER);
+ hba->capabilities &= ~MASK_AUTO_HIBERN8_SUPPORT;
+ }
+
+ /*
+ * Turn on CLK_CG early to bypass abnormal ERR_CHK signal
+ * to prevent host hang issue
+ */
+ ufshcd_writel(hba,
+ ufshcd_readl(hba, REG_UFS_XOUFS_CTRL) | 0x80,
+ REG_UFS_XOUFS_CTRL);
+
+ /* DDR_EN setting */
+ if (host->ip_ver >= IP_VER_MT6989) {
+ ufshcd_rmwl(hba, UFS_MASK(0x7FFF, 8),
+ 0x453000, REG_UFS_MMIO_OPT_CTRL_0);
+ }
+ }
+
+ return 0;
+}
+
+static int ufs_mtk_unipro_set_lpm(struct ufs_hba *hba, bool lpm)
+{
+ int ret;
+ struct ufs_mtk_host *host = dev_get_priv(hba->dev);
+
+ ret = ufshcd_dme_set(hba,
+ UIC_ARG_MIB_SEL(VS_UNIPROPOWERDOWNCONTROL, 0),
+ lpm ? 1 : 0);
+ if (!ret || !lpm) {
+ /*
+ * Forcibly set as non-LPM mode if UIC commands is failed
+ * to use default hba_enable_delay_us value for re-enabling
+ * the host.
+ */
+ host->unipro_lpm = lpm;
+ }
+
+ return ret;
+}
+
+static int ufs_mtk_pre_link(struct ufs_hba *hba)
+{
+ int ret;
+ u32 tmp;
+
+ ret = ufs_mtk_unipro_set_lpm(hba, false);
+ if (ret)
+ return ret;
+
+ /*
+ * Setting PA_Local_TX_LCC_Enable to 0 before link startup
+ * to make sure that both host and device TX LCC are disabled
+ * once link startup is completed.
+ */
+ ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0);
+ if (ret)
+ return ret;
+
+ /* disable deep stall */
+ ret = ufshcd_dme_get(hba, UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp);
+ if (ret)
+ return ret;
+
+ tmp &= ~(1 << 6);
+
+ ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp);
+ if (ret)
+ return ret;
+
+ ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_SCRAMBLING), tmp);
+
+ return ret;
+}
+
+static void ufs_mtk_cfg_unipro_cg(struct ufs_hba *hba, bool enable)
+{
+ u32 tmp;
+
+ if (enable) {
+ ufshcd_dme_get(hba,
+ UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp);
+ tmp = tmp |
+ (1 << RX_SYMBOL_CLK_GATE_EN) |
+ (1 << SYS_CLK_GATE_EN) |
+ (1 << TX_CLK_GATE_EN);
+ ufshcd_dme_set(hba,
+ UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp);
+
+ ufshcd_dme_get(hba,
+ UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), &tmp);
+ tmp = tmp & ~(1 << TX_SYMBOL_CLK_REQ_FORCE);
+ ufshcd_dme_set(hba,
+ UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), tmp);
+ } else {
+ ufshcd_dme_get(hba,
+ UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp);
+ tmp = tmp & ~((1 << RX_SYMBOL_CLK_GATE_EN) |
+ (1 << SYS_CLK_GATE_EN) |
+ (1 << TX_CLK_GATE_EN));
+ ufshcd_dme_set(hba,
+ UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp);
+
+ ufshcd_dme_get(hba,
+ UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), &tmp);
+ tmp = tmp | (1 << TX_SYMBOL_CLK_REQ_FORCE);
+ ufshcd_dme_set(hba,
+ UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), tmp);
+ }
+}
+
+static void ufs_mtk_post_link(struct ufs_hba *hba)
+{
+ /* enable unipro clock gating feature */
+ ufs_mtk_cfg_unipro_cg(hba, true);
+}
+
+static int ufs_mtk_link_startup_notify(struct ufs_hba *hba,
+ enum ufs_notify_change_status status)
+{
+ int ret = 0;
+
+ switch (status) {
+ case PRE_CHANGE:
+ ret = ufs_mtk_pre_link(hba);
+ break;
+ case POST_CHANGE:
+ ufs_mtk_post_link(hba);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int ufs_mtk_bind_mphy(struct ufs_hba *hba)
+{
+ struct ufs_mtk_host *host = dev_get_priv(hba->dev);
+ int err = 0;
+
+ err = generic_phy_get_by_index(hba->dev, 0, host->mphy);
+
+ if (IS_ERR(host->mphy)) {
+ err = PTR_ERR(host->mphy);
+ if (err != -ENODEV) {
+ dev_info(hba->dev, "%s: Could NOT get a valid PHY %d\n", __func__,
+ err);
+ }
+ }
+
+ if (err)
+ host->mphy = NULL;
+
+ return err;
+}
+
+static void ufs_mtk_init_reset_control(struct ufs_hba *hba,
+ struct reset_ctl **rc,
+ char *str)
+{
+ *rc = devm_reset_control_get(hba->dev, str);
+ if (IS_ERR(*rc)) {
+ dev_info(hba->dev, "Failed to get reset control %s: %ld\n",
+ str, PTR_ERR(*rc));
+ *rc = NULL;
+ }
+}
+
+static void ufs_mtk_init_reset(struct ufs_hba *hba)
+{
+ struct ufs_mtk_host *host = dev_get_priv(hba->dev);
+
+ ufs_mtk_init_reset_control(hba, &host->hci_reset,
+ "hci_rst");
+ ufs_mtk_init_reset_control(hba, &host->unipro_reset,
+ "unipro_rst");
+ ufs_mtk_init_reset_control(hba, &host->crypto_reset,
+ "crypto_rst");
+}
+
+static void ufs_mtk_get_hw_ip_version(struct ufs_hba *hba)
+{
+ struct ufs_mtk_host *host = dev_get_priv(hba->dev);
+ u32 hw_ip_ver;
+
+ hw_ip_ver = ufshcd_readl(hba, REG_UFS_MTK_IP_VER);
+
+ if (((hw_ip_ver & (0xFF << 24)) == (0x1 << 24)) ||
+ ((hw_ip_ver & (0xFF << 24)) == 0)) {
+ hw_ip_ver &= ~(0xFF << 24);
+ hw_ip_ver |= (0x1 << 28);
+ }
+
+ host->ip_ver = hw_ip_ver;
+
+ dev_info(hba->dev, "MediaTek UFS IP Version: 0x%x\n", hw_ip_ver);
+}
+
+static int ufs_mtk_setup_ref_clk(struct ufs_hba *hba, bool on)
+{
+ struct ufs_mtk_host *host = dev_get_priv(hba->dev);
+ struct arm_smccc_res res;
+ int timeout, time_checked = 0;
+ u32 value;
+
+ if (host->ref_clk_enabled == on)
+ return 0;
+
+ ufs_mtk_ref_clk_notify(on, PRE_CHANGE, res);
+
+ if (on) {
+ ufshcd_writel(hba, REFCLK_REQUEST, REG_UFS_REFCLK_CTRL);
+ } else {
+ udelay(10);
+ ufshcd_writel(hba, REFCLK_RELEASE, REG_UFS_REFCLK_CTRL);
+ }
+
+ /* Wait for ack */
+ timeout = REFCLK_REQ_TIMEOUT_US;
+ do {
+ value = ufshcd_readl(hba, REG_UFS_REFCLK_CTRL);
+
+ /* Wait until ack bit equals to req bit */
+ if (((value & REFCLK_ACK) >> 1) == (value & REFCLK_REQUEST))
+ goto out;
+
+ udelay(200);
+ time_checked += 200;
+ } while (time_checked != timeout);
+
+ dev_err(hba->dev, "missing ack of refclk req, reg: 0x%x\n", value);
+
+ /*
+ * If clock on timeout, assume clock is off, notify tfa do clock
+ * off setting.(keep DIFN disable, release resource)
+ * If clock off timeout, assume clock will off finally,
+ * set ref_clk_enabled directly.(keep DIFN disable, keep resource)
+ */
+ if (on)
+ ufs_mtk_ref_clk_notify(false, POST_CHANGE, res);
+ else
+ host->ref_clk_enabled = false;
+
+ return -ETIMEDOUT;
+
+out:
+ host->ref_clk_enabled = on;
+ if (on)
+ udelay(10);
+
+ ufs_mtk_ref_clk_notify(on, POST_CHANGE, res);
+
+ return 0;
+}
+
+/**
+ * ufs_mtk_init - bind phy with controller
+ * @hba: host controller instance
+ *
+ * Powers up PHY enabling clocks and regulators.
+ *
+ * Returns -ENODEV if binding fails, returns negative error
+ * on phy power up failure and returns zero on success.
+ */
+static int ufs_mtk_init(struct ufs_hba *hba)
+{
+ struct ufs_mtk_host *priv = dev_get_priv(hba->dev);
+ int err;
+
+ priv->hba = hba;
+
+ err = ufs_mtk_bind_mphy(hba);
+ if (err)
+ return -ENODEV;
+
+ ufs_mtk_advertise_quirks(hba);
+
+ ufs_mtk_init_reset(hba);
+
+ // TODO: Clocking
+
+ err = generic_phy_power_on(priv->mphy);
+ if (err) {
+ dev_err(hba->dev, "%s: phy init failed, err = %d\n",
+ __func__, err);
+ return err;
+ }
+
+ ufs_mtk_setup_ref_clk(hba, true);
+ ufs_mtk_get_hw_ip_version(hba);
+
+ return 0;
+}
+
+static int ufs_mtk_device_reset(struct ufs_hba *hba)
+{
+ struct arm_smccc_res res;
+
+ ufs_mtk_device_reset_ctrl(0, res);
+
+ /*
+ * The reset signal is active low. UFS devices shall detect
+ * more than or equal to 1us of positive or negative RST_n
+ * pulse width.
+ *
+ * To be on safe side, keep the reset low for at least 10us.
+ */
+ udelay(13);
+
+ ufs_mtk_device_reset_ctrl(1, res);
+
+ /* Some devices may need time to respond to rst_n */
+ mdelay(13);
+
+ dev_dbg(hba->dev, "device reset done\n");
+
+ return 0;
+}
+
+static struct ufs_hba_ops ufs_mtk_hba_ops = {
+ .init = ufs_mtk_init,
+ .hce_enable_notify = ufs_mtk_hce_enable_notify,
+ .link_startup_notify = ufs_mtk_link_startup_notify,
+ .device_reset = ufs_mtk_device_reset,
+};
+
+static int ufs_mtk_probe(struct udevice *dev)
+{
+ int ret;
+
+ ret = ufshcd_probe(dev, &ufs_mtk_hba_ops);
+ if (ret) {
+ dev_err(dev, "ufshcd_probe() failed, ret:%d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id ufs_mtk_ids[] = {
+ { .compatible = "mediatek,mt6878-ufshci" },
+ {},
+};
+
+U_BOOT_DRIVER(mediatek_ufshci) = {
+ .name = "mediatek-ufshci",
+ .id = UCLASS_UFS,
+ .of_match = ufs_mtk_ids,
+ .probe = ufs_mtk_probe,
+ .priv_auto = sizeof(struct ufs_mtk_host),
+};
diff --git a/drivers/ufs/ufs-mediatek.h b/drivers/ufs/ufs-mediatek.h
new file mode 100644
index 00000000000..11a83d34c5b
--- /dev/null
+++ b/drivers/ufs/ufs-mediatek.h
@@ -0,0 +1,210 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 MediaTek Inc.
+ * Copyright (c) 2025, Igor Belwon <igor.belwon@mentallysanemainliners.org>
+ *
+ * Slimmed down header from Linux: drivers/ufs/host/ufs-mediatek.h
+ */
+
+#ifndef _UFS_MEDIATEK_H
+#define _UFS_MEDIATEK_H
+
+#include <clk.h>
+#include <linux/bitops.h>
+
+/*
+ * MCQ define and struct
+ */
+#define UFSHCD_MAX_Q_NR 8
+#define MTK_MCQ_INVALID_IRQ 0xFFFF
+
+/* REG_UFS_MMIO_OPT_CTRL_0 160h */
+#define EHS_EN BIT(0)
+#define PFM_IMPV BIT(1)
+#define MCQ_MULTI_INTR_EN BIT(2)
+#define MCQ_CMB_INTR_EN BIT(3)
+#define MCQ_AH8 BIT(4)
+
+#define MCQ_INTR_EN_MSK (MCQ_MULTI_INTR_EN | MCQ_CMB_INTR_EN)
+
+/*
+ * Vendor specific UFSHCI Registers
+ */
+#define REG_UFS_XOUFS_CTRL 0x140
+#define REG_UFS_REFCLK_CTRL 0x144
+#define REG_UFS_MMIO_OPT_CTRL_0 0x160
+#define REG_UFS_EXTREG 0x2100
+#define REG_UFS_MPHYCTRL 0x2200
+#define REG_UFS_MTK_IP_VER 0x2240
+#define REG_UFS_REJECT_MON 0x22AC
+#define REG_UFS_DEBUG_SEL 0x22C0
+#define REG_UFS_PROBE 0x22C8
+#define REG_UFS_DEBUG_SEL_B0 0x22D0
+#define REG_UFS_DEBUG_SEL_B1 0x22D4
+#define REG_UFS_DEBUG_SEL_B2 0x22D8
+#define REG_UFS_DEBUG_SEL_B3 0x22DC
+
+#define REG_UFS_MTK_SQD 0x2800
+#define REG_UFS_MTK_SQIS 0x2814
+#define REG_UFS_MTK_CQD 0x281C
+#define REG_UFS_MTK_CQIS 0x2824
+
+#define REG_UFS_MCQ_STRIDE 0x30
+
+/*
+ * Ref-clk control
+ *
+ * Values for register REG_UFS_REFCLK_CTRL
+ */
+#define REFCLK_RELEASE 0x0
+#define REFCLK_REQUEST BIT(0)
+#define REFCLK_ACK BIT(1)
+
+#define REFCLK_REQ_TIMEOUT_US 3000
+#define REFCLK_DEFAULT_WAIT_US 32
+
+/*
+ * Other attributes
+ */
+#define VS_DEBUGCLOCKENABLE 0xD0A1
+#define VS_SAVEPOWERCONTROL 0xD0A6
+#define VS_UNIPROPOWERDOWNCONTROL 0xD0A8
+
+/*
+ * Vendor specific link state
+ */
+enum {
+ VS_LINK_DISABLED = 0,
+ VS_LINK_DOWN = 1,
+ VS_LINK_UP = 2,
+ VS_LINK_HIBERN8 = 3,
+ VS_LINK_LOST = 4,
+ VS_LINK_CFG = 5,
+};
+
+/*
+ * Vendor specific host controller state
+ */
+enum {
+ VS_HCE_RESET = 0,
+ VS_HCE_BASE = 1,
+ VS_HCE_OOCPR_WAIT = 2,
+ VS_HCE_DME_RESET = 3,
+ VS_HCE_MIDDLE = 4,
+ VS_HCE_DME_ENABLE = 5,
+ VS_HCE_DEFAULTS = 6,
+ VS_HIB_IDLEEN = 7,
+ VS_HIB_ENTER = 8,
+ VS_HIB_ENTER_CONF = 9,
+ VS_HIB_MIDDLE = 10,
+ VS_HIB_WAITTIMER = 11,
+ VS_HIB_EXIT_CONF = 12,
+ VS_HIB_EXIT = 13,
+};
+
+/*
+ * VS_DEBUGCLOCKENABLE
+ */
+enum {
+ TX_SYMBOL_CLK_REQ_FORCE = 5,
+};
+
+/*
+ * VS_SAVEPOWERCONTROL
+ */
+enum {
+ RX_SYMBOL_CLK_GATE_EN = 0,
+ SYS_CLK_GATE_EN = 2,
+ TX_CLK_GATE_EN = 3,
+};
+
+/*
+ * Host capability
+ */
+enum ufs_mtk_host_caps {
+ UFS_MTK_CAP_BOOST_CRYPT_ENGINE = 1 << 0,
+ UFS_MTK_CAP_VA09_PWR_CTRL = 1 << 1,
+ UFS_MTK_CAP_DISABLE_AH8 = 1 << 2,
+ UFS_MTK_CAP_BROKEN_VCC = 1 << 3,
+
+ /*
+ * Override UFS_MTK_CAP_BROKEN_VCC's behavior to
+ * allow vccqx upstream to enter LPM
+ */
+ UFS_MTK_CAP_ALLOW_VCCQX_LPM = 1 << 5,
+ UFS_MTK_CAP_PMC_VIA_FASTAUTO = 1 << 6,
+ UFS_MTK_CAP_TX_SKEW_FIX = 1 << 7,
+ UFS_MTK_CAP_DISABLE_MCQ = 1 << 8,
+ /* Control MTCMOS with RTFF */
+ UFS_MTK_CAP_RTFF_MTCMOS = 1 << 9,
+
+ UFS_MTK_CAP_MCQ_BROKEN_RTC = 1 << 10,
+};
+
+struct ufs_mtk_hw_ver {
+ u8 step;
+ u8 minor;
+ u8 major;
+};
+
+struct ufs_mtk_mcq_intr_info {
+ struct ufs_hba *hba;
+ u32 irq;
+ u8 qid;
+};
+
+struct ufs_mtk_host {
+ struct phy *mphy;
+ struct reset_ctl *unipro_reset;
+ struct reset_ctl *crypto_reset;
+ struct reset_ctl *hci_reset;
+ struct ufs_hba *hba;
+ struct ufs_mtk_crypt_cfg *crypt;
+ struct clk_bulk clks;
+ struct ufs_mtk_hw_ver hw_ver;
+ enum ufs_mtk_host_caps caps;
+ bool mphy_powered_on;
+ bool unipro_lpm;
+ bool ref_clk_enabled;
+ bool is_clks_enabled;
+ u16 ref_clk_ungating_wait_us;
+ u16 ref_clk_gating_wait_us;
+ u32 ip_ver;
+ bool legacy_ip_ver;
+
+ bool mcq_set_intr;
+ bool is_mcq_intr_enabled;
+ int mcq_nr_intr;
+ struct ufs_mtk_mcq_intr_info mcq_intr_info[UFSHCD_MAX_Q_NR];
+};
+
+/* MTK delay of autosuspend: 500 ms */
+#define MTK_RPM_AUTOSUSPEND_DELAY_MS 500
+
+/* MTK RTT support number */
+#define MTK_MAX_NUM_RTT 2
+
+/* UFSHCI MTK ip version value */
+enum {
+ /* UFSHCI 3.1 */
+ IP_VER_MT6983 = 0x10360000,
+ IP_VER_MT6878 = 0x10420200,
+
+ /* UFSHCI 4.0 */
+ IP_VER_MT6897 = 0x10440000,
+ IP_VER_MT6989 = 0x10450000,
+ IP_VER_MT6899 = 0x10450100,
+ IP_VER_MT6991_A0 = 0x10460000,
+ IP_VER_MT6991_B0 = 0x10470000,
+ IP_VER_MT6993 = 0x10480000,
+
+ IP_VER_NONE = 0xFFFFFFFF
+};
+
+enum ip_ver_legacy {
+ IP_LEGACY_VER_MT6781 = 0x10380000,
+ IP_LEGACY_VER_MT6879 = 0x10360000,
+ IP_LEGACY_VER_MT6893 = 0x20160706
+};
+
+#endif /* !_UFS_MEDIATEK_H */
diff --git a/drivers/ufs/ufs-pci.c b/drivers/ufs/ufs-pci.c
index 871f3f50f5c..5b9c72a695d 100644
--- a/drivers/ufs/ufs-pci.c
+++ b/drivers/ufs/ufs-pci.c
@@ -11,13 +11,6 @@
#include <dm/device_compat.h>
#include "ufs.h"
-static int ufs_pci_bind(struct udevice *dev)
-{
- struct udevice *scsi_dev;
-
- return ufs_scsi_bind(dev, &scsi_dev);
-}
-
static int ufs_pci_probe(struct udevice *dev)
{
int err;
@@ -32,7 +25,6 @@ static int ufs_pci_probe(struct udevice *dev)
U_BOOT_DRIVER(ufs_pci) = {
.name = "ufs_pci",
.id = UCLASS_UFS,
- .bind = ufs_pci_bind,
.probe = ufs_pci_probe,
};
diff --git a/drivers/ufs/ufs-qcom.c b/drivers/ufs/ufs-qcom.c
index 843585726c7..9f0a6940d98 100644
--- a/drivers/ufs/ufs-qcom.c
+++ b/drivers/ufs/ufs-qcom.c
@@ -648,13 +648,6 @@ static int ufs_qcom_probe(struct udevice *dev)
return 0;
}
-static int ufs_qcom_bind(struct udevice *dev)
-{
- struct udevice *scsi_dev;
-
- return ufs_scsi_bind(dev, &scsi_dev);
-}
-
static const struct udevice_id ufs_qcom_ids[] = {
{ .compatible = "qcom,ufshc" },
{},
@@ -665,6 +658,5 @@ U_BOOT_DRIVER(qcom_ufshcd) = {
.id = UCLASS_UFS,
.of_match = ufs_qcom_ids,
.probe = ufs_qcom_probe,
- .bind = ufs_qcom_bind,
.priv_auto = sizeof(struct ufs_qcom_priv),
};
diff --git a/drivers/ufs/ufs-renesas-rcar-gen5.c b/drivers/ufs/ufs-renesas-rcar-gen5.c
new file mode 100644
index 00000000000..cc53e91449c
--- /dev/null
+++ b/drivers/ufs/ufs-renesas-rcar-gen5.c
@@ -0,0 +1,268 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Renesas UFS host controller driver
+ *
+ * Copyright (C) 2025 Renesas Electronics Corporation
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <ufs.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/iopoll.h>
+#include <reset.h>
+
+#include "ufs.h"
+
+#define UFS_RENESAS_TIMEOUT_US 100000
+
+struct ufs_renesas_priv {
+ struct clk_bulk clks;
+ struct reset_ctl_bulk resets;
+ fdt_addr_t phy_base;
+ /* The hardware needs initialization once */
+ bool initialized;
+};
+
+static void ufs_dme_command(struct ufs_hba *hba, u32 cmd,
+ u32 arg1, u32 arg2, u32 arg3)
+{
+ ufshcd_writel(hba, arg1, REG_UIC_COMMAND_ARG_1);
+ ufshcd_writel(hba, arg2, REG_UIC_COMMAND_ARG_2);
+ ufshcd_writel(hba, arg3, REG_UIC_COMMAND_ARG_3);
+ ufshcd_writel(hba, cmd, REG_UIC_COMMAND);
+}
+
+static int ufs_renesas_pre_init(struct ufs_hba *hba)
+{
+ struct ufs_renesas_priv *priv = dev_get_priv(hba->dev);
+ u32 val32;
+ u16 val16;
+ int ret;
+
+ writew(0x0001, priv->phy_base + 0x20000);
+ writew(0x005c, priv->phy_base + 0x20212);
+ writew(0x005c, priv->phy_base + 0x20214);
+ writew(0x005c, priv->phy_base + 0x20216);
+ writew(0x005c, priv->phy_base + 0x20218);
+ writew(0x036a, priv->phy_base + 0x201d0);
+ writew(0x0102, priv->phy_base + 0x201d2);
+ writew(0x001f, priv->phy_base + 0x20082);
+ writew(0x000b, priv->phy_base + 0x20084);
+ writew(0x0126, priv->phy_base + 0x201d2);
+ writew(0x01dc, priv->phy_base + 0x20214);
+ writew(0x01dc, priv->phy_base + 0x20218);
+ writew(0x0000, priv->phy_base + 0x201cc);
+ writew(0x0200, priv->phy_base + 0x201ce);
+ writew(0x0000, priv->phy_base + 0x20212);
+ writew(0x0000, priv->phy_base + 0x20216);
+
+ ret = readw_poll_timeout(priv->phy_base + 0x201ec, val16,
+ !(val16 & BIT(12)), UFS_RENESAS_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ ret = readw_poll_timeout(priv->phy_base + 0x201e4, val16,
+ !(val16 & BIT(12)), UFS_RENESAS_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ ret = readw_poll_timeout(priv->phy_base + 0x201f0, val16,
+ !(val16 & BIT(12)), UFS_RENESAS_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ writew(0x0000, priv->phy_base + 0x20000);
+
+ ufshcd_writel(hba, BIT(0), REG_CONTROLLER_ENABLE);
+
+ ret = read_poll_timeout(ufshcd_readl, val32, (val32 & BIT(0)),
+ 1, UFS_RENESAS_TIMEOUT_US,
+ hba, REG_CONTROLLER_ENABLE);
+ if (ret)
+ return ret;
+
+ ret = read_poll_timeout(ufshcd_readl, val32, (val32 & BIT(3)),
+ 1, UFS_RENESAS_TIMEOUT_US,
+ hba, REG_CONTROLLER_STATUS);
+ if (ret)
+ return ret;
+
+ /* Skip IE because we cannot handle interrupts here */
+ ufs_dme_command(hba, 0x00000002, 0x81010000, 0x00000000, 0x00000005);
+ ufs_dme_command(hba, 0x00000002, 0x81150000, 0x00000000, 0x00000001);
+ ufs_dme_command(hba, 0x00000002, 0x81180000, 0x00000000, 0x00000001);
+ ufs_dme_command(hba, 0x00000002, 0x80090000, 0x00000000, 0x00000000);
+ ufs_dme_command(hba, 0x00000002, 0x800a0000, 0x00000000, 0x000000c8);
+ ufs_dme_command(hba, 0x00000002, 0x80090001, 0x00000000, 0x00000000);
+ ufs_dme_command(hba, 0x00000002, 0x800a0001, 0x00000000, 0x000000c8);
+ ufs_dme_command(hba, 0x00000002, 0x800a0004, 0x00000000, 0x00000000);
+ ufs_dme_command(hba, 0x00000002, 0x800b0004, 0x00000000, 0x00000064);
+ ufs_dme_command(hba, 0x00000002, 0x800a0005, 0x00000000, 0x00000000);
+ ufs_dme_command(hba, 0x00000002, 0x800b0005, 0x00000000, 0x00000064);
+ ufs_dme_command(hba, 0x00000002, 0xd0850000, 0x00000000, 0x00000001);
+
+ writew(0x0001, priv->phy_base + 0x20000);
+
+ clrbits_le16(priv->phy_base + 0x20022, BIT(0));
+
+ ret = readw_poll_timeout(priv->phy_base + (0x00198 << 1), val16,
+ (val16 & BIT(0)), UFS_RENESAS_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ writew(0x0368, priv->phy_base + 0x201d0);
+
+ ret = readw_poll_timeout(priv->phy_base + 0x201e4, val16,
+ !(val16 & BIT(11)), UFS_RENESAS_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ ret = readw_poll_timeout(priv->phy_base + 0x201e8, val16,
+ !(val16 & BIT(11)), UFS_RENESAS_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ ret = readw_poll_timeout(priv->phy_base + 0x201ec, val16,
+ !(val16 & BIT(11)), UFS_RENESAS_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ ret = readw_poll_timeout(priv->phy_base + 0x201f0, val16,
+ !(val16 & BIT(11)), UFS_RENESAS_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ priv->initialized = true;
+
+ return 0;
+}
+
+static int ufs_renesas_init(struct ufs_hba *hba)
+{
+ hba->quirks |= UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS | UFSHCD_QUIRK_HIBERN_FASTAUTO |
+ UFSHCD_QUIRK_BROKEN_LCC;
+
+ return 0;
+}
+
+static int ufs_renesas_hce_enable_notify(struct ufs_hba *hba,
+ enum ufs_notify_change_status status)
+{
+ struct ufs_renesas_priv *priv = dev_get_priv(hba->dev);
+ int ret;
+
+ if (priv->initialized)
+ return 0;
+
+ if (status == PRE_CHANGE) {
+ ret = ufs_renesas_pre_init(hba);
+ if (ret)
+ return ret;
+ }
+
+ priv->initialized = true;
+
+ return 0;
+}
+
+static int ufs_renesas_link_startup_notify(struct ufs_hba *hba,
+ enum ufs_notify_change_status status)
+{
+ if (status == PRE_CHANGE)
+ return ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0);
+
+ return 0;
+}
+
+static int ufs_renesas_get_max_pwr_mode(struct ufs_hba *hba,
+ struct ufs_pwr_mode_info *max_pwr_info)
+{
+ max_pwr_info->info.gear_rx = UFS_HS_G5;
+ max_pwr_info->info.gear_tx = UFS_HS_G5;
+ max_pwr_info->info.pwr_tx = FASTAUTO_MODE;
+ max_pwr_info->info.pwr_rx = FASTAUTO_MODE;
+ max_pwr_info->info.hs_rate = PA_HS_MODE_A;
+
+ max_pwr_info->info.lane_rx = 1;
+ max_pwr_info->info.lane_tx = 1;
+
+ dev_info(hba->dev, "Max HS Gear: %d\n", max_pwr_info->info.gear_rx);
+
+ return 0;
+}
+
+static struct ufs_hba_ops ufs_renesas_vops = {
+ .init = ufs_renesas_init,
+ .hce_enable_notify = ufs_renesas_hce_enable_notify,
+ .link_startup_notify = ufs_renesas_link_startup_notify,
+ .get_max_pwr_mode = ufs_renesas_get_max_pwr_mode,
+};
+
+static int ufs_renesas_pltfm_probe(struct udevice *dev)
+{
+ struct ufs_renesas_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->phy_base = dev_read_addr_name(dev, "phy");
+ if (priv->phy_base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ ret = reset_get_bulk(dev, &priv->resets);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_get_bulk(dev, &priv->clks);
+ if (ret < 0)
+ goto err_clk_get;
+
+ ret = clk_enable_bulk(&priv->clks);
+ if (ret)
+ goto err_clk_enable;
+
+ reset_assert_bulk(&priv->resets);
+ reset_deassert_bulk(&priv->resets);
+
+ ret = ufshcd_probe(dev, &ufs_renesas_vops);
+ if (ret) {
+ dev_err(dev, "ufshcd_probe() failed %d\n", ret);
+ goto err_ufshcd_probe;
+ }
+
+ return 0;
+
+err_ufshcd_probe:
+ reset_assert_bulk(&priv->resets);
+ clk_disable_bulk(&priv->clks);
+err_clk_enable:
+ clk_release_bulk(&priv->clks);
+err_clk_get:
+ reset_release_bulk(&priv->resets);
+ return ret;
+}
+
+static int ufs_renesas_pltfm_remove(struct udevice *dev)
+{
+ struct ufs_renesas_priv *priv = dev_get_priv(dev);
+
+ reset_release_bulk(&priv->resets);
+ clk_disable_bulk(&priv->clks);
+ clk_release_bulk(&priv->clks);
+
+ return 0;
+}
+
+static const struct udevice_id ufs_renesas_pltfm_ids[] = {
+ { .compatible = "renesas,r8a78000-ufs" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(ufs_renesas_gen5) = {
+ .name = "ufs-renesas-gen5",
+ .id = UCLASS_UFS,
+ .of_match = ufs_renesas_pltfm_ids,
+ .probe = ufs_renesas_pltfm_probe,
+ .remove = ufs_renesas_pltfm_remove,
+ .priv_auto = sizeof(struct ufs_renesas_priv),
+};
diff --git a/drivers/ufs/ufs-renesas.c b/drivers/ufs/ufs-renesas.c
index ae05bdc8102..0b74b39dc2a 100644
--- a/drivers/ufs/ufs-renesas.c
+++ b/drivers/ufs/ufs-renesas.c
@@ -351,13 +351,6 @@ static struct ufs_hba_ops ufs_renesas_vops = {
.hce_enable_notify = ufs_renesas_hce_enable_notify,
};
-static int ufs_renesas_pltfm_bind(struct udevice *dev)
-{
- struct udevice *scsi_dev;
-
- return ufs_scsi_bind(dev, &scsi_dev);
-}
-
static int ufs_renesas_pltfm_probe(struct udevice *dev)
{
struct ufs_renesas_priv *priv = dev_get_priv(dev);
@@ -405,7 +398,6 @@ U_BOOT_DRIVER(ufs_renesas) = {
.name = "ufs-renesas",
.id = UCLASS_UFS,
.of_match = ufs_renesas_pltfm_ids,
- .bind = ufs_renesas_pltfm_bind,
.probe = ufs_renesas_pltfm_probe,
.remove = ufs_renesas_pltfm_remove,
.priv_auto = sizeof(struct ufs_renesas_priv),
diff --git a/drivers/ufs/ufs-rockchip.c b/drivers/ufs/ufs-rockchip.c
new file mode 100644
index 00000000000..0384244387d
--- /dev/null
+++ b/drivers/ufs/ufs-rockchip.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Rockchip UFS Host Controller driver
+ *
+ * Copyright (C) 2025 Rockchip Electronics Co.Ltd.
+ */
+
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/ioport.h>
+#include <reset.h>
+#include <ufs.h>
+
+#include "ufs.h"
+#include "unipro.h"
+#include "ufs-rockchip.h"
+
+static int ufs_rockchip_hce_enable_notify(struct ufs_hba *hba,
+ enum ufs_notify_change_status status)
+{
+ int err = 0;
+
+ if (status != POST_CHANGE)
+ return 0;
+
+ ufshcd_dme_reset(hba);
+ ufshcd_dme_enable(hba);
+
+ if (hba->ops->phy_initialization) {
+ err = hba->ops->phy_initialization(hba);
+ if (err)
+ dev_err(hba->dev,
+ "Phy init failed (%d)\n", err);
+ }
+
+ return err;
+}
+
+static void ufs_rockchip_rk3576_phy_parameter_init(struct ufs_hba *hba)
+{
+ struct ufs_rockchip_host *host = dev_get_priv(hba->dev);
+
+ ufs_sys_writel(host->mphy_base, 0x80, CMN_REG23);
+ ufs_sys_writel(host->mphy_base, 0xB5, TRSV0_REG14);
+ ufs_sys_writel(host->mphy_base, 0xB5, TRSV1_REG14);
+ ufs_sys_writel(host->mphy_base, 0x03, TRSV0_REG15);
+ ufs_sys_writel(host->mphy_base, 0x03, TRSV1_REG15);
+ ufs_sys_writel(host->mphy_base, 0x38, TRSV0_REG08);
+ ufs_sys_writel(host->mphy_base, 0x38, TRSV1_REG08);
+ ufs_sys_writel(host->mphy_base, 0x50, TRSV0_REG29);
+ ufs_sys_writel(host->mphy_base, 0x50, TRSV1_REG29);
+ ufs_sys_writel(host->mphy_base, 0x80, TRSV0_REG2E);
+ ufs_sys_writel(host->mphy_base, 0x80, TRSV1_REG2E);
+ ufs_sys_writel(host->mphy_base, 0x18, TRSV0_REG3C);
+ ufs_sys_writel(host->mphy_base, 0x18, TRSV1_REG3C);
+ ufs_sys_writel(host->mphy_base, 0x03, TRSV0_REG16);
+ ufs_sys_writel(host->mphy_base, 0x03, TRSV1_REG16);
+ ufs_sys_writel(host->mphy_base, 0x20, TRSV0_REG17);
+ ufs_sys_writel(host->mphy_base, 0x20, TRSV1_REG17);
+ ufs_sys_writel(host->mphy_base, 0xC0, TRSV0_REG18);
+ ufs_sys_writel(host->mphy_base, 0xC0, TRSV1_REG18);
+ ufs_sys_writel(host->mphy_base, 0x03, CMN_REG25);
+ ufs_sys_writel(host->mphy_base, 0x03, TRSV0_REG3D);
+ ufs_sys_writel(host->mphy_base, 0x03, TRSV1_REG3D);
+ ufs_sys_writel(host->mphy_base, 0xC0, CMN_REG23);
+ udelay(1);
+ ufs_sys_writel(host->mphy_base, 0x00, CMN_REG23);
+ udelay(200);
+}
+
+static int ufs_rockchip_rk3576_phy_init(struct ufs_hba *hba)
+{
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(PA_LOCAL_TX_LCC_ENABLE, 0x0), 0x0);
+ /* enable the mphy DME_SET cfg */
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(MPHY_CFG, 0x0), MPHY_CFG_ENABLE);
+ for (int i = 0; i < 2; i++) {
+ /* Configuration M-TX */
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_CLK_PRD, SEL_TX_LANE0 + i), 0x06);
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_CLK_PRD_EN, SEL_TX_LANE0 + i), 0x02);
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_VALUE, SEL_TX_LANE0 + i), 0x44);
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE1, SEL_TX_LANE0 + i), 0xe6);
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE2, SEL_TX_LANE0 + i), 0x07);
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_TASE_VALUE, SEL_TX_LANE0 + i), 0x93);
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_BASE_NVALUE, SEL_TX_LANE0 + i), 0xc9);
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_POWER_SAVING_CTRL, SEL_TX_LANE0 + i), 0x00);
+ /* Configuration M-RX */
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_CLK_PRD, SEL_RX_LANE0 + i), 0x06);
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_CLK_PRD_EN, SEL_RX_LANE0 + i), 0x00);
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_VALUE, SEL_RX_LANE0 + i), 0x58);
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_PVALUE1, SEL_RX_LANE0 + i), 0x8c);
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_PVALUE2, SEL_RX_LANE0 + i), 0x02);
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_OPTION, SEL_RX_LANE0 + i), 0xf6);
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_POWER_SAVING_CTRL, SEL_RX_LANE0 + i), 0x69);
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_SAVE_DET_CTRL, SEL_RX_LANE0 + i), 0x18);
+ }
+
+ /* disable the mphy DME_SET cfg */
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(MPHY_CFG, 0x0), MPHY_CFG_DISABLE);
+
+ ufs_rockchip_rk3576_phy_parameter_init(hba);
+
+ /* start link up */
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(MIB_T_DBG_CPORT_TX_ENDIAN, 0), 0x0);
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(MIB_T_DBG_CPORT_RX_ENDIAN, 0), 0x0);
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(N_DEVICEID, 0), 0x0);
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(N_DEVICEID_VALID, 0), 0x1);
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(T_PEERDEVICEID, 0), 0x1);
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(T_CONNECTIONSTATE, 0), 0x1);
+
+ return 0;
+}
+
+static int ufs_rockchip_common_init(struct ufs_hba *hba)
+{
+ struct udevice *dev = hba->dev;
+ struct ufs_rockchip_host *host = dev_get_priv(dev);
+ struct resource res;
+ int err;
+
+ /* system control register for hci */
+ err = dev_read_resource_byname(dev, "hci_grf", &res);
+ if (err) {
+ dev_err(dev, "cannot ioremap for hci system control register\n");
+ return err;
+ }
+ host->ufs_sys_ctrl = (void *)(res.start);
+
+ /* system control register for mphy */
+ err = dev_read_resource_byname(dev, "mphy_grf", &res);
+ if (err) {
+ dev_err(dev, "cannot ioremap for mphy system control register\n");
+ return err;
+ }
+ host->ufs_phy_ctrl = (void *)(res.start);
+
+ /* mphy base register */
+ err = dev_read_resource_byname(dev, "mphy", &res);
+ if (err) {
+ dev_err(dev, "cannot ioremap for mphy base register\n");
+ return err;
+ }
+ host->mphy_base = (void *)(res.start);
+
+ host->phy_config_mode = dev_read_u32_default(dev, "ufs-phy-config-mode", 0);
+
+ err = reset_get_bulk(dev, &host->rsts);
+ if (err) {
+ dev_err(dev, "Can't get reset: %d\n", err);
+ return err;
+ }
+
+ host->hba = hba;
+
+ return 0;
+}
+
+static int ufs_rockchip_rk3576_init(struct ufs_hba *hba)
+{
+ int ret = 0;
+
+ ret = ufs_rockchip_common_init(hba);
+ if (ret) {
+ dev_err(hba->dev, "%s: ufs common init fail\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct ufs_hba_ops ufs_hba_rk3576_vops = {
+ .init = ufs_rockchip_rk3576_init,
+ .phy_initialization = ufs_rockchip_rk3576_phy_init,
+ .hce_enable_notify = ufs_rockchip_hce_enable_notify,
+};
+
+static const struct udevice_id ufs_rockchip_of_match[] = {
+ { .compatible = "rockchip,rk3576-ufshc", .data = (ulong)&ufs_hba_rk3576_vops},
+ {},
+};
+
+static int ufs_rockchip_probe(struct udevice *dev)
+{
+ struct ufs_hba_ops *ops = (struct ufs_hba_ops *)dev_get_driver_data(dev);
+ int err;
+
+ err = ufshcd_probe(dev, ops);
+ if (err)
+ dev_err(dev, "ufshcd_pltfrm_init() failed %d\n", err);
+
+ return err;
+}
+
+U_BOOT_DRIVER(rockchip_ufs) = {
+ .name = "ufshcd-rockchip",
+ .id = UCLASS_UFS,
+ .of_match = ufs_rockchip_of_match,
+ .probe = ufs_rockchip_probe,
+ .priv_auto = sizeof(struct ufs_rockchip_host),
+};
diff --git a/drivers/ufs/ufs-rockchip.h b/drivers/ufs/ufs-rockchip.h
new file mode 100644
index 00000000000..3dcb80f5702
--- /dev/null
+++ b/drivers/ufs/ufs-rockchip.h
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Rockchip UFS Host Controller driver
+ *
+ * Copyright (C) 2025 Rockchip Electronics Co.Ltd.
+ */
+
+#ifndef _UFS_ROCKCHIP_H_
+#define _UFS_ROCKCHIP_H_
+
+#define UFS_MAX_CLKS 3
+
+#define SEL_TX_LANE0 0x0
+#define SEL_TX_LANE1 0x1
+#define SEL_TX_LANE2 0x2
+#define SEL_TX_LANE3 0x3
+#define SEL_RX_LANE0 0x4
+#define SEL_RX_LANE1 0x5
+#define SEL_RX_LANE2 0x6
+#define SEL_RX_LANE3 0x7
+
+#define VND_TX_CLK_PRD 0xAA
+#define VND_TX_CLK_PRD_EN 0xA9
+#define VND_TX_LINERESET_PVALUE2 0xAB
+#define VND_TX_LINERESET_PVALUE1 0xAC
+#define VND_TX_LINERESET_VALUE 0xAD
+#define VND_TX_BASE_NVALUE 0x93
+#define VND_TX_TASE_VALUE 0x94
+#define VND_TX_POWER_SAVING_CTRL 0x7F
+#define VND_RX_CLK_PRD 0x12
+#define VND_RX_CLK_PRD_EN 0x11
+#define VND_RX_LINERESET_PVALUE2 0x1B
+#define VND_RX_LINERESET_PVALUE1 0x1C
+#define VND_RX_LINERESET_VALUE 0x1D
+#define VND_RX_LINERESET_OPTION 0x25
+#define VND_RX_POWER_SAVING_CTRL 0x2F
+#define VND_RX_SAVE_DET_CTRL 0x1E
+
+#define CMN_REG23 0x8C
+#define CMN_REG25 0x94
+#define TRSV0_REG08 0xE0
+#define TRSV1_REG08 0x220
+#define TRSV0_REG14 0x110
+#define TRSV1_REG14 0x250
+#define TRSV0_REG15 0x134
+#define TRSV1_REG15 0x274
+#define TRSV0_REG16 0x128
+#define TRSV1_REG16 0x268
+#define TRSV0_REG17 0x12C
+#define TRSV1_REG17 0x26c
+#define TRSV0_REG18 0x120
+#define TRSV1_REG18 0x260
+#define TRSV0_REG29 0x164
+#define TRSV1_REG29 0x2A4
+#define TRSV0_REG2E 0x178
+#define TRSV1_REG2E 0x2B8
+#define TRSV0_REG3C 0x1B0
+#define TRSV1_REG3C 0x2F0
+#define TRSV0_REG3D 0x1B4
+#define TRSV1_REG3D 0x2F4
+
+#define MPHY_CFG 0x200
+#define MPHY_CFG_ENABLE 0x40
+#define MPHY_CFG_DISABLE 0x0
+
+#define MIB_T_DBG_CPORT_TX_ENDIAN 0xc022
+#define MIB_T_DBG_CPORT_RX_ENDIAN 0xc023
+
+struct ufs_rockchip_host {
+ struct ufs_hba *hba;
+ void __iomem *ufs_phy_ctrl;
+ void __iomem *ufs_sys_ctrl;
+ void __iomem *mphy_base;
+ struct reset_ctl_bulk rsts;
+ struct clk ref_out_clk;
+ uint64_t caps;
+ uint32_t phy_config_mode;
+};
+
+#define ufs_sys_writel(base, val, reg) \
+ writel((val), (base) + (reg))
+#define ufs_sys_readl(base, reg) readl((base) + (reg))
+#define ufs_sys_set_bits(base, mask, reg) \
+ ufs_sys_writel((base), ((mask) | (ufs_sys_readl((base), (reg)))), (reg))
+#define ufs_sys_ctrl_clr_bits(base, mask, reg) \
+ ufs_sys_writel((base), ((~(mask)) & (ufs_sys_readl((base), (reg)))), (reg))
+
+#endif /* _UFS_ROCKCHIP_H_ */
diff --git a/drivers/ufs/ufs-uclass.c b/drivers/ufs/ufs-uclass.c
index 334bfcfa06a..3c8e4299259 100644
--- a/drivers/ufs/ufs-uclass.c
+++ b/drivers/ufs/ufs-uclass.c
@@ -1,17 +1,2308 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0+
/**
- * ufs-uclass.c - Universal Flash Storage (UFS) Uclass driver
+ * ufs.c - Universal Flash Storage (UFS) driver
+ *
+ * Taken from Linux Kernel v5.2 (drivers/scsi/ufs/ufshcd.c) and ported
+ * to u-boot.
*
* Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com
*/
-#define LOG_CATEGORY UCLASS_UFS
+#include <bouncebuf.h>
+#include <charset.h>
+#include <clk.h>
+#include <dm.h>
+#include <log.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <dm/lists.h>
+#include <dm/device-internal.h>
+#include <malloc.h>
+#include <hexdump.h>
+#include <scsi.h>
+#include <ufs.h>
+#include <asm/io.h>
+#include <asm/dma-mapping.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
#include "ufs.h"
-#include <dm.h>
+
+#define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
+ UTP_TASK_REQ_COMPL |\
+ UFSHCD_ERROR_MASK)
+/* maximum number of link-startup retries */
+#define DME_LINKSTARTUP_RETRIES 3
+
+/* maximum number of retries for a general UIC command */
+#define UFS_UIC_COMMAND_RETRIES 3
+
+/* Query request retries */
+#define QUERY_REQ_RETRIES 3
+/* Query request timeout */
+#define QUERY_REQ_TIMEOUT 1500 /* 1.5 seconds */
+
+/* maximum timeout in ms for a general UIC command */
+#define UFS_UIC_CMD_TIMEOUT 1000
+/* NOP OUT retries waiting for NOP IN response */
+#define NOP_OUT_RETRIES 10
+/* Timeout after 30 msecs if NOP OUT hangs without response */
+#define NOP_OUT_TIMEOUT 30 /* msecs */
+
+/* Only use one Task Tag for all requests */
+#define TASK_TAG 0
+
+/* Expose the flag value from utp_upiu_query.value */
+#define MASK_QUERY_UPIU_FLAG_LOC 0xFF
+
+#define MAX_PRDT_ENTRY 262144
+
+/* maximum bytes per request */
+#define UFS_MAX_BYTES (128 * 256 * 1024)
+
+static inline bool ufshcd_is_hba_active(struct ufs_hba *hba);
+static inline void ufshcd_hba_stop(struct ufs_hba *hba);
+static int ufshcd_hba_enable(struct ufs_hba *hba);
+
+/*
+ * ufshcd_wait_for_register - wait for register value to change
+ */
+static int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
+ u32 val, unsigned long timeout_ms)
+{
+ int err = 0;
+ unsigned long start = get_timer(0);
+
+ /* ignore bits that we don't intend to wait on */
+ val = val & mask;
+
+ while ((ufshcd_readl(hba, reg) & mask) != val) {
+ if (get_timer(start) > timeout_ms) {
+ if ((ufshcd_readl(hba, reg) & mask) != val)
+ err = -ETIMEDOUT;
+ break;
+ }
+ }
+
+ return err;
+}
+
+/**
+ * ufshcd_init_pwr_info - setting the POR (power on reset)
+ * values in hba power info
+ */
+static void ufshcd_init_pwr_info(struct ufs_hba *hba)
+{
+ hba->pwr_info.gear_rx = UFS_PWM_G1;
+ hba->pwr_info.gear_tx = UFS_PWM_G1;
+ hba->pwr_info.lane_rx = 1;
+ hba->pwr_info.lane_tx = 1;
+ hba->pwr_info.pwr_rx = SLOWAUTO_MODE;
+ hba->pwr_info.pwr_tx = SLOWAUTO_MODE;
+ hba->pwr_info.hs_rate = 0;
+}
+
+/**
+ * ufshcd_print_pwr_info - print power params as saved in hba
+ * power info
+ */
+static void ufshcd_print_pwr_info(struct ufs_hba *hba)
+{
+ static const char * const names[] = {
+ "INVALID MODE",
+ "FAST MODE",
+ "SLOW_MODE",
+ "INVALID MODE",
+ "FASTAUTO_MODE",
+ "SLOWAUTO_MODE",
+ "INVALID MODE",
+ };
+
+ dev_err(hba->dev, "[RX, TX]: gear=[%d, %d], lane[%d, %d], pwr[%s, %s], rate = %d\n",
+ hba->pwr_info.gear_rx, hba->pwr_info.gear_tx,
+ hba->pwr_info.lane_rx, hba->pwr_info.lane_tx,
+ names[hba->pwr_info.pwr_rx],
+ names[hba->pwr_info.pwr_tx],
+ hba->pwr_info.hs_rate);
+}
+
+static void ufshcd_device_reset(struct ufs_hba *hba)
+{
+ ufshcd_vops_device_reset(hba);
+}
+
+/**
+ * ufshcd_ready_for_uic_cmd - Check if controller is ready
+ * to accept UIC commands
+ */
+static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba)
+{
+ if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY)
+ return true;
+ else
+ return false;
+}
+
+/**
+ * ufshcd_get_uic_cmd_result - Get the UIC command result
+ */
+static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
+{
+ return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2) &
+ MASK_UIC_COMMAND_RESULT;
+}
+
+/**
+ * ufshcd_get_dme_attr_val - Get the value of attribute returned by UIC command
+ */
+static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba)
+{
+ return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3);
+}
+
+/**
+ * ufshcd_is_device_present - Check if any device connected to
+ * the host controller
+ */
+static inline bool ufshcd_is_device_present(struct ufs_hba *hba)
+{
+ return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) &
+ DEVICE_PRESENT) ? true : false;
+}
+
+/**
+ * ufshcd_send_uic_cmd - UFS Interconnect layer command API
+ *
+ */
+static int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+{
+ unsigned long start = 0;
+ u32 intr_status;
+ u32 enabled_intr_status;
+
+ if (!ufshcd_ready_for_uic_cmd(hba)) {
+ dev_err(hba->dev,
+ "Controller not ready to accept UIC commands\n");
+ return -EIO;
+ }
+
+ debug("sending uic command:%d\n", uic_cmd->command);
+
+ /* Write Args */
+ ufshcd_writel(hba, uic_cmd->argument1, REG_UIC_COMMAND_ARG_1);
+ ufshcd_writel(hba, uic_cmd->argument2, REG_UIC_COMMAND_ARG_2);
+ ufshcd_writel(hba, uic_cmd->argument3, REG_UIC_COMMAND_ARG_3);
+
+ /* Write UIC Cmd */
+ ufshcd_writel(hba, uic_cmd->command & COMMAND_OPCODE_MASK,
+ REG_UIC_COMMAND);
+
+ start = get_timer(0);
+ do {
+ intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
+ enabled_intr_status = intr_status & hba->intr_mask;
+ ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
+
+ if (get_timer(start) > UFS_UIC_CMD_TIMEOUT) {
+ dev_err(hba->dev,
+ "Timedout waiting for UIC response\n");
+
+ return -ETIMEDOUT;
+ }
+
+ if (enabled_intr_status & UFSHCD_ERROR_MASK) {
+ dev_err(hba->dev, "Error in status:%08x\n",
+ enabled_intr_status);
+
+ return -1;
+ }
+ } while (!(enabled_intr_status & UFSHCD_UIC_MASK));
+
+ uic_cmd->argument2 = ufshcd_get_uic_cmd_result(hba);
+ uic_cmd->argument3 = ufshcd_get_dme_attr_val(hba);
+
+ debug("Sent successfully\n");
+
+ return 0;
+}
+
+int ufshcd_dme_configure_adapt(struct ufs_hba *hba,
+ int agreed_gear,
+ int adapt_val)
+{
+ int ret;
+
+ if (agreed_gear < UFS_HS_G4)
+ adapt_val = PA_NO_ADAPT;
+
+ ret = ufshcd_dme_set(hba,
+ UIC_ARG_MIB(PA_TXHSADAPTTYPE),
+ adapt_val);
+ return ret;
+}
+
+/**
+ * ufshcd_dme_set_attr - UIC command for DME_SET, DME_PEER_SET
+ *
+ */
+int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel, u8 attr_set,
+ u32 mib_val, u8 peer)
+{
+ struct uic_command uic_cmd = {0};
+ static const char *const action[] = {
+ "dme-set",
+ "dme-peer-set"
+ };
+ const char *set = action[!!peer];
+ int ret;
+ int retries = UFS_UIC_COMMAND_RETRIES;
+
+ uic_cmd.command = peer ?
+ UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET;
+ uic_cmd.argument1 = attr_sel;
+ uic_cmd.argument2 = UIC_ARG_ATTR_TYPE(attr_set);
+ uic_cmd.argument3 = mib_val;
+
+ do {
+ /* for peer attributes we retry upon failure */
+ ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+ if (ret)
+ dev_dbg(hba->dev, "%s: attr-id 0x%x val 0x%x error code %d\n",
+ set, UIC_GET_ATTR_ID(attr_sel), mib_val, ret);
+ } while (ret && peer && --retries);
+
+ if (ret)
+ dev_err(hba->dev, "%s: attr-id 0x%x val 0x%x failed %d retries\n",
+ set, UIC_GET_ATTR_ID(attr_sel), mib_val,
+ UFS_UIC_COMMAND_RETRIES - retries);
+
+ return ret;
+}
+
+/**
+ * ufshcd_dme_get_attr - UIC command for DME_GET, DME_PEER_GET
+ *
+ */
+int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
+ u32 *mib_val, u8 peer)
+{
+ struct uic_command uic_cmd = {0};
+ static const char *const action[] = {
+ "dme-get",
+ "dme-peer-get"
+ };
+ const char *get = action[!!peer];
+ int ret;
+ int retries = UFS_UIC_COMMAND_RETRIES;
+
+ uic_cmd.command = peer ?
+ UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET;
+ uic_cmd.argument1 = attr_sel;
+
+ do {
+ /* for peer attributes we retry upon failure */
+ ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+ if (ret)
+ dev_dbg(hba->dev, "%s: attr-id 0x%x error code %d\n",
+ get, UIC_GET_ATTR_ID(attr_sel), ret);
+ } while (ret && peer && --retries);
+
+ if (ret)
+ dev_err(hba->dev, "%s: attr-id 0x%x failed %d retries\n",
+ get, UIC_GET_ATTR_ID(attr_sel),
+ UFS_UIC_COMMAND_RETRIES - retries);
+
+ if (mib_val && !ret)
+ *mib_val = uic_cmd.argument3;
+
+ return ret;
+}
+
+static int ufshcd_disable_tx_lcc(struct ufs_hba *hba, bool peer)
+{
+ u32 tx_lanes, i, err = 0;
+
+ if (!peer)
+ ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES),
+ &tx_lanes);
+ else
+ ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES),
+ &tx_lanes);
+ for (i = 0; i < tx_lanes; i++) {
+ unsigned int val = UIC_ARG_MIB_SEL(TX_LCC_ENABLE,
+ UIC_ARG_MPHY_TX_GEN_SEL_INDEX(i));
+ if (!peer)
+ err = ufshcd_dme_set(hba, val, 0);
+ else
+ err = ufshcd_dme_peer_set(hba, val, 0);
+ if (err) {
+ dev_err(hba->dev, "%s: TX LCC Disable failed, peer = %d, lane = %d, err = %d\n",
+ __func__, peer, i, err);
+ break;
+ }
+ }
+
+ return err;
+}
+
+static inline int ufshcd_disable_device_tx_lcc(struct ufs_hba *hba)
+{
+ return ufshcd_disable_tx_lcc(hba, true);
+}
+
+/**
+ * ufshcd_dme_link_startup - Notify Unipro to perform link startup
+ *
+ */
+static int ufshcd_dme_link_startup(struct ufs_hba *hba)
+{
+ struct uic_command uic_cmd = {0};
+ int ret;
+
+ uic_cmd.command = UIC_CMD_DME_LINK_STARTUP;
+
+ ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+ if (ret)
+ dev_dbg(hba->dev,
+ "dme-link-startup: error code %d\n", ret);
+ return ret;
+}
+
+int ufshcd_dme_enable(struct ufs_hba *hba)
+{
+ struct uic_command uic_cmd = {0};
+ int ret;
+
+ uic_cmd.command = UIC_CMD_DME_ENABLE;
+
+ ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+ if (ret)
+ dev_dbg(hba->dev,
+ "dme-enable: error code %d\n", ret);
+
+ return ret;
+}
+
+int ufshcd_dme_reset(struct ufs_hba *hba)
+{
+ struct uic_command uic_cmd = {0};
+ int ret;
+
+ uic_cmd.command = UIC_CMD_DME_RESET;
+
+ ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+ if (ret)
+ dev_dbg(hba->dev,
+ "dme-reset: error code %d\n", ret);
+
+ return ret;
+}
+
+/**
+ * ufshcd_disable_intr_aggr - Disables interrupt aggregation.
+ *
+ */
+static inline void ufshcd_disable_intr_aggr(struct ufs_hba *hba)
+{
+ ufshcd_writel(hba, 0, REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
+}
+
+/**
+ * ufshcd_get_lists_status - Check UCRDY, UTRLRDY and UTMRLRDY
+ */
+static inline int ufshcd_get_lists_status(u32 reg)
+{
+ return !((reg & UFSHCD_STATUS_READY) == UFSHCD_STATUS_READY);
+}
+
+/**
+ * ufshcd_enable_run_stop_reg - Enable run-stop registers,
+ * When run-stop registers are set to 1, it indicates the
+ * host controller that it can process the requests
+ */
+static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
+{
+ ufshcd_writel(hba, UTP_TASK_REQ_LIST_RUN_STOP_BIT,
+ REG_UTP_TASK_REQ_LIST_RUN_STOP);
+ ufshcd_writel(hba, UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
+ REG_UTP_TRANSFER_REQ_LIST_RUN_STOP);
+}
+
+/**
+ * ufshcd_enable_intr - enable interrupts
+ */
+static void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs)
+{
+ u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
+ u32 rw;
+
+ if (hba->version == UFSHCI_VERSION_10) {
+ rw = set & INTERRUPT_MASK_RW_VER_10;
+ set = rw | ((set ^ intrs) & intrs);
+ } else {
+ set |= intrs;
+ }
+
+ ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE);
+
+ hba->intr_mask = set;
+}
+
+/**
+ * ufshcd_make_hba_operational - Make UFS controller operational
+ *
+ * To bring UFS host controller to operational state,
+ * 1. Enable required interrupts
+ * 2. Configure interrupt aggregation
+ * 3. Program UTRL and UTMRL base address
+ * 4. Configure run-stop-registers
+ *
+ */
+static int ufshcd_make_hba_operational(struct ufs_hba *hba)
+{
+ int err = 0;
+ u32 reg;
+
+ /* Enable required interrupts */
+ ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
+
+ /* Disable interrupt aggregation */
+ ufshcd_disable_intr_aggr(hba);
+
+ /* Configure UTRL and UTMRL base address registers */
+ ufshcd_writel(hba, lower_32_bits((dma_addr_t)hba->utrdl),
+ REG_UTP_TRANSFER_REQ_LIST_BASE_L);
+ ufshcd_writel(hba, upper_32_bits((dma_addr_t)hba->utrdl),
+ REG_UTP_TRANSFER_REQ_LIST_BASE_H);
+ ufshcd_writel(hba, lower_32_bits((dma_addr_t)hba->utmrdl),
+ REG_UTP_TASK_REQ_LIST_BASE_L);
+ ufshcd_writel(hba, upper_32_bits((dma_addr_t)hba->utmrdl),
+ REG_UTP_TASK_REQ_LIST_BASE_H);
+
+ /*
+ * Make sure base address and interrupt setup are updated before
+ * enabling the run/stop registers below.
+ */
+ wmb();
+
+ /*
+ * UCRDY, UTMRLDY and UTRLRDY bits must be 1
+ */
+ reg = ufshcd_readl(hba, REG_CONTROLLER_STATUS);
+ if (!(ufshcd_get_lists_status(reg))) {
+ ufshcd_enable_run_stop_reg(hba);
+ } else {
+ dev_err(hba->dev,
+ "Host controller not ready to process requests\n");
+ err = -EIO;
+ goto out;
+ }
+
+out:
+ return err;
+}
+
+/**
+ * ufshcd_link_startup - Initialize unipro link startup
+ */
+static int ufshcd_link_startup(struct ufs_hba *hba)
+{
+ int ret;
+ int retries = DME_LINKSTARTUP_RETRIES;
+
+ do {
+ ufshcd_ops_link_startup_notify(hba, PRE_CHANGE);
+
+ ret = ufshcd_dme_link_startup(hba);
+
+ /* check if device is detected by inter-connect layer */
+ if (!ret && !ufshcd_is_device_present(hba)) {
+ dev_err(hba->dev, "%s: Device not present\n", __func__);
+ ret = -ENXIO;
+ goto out;
+ }
+
+ /*
+ * DME link lost indication is only received when link is up,
+ * but we can't be sure if the link is up until link startup
+ * succeeds. So reset the local Uni-Pro and try again.
+ */
+ if (ret && ufshcd_hba_enable(hba))
+ goto out;
+ } while (ret && retries--);
+
+ if (ret)
+ /* failed to get the link up... retire */
+ goto out;
+
+ /* Mark that link is up in PWM-G1, 1-lane, SLOW-AUTO mode */
+ ufshcd_init_pwr_info(hba);
+
+ if (hba->quirks & UFSHCD_QUIRK_BROKEN_LCC) {
+ ret = ufshcd_disable_device_tx_lcc(hba);
+ if (ret)
+ goto out;
+ }
+
+ /* Include any host controller configuration via UIC commands */
+ ret = ufshcd_ops_link_startup_notify(hba, POST_CHANGE);
+ if (ret)
+ goto out;
+
+ /* Clear UECPA once due to LINERESET has happened during LINK_STARTUP */
+ ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
+ ret = ufshcd_make_hba_operational(hba);
+out:
+ if (ret)
+ dev_err(hba->dev, "link startup failed %d\n", ret);
+
+ return ret;
+}
+
+/**
+ * ufshcd_hba_stop - Send controller to reset state
+ */
+static inline void ufshcd_hba_stop(struct ufs_hba *hba)
+{
+ int err;
+
+ ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
+ err = ufshcd_wait_for_register(hba, REG_CONTROLLER_ENABLE,
+ CONTROLLER_ENABLE, CONTROLLER_DISABLE,
+ 10);
+ if (err)
+ dev_err(hba->dev, "%s: Controller disable failed\n", __func__);
+}
+
+/**
+ * ufshcd_is_hba_active - Get controller state
+ */
+static inline bool ufshcd_is_hba_active(struct ufs_hba *hba)
+{
+ return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & CONTROLLER_ENABLE)
+ ? false : true;
+}
+
+/**
+ * ufshcd_hba_start - Start controller initialization sequence
+ */
+static inline void ufshcd_hba_start(struct ufs_hba *hba)
+{
+ ufshcd_writel(hba, CONTROLLER_ENABLE, REG_CONTROLLER_ENABLE);
+}
+
+/**
+ * ufshcd_hba_enable - initialize the controller
+ */
+static int ufshcd_hba_enable(struct ufs_hba *hba)
+{
+ int retry;
+
+ if (!ufshcd_is_hba_active(hba))
+ /* change controller state to "reset state" */
+ ufshcd_hba_stop(hba);
+
+ ufshcd_ops_hce_enable_notify(hba, PRE_CHANGE);
+
+ /* start controller initialization sequence */
+ ufshcd_hba_start(hba);
+
+ /*
+ * To initialize a UFS host controller HCE bit must be set to 1.
+ * During initialization the HCE bit value changes from 1->0->1.
+ * When the host controller completes initialization sequence
+ * it sets the value of HCE bit to 1. The same HCE bit is read back
+ * to check if the controller has completed initialization sequence.
+ * So without this delay the value HCE = 1, set in the previous
+ * instruction might be read back.
+ * This delay can be changed based on the controller.
+ */
+ mdelay(1);
+
+ /* wait for the host controller to complete initialization */
+ retry = 10;
+ while (ufshcd_is_hba_active(hba)) {
+ if (retry) {
+ retry--;
+ } else {
+ dev_err(hba->dev, "Controller enable failed\n");
+ return -EIO;
+ }
+ mdelay(5);
+ }
+
+ /* enable UIC related interrupts */
+ ufshcd_enable_intr(hba, UFSHCD_UIC_MASK);
+
+ ufshcd_ops_hce_enable_notify(hba, POST_CHANGE);
+
+ return 0;
+}
+
+/**
+ * ufshcd_host_memory_configure - configure local reference block with
+ * memory offsets
+ */
+static void ufshcd_host_memory_configure(struct ufs_hba *hba)
+{
+ struct utp_transfer_req_desc *utrdlp;
+ dma_addr_t cmd_desc_dma_addr;
+ u16 response_offset;
+ u16 prdt_offset;
+
+ utrdlp = hba->utrdl;
+ cmd_desc_dma_addr = (dma_addr_t)hba->ucdl;
+
+ utrdlp->command_desc_base_addr_lo =
+ cpu_to_le32(lower_32_bits(cmd_desc_dma_addr));
+ utrdlp->command_desc_base_addr_hi =
+ cpu_to_le32(upper_32_bits(cmd_desc_dma_addr));
+
+ response_offset = offsetof(struct utp_transfer_cmd_desc, response_upiu);
+ prdt_offset = offsetof(struct utp_transfer_cmd_desc, prd_table);
+
+ utrdlp->response_upiu_offset = cpu_to_le16(response_offset >> 2);
+ utrdlp->prd_table_offset = cpu_to_le16(prdt_offset >> 2);
+ utrdlp->response_upiu_length = cpu_to_le16(ALIGNED_UPIU_SIZE >> 2);
+
+ hba->ucd_req_ptr = (struct utp_upiu_req *)hba->ucdl;
+ hba->ucd_rsp_ptr =
+ (struct utp_upiu_rsp *)&hba->ucdl->response_upiu;
+ hba->ucd_prdt_ptr =
+ (struct ufshcd_sg_entry *)&hba->ucdl->prd_table;
+}
+
+/**
+ * ufshcd_memory_alloc - allocate memory for host memory space data structures
+ */
+static int ufshcd_memory_alloc(struct ufs_hba *hba)
+{
+ /* Allocate one Transfer Request Descriptor
+ * Should be aligned to 1k boundary.
+ */
+ hba->utrdl = memalign(1024,
+ ALIGN(sizeof(struct utp_transfer_req_desc),
+ ARCH_DMA_MINALIGN));
+ if (!hba->utrdl) {
+ dev_err(hba->dev, "Transfer Descriptor memory allocation failed\n");
+ return -ENOMEM;
+ }
+
+ /* Allocate one Command Descriptor
+ * Should be aligned to 1k boundary.
+ */
+ hba->ucdl = memalign(1024,
+ ALIGN(sizeof(struct utp_transfer_cmd_desc),
+ ARCH_DMA_MINALIGN));
+ if (!hba->ucdl) {
+ dev_err(hba->dev, "Command descriptor memory allocation failed\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/**
+ * ufshcd_get_intr_mask - Get the interrupt bit mask
+ */
+static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba)
+{
+ u32 intr_mask = 0;
+
+ switch (hba->version) {
+ case UFSHCI_VERSION_10:
+ intr_mask = INTERRUPT_MASK_ALL_VER_10;
+ break;
+ case UFSHCI_VERSION_11:
+ case UFSHCI_VERSION_20:
+ intr_mask = INTERRUPT_MASK_ALL_VER_11;
+ break;
+ case UFSHCI_VERSION_21:
+ default:
+ intr_mask = INTERRUPT_MASK_ALL_VER_21;
+ break;
+ }
+
+ return intr_mask;
+}
+
+/**
+ * ufshcd_get_ufs_version - Get the UFS version supported by the HBA
+ */
+static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
+{
+ return ufshcd_readl(hba, REG_UFS_VERSION);
+}
+
+/**
+ * ufshcd_get_upmcrs - Get the power mode change request status
+ */
+static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba)
+{
+ return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7;
+}
+
+/**
+ * ufshcd_cache_flush - Flush cache
+ *
+ * Flush cache in aligned address..address+size range.
+ */
+static void ufshcd_cache_flush(void *addr, unsigned long size)
+{
+ uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1);
+ uintptr_t end_addr = ALIGN((uintptr_t)addr + size, ARCH_DMA_MINALIGN);
+
+ flush_dcache_range(start_addr, end_addr);
+}
+
+/**
+ * ufshcd_cache_invalidate - Invalidate cache
+ *
+ * Invalidate cache in aligned address..address+size range.
+ */
+static void ufshcd_cache_invalidate(void *addr, unsigned long size)
+{
+ uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1);
+ uintptr_t end_addr = ALIGN((uintptr_t)addr + size, ARCH_DMA_MINALIGN);
+
+ invalidate_dcache_range(start_addr, end_addr);
+}
+
+/**
+ * ufshcd_prepare_req_desc_hdr() - Fills the requests header
+ * descriptor according to request
+ */
+static void ufshcd_prepare_req_desc_hdr(struct ufs_hba *hba,
+ u32 *upiu_flags,
+ enum dma_data_direction cmd_dir)
+{
+ struct utp_transfer_req_desc *req_desc = hba->utrdl;
+ u32 data_direction;
+ u32 dword_0;
+
+ if (cmd_dir == DMA_FROM_DEVICE) {
+ data_direction = UTP_DEVICE_TO_HOST;
+ *upiu_flags = UPIU_CMD_FLAGS_READ;
+ } else if (cmd_dir == DMA_TO_DEVICE) {
+ data_direction = UTP_HOST_TO_DEVICE;
+ *upiu_flags = UPIU_CMD_FLAGS_WRITE;
+ } else {
+ data_direction = UTP_NO_DATA_TRANSFER;
+ *upiu_flags = UPIU_CMD_FLAGS_NONE;
+ }
+
+ dword_0 = (data_direction << UPIU_DATA_DIRECTION_OFFSET)
+ | (0x1 << UPIU_COMMAND_TYPE_OFFSET);
+
+ /* Enable Interrupt for command */
+ dword_0 |= UTP_REQ_DESC_INT_CMD;
+
+ /* Transfer request descriptor header fields */
+ req_desc->header.dword_0 = cpu_to_le32(dword_0);
+ /* dword_1 is reserved, hence it is set to 0 */
+ req_desc->header.dword_1 = 0;
+ /*
+ * assigning invalid value for command status. Controller
+ * updates OCS on command completion, with the command
+ * status
+ */
+ req_desc->header.dword_2 =
+ cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
+ /* dword_3 is reserved, hence it is set to 0 */
+ req_desc->header.dword_3 = 0;
+
+ req_desc->prd_table_length = 0;
+
+ ufshcd_cache_flush(req_desc, sizeof(*req_desc));
+}
+
+static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba,
+ u32 upiu_flags)
+{
+ struct utp_upiu_req *ucd_req_ptr = hba->ucd_req_ptr;
+ struct ufs_query *query = &hba->dev_cmd.query;
+ u16 len = be16_to_cpu(query->request.upiu_req.length);
+
+ /* Query request header */
+ ucd_req_ptr->header.dword_0 =
+ UPIU_HEADER_DWORD(UPIU_TRANSACTION_QUERY_REQ,
+ upiu_flags, 0, TASK_TAG);
+ ucd_req_ptr->header.dword_1 =
+ UPIU_HEADER_DWORD(0, query->request.query_func,
+ 0, 0);
+
+ /* Data segment length only need for WRITE_DESC */
+ if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC)
+ ucd_req_ptr->header.dword_2 =
+ UPIU_HEADER_DWORD(0, 0, (len >> 8), (u8)len);
+ else
+ ucd_req_ptr->header.dword_2 = 0;
+
+ /* Copy the Query Request buffer as is */
+ memcpy(&ucd_req_ptr->qr, &query->request.upiu_req, QUERY_OSF_SIZE);
+
+ /* Copy the Descriptor */
+ if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) {
+ memcpy(ucd_req_ptr + 1, query->descriptor, len);
+ ufshcd_cache_flush(ucd_req_ptr, 2 * sizeof(*ucd_req_ptr));
+ } else {
+ ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr));
+ }
+
+ memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
+ ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr));
+}
+
+static inline void ufshcd_prepare_utp_nop_upiu(struct ufs_hba *hba)
+{
+ struct utp_upiu_req *ucd_req_ptr = hba->ucd_req_ptr;
+
+ memset(ucd_req_ptr, 0, sizeof(struct utp_upiu_req));
+
+ /* command descriptor fields */
+ ucd_req_ptr->header.dword_0 =
+ UPIU_HEADER_DWORD(UPIU_TRANSACTION_NOP_OUT, 0, 0, TASK_TAG);
+ /* clear rest of the fields of basic header */
+ ucd_req_ptr->header.dword_1 = 0;
+ ucd_req_ptr->header.dword_2 = 0;
+
+ memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
+
+ ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr));
+ ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr));
+}
+
+/**
+ * ufshcd_comp_devman_upiu - UFS Protocol Information Unit(UPIU)
+ * for Device Management Purposes
+ */
+static int ufshcd_comp_devman_upiu(struct ufs_hba *hba,
+ enum dev_cmd_type cmd_type)
+{
+ u32 upiu_flags;
+ int ret = 0;
+
+ hba->dev_cmd.type = cmd_type;
+
+ ufshcd_prepare_req_desc_hdr(hba, &upiu_flags, DMA_NONE);
+ switch (cmd_type) {
+ case DEV_CMD_TYPE_QUERY:
+ ufshcd_prepare_utp_query_req_upiu(hba, upiu_flags);
+ break;
+ case DEV_CMD_TYPE_NOP:
+ ufshcd_prepare_utp_nop_upiu(hba);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
+{
+ unsigned long start;
+ u32 intr_status;
+ u32 enabled_intr_status;
+
+ ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
+
+ /* Make sure doorbell reg is updated before reading interrupt status */
+ wmb();
+
+ start = get_timer(0);
+ do {
+ intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
+ enabled_intr_status = intr_status & hba->intr_mask;
+ ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
+
+ if (get_timer(start) > QUERY_REQ_TIMEOUT) {
+ dev_err(hba->dev,
+ "Timedout waiting for UTP response\n");
+
+ return -ETIMEDOUT;
+ }
+
+ if (enabled_intr_status & UFSHCD_ERROR_MASK) {
+ dev_err(hba->dev, "Error in status:%08x\n",
+ enabled_intr_status);
+
+ return -1;
+ }
+ } while (!(enabled_intr_status & UTP_TRANSFER_REQ_COMPL));
+
+ return 0;
+}
+
+/**
+ * ufshcd_get_req_rsp - returns the TR response transaction type
+ */
+static inline int ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
+{
+ ufshcd_cache_invalidate(ucd_rsp_ptr, sizeof(*ucd_rsp_ptr));
+
+ return be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24;
+}
+
+/**
+ * ufshcd_get_tr_ocs - Get the UTRD Overall Command Status
+ *
+ */
+static inline int ufshcd_get_tr_ocs(struct ufs_hba *hba)
+{
+ struct utp_transfer_req_desc *req_desc = hba->utrdl;
+
+ ufshcd_cache_invalidate(req_desc, sizeof(*req_desc));
+
+ return le32_to_cpu(req_desc->header.dword_2) & MASK_OCS;
+}
+
+static inline int ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp *ucd_rsp_ptr)
+{
+ return be32_to_cpu(ucd_rsp_ptr->header.dword_1) & MASK_RSP_UPIU_RESULT;
+}
+
+static int ufshcd_check_query_response(struct ufs_hba *hba)
+{
+ struct ufs_query_res *query_res = &hba->dev_cmd.query.response;
+
+ /* Get the UPIU response */
+ query_res->response = ufshcd_get_rsp_upiu_result(hba->ucd_rsp_ptr) >>
+ UPIU_RSP_CODE_OFFSET;
+ return query_res->response;
+}
+
+/**
+ * ufshcd_copy_query_response() - Copy the Query Response and the data
+ * descriptor
+ */
+static int ufshcd_copy_query_response(struct ufs_hba *hba)
+{
+ struct ufs_query_res *query_res = &hba->dev_cmd.query.response;
+
+ memcpy(&query_res->upiu_res, &hba->ucd_rsp_ptr->qr, QUERY_OSF_SIZE);
+
+ /* Get the descriptor */
+ if (hba->dev_cmd.query.descriptor &&
+ hba->ucd_rsp_ptr->qr.opcode == UPIU_QUERY_OPCODE_READ_DESC) {
+ u8 *descp = (u8 *)hba->ucd_rsp_ptr +
+ GENERAL_UPIU_REQUEST_SIZE;
+ u16 resp_len;
+ u16 buf_len;
+
+ /* data segment length */
+ resp_len = be32_to_cpu(hba->ucd_rsp_ptr->header.dword_2) &
+ MASK_QUERY_DATA_SEG_LEN;
+ buf_len =
+ be16_to_cpu(hba->dev_cmd.query.request.upiu_req.length);
+ if (likely(buf_len >= resp_len)) {
+ memcpy(hba->dev_cmd.query.descriptor, descp, resp_len);
+ } else {
+ dev_warn(hba->dev,
+ "%s: Response size is bigger than buffer\n",
+ __func__);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * ufshcd_exec_dev_cmd - API for sending device management requests
+ */
+static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, enum dev_cmd_type cmd_type,
+ int timeout)
+{
+ int err;
+ int resp;
+
+ err = ufshcd_comp_devman_upiu(hba, cmd_type);
+ if (err)
+ return err;
+
+ err = ufshcd_send_command(hba, TASK_TAG);
+ if (err)
+ return err;
+
+ err = ufshcd_get_tr_ocs(hba);
+ if (err) {
+ dev_err(hba->dev, "Error in OCS:%d\n", err);
+ return -EINVAL;
+ }
+
+ resp = ufshcd_get_req_rsp(hba->ucd_rsp_ptr);
+ switch (resp) {
+ case UPIU_TRANSACTION_NOP_IN:
+ break;
+ case UPIU_TRANSACTION_QUERY_RSP:
+ err = ufshcd_check_query_response(hba);
+ if (!err)
+ err = ufshcd_copy_query_response(hba);
+ break;
+ case UPIU_TRANSACTION_REJECT_UPIU:
+ /* TODO: handle Reject UPIU Response */
+ err = -EPERM;
+ dev_err(hba->dev, "%s: Reject UPIU not fully implemented\n",
+ __func__);
+ break;
+ default:
+ err = -EINVAL;
+ dev_err(hba->dev, "%s: Invalid device management cmd response: %x\n",
+ __func__, resp);
+ }
+
+ return err;
+}
+
+/**
+ * ufshcd_init_query() - init the query response and request parameters
+ */
+static inline void ufshcd_init_query(struct ufs_hba *hba,
+ struct ufs_query_req **request,
+ struct ufs_query_res **response,
+ enum query_opcode opcode,
+ u8 idn, u8 index, u8 selector)
+{
+ *request = &hba->dev_cmd.query.request;
+ *response = &hba->dev_cmd.query.response;
+ memset(*request, 0, sizeof(struct ufs_query_req));
+ memset(*response, 0, sizeof(struct ufs_query_res));
+ (*request)->upiu_req.opcode = opcode;
+ (*request)->upiu_req.idn = idn;
+ (*request)->upiu_req.index = index;
+ (*request)->upiu_req.selector = selector;
+}
+
+/**
+ * ufshcd_query_flag() - API function for sending flag query requests
+ */
+static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
+ enum flag_idn idn, bool *flag_res)
+{
+ struct ufs_query_req *request = NULL;
+ struct ufs_query_res *response = NULL;
+ int err, index = 0, selector = 0;
+ int timeout = QUERY_REQ_TIMEOUT;
+
+ ufshcd_init_query(hba, &request, &response, opcode, idn, index,
+ selector);
+
+ switch (opcode) {
+ case UPIU_QUERY_OPCODE_SET_FLAG:
+ case UPIU_QUERY_OPCODE_CLEAR_FLAG:
+ case UPIU_QUERY_OPCODE_TOGGLE_FLAG:
+ request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST;
+ break;
+ case UPIU_QUERY_OPCODE_READ_FLAG:
+ request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST;
+ if (!flag_res) {
+ /* No dummy reads */
+ dev_err(hba->dev, "%s: Invalid argument for read request\n",
+ __func__);
+ err = -EINVAL;
+ goto out;
+ }
+ break;
+ default:
+ dev_err(hba->dev,
+ "%s: Expected query flag opcode but got = %d\n",
+ __func__, opcode);
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, timeout);
+
+ if (err) {
+ dev_err(hba->dev,
+ "%s: Sending flag query for idn %d failed, err = %d\n",
+ __func__, idn, err);
+ goto out;
+ }
+
+ if (flag_res)
+ *flag_res = (be32_to_cpu(response->upiu_res.value) &
+ MASK_QUERY_UPIU_FLAG_LOC) & 0x1;
+
+out:
+ return err;
+}
+
+static int ufshcd_query_flag_retry(struct ufs_hba *hba,
+ enum query_opcode opcode,
+ enum flag_idn idn, bool *flag_res)
+{
+ int ret;
+ int retries;
+
+ for (retries = 0; retries < QUERY_REQ_RETRIES; retries++) {
+ ret = ufshcd_query_flag(hba, opcode, idn, flag_res);
+ if (ret)
+ dev_dbg(hba->dev,
+ "%s: failed with error %d, retries %d\n",
+ __func__, ret, retries);
+ else
+ break;
+ }
+
+ if (ret)
+ dev_err(hba->dev,
+ "%s: query attribute, opcode %d, idn %d, failed with error %d after %d retires\n",
+ __func__, opcode, idn, ret, retries);
+ return ret;
+}
+
+/**
+ * ufshcd_query_attr - API function for sending attribute requests
+ * @hba: per-adapter instance
+ * @opcode: attribute opcode
+ * @idn: attribute idn to access
+ * @index: index field
+ * @selector: selector field
+ * @attr_val: the attribute value after the query request completes
+ *
+ * Return: 0 for success, non-zero in case of failure.
+ */
+int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
+ enum attr_idn idn, u8 index, u8 selector, u32 *attr_val)
+{
+ struct ufs_query_req *request = NULL;
+ struct ufs_query_res *response = NULL;
+ int err;
+
+ if (!attr_val) {
+ dev_err(hba->dev,
+ "%s: attribute value required for opcode 0x%x\n",
+ __func__, opcode);
+ return -EINVAL;
+ }
+
+ ufshcd_init_query(hba, &request, &response, opcode, idn, index, selector);
+
+ switch (opcode) {
+ case UPIU_QUERY_OPCODE_WRITE_ATTR:
+ request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST;
+ request->upiu_req.value = cpu_to_be32(*attr_val);
+ break;
+ case UPIU_QUERY_OPCODE_READ_ATTR:
+ request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST;
+ break;
+ default:
+ dev_err(hba->dev,
+ "%s: Expected query attr opcode but got = 0x%.2x\n",
+ __func__, opcode);
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT);
+
+ if (err) {
+ dev_err(hba->dev,
+ "%s: opcode 0x%.2x for idn %d failed, index %d, err = %d\n",
+ __func__, opcode, idn, index, err);
+ goto out;
+ }
+
+ *attr_val = be32_to_cpu(response->upiu_res.value);
+
+out:
+ return err;
+}
+
+/**
+ * ufshcd_query_attr_retry() - API function for sending query
+ * attribute with retries
+ * @hba: per-adapter instance
+ * @opcode: attribute opcode
+ * @idn: attribute idn to access
+ * @index: index field
+ * @selector: selector field
+ * @attr_val: the attribute value after the query request
+ * completes
+ *
+ * Return: 0 for success, non-zero in case of failure.
+ */
+int ufshcd_query_attr_retry(struct ufs_hba *hba, enum query_opcode opcode,
+ enum attr_idn idn, u8 index, u8 selector,
+ u32 *attr_val)
+{
+ int ret = 0;
+ u32 retries;
+
+ for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+ ret = ufshcd_query_attr(hba, opcode, idn, index, selector, attr_val);
+ if (ret)
+ dev_dbg(hba->dev,
+ "%s: failed with error %d, retries %d\n",
+ __func__, ret, retries);
+ else
+ break;
+ }
+
+ if (ret)
+ dev_err(hba->dev,
+ "%s: query attribute, idn %d, failed with error %d after %d retries\n",
+ __func__, idn, ret, QUERY_REQ_RETRIES);
+ return ret;
+}
+
+static int __ufshcd_query_descriptor(struct ufs_hba *hba,
+ enum query_opcode opcode,
+ enum desc_idn idn, u8 index, u8 selector,
+ u8 *desc_buf, int *buf_len)
+{
+ struct ufs_query_req *request = NULL;
+ struct ufs_query_res *response = NULL;
+ int err;
+
+ if (!desc_buf) {
+ dev_err(hba->dev, "%s: descriptor buffer required for opcode 0x%x\n",
+ __func__, opcode);
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (*buf_len < QUERY_DESC_MIN_SIZE || *buf_len > QUERY_DESC_MAX_SIZE) {
+ dev_err(hba->dev, "%s: descriptor buffer size (%d) is out of range\n",
+ __func__, *buf_len);
+ err = -EINVAL;
+ goto out;
+ }
+
+ ufshcd_init_query(hba, &request, &response, opcode, idn, index,
+ selector);
+ hba->dev_cmd.query.descriptor = desc_buf;
+ request->upiu_req.length = cpu_to_be16(*buf_len);
+
+ switch (opcode) {
+ case UPIU_QUERY_OPCODE_WRITE_DESC:
+ request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST;
+ break;
+ case UPIU_QUERY_OPCODE_READ_DESC:
+ request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST;
+ break;
+ default:
+ dev_err(hba->dev, "%s: Expected query descriptor opcode but got = 0x%.2x\n",
+ __func__, opcode);
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT);
+
+ if (err) {
+ dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, index %d, err = %d\n",
+ __func__, opcode, idn, index, err);
+ goto out;
+ }
+
+ hba->dev_cmd.query.descriptor = NULL;
+ *buf_len = be16_to_cpu(response->upiu_res.length);
+
+out:
+ return err;
+}
+
+/**
+ * ufshcd_query_descriptor_retry - API function for sending descriptor requests
+ */
+static int ufshcd_query_descriptor_retry(struct ufs_hba *hba, enum query_opcode opcode,
+ enum desc_idn idn, u8 index, u8 selector,
+ u8 *desc_buf, int *buf_len)
+{
+ int err;
+ int retries;
+
+ for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+ err = __ufshcd_query_descriptor(hba, opcode, idn, index,
+ selector, desc_buf, buf_len);
+ if (!err || err == -EINVAL)
+ break;
+ }
+
+ return err;
+}
+
+/**
+ * ufshcd_read_desc_length - read the specified descriptor length from header
+ */
+static int ufshcd_read_desc_length(struct ufs_hba *hba, enum desc_idn desc_id,
+ int desc_index, int *desc_length)
+{
+ int ret;
+ u8 header[QUERY_DESC_HDR_SIZE];
+ int header_len = QUERY_DESC_HDR_SIZE;
+
+ if (desc_id >= QUERY_DESC_IDN_MAX)
+ return -EINVAL;
+
+ ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC,
+ desc_id, desc_index, 0, header,
+ &header_len);
+
+ if (ret) {
+ dev_err(hba->dev, "%s: Failed to get descriptor header id %d\n",
+ __func__, desc_id);
+ return ret;
+ } else if (desc_id != header[QUERY_DESC_DESC_TYPE_OFFSET]) {
+ dev_warn(hba->dev, "%s: descriptor header id %d and desc_id %d mismatch\n",
+ __func__, header[QUERY_DESC_DESC_TYPE_OFFSET],
+ desc_id);
+ ret = -EINVAL;
+ }
+
+ *desc_length = header[QUERY_DESC_LENGTH_OFFSET];
+
+ return ret;
+}
+
+static void ufshcd_init_desc_sizes(struct ufs_hba *hba)
+{
+ int err;
+
+ err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_DEVICE, 0,
+ &hba->desc_size.dev_desc);
+ if (err)
+ hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE;
+
+ err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_POWER, 0,
+ &hba->desc_size.pwr_desc);
+ if (err)
+ hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE;
+
+ err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_INTERCONNECT, 0,
+ &hba->desc_size.interc_desc);
+ if (err)
+ hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE;
+
+ err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_CONFIGURATION, 0,
+ &hba->desc_size.conf_desc);
+ if (err)
+ hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE;
+
+ err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_UNIT, 0,
+ &hba->desc_size.unit_desc);
+ if (err)
+ hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE;
+
+ err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_GEOMETRY, 0,
+ &hba->desc_size.geom_desc);
+ if (err)
+ hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE;
+
+ err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_HEALTH, 0,
+ &hba->desc_size.hlth_desc);
+ if (err)
+ hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE;
+}
+
+/**
+ * ufshcd_map_desc_id_to_length - map descriptor IDN to its length
+ *
+ */
+static int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id,
+ int *desc_len)
+{
+ switch (desc_id) {
+ case QUERY_DESC_IDN_DEVICE:
+ *desc_len = hba->desc_size.dev_desc;
+ break;
+ case QUERY_DESC_IDN_POWER:
+ *desc_len = hba->desc_size.pwr_desc;
+ break;
+ case QUERY_DESC_IDN_GEOMETRY:
+ *desc_len = hba->desc_size.geom_desc;
+ break;
+ case QUERY_DESC_IDN_CONFIGURATION:
+ *desc_len = hba->desc_size.conf_desc;
+ break;
+ case QUERY_DESC_IDN_UNIT:
+ *desc_len = hba->desc_size.unit_desc;
+ break;
+ case QUERY_DESC_IDN_INTERCONNECT:
+ *desc_len = hba->desc_size.interc_desc;
+ break;
+ case QUERY_DESC_IDN_STRING:
+ *desc_len = QUERY_DESC_MAX_SIZE;
+ break;
+ case QUERY_DESC_IDN_HEALTH:
+ *desc_len = hba->desc_size.hlth_desc;
+ break;
+ case QUERY_DESC_IDN_RFU_0:
+ case QUERY_DESC_IDN_RFU_1:
+ *desc_len = 0;
+ break;
+ default:
+ *desc_len = 0;
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * ufshcd_read_desc_param - read the specified descriptor parameter
+ *
+ */
+static int ufshcd_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id,
+ int desc_index, u8 param_offset,
+ u8 *param_read_buf, u8 param_size)
+{
+ int ret;
+ u8 *desc_buf;
+ int buff_len;
+ bool is_kmalloc = true;
+
+ /* Safety check */
+ if (desc_id >= QUERY_DESC_IDN_MAX || !param_size)
+ return -EINVAL;
+
+ /* Get the max length of descriptor from structure filled up at probe
+ * time.
+ */
+ ret = ufshcd_map_desc_id_to_length(hba, desc_id, &buff_len);
+
+ /* Sanity checks */
+ if (ret || !buff_len) {
+ dev_err(hba->dev, "%s: Failed to get full descriptor length\n",
+ __func__);
+ return ret;
+ }
+
+ /* Check whether we need temp memory */
+ if (param_offset != 0 || param_size < buff_len) {
+ desc_buf = kmalloc(buff_len, GFP_KERNEL);
+ if (!desc_buf)
+ return -ENOMEM;
+ } else {
+ desc_buf = param_read_buf;
+ is_kmalloc = false;
+ }
+
+ /* Request for full descriptor */
+ ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC,
+ desc_id, desc_index, 0, desc_buf,
+ &buff_len);
+
+ if (ret) {
+ dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d\n",
+ __func__, desc_id, desc_index, param_offset, ret);
+ goto out;
+ }
+
+ /* Sanity check */
+ if (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id) {
+ dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header\n",
+ __func__, desc_buf[QUERY_DESC_DESC_TYPE_OFFSET]);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Check wherher we will not copy more data, than available */
+ if (is_kmalloc && param_size > buff_len)
+ param_size = buff_len;
+
+ if (is_kmalloc)
+ memcpy(param_read_buf, &desc_buf[param_offset], param_size);
+out:
+ if (is_kmalloc)
+ kfree(desc_buf);
+ return ret;
+}
+
+/* replace non-printable or non-ASCII characters with spaces */
+static inline void ufshcd_remove_non_printable(uint8_t *val)
+{
+ if (!val)
+ return;
+
+ if (*val < 0x20 || *val > 0x7e)
+ *val = ' ';
+}
+
+/**
+ * ufshcd_uic_pwr_ctrl - executes UIC commands (which affects the link power
+ * state) and waits for it to take effect.
+ *
+ */
+static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
+{
+ unsigned long start = 0;
+ u8 status;
+ int ret;
+
+ ret = ufshcd_send_uic_cmd(hba, cmd);
+ if (ret) {
+ dev_err(hba->dev,
+ "pwr ctrl cmd 0x%x with mode 0x%x uic error %d\n",
+ cmd->command, cmd->argument3, ret);
+
+ return ret;
+ }
+
+ start = get_timer(0);
+ do {
+ status = ufshcd_get_upmcrs(hba);
+ if (get_timer(start) > UFS_UIC_CMD_TIMEOUT) {
+ dev_err(hba->dev,
+ "pwr ctrl cmd 0x%x failed, host upmcrs:0x%x\n",
+ cmd->command, status);
+ ret = (status != PWR_OK) ? status : -1;
+ break;
+ }
+ } while (status != PWR_LOCAL);
+
+ return ret;
+}
+
+/**
+ * ufshcd_uic_change_pwr_mode - Perform the UIC power mode change
+ * using DME_SET primitives.
+ */
+static int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode)
+{
+ struct uic_command uic_cmd = {0};
+ int ret;
+
+ uic_cmd.command = UIC_CMD_DME_SET;
+ uic_cmd.argument1 = UIC_ARG_MIB(PA_PWRMODE);
+ uic_cmd.argument3 = mode;
+ ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd);
+
+ return ret;
+}
+
+static
+void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufs_hba *hba,
+ struct scsi_cmd *pccb, u32 upiu_flags)
+{
+ struct utp_upiu_req *ucd_req_ptr = hba->ucd_req_ptr;
+ unsigned int cdb_len;
+
+ /* command descriptor fields */
+ ucd_req_ptr->header.dword_0 =
+ UPIU_HEADER_DWORD(UPIU_TRANSACTION_COMMAND, upiu_flags,
+ pccb->lun, TASK_TAG);
+ ucd_req_ptr->header.dword_1 =
+ UPIU_HEADER_DWORD(UPIU_COMMAND_SET_TYPE_SCSI, 0, 0, 0);
+
+ /* Total EHS length and Data segment length will be zero */
+ ucd_req_ptr->header.dword_2 = 0;
+
+ ucd_req_ptr->sc.exp_data_transfer_len = cpu_to_be32(pccb->datalen);
+
+ cdb_len = min_t(unsigned short, pccb->cmdlen, UFS_CDB_SIZE);
+ memset(ucd_req_ptr->sc.cdb, 0, UFS_CDB_SIZE);
+ memcpy(ucd_req_ptr->sc.cdb, pccb->cmd, cdb_len);
+
+ memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
+ ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr));
+ ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr));
+}
+
+static inline void prepare_prdt_desc(struct ufshcd_sg_entry *entry,
+ unsigned char *buf, ulong len)
+{
+ entry->size = cpu_to_le32(len) | GENMASK(1, 0);
+ entry->base_addr = cpu_to_le32(lower_32_bits((unsigned long)buf));
+ entry->upper_addr = cpu_to_le32(upper_32_bits((unsigned long)buf));
+}
+
+static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb)
+{
+ struct utp_transfer_req_desc *req_desc = hba->utrdl;
+ struct ufshcd_sg_entry *prd_table = hba->ucd_prdt_ptr;
+ ulong datalen = pccb->datalen;
+ int table_length;
+ u8 *buf;
+ int i;
+
+ if (!datalen) {
+ req_desc->prd_table_length = 0;
+ ufshcd_cache_flush(req_desc, sizeof(*req_desc));
+ return;
+ }
+
+ table_length = DIV_ROUND_UP(pccb->datalen, MAX_PRDT_ENTRY);
+ buf = pccb->pdata;
+ i = table_length;
+ while (--i) {
+ prepare_prdt_desc(&prd_table[table_length - i - 1], buf,
+ MAX_PRDT_ENTRY - 1);
+ buf += MAX_PRDT_ENTRY;
+ datalen -= MAX_PRDT_ENTRY;
+ }
+
+ prepare_prdt_desc(&prd_table[table_length - i - 1], buf, datalen - 1);
+
+ req_desc->prd_table_length = table_length;
+ ufshcd_cache_flush(prd_table, sizeof(*prd_table) * table_length);
+ ufshcd_cache_flush(req_desc, sizeof(*req_desc));
+}
+
+static int ufs_scsi_exec(struct udevice *scsi_dev, struct scsi_cmd *pccb)
+{
+ struct ufs_hba *hba = dev_get_uclass_priv(scsi_dev->parent);
+ u32 upiu_flags;
+ int ocs, result = 0;
+ u8 scsi_status;
+
+ ufshcd_prepare_req_desc_hdr(hba, &upiu_flags, pccb->dma_dir);
+ ufshcd_prepare_utp_scsi_cmd_upiu(hba, pccb, upiu_flags);
+ prepare_prdt_table(hba, pccb);
+
+ ufshcd_cache_flush(pccb->pdata, pccb->datalen);
+
+ ufshcd_send_command(hba, TASK_TAG);
+
+ ufshcd_cache_invalidate(pccb->pdata, pccb->datalen);
+
+ ocs = ufshcd_get_tr_ocs(hba);
+ switch (ocs) {
+ case OCS_SUCCESS:
+ result = ufshcd_get_req_rsp(hba->ucd_rsp_ptr);
+ switch (result) {
+ case UPIU_TRANSACTION_RESPONSE:
+ result = ufshcd_get_rsp_upiu_result(hba->ucd_rsp_ptr);
+
+ scsi_status = result & MASK_SCSI_STATUS;
+ if (scsi_status)
+ return -EINVAL;
+
+ break;
+ case UPIU_TRANSACTION_REJECT_UPIU:
+ /* TODO: handle Reject UPIU Response */
+ dev_err(hba->dev,
+ "Reject UPIU not fully implemented\n");
+ return -EINVAL;
+ default:
+ dev_err(hba->dev,
+ "Unexpected request response code = %x\n",
+ result);
+ return -EINVAL;
+ }
+ break;
+ default:
+ dev_err(hba->dev, "OCS error from controller = %x\n", ocs);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static inline int ufshcd_read_desc(struct ufs_hba *hba, enum desc_idn desc_id,
+ int desc_index, u8 *buf, u32 size)
+{
+ return ufshcd_read_desc_param(hba, desc_id, desc_index, 0, buf, size);
+}
+
+static int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size)
+{
+ return ufshcd_read_desc(hba, QUERY_DESC_IDN_DEVICE, 0, buf, size);
+}
+
+/**
+ * ufshcd_read_string_desc - read string descriptor
+ *
+ */
+static int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index,
+ u8 *buf, u32 size, bool ascii)
+{
+ int err = 0;
+
+ err = ufshcd_read_desc(hba, QUERY_DESC_IDN_STRING, desc_index, buf,
+ size);
+
+ if (err) {
+ dev_err(hba->dev, "%s: reading String Desc failed after %d retries. err = %d\n",
+ __func__, QUERY_REQ_RETRIES, err);
+ goto out;
+ }
+
+ if (ascii) {
+ int desc_len;
+ int ascii_len;
+ int i;
+ u8 *buff_ascii;
+
+ desc_len = buf[0];
+ /* remove header and divide by 2 to move from UTF16 to UTF8 */
+ ascii_len = (desc_len - QUERY_DESC_HDR_SIZE) / 2 + 1;
+ if (size < ascii_len + QUERY_DESC_HDR_SIZE) {
+ dev_err(hba->dev, "%s: buffer allocated size is too small\n",
+ __func__);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ buff_ascii = kmalloc(ascii_len, GFP_KERNEL);
+ if (!buff_ascii) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ /*
+ * the descriptor contains string in UTF16 format
+ * we need to convert to utf-8 so it can be displayed
+ */
+ utf16_to_utf8(buff_ascii,
+ (uint16_t *)&buf[QUERY_DESC_HDR_SIZE], ascii_len);
+
+ /* replace non-printable or non-ASCII characters with spaces */
+ for (i = 0; i < ascii_len; i++)
+ ufshcd_remove_non_printable(&buff_ascii[i]);
+
+ memset(buf + QUERY_DESC_HDR_SIZE, 0,
+ size - QUERY_DESC_HDR_SIZE);
+ memcpy(buf + QUERY_DESC_HDR_SIZE, buff_ascii, ascii_len);
+ buf[QUERY_DESC_LENGTH_OFFSET] = ascii_len + QUERY_DESC_HDR_SIZE;
+ kfree(buff_ascii);
+ }
+out:
+ return err;
+}
+
+static int ufs_get_device_desc(struct ufs_hba *hba,
+ struct ufs_dev_desc *dev_desc)
+{
+ int err;
+ size_t buff_len;
+ u8 model_index;
+ u8 *desc_buf;
+
+ buff_len = max_t(size_t, hba->desc_size.dev_desc,
+ QUERY_DESC_MAX_SIZE + 1);
+ desc_buf = kmalloc(buff_len, GFP_KERNEL);
+ if (!desc_buf) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = ufshcd_read_device_desc(hba, desc_buf, hba->desc_size.dev_desc);
+ if (err) {
+ dev_err(hba->dev, "%s: Failed reading Device Desc. err = %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ /*
+ * getting vendor (manufacturerID) and Bank Index in big endian
+ * format
+ */
+ dev_desc->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 |
+ desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1];
+
+ model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];
+
+ /* Zero-pad entire buffer for string termination. */
+ memset(desc_buf, 0, buff_len);
+
+ err = ufshcd_read_string_desc(hba, model_index, desc_buf,
+ QUERY_DESC_MAX_SIZE, true/*ASCII*/);
+ if (err) {
+ dev_err(hba->dev, "%s: Failed reading Product Name. err = %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ desc_buf[QUERY_DESC_MAX_SIZE] = '\0';
+ strlcpy(dev_desc->model, (char *)(desc_buf + QUERY_DESC_HDR_SIZE),
+ min_t(u8, desc_buf[QUERY_DESC_LENGTH_OFFSET],
+ MAX_MODEL_LEN));
+
+ /* Null terminate the model string */
+ dev_desc->model[MAX_MODEL_LEN] = '\0';
+
+out:
+ kfree(desc_buf);
+ return err;
+}
+
+struct ufs_ref_clk {
+ unsigned long freq_hz;
+ enum ufs_ref_clk_freq val;
+};
+
+static const struct ufs_ref_clk ufs_ref_clk_freqs[] = {
+ {19200000, REF_CLK_FREQ_19_2_MHZ},
+ {26000000, REF_CLK_FREQ_26_MHZ},
+ {38400000, REF_CLK_FREQ_38_4_MHZ},
+ {52000000, REF_CLK_FREQ_52_MHZ},
+ {0, REF_CLK_FREQ_INVAL},
+};
+
+static enum ufs_ref_clk_freq
+ufs_get_bref_clk_from_hz(unsigned long freq)
+{
+ int i;
+
+ for (i = 0; ufs_ref_clk_freqs[i].freq_hz; i++)
+ if (ufs_ref_clk_freqs[i].freq_hz == freq)
+ return ufs_ref_clk_freqs[i].val;
+
+ return REF_CLK_FREQ_INVAL;
+}
+
+enum ufs_ref_clk_freq ufshcd_parse_dev_ref_clk_freq(struct ufs_hba *hba, struct clk *refclk)
+{
+ unsigned long freq;
+
+ freq = clk_get_rate(refclk);
+ return ufs_get_bref_clk_from_hz(freq);
+}
+
+static int ufshcd_set_dev_ref_clk(struct ufs_hba *hba)
+{
+ int err;
+ struct clk *ref_clk;
+ u32 host_ref_clk_freq;
+ u32 dev_ref_clk_freq;
+
+ /* get ref_clk */
+ ref_clk = devm_clk_get(hba->dev, "ref_clk");
+ if (IS_ERR((const void *)ref_clk)) {
+ err = PTR_ERR(ref_clk);
+ goto out;
+ }
+
+ host_ref_clk_freq = ufshcd_parse_dev_ref_clk_freq(hba, ref_clk);
+ if (host_ref_clk_freq == REF_CLK_FREQ_INVAL)
+ dev_err(hba->dev,
+ "invalid ref_clk setting = %ld\n", clk_get_rate(ref_clk));
+
+ if (host_ref_clk_freq == REF_CLK_FREQ_INVAL)
+ goto out;
+
+ err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR,
+ QUERY_ATTR_IDN_REF_CLK_FREQ, 0, 0, &dev_ref_clk_freq);
+
+ if (err) {
+ dev_err(hba->dev, "failed reading bRefClkFreq. err = %d\n", err);
+ goto out;
+ }
+
+ if (dev_ref_clk_freq == host_ref_clk_freq)
+ goto out; /* nothing to update */
+
+ err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
+ QUERY_ATTR_IDN_REF_CLK_FREQ, 0, 0, &host_ref_clk_freq);
+
+ if (err) {
+ dev_err(hba->dev, "bRefClkFreq setting to %lu Hz failed\n",
+ ufs_ref_clk_freqs[host_ref_clk_freq].freq_hz);
+ goto out;
+ }
+
+ dev_dbg(hba->dev, "bRefClkFreq setting to %lu Hz succeeded\n",
+ ufs_ref_clk_freqs[host_ref_clk_freq].freq_hz);
+
+out:
+ return err;
+}
+
+/**
+ * ufshcd_get_max_pwr_mode - reads the max power mode negotiated with device
+ */
+static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba)
+{
+ struct ufs_pa_layer_attr *pwr_info = &hba->max_pwr_info.info;
+
+ if (hba->max_pwr_info.is_valid)
+ return 0;
+
+ if (hba->quirks & UFSHCD_QUIRK_HIBERN_FASTAUTO) {
+ pwr_info->pwr_tx = FASTAUTO_MODE;
+ pwr_info->pwr_rx = FASTAUTO_MODE;
+ } else {
+ pwr_info->pwr_tx = FAST_MODE;
+ pwr_info->pwr_rx = FAST_MODE;
+ }
+ pwr_info->hs_rate = PA_HS_MODE_B;
+
+ /* Get the connected lane count */
+ ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES),
+ &pwr_info->lane_rx);
+ ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES),
+ &pwr_info->lane_tx);
+
+ if (!pwr_info->lane_rx || !pwr_info->lane_tx) {
+ dev_err(hba->dev, "%s: invalid connected lanes value. rx=%d, tx=%d\n",
+ __func__, pwr_info->lane_rx, pwr_info->lane_tx);
+ return -EINVAL;
+ }
+
+ /*
+ * First, get the maximum gears of HS speed.
+ * If a zero value, it means there is no HSGEAR capability.
+ * Then, get the maximum gears of PWM speed.
+ */
+ ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), &pwr_info->gear_rx);
+ if (!pwr_info->gear_rx) {
+ ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
+ &pwr_info->gear_rx);
+ if (!pwr_info->gear_rx) {
+ dev_err(hba->dev, "%s: invalid max pwm rx gear read = %d\n",
+ __func__, pwr_info->gear_rx);
+ return -EINVAL;
+ }
+ pwr_info->pwr_rx = SLOW_MODE;
+ }
+
+ ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR),
+ &pwr_info->gear_tx);
+ if (!pwr_info->gear_tx) {
+ ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
+ &pwr_info->gear_tx);
+ if (!pwr_info->gear_tx) {
+ dev_err(hba->dev, "%s: invalid max pwm tx gear read = %d\n",
+ __func__, pwr_info->gear_tx);
+ return -EINVAL;
+ }
+ pwr_info->pwr_tx = SLOW_MODE;
+ }
+
+ hba->max_pwr_info.is_valid = true;
+ return ufshcd_ops_get_max_pwr_mode(hba, &hba->max_pwr_info);
+}
+
+static int ufshcd_change_power_mode(struct ufs_hba *hba,
+ struct ufs_pa_layer_attr *pwr_mode)
+{
+ int ret;
+
+ /* if already configured to the requested pwr_mode */
+ if (pwr_mode->gear_rx == hba->pwr_info.gear_rx &&
+ pwr_mode->gear_tx == hba->pwr_info.gear_tx &&
+ pwr_mode->lane_rx == hba->pwr_info.lane_rx &&
+ pwr_mode->lane_tx == hba->pwr_info.lane_tx &&
+ pwr_mode->pwr_rx == hba->pwr_info.pwr_rx &&
+ pwr_mode->pwr_tx == hba->pwr_info.pwr_tx &&
+ pwr_mode->hs_rate == hba->pwr_info.hs_rate) {
+ dev_dbg(hba->dev, "%s: power already configured\n", __func__);
+ return 0;
+ }
+
+ /*
+ * Configure attributes for power mode change with below.
+ * - PA_RXGEAR, PA_ACTIVERXDATALANES, PA_RXTERMINATION,
+ * - PA_TXGEAR, PA_ACTIVETXDATALANES, PA_TXTERMINATION,
+ * - PA_HSSERIES
+ */
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXGEAR), pwr_mode->gear_rx);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVERXDATALANES),
+ pwr_mode->lane_rx);
+ if (pwr_mode->pwr_rx == FASTAUTO_MODE || pwr_mode->pwr_rx == FAST_MODE)
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), TRUE);
+ else
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), FALSE);
+
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXGEAR), pwr_mode->gear_tx);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVETXDATALANES),
+ pwr_mode->lane_tx);
+ if (pwr_mode->pwr_tx == FASTAUTO_MODE || pwr_mode->pwr_tx == FAST_MODE)
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), TRUE);
+ else
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), FALSE);
+
+ if (pwr_mode->pwr_rx == FASTAUTO_MODE ||
+ pwr_mode->pwr_tx == FASTAUTO_MODE ||
+ pwr_mode->pwr_rx == FAST_MODE ||
+ pwr_mode->pwr_tx == FAST_MODE)
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HSSERIES),
+ pwr_mode->hs_rate);
+
+ ret = ufshcd_uic_change_pwr_mode(hba, pwr_mode->pwr_rx << 4 |
+ pwr_mode->pwr_tx);
+
+ if (ret) {
+ dev_err(hba->dev,
+ "%s: power mode change failed %d\n", __func__, ret);
+
+ return ret;
+ }
+
+ /* Copy new Power Mode to power info */
+ memcpy(&hba->pwr_info, pwr_mode, sizeof(struct ufs_pa_layer_attr));
+
+ return ret;
+}
+
+/**
+ * ufshcd_verify_dev_init() - Verify device initialization
+ *
+ */
+static int ufshcd_verify_dev_init(struct ufs_hba *hba)
+{
+ int retries;
+ int err;
+
+ for (retries = NOP_OUT_RETRIES; retries > 0; retries--) {
+ err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_NOP,
+ NOP_OUT_TIMEOUT);
+ if (!err || err == -ETIMEDOUT)
+ break;
+
+ dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
+ }
+
+ if (err)
+ dev_err(hba->dev, "%s: NOP OUT failed %d\n", __func__, err);
+
+ return err;
+}
+
+/**
+ * ufshcd_complete_dev_init() - checks device readiness
+ */
+static int ufshcd_complete_dev_init(struct ufs_hba *hba)
+{
+ int i;
+ int err;
+ bool flag_res = 1;
+
+ err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG,
+ QUERY_FLAG_IDN_FDEVICEINIT, NULL);
+ if (err) {
+ dev_err(hba->dev,
+ "%s setting fDeviceInit flag failed with error %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ /* poll for max. 1000 iterations for fDeviceInit flag to clear */
+ for (i = 0; i < 1000 && !err && flag_res; i++)
+ err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_READ_FLAG,
+ QUERY_FLAG_IDN_FDEVICEINIT,
+ &flag_res);
+
+ if (err)
+ dev_err(hba->dev,
+ "%s reading fDeviceInit flag failed with error %d\n",
+ __func__, err);
+ else if (flag_res)
+ dev_err(hba->dev,
+ "%s fDeviceInit was not cleared by the device\n",
+ __func__);
+
+out:
+ return err;
+}
+
+static void ufshcd_def_desc_sizes(struct ufs_hba *hba)
+{
+ hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE;
+ hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE;
+ hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE;
+ hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE;
+ hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE;
+ hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE;
+ hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE;
+}
+
+static int ufs_start(struct ufs_hba *hba)
+{
+ struct ufs_dev_desc card = {0};
+ int ret;
+
+ ret = ufshcd_link_startup(hba);
+ if (ret)
+ return ret;
+
+ ret = ufshcd_verify_dev_init(hba);
+ if (ret)
+ return ret;
+
+ ret = ufshcd_complete_dev_init(hba);
+ if (ret)
+ return ret;
+
+ /* Init check for device descriptor sizes */
+ ufshcd_init_desc_sizes(hba);
+
+ ret = ufs_get_device_desc(hba, &card);
+ if (ret) {
+ dev_err(hba->dev, "%s: Failed getting device info. err = %d\n",
+ __func__, ret);
+
+ return ret;
+ }
+
+ ufshcd_set_dev_ref_clk(hba);
+
+ if (ufshcd_get_max_pwr_mode(hba)) {
+ dev_err(hba->dev,
+ "%s: Failed getting max supported power mode\n",
+ __func__);
+ } else {
+ ret = ufshcd_change_power_mode(hba, &hba->max_pwr_info.info);
+ if (ret) {
+ dev_err(hba->dev, "%s: Failed setting power mode, err = %d\n",
+ __func__, ret);
+
+ return ret;
+ }
+
+ debug("UFS Device %s is up!\n", hba->dev->name);
+ ufshcd_print_pwr_info(hba);
+ }
+
+ return 0;
+}
+
+int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops)
+{
+ struct ufs_hba *hba = dev_get_uclass_priv(ufs_dev);
+ struct scsi_plat *scsi_plat;
+ struct udevice *scsi_dev;
+ void __iomem *mmio_base;
+ int err;
+
+ device_find_first_child(ufs_dev, &scsi_dev);
+ if (!scsi_dev)
+ return -ENODEV;
+
+ scsi_plat = dev_get_uclass_plat(scsi_dev);
+ scsi_plat->max_id = UFSHCD_MAX_ID;
+ scsi_plat->max_lun = UFS_MAX_LUNS;
+ scsi_plat->max_bytes_per_req = UFS_MAX_BYTES;
+
+ hba->dev = ufs_dev;
+ hba->ops = hba_ops;
+
+ if (device_is_on_pci_bus(ufs_dev)) {
+ mmio_base = dm_pci_map_bar(ufs_dev, PCI_BASE_ADDRESS_0, 0, 0,
+ PCI_REGION_TYPE, PCI_REGION_MEM);
+ } else {
+ mmio_base = dev_read_addr_ptr(ufs_dev);
+ }
+ hba->mmio_base = mmio_base;
+
+ /* Set descriptor lengths to specification defaults */
+ ufshcd_def_desc_sizes(hba);
+
+ ufshcd_ops_init(hba);
+
+ /* Read capabilities registers */
+ hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES);
+ if (hba->quirks & UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS)
+ hba->capabilities &= ~MASK_64_ADDRESSING_SUPPORT;
+
+ /* Get UFS version supported by the controller */
+ hba->version = ufshcd_get_ufs_version(hba);
+ if (hba->version != UFSHCI_VERSION_10 &&
+ hba->version != UFSHCI_VERSION_11 &&
+ hba->version != UFSHCI_VERSION_20 &&
+ hba->version != UFSHCI_VERSION_21 &&
+ hba->version != UFSHCI_VERSION_30 &&
+ hba->version != UFSHCI_VERSION_31 &&
+ hba->version != UFSHCI_VERSION_40)
+ dev_err(hba->dev, "invalid UFS version 0x%x\n",
+ hba->version);
+
+ /* Get Interrupt bit mask per version */
+ hba->intr_mask = ufshcd_get_intr_mask(hba);
+
+ /* Allocate memory for host memory space */
+ err = ufshcd_memory_alloc(hba);
+ if (err) {
+ dev_err(hba->dev, "Memory allocation failed\n");
+ return err;
+ }
+
+ /* Configure Local data structures */
+ ufshcd_host_memory_configure(hba);
+
+ /*
+ * In order to avoid any spurious interrupt immediately after
+ * registering UFS controller interrupt handler, clear any pending UFS
+ * interrupt status and disable all the UFS interrupts.
+ */
+ ufshcd_writel(hba, ufshcd_readl(hba, REG_INTERRUPT_STATUS),
+ REG_INTERRUPT_STATUS);
+ ufshcd_writel(hba, 0, REG_INTERRUPT_ENABLE);
+
+ mb(); /* flush previous writes */
+
+ /* Reset the attached device */
+ ufshcd_device_reset(hba);
+
+ err = ufshcd_hba_enable(hba);
+ if (err) {
+ dev_err(hba->dev, "Host controller enable failed\n");
+ return err;
+ }
+
+ err = ufs_start(hba);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+#if IS_ENABLED(CONFIG_BOUNCE_BUFFER)
+static int ufs_scsi_buffer_aligned(struct udevice *scsi_dev, struct bounce_buffer *state)
+{
+#ifdef CONFIG_PHYS_64BIT
+ struct ufs_hba *hba = dev_get_uclass_priv(scsi_dev->parent);
+ uintptr_t ubuf = (uintptr_t)state->user_buffer;
+ size_t len = state->len_aligned;
+
+ /* Check if below 32bit boundary */
+ if ((hba->quirks & UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS) &&
+ ((ubuf >> 32) || (ubuf + len) >> 32)) {
+ dev_dbg(scsi_dev, "Buffer above 32bit boundary %lx-%lx\n",
+ ubuf, ubuf + len);
+ return 0;
+ }
+#endif
+ return 1;
+}
+#endif /* CONFIG_BOUNCE_BUFFER */
+
+static struct scsi_ops ufs_ops = {
+ .exec = ufs_scsi_exec,
+#if IS_ENABLED(CONFIG_BOUNCE_BUFFER)
+ .buffer_aligned = ufs_scsi_buffer_aligned,
+#endif /* CONFIG_BOUNCE_BUFFER */
+};
+
+int ufs_probe_dev(int index)
+{
+ struct udevice *dev;
+
+ return uclass_get_device(UCLASS_UFS, index, &dev);
+}
+
+int ufs_probe(void)
+{
+ struct udevice *dev;
+ int ret, i;
+
+ for (i = 0;; i++) {
+ ret = uclass_get_device(UCLASS_UFS, i, &dev);
+ if (ret == -ENODEV)
+ break;
+ }
+
+ return 0;
+}
+
+U_BOOT_DRIVER(ufs_scsi) = {
+ .id = UCLASS_SCSI,
+ .name = "ufs_scsi",
+ .ops = &ufs_ops,
+};
+
+static int ufs_post_bind(struct udevice *dev)
+{
+ return device_bind_driver(dev, "ufs_scsi", "ufs_scsi", NULL);
+}
UCLASS_DRIVER(ufs) = {
- .id = UCLASS_UFS,
- .name = "ufs",
+ .id = UCLASS_UFS,
+ .name = "ufs",
+ .post_bind = ufs_post_bind,
.per_device_auto = sizeof(struct ufs_hba),
};
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c
deleted file mode 100644
index 57e6e8c013b..00000000000
--- a/drivers/ufs/ufs.c
+++ /dev/null
@@ -1,2093 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/**
- * ufs.c - Universal Flash Storage (UFS) driver
- *
- * Taken from Linux Kernel v5.2 (drivers/scsi/ufs/ufshcd.c) and ported
- * to u-boot.
- *
- * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com
- */
-
-#include <bouncebuf.h>
-#include <charset.h>
-#include <dm.h>
-#include <log.h>
-#include <dm/device_compat.h>
-#include <dm/devres.h>
-#include <dm/lists.h>
-#include <dm/device-internal.h>
-#include <malloc.h>
-#include <hexdump.h>
-#include <scsi.h>
-#include <ufs.h>
-#include <asm/io.h>
-#include <asm/dma-mapping.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-
-#include "ufs.h"
-
-#define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
- UTP_TASK_REQ_COMPL |\
- UFSHCD_ERROR_MASK)
-/* maximum number of link-startup retries */
-#define DME_LINKSTARTUP_RETRIES 3
-
-/* maximum number of retries for a general UIC command */
-#define UFS_UIC_COMMAND_RETRIES 3
-
-/* Query request retries */
-#define QUERY_REQ_RETRIES 3
-/* Query request timeout */
-#define QUERY_REQ_TIMEOUT 1500 /* 1.5 seconds */
-
-/* maximum timeout in ms for a general UIC command */
-#define UFS_UIC_CMD_TIMEOUT 1000
-/* NOP OUT retries waiting for NOP IN response */
-#define NOP_OUT_RETRIES 10
-/* Timeout after 30 msecs if NOP OUT hangs without response */
-#define NOP_OUT_TIMEOUT 30 /* msecs */
-
-/* Only use one Task Tag for all requests */
-#define TASK_TAG 0
-
-/* Expose the flag value from utp_upiu_query.value */
-#define MASK_QUERY_UPIU_FLAG_LOC 0xFF
-
-#define MAX_PRDT_ENTRY 262144
-
-/* maximum bytes per request */
-#define UFS_MAX_BYTES (128 * 256 * 1024)
-
-static inline bool ufshcd_is_hba_active(struct ufs_hba *hba);
-static inline void ufshcd_hba_stop(struct ufs_hba *hba);
-static int ufshcd_hba_enable(struct ufs_hba *hba);
-
-/*
- * ufshcd_wait_for_register - wait for register value to change
- */
-static int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
- u32 val, unsigned long timeout_ms)
-{
- int err = 0;
- unsigned long start = get_timer(0);
-
- /* ignore bits that we don't intend to wait on */
- val = val & mask;
-
- while ((ufshcd_readl(hba, reg) & mask) != val) {
- if (get_timer(start) > timeout_ms) {
- if ((ufshcd_readl(hba, reg) & mask) != val)
- err = -ETIMEDOUT;
- break;
- }
- }
-
- return err;
-}
-
-/**
- * ufshcd_init_pwr_info - setting the POR (power on reset)
- * values in hba power info
- */
-static void ufshcd_init_pwr_info(struct ufs_hba *hba)
-{
- hba->pwr_info.gear_rx = UFS_PWM_G1;
- hba->pwr_info.gear_tx = UFS_PWM_G1;
- hba->pwr_info.lane_rx = 1;
- hba->pwr_info.lane_tx = 1;
- hba->pwr_info.pwr_rx = SLOWAUTO_MODE;
- hba->pwr_info.pwr_tx = SLOWAUTO_MODE;
- hba->pwr_info.hs_rate = 0;
-}
-
-/**
- * ufshcd_print_pwr_info - print power params as saved in hba
- * power info
- */
-static void ufshcd_print_pwr_info(struct ufs_hba *hba)
-{
- static const char * const names[] = {
- "INVALID MODE",
- "FAST MODE",
- "SLOW_MODE",
- "INVALID MODE",
- "FASTAUTO_MODE",
- "SLOWAUTO_MODE",
- "INVALID MODE",
- };
-
- dev_err(hba->dev, "[RX, TX]: gear=[%d, %d], lane[%d, %d], pwr[%s, %s], rate = %d\n",
- hba->pwr_info.gear_rx, hba->pwr_info.gear_tx,
- hba->pwr_info.lane_rx, hba->pwr_info.lane_tx,
- names[hba->pwr_info.pwr_rx],
- names[hba->pwr_info.pwr_tx],
- hba->pwr_info.hs_rate);
-}
-
-static void ufshcd_device_reset(struct ufs_hba *hba)
-{
- ufshcd_vops_device_reset(hba);
-}
-
-/**
- * ufshcd_ready_for_uic_cmd - Check if controller is ready
- * to accept UIC commands
- */
-static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba)
-{
- if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY)
- return true;
- else
- return false;
-}
-
-/**
- * ufshcd_get_uic_cmd_result - Get the UIC command result
- */
-static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
-{
- return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2) &
- MASK_UIC_COMMAND_RESULT;
-}
-
-/**
- * ufshcd_get_dme_attr_val - Get the value of attribute returned by UIC command
- */
-static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba)
-{
- return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3);
-}
-
-/**
- * ufshcd_is_device_present - Check if any device connected to
- * the host controller
- */
-static inline bool ufshcd_is_device_present(struct ufs_hba *hba)
-{
- return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) &
- DEVICE_PRESENT) ? true : false;
-}
-
-/**
- * ufshcd_send_uic_cmd - UFS Interconnect layer command API
- *
- */
-static int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
-{
- unsigned long start = 0;
- u32 intr_status;
- u32 enabled_intr_status;
-
- if (!ufshcd_ready_for_uic_cmd(hba)) {
- dev_err(hba->dev,
- "Controller not ready to accept UIC commands\n");
- return -EIO;
- }
-
- debug("sending uic command:%d\n", uic_cmd->command);
-
- /* Write Args */
- ufshcd_writel(hba, uic_cmd->argument1, REG_UIC_COMMAND_ARG_1);
- ufshcd_writel(hba, uic_cmd->argument2, REG_UIC_COMMAND_ARG_2);
- ufshcd_writel(hba, uic_cmd->argument3, REG_UIC_COMMAND_ARG_3);
-
- /* Write UIC Cmd */
- ufshcd_writel(hba, uic_cmd->command & COMMAND_OPCODE_MASK,
- REG_UIC_COMMAND);
-
- start = get_timer(0);
- do {
- intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
- enabled_intr_status = intr_status & hba->intr_mask;
- ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
-
- if (get_timer(start) > UFS_UIC_CMD_TIMEOUT) {
- dev_err(hba->dev,
- "Timedout waiting for UIC response\n");
-
- return -ETIMEDOUT;
- }
-
- if (enabled_intr_status & UFSHCD_ERROR_MASK) {
- dev_err(hba->dev, "Error in status:%08x\n",
- enabled_intr_status);
-
- return -1;
- }
- } while (!(enabled_intr_status & UFSHCD_UIC_MASK));
-
- uic_cmd->argument2 = ufshcd_get_uic_cmd_result(hba);
- uic_cmd->argument3 = ufshcd_get_dme_attr_val(hba);
-
- debug("Sent successfully\n");
-
- return 0;
-}
-
-int ufshcd_dme_configure_adapt(struct ufs_hba *hba,
- int agreed_gear,
- int adapt_val)
-{
- int ret;
-
- if (agreed_gear < UFS_HS_G4)
- adapt_val = PA_NO_ADAPT;
-
- ret = ufshcd_dme_set(hba,
- UIC_ARG_MIB(PA_TXHSADAPTTYPE),
- adapt_val);
- return ret;
-}
-
-/**
- * ufshcd_dme_set_attr - UIC command for DME_SET, DME_PEER_SET
- *
- */
-int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel, u8 attr_set,
- u32 mib_val, u8 peer)
-{
- struct uic_command uic_cmd = {0};
- static const char *const action[] = {
- "dme-set",
- "dme-peer-set"
- };
- const char *set = action[!!peer];
- int ret;
- int retries = UFS_UIC_COMMAND_RETRIES;
-
- uic_cmd.command = peer ?
- UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET;
- uic_cmd.argument1 = attr_sel;
- uic_cmd.argument2 = UIC_ARG_ATTR_TYPE(attr_set);
- uic_cmd.argument3 = mib_val;
-
- do {
- /* for peer attributes we retry upon failure */
- ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
- if (ret)
- dev_dbg(hba->dev, "%s: attr-id 0x%x val 0x%x error code %d\n",
- set, UIC_GET_ATTR_ID(attr_sel), mib_val, ret);
- } while (ret && peer && --retries);
-
- if (ret)
- dev_err(hba->dev, "%s: attr-id 0x%x val 0x%x failed %d retries\n",
- set, UIC_GET_ATTR_ID(attr_sel), mib_val,
- UFS_UIC_COMMAND_RETRIES - retries);
-
- return ret;
-}
-
-/**
- * ufshcd_dme_get_attr - UIC command for DME_GET, DME_PEER_GET
- *
- */
-int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
- u32 *mib_val, u8 peer)
-{
- struct uic_command uic_cmd = {0};
- static const char *const action[] = {
- "dme-get",
- "dme-peer-get"
- };
- const char *get = action[!!peer];
- int ret;
- int retries = UFS_UIC_COMMAND_RETRIES;
-
- uic_cmd.command = peer ?
- UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET;
- uic_cmd.argument1 = attr_sel;
-
- do {
- /* for peer attributes we retry upon failure */
- ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
- if (ret)
- dev_dbg(hba->dev, "%s: attr-id 0x%x error code %d\n",
- get, UIC_GET_ATTR_ID(attr_sel), ret);
- } while (ret && peer && --retries);
-
- if (ret)
- dev_err(hba->dev, "%s: attr-id 0x%x failed %d retries\n",
- get, UIC_GET_ATTR_ID(attr_sel),
- UFS_UIC_COMMAND_RETRIES - retries);
-
- if (mib_val && !ret)
- *mib_val = uic_cmd.argument3;
-
- return ret;
-}
-
-static int ufshcd_disable_tx_lcc(struct ufs_hba *hba, bool peer)
-{
- u32 tx_lanes, i, err = 0;
-
- if (!peer)
- ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES),
- &tx_lanes);
- else
- ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES),
- &tx_lanes);
- for (i = 0; i < tx_lanes; i++) {
- unsigned int val = UIC_ARG_MIB_SEL(TX_LCC_ENABLE,
- UIC_ARG_MPHY_TX_GEN_SEL_INDEX(i));
- if (!peer)
- err = ufshcd_dme_set(hba, val, 0);
- else
- err = ufshcd_dme_peer_set(hba, val, 0);
- if (err) {
- dev_err(hba->dev, "%s: TX LCC Disable failed, peer = %d, lane = %d, err = %d\n",
- __func__, peer, i, err);
- break;
- }
- }
-
- return err;
-}
-
-static inline int ufshcd_disable_device_tx_lcc(struct ufs_hba *hba)
-{
- return ufshcd_disable_tx_lcc(hba, true);
-}
-
-/**
- * ufshcd_dme_link_startup - Notify Unipro to perform link startup
- *
- */
-static int ufshcd_dme_link_startup(struct ufs_hba *hba)
-{
- struct uic_command uic_cmd = {0};
- int ret;
-
- uic_cmd.command = UIC_CMD_DME_LINK_STARTUP;
-
- ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
- if (ret)
- dev_dbg(hba->dev,
- "dme-link-startup: error code %d\n", ret);
- return ret;
-}
-
-/**
- * ufshcd_disable_intr_aggr - Disables interrupt aggregation.
- *
- */
-static inline void ufshcd_disable_intr_aggr(struct ufs_hba *hba)
-{
- ufshcd_writel(hba, 0, REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
-}
-
-/**
- * ufshcd_get_lists_status - Check UCRDY, UTRLRDY and UTMRLRDY
- */
-static inline int ufshcd_get_lists_status(u32 reg)
-{
- return !((reg & UFSHCD_STATUS_READY) == UFSHCD_STATUS_READY);
-}
-
-/**
- * ufshcd_enable_run_stop_reg - Enable run-stop registers,
- * When run-stop registers are set to 1, it indicates the
- * host controller that it can process the requests
- */
-static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
-{
- ufshcd_writel(hba, UTP_TASK_REQ_LIST_RUN_STOP_BIT,
- REG_UTP_TASK_REQ_LIST_RUN_STOP);
- ufshcd_writel(hba, UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
- REG_UTP_TRANSFER_REQ_LIST_RUN_STOP);
-}
-
-/**
- * ufshcd_enable_intr - enable interrupts
- */
-static void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs)
-{
- u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
- u32 rw;
-
- if (hba->version == UFSHCI_VERSION_10) {
- rw = set & INTERRUPT_MASK_RW_VER_10;
- set = rw | ((set ^ intrs) & intrs);
- } else {
- set |= intrs;
- }
-
- ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE);
-
- hba->intr_mask = set;
-}
-
-/**
- * ufshcd_make_hba_operational - Make UFS controller operational
- *
- * To bring UFS host controller to operational state,
- * 1. Enable required interrupts
- * 2. Configure interrupt aggregation
- * 3. Program UTRL and UTMRL base address
- * 4. Configure run-stop-registers
- *
- */
-static int ufshcd_make_hba_operational(struct ufs_hba *hba)
-{
- int err = 0;
- u32 reg;
-
- /* Enable required interrupts */
- ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
-
- /* Disable interrupt aggregation */
- ufshcd_disable_intr_aggr(hba);
-
- /* Configure UTRL and UTMRL base address registers */
- ufshcd_writel(hba, lower_32_bits((dma_addr_t)hba->utrdl),
- REG_UTP_TRANSFER_REQ_LIST_BASE_L);
- ufshcd_writel(hba, upper_32_bits((dma_addr_t)hba->utrdl),
- REG_UTP_TRANSFER_REQ_LIST_BASE_H);
- ufshcd_writel(hba, lower_32_bits((dma_addr_t)hba->utmrdl),
- REG_UTP_TASK_REQ_LIST_BASE_L);
- ufshcd_writel(hba, upper_32_bits((dma_addr_t)hba->utmrdl),
- REG_UTP_TASK_REQ_LIST_BASE_H);
-
- /*
- * Make sure base address and interrupt setup are updated before
- * enabling the run/stop registers below.
- */
- wmb();
-
- /*
- * UCRDY, UTMRLDY and UTRLRDY bits must be 1
- */
- reg = ufshcd_readl(hba, REG_CONTROLLER_STATUS);
- if (!(ufshcd_get_lists_status(reg))) {
- ufshcd_enable_run_stop_reg(hba);
- } else {
- dev_err(hba->dev,
- "Host controller not ready to process requests\n");
- err = -EIO;
- goto out;
- }
-
-out:
- return err;
-}
-
-/**
- * ufshcd_link_startup - Initialize unipro link startup
- */
-static int ufshcd_link_startup(struct ufs_hba *hba)
-{
- int ret;
- int retries = DME_LINKSTARTUP_RETRIES;
-
- do {
- ufshcd_ops_link_startup_notify(hba, PRE_CHANGE);
-
- ret = ufshcd_dme_link_startup(hba);
-
- /* check if device is detected by inter-connect layer */
- if (!ret && !ufshcd_is_device_present(hba)) {
- dev_err(hba->dev, "%s: Device not present\n", __func__);
- ret = -ENXIO;
- goto out;
- }
-
- /*
- * DME link lost indication is only received when link is up,
- * but we can't be sure if the link is up until link startup
- * succeeds. So reset the local Uni-Pro and try again.
- */
- if (ret && ufshcd_hba_enable(hba))
- goto out;
- } while (ret && retries--);
-
- if (ret)
- /* failed to get the link up... retire */
- goto out;
-
- /* Mark that link is up in PWM-G1, 1-lane, SLOW-AUTO mode */
- ufshcd_init_pwr_info(hba);
-
- if (hba->quirks & UFSHCD_QUIRK_BROKEN_LCC) {
- ret = ufshcd_disable_device_tx_lcc(hba);
- if (ret)
- goto out;
- }
-
- /* Include any host controller configuration via UIC commands */
- ret = ufshcd_ops_link_startup_notify(hba, POST_CHANGE);
- if (ret)
- goto out;
-
- /* Clear UECPA once due to LINERESET has happened during LINK_STARTUP */
- ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
- ret = ufshcd_make_hba_operational(hba);
-out:
- if (ret)
- dev_err(hba->dev, "link startup failed %d\n", ret);
-
- return ret;
-}
-
-/**
- * ufshcd_hba_stop - Send controller to reset state
- */
-static inline void ufshcd_hba_stop(struct ufs_hba *hba)
-{
- int err;
-
- ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
- err = ufshcd_wait_for_register(hba, REG_CONTROLLER_ENABLE,
- CONTROLLER_ENABLE, CONTROLLER_DISABLE,
- 10);
- if (err)
- dev_err(hba->dev, "%s: Controller disable failed\n", __func__);
-}
-
-/**
- * ufshcd_is_hba_active - Get controller state
- */
-static inline bool ufshcd_is_hba_active(struct ufs_hba *hba)
-{
- return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & CONTROLLER_ENABLE)
- ? false : true;
-}
-
-/**
- * ufshcd_hba_start - Start controller initialization sequence
- */
-static inline void ufshcd_hba_start(struct ufs_hba *hba)
-{
- ufshcd_writel(hba, CONTROLLER_ENABLE, REG_CONTROLLER_ENABLE);
-}
-
-/**
- * ufshcd_hba_enable - initialize the controller
- */
-static int ufshcd_hba_enable(struct ufs_hba *hba)
-{
- int retry;
-
- if (!ufshcd_is_hba_active(hba))
- /* change controller state to "reset state" */
- ufshcd_hba_stop(hba);
-
- ufshcd_ops_hce_enable_notify(hba, PRE_CHANGE);
-
- /* start controller initialization sequence */
- ufshcd_hba_start(hba);
-
- /*
- * To initialize a UFS host controller HCE bit must be set to 1.
- * During initialization the HCE bit value changes from 1->0->1.
- * When the host controller completes initialization sequence
- * it sets the value of HCE bit to 1. The same HCE bit is read back
- * to check if the controller has completed initialization sequence.
- * So without this delay the value HCE = 1, set in the previous
- * instruction might be read back.
- * This delay can be changed based on the controller.
- */
- mdelay(1);
-
- /* wait for the host controller to complete initialization */
- retry = 10;
- while (ufshcd_is_hba_active(hba)) {
- if (retry) {
- retry--;
- } else {
- dev_err(hba->dev, "Controller enable failed\n");
- return -EIO;
- }
- mdelay(5);
- }
-
- /* enable UIC related interrupts */
- ufshcd_enable_intr(hba, UFSHCD_UIC_MASK);
-
- ufshcd_ops_hce_enable_notify(hba, POST_CHANGE);
-
- return 0;
-}
-
-/**
- * ufshcd_host_memory_configure - configure local reference block with
- * memory offsets
- */
-static void ufshcd_host_memory_configure(struct ufs_hba *hba)
-{
- struct utp_transfer_req_desc *utrdlp;
- dma_addr_t cmd_desc_dma_addr;
- u16 response_offset;
- u16 prdt_offset;
-
- utrdlp = hba->utrdl;
- cmd_desc_dma_addr = (dma_addr_t)hba->ucdl;
-
- utrdlp->command_desc_base_addr_lo =
- cpu_to_le32(lower_32_bits(cmd_desc_dma_addr));
- utrdlp->command_desc_base_addr_hi =
- cpu_to_le32(upper_32_bits(cmd_desc_dma_addr));
-
- response_offset = offsetof(struct utp_transfer_cmd_desc, response_upiu);
- prdt_offset = offsetof(struct utp_transfer_cmd_desc, prd_table);
-
- utrdlp->response_upiu_offset = cpu_to_le16(response_offset >> 2);
- utrdlp->prd_table_offset = cpu_to_le16(prdt_offset >> 2);
- utrdlp->response_upiu_length = cpu_to_le16(ALIGNED_UPIU_SIZE >> 2);
-
- hba->ucd_req_ptr = (struct utp_upiu_req *)hba->ucdl;
- hba->ucd_rsp_ptr =
- (struct utp_upiu_rsp *)&hba->ucdl->response_upiu;
- hba->ucd_prdt_ptr =
- (struct ufshcd_sg_entry *)&hba->ucdl->prd_table;
-}
-
-/**
- * ufshcd_memory_alloc - allocate memory for host memory space data structures
- */
-static int ufshcd_memory_alloc(struct ufs_hba *hba)
-{
- /* Allocate one Transfer Request Descriptor
- * Should be aligned to 1k boundary.
- */
- hba->utrdl = memalign(1024,
- ALIGN(sizeof(struct utp_transfer_req_desc),
- ARCH_DMA_MINALIGN));
- if (!hba->utrdl) {
- dev_err(hba->dev, "Transfer Descriptor memory allocation failed\n");
- return -ENOMEM;
- }
-
- /* Allocate one Command Descriptor
- * Should be aligned to 1k boundary.
- */
- hba->ucdl = memalign(1024,
- ALIGN(sizeof(struct utp_transfer_cmd_desc),
- ARCH_DMA_MINALIGN));
- if (!hba->ucdl) {
- dev_err(hba->dev, "Command descriptor memory allocation failed\n");
- return -ENOMEM;
- }
-
- return 0;
-}
-
-/**
- * ufshcd_get_intr_mask - Get the interrupt bit mask
- */
-static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba)
-{
- u32 intr_mask = 0;
-
- switch (hba->version) {
- case UFSHCI_VERSION_10:
- intr_mask = INTERRUPT_MASK_ALL_VER_10;
- break;
- case UFSHCI_VERSION_11:
- case UFSHCI_VERSION_20:
- intr_mask = INTERRUPT_MASK_ALL_VER_11;
- break;
- case UFSHCI_VERSION_21:
- default:
- intr_mask = INTERRUPT_MASK_ALL_VER_21;
- break;
- }
-
- return intr_mask;
-}
-
-/**
- * ufshcd_get_ufs_version - Get the UFS version supported by the HBA
- */
-static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
-{
- return ufshcd_readl(hba, REG_UFS_VERSION);
-}
-
-/**
- * ufshcd_get_upmcrs - Get the power mode change request status
- */
-static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba)
-{
- return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7;
-}
-
-/**
- * ufshcd_cache_flush - Flush cache
- *
- * Flush cache in aligned address..address+size range.
- */
-static void ufshcd_cache_flush(void *addr, unsigned long size)
-{
- uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1);
- uintptr_t end_addr = ALIGN((uintptr_t)addr + size, ARCH_DMA_MINALIGN);
-
- flush_dcache_range(start_addr, end_addr);
-}
-
-/**
- * ufshcd_cache_invalidate - Invalidate cache
- *
- * Invalidate cache in aligned address..address+size range.
- */
-static void ufshcd_cache_invalidate(void *addr, unsigned long size)
-{
- uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1);
- uintptr_t end_addr = ALIGN((uintptr_t)addr + size, ARCH_DMA_MINALIGN);
-
- invalidate_dcache_range(start_addr, end_addr);
-}
-
-/**
- * ufshcd_prepare_req_desc_hdr() - Fills the requests header
- * descriptor according to request
- */
-static void ufshcd_prepare_req_desc_hdr(struct ufs_hba *hba,
- u32 *upiu_flags,
- enum dma_data_direction cmd_dir)
-{
- struct utp_transfer_req_desc *req_desc = hba->utrdl;
- u32 data_direction;
- u32 dword_0;
-
- if (cmd_dir == DMA_FROM_DEVICE) {
- data_direction = UTP_DEVICE_TO_HOST;
- *upiu_flags = UPIU_CMD_FLAGS_READ;
- } else if (cmd_dir == DMA_TO_DEVICE) {
- data_direction = UTP_HOST_TO_DEVICE;
- *upiu_flags = UPIU_CMD_FLAGS_WRITE;
- } else {
- data_direction = UTP_NO_DATA_TRANSFER;
- *upiu_flags = UPIU_CMD_FLAGS_NONE;
- }
-
- dword_0 = data_direction | (0x1 << UPIU_COMMAND_TYPE_OFFSET);
-
- /* Enable Interrupt for command */
- dword_0 |= UTP_REQ_DESC_INT_CMD;
-
- /* Transfer request descriptor header fields */
- req_desc->header.dword_0 = cpu_to_le32(dword_0);
- /* dword_1 is reserved, hence it is set to 0 */
- req_desc->header.dword_1 = 0;
- /*
- * assigning invalid value for command status. Controller
- * updates OCS on command completion, with the command
- * status
- */
- req_desc->header.dword_2 =
- cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
- /* dword_3 is reserved, hence it is set to 0 */
- req_desc->header.dword_3 = 0;
-
- req_desc->prd_table_length = 0;
-
- ufshcd_cache_flush(req_desc, sizeof(*req_desc));
-}
-
-static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba,
- u32 upiu_flags)
-{
- struct utp_upiu_req *ucd_req_ptr = hba->ucd_req_ptr;
- struct ufs_query *query = &hba->dev_cmd.query;
- u16 len = be16_to_cpu(query->request.upiu_req.length);
-
- /* Query request header */
- ucd_req_ptr->header.dword_0 =
- UPIU_HEADER_DWORD(UPIU_TRANSACTION_QUERY_REQ,
- upiu_flags, 0, TASK_TAG);
- ucd_req_ptr->header.dword_1 =
- UPIU_HEADER_DWORD(0, query->request.query_func,
- 0, 0);
-
- /* Data segment length only need for WRITE_DESC */
- if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC)
- ucd_req_ptr->header.dword_2 =
- UPIU_HEADER_DWORD(0, 0, (len >> 8), (u8)len);
- else
- ucd_req_ptr->header.dword_2 = 0;
-
- /* Copy the Query Request buffer as is */
- memcpy(&ucd_req_ptr->qr, &query->request.upiu_req, QUERY_OSF_SIZE);
-
- /* Copy the Descriptor */
- if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) {
- memcpy(ucd_req_ptr + 1, query->descriptor, len);
- ufshcd_cache_flush(ucd_req_ptr, 2 * sizeof(*ucd_req_ptr));
- } else {
- ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr));
- }
-
- memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
- ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr));
-}
-
-static inline void ufshcd_prepare_utp_nop_upiu(struct ufs_hba *hba)
-{
- struct utp_upiu_req *ucd_req_ptr = hba->ucd_req_ptr;
-
- memset(ucd_req_ptr, 0, sizeof(struct utp_upiu_req));
-
- /* command descriptor fields */
- ucd_req_ptr->header.dword_0 =
- UPIU_HEADER_DWORD(UPIU_TRANSACTION_NOP_OUT, 0, 0, TASK_TAG);
- /* clear rest of the fields of basic header */
- ucd_req_ptr->header.dword_1 = 0;
- ucd_req_ptr->header.dword_2 = 0;
-
- memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
-
- ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr));
- ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr));
-}
-
-/**
- * ufshcd_comp_devman_upiu - UFS Protocol Information Unit(UPIU)
- * for Device Management Purposes
- */
-static int ufshcd_comp_devman_upiu(struct ufs_hba *hba,
- enum dev_cmd_type cmd_type)
-{
- u32 upiu_flags;
- int ret = 0;
-
- hba->dev_cmd.type = cmd_type;
-
- ufshcd_prepare_req_desc_hdr(hba, &upiu_flags, DMA_NONE);
- switch (cmd_type) {
- case DEV_CMD_TYPE_QUERY:
- ufshcd_prepare_utp_query_req_upiu(hba, upiu_flags);
- break;
- case DEV_CMD_TYPE_NOP:
- ufshcd_prepare_utp_nop_upiu(hba);
- break;
- default:
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
-{
- unsigned long start;
- u32 intr_status;
- u32 enabled_intr_status;
-
- ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
-
- /* Make sure doorbell reg is updated before reading interrupt status */
- wmb();
-
- start = get_timer(0);
- do {
- intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
- enabled_intr_status = intr_status & hba->intr_mask;
- ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
-
- if (get_timer(start) > QUERY_REQ_TIMEOUT) {
- dev_err(hba->dev,
- "Timedout waiting for UTP response\n");
-
- return -ETIMEDOUT;
- }
-
- if (enabled_intr_status & UFSHCD_ERROR_MASK) {
- dev_err(hba->dev, "Error in status:%08x\n",
- enabled_intr_status);
-
- return -1;
- }
- } while (!(enabled_intr_status & UTP_TRANSFER_REQ_COMPL));
-
- return 0;
-}
-
-/**
- * ufshcd_get_req_rsp - returns the TR response transaction type
- */
-static inline int ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
-{
- ufshcd_cache_invalidate(ucd_rsp_ptr, sizeof(*ucd_rsp_ptr));
-
- return be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24;
-}
-
-/**
- * ufshcd_get_tr_ocs - Get the UTRD Overall Command Status
- *
- */
-static inline int ufshcd_get_tr_ocs(struct ufs_hba *hba)
-{
- struct utp_transfer_req_desc *req_desc = hba->utrdl;
-
- ufshcd_cache_invalidate(req_desc, sizeof(*req_desc));
-
- return le32_to_cpu(req_desc->header.dword_2) & MASK_OCS;
-}
-
-static inline int ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp *ucd_rsp_ptr)
-{
- return be32_to_cpu(ucd_rsp_ptr->header.dword_1) & MASK_RSP_UPIU_RESULT;
-}
-
-static int ufshcd_check_query_response(struct ufs_hba *hba)
-{
- struct ufs_query_res *query_res = &hba->dev_cmd.query.response;
-
- /* Get the UPIU response */
- query_res->response = ufshcd_get_rsp_upiu_result(hba->ucd_rsp_ptr) >>
- UPIU_RSP_CODE_OFFSET;
- return query_res->response;
-}
-
-/**
- * ufshcd_copy_query_response() - Copy the Query Response and the data
- * descriptor
- */
-static int ufshcd_copy_query_response(struct ufs_hba *hba)
-{
- struct ufs_query_res *query_res = &hba->dev_cmd.query.response;
-
- memcpy(&query_res->upiu_res, &hba->ucd_rsp_ptr->qr, QUERY_OSF_SIZE);
-
- /* Get the descriptor */
- if (hba->dev_cmd.query.descriptor &&
- hba->ucd_rsp_ptr->qr.opcode == UPIU_QUERY_OPCODE_READ_DESC) {
- u8 *descp = (u8 *)hba->ucd_rsp_ptr +
- GENERAL_UPIU_REQUEST_SIZE;
- u16 resp_len;
- u16 buf_len;
-
- /* data segment length */
- resp_len = be32_to_cpu(hba->ucd_rsp_ptr->header.dword_2) &
- MASK_QUERY_DATA_SEG_LEN;
- buf_len =
- be16_to_cpu(hba->dev_cmd.query.request.upiu_req.length);
- if (likely(buf_len >= resp_len)) {
- memcpy(hba->dev_cmd.query.descriptor, descp, resp_len);
- } else {
- dev_warn(hba->dev,
- "%s: Response size is bigger than buffer\n",
- __func__);
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-/**
- * ufshcd_exec_dev_cmd - API for sending device management requests
- */
-static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, enum dev_cmd_type cmd_type,
- int timeout)
-{
- int err;
- int resp;
-
- err = ufshcd_comp_devman_upiu(hba, cmd_type);
- if (err)
- return err;
-
- err = ufshcd_send_command(hba, TASK_TAG);
- if (err)
- return err;
-
- err = ufshcd_get_tr_ocs(hba);
- if (err) {
- dev_err(hba->dev, "Error in OCS:%d\n", err);
- return -EINVAL;
- }
-
- resp = ufshcd_get_req_rsp(hba->ucd_rsp_ptr);
- switch (resp) {
- case UPIU_TRANSACTION_NOP_IN:
- break;
- case UPIU_TRANSACTION_QUERY_RSP:
- err = ufshcd_check_query_response(hba);
- if (!err)
- err = ufshcd_copy_query_response(hba);
- break;
- case UPIU_TRANSACTION_REJECT_UPIU:
- /* TODO: handle Reject UPIU Response */
- err = -EPERM;
- dev_err(hba->dev, "%s: Reject UPIU not fully implemented\n",
- __func__);
- break;
- default:
- err = -EINVAL;
- dev_err(hba->dev, "%s: Invalid device management cmd response: %x\n",
- __func__, resp);
- }
-
- return err;
-}
-
-/**
- * ufshcd_init_query() - init the query response and request parameters
- */
-static inline void ufshcd_init_query(struct ufs_hba *hba,
- struct ufs_query_req **request,
- struct ufs_query_res **response,
- enum query_opcode opcode,
- u8 idn, u8 index, u8 selector)
-{
- *request = &hba->dev_cmd.query.request;
- *response = &hba->dev_cmd.query.response;
- memset(*request, 0, sizeof(struct ufs_query_req));
- memset(*response, 0, sizeof(struct ufs_query_res));
- (*request)->upiu_req.opcode = opcode;
- (*request)->upiu_req.idn = idn;
- (*request)->upiu_req.index = index;
- (*request)->upiu_req.selector = selector;
-}
-
-/**
- * ufshcd_query_flag() - API function for sending flag query requests
- */
-static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
- enum flag_idn idn, bool *flag_res)
-{
- struct ufs_query_req *request = NULL;
- struct ufs_query_res *response = NULL;
- int err, index = 0, selector = 0;
- int timeout = QUERY_REQ_TIMEOUT;
-
- ufshcd_init_query(hba, &request, &response, opcode, idn, index,
- selector);
-
- switch (opcode) {
- case UPIU_QUERY_OPCODE_SET_FLAG:
- case UPIU_QUERY_OPCODE_CLEAR_FLAG:
- case UPIU_QUERY_OPCODE_TOGGLE_FLAG:
- request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST;
- break;
- case UPIU_QUERY_OPCODE_READ_FLAG:
- request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST;
- if (!flag_res) {
- /* No dummy reads */
- dev_err(hba->dev, "%s: Invalid argument for read request\n",
- __func__);
- err = -EINVAL;
- goto out;
- }
- break;
- default:
- dev_err(hba->dev,
- "%s: Expected query flag opcode but got = %d\n",
- __func__, opcode);
- err = -EINVAL;
- goto out;
- }
-
- err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, timeout);
-
- if (err) {
- dev_err(hba->dev,
- "%s: Sending flag query for idn %d failed, err = %d\n",
- __func__, idn, err);
- goto out;
- }
-
- if (flag_res)
- *flag_res = (be32_to_cpu(response->upiu_res.value) &
- MASK_QUERY_UPIU_FLAG_LOC) & 0x1;
-
-out:
- return err;
-}
-
-static int ufshcd_query_flag_retry(struct ufs_hba *hba,
- enum query_opcode opcode,
- enum flag_idn idn, bool *flag_res)
-{
- int ret;
- int retries;
-
- for (retries = 0; retries < QUERY_REQ_RETRIES; retries++) {
- ret = ufshcd_query_flag(hba, opcode, idn, flag_res);
- if (ret)
- dev_dbg(hba->dev,
- "%s: failed with error %d, retries %d\n",
- __func__, ret, retries);
- else
- break;
- }
-
- if (ret)
- dev_err(hba->dev,
- "%s: query attribute, opcode %d, idn %d, failed with error %d after %d retires\n",
- __func__, opcode, idn, ret, retries);
- return ret;
-}
-
-static int __ufshcd_query_descriptor(struct ufs_hba *hba,
- enum query_opcode opcode,
- enum desc_idn idn, u8 index, u8 selector,
- u8 *desc_buf, int *buf_len)
-{
- struct ufs_query_req *request = NULL;
- struct ufs_query_res *response = NULL;
- int err;
-
- if (!desc_buf) {
- dev_err(hba->dev, "%s: descriptor buffer required for opcode 0x%x\n",
- __func__, opcode);
- err = -EINVAL;
- goto out;
- }
-
- if (*buf_len < QUERY_DESC_MIN_SIZE || *buf_len > QUERY_DESC_MAX_SIZE) {
- dev_err(hba->dev, "%s: descriptor buffer size (%d) is out of range\n",
- __func__, *buf_len);
- err = -EINVAL;
- goto out;
- }
-
- ufshcd_init_query(hba, &request, &response, opcode, idn, index,
- selector);
- hba->dev_cmd.query.descriptor = desc_buf;
- request->upiu_req.length = cpu_to_be16(*buf_len);
-
- switch (opcode) {
- case UPIU_QUERY_OPCODE_WRITE_DESC:
- request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST;
- break;
- case UPIU_QUERY_OPCODE_READ_DESC:
- request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST;
- break;
- default:
- dev_err(hba->dev, "%s: Expected query descriptor opcode but got = 0x%.2x\n",
- __func__, opcode);
- err = -EINVAL;
- goto out;
- }
-
- err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT);
-
- if (err) {
- dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, index %d, err = %d\n",
- __func__, opcode, idn, index, err);
- goto out;
- }
-
- hba->dev_cmd.query.descriptor = NULL;
- *buf_len = be16_to_cpu(response->upiu_res.length);
-
-out:
- return err;
-}
-
-/**
- * ufshcd_query_descriptor_retry - API function for sending descriptor requests
- */
-static int ufshcd_query_descriptor_retry(struct ufs_hba *hba, enum query_opcode opcode,
- enum desc_idn idn, u8 index, u8 selector,
- u8 *desc_buf, int *buf_len)
-{
- int err;
- int retries;
-
- for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
- err = __ufshcd_query_descriptor(hba, opcode, idn, index,
- selector, desc_buf, buf_len);
- if (!err || err == -EINVAL)
- break;
- }
-
- return err;
-}
-
-/**
- * ufshcd_read_desc_length - read the specified descriptor length from header
- */
-static int ufshcd_read_desc_length(struct ufs_hba *hba, enum desc_idn desc_id,
- int desc_index, int *desc_length)
-{
- int ret;
- u8 header[QUERY_DESC_HDR_SIZE];
- int header_len = QUERY_DESC_HDR_SIZE;
-
- if (desc_id >= QUERY_DESC_IDN_MAX)
- return -EINVAL;
-
- ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC,
- desc_id, desc_index, 0, header,
- &header_len);
-
- if (ret) {
- dev_err(hba->dev, "%s: Failed to get descriptor header id %d\n",
- __func__, desc_id);
- return ret;
- } else if (desc_id != header[QUERY_DESC_DESC_TYPE_OFFSET]) {
- dev_warn(hba->dev, "%s: descriptor header id %d and desc_id %d mismatch\n",
- __func__, header[QUERY_DESC_DESC_TYPE_OFFSET],
- desc_id);
- ret = -EINVAL;
- }
-
- *desc_length = header[QUERY_DESC_LENGTH_OFFSET];
-
- return ret;
-}
-
-static void ufshcd_init_desc_sizes(struct ufs_hba *hba)
-{
- int err;
-
- err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_DEVICE, 0,
- &hba->desc_size.dev_desc);
- if (err)
- hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE;
-
- err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_POWER, 0,
- &hba->desc_size.pwr_desc);
- if (err)
- hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE;
-
- err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_INTERCONNECT, 0,
- &hba->desc_size.interc_desc);
- if (err)
- hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE;
-
- err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_CONFIGURATION, 0,
- &hba->desc_size.conf_desc);
- if (err)
- hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE;
-
- err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_UNIT, 0,
- &hba->desc_size.unit_desc);
- if (err)
- hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE;
-
- err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_GEOMETRY, 0,
- &hba->desc_size.geom_desc);
- if (err)
- hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE;
-
- err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_HEALTH, 0,
- &hba->desc_size.hlth_desc);
- if (err)
- hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE;
-}
-
-/**
- * ufshcd_map_desc_id_to_length - map descriptor IDN to its length
- *
- */
-static int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id,
- int *desc_len)
-{
- switch (desc_id) {
- case QUERY_DESC_IDN_DEVICE:
- *desc_len = hba->desc_size.dev_desc;
- break;
- case QUERY_DESC_IDN_POWER:
- *desc_len = hba->desc_size.pwr_desc;
- break;
- case QUERY_DESC_IDN_GEOMETRY:
- *desc_len = hba->desc_size.geom_desc;
- break;
- case QUERY_DESC_IDN_CONFIGURATION:
- *desc_len = hba->desc_size.conf_desc;
- break;
- case QUERY_DESC_IDN_UNIT:
- *desc_len = hba->desc_size.unit_desc;
- break;
- case QUERY_DESC_IDN_INTERCONNECT:
- *desc_len = hba->desc_size.interc_desc;
- break;
- case QUERY_DESC_IDN_STRING:
- *desc_len = QUERY_DESC_MAX_SIZE;
- break;
- case QUERY_DESC_IDN_HEALTH:
- *desc_len = hba->desc_size.hlth_desc;
- break;
- case QUERY_DESC_IDN_RFU_0:
- case QUERY_DESC_IDN_RFU_1:
- *desc_len = 0;
- break;
- default:
- *desc_len = 0;
- return -EINVAL;
- }
- return 0;
-}
-
-/**
- * ufshcd_read_desc_param - read the specified descriptor parameter
- *
- */
-static int ufshcd_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id,
- int desc_index, u8 param_offset,
- u8 *param_read_buf, u8 param_size)
-{
- int ret;
- u8 *desc_buf;
- int buff_len;
- bool is_kmalloc = true;
-
- /* Safety check */
- if (desc_id >= QUERY_DESC_IDN_MAX || !param_size)
- return -EINVAL;
-
- /* Get the max length of descriptor from structure filled up at probe
- * time.
- */
- ret = ufshcd_map_desc_id_to_length(hba, desc_id, &buff_len);
-
- /* Sanity checks */
- if (ret || !buff_len) {
- dev_err(hba->dev, "%s: Failed to get full descriptor length\n",
- __func__);
- return ret;
- }
-
- /* Check whether we need temp memory */
- if (param_offset != 0 || param_size < buff_len) {
- desc_buf = kmalloc(buff_len, GFP_KERNEL);
- if (!desc_buf)
- return -ENOMEM;
- } else {
- desc_buf = param_read_buf;
- is_kmalloc = false;
- }
-
- /* Request for full descriptor */
- ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC,
- desc_id, desc_index, 0, desc_buf,
- &buff_len);
-
- if (ret) {
- dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d\n",
- __func__, desc_id, desc_index, param_offset, ret);
- goto out;
- }
-
- /* Sanity check */
- if (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id) {
- dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header\n",
- __func__, desc_buf[QUERY_DESC_DESC_TYPE_OFFSET]);
- ret = -EINVAL;
- goto out;
- }
-
- /* Check wherher we will not copy more data, than available */
- if (is_kmalloc && param_size > buff_len)
- param_size = buff_len;
-
- if (is_kmalloc)
- memcpy(param_read_buf, &desc_buf[param_offset], param_size);
-out:
- if (is_kmalloc)
- kfree(desc_buf);
- return ret;
-}
-
-/* replace non-printable or non-ASCII characters with spaces */
-static inline void ufshcd_remove_non_printable(uint8_t *val)
-{
- if (!val)
- return;
-
- if (*val < 0x20 || *val > 0x7e)
- *val = ' ';
-}
-
-/**
- * ufshcd_uic_pwr_ctrl - executes UIC commands (which affects the link power
- * state) and waits for it to take effect.
- *
- */
-static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
-{
- unsigned long start = 0;
- u8 status;
- int ret;
-
- ret = ufshcd_send_uic_cmd(hba, cmd);
- if (ret) {
- dev_err(hba->dev,
- "pwr ctrl cmd 0x%x with mode 0x%x uic error %d\n",
- cmd->command, cmd->argument3, ret);
-
- return ret;
- }
-
- start = get_timer(0);
- do {
- status = ufshcd_get_upmcrs(hba);
- if (get_timer(start) > UFS_UIC_CMD_TIMEOUT) {
- dev_err(hba->dev,
- "pwr ctrl cmd 0x%x failed, host upmcrs:0x%x\n",
- cmd->command, status);
- ret = (status != PWR_OK) ? status : -1;
- break;
- }
- } while (status != PWR_LOCAL);
-
- return ret;
-}
-
-/**
- * ufshcd_uic_change_pwr_mode - Perform the UIC power mode change
- * using DME_SET primitives.
- */
-static int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode)
-{
- struct uic_command uic_cmd = {0};
- int ret;
-
- uic_cmd.command = UIC_CMD_DME_SET;
- uic_cmd.argument1 = UIC_ARG_MIB(PA_PWRMODE);
- uic_cmd.argument3 = mode;
- ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd);
-
- return ret;
-}
-
-static
-void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufs_hba *hba,
- struct scsi_cmd *pccb, u32 upiu_flags)
-{
- struct utp_upiu_req *ucd_req_ptr = hba->ucd_req_ptr;
- unsigned int cdb_len;
-
- /* command descriptor fields */
- ucd_req_ptr->header.dword_0 =
- UPIU_HEADER_DWORD(UPIU_TRANSACTION_COMMAND, upiu_flags,
- pccb->lun, TASK_TAG);
- ucd_req_ptr->header.dword_1 =
- UPIU_HEADER_DWORD(UPIU_COMMAND_SET_TYPE_SCSI, 0, 0, 0);
-
- /* Total EHS length and Data segment length will be zero */
- ucd_req_ptr->header.dword_2 = 0;
-
- ucd_req_ptr->sc.exp_data_transfer_len = cpu_to_be32(pccb->datalen);
-
- cdb_len = min_t(unsigned short, pccb->cmdlen, UFS_CDB_SIZE);
- memset(ucd_req_ptr->sc.cdb, 0, UFS_CDB_SIZE);
- memcpy(ucd_req_ptr->sc.cdb, pccb->cmd, cdb_len);
-
- memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
- ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr));
- ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr));
-}
-
-static inline void prepare_prdt_desc(struct ufshcd_sg_entry *entry,
- unsigned char *buf, ulong len)
-{
- entry->size = cpu_to_le32(len) | GENMASK(1, 0);
- entry->base_addr = cpu_to_le32(lower_32_bits((unsigned long)buf));
- entry->upper_addr = cpu_to_le32(upper_32_bits((unsigned long)buf));
-}
-
-static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb)
-{
- struct utp_transfer_req_desc *req_desc = hba->utrdl;
- struct ufshcd_sg_entry *prd_table = hba->ucd_prdt_ptr;
- ulong datalen = pccb->datalen;
- int table_length;
- u8 *buf;
- int i;
-
- if (!datalen) {
- req_desc->prd_table_length = 0;
- ufshcd_cache_flush(req_desc, sizeof(*req_desc));
- return;
- }
-
- table_length = DIV_ROUND_UP(pccb->datalen, MAX_PRDT_ENTRY);
- buf = pccb->pdata;
- i = table_length;
- while (--i) {
- prepare_prdt_desc(&prd_table[table_length - i - 1], buf,
- MAX_PRDT_ENTRY - 1);
- buf += MAX_PRDT_ENTRY;
- datalen -= MAX_PRDT_ENTRY;
- }
-
- prepare_prdt_desc(&prd_table[table_length - i - 1], buf, datalen - 1);
-
- req_desc->prd_table_length = table_length;
- ufshcd_cache_flush(prd_table, sizeof(*prd_table) * table_length);
- ufshcd_cache_flush(req_desc, sizeof(*req_desc));
-}
-
-static int ufs_scsi_exec(struct udevice *scsi_dev, struct scsi_cmd *pccb)
-{
- struct ufs_hba *hba = dev_get_uclass_priv(scsi_dev->parent);
- u32 upiu_flags;
- int ocs, result = 0;
- u8 scsi_status;
-
- ufshcd_prepare_req_desc_hdr(hba, &upiu_flags, pccb->dma_dir);
- ufshcd_prepare_utp_scsi_cmd_upiu(hba, pccb, upiu_flags);
- prepare_prdt_table(hba, pccb);
-
- ufshcd_cache_flush(pccb->pdata, pccb->datalen);
-
- ufshcd_send_command(hba, TASK_TAG);
-
- ufshcd_cache_invalidate(pccb->pdata, pccb->datalen);
-
- ocs = ufshcd_get_tr_ocs(hba);
- switch (ocs) {
- case OCS_SUCCESS:
- result = ufshcd_get_req_rsp(hba->ucd_rsp_ptr);
- switch (result) {
- case UPIU_TRANSACTION_RESPONSE:
- result = ufshcd_get_rsp_upiu_result(hba->ucd_rsp_ptr);
-
- scsi_status = result & MASK_SCSI_STATUS;
- if (scsi_status)
- return -EINVAL;
-
- break;
- case UPIU_TRANSACTION_REJECT_UPIU:
- /* TODO: handle Reject UPIU Response */
- dev_err(hba->dev,
- "Reject UPIU not fully implemented\n");
- return -EINVAL;
- default:
- dev_err(hba->dev,
- "Unexpected request response code = %x\n",
- result);
- return -EINVAL;
- }
- break;
- default:
- dev_err(hba->dev, "OCS error from controller = %x\n", ocs);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static inline int ufshcd_read_desc(struct ufs_hba *hba, enum desc_idn desc_id,
- int desc_index, u8 *buf, u32 size)
-{
- return ufshcd_read_desc_param(hba, desc_id, desc_index, 0, buf, size);
-}
-
-static int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size)
-{
- return ufshcd_read_desc(hba, QUERY_DESC_IDN_DEVICE, 0, buf, size);
-}
-
-/**
- * ufshcd_read_string_desc - read string descriptor
- *
- */
-static int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index,
- u8 *buf, u32 size, bool ascii)
-{
- int err = 0;
-
- err = ufshcd_read_desc(hba, QUERY_DESC_IDN_STRING, desc_index, buf,
- size);
-
- if (err) {
- dev_err(hba->dev, "%s: reading String Desc failed after %d retries. err = %d\n",
- __func__, QUERY_REQ_RETRIES, err);
- goto out;
- }
-
- if (ascii) {
- int desc_len;
- int ascii_len;
- int i;
- u8 *buff_ascii;
-
- desc_len = buf[0];
- /* remove header and divide by 2 to move from UTF16 to UTF8 */
- ascii_len = (desc_len - QUERY_DESC_HDR_SIZE) / 2 + 1;
- if (size < ascii_len + QUERY_DESC_HDR_SIZE) {
- dev_err(hba->dev, "%s: buffer allocated size is too small\n",
- __func__);
- err = -ENOMEM;
- goto out;
- }
-
- buff_ascii = kmalloc(ascii_len, GFP_KERNEL);
- if (!buff_ascii) {
- err = -ENOMEM;
- goto out;
- }
-
- /*
- * the descriptor contains string in UTF16 format
- * we need to convert to utf-8 so it can be displayed
- */
- utf16_to_utf8(buff_ascii,
- (uint16_t *)&buf[QUERY_DESC_HDR_SIZE], ascii_len);
-
- /* replace non-printable or non-ASCII characters with spaces */
- for (i = 0; i < ascii_len; i++)
- ufshcd_remove_non_printable(&buff_ascii[i]);
-
- memset(buf + QUERY_DESC_HDR_SIZE, 0,
- size - QUERY_DESC_HDR_SIZE);
- memcpy(buf + QUERY_DESC_HDR_SIZE, buff_ascii, ascii_len);
- buf[QUERY_DESC_LENGTH_OFFSET] = ascii_len + QUERY_DESC_HDR_SIZE;
- kfree(buff_ascii);
- }
-out:
- return err;
-}
-
-static int ufs_get_device_desc(struct ufs_hba *hba,
- struct ufs_dev_desc *dev_desc)
-{
- int err;
- size_t buff_len;
- u8 model_index;
- u8 *desc_buf;
-
- buff_len = max_t(size_t, hba->desc_size.dev_desc,
- QUERY_DESC_MAX_SIZE + 1);
- desc_buf = kmalloc(buff_len, GFP_KERNEL);
- if (!desc_buf) {
- err = -ENOMEM;
- goto out;
- }
-
- err = ufshcd_read_device_desc(hba, desc_buf, hba->desc_size.dev_desc);
- if (err) {
- dev_err(hba->dev, "%s: Failed reading Device Desc. err = %d\n",
- __func__, err);
- goto out;
- }
-
- /*
- * getting vendor (manufacturerID) and Bank Index in big endian
- * format
- */
- dev_desc->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 |
- desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1];
-
- model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];
-
- /* Zero-pad entire buffer for string termination. */
- memset(desc_buf, 0, buff_len);
-
- err = ufshcd_read_string_desc(hba, model_index, desc_buf,
- QUERY_DESC_MAX_SIZE, true/*ASCII*/);
- if (err) {
- dev_err(hba->dev, "%s: Failed reading Product Name. err = %d\n",
- __func__, err);
- goto out;
- }
-
- desc_buf[QUERY_DESC_MAX_SIZE] = '\0';
- strlcpy(dev_desc->model, (char *)(desc_buf + QUERY_DESC_HDR_SIZE),
- min_t(u8, desc_buf[QUERY_DESC_LENGTH_OFFSET],
- MAX_MODEL_LEN));
-
- /* Null terminate the model string */
- dev_desc->model[MAX_MODEL_LEN] = '\0';
-
-out:
- kfree(desc_buf);
- return err;
-}
-
-/**
- * ufshcd_get_max_pwr_mode - reads the max power mode negotiated with device
- */
-static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba)
-{
- struct ufs_pa_layer_attr *pwr_info = &hba->max_pwr_info.info;
-
- if (hba->max_pwr_info.is_valid)
- return 0;
-
- if (hba->quirks & UFSHCD_QUIRK_HIBERN_FASTAUTO) {
- pwr_info->pwr_tx = FASTAUTO_MODE;
- pwr_info->pwr_rx = FASTAUTO_MODE;
- } else {
- pwr_info->pwr_tx = FAST_MODE;
- pwr_info->pwr_rx = FAST_MODE;
- }
- pwr_info->hs_rate = PA_HS_MODE_B;
-
- /* Get the connected lane count */
- ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES),
- &pwr_info->lane_rx);
- ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES),
- &pwr_info->lane_tx);
-
- if (!pwr_info->lane_rx || !pwr_info->lane_tx) {
- dev_err(hba->dev, "%s: invalid connected lanes value. rx=%d, tx=%d\n",
- __func__, pwr_info->lane_rx, pwr_info->lane_tx);
- return -EINVAL;
- }
-
- /*
- * First, get the maximum gears of HS speed.
- * If a zero value, it means there is no HSGEAR capability.
- * Then, get the maximum gears of PWM speed.
- */
- ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), &pwr_info->gear_rx);
- if (!pwr_info->gear_rx) {
- ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
- &pwr_info->gear_rx);
- if (!pwr_info->gear_rx) {
- dev_err(hba->dev, "%s: invalid max pwm rx gear read = %d\n",
- __func__, pwr_info->gear_rx);
- return -EINVAL;
- }
- pwr_info->pwr_rx = SLOW_MODE;
- }
-
- ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR),
- &pwr_info->gear_tx);
- if (!pwr_info->gear_tx) {
- ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
- &pwr_info->gear_tx);
- if (!pwr_info->gear_tx) {
- dev_err(hba->dev, "%s: invalid max pwm tx gear read = %d\n",
- __func__, pwr_info->gear_tx);
- return -EINVAL;
- }
- pwr_info->pwr_tx = SLOW_MODE;
- }
-
- hba->max_pwr_info.is_valid = true;
- return ufshcd_ops_get_max_pwr_mode(hba, &hba->max_pwr_info);
-}
-
-static int ufshcd_change_power_mode(struct ufs_hba *hba,
- struct ufs_pa_layer_attr *pwr_mode)
-{
- int ret;
-
- /* if already configured to the requested pwr_mode */
- if (pwr_mode->gear_rx == hba->pwr_info.gear_rx &&
- pwr_mode->gear_tx == hba->pwr_info.gear_tx &&
- pwr_mode->lane_rx == hba->pwr_info.lane_rx &&
- pwr_mode->lane_tx == hba->pwr_info.lane_tx &&
- pwr_mode->pwr_rx == hba->pwr_info.pwr_rx &&
- pwr_mode->pwr_tx == hba->pwr_info.pwr_tx &&
- pwr_mode->hs_rate == hba->pwr_info.hs_rate) {
- dev_dbg(hba->dev, "%s: power already configured\n", __func__);
- return 0;
- }
-
- /*
- * Configure attributes for power mode change with below.
- * - PA_RXGEAR, PA_ACTIVERXDATALANES, PA_RXTERMINATION,
- * - PA_TXGEAR, PA_ACTIVETXDATALANES, PA_TXTERMINATION,
- * - PA_HSSERIES
- */
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXGEAR), pwr_mode->gear_rx);
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVERXDATALANES),
- pwr_mode->lane_rx);
- if (pwr_mode->pwr_rx == FASTAUTO_MODE || pwr_mode->pwr_rx == FAST_MODE)
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), TRUE);
- else
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), FALSE);
-
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXGEAR), pwr_mode->gear_tx);
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVETXDATALANES),
- pwr_mode->lane_tx);
- if (pwr_mode->pwr_tx == FASTAUTO_MODE || pwr_mode->pwr_tx == FAST_MODE)
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), TRUE);
- else
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), FALSE);
-
- if (pwr_mode->pwr_rx == FASTAUTO_MODE ||
- pwr_mode->pwr_tx == FASTAUTO_MODE ||
- pwr_mode->pwr_rx == FAST_MODE ||
- pwr_mode->pwr_tx == FAST_MODE)
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HSSERIES),
- pwr_mode->hs_rate);
-
- ret = ufshcd_uic_change_pwr_mode(hba, pwr_mode->pwr_rx << 4 |
- pwr_mode->pwr_tx);
-
- if (ret) {
- dev_err(hba->dev,
- "%s: power mode change failed %d\n", __func__, ret);
-
- return ret;
- }
-
- /* Copy new Power Mode to power info */
- memcpy(&hba->pwr_info, pwr_mode, sizeof(struct ufs_pa_layer_attr));
-
- return ret;
-}
-
-/**
- * ufshcd_verify_dev_init() - Verify device initialization
- *
- */
-static int ufshcd_verify_dev_init(struct ufs_hba *hba)
-{
- int retries;
- int err;
-
- for (retries = NOP_OUT_RETRIES; retries > 0; retries--) {
- err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_NOP,
- NOP_OUT_TIMEOUT);
- if (!err || err == -ETIMEDOUT)
- break;
-
- dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
- }
-
- if (err)
- dev_err(hba->dev, "%s: NOP OUT failed %d\n", __func__, err);
-
- return err;
-}
-
-/**
- * ufshcd_complete_dev_init() - checks device readiness
- */
-static int ufshcd_complete_dev_init(struct ufs_hba *hba)
-{
- int i;
- int err;
- bool flag_res = 1;
-
- err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG,
- QUERY_FLAG_IDN_FDEVICEINIT, NULL);
- if (err) {
- dev_err(hba->dev,
- "%s setting fDeviceInit flag failed with error %d\n",
- __func__, err);
- goto out;
- }
-
- /* poll for max. 1000 iterations for fDeviceInit flag to clear */
- for (i = 0; i < 1000 && !err && flag_res; i++)
- err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_READ_FLAG,
- QUERY_FLAG_IDN_FDEVICEINIT,
- &flag_res);
-
- if (err)
- dev_err(hba->dev,
- "%s reading fDeviceInit flag failed with error %d\n",
- __func__, err);
- else if (flag_res)
- dev_err(hba->dev,
- "%s fDeviceInit was not cleared by the device\n",
- __func__);
-
-out:
- return err;
-}
-
-static void ufshcd_def_desc_sizes(struct ufs_hba *hba)
-{
- hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE;
- hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE;
- hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE;
- hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE;
- hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE;
- hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE;
- hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE;
-}
-
-static int ufs_start(struct ufs_hba *hba)
-{
- struct ufs_dev_desc card = {0};
- int ret;
-
- ret = ufshcd_link_startup(hba);
- if (ret)
- return ret;
-
- ret = ufshcd_verify_dev_init(hba);
- if (ret)
- return ret;
-
- ret = ufshcd_complete_dev_init(hba);
- if (ret)
- return ret;
-
- /* Init check for device descriptor sizes */
- ufshcd_init_desc_sizes(hba);
-
- ret = ufs_get_device_desc(hba, &card);
- if (ret) {
- dev_err(hba->dev, "%s: Failed getting device info. err = %d\n",
- __func__, ret);
-
- return ret;
- }
-
- if (ufshcd_get_max_pwr_mode(hba)) {
- dev_err(hba->dev,
- "%s: Failed getting max supported power mode\n",
- __func__);
- } else {
- ret = ufshcd_change_power_mode(hba, &hba->max_pwr_info.info);
- if (ret) {
- dev_err(hba->dev, "%s: Failed setting power mode, err = %d\n",
- __func__, ret);
-
- return ret;
- }
-
- debug("UFS Device %s is up!\n", hba->dev->name);
- ufshcd_print_pwr_info(hba);
- }
-
- return 0;
-}
-
-int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops)
-{
- struct ufs_hba *hba = dev_get_uclass_priv(ufs_dev);
- struct scsi_plat *scsi_plat;
- struct udevice *scsi_dev;
- void __iomem *mmio_base;
- int err;
-
- device_find_first_child(ufs_dev, &scsi_dev);
- if (!scsi_dev)
- return -ENODEV;
-
- scsi_plat = dev_get_uclass_plat(scsi_dev);
- scsi_plat->max_id = UFSHCD_MAX_ID;
- scsi_plat->max_lun = UFS_MAX_LUNS;
- scsi_plat->max_bytes_per_req = UFS_MAX_BYTES;
-
- hba->dev = ufs_dev;
- hba->ops = hba_ops;
-
- if (device_is_on_pci_bus(ufs_dev)) {
- mmio_base = dm_pci_map_bar(ufs_dev, PCI_BASE_ADDRESS_0, 0, 0,
- PCI_REGION_TYPE, PCI_REGION_MEM);
- } else {
- mmio_base = dev_read_addr_ptr(ufs_dev);
- }
- hba->mmio_base = mmio_base;
-
- /* Set descriptor lengths to specification defaults */
- ufshcd_def_desc_sizes(hba);
-
- ufshcd_ops_init(hba);
-
- /* Read capabilities registers */
- hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES);
- if (hba->quirks & UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS)
- hba->capabilities &= ~MASK_64_ADDRESSING_SUPPORT;
-
- /* Get UFS version supported by the controller */
- hba->version = ufshcd_get_ufs_version(hba);
- if (hba->version != UFSHCI_VERSION_10 &&
- hba->version != UFSHCI_VERSION_11 &&
- hba->version != UFSHCI_VERSION_20 &&
- hba->version != UFSHCI_VERSION_21 &&
- hba->version != UFSHCI_VERSION_30 &&
- hba->version != UFSHCI_VERSION_31 &&
- hba->version != UFSHCI_VERSION_40)
- dev_err(hba->dev, "invalid UFS version 0x%x\n",
- hba->version);
-
- /* Get Interrupt bit mask per version */
- hba->intr_mask = ufshcd_get_intr_mask(hba);
-
- /* Allocate memory for host memory space */
- err = ufshcd_memory_alloc(hba);
- if (err) {
- dev_err(hba->dev, "Memory allocation failed\n");
- return err;
- }
-
- /* Configure Local data structures */
- ufshcd_host_memory_configure(hba);
-
- /*
- * In order to avoid any spurious interrupt immediately after
- * registering UFS controller interrupt handler, clear any pending UFS
- * interrupt status and disable all the UFS interrupts.
- */
- ufshcd_writel(hba, ufshcd_readl(hba, REG_INTERRUPT_STATUS),
- REG_INTERRUPT_STATUS);
- ufshcd_writel(hba, 0, REG_INTERRUPT_ENABLE);
-
- mb(); /* flush previous writes */
-
- /* Reset the attached device */
- ufshcd_device_reset(hba);
-
- err = ufshcd_hba_enable(hba);
- if (err) {
- dev_err(hba->dev, "Host controller enable failed\n");
- return err;
- }
-
- err = ufs_start(hba);
- if (err)
- return err;
-
- return 0;
-}
-
-int ufs_scsi_bind(struct udevice *ufs_dev, struct udevice **scsi_devp)
-{
- int ret = device_bind_driver(ufs_dev, "ufs_scsi", "ufs_scsi",
- scsi_devp);
-
- return ret;
-}
-
-#if IS_ENABLED(CONFIG_BOUNCE_BUFFER)
-static int ufs_scsi_buffer_aligned(struct udevice *scsi_dev, struct bounce_buffer *state)
-{
-#ifdef CONFIG_PHYS_64BIT
- struct ufs_hba *hba = dev_get_uclass_priv(scsi_dev->parent);
- uintptr_t ubuf = (uintptr_t)state->user_buffer;
- size_t len = state->len_aligned;
-
- /* Check if below 32bit boundary */
- if ((hba->quirks & UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS) &&
- ((ubuf >> 32) || (ubuf + len) >> 32)) {
- dev_dbg(scsi_dev, "Buffer above 32bit boundary %lx-%lx\n",
- ubuf, ubuf + len);
- return 0;
- }
-#endif
- return 1;
-}
-#endif /* CONFIG_BOUNCE_BUFFER */
-
-static struct scsi_ops ufs_ops = {
- .exec = ufs_scsi_exec,
-#if IS_ENABLED(CONFIG_BOUNCE_BUFFER)
- .buffer_aligned = ufs_scsi_buffer_aligned,
-#endif /* CONFIG_BOUNCE_BUFFER */
-};
-
-int ufs_probe_dev(int index)
-{
- struct udevice *dev;
-
- return uclass_get_device(UCLASS_UFS, index, &dev);
-}
-
-int ufs_probe(void)
-{
- struct udevice *dev;
- int ret, i;
-
- for (i = 0;; i++) {
- ret = uclass_get_device(UCLASS_UFS, i, &dev);
- if (ret == -ENODEV)
- break;
- }
-
- return 0;
-}
-
-U_BOOT_DRIVER(ufs_scsi) = {
- .id = UCLASS_SCSI,
- .name = "ufs_scsi",
- .ops = &ufs_ops,
-};
diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h
index 0337ac5996b..bc839a43704 100644
--- a/drivers/ufs/ufs.h
+++ b/drivers/ufs/ufs.h
@@ -77,6 +77,9 @@ enum {
/* UTP Transfer Request Command Offset */
#define UPIU_COMMAND_TYPE_OFFSET 28
+/* UTP Transfer Request Data Direction Offset */
+#define UPIU_DATA_DIRECTION_OFFSET 25
+
/* Offset of the response code in the UPIU header */
#define UPIU_RSP_CODE_OFFSET 8
@@ -172,6 +175,15 @@ enum query_opcode {
UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8,
};
+/* bRefClkFreq attribute values */
+enum ufs_ref_clk_freq {
+ REF_CLK_FREQ_19_2_MHZ = 0,
+ REF_CLK_FREQ_26_MHZ = 1,
+ REF_CLK_FREQ_38_4_MHZ = 2,
+ REF_CLK_FREQ_52_MHZ = 3,
+ REF_CLK_FREQ_INVAL = -1,
+};
+
/* Query response result code */
enum {
QUERY_RESULT_SUCCESS = 0x00,
@@ -435,6 +447,8 @@ int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
u8 attr_set, u32 mib_val, u8 peer);
int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
u32 *mib_val, u8 peer);
+int ufshcd_dme_enable(struct ufs_hba *hba);
+int ufshcd_dme_reset(struct ufs_hba *hba);
static inline int ufshcd_dme_set(struct ufs_hba *hba, u32 attr_sel,
u32 mib_val)
diff --git a/drivers/ufs/unipro.h b/drivers/ufs/unipro.h
index 56833602b77..bde1490397c 100644
--- a/drivers/ufs/unipro.h
+++ b/drivers/ufs/unipro.h
@@ -125,6 +125,7 @@
#define PA_RXPWRSTATUS 0x1582
#define PA_RXGEAR 0x1583
#define PA_RXTERMINATION 0x1584
+#define PA_SCRAMBLING 0x1585
#define PA_MAXRXPWMGEAR 0x1586
#define PA_MAXRXHSGEAR 0x1587
#define PA_PACPREQTIMEOUT 0x1590
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index daf2240ffd9..93c5ee69b25 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -78,8 +78,6 @@ source "drivers/usb/dwc3/Kconfig"
source "drivers/usb/mtu3/Kconfig"
-source "drivers/usb/musb/Kconfig"
-
source "drivers/usb/musb-new/Kconfig"
source "drivers/usb/emul/Kconfig"
diff --git a/drivers/usb/common/fsl-dt-fixup.c b/drivers/usb/common/fsl-dt-fixup.c
index 6a68bd76c27..55176f7a871 100644
--- a/drivers/usb/common/fsl-dt-fixup.c
+++ b/drivers/usb/common/fsl-dt-fixup.c
@@ -99,7 +99,7 @@ static int fsl_fdt_fixup_usb_erratum(void *blob, const char *prop_erratum,
else
node_name = node_type;
if (strcmp(node_name, controller_type))
- return err;
+ return -EINVAL;
err = fdt_setprop(blob, node_offset, prop_erratum, NULL, 0);
if (err < 0) {
diff --git a/drivers/usb/common/fsl-errata.c b/drivers/usb/common/fsl-errata.c
index 89ae73f2ba4..66ff93b2982 100644
--- a/drivers/usb/common/fsl-errata.c
+++ b/drivers/usb/common/fsl-errata.c
@@ -7,7 +7,7 @@
#include <hwconfig.h>
#include <fsl_errata.h>
-#include<fsl_usb.h>
+#include <fsl_usb.h>
#if defined(CONFIG_FSL_LSCH2) || defined(CONFIG_FSL_LSCH3) || \
defined(CONFIG_ARM)
#include <asm/arch/clock.h>
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 682a6910655..744dfa90463 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -17,6 +17,7 @@ comment "Platform Glue Driver Support"
config USB_DWC3_OMAP
bool "Texas Instruments OMAP5 and similar Platforms"
+ depends on ARCH_OMAP2PLUS
help
Some platforms from Texas Instruments like OMAP5, DRA7xxx and
AM437x use this IP for USB2/3 functionality.
@@ -39,14 +40,14 @@ config SPL_USB_DWC3_GENERIC
config SPL_USB_DWC3_AM62
bool "TI AM62 USB wrapper"
- depends on SPL_DM_USB && SPL_USB_DWC3_GENERIC && SPL_SYSCON
+ depends on SPL_DM_USB && SPL_USB_DWC3_GENERIC && SPL_SYSCON && ARCH_K3
help
Select this for TI AM62 Platforms.
This wrapper supports Host and Peripheral operation modes.
config USB_DWC3_AM62
bool "TI AM62 USB wrapper"
- depends on DM_USB && USB_DWC3_GENERIC && SYSCON
+ depends on DM_USB && USB_DWC3_GENERIC && SYSCON && ARCH_K3
help
Select this for TI AM62 Platforms.
This wrapper supports Host and Peripheral operation modes.
@@ -80,7 +81,7 @@ config USB_DWC3_UNIPHIER
config USB_DWC3_LAYERSCAPE
bool "Freescale Layerscape platform support"
depends on DM_USB && USB_DWC3
- depends on !USB_XHCI_FSL
+ depends on !USB_XHCI_FSL && ARM
help
Select this for Freescale Layerscape Platforms.
@@ -99,12 +100,14 @@ menu "PHY Subsystem"
config USB_DWC3_PHY_OMAP
bool "TI OMAP SoC series USB DRD PHY driver"
+ depends on ARCH_OMAP2PLUS
help
Enable single driver for both USB2 PHY programming and USB3 PHY
programming for TI SoCs.
config USB_DWC3_PHY_SAMSUNG
bool "Exynos5 SoC series USB DRD PHY driver"
+ depends on ARCH_EXYNOS
help
Enable USB DRD PHY support for Exynos 5 SoC series.
This driver provides PHY interface for USB 3.0 DRD controller
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index c656cbe25ce..680756532f0 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -799,10 +799,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
status = DWC3_TRB_SIZE_TRBSTS(trb->size);
if (status == DWC3_TRBSTS_SETUP_PENDING) {
dev_dbg(dwc->dev, "Setup Pending received");
-
- if (r)
- dwc3_gadget_giveback(ep0, r, -ECONNRESET);
-
+ dwc3_gadget_giveback(ep0, r, -ECONNRESET);
return;
}
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 0121f9872ae..7e08aeab904 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -39,6 +39,7 @@ menuconfig USB_GADGET
config SPL_USB_GADGET
bool "USB Gadget Support in SPL"
+ depends on SPL_FRAMEWORK
help
Enable USB Gadget API which allows to enable USB device functions
in SPL.
@@ -60,6 +61,7 @@ config USB_GADGET_VENDOR_NUM
default 0x0955 if ARCH_TEGRA
default 0x1f3a if ARCH_SUNXI
default 0x2207 if ARCH_ROCKCHIP
+ default 0x18d1 if ARCH_QCOM
default 0x0
help
Vendor ID of the USB device emulated, reported to the host device.
@@ -87,28 +89,26 @@ config USB_GADGET_PRODUCT_NUM
default 0x350b if ROCKCHIP_RK3588
default 0x350c if ROCKCHIP_RK3528
default 0x350e if ROCKCHIP_RK3576
+ default 0x4ee0 if ARCH_QCOM
default 0x0
help
Product ID of the USB device emulated, reported to the host device.
config USB_GADGET_ATMEL_USBA
bool "Atmel USBA"
+ depends on ARCH_AT91
select USB_GADGET_DUALSPEED
help
USBA is the integrated high-speed USB Device controller on
the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
-config USB_GADGET_BCM_UDC_OTG_PHY
- bool "Broadcom UDC OTG PHY"
- help
- Enable the Broadcom UDC OTG physical device interface.
-
config USB_GADGET_AT91
bool "Atmel AT91 USB Gadget Controller"
depends on ARCH_AT91
config USB_GADGET_DWC2_OTG
bool "DesignWare USB2.0 HS OTG controller (gadget mode)"
+ depends on ARM
select USB_GADGET_DUALSPEED
help
The Designware USB2.0 high-speed gadget controller
@@ -151,17 +151,12 @@ config USB_GADGET_OS_DESCRIPTORS
config CI_UDC
bool "ChipIdea device controller"
+ depends on !DM_USB_GADGET
select USB_GADGET_DUALSPEED
help
Say Y here to enable device controller functionality of the
ChipIdea driver.
-config USB_GADGET_MAX3420
- bool "MAX3420 USB Over SPI"
- depends on DM_SPI
- help
- MAX3420, from MAXIM, implements USB-over-SPI Full-Speed device controller.
-
config USB_GADGET_VBUS_DRAW
int "Maximum VBUS Power usage (2-500 mA)"
range 2 500
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index db5f8895a33..f2aebf4e480 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -17,10 +17,8 @@ endif
ifdef CONFIG_USB_GADGET
obj-$(CONFIG_USB_GADGET_AT91) += at91_udc.o
obj-$(CONFIG_USB_GADGET_ATMEL_USBA) += atmel_usba_udc.o
-obj-$(CONFIG_USB_GADGET_BCM_UDC_OTG_PHY) += bcm_udc_otg_phy.o
obj-$(CONFIG_USB_GADGET_DWC2_OTG) += dwc2_udc_otg.o
obj-$(CONFIG_USB_GADGET_DWC2_OTG_PHY) += dwc2_udc_otg_phy.o
-obj-$(CONFIG_USB_GADGET_MAX3420) += max3420_udc.o
obj-$(CONFIG_USB_RENESAS_USBHS) += rcar/
ifndef CONFIG_XPL_BUILD
obj-$(CONFIG_USB_GADGET_DOWNLOAD) += g_dnl.o
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index 72f68dba3a7..f7a92ded6da 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -1147,7 +1147,7 @@ static int usba_udc_irq(struct usba_udc *udc)
reset_all_endpoints(udc);
if (udc->gadget.speed != USB_SPEED_UNKNOWN &&
- udc->driver->disconnect) {
+ udc->driver && udc->driver->disconnect) {
udc->gadget.speed = USB_SPEED_UNKNOWN;
spin_unlock(&udc->lock);
udc->driver->disconnect(&udc->gadget);
diff --git a/drivers/usb/gadget/bcm_udc_otg.h b/drivers/usb/gadget/bcm_udc_otg.h
deleted file mode 100644
index 48370f37d8a..00000000000
--- a/drivers/usb/gadget/bcm_udc_otg.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright 2015 Broadcom Corporation.
- */
-
-#ifndef __BCM_UDC_OTG_H
-#define __BCM_UDC_OTG_H
-
-static inline void wfld_set(uintptr_t addr, uint32_t fld_val, uint32_t fld_mask)
-{
- writel(((readl(addr) & ~(fld_mask)) | (fld_val)), (addr));
-}
-
-static inline void wfld_clear(uintptr_t addr, uint32_t fld_mask)
-{
- writel((readl(addr) & ~(fld_mask)), (addr));
-}
-
-#endif
diff --git a/drivers/usb/gadget/bcm_udc_otg_phy.c b/drivers/usb/gadget/bcm_udc_otg_phy.c
deleted file mode 100644
index 9875191091c..00000000000
--- a/drivers/usb/gadget/bcm_udc_otg_phy.c
+++ /dev/null
@@ -1,54 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright 2015 Broadcom Corporation.
- */
-
-#include <config.h>
-#include <asm/io.h>
-#include <asm/arch/sysmap.h>
-#include <asm/kona-common/clk.h>
-#include <linux/delay.h>
-
-#include "dwc2_udc_otg_priv.h"
-#include "bcm_udc_otg.h"
-
-void otg_phy_init(struct dwc2_udc *dev)
-{
- /* turn on the USB OTG clocks */
- clk_usb_otg_enable((void *)HSOTG_BASE_ADDR);
-
- /* set Phy to driving mode */
- wfld_clear(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_PHY_P1CTL_OFFSET,
- HSOTG_CTRL_PHY_P1CTL_NON_DRIVING_MASK);
-
- udelay(100);
-
- /* clear Soft Disconnect */
- wfld_clear(HSOTG_BASE_ADDR + HSOTG_DCTL_OFFSET,
- HSOTG_DCTL_SFTDISCON_MASK);
-
- /* invoke Reset (active low) */
- wfld_clear(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_PHY_P1CTL_OFFSET,
- HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK);
-
- /* Reset needs to be asserted for 2ms */
- udelay(2000);
-
- /* release Reset */
- wfld_set(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_PHY_P1CTL_OFFSET,
- HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK,
- HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK);
-}
-
-void otg_phy_off(struct dwc2_udc *dev)
-{
- /* Soft Disconnect */
- wfld_set(HSOTG_BASE_ADDR + HSOTG_DCTL_OFFSET,
- HSOTG_DCTL_SFTDISCON_MASK,
- HSOTG_DCTL_SFTDISCON_MASK);
-
- /* set Phy to non-driving (reset) mode */
- wfld_set(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_PHY_P1CTL_OFFSET,
- HSOTG_CTRL_PHY_P1CTL_NON_DRIVING_MASK,
- HSOTG_CTRL_PHY_P1CTL_NON_DRIVING_MASK);
-}
diff --git a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
index fca052b4556..5a7f50ebaa5 100644
--- a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
+++ b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
@@ -526,7 +526,7 @@ static int dwc2_udc_irq(int irq, void *_dev)
if (gotgint & GOTGINT_SES_END_DET) {
debug_cond(DEBUG_ISR, "\t\tSession End Detected\n");
/* Let gadget detect disconnected state */
- if (dev->driver->disconnect) {
+ if (dev->driver && dev->driver->disconnect) {
spin_unlock_irqrestore(&dev->lock, flags);
dev->driver->disconnect(&dev->gadget);
spin_lock_irqsave(&dev->lock, flags);
diff --git a/drivers/usb/gadget/f_sdp.c b/drivers/usb/gadget/f_sdp.c
index 647001d8dd0..f72e27028b7 100644
--- a/drivers/usb/gadget/f_sdp.c
+++ b/drivers/usb/gadget/f_sdp.c
@@ -765,7 +765,7 @@ static ulong search_container_header(ulong p, int size)
for (i = 0; i < size; i += 4) {
hdr = (u8 *)(p + i);
- if (*(hdr + 3) == 0x87 && *hdr == 0)
+ if (*(hdr + 3) == 0x87 && (*hdr == 0 || *hdr == 2))
if (*(hdr + 1) != 0 || *(hdr + 2) != 0)
return p + i;
}
diff --git a/drivers/usb/gadget/max3420_udc.c b/drivers/usb/gadget/max3420_udc.c
deleted file mode 100644
index 557a1f0644e..00000000000
--- a/drivers/usb/gadget/max3420_udc.c
+++ /dev/null
@@ -1,879 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <asm/gpio.h>
-#include <linux/list.h>
-#include <linux/bitfield.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-#include <malloc.h>
-#include <spi.h>
-#include <dm.h>
-#include <g_dnl.h>
-
-#define MAX3420_MAX_EPS 4
-#define EP_MAX_PACKET 64 /* Same for all Endpoints */
-#define EPNAME_SIZE 16 /* Buffer size for endpoint name */
-
-#define MAX3420_SPI_DIR_RD 0 /* read register from MAX3420 */
-#define MAX3420_SPI_DIR_WR 1 /* write register to MAX3420 */
-
-/* SPI commands: */
-#define MAX3420_SPI_ACK_MASK BIT(0)
-#define MAX3420_SPI_DIR_MASK BIT(1)
-#define MAX3420_SPI_REG_MASK GENMASK(7, 3)
-
-#define MAX3420_REG_EP0FIFO 0
-#define MAX3420_REG_EP1FIFO 1
-#define MAX3420_REG_EP2FIFO 2
-#define MAX3420_REG_EP3FIFO 3
-#define MAX3420_REG_SUDFIFO 4
-#define MAX3420_REG_EP0BC 5
-#define MAX3420_REG_EP1BC 6
-#define MAX3420_REG_EP2BC 7
-#define MAX3420_REG_EP3BC 8
-
-#define MAX3420_REG_EPSTALLS 9
- #define bACKSTAT BIT(6)
- #define bSTLSTAT BIT(5)
- #define bSTLEP3IN BIT(4)
- #define bSTLEP2IN BIT(3)
- #define bSTLEP1OUT BIT(2)
- #define bSTLEP0OUT BIT(1)
- #define bSTLEP0IN BIT(0)
-
-#define MAX3420_REG_CLRTOGS 10
- #define bEP3DISAB BIT(7)
- #define bEP2DISAB BIT(6)
- #define bEP1DISAB BIT(5)
- #define bCTGEP3IN BIT(4)
- #define bCTGEP2IN BIT(3)
- #define bCTGEP1OUT BIT(2)
-
-#define MAX3420_REG_EPIRQ 11
-#define MAX3420_REG_EPIEN 12
- #define bSUDAVIRQ BIT(5)
- #define bIN3BAVIRQ BIT(4)
- #define bIN2BAVIRQ BIT(3)
- #define bOUT1DAVIRQ BIT(2)
- #define bOUT0DAVIRQ BIT(1)
- #define bIN0BAVIRQ BIT(0)
-
-#define MAX3420_REG_USBIRQ 13
-#define MAX3420_REG_USBIEN 14
- #define bOSCOKIRQ BIT(0)
- #define bRWUDNIRQ BIT(1)
- #define bBUSACTIRQ BIT(2)
- #define bURESIRQ BIT(3)
- #define bSUSPIRQ BIT(4)
- #define bNOVBUSIRQ BIT(5)
- #define bVBUSIRQ BIT(6)
- #define bURESDNIRQ BIT(7)
-
-#define MAX3420_REG_USBCTL 15
- #define bHOSCSTEN BIT(7)
- #define bVBGATE BIT(6)
- #define bCHIPRES BIT(5)
- #define bPWRDOWN BIT(4)
- #define bCONNECT BIT(3)
- #define bSIGRWU BIT(2)
-
-#define MAX3420_REG_CPUCTL 16
- #define bIE BIT(0)
-
-#define MAX3420_REG_PINCTL 17
- #define bEP3INAK BIT(7)
- #define bEP2INAK BIT(6)
- #define bEP0INAK BIT(5)
- #define bFDUPSPI BIT(4)
- #define bINTLEVEL BIT(3)
- #define bPOSINT BIT(2)
- #define bGPXB BIT(1)
- #define bGPXA BIT(0)
-
-#define MAX3420_REG_REVISION 18
-
-#define MAX3420_REG_FNADDR 19
- #define FNADDR_MASK 0x7f
-
-#define MAX3420_REG_IOPINS 20
-#define MAX3420_REG_IOPINS2 21
-#define MAX3420_REG_GPINIRQ 22
-#define MAX3420_REG_GPINIEN 23
-#define MAX3420_REG_GPINPOL 24
-#define MAX3420_REG_HIRQ 25
-#define MAX3420_REG_HIEN 26
-#define MAX3420_REG_MODE 27
-#define MAX3420_REG_PERADDR 28
-#define MAX3420_REG_HCTL 29
-#define MAX3420_REG_HXFR 30
-#define MAX3420_REG_HRSL 31
-
-struct max3420_req {
- struct usb_request usb_req;
- struct list_head queue;
- struct max3420_ep *ep;
-};
-
-struct max3420_ep {
- struct max3420_udc *udc;
- struct list_head queue;
- char name[EPNAME_SIZE];
- unsigned int maxpacket;
- struct usb_ep ep_usb;
- int halted;
- int id;
-};
-
-struct max3420_udc {
- struct max3420_ep ep[MAX3420_MAX_EPS];
- struct usb_gadget_driver *driver;
- bool softconnect;
- struct usb_ctrlrequest setup;
- struct max3420_req ep0req;
- struct usb_gadget gadget;
- struct spi_slave *slave;
- struct udevice *dev;
- u8 ep0buf[64];
- int remote_wkp;
- bool suspended;
-};
-
-#define to_max3420_req(r) container_of((r), struct max3420_req, usb_req)
-#define to_max3420_ep(e) container_of((e), struct max3420_ep, ep_usb)
-#define to_udc(g) container_of((g), struct max3420_udc, gadget)
-
-static void spi_ack_ctrl(struct max3420_udc *udc)
-{
- struct spi_slave *slave = udc->slave;
- u8 txdata[1];
-
- txdata[0] = FIELD_PREP(MAX3420_SPI_ACK_MASK, 1);
- spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_ONCE);
-}
-
-static u8 spi_rd8_ack(struct max3420_udc *udc, u8 reg, int ackstat)
-{
- struct spi_slave *slave = udc->slave;
- u8 txdata[2], rxdata[2];
-
- txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) |
- FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_RD) |
- FIELD_PREP(MAX3420_SPI_ACK_MASK, ackstat ? 1 : 0);
-
- rxdata[0] = 0;
- rxdata[1] = 0;
- spi_xfer(slave, sizeof(txdata), txdata, rxdata, SPI_XFER_ONCE);
-
- return rxdata[1];
-}
-
-static u8 spi_rd8(struct max3420_udc *udc, u8 reg)
-{
- return spi_rd8_ack(udc, reg, 0);
-}
-
-static void spi_wr8_ack(struct max3420_udc *udc, u8 reg, u8 val, int ackstat)
-{
- struct spi_slave *slave = udc->slave;
- u8 txdata[2];
-
- txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) |
- FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_WR) |
- FIELD_PREP(MAX3420_SPI_ACK_MASK, ackstat ? 1 : 0);
- txdata[1] = val;
-
- spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_ONCE);
-}
-
-static void spi_wr8(struct max3420_udc *udc, u8 reg, u8 val)
-{
- spi_wr8_ack(udc, reg, val, 0);
-}
-
-static void spi_rd_buf(struct max3420_udc *udc, u8 reg, void *buf, u8 len)
-{
- struct spi_slave *slave = udc->slave;
- u8 txdata[1];
-
- txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) |
- FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_RD);
-
- spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_BEGIN);
- spi_xfer(slave, len * 8, NULL, buf, SPI_XFER_END);
-}
-
-static void spi_wr_buf(struct max3420_udc *udc, u8 reg, void *buf, u8 len)
-{
- struct spi_slave *slave = udc->slave;
- u8 txdata[1];
-
- txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) |
- FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_WR);
-
- spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_BEGIN);
- spi_xfer(slave, len * 8, buf, NULL, SPI_XFER_END);
-}
-
-/* 0 if not-connected */
-int g_dnl_board_usb_cable_connected(void)
-{
- return 1;
-}
-
-static void spi_max3420_enable(struct max3420_ep *ep, int enable)
-{
- struct max3420_udc *udc = ep->udc;
- u8 epdis, epien;
-
- if (ep->id == 0)
- return;
-
- epien = spi_rd8(udc, MAX3420_REG_EPIEN);
- epdis = spi_rd8(udc, MAX3420_REG_CLRTOGS);
-
- if (enable) {
- epdis &= ~BIT(ep->id + 4);
- epien |= BIT(ep->id + 1);
- } else {
- epdis |= BIT(ep->id + 4);
- epien &= ~BIT(ep->id + 1);
- }
-
- spi_wr8(udc, MAX3420_REG_CLRTOGS, epdis);
- spi_wr8(udc, MAX3420_REG_EPIEN, epien);
-}
-
-static int
-max3420_ep_enable(struct usb_ep *_ep,
- const struct usb_endpoint_descriptor *desc)
-{
- struct max3420_ep *ep = to_max3420_ep(_ep);
-
- _ep->desc = desc;
- _ep->maxpacket = usb_endpoint_maxp(desc) & 0x7ff;
-
- spi_max3420_enable(ep, 1);
-
- return 0;
-}
-
-static void max3420_req_done(struct max3420_req *req, int status)
-{
- struct max3420_ep *ep = req->ep;
-
- if (req->usb_req.status == -EINPROGRESS)
- req->usb_req.status = status;
- else
- status = req->usb_req.status;
-
- if (status && status != -ESHUTDOWN)
- dev_err(ep->udc->dev, "%s done %p, status %d\n",
- ep->ep_usb.name, req, status);
-
- if (req->usb_req.complete)
- req->usb_req.complete(&ep->ep_usb, &req->usb_req);
-}
-
-static void max3420_ep_nuke(struct max3420_ep *ep, int status)
-{
- struct max3420_req *req, *r;
-
- list_for_each_entry_safe(req, r, &ep->queue, queue) {
- list_del_init(&req->queue);
- max3420_req_done(req, status);
- }
-}
-
-static int max3420_ep_disable(struct usb_ep *_ep)
-{
- struct max3420_ep *ep = to_max3420_ep(_ep);
-
- _ep->desc = NULL;
- max3420_ep_nuke(ep, -ESHUTDOWN);
- spi_max3420_enable(ep, 0);
-
- return 0;
-}
-
-static struct usb_request *
-max3420_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
-{
- struct max3420_ep *ep = to_max3420_ep(_ep);
- struct max3420_req *req = kzalloc(sizeof(*req), gfp_flags);
-
- if (!req)
- return NULL;
-
- req->ep = ep;
- INIT_LIST_HEAD(&req->queue);
-
- return &req->usb_req;
-}
-
-static void
-max3420_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
-{
- kfree(to_max3420_req(_req));
-}
-
-static int
-max3420_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
-{
- struct max3420_req *req = to_max3420_req(_req);
- struct max3420_ep *ep = to_max3420_ep(_ep);
-
- _req->status = -EINPROGRESS;
- _req->actual = 0;
- list_add_tail(&req->queue, &ep->queue);
-
- return 0;
-}
-
-static int max3420_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
-{
- struct max3420_req *req = to_max3420_req(_req);
-
- list_del_init(&req->queue);
- max3420_req_done(req, -ECONNRESET);
-
- return 0;
-}
-
-static int max3420_ep_set_halt(struct usb_ep *_ep, int halt)
-{
- struct max3420_ep *ep = to_max3420_ep(_ep);
- struct max3420_udc *udc = ep->udc;
- u8 epstalls;
-
- if (ep->id == 0) /* can't stall EP0 */
- return 0;
-
- epstalls = spi_rd8(udc, MAX3420_REG_EPSTALLS);
- if (halt) {
- ep->halted = 1;
- epstalls |= BIT(ep->id + 1);
- } else {
- u8 clrtogs;
-
- ep->halted = 0;
- epstalls &= ~BIT(ep->id + 1);
- clrtogs = spi_rd8(udc, MAX3420_REG_CLRTOGS);
- clrtogs |= BIT(ep->id + 1);
- spi_wr8(udc, MAX3420_REG_CLRTOGS, clrtogs);
- }
- spi_wr8(udc, MAX3420_REG_EPSTALLS, epstalls | bACKSTAT);
-
- return 0;
-}
-
-static const struct usb_ep_ops max3420_ep_ops = {
- .enable = max3420_ep_enable,
- .disable = max3420_ep_disable,
- .alloc_request = max3420_ep_alloc_request,
- .free_request = max3420_ep_free_request,
- .queue = max3420_ep_queue,
- .dequeue = max3420_ep_dequeue,
- .set_halt = max3420_ep_set_halt,
-};
-
-static void __max3420_stop(struct max3420_udc *udc)
-{
- u8 val;
-
- /* Disable IRQ to CPU */
- spi_wr8(udc, MAX3420_REG_CPUCTL, 0);
-
- val = spi_rd8(udc, MAX3420_REG_USBCTL);
- val |= bPWRDOWN;
- val |= bHOSCSTEN;
- spi_wr8(udc, MAX3420_REG_USBCTL, val);
-}
-
-static void __max3420_start(struct max3420_udc *udc)
-{
- u8 val;
-
- /* configure SPI */
- spi_wr8(udc, MAX3420_REG_PINCTL, bFDUPSPI);
-
- /* Chip Reset */
- spi_wr8(udc, MAX3420_REG_USBCTL, bCHIPRES);
- mdelay(5);
- spi_wr8(udc, MAX3420_REG_USBCTL, 0);
-
- /* Poll for OSC to stabilize */
- while (1) {
- val = spi_rd8(udc, MAX3420_REG_USBIRQ);
- if (val & bOSCOKIRQ)
- break;
- cond_resched();
- }
-
- /* Enable PULL-UP only when Vbus detected */
- val = spi_rd8(udc, MAX3420_REG_USBCTL);
- val |= bVBGATE | bCONNECT;
- spi_wr8(udc, MAX3420_REG_USBCTL, val);
-
- val = bURESDNIRQ | bURESIRQ;
- spi_wr8(udc, MAX3420_REG_USBIEN, val);
-
- /* Enable only EP0 interrupts */
- val = bIN0BAVIRQ | bOUT0DAVIRQ | bSUDAVIRQ;
- spi_wr8(udc, MAX3420_REG_EPIEN, val);
-
- /* Enable IRQ to CPU */
- spi_wr8(udc, MAX3420_REG_CPUCTL, bIE);
-}
-
-static int max3420_udc_start(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver)
-{
- struct max3420_udc *udc = to_udc(gadget);
-
- udc->driver = driver;
- udc->remote_wkp = 0;
- udc->softconnect = true;
-
- __max3420_start(udc);
-
- return 0;
-}
-
-static int max3420_udc_stop(struct usb_gadget *gadget)
-{
- struct max3420_udc *udc = to_udc(gadget);
-
- udc->driver = NULL;
- udc->softconnect = false;
-
- __max3420_stop(udc);
-
- return 0;
-}
-
-static int max3420_wakeup(struct usb_gadget *gadget)
-{
- struct max3420_udc *udc = to_udc(gadget);
- u8 usbctl;
-
- /* Only if wakeup allowed by host */
- if (!udc->remote_wkp || !udc->suspended)
- return 0;
-
- /* Set Remote-Wakeup Signal*/
- usbctl = spi_rd8(udc, MAX3420_REG_USBCTL);
- usbctl |= bSIGRWU;
- spi_wr8(udc, MAX3420_REG_USBCTL, usbctl);
-
- mdelay(5);
-
- /* Clear Remote-WkUp Signal*/
- usbctl = spi_rd8(udc, MAX3420_REG_USBCTL);
- usbctl &= ~bSIGRWU;
- spi_wr8(udc, MAX3420_REG_USBCTL, usbctl);
-
- udc->suspended = false;
-
- return 0;
-}
-
-static const struct usb_gadget_ops max3420_udc_ops = {
- .udc_start = max3420_udc_start,
- .udc_stop = max3420_udc_stop,
- .wakeup = max3420_wakeup,
-};
-
-static struct usb_endpoint_descriptor ep0_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
- .wMaxPacketSize = cpu_to_le16(EP_MAX_PACKET),
-};
-
-static void max3420_getstatus(struct max3420_udc *udc)
-{
- struct max3420_ep *ep;
- u16 status = 0;
-
- switch (udc->setup.bRequestType & USB_RECIP_MASK) {
- case USB_RECIP_DEVICE:
- /* Get device status */
- status = 0 << USB_DEVICE_SELF_POWERED;
- status |= (udc->remote_wkp << USB_DEVICE_REMOTE_WAKEUP);
- break;
- case USB_RECIP_INTERFACE:
- if (udc->driver->setup(&udc->gadget, &udc->setup) < 0)
- goto stall;
- break;
- case USB_RECIP_ENDPOINT:
- ep = &udc->ep[udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK];
- if (ep->halted)
- status = 1 << USB_ENDPOINT_HALT;
- break;
- default:
- goto stall;
- }
-
- status = cpu_to_le16(status);
- spi_wr_buf(udc, MAX3420_REG_EP0FIFO, &status, 2);
- spi_wr8_ack(udc, MAX3420_REG_EP0BC, 2, 1);
- return;
-stall:
- dev_err(udc->dev, "Can't respond to getstatus request\n");
- spi_wr8(udc, MAX3420_REG_EPSTALLS, bSTLEP0IN | bSTLEP0OUT | bSTLSTAT);
-}
-
-static void max3420_set_clear_feature(struct max3420_udc *udc)
-{
- int set = udc->setup.bRequest == USB_REQ_SET_FEATURE;
- struct max3420_ep *ep;
- int id;
-
- switch (udc->setup.bRequestType) {
- case USB_RECIP_DEVICE:
- if (udc->setup.wValue != USB_DEVICE_REMOTE_WAKEUP)
- break;
-
- if (udc->setup.bRequest == USB_REQ_SET_FEATURE)
- udc->remote_wkp = 1;
- else
- udc->remote_wkp = 0;
-
- return spi_ack_ctrl(udc);
-
- case USB_RECIP_ENDPOINT:
- if (udc->setup.wValue != USB_ENDPOINT_HALT)
- break;
-
- id = udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK;
- ep = &udc->ep[id];
-
- max3420_ep_set_halt(&ep->ep_usb, set);
- return;
- default:
- break;
- }
-
- dev_err(udc->dev, "Can't respond to SET/CLEAR FEATURE\n");
- spi_wr8(udc, MAX3420_REG_EPSTALLS, bSTLEP0IN | bSTLEP0OUT | bSTLSTAT);
-}
-
-static void max3420_handle_setup(struct max3420_udc *udc)
-{
- struct usb_ctrlrequest setup;
- u8 addr;
-
- spi_rd_buf(udc, MAX3420_REG_SUDFIFO, (void *)&setup, 8);
-
- udc->setup = setup;
- udc->setup.wValue = cpu_to_le16(setup.wValue);
- udc->setup.wIndex = cpu_to_le16(setup.wIndex);
- udc->setup.wLength = cpu_to_le16(setup.wLength);
-
- switch (udc->setup.bRequest) {
- case USB_REQ_GET_STATUS:
- /* Data+Status phase form udc */
- if ((udc->setup.bRequestType &
- (USB_DIR_IN | USB_TYPE_MASK)) !=
- (USB_DIR_IN | USB_TYPE_STANDARD)) {
- break;
- }
- return max3420_getstatus(udc);
- case USB_REQ_SET_ADDRESS:
- /* Status phase from udc */
- if (udc->setup.bRequestType != (USB_DIR_OUT |
- USB_TYPE_STANDARD | USB_RECIP_DEVICE))
- break;
- addr = spi_rd8_ack(udc, MAX3420_REG_FNADDR, 1);
- dev_dbg(udc->dev, "Assigned Address=%d/%d\n",
- udc->setup.wValue, addr);
- return;
- case USB_REQ_CLEAR_FEATURE:
- case USB_REQ_SET_FEATURE:
- /* Requests with no data phase, status phase from udc */
- if ((udc->setup.bRequestType & USB_TYPE_MASK)
- != USB_TYPE_STANDARD)
- break;
- return max3420_set_clear_feature(udc);
- default:
- break;
- }
-
- if (udc->driver->setup(&udc->gadget, &setup) < 0) {
- /* Stall EP0 */
- spi_wr8(udc, MAX3420_REG_EPSTALLS,
- bSTLEP0IN | bSTLEP0OUT | bSTLSTAT);
- }
-}
-
-static int do_data(struct max3420_udc *udc, int ep_id, int in)
-{
- struct max3420_ep *ep = &udc->ep[ep_id];
- struct max3420_req *req;
- int done, length, psz;
- void *buf;
-
- if (list_empty(&ep->queue))
- return 0;
-
- req = list_first_entry(&ep->queue, struct max3420_req, queue);
- buf = req->usb_req.buf + req->usb_req.actual;
-
- psz = ep->ep_usb.maxpacket;
- length = req->usb_req.length - req->usb_req.actual;
- length = min(length, psz);
-
- if (length == 0) {
- done = 1;
- goto xfer_done;
- }
-
- done = 0;
- if (in) {
- spi_wr_buf(udc, MAX3420_REG_EP0FIFO + ep_id, buf, length);
- spi_wr8(udc, MAX3420_REG_EP0BC + ep_id, length);
- if (length < psz)
- done = 1;
- } else {
- psz = spi_rd8(udc, MAX3420_REG_EP0BC + ep_id);
- length = min(length, psz);
- spi_rd_buf(udc, MAX3420_REG_EP0FIFO + ep_id, buf, length);
- if (length < ep->ep_usb.maxpacket)
- done = 1;
- }
-
- req->usb_req.actual += length;
-
- if (req->usb_req.actual == req->usb_req.length)
- done = 1;
-
-xfer_done:
- if (done) {
- list_del_init(&req->queue);
-
- if (ep_id == 0)
- spi_ack_ctrl(udc);
-
- max3420_req_done(req, 0);
- }
-
- return 1;
-}
-
-static int max3420_handle_irqs(struct max3420_udc *udc)
-{
- u8 epien, epirq, usbirq, usbien, reg[4];
- int ret = 0;
-
- spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 4);
- epirq = reg[0];
- epien = reg[1];
- usbirq = reg[2];
- usbien = reg[3];
-
- usbirq &= usbien;
- epirq &= epien;
-
- if (epirq & bSUDAVIRQ) {
- spi_wr8(udc, MAX3420_REG_EPIRQ, bSUDAVIRQ);
- max3420_handle_setup(udc);
- return 1;
- }
-
- if (usbirq & bVBUSIRQ) {
- spi_wr8(udc, MAX3420_REG_USBIRQ, bVBUSIRQ);
- dev_dbg(udc->dev, "Cable plugged in\n");
- g_dnl_clear_detach();
- return 1;
- }
-
- if (usbirq & bNOVBUSIRQ) {
- spi_wr8(udc, MAX3420_REG_USBIRQ, bNOVBUSIRQ);
- dev_dbg(udc->dev, "Cable pulled out\n");
- g_dnl_trigger_detach();
- return 1;
- }
-
- if (usbirq & bURESIRQ) {
- spi_wr8(udc, MAX3420_REG_USBIRQ, bURESIRQ);
- return 1;
- }
-
- if (usbirq & bURESDNIRQ) {
- spi_wr8(udc, MAX3420_REG_USBIRQ, bURESDNIRQ);
- spi_wr8(udc, MAX3420_REG_USBIEN, bURESDNIRQ | bURESIRQ);
- spi_wr8(udc, MAX3420_REG_EPIEN, bSUDAVIRQ
- | bIN0BAVIRQ | bOUT0DAVIRQ);
- return 1;
- }
-
- if (usbirq & bSUSPIRQ) {
- spi_wr8(udc, MAX3420_REG_USBIRQ, bSUSPIRQ);
- dev_dbg(udc->dev, "USB Suspend - Enter\n");
- udc->suspended = true;
- return 1;
- }
-
- if (usbirq & bBUSACTIRQ) {
- spi_wr8(udc, MAX3420_REG_USBIRQ, bBUSACTIRQ);
- dev_dbg(udc->dev, "USB Suspend - Exit\n");
- udc->suspended = false;
- return 1;
- }
-
- if (usbirq & bRWUDNIRQ) {
- spi_wr8(udc, MAX3420_REG_USBIRQ, bRWUDNIRQ);
- dev_dbg(udc->dev, "Asked Host to wakeup\n");
- return 1;
- }
-
- if (usbirq & bOSCOKIRQ) {
- spi_wr8(udc, MAX3420_REG_USBIRQ, bOSCOKIRQ);
- dev_dbg(udc->dev, "Osc stabilized, start work\n");
- return 1;
- }
-
- if (epirq & bOUT0DAVIRQ && do_data(udc, 0, 0)) {
- spi_wr8_ack(udc, MAX3420_REG_EPIRQ, bOUT0DAVIRQ, 1);
- ret = 1;
- }
-
- if (epirq & bIN0BAVIRQ && do_data(udc, 0, 1))
- ret = 1;
-
- if (epirq & bOUT1DAVIRQ && do_data(udc, 1, 0)) {
- spi_wr8_ack(udc, MAX3420_REG_EPIRQ, bOUT1DAVIRQ, 1);
- ret = 1;
- }
-
- if (epirq & bIN2BAVIRQ && do_data(udc, 2, 1))
- ret = 1;
-
- if (epirq & bIN3BAVIRQ && do_data(udc, 3, 1))
- ret = 1;
-
- return ret;
-}
-
-static int max3420_irq(struct max3420_udc *udc)
-{
- do_data(udc, 0, 1); /* get done with the EP0 ZLP */
-
- return max3420_handle_irqs(udc);
-}
-
-static void max3420_setup_eps(struct max3420_udc *udc)
-{
- int i;
-
- INIT_LIST_HEAD(&udc->gadget.ep_list);
- INIT_LIST_HEAD(&udc->ep[0].ep_usb.ep_list);
-
- for (i = 0; i < MAX3420_MAX_EPS; i++) {
- struct max3420_ep *ep = &udc->ep[i];
-
- INIT_LIST_HEAD(&ep->queue);
-
- ep->id = i;
- ep->udc = udc;
- ep->ep_usb.ops = &max3420_ep_ops;
- ep->ep_usb.name = ep->name;
- ep->ep_usb.maxpacket = EP_MAX_PACKET;
-
- if (i == 0) {
- ep->ep_usb.desc = &ep0_desc;
- snprintf(ep->name, EPNAME_SIZE, "ep0");
- continue;
- }
-
- list_add_tail(&ep->ep_usb.ep_list, &udc->gadget.ep_list);
-
- if (i == 1)
- snprintf(ep->name, EPNAME_SIZE, "ep1out-bulk");
- else
- snprintf(ep->name, EPNAME_SIZE, "ep%din-bulk", i);
- };
-}
-
-static void max3420_setup_spi(struct max3420_udc *udc)
-{
- u8 reg[8];
-
- spi_claim_bus(udc->slave);
- spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 8);
- /* configure SPI */
- spi_wr8(udc, MAX3420_REG_PINCTL, bFDUPSPI);
-}
-
-static int max3420_udc_probe(struct udevice *dev)
-{
- struct max3420_udc *udc = dev_get_priv(dev);
- struct dm_spi_slave_plat *slave_pdata;
- struct udevice *bus = dev->parent;
- int busnum = dev_seq(bus);
- unsigned int cs;
- uint speed, mode;
- struct udevice *spid;
-
- slave_pdata = dev_get_parent_plat(dev);
- cs = slave_pdata->cs;
- speed = slave_pdata->max_hz;
- mode = slave_pdata->mode;
- _spi_get_bus_and_cs(busnum, cs, speed, mode, false, "spi_generic_drv",
- NULL, &spid, &udc->slave);
-
- udc->dev = dev;
- udc->gadget.ep0 = &udc->ep[0].ep_usb;
- udc->gadget.max_speed = USB_SPEED_FULL;
- udc->gadget.speed = USB_SPEED_FULL;
- udc->gadget.is_dualspeed = 0;
- udc->gadget.ops = &max3420_udc_ops;
- udc->gadget.name = "max3420-udc";
-
- max3420_setup_eps(udc);
- max3420_setup_spi(udc);
-
- usb_add_gadget_udc((struct device *)dev, &udc->gadget);
-
- return 0;
-}
-
-static int max3420_udc_remove(struct udevice *dev)
-{
- struct max3420_udc *udc = dev_get_priv(dev);
-
- usb_del_gadget_udc(&udc->gadget);
-
- spi_release_bus(udc->slave);
-
- return 0;
-}
-
-static int max3420_gadget_handle_interrupts(struct udevice *dev)
-{
- struct max3420_udc *udc = dev_get_priv(dev);
-
- return max3420_irq(udc);
-}
-
-static const struct usb_gadget_generic_ops max3420_gadget_ops = {
- .handle_interrupts = max3420_gadget_handle_interrupts,
-};
-
-static const struct udevice_id max3420_ids[] = {
- { .compatible = "maxim,max3421-udc" },
- { }
-};
-
-U_BOOT_DRIVER(max3420_generic_udc) = {
- .name = "max3420-udc",
- .id = UCLASS_USB_GADGET_GENERIC,
- .of_match = max3420_ids,
- .ops = &max3420_gadget_ops,
- .probe = max3420_udc_probe,
- .remove = max3420_udc_remove,
- .priv_auto = sizeof(struct max3420_udc),
-};
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 5c9e8fc9d15..427b62e934b 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -121,8 +121,9 @@ config USB_XHCI_DRA7XX_INDEX
config USB_XHCI_FSL
bool "Support for NXP Layerscape on-chip xHCI USB controller"
- default y if ARCH_LS1021A || FSL_LSCH3 || FSL_LSCH2
+ depends on ARCH_LS1021A || FSL_LSCH3 || FSL_LSCH2
depends on !SPL_NO_USB
+ default y
help
Enables support for the on-chip xHCI controller on NXP Layerscape SoCs.
@@ -209,10 +210,10 @@ config USB_EHCI_MX6
config USB_EHCI_MX7
bool "Support for i.MX7/i.MX8M/i.MX9 on-chip EHCI USB controller"
- depends on ARCH_MX7 || IMX8M || IMX93 || IMX95
+ depends on ARCH_MX7 || IMX8M || IMX9
select EHCI_HCD_INIT_AFTER_RESET if ARCH_MX7
- select PHY if IMX8M || IMX93 || IMX95
- select NOP_PHY if IMX8M || IMX93 || IMX95
+ select PHY if IMX8M || IMX9
+ select NOP_PHY if IMX8M || IMX9
default y
---help---
Enables support for the on-chip EHCI controller on i.MX7/i.MX8M/i.MX9 SoCs.
@@ -286,7 +287,8 @@ config USB_EHCI_TEGRA
config USB_EHCI_ZYNQ
bool "Support for Xilinx Zynq on-chip EHCI USB controller"
- default y if ARCH_ZYNQ
+ depends on ARCH_ZYNQ
+ default y
select USB_EHCI_IS_TDI
---help---
Enable support for Zynq on-chip EHCI USB controller
@@ -303,6 +305,7 @@ config EHCI_HCD_INIT_AFTER_RESET
config USB_EHCI_FSL
bool "Support for FSL on-chip EHCI USB controller"
+ depends on PPC
select EHCI_HCD_INIT_AFTER_RESET
select SYS_FSL_USB_INTERNAL_UTMI_PHY if MPC85xx && \
!(ARCH_B4860 || ARCH_B4420 || ARCH_P4080 || ARCH_P1020 || ARCH_P2020)
@@ -362,6 +365,7 @@ config USB_OHCI_GENERIC
config USB_OHCI_DA8XX
bool "Support for da850 OHCI USB controller"
+ depends on ARCH_DAVINCI
help
Enable support for the da850 USB controller.
diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c
index 1e4a5a0b6f6..e1fc04efd2e 100644
--- a/drivers/usb/host/ehci-exynos.c
+++ b/drivers/usb/host/ehci-exynos.c
@@ -47,8 +47,7 @@ static int ehci_usb_of_to_plat(struct udevice *dev)
{
struct exynos_ehci_plat *plat = dev_get_plat(dev);
const void *blob = gd->fdt_blob;
- unsigned int node;
- int depth;
+ int node, depth;
/*
* Get the base address for XHCI controller from the device node
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index a759aea9db3..8aeb6a91556 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -24,10 +24,11 @@
struct msm_ehci_priv {
struct ehci_ctrl ctrl; /* Needed by EHCI */
struct usb_ehci *ehci; /* Start of IP core*/
- struct ulpi_viewport ulpi_vp; /* ULPI Viewport */
struct phy phy;
- struct clk iface_clk;
- struct clk core_clk;
+};
+
+struct qcom_ci_hdrc_priv {
+ struct clk_bulk clks;
};
static int msm_init_after_reset(struct ehci_ctrl *dev)
@@ -56,64 +57,31 @@ static int ehci_usb_probe(struct udevice *dev)
struct ehci_hcor *hcor;
int ret;
- ret = clk_get_by_name(dev, "core", &p->core_clk);
- if (ret) {
- dev_err(dev, "Failed to get core clock: %d\n", ret);
- return ret;
- }
-
- ret = clk_get_by_name(dev, "iface", &p->iface_clk);
- if (ret) {
- dev_err(dev, "Failed to get iface clock: %d\n", ret);
- return ret;
- }
-
- ret = clk_prepare_enable(&p->core_clk);
- if (ret)
- return ret;
-
- ret = clk_prepare_enable(&p->iface_clk);
- if (ret)
- goto cleanup_core;
-
hccr = (struct ehci_hccr *)((phys_addr_t)&ehci->caplength);
hcor = (struct ehci_hcor *)((phys_addr_t)hccr +
HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
ret = generic_setup_phy(dev, &p->phy, 0, PHY_MODE_USB_HOST, 0);
if (ret)
- goto cleanup_iface;
+ return ret;
ret = board_usb_init(0, plat->init_type);
if (ret < 0)
- goto cleanup_iface;
+ return ret;
return ehci_register(dev, hccr, hcor, &msm_ehci_ops, 0,
plat->init_type);
-
-cleanup_iface:
- clk_disable_unprepare(&p->iface_clk);
-cleanup_core:
- clk_disable_unprepare(&p->core_clk);
- return ret;
}
static int ehci_usb_remove(struct udevice *dev)
{
struct msm_ehci_priv *p = dev_get_priv(dev);
- struct usb_ehci *ehci = p->ehci;
int ret;
ret = ehci_deregister(dev);
if (ret)
return ret;
- /* Stop controller. */
- clrbits_le32(&ehci->usbcmd, CMD_RUN);
-
- clk_disable_unprepare(&p->iface_clk);
- clk_disable_unprepare(&p->core_clk);
-
ret = generic_shutdown_phy(&p->phy);
if (ret)
return ret;
@@ -122,15 +90,6 @@ static int ehci_usb_remove(struct udevice *dev)
if (ret < 0)
return ret;
- /* Reset controller */
- setbits_le32(&ehci->usbcmd, CMD_RESET);
-
- /* Wait for reset */
- if (wait_for_bit_le32(&ehci->usbcmd, CMD_RESET, false, 30, false)) {
- printf("Stuck on USB reset.\n");
- return -ETIMEDOUT;
- }
-
return 0;
}
@@ -138,38 +97,14 @@ static int ehci_usb_of_to_plat(struct udevice *dev)
{
struct msm_ehci_priv *priv = dev_get_priv(dev);
- priv->ulpi_vp.port_num = 0;
priv->ehci = dev_read_addr_ptr(dev);
- if (priv->ehci == (void *)FDT_ADDR_T_NONE)
+ if (!priv->ehci)
return -EINVAL;
- /* Warning: this will not work if viewport address is > 64 bit due to
- * ULPI design.
- */
- priv->ulpi_vp.viewport_addr = (phys_addr_t)&priv->ehci->ulpi_viewpoint;
-
return 0;
}
-static int ehci_usb_of_bind(struct udevice *dev)
-{
- ofnode ulpi_node = ofnode_first_subnode(dev_ofnode(dev));
- ofnode phy_node;
-
- if (!ofnode_valid(ulpi_node))
- return 0;
-
- phy_node = ofnode_first_subnode(ulpi_node);
- if (!ofnode_valid(phy_node)) {
- printf("%s: ulpi subnode with no phy\n", __func__);
- return -ENOENT;
- }
-
- return device_bind_driver_to_node(dev, "msm8916_usbphy", "msm8916_usbphy",
- phy_node, NULL);
-}
-
#if defined(CONFIG_CI_UDC)
/* Little quirk that MSM needs with Chipidea controller
* Must reinit phy after reset
@@ -182,17 +117,10 @@ void ci_init_after_reset(struct ehci_ctrl *ctrl)
}
#endif
-static const struct udevice_id ehci_usb_ids[] = {
- { .compatible = "qcom,ci-hdrc", },
- { }
-};
-
U_BOOT_DRIVER(usb_ehci) = {
.name = "ehci_msm",
.id = UCLASS_USB,
- .of_match = ehci_usb_ids,
.of_to_plat = ehci_usb_of_to_plat,
- .bind = ehci_usb_of_bind,
.probe = ehci_usb_probe,
.remove = ehci_usb_remove,
.ops = &ehci_usb_ops,
@@ -200,3 +128,63 @@ U_BOOT_DRIVER(usb_ehci) = {
.plat_auto = sizeof(struct usb_plat),
.flags = DM_FLAG_ALLOC_PRIV_DMA,
};
+
+static int qcom_ci_hdrc_probe(struct udevice *dev)
+{
+ struct qcom_ci_hdrc_priv *p = dev_get_priv(dev);
+ int ret;
+
+ ret = clk_get_bulk(dev, &p->clks);
+ if (ret && (ret != -ENOSYS && ret != -ENOENT)) {
+ dev_err(dev, "Failed to get clocks: %d\n", ret);
+ return ret;
+ }
+
+ return clk_enable_bulk(&p->clks);
+}
+
+static int qcom_ci_hdrc_remove(struct udevice *dev)
+{
+ struct qcom_ci_hdrc_priv *p = dev_get_priv(dev);
+
+ return clk_release_bulk(&p->clks);
+}
+
+static int qcom_ci_hdrc_bind(struct udevice *dev)
+{
+ ofnode ulpi_node = ofnode_first_subnode(dev_ofnode(dev));
+ ofnode phy_node;
+ int ret;
+
+ ret = device_bind_driver_to_node(dev, "ehci_msm", "ehci_msm",
+ dev_ofnode(dev), NULL);
+ if (ret)
+ return ret;
+
+ if (!ofnode_valid(ulpi_node))
+ return 0;
+
+ phy_node = ofnode_first_subnode(ulpi_node);
+ if (!ofnode_valid(phy_node)) {
+ printf("%s: ulpi subnode with no phy\n", __func__);
+ return -ENOENT;
+ }
+
+ return device_bind_driver_to_node(dev, "msm8916_usbphy", "msm8916_usbphy",
+ phy_node, NULL);
+}
+
+static const struct udevice_id qcom_ci_hdrc_ids[] = {
+ { .compatible = "qcom,ci-hdrc", },
+ { }
+};
+
+U_BOOT_DRIVER(qcom_ci_hdrc) = {
+ .name = "qcom_ci_hdrc",
+ .id = UCLASS_NOP,
+ .of_match = qcom_ci_hdrc_ids,
+ .bind = qcom_ci_hdrc_bind,
+ .probe = qcom_ci_hdrc_probe,
+ .remove = qcom_ci_hdrc_remove,
+ .priv_auto = sizeof(struct qcom_ci_hdrc_priv),
+};
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 234a6f3645d..1d6711ccec4 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1040,9 +1040,11 @@ static void dl_transfer_length(td_t *td)
static void check_status(td_t *td_list)
{
urb_priv_t *lurb_priv = td_list->ed->purb;
- int urb_len = lurb_priv->length;
__u32 *phwHeadP = &td_list->ed->hwHeadP;
- int cc;
+ int cc, urb_len;
+
+ if (lurb_priv)
+ urb_len = lurb_priv->length;
cc = TD_CC_GET(m32_swap(td_list->hwINFO));
if (cc) {
diff --git a/drivers/usb/host/xhci-brcm.c b/drivers/usb/host/xhci-brcm.c
index 2ffad148dea..595839fac3c 100644
--- a/drivers/usb/host/xhci-brcm.c
+++ b/drivers/usb/host/xhci-brcm.c
@@ -85,7 +85,7 @@ static const struct udevice_id xhci_brcm_ids[] = {
{ }
};
-U_BOOT_DRIVER(usb_xhci) = {
+U_BOOT_DRIVER(xhci_brcm) = {
.name = "xhci_brcm",
.id = UCLASS_USB,
.probe = xhci_brcm_probe,
diff --git a/drivers/usb/host/xhci-exynos5.c b/drivers/usb/host/xhci-exynos5.c
index 6a2d422c4b8..500696ccae7 100644
--- a/drivers/usb/host/xhci-exynos5.c
+++ b/drivers/usb/host/xhci-exynos5.c
@@ -56,8 +56,7 @@ static int xhci_usb_of_to_plat(struct udevice *dev)
{
struct exynos_xhci_plat *plat = dev_get_plat(dev);
const void *blob = gd->fdt_blob;
- unsigned int node;
- int depth;
+ int node, depth;
/*
* Get the base address for XHCI controller from the device node
@@ -247,7 +246,7 @@ static const struct udevice_id xhci_usb_ids[] = {
{ }
};
-U_BOOT_DRIVER(usb_xhci) = {
+U_BOOT_DRIVER(xhci_exynos) = {
.name = "xhci_exynos",
.id = UCLASS_USB,
.of_match = xhci_usb_ids,
diff --git a/drivers/usb/host/xhci-generic.c b/drivers/usb/host/xhci-generic.c
index 355d4883176..8bb4e277423 100644
--- a/drivers/usb/host/xhci-generic.c
+++ b/drivers/usb/host/xhci-generic.c
@@ -61,7 +61,7 @@ static const struct udevice_id xhci_usb_ids[] = {
{ }
};
-U_BOOT_DRIVER(usb_xhci) = {
+U_BOOT_DRIVER(xhci_generic) = {
.name = "xhci_generic",
.id = UCLASS_USB,
.of_match = xhci_usb_ids,
diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
index 7e288f0575b..ffe80c0bbdc 100644
--- a/drivers/usb/host/xhci-mtk.c
+++ b/drivers/usb/host/xhci-mtk.c
@@ -357,7 +357,7 @@ static const struct udevice_id xhci_mtk_ids[] = {
{ }
};
-U_BOOT_DRIVER(usb_xhci) = {
+U_BOOT_DRIVER(xhci_mtk) = {
.name = "xhci-mtk",
.id = UCLASS_USB,
.of_match = xhci_mtk_ids,
diff --git a/drivers/usb/host/xhci-mvebu.c b/drivers/usb/host/xhci-mvebu.c
index 1338b1021c6..12dc61aee9d 100644
--- a/drivers/usb/host/xhci-mvebu.c
+++ b/drivers/usb/host/xhci-mvebu.c
@@ -87,7 +87,7 @@ static const struct udevice_id xhci_usb_ids[] = {
{ }
};
-U_BOOT_DRIVER(usb_xhci) = {
+U_BOOT_DRIVER(xhci_mvebu) = {
.name = "xhci_mvebu",
.id = UCLASS_USB,
.of_match = xhci_usb_ids,
diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c
index b72807053c4..95dfa2c3f87 100644
--- a/drivers/usb/host/xhci-rcar.c
+++ b/drivers/usb/host/xhci-rcar.c
@@ -149,7 +149,7 @@ static const struct udevice_id xhci_rcar_ids[] = {
{ }
};
-U_BOOT_DRIVER(usb_xhci) = {
+U_BOOT_DRIVER(xhci_rcar) = {
.name = "xhci_rcar",
.id = UCLASS_USB,
.probe = xhci_rcar_probe,
diff --git a/drivers/usb/musb-new/Kconfig b/drivers/usb/musb-new/Kconfig
index ad9072a5327..f8daaddc657 100644
--- a/drivers/usb/musb-new/Kconfig
+++ b/drivers/usb/musb-new/Kconfig
@@ -40,6 +40,7 @@ config USB_MUSB_DA8XX
config USB_MUSB_TI
bool "Enable TI OTG USB controller"
depends on AM33XX
+ select MISC if OF_CONTROL
select USB_MUSB_DSPS
help
Say y here to enable support for the dual role high
@@ -52,9 +53,11 @@ config USB_MUSB_OMAP2PLUS
config USB_MUSB_AM35X
bool "AM35x"
+ depends on ARCH_OMAP2PLUS
config USB_MUSB_DSPS
bool "TI DSPS platforms"
+ depends on ARCH_OMAP2PLUS
config USB_MUSB_MT85XX
bool "Enable Mediatek MT85XX DRC USB controller"
diff --git a/drivers/usb/musb-new/am35x.c b/drivers/usb/musb-new/am35x.c
index 42bc816e4f1..ca4d798642e 100644
--- a/drivers/usb/musb-new/am35x.c
+++ b/drivers/usb/musb-new/am35x.c
@@ -402,7 +402,7 @@ static int am35x_musb_init(struct musb *musb)
#endif
/* Reset the musb */
- if (data->reset)
+ if (data && data->reset)
data->reset(data->dev);
/* Reset the controller */
@@ -417,7 +417,7 @@ static int am35x_musb_init(struct musb *musb)
musb->isr = am35x_musb_interrupt;
/* clear level interrupt */
- if (data->clear_irq)
+ if (data && data->clear_irq)
data->clear_irq(data->dev);
return 0;
diff --git a/drivers/usb/musb-new/musb_core.c b/drivers/usb/musb-new/musb_core.c
index a14b127dc37..17ec0d3acbd 100644
--- a/drivers/usb/musb-new/musb_core.c
+++ b/drivers/usb/musb-new/musb_core.c
@@ -1954,7 +1954,7 @@ musb_init_controller(struct musb_hdrc_platform_data *plat, struct device *dev,
/* The musb_platform_init() call:
* - adjusts musb->mregs and musb->isr if needed,
- * - may initialize an integrated tranceiver
+ * - may initialize an integrated transceiver
* - initializes musb->xceiv, usually by otg_get_phy()
* - stops powering VBUS
*
diff --git a/drivers/usb/musb-new/musb_gadget.c b/drivers/usb/musb-new/musb_gadget.c
index 08fac829ce7..7daff5850f1 100644
--- a/drivers/usb/musb-new/musb_gadget.c
+++ b/drivers/usb/musb-new/musb_gadget.c
@@ -728,7 +728,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
* mode 0 only. So we do not get endpoint interrupts due to DMA
* completion. We only get interrupts from DMA controller.
*
- * We could operate in DMA mode 1 if we knew the size of the tranfer
+ * We could operate in DMA mode 1 if we knew the size of the transfer
* in advance. For mass storage class, request->length = what the host
* sends, so that'd work. But for pretty much everything else,
* request->length is routinely more than what the host sends. For
@@ -1422,7 +1422,7 @@ done:
}
/*
- * Set or clear the halt bit of an endpoint. A halted enpoint won't tx/rx any
+ * Set or clear the halt bit of an endpoint. A halted endpoint won't tx/rx any
* data but will queue requests.
*
* exported to ep0 code
diff --git a/drivers/usb/musb-new/musb_gadget_ep0.c b/drivers/usb/musb-new/musb_gadget_ep0.c
index ea65326ab62..25b1de6e58f 100644
--- a/drivers/usb/musb-new/musb_gadget_ep0.c
+++ b/drivers/usb/musb-new/musb_gadget_ep0.c
@@ -96,6 +96,9 @@ static int service_tx_status_request(
if (!epnum) {
result[0] = 0;
break;
+ } else if (epnum >= MUSB_C_NUM_EPS) {
+ handled = -EINVAL;
+ break;
}
is_in = epnum & USB_DIR_IN;
@@ -107,7 +110,7 @@ static int service_tx_status_request(
}
regs = musb->endpoints[epnum].regs;
- if (epnum >= MUSB_C_NUM_EPS || !ep->desc) {
+ if (!ep->desc) {
handled = -EINVAL;
break;
}
diff --git a/drivers/usb/musb-new/musb_host.c b/drivers/usb/musb-new/musb_host.c
index 7528a53d73e..7f296d15984 100644
--- a/drivers/usb/musb-new/musb_host.c
+++ b/drivers/usb/musb-new/musb_host.c
@@ -1862,7 +1862,7 @@ static int musb_schedule(
head = &musb->out_bulk;
/* Enable bulk RX NAK timeout scheme when bulk requests are
- * multiplexed. This scheme doen't work in high speed to full
+ * multiplexed. This scheme doesn't work in high speed to full
* speed scenario as NAK interrupts are not coming from a
* full speed device connected to a high speed device.
* NAK timeout interval is 8 (128 uframe or 16ms) for HS and
diff --git a/drivers/usb/musb-new/omap2430.c b/drivers/usb/musb-new/omap2430.c
index ba600d01102..7fd6639013a 100644
--- a/drivers/usb/musb-new/omap2430.c
+++ b/drivers/usb/musb-new/omap2430.c
@@ -142,41 +142,49 @@ static int omap2430_musb_of_to_plat(struct udevice *dev)
struct omap2430_musb_plat *plat = dev_get_plat(dev);
const void *fdt = gd->fdt_blob;
int node = dev_of_offset(dev);
+ int ret;
plat->base = (void *)dev_read_addr_ptr(dev);
- plat->musb_config.multipoint = fdtdec_get_int(fdt, node, "multipoint",
- -1);
- if (plat->musb_config.multipoint < 0) {
+ ret = fdtdec_get_int(fdt, node, "multipoint", -1);
+ if (ret < 0) {
pr_err("MUSB multipoint DT entry missing\n");
return -ENOENT;
+ } else {
+ plat->musb_config.multipoint = ret;
}
plat->musb_config.dyn_fifo = 1;
- plat->musb_config.num_eps = fdtdec_get_int(fdt, node, "num-eps", -1);
- if (plat->musb_config.num_eps < 0) {
+ ret = fdtdec_get_int(fdt, node, "num-eps", -1);
+ if (ret < 0) {
pr_err("MUSB num-eps DT entry missing\n");
return -ENOENT;
+ } else {
+ plat->musb_config.num_eps = ret;
}
- plat->musb_config.ram_bits = fdtdec_get_int(fdt, node, "ram-bits", -1);
- if (plat->musb_config.ram_bits < 0) {
+ ret = fdtdec_get_int(fdt, node, "ram-bits", -1);
+ if (ret < 0) {
pr_err("MUSB ram-bits DT entry missing\n");
return -ENOENT;
+ } else {
+ plat->musb_config.ram_bits = ret;
}
- plat->plat.power = fdtdec_get_int(fdt, node, "power", -1);
- if (plat->plat.power < 0) {
+ ret = fdtdec_get_int(fdt, node, "power", -1);
+ if (ret < 0) {
pr_err("MUSB power DT entry missing\n");
return -ENOENT;
+ } else {
+ plat->plat.power = ret;
}
- plat->otg_board_data.interface_type = fdtdec_get_int(fdt, node,
- "interface-type",
- -1);
- if (plat->otg_board_data.interface_type < 0) {
+ ret = fdtdec_get_int(fdt, node, "interface-type", -1);
+ if (ret < 0) {
pr_err("MUSB interface-type DT entry missing\n");
return -ENOENT;
+ } else {
+ plat->otg_board_data.interface_type = ret;
}
#if 0 /* In a perfect world, mode would be set to OTG, mode 3 from DT */
diff --git a/drivers/usb/musb-new/ti-musb.c b/drivers/usb/musb-new/ti-musb.c
index 967d0953875..bcd31adba52 100644
--- a/drivers/usb/musb-new/ti-musb.c
+++ b/drivers/usb/musb-new/ti-musb.c
@@ -86,6 +86,7 @@ static int ti_musb_of_to_plat(struct udevice *dev)
int phys;
int ctrl_mod;
int usb_index;
+ int ret;
struct musb_hdrc_config *musb_config;
plat->base = devfdt_get_addr_index_ptr(dev, 1);
@@ -108,35 +109,40 @@ static int ti_musb_of_to_plat(struct udevice *dev)
musb_config = malloc(sizeof(struct musb_hdrc_config));
memset(musb_config, 0, sizeof(struct musb_hdrc_config));
- musb_config->multipoint = fdtdec_get_int(fdt, node,
- "mentor,multipoint", -1);
- if (musb_config->multipoint < 0) {
+ ret = fdtdec_get_int(fdt, node, "mentor,multipoint", -1);
+ if (ret < 0) {
pr_err("MUSB multipoint DT entry missing\n");
return -ENOENT;
+ } else {
+ musb_config->multipoint = ret;
}
musb_config->dyn_fifo = 1;
- musb_config->num_eps = fdtdec_get_int(fdt, node, "mentor,num-eps",
- -1);
- if (musb_config->num_eps < 0) {
+ ret = fdtdec_get_int(fdt, node, "mentor,num-eps", -1);
+ if (ret < 0) {
pr_err("MUSB num-eps DT entry missing\n");
return -ENOENT;
+ } else {
+ musb_config->num_eps = ret;
}
- musb_config->ram_bits = fdtdec_get_int(fdt, node, "mentor,ram-bits",
- -1);
- if (musb_config->ram_bits < 0) {
+ ret = fdtdec_get_int(fdt, node, "mentor,ram-bits", -1);
+ if (ret < 0) {
pr_err("MUSB ram-bits DT entry missing\n");
return -ENOENT;
+ } else {
+ musb_config->ram_bits = ret;
}
plat->plat.config = musb_config;
- plat->plat.power = fdtdec_get_int(fdt, node, "mentor,power", -1);
- if (plat->plat.power < 0) {
+ ret = fdtdec_get_int(fdt, node, "mentor,power", -1);
+ if (ret < 0) {
pr_err("MUSB mentor,power DT entry missing\n");
return -ENOENT;
+ } else {
+ plat->plat.power = ret;
}
plat->plat.platform_ops = &musb_dsps_ops;
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
deleted file mode 100644
index 2508b6ed0d1..00000000000
--- a/drivers/usb/musb/Kconfig
+++ /dev/null
@@ -1,20 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0+
-#
-# (C) Copyright 2017
-# Adam Ford, Logic PD, aford173@gmail.com
-
-comment "Legacy MUSB Support"
-
-config USB_MUSB_HCD
- bool "Legacy MUSB Host Controller"
-
-config USB_MUSB_UDC
- bool "Legacy USB Device Controller"
-
-config USB_OMAP3
- bool "Legacy MUSB OMAP3 / OMAP4"
- depends on ARCH_OMAP2PLUS
-
-config USB_AM35X
- bool"Legacy MUSB AM35x"
- depends on ARCH_OMAP2PLUS && !USB_OMAP3
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
deleted file mode 100644
index 744f2cfaa29..00000000000
--- a/drivers/usb/musb/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0+
-#
-# (C) Copyright 2000-2007
-# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
-
-obj-$(CONFIG_USB_MUSB_HCD) += musb_hcd.o musb_core.o
-obj-$(CONFIG_USB_MUSB_UDC) += musb_udc.o musb_core.o
-obj-$(CONFIG_USB_OMAP3) += omap3.o
-obj-$(CONFIG_USB_AM35X) += am35x.o
diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c
deleted file mode 100644
index 2c23043d40e..00000000000
--- a/drivers/usb/musb/am35x.c
+++ /dev/null
@@ -1,138 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * am35x.c - TI's AM35x platform specific usb wrapper functions.
- *
- * Author: Ajay Kumar Gupta <ajay.gupta@ti.com>
- *
- * Based on drivers/usb/musb/da8xx.c
- *
- * Copyright (c) 2010 Texas Instruments Incorporated
- */
-
-#include <linux/delay.h>
-
-#include "am35x.h"
-
-/* MUSB platform configuration */
-struct musb_config musb_cfg = {
- .regs = (struct musb_regs *)AM35X_USB_OTG_CORE_BASE,
- .timeout = AM35X_USB_OTG_TIMEOUT,
- .musb_speed = 0,
-};
-
-/*
- * Enable the USB phy
- */
-static u8 phy_on(void)
-{
- u32 devconf2;
- u32 timeout;
-
- devconf2 = readl(&am35x_scm_general_regs->devconf2);
-
- devconf2 &= ~(DEVCONF2_RESET | DEVCONF2_PHYPWRDN | DEVCONF2_OTGPWRDN |
- DEVCONF2_OTGMODE | DEVCONF2_REFFREQ |
- DEVCONF2_PHY_GPIOMODE);
- devconf2 |= DEVCONF2_SESENDEN | DEVCONF2_VBDTCTEN | DEVCONF2_PHY_PLLON |
- DEVCONF2_REFFREQ_13MHZ | DEVCONF2_DATPOL;
-
- writel(devconf2, &am35x_scm_general_regs->devconf2);
-
- /* wait until the USB phy is turned on */
- timeout = musb_cfg.timeout;
- while (timeout--)
- if (readl(&am35x_scm_general_regs->devconf2) & DEVCONF2_PHYCKGD)
- return 1;
-
- /* USB phy was not turned on */
- return 0;
-}
-
-/*
- * Disable the USB phy
- */
-static void phy_off(void)
-{
- u32 devconf2;
-
- /*
- * Power down the on-chip PHY.
- */
- devconf2 = readl(&am35x_scm_general_regs->devconf2);
-
- devconf2 &= ~DEVCONF2_PHY_PLLON;
- devconf2 |= DEVCONF2_PHYPWRDN | DEVCONF2_OTGPWRDN;
- writel(devconf2, &am35x_scm_general_regs->devconf2);
-}
-
-/*
- * This function performs platform specific initialization for usb0.
- */
-int musb_platform_init(void)
-{
- u32 revision;
- u32 sw_reset;
-
- /* global usb reset */
- sw_reset = readl(&am35x_scm_general_regs->ip_sw_reset);
- sw_reset |= (1 << 0);
- writel(sw_reset, &am35x_scm_general_regs->ip_sw_reset);
- sw_reset &= ~(1 << 0);
- writel(sw_reset, &am35x_scm_general_regs->ip_sw_reset);
-
- /* reset the controller */
- writel(0x1, &am35x_usb_regs->control);
- udelay(5000);
-
- /* start the on-chip usb phy and its pll */
- if (phy_on() == 0)
- return -1;
-
- /* Returns zero if e.g. not clocked */
- revision = readl(&am35x_usb_regs->revision);
- if (revision == 0)
- return -1;
-
- return 0;
-}
-
-/*
- * This function performs platform specific deinitialization for usb0.
- */
-void musb_platform_deinit(void)
-{
- /* Turn off the phy */
- phy_off();
-}
-
-/*
- * This function reads data from endpoint fifo for AM35x
- * which supports only 32bit read operation.
- *
- * ep - endpoint number
- * length - number of bytes to read from FIFO
- * fifo_data - pointer to data buffer into which data is read
- */
-__attribute__((weak))
-void read_fifo(u8 ep, u32 length, void *fifo_data)
-{
- u8 *data = (u8 *)fifo_data;
- u32 val;
- int i;
-
- /* select the endpoint index */
- writeb(ep, &musbr->index);
-
- if (length > 4) {
- for (i = 0; i < (length >> 2); i++) {
- val = readl(&musbr->fifox[ep]);
- memcpy(data, &val, 4);
- data += 4;
- }
- length %= 4;
- }
- if (length > 0) {
- val = readl(&musbr->fifox[ep]);
- memcpy(data, &val, length);
- }
-}
diff --git a/drivers/usb/musb/am35x.h b/drivers/usb/musb/am35x.h
deleted file mode 100644
index 82ad94329cb..00000000000
--- a/drivers/usb/musb/am35x.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * am35x.h - TI's AM35x platform specific usb wrapper definitions.
- *
- * Author: Ajay Kumar Gupta <ajay.gupta@ti.com>
- *
- * Based on drivers/usb/musb/da8xx.h
- *
- * Copyright (c) 2010 Texas Instruments Incorporated
- */
-
-#ifndef __AM35X_USB_H__
-#define __AM35X_USB_H__
-
-#include <asm/arch/am35x_def.h>
-#include "musb_core.h"
-
-/* Base address of musb wrapper */
-#define AM35X_USB_OTG_BASE 0x5C040000
-
-/* Base address of musb core */
-#define AM35X_USB_OTG_CORE_BASE (AM35X_USB_OTG_BASE + 0x400)
-
-/* Timeout for AM35x usb module */
-#define AM35X_USB_OTG_TIMEOUT 0x3FFFFFF
-
-/*
- * AM35x platform USB wrapper register overlay.
- */
-struct am35x_usb_regs {
- u32 revision;
- u32 control;
- u32 status;
- u32 emulation;
- u32 reserved0[1];
- u32 autoreq;
- u32 srpfixtime;
- u32 ep_intsrc;
- u32 ep_intsrcset;
- u32 ep_intsrcclr;
- u32 ep_intmsk;
- u32 ep_intmskset;
- u32 ep_intmskclr;
- u32 ep_intsrcmsked;
- u32 reserved1[1];
- u32 core_intsrc;
- u32 core_intsrcset;
- u32 core_intsrcclr;
- u32 core_intmsk;
- u32 core_intmskset;
- u32 core_intmskclr;
- u32 core_intsrcmsked;
- u32 reserved2[1];
- u32 eoi;
- u32 mop_sop_en;
- u32 reserved3[2];
- u32 txmode;
- u32 rxmode;
- u32 epcount_mode;
-};
-
-#define am35x_usb_regs ((struct am35x_usb_regs *)AM35X_USB_OTG_BASE)
-
-/* USB 2.0 PHY Control */
-#define DEVCONF2_PHY_GPIOMODE (1 << 23)
-#define DEVCONF2_OTGMODE (3 << 14)
-#define DEVCONF2_SESENDEN (1 << 13) /* Vsess_end comparator */
-#define DEVCONF2_VBDTCTEN (1 << 12) /* Vbus comparator */
-#define DEVCONF2_REFFREQ_24MHZ (2 << 8)
-#define DEVCONF2_REFFREQ_26MHZ (7 << 8)
-#define DEVCONF2_REFFREQ_13MHZ (6 << 8)
-#define DEVCONF2_REFFREQ (0xf << 8)
-#define DEVCONF2_PHYCKGD (1 << 7)
-#define DEVCONF2_VBUSSENSE (1 << 6)
-#define DEVCONF2_PHY_PLLON (1 << 5) /* override PLL suspend */
-#define DEVCONF2_RESET (1 << 4)
-#define DEVCONF2_PHYPWRDN (1 << 3)
-#define DEVCONF2_OTGPWRDN (1 << 2)
-#define DEVCONF2_DATPOL (1 << 1)
-
-#endif /* __AM35X_USB_H__ */
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
deleted file mode 100644
index 260552e4dbd..00000000000
--- a/drivers/usb/musb/musb_core.c
+++ /dev/null
@@ -1,150 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Mentor USB OTG Core functionality common for both Host and Device
- * functionality.
- *
- * Copyright (c) 2008 Texas Instruments
- *
- * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
- */
-
-#include <linux/bitops.h>
-
-#include "musb_core.h"
-struct musb_regs *musbr;
-
-/*
- * program the mentor core to start (enable interrupts, dma, etc.)
- */
-void musb_start(void)
-{
-#if defined(CONFIG_USB_MUSB_HCD)
- u8 devctl;
- u8 busctl;
-#endif
-
- /* disable all interrupts */
- writew(0, &musbr->intrtxe);
- writew(0, &musbr->intrrxe);
- writeb(0, &musbr->intrusbe);
- writeb(0, &musbr->testmode);
-
- /* put into basic highspeed mode and start session */
- writeb(MUSB_POWER_HSENAB, &musbr->power);
-#if defined(CONFIG_USB_MUSB_HCD)
- /* Program PHY to use EXT VBUS if required */
- if (musb_cfg.extvbus == 1) {
- busctl = musb_read_ulpi_buscontrol(musbr);
- musb_write_ulpi_buscontrol(musbr, busctl | ULPI_USE_EXTVBUS);
- }
-
- devctl = readb(&musbr->devctl);
- writeb(devctl | MUSB_DEVCTL_SESSION, &musbr->devctl);
-#endif
-}
-
-#ifdef MUSB_NO_DYNAMIC_FIFO
-# define config_fifo(dir, idx, addr)
-#else
-# define config_fifo(dir, idx, addr) \
- do { \
- writeb(idx, &musbr->dir##fifosz); \
- writew(addr, &musbr->dir##fifoadd); \
- } while (0)
-#endif
-
-/*
- * This function configures the endpoint configuration. The musb hcd or musb
- * device implementation can use this function to configure the endpoints
- * and set the FIFO sizes. Note: The summation of FIFO sizes of all endpoints
- * should not be more than the available FIFO size.
- *
- * epinfo - Pointer to EP configuration table
- * cnt - Number of entries in the EP conf table.
- */
-void musb_configure_ep(const struct musb_epinfo *epinfo, u8 cnt)
-{
- u16 csr;
- u16 fifoaddr = 64 >> 3; /* First 64 bytes of FIFO reserved for EP0 */
- u32 fifosize;
- u8 idx;
-
- while (cnt--) {
- /* prepare fifosize to write to register */
- fifosize = epinfo->epsize >> 3;
- idx = fifosize ? ((ffs(fifosize) - 1) & 0xF) : 0;
-
- writeb(epinfo->epnum, &musbr->index);
- if (epinfo->epdir) {
- /* Configure fifo size and fifo base address */
- config_fifo(tx, idx, fifoaddr);
-
- csr = readw(&musbr->txcsr);
- /* clear the data toggle bit */
- writew(csr | MUSB_TXCSR_CLRDATATOG, &musbr->txcsr);
- /* Flush fifo if required */
- if (csr & MUSB_TXCSR_TXPKTRDY)
- writew(csr | MUSB_TXCSR_FLUSHFIFO,
- &musbr->txcsr);
- } else {
- /* Configure fifo size and fifo base address */
- config_fifo(rx, idx, fifoaddr);
-
- csr = readw(&musbr->rxcsr);
- /* clear the data toggle bit */
- writew(csr | MUSB_RXCSR_CLRDATATOG, &musbr->rxcsr);
- /* Flush fifo if required */
- if (csr & MUSB_RXCSR_RXPKTRDY)
- writew(csr | MUSB_RXCSR_FLUSHFIFO,
- &musbr->rxcsr);
- }
- fifoaddr += 1 << idx;
- epinfo++;
- }
-}
-
-/*
- * This function writes data to endpoint fifo
- *
- * ep - endpoint number
- * length - number of bytes to write to FIFO
- * fifo_data - Pointer to data buffer that contains the data to write
- */
-__attribute__((weak))
-void write_fifo(u8 ep, u32 length, void *fifo_data)
-{
- u8 *data = (u8 *)fifo_data;
-
- /* select the endpoint index */
- writeb(ep, &musbr->index);
-
- /* write the data to the fifo */
- while (length--)
- writeb(*data++, &musbr->fifox[ep]);
-}
-
-/*
- * AM35x supports only 32bit read operations so
- * use seperate read_fifo() function for it.
- */
-#ifndef CONFIG_USB_AM35X
-/*
- * This function reads data from endpoint fifo
- *
- * ep - endpoint number
- * length - number of bytes to read from FIFO
- * fifo_data - pointer to data buffer into which data is read
- */
-__attribute__((weak))
-void read_fifo(u8 ep, u32 length, void *fifo_data)
-{
- u8 *data = (u8 *)fifo_data;
-
- /* select the endpoint index */
- writeb(ep, &musbr->index);
-
- /* read the data to the fifo */
- while (length--)
- *data++ = readb(&musbr->fifox[ep]);
-}
-#endif /* CONFIG_USB_AM35X */
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
deleted file mode 100644
index 47b839c0835..00000000000
--- a/drivers/usb/musb/musb_core.h
+++ /dev/null
@@ -1,343 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/******************************************************************
- * Copyright 2008 Mentor Graphics Corporation
- * Copyright (C) 2008 by Texas Instruments
- *
- * This file is part of the Inventra Controller Driver for Linux.
- ******************************************************************/
-
-#ifndef __MUSB_HDRC_DEFS_H__
-#define __MUSB_HDRC_DEFS_H__
-
-#include <usb_defs.h>
-#include <asm/io.h>
-
-#define MUSB_EP0_FIFOSIZE 64 /* This is non-configurable */
-
-/* EP0 */
-struct musb_ep0_regs {
- u16 reserved4;
- u16 csr0;
- u16 reserved5;
- u16 reserved6;
- u16 count0;
- u8 host_type0;
- u8 host_naklimit0;
- u8 reserved7;
- u8 reserved8;
- u8 reserved9;
- u8 configdata;
-};
-
-/* EP 1-15 */
-struct musb_epN_regs {
- u16 txmaxp;
- u16 txcsr;
- u16 rxmaxp;
- u16 rxcsr;
- u16 rxcount;
- u8 txtype;
- u8 txinterval;
- u8 rxtype;
- u8 rxinterval;
- u8 reserved0;
- u8 fifosize;
-};
-
-/* Mentor USB core register overlay structure */
-#ifndef musb_regs
-struct musb_regs {
- /* common registers */
- u8 faddr;
- u8 power;
- u16 intrtx;
- u16 intrrx;
- u16 intrtxe;
- u16 intrrxe;
- u8 intrusb;
- u8 intrusbe;
- u16 frame;
- u8 index;
- u8 testmode;
- /* indexed registers */
- u16 txmaxp;
- u16 txcsr;
- u16 rxmaxp;
- u16 rxcsr;
- u16 rxcount;
- u8 txtype;
- u8 txinterval;
- u8 rxtype;
- u8 rxinterval;
- u8 reserved0;
- u8 fifosize;
- /* fifo */
- u32 fifox[16];
- /* OTG, dynamic FIFO, version & vendor registers */
- u8 devctl;
- u8 reserved1;
- u8 txfifosz;
- u8 rxfifosz;
- u16 txfifoadd;
- u16 rxfifoadd;
- u32 vcontrol;
- u16 hwvers;
- u16 reserved2a[1];
- u8 ulpi_busctl;
- u8 reserved2b[1];
- u16 reserved2[3];
- u8 epinfo;
- u8 raminfo;
- u8 linkinfo;
- u8 vplen;
- u8 hseof1;
- u8 fseof1;
- u8 lseof1;
- u8 reserved3;
- /* target address registers */
- struct musb_tar_regs {
- u8 txfuncaddr;
- u8 reserved0;
- u8 txhubaddr;
- u8 txhubport;
- u8 rxfuncaddr;
- u8 reserved1;
- u8 rxhubaddr;
- u8 rxhubport;
- } tar[16];
- /*
- * endpoint registers
- * ep0 elements are valid when array index is 0
- * otherwise epN is valid
- */
- union musb_ep_regs {
- struct musb_ep0_regs ep0;
- struct musb_epN_regs epN;
- } ep[16];
-
-} __attribute__((packed));
-#endif
-
-/*
- * MUSB Register bits
- */
-
-/* POWER */
-#define MUSB_POWER_ISOUPDATE 0x80
-#define MUSB_POWER_SOFTCONN 0x40
-#define MUSB_POWER_HSENAB 0x20
-#define MUSB_POWER_HSMODE 0x10
-#define MUSB_POWER_RESET 0x08
-#define MUSB_POWER_RESUME 0x04
-#define MUSB_POWER_SUSPENDM 0x02
-#define MUSB_POWER_ENSUSPEND 0x01
-#define MUSB_POWER_HSMODE_SHIFT 4
-
-/* INTRUSB */
-#define MUSB_INTR_SUSPEND 0x01
-#define MUSB_INTR_RESUME 0x02
-#define MUSB_INTR_RESET 0x04
-#define MUSB_INTR_BABBLE 0x04
-#define MUSB_INTR_SOF 0x08
-#define MUSB_INTR_CONNECT 0x10
-#define MUSB_INTR_DISCONNECT 0x20
-#define MUSB_INTR_SESSREQ 0x40
-#define MUSB_INTR_VBUSERROR 0x80 /* For SESSION end */
-
-/* DEVCTL */
-#define MUSB_DEVCTL_BDEVICE 0x80
-#define MUSB_DEVCTL_FSDEV 0x40
-#define MUSB_DEVCTL_LSDEV 0x20
-#define MUSB_DEVCTL_VBUS 0x18
-#define MUSB_DEVCTL_VBUS_SHIFT 3
-#define MUSB_DEVCTL_HM 0x04
-#define MUSB_DEVCTL_HR 0x02
-#define MUSB_DEVCTL_SESSION 0x01
-
-/* ULPI VBUSCONTROL */
-#define ULPI_USE_EXTVBUS 0x01
-#define ULPI_USE_EXTVBUSIND 0x02
-
-/* TESTMODE */
-#define MUSB_TEST_FORCE_HOST 0x80
-#define MUSB_TEST_FIFO_ACCESS 0x40
-#define MUSB_TEST_FORCE_FS 0x20
-#define MUSB_TEST_FORCE_HS 0x10
-#define MUSB_TEST_PACKET 0x08
-#define MUSB_TEST_K 0x04
-#define MUSB_TEST_J 0x02
-#define MUSB_TEST_SE0_NAK 0x01
-
-/* Allocate for double-packet buffering (effectively doubles assigned _SIZE) */
-#define MUSB_FIFOSZ_DPB 0x10
-/* Allocation size (8, 16, 32, ... 4096) */
-#define MUSB_FIFOSZ_SIZE 0x0f
-
-/* CSR0 */
-#define MUSB_CSR0_FLUSHFIFO 0x0100
-#define MUSB_CSR0_TXPKTRDY 0x0002
-#define MUSB_CSR0_RXPKTRDY 0x0001
-
-/* CSR0 in Peripheral mode */
-#define MUSB_CSR0_P_SVDSETUPEND 0x0080
-#define MUSB_CSR0_P_SVDRXPKTRDY 0x0040
-#define MUSB_CSR0_P_SENDSTALL 0x0020
-#define MUSB_CSR0_P_SETUPEND 0x0010
-#define MUSB_CSR0_P_DATAEND 0x0008
-#define MUSB_CSR0_P_SENTSTALL 0x0004
-
-/* CSR0 in Host mode */
-#define MUSB_CSR0_H_DIS_PING 0x0800
-#define MUSB_CSR0_H_WR_DATATOGGLE 0x0400 /* Set to allow setting: */
-#define MUSB_CSR0_H_DATATOGGLE 0x0200 /* Data toggle control */
-#define MUSB_CSR0_H_NAKTIMEOUT 0x0080
-#define MUSB_CSR0_H_STATUSPKT 0x0040
-#define MUSB_CSR0_H_REQPKT 0x0020
-#define MUSB_CSR0_H_ERROR 0x0010
-#define MUSB_CSR0_H_SETUPPKT 0x0008
-#define MUSB_CSR0_H_RXSTALL 0x0004
-
-/* CSR0 bits to avoid zeroing (write zero clears, write 1 ignored) */
-#define MUSB_CSR0_P_WZC_BITS \
- (MUSB_CSR0_P_SENTSTALL)
-#define MUSB_CSR0_H_WZC_BITS \
- (MUSB_CSR0_H_NAKTIMEOUT | MUSB_CSR0_H_RXSTALL \
- | MUSB_CSR0_RXPKTRDY)
-
-/* TxType/RxType */
-#define MUSB_TYPE_SPEED 0xc0
-#define MUSB_TYPE_SPEED_SHIFT 6
-#define MUSB_TYPE_SPEED_HIGH 1
-#define MUSB_TYPE_SPEED_FULL 2
-#define MUSB_TYPE_SPEED_LOW 3
-#define MUSB_TYPE_PROTO 0x30 /* Implicitly zero for ep0 */
-#define MUSB_TYPE_PROTO_SHIFT 4
-#define MUSB_TYPE_REMOTE_END 0xf /* Implicitly zero for ep0 */
-#define MUSB_TYPE_PROTO_BULK 2
-#define MUSB_TYPE_PROTO_INTR 3
-
-/* CONFIGDATA */
-#define MUSB_CONFIGDATA_MPRXE 0x80 /* Auto bulk pkt combining */
-#define MUSB_CONFIGDATA_MPTXE 0x40 /* Auto bulk pkt splitting */
-#define MUSB_CONFIGDATA_BIGENDIAN 0x20
-#define MUSB_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */
-#define MUSB_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */
-#define MUSB_CONFIGDATA_DYNFIFO 0x04 /* Dynamic FIFO sizing */
-#define MUSB_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */
-#define MUSB_CONFIGDATA_UTMIDW 0x01 /* Data width 0/1 => 8/16bits */
-
-/* TXCSR in Peripheral and Host mode */
-#define MUSB_TXCSR_AUTOSET 0x8000
-#define MUSB_TXCSR_MODE 0x2000
-#define MUSB_TXCSR_DMAENAB 0x1000
-#define MUSB_TXCSR_FRCDATATOG 0x0800
-#define MUSB_TXCSR_DMAMODE 0x0400
-#define MUSB_TXCSR_CLRDATATOG 0x0040
-#define MUSB_TXCSR_FLUSHFIFO 0x0008
-#define MUSB_TXCSR_FIFONOTEMPTY 0x0002
-#define MUSB_TXCSR_TXPKTRDY 0x0001
-
-/* TXCSR in Peripheral mode */
-#define MUSB_TXCSR_P_ISO 0x4000
-#define MUSB_TXCSR_P_INCOMPTX 0x0080
-#define MUSB_TXCSR_P_SENTSTALL 0x0020
-#define MUSB_TXCSR_P_SENDSTALL 0x0010
-#define MUSB_TXCSR_P_UNDERRUN 0x0004
-
-/* TXCSR in Host mode */
-#define MUSB_TXCSR_H_WR_DATATOGGLE 0x0200
-#define MUSB_TXCSR_H_DATATOGGLE 0x0100
-#define MUSB_TXCSR_H_NAKTIMEOUT 0x0080
-#define MUSB_TXCSR_H_RXSTALL 0x0020
-#define MUSB_TXCSR_H_ERROR 0x0004
-#define MUSB_TXCSR_H_DATATOGGLE_SHIFT 8
-
-/* TXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
-#define MUSB_TXCSR_P_WZC_BITS \
- (MUSB_TXCSR_P_INCOMPTX | MUSB_TXCSR_P_SENTSTALL \
- | MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_FIFONOTEMPTY)
-#define MUSB_TXCSR_H_WZC_BITS \
- (MUSB_TXCSR_H_NAKTIMEOUT | MUSB_TXCSR_H_RXSTALL \
- | MUSB_TXCSR_H_ERROR | MUSB_TXCSR_FIFONOTEMPTY)
-
-/* RXCSR in Peripheral and Host mode */
-#define MUSB_RXCSR_AUTOCLEAR 0x8000
-#define MUSB_RXCSR_DMAENAB 0x2000
-#define MUSB_RXCSR_DISNYET 0x1000
-#define MUSB_RXCSR_PID_ERR 0x1000
-#define MUSB_RXCSR_DMAMODE 0x0800
-#define MUSB_RXCSR_INCOMPRX 0x0100
-#define MUSB_RXCSR_CLRDATATOG 0x0080
-#define MUSB_RXCSR_FLUSHFIFO 0x0010
-#define MUSB_RXCSR_DATAERROR 0x0008
-#define MUSB_RXCSR_FIFOFULL 0x0002
-#define MUSB_RXCSR_RXPKTRDY 0x0001
-
-/* RXCSR in Peripheral mode */
-#define MUSB_RXCSR_P_ISO 0x4000
-#define MUSB_RXCSR_P_SENTSTALL 0x0040
-#define MUSB_RXCSR_P_SENDSTALL 0x0020
-#define MUSB_RXCSR_P_OVERRUN 0x0004
-
-/* RXCSR in Host mode */
-#define MUSB_RXCSR_H_AUTOREQ 0x4000
-#define MUSB_RXCSR_H_WR_DATATOGGLE 0x0400
-#define MUSB_RXCSR_H_DATATOGGLE 0x0200
-#define MUSB_RXCSR_H_RXSTALL 0x0040
-#define MUSB_RXCSR_H_REQPKT 0x0020
-#define MUSB_RXCSR_H_ERROR 0x0004
-#define MUSB_S_RXCSR_H_DATATOGGLE 9
-
-/* RXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
-#define MUSB_RXCSR_P_WZC_BITS \
- (MUSB_RXCSR_P_SENTSTALL | MUSB_RXCSR_P_OVERRUN \
- | MUSB_RXCSR_RXPKTRDY)
-#define MUSB_RXCSR_H_WZC_BITS \
- (MUSB_RXCSR_H_RXSTALL | MUSB_RXCSR_H_ERROR \
- | MUSB_RXCSR_DATAERROR | MUSB_RXCSR_RXPKTRDY)
-
-/* HUBADDR */
-#define MUSB_HUBADDR_MULTI_TT 0x80
-
-/* Endpoint configuration information. Note: The value of endpoint fifo size
- * element should be either 8,16,32,64,128,256,512,1024,2048 or 4096. Other
- * values are not supported
- */
-struct musb_epinfo {
- u8 epnum; /* endpoint number */
- u8 epdir; /* endpoint direction */
- u16 epsize; /* endpoint FIFO size */
-};
-
-/*
- * Platform specific MUSB configuration. Any platform using the musb
- * functionality should create one instance of this structure in the
- * platform specific file.
- */
-struct musb_config {
- struct musb_regs *regs;
- u32 timeout;
- u8 musb_speed;
- u8 extvbus;
-};
-
-/* externally defined data */
-extern struct musb_config musb_cfg;
-extern struct musb_regs *musbr;
-
-/* exported functions */
-extern void musb_start(void);
-extern void musb_configure_ep(const struct musb_epinfo *epinfo, u8 cnt);
-extern void write_fifo(u8 ep, u32 length, void *fifo_data);
-extern void read_fifo(u8 ep, u32 length, void *fifo_data);
-
-static inline u8 musb_read_ulpi_buscontrol(struct musb_regs *musbr)
-{
- return readb(&musbr->ulpi_busctl);
-}
-static inline void musb_write_ulpi_buscontrol(struct musb_regs *musbr, u8 val)
-{
- writeb(val, &musbr->ulpi_busctl);
-}
-
-#endif /* __MUSB_HDRC_DEFS_H__ */
diff --git a/drivers/usb/musb/musb_debug.h b/drivers/usb/musb/musb_debug.h
deleted file mode 100644
index 2c5e192ab21..00000000000
--- a/drivers/usb/musb/musb_debug.h
+++ /dev/null
@@ -1,191 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright (c) 2009 Wind River Systems, Inc.
- * Tom Rix <Tom.Rix@windriver.com>
- */
-
-/* Define MUSB_DEBUG before including this file to get debug macros */
-#ifdef MUSB_DEBUG
-
-#define MUSB_FLAGS_PRINT(v, x, y) \
- if (((v) & MUSB_##x##_##y)) \
- serial_printf("\t\t"#y"\n")
-
-static inline void musb_print_pwr(u8 b)
-{
- serial_printf("\tpower 0x%2.2x\n", b);
- MUSB_FLAGS_PRINT(b, POWER, ISOUPDATE);
- MUSB_FLAGS_PRINT(b, POWER, SOFTCONN);
- MUSB_FLAGS_PRINT(b, POWER, HSENAB);
- MUSB_FLAGS_PRINT(b, POWER, HSMODE);
- MUSB_FLAGS_PRINT(b, POWER, RESET);
- MUSB_FLAGS_PRINT(b, POWER, RESUME);
- MUSB_FLAGS_PRINT(b, POWER, SUSPENDM);
- MUSB_FLAGS_PRINT(b, POWER, ENSUSPEND);
-}
-
-static inline void musb_print_csr0(u16 w)
-{
- serial_printf("\tcsr0 0x%4.4x\n", w);
- MUSB_FLAGS_PRINT(w, CSR0, FLUSHFIFO);
- MUSB_FLAGS_PRINT(w, CSR0_P, SVDSETUPEND);
- MUSB_FLAGS_PRINT(w, CSR0_P, SVDRXPKTRDY);
- MUSB_FLAGS_PRINT(w, CSR0_P, SENDSTALL);
- MUSB_FLAGS_PRINT(w, CSR0_P, SETUPEND);
- MUSB_FLAGS_PRINT(w, CSR0_P, DATAEND);
- MUSB_FLAGS_PRINT(w, CSR0_P, SENTSTALL);
- MUSB_FLAGS_PRINT(w, CSR0, TXPKTRDY);
- MUSB_FLAGS_PRINT(w, CSR0, RXPKTRDY);
-}
-
-static inline void musb_print_intrusb(u8 b)
-{
- serial_printf("\tintrusb 0x%2.2x\n", b);
- MUSB_FLAGS_PRINT(b, INTR, VBUSERROR);
- MUSB_FLAGS_PRINT(b, INTR, SESSREQ);
- MUSB_FLAGS_PRINT(b, INTR, DISCONNECT);
- MUSB_FLAGS_PRINT(b, INTR, CONNECT);
- MUSB_FLAGS_PRINT(b, INTR, SOF);
- MUSB_FLAGS_PRINT(b, INTR, RESUME);
- MUSB_FLAGS_PRINT(b, INTR, SUSPEND);
-
- if (b & MUSB_INTR_BABBLE)
- serial_printf("\t\tMUSB_INTR_RESET or MUSB_INTR_BABBLE\n");
-
-}
-
-static inline void musb_print_intrtx(u16 w)
-{
- serial_printf("\tintrtx 0x%4.4x\n", w);
-}
-
-static inline void musb_print_intrrx(u16 w)
-{
- serial_printf("\tintrx 0x%4.4x\n", w);
-}
-
-static inline void musb_print_devctl(u8 b)
-{
- serial_printf("\tdevctl 0x%2.2x\n", b);
- if (b & MUSB_DEVCTL_BDEVICE)
- serial_printf("\t\tB device\n");
- else
- serial_printf("\t\tA device\n");
- if (b & MUSB_DEVCTL_FSDEV)
- serial_printf("\t\tFast Device -(host mode)\n");
- if (b & MUSB_DEVCTL_LSDEV)
- serial_printf("\t\tSlow Device -(host mode)\n");
- if (b & MUSB_DEVCTL_HM)
- serial_printf("\t\tHost mode\n");
- else
- serial_printf("\t\tPeripherial mode\n");
- if (b & MUSB_DEVCTL_HR)
- serial_printf("\t\tHost request started(B device)\n");
- else
- serial_printf("\t\tHost request finished(B device)\n");
- if (b & MUSB_DEVCTL_BDEVICE) {
- if (b & MUSB_DEVCTL_SESSION)
- serial_printf("\t\tStart of session(B device)\n");
- else
- serial_printf("\t\tEnd of session(B device)\n");
- } else {
- if (b & MUSB_DEVCTL_SESSION)
- serial_printf("\t\tStart of session(A device)\n");
- else
- serial_printf("\t\tEnd of session(A device)\n");
- }
-}
-
-static inline void musb_print_config(u8 b)
-{
- serial_printf("\tconfig 0x%2.2x\n", b);
- if (b & MUSB_CONFIGDATA_MPRXE)
- serial_printf("\t\tAuto combine rx bulk packets\n");
- if (b & MUSB_CONFIGDATA_MPTXE)
- serial_printf("\t\tAuto split tx bulk packets\n");
- if (b & MUSB_CONFIGDATA_BIGENDIAN)
- serial_printf("\t\tBig Endian ordering\n");
- else
- serial_printf("\t\tLittle Endian ordering\n");
- if (b & MUSB_CONFIGDATA_HBRXE)
- serial_printf("\t\tHigh speed rx iso endpoint\n");
- if (b & MUSB_CONFIGDATA_HBTXE)
- serial_printf("\t\tHigh speed tx iso endpoint\n");
- if (b & MUSB_CONFIGDATA_DYNFIFO)
- serial_printf("\t\tDynamic fifo sizing\n");
- if (b & MUSB_CONFIGDATA_SOFTCONE)
- serial_printf("\t\tSoft Connect\n");
- if (b & MUSB_CONFIGDATA_UTMIDW)
- serial_printf("\t\t16 bit data width\n");
- else
- serial_printf("\t\t8 bit data width\n");
-}
-
-static inline void musb_print_rxmaxp(u16 w)
-{
- serial_printf("\trxmaxp 0x%4.4x\n", w);
-}
-
-static inline void musb_print_rxcsr(u16 w)
-{
- serial_printf("\trxcsr 0x%4.4x\n", w);
- MUSB_FLAGS_PRINT(w, RXCSR, AUTOCLEAR);
- MUSB_FLAGS_PRINT(w, RXCSR, DMAENAB);
- MUSB_FLAGS_PRINT(w, RXCSR, DISNYET);
- MUSB_FLAGS_PRINT(w, RXCSR, PID_ERR);
- MUSB_FLAGS_PRINT(w, RXCSR, DMAMODE);
- MUSB_FLAGS_PRINT(w, RXCSR, CLRDATATOG);
- MUSB_FLAGS_PRINT(w, RXCSR, FLUSHFIFO);
- MUSB_FLAGS_PRINT(w, RXCSR, DATAERROR);
- MUSB_FLAGS_PRINT(w, RXCSR, FIFOFULL);
- MUSB_FLAGS_PRINT(w, RXCSR, RXPKTRDY);
- MUSB_FLAGS_PRINT(w, RXCSR_P, SENTSTALL);
- MUSB_FLAGS_PRINT(w, RXCSR_P, SENDSTALL);
- MUSB_FLAGS_PRINT(w, RXCSR_P, OVERRUN);
-
- if (w & MUSB_RXCSR_P_ISO)
- serial_printf("\t\tiso mode\n");
- else
- serial_printf("\t\tbulk mode\n");
-
-}
-
-static inline void musb_print_txmaxp(u16 w)
-{
- serial_printf("\ttxmaxp 0x%4.4x\n", w);
-}
-
-static inline void musb_print_txcsr(u16 w)
-{
- serial_printf("\ttxcsr 0x%4.4x\n", w);
- MUSB_FLAGS_PRINT(w, TXCSR, TXPKTRDY);
- MUSB_FLAGS_PRINT(w, TXCSR, FIFONOTEMPTY);
- MUSB_FLAGS_PRINT(w, TXCSR, FLUSHFIFO);
- MUSB_FLAGS_PRINT(w, TXCSR, CLRDATATOG);
- MUSB_FLAGS_PRINT(w, TXCSR_P, UNDERRUN);
- MUSB_FLAGS_PRINT(w, TXCSR_P, SENTSTALL);
- MUSB_FLAGS_PRINT(w, TXCSR_P, SENDSTALL);
-
- if (w & MUSB_TXCSR_MODE)
- serial_printf("\t\tTX mode\n");
- else
- serial_printf("\t\tRX mode\n");
-}
-
-#else
-
-/* stubs */
-
-#define musb_print_pwr(b)
-#define musb_print_csr0(w)
-#define musb_print_intrusb(b)
-#define musb_print_intrtx(w)
-#define musb_print_intrrx(w)
-#define musb_print_devctl(b)
-#define musb_print_config(b)
-#define musb_print_rxmaxp(w)
-#define musb_print_rxcsr(w)
-#define musb_print_txmaxp(w)
-#define musb_print_txcsr(w)
-
-#endif /* MUSB_DEBUG */
diff --git a/drivers/usb/musb/musb_hcd.c b/drivers/usb/musb/musb_hcd.c
deleted file mode 100644
index c95c6a48281..00000000000
--- a/drivers/usb/musb/musb_hcd.c
+++ /dev/null
@@ -1,1161 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Mentor USB OTG Core host controller driver.
- *
- * Copyright (c) 2008 Texas Instruments
- *
- * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
- */
-
-#include <log.h>
-#include <usb.h>
-#include <linux/delay.h>
-#include "musb_hcd.h"
-
-/* MSC control transfers */
-#define USB_MSC_BBB_RESET 0xFF
-#define USB_MSC_BBB_GET_MAX_LUN 0xFE
-
-/* Endpoint configuration information */
-static const struct musb_epinfo epinfo[3] = {
- {MUSB_BULK_EP, 1, 512}, /* EP1 - Bluk Out - 512 Bytes */
- {MUSB_BULK_EP, 0, 512}, /* EP1 - Bluk In - 512 Bytes */
- {MUSB_INTR_EP, 0, 64} /* EP2 - Interrupt IN - 64 Bytes */
-};
-
-/* --- Virtual Root Hub ---------------------------------------------------- */
-#ifdef MUSB_NO_MULTIPOINT
-static int rh_devnum;
-static u32 port_status;
-
-#include <usbroothubdes.h>
-
-#endif
-
-/*
- * This function writes the data toggle value.
- */
-static void write_toggle(struct usb_device *dev, u8 ep, u8 dir_out)
-{
- u16 toggle = usb_gettoggle(dev, ep, dir_out);
- u16 csr;
-
- if (dir_out) {
- csr = readw(&musbr->txcsr);
- if (!toggle) {
- if (csr & MUSB_TXCSR_MODE)
- csr = MUSB_TXCSR_CLRDATATOG;
- else
- csr = 0;
- writew(csr, &musbr->txcsr);
- } else {
- csr |= MUSB_TXCSR_H_WR_DATATOGGLE;
- writew(csr, &musbr->txcsr);
- csr |= (toggle << MUSB_TXCSR_H_DATATOGGLE_SHIFT);
- writew(csr, &musbr->txcsr);
- }
- } else {
- if (!toggle) {
- csr = readw(&musbr->txcsr);
- if (csr & MUSB_TXCSR_MODE)
- csr = MUSB_RXCSR_CLRDATATOG;
- else
- csr = 0;
- writew(csr, &musbr->rxcsr);
- } else {
- csr = readw(&musbr->rxcsr);
- csr |= MUSB_RXCSR_H_WR_DATATOGGLE;
- writew(csr, &musbr->rxcsr);
- csr |= (toggle << MUSB_S_RXCSR_H_DATATOGGLE);
- writew(csr, &musbr->rxcsr);
- }
- }
-}
-
-/*
- * This function checks if RxStall has occurred on the endpoint. If a RxStall
- * has occurred, the RxStall is cleared and 1 is returned. If RxStall has
- * not occurred, 0 is returned.
- */
-static u8 check_stall(u8 ep, u8 dir_out)
-{
- u16 csr;
-
- /* For endpoint 0 */
- if (!ep) {
- csr = readw(&musbr->txcsr);
- if (csr & MUSB_CSR0_H_RXSTALL) {
- csr &= ~MUSB_CSR0_H_RXSTALL;
- writew(csr, &musbr->txcsr);
- return 1;
- }
- } else { /* For non-ep0 */
- if (dir_out) { /* is it tx ep */
- csr = readw(&musbr->txcsr);
- if (csr & MUSB_TXCSR_H_RXSTALL) {
- csr &= ~MUSB_TXCSR_H_RXSTALL;
- writew(csr, &musbr->txcsr);
- return 1;
- }
- } else { /* is it rx ep */
- csr = readw(&musbr->rxcsr);
- if (csr & MUSB_RXCSR_H_RXSTALL) {
- csr &= ~MUSB_RXCSR_H_RXSTALL;
- writew(csr, &musbr->rxcsr);
- return 1;
- }
- }
- }
- return 0;
-}
-
-/*
- * waits until ep0 is ready. Returns 0 if ep is ready, -1 for timeout
- * error and -2 for stall.
- */
-static int wait_until_ep0_ready(struct usb_device *dev, u32 bit_mask)
-{
- u16 csr;
- int result = 1;
- int timeout = MUSB_TIMEOUT;
-
- while (result > 0) {
- csr = readw(&musbr->txcsr);
- if (csr & MUSB_CSR0_H_ERROR) {
- csr &= ~MUSB_CSR0_H_ERROR;
- writew(csr, &musbr->txcsr);
- dev->status = USB_ST_CRC_ERR;
- result = -1;
- break;
- }
-
- switch (bit_mask) {
- case MUSB_CSR0_TXPKTRDY:
- if (!(csr & MUSB_CSR0_TXPKTRDY)) {
- if (check_stall(MUSB_CONTROL_EP, 0)) {
- dev->status = USB_ST_STALLED;
- result = -2;
- } else
- result = 0;
- }
- break;
-
- case MUSB_CSR0_RXPKTRDY:
- if (check_stall(MUSB_CONTROL_EP, 0)) {
- dev->status = USB_ST_STALLED;
- result = -2;
- } else
- if (csr & MUSB_CSR0_RXPKTRDY)
- result = 0;
- break;
-
- case MUSB_CSR0_H_REQPKT:
- if (!(csr & MUSB_CSR0_H_REQPKT)) {
- if (check_stall(MUSB_CONTROL_EP, 0)) {
- dev->status = USB_ST_STALLED;
- result = -2;
- } else
- result = 0;
- }
- break;
- }
-
- /* Check the timeout */
- if (--timeout)
- udelay(1);
- else {
- dev->status = USB_ST_CRC_ERR;
- result = -1;
- break;
- }
- }
-
- return result;
-}
-
-/*
- * waits until tx ep is ready. Returns 1 when ep is ready and 0 on error.
- */
-static int wait_until_txep_ready(struct usb_device *dev, u8 ep)
-{
- u16 csr;
- int timeout = MUSB_TIMEOUT;
-
- do {
- if (check_stall(ep, 1)) {
- dev->status = USB_ST_STALLED;
- return 0;
- }
-
- csr = readw(&musbr->txcsr);
- if (csr & MUSB_TXCSR_H_ERROR) {
- dev->status = USB_ST_CRC_ERR;
- return 0;
- }
-
- /* Check the timeout */
- if (--timeout)
- udelay(1);
- else {
- dev->status = USB_ST_CRC_ERR;
- return -1;
- }
-
- } while (csr & MUSB_TXCSR_TXPKTRDY);
- return 1;
-}
-
-/*
- * waits until rx ep is ready. Returns 1 when ep is ready and 0 on error.
- */
-static int wait_until_rxep_ready(struct usb_device *dev, u8 ep)
-{
- u16 csr;
- int timeout = MUSB_TIMEOUT;
-
- do {
- if (check_stall(ep, 0)) {
- dev->status = USB_ST_STALLED;
- return 0;
- }
-
- csr = readw(&musbr->rxcsr);
- if (csr & MUSB_RXCSR_H_ERROR) {
- dev->status = USB_ST_CRC_ERR;
- return 0;
- }
-
- /* Check the timeout */
- if (--timeout)
- udelay(1);
- else {
- dev->status = USB_ST_CRC_ERR;
- return -1;
- }
-
- } while (!(csr & MUSB_RXCSR_RXPKTRDY));
- return 1;
-}
-
-/*
- * This function performs the setup phase of the control transfer
- */
-static int ctrlreq_setup_phase(struct usb_device *dev, struct devrequest *setup)
-{
- int result;
- u16 csr;
-
- /* write the control request to ep0 fifo */
- write_fifo(MUSB_CONTROL_EP, sizeof(struct devrequest), (void *)setup);
-
- /* enable transfer of setup packet */
- csr = readw(&musbr->txcsr);
- csr |= (MUSB_CSR0_TXPKTRDY|MUSB_CSR0_H_SETUPPKT);
- writew(csr, &musbr->txcsr);
-
- /* wait until the setup packet is transmitted */
- result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
- dev->act_len = 0;
- return result;
-}
-
-/*
- * This function handles the control transfer in data phase
- */
-static int ctrlreq_in_data_phase(struct usb_device *dev, u32 len, void *buffer)
-{
- u16 csr;
- u32 rxlen = 0;
- u32 nextlen = 0;
- u8 maxpktsize = (1 << dev->maxpacketsize) * 8;
- u8 *rxbuff = (u8 *)buffer;
- u8 rxedlength;
- int result;
-
- while (rxlen < len) {
- /* Determine the next read length */
- nextlen = ((len-rxlen) > maxpktsize) ? maxpktsize : (len-rxlen);
-
- /* Set the ReqPkt bit */
- csr = readw(&musbr->txcsr);
- writew(csr | MUSB_CSR0_H_REQPKT, &musbr->txcsr);
- result = wait_until_ep0_ready(dev, MUSB_CSR0_RXPKTRDY);
- if (result < 0)
- return result;
-
- /* Actual number of bytes received by usb */
- rxedlength = readb(&musbr->rxcount);
-
- /* Read the data from the RxFIFO */
- read_fifo(MUSB_CONTROL_EP, rxedlength, &rxbuff[rxlen]);
-
- /* Clear the RxPktRdy Bit */
- csr = readw(&musbr->txcsr);
- csr &= ~MUSB_CSR0_RXPKTRDY;
- writew(csr, &musbr->txcsr);
-
- /* short packet? */
- if (rxedlength != nextlen) {
- dev->act_len += rxedlength;
- break;
- }
- rxlen += nextlen;
- dev->act_len = rxlen;
- }
- return 0;
-}
-
-/*
- * This function handles the control transfer out data phase
- */
-static int ctrlreq_out_data_phase(struct usb_device *dev, u32 len, void *buffer)
-{
- u16 csr;
- u32 txlen = 0;
- u32 nextlen = 0;
- u8 maxpktsize = (1 << dev->maxpacketsize) * 8;
- u8 *txbuff = (u8 *)buffer;
- int result = 0;
-
- while (txlen < len) {
- /* Determine the next write length */
- nextlen = ((len-txlen) > maxpktsize) ? maxpktsize : (len-txlen);
-
- /* Load the data to send in FIFO */
- write_fifo(MUSB_CONTROL_EP, txlen, &txbuff[txlen]);
-
- /* Set TXPKTRDY bit */
- csr = readw(&musbr->txcsr);
-
- csr |= MUSB_CSR0_TXPKTRDY;
- csr |= MUSB_CSR0_H_DIS_PING;
- writew(csr, &musbr->txcsr);
- result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
- if (result < 0)
- break;
-
- txlen += nextlen;
- dev->act_len = txlen;
- }
- return result;
-}
-
-/*
- * This function handles the control transfer out status phase
- */
-static int ctrlreq_out_status_phase(struct usb_device *dev)
-{
- u16 csr;
- int result;
-
- /* Set the StatusPkt bit */
- csr = readw(&musbr->txcsr);
- csr |= (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_H_STATUSPKT);
- csr |= MUSB_CSR0_H_DIS_PING;
- writew(csr, &musbr->txcsr);
-
- /* Wait until TXPKTRDY bit is cleared */
- result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
- return result;
-}
-
-/*
- * This function handles the control transfer in status phase
- */
-static int ctrlreq_in_status_phase(struct usb_device *dev)
-{
- u16 csr;
- int result;
-
- /* Set the StatusPkt bit and ReqPkt bit */
- csr = MUSB_CSR0_H_REQPKT | MUSB_CSR0_H_STATUSPKT;
- csr |= MUSB_CSR0_H_DIS_PING;
- writew(csr, &musbr->txcsr);
- result = wait_until_ep0_ready(dev, MUSB_CSR0_H_REQPKT);
-
- /* clear StatusPkt bit and RxPktRdy bit */
- csr = readw(&musbr->txcsr);
- csr &= ~(MUSB_CSR0_RXPKTRDY | MUSB_CSR0_H_STATUSPKT);
- writew(csr, &musbr->txcsr);
- return result;
-}
-
-/*
- * determines the speed of the device (High/Full/Slow)
- */
-static u8 get_dev_speed(struct usb_device *dev)
-{
- return (dev->speed == USB_SPEED_HIGH) ? MUSB_TYPE_SPEED_HIGH :
- ((dev->speed == USB_SPEED_LOW) ? MUSB_TYPE_SPEED_LOW :
- MUSB_TYPE_SPEED_FULL);
-}
-
-/*
- * configure the hub address and the port address.
- */
-static void config_hub_port(struct usb_device *dev, u8 ep)
-{
- u8 chid;
- u8 hub;
-
- /* Find out the nearest parent which is high speed */
- while (dev->parent->parent != NULL)
- if (get_dev_speed(dev->parent) != MUSB_TYPE_SPEED_HIGH)
- dev = dev->parent;
- else
- break;
-
- /* determine the port address at that hub */
- hub = dev->parent->devnum;
- for (chid = 0; chid < USB_MAXCHILDREN; chid++)
- if (dev->parent->children[chid] == dev)
- break;
-
-#ifndef MUSB_NO_MULTIPOINT
- /* configure the hub address and the port address */
- writeb(hub, &musbr->tar[ep].txhubaddr);
- writeb((chid + 1), &musbr->tar[ep].txhubport);
- writeb(hub, &musbr->tar[ep].rxhubaddr);
- writeb((chid + 1), &musbr->tar[ep].rxhubport);
-#endif
-}
-
-#ifdef MUSB_NO_MULTIPOINT
-
-static void musb_port_reset(int do_reset)
-{
- u8 power = readb(&musbr->power);
-
- if (do_reset) {
- power &= 0xf0;
- writeb(power | MUSB_POWER_RESET, &musbr->power);
- port_status |= USB_PORT_STAT_RESET;
- port_status &= ~USB_PORT_STAT_ENABLE;
- udelay(30000);
- } else {
- writeb(power & ~MUSB_POWER_RESET, &musbr->power);
-
- power = readb(&musbr->power);
- if (power & MUSB_POWER_HSMODE)
- port_status |= USB_PORT_STAT_HIGH_SPEED;
-
- port_status &= ~(USB_PORT_STAT_RESET | (USB_PORT_STAT_C_CONNECTION << 16));
- port_status |= USB_PORT_STAT_ENABLE
- | (USB_PORT_STAT_C_RESET << 16)
- | (USB_PORT_STAT_C_ENABLE << 16);
- }
-}
-
-/*
- * root hub control
- */
-static int musb_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
- void *buffer, int transfer_len,
- struct devrequest *cmd)
-{
- int leni = transfer_len;
- int len = 0;
- int stat = 0;
- u32 datab[4];
- const u8 *data_buf = (u8 *) datab;
- u16 bmRType_bReq;
- u16 wValue;
- u16 wIndex;
- u16 wLength;
- u16 int_usb;
-
- if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
- debug("Root-Hub submit IRQ: NOT implemented\n");
- return 0;
- }
-
- bmRType_bReq = cmd->requesttype | (cmd->request << 8);
- wValue = swap_16(cmd->value);
- wIndex = swap_16(cmd->index);
- wLength = swap_16(cmd->length);
-
- debug("--- HUB ----------------------------------------\n");
- debug("submit rh urb, req=%x val=%#x index=%#x len=%d\n",
- bmRType_bReq, wValue, wIndex, wLength);
- debug("------------------------------------------------\n");
-
- switch (bmRType_bReq) {
- case RH_GET_STATUS:
- debug("RH_GET_STATUS\n");
-
- *(__u16 *) data_buf = swap_16(1);
- len = 2;
- break;
-
- case RH_GET_STATUS | RH_INTERFACE:
- debug("RH_GET_STATUS | RH_INTERFACE\n");
-
- *(__u16 *) data_buf = swap_16(0);
- len = 2;
- break;
-
- case RH_GET_STATUS | RH_ENDPOINT:
- debug("RH_GET_STATUS | RH_ENDPOINT\n");
-
- *(__u16 *) data_buf = swap_16(0);
- len = 2;
- break;
-
- case RH_GET_STATUS | RH_CLASS:
- debug("RH_GET_STATUS | RH_CLASS\n");
-
- *(__u32 *) data_buf = swap_32(0);
- len = 4;
- break;
-
- case RH_GET_STATUS | RH_OTHER | RH_CLASS:
- debug("RH_GET_STATUS | RH_OTHER | RH_CLASS\n");
-
- int_usb = readw(&musbr->intrusb);
- if (int_usb & MUSB_INTR_CONNECT) {
- port_status |= USB_PORT_STAT_CONNECTION
- | (USB_PORT_STAT_C_CONNECTION << 16);
- port_status |= USB_PORT_STAT_HIGH_SPEED
- | USB_PORT_STAT_ENABLE;
- }
-
- if (port_status & USB_PORT_STAT_RESET)
- musb_port_reset(0);
-
- *(__u32 *) data_buf = swap_32(port_status);
- len = 4;
- break;
-
- case RH_CLEAR_FEATURE | RH_ENDPOINT:
- debug("RH_CLEAR_FEATURE | RH_ENDPOINT\n");
-
- switch (wValue) {
- case RH_ENDPOINT_STALL:
- debug("C_HUB_ENDPOINT_STALL\n");
- len = 0;
- break;
- }
- port_status &= ~(1 << wValue);
- break;
-
- case RH_CLEAR_FEATURE | RH_CLASS:
- debug("RH_CLEAR_FEATURE | RH_CLASS\n");
-
- switch (wValue) {
- case RH_C_HUB_LOCAL_POWER:
- debug("C_HUB_LOCAL_POWER\n");
- len = 0;
- break;
-
- case RH_C_HUB_OVER_CURRENT:
- debug("C_HUB_OVER_CURRENT\n");
- len = 0;
- break;
- }
- port_status &= ~(1 << wValue);
- break;
-
- case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
- debug("RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS\n");
-
- switch (wValue) {
- case RH_PORT_ENABLE:
- len = 0;
- break;
-
- case RH_PORT_SUSPEND:
- len = 0;
- break;
-
- case RH_PORT_POWER:
- len = 0;
- break;
-
- case RH_C_PORT_CONNECTION:
- len = 0;
- break;
-
- case RH_C_PORT_ENABLE:
- len = 0;
- break;
-
- case RH_C_PORT_SUSPEND:
- len = 0;
- break;
-
- case RH_C_PORT_OVER_CURRENT:
- len = 0;
- break;
-
- case RH_C_PORT_RESET:
- len = 0;
- break;
-
- default:
- debug("invalid wValue\n");
- stat = USB_ST_STALLED;
- }
-
- port_status &= ~(1 << wValue);
- break;
-
- case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
- debug("RH_SET_FEATURE | RH_OTHER | RH_CLASS\n");
-
- switch (wValue) {
- case RH_PORT_SUSPEND:
- len = 0;
- break;
-
- case RH_PORT_RESET:
- musb_port_reset(1);
- len = 0;
- break;
-
- case RH_PORT_POWER:
- len = 0;
- break;
-
- case RH_PORT_ENABLE:
- len = 0;
- break;
-
- default:
- debug("invalid wValue\n");
- stat = USB_ST_STALLED;
- }
-
- port_status |= 1 << wValue;
- break;
-
- case RH_SET_ADDRESS:
- debug("RH_SET_ADDRESS\n");
-
- rh_devnum = wValue;
- len = 0;
- break;
-
- case RH_GET_DESCRIPTOR:
- debug("RH_GET_DESCRIPTOR: %x, %d\n", wValue, wLength);
-
- switch (wValue) {
- case (USB_DT_DEVICE << 8): /* device descriptor */
- len = min_t(unsigned int,
- leni, min_t(unsigned int,
- sizeof(root_hub_dev_des),
- wLength));
- data_buf = root_hub_dev_des;
- break;
-
- case (USB_DT_CONFIG << 8): /* configuration descriptor */
- len = min_t(unsigned int,
- leni, min_t(unsigned int,
- sizeof(root_hub_config_des),
- wLength));
- data_buf = root_hub_config_des;
- break;
-
- case ((USB_DT_STRING << 8) | 0x00): /* string 0 descriptors */
- len = min_t(unsigned int,
- leni, min_t(unsigned int,
- sizeof(root_hub_str_index0),
- wLength));
- data_buf = root_hub_str_index0;
- break;
-
- case ((USB_DT_STRING << 8) | 0x01): /* string 1 descriptors */
- len = min_t(unsigned int,
- leni, min_t(unsigned int,
- sizeof(root_hub_str_index1),
- wLength));
- data_buf = root_hub_str_index1;
- break;
-
- default:
- debug("invalid wValue\n");
- stat = USB_ST_STALLED;
- }
-
- break;
-
- case RH_GET_DESCRIPTOR | RH_CLASS: {
- u8 *_data_buf = (u8 *) datab;
- debug("RH_GET_DESCRIPTOR | RH_CLASS\n");
-
- _data_buf[0] = 0x09; /* min length; */
- _data_buf[1] = 0x29;
- _data_buf[2] = 0x1; /* 1 port */
- _data_buf[3] = 0x01; /* per-port power switching */
- _data_buf[3] |= 0x10; /* no overcurrent reporting */
-
- /* Corresponds to data_buf[4-7] */
- _data_buf[4] = 0;
- _data_buf[5] = 5;
- _data_buf[6] = 0;
- _data_buf[7] = 0x02;
- _data_buf[8] = 0xff;
-
- len = min_t(unsigned int, leni,
- min_t(unsigned int, data_buf[0], wLength));
- break;
- }
-
- case RH_GET_CONFIGURATION:
- debug("RH_GET_CONFIGURATION\n");
-
- *(__u8 *) data_buf = 0x01;
- len = 1;
- break;
-
- case RH_SET_CONFIGURATION:
- debug("RH_SET_CONFIGURATION\n");
-
- len = 0;
- break;
-
- default:
- debug("*** *** *** unsupported root hub command *** *** ***\n");
- stat = USB_ST_STALLED;
- }
-
- len = min_t(int, len, leni);
- if (buffer != data_buf)
- memcpy(buffer, data_buf, len);
-
- dev->act_len = len;
- dev->status = stat;
- debug("dev act_len %d, status %lu\n", dev->act_len, dev->status);
-
- return stat;
-}
-
-static void musb_rh_init(void)
-{
- rh_devnum = 0;
- port_status = 0;
-}
-
-#else
-
-static void musb_rh_init(void) {}
-
-#endif
-
-/*
- * do a control transfer
- */
-int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int len, struct devrequest *setup)
-{
- int devnum = usb_pipedevice(pipe);
- u8 devspeed;
-
-#ifdef MUSB_NO_MULTIPOINT
- /* Control message is for the HUB? */
- if (devnum == rh_devnum) {
- int stat = musb_submit_rh_msg(dev, pipe, buffer, len, setup);
- if (stat)
- return stat;
- }
-#endif
-
- /* select control endpoint */
- writeb(MUSB_CONTROL_EP, &musbr->index);
- readw(&musbr->txcsr);
-
-#ifndef MUSB_NO_MULTIPOINT
- /* target addr and (for multipoint) hub addr/port */
- writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].txfuncaddr);
- writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].rxfuncaddr);
-#endif
-
- /* configure the hub address and the port number as required */
- devspeed = get_dev_speed(dev);
- if ((musb_ishighspeed()) && (dev->parent != NULL) &&
- (devspeed != MUSB_TYPE_SPEED_HIGH)) {
- config_hub_port(dev, MUSB_CONTROL_EP);
- writeb(devspeed << 6, &musbr->txtype);
- } else {
- writeb(musb_cfg.musb_speed << 6, &musbr->txtype);
-#ifndef MUSB_NO_MULTIPOINT
- writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubaddr);
- writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubport);
- writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubaddr);
- writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubport);
-#endif
- }
-
- /* Control transfer setup phase */
- if (ctrlreq_setup_phase(dev, setup) < 0)
- return 0;
-
- switch (setup->request) {
- case USB_REQ_GET_DESCRIPTOR:
- case USB_REQ_GET_CONFIGURATION:
- case USB_REQ_GET_INTERFACE:
- case USB_REQ_GET_STATUS:
- case USB_MSC_BBB_GET_MAX_LUN:
- /* control transfer in-data-phase */
- if (ctrlreq_in_data_phase(dev, len, buffer) < 0)
- return 0;
- /* control transfer out-status-phase */
- if (ctrlreq_out_status_phase(dev) < 0)
- return 0;
- break;
-
- case USB_REQ_SET_ADDRESS:
- case USB_REQ_SET_CONFIGURATION:
- case USB_REQ_SET_FEATURE:
- case USB_REQ_SET_INTERFACE:
- case USB_REQ_CLEAR_FEATURE:
- case USB_MSC_BBB_RESET:
- /* control transfer in status phase */
- if (ctrlreq_in_status_phase(dev) < 0)
- return 0;
- break;
-
- case USB_REQ_SET_DESCRIPTOR:
- /* control transfer out data phase */
- if (ctrlreq_out_data_phase(dev, len, buffer) < 0)
- return 0;
- /* control transfer in status phase */
- if (ctrlreq_in_status_phase(dev) < 0)
- return 0;
- break;
-
- default:
- /* unhandled control transfer */
- return -1;
- }
-
- dev->status = 0;
- dev->act_len = len;
-
-#ifdef MUSB_NO_MULTIPOINT
- /* Set device address to USB_FADDR register */
- if (setup->request == USB_REQ_SET_ADDRESS)
- writeb(dev->devnum, &musbr->faddr);
-#endif
-
- return len;
-}
-
-/*
- * do a bulk transfer
- */
-int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
- void *buffer, int len)
-{
- int dir_out = usb_pipeout(pipe);
- int ep = usb_pipeendpoint(pipe);
-#ifndef MUSB_NO_MULTIPOINT
- int devnum = usb_pipedevice(pipe);
-#endif
- u8 type;
- u16 csr;
- u32 txlen = 0;
- u32 nextlen = 0;
- u8 devspeed;
-
- /* select bulk endpoint */
- writeb(MUSB_BULK_EP, &musbr->index);
-
-#ifndef MUSB_NO_MULTIPOINT
- /* write the address of the device */
- if (dir_out)
- writeb(devnum, &musbr->tar[MUSB_BULK_EP].txfuncaddr);
- else
- writeb(devnum, &musbr->tar[MUSB_BULK_EP].rxfuncaddr);
-#endif
-
- /* configure the hub address and the port number as required */
- devspeed = get_dev_speed(dev);
- if ((musb_ishighspeed()) && (dev->parent != NULL) &&
- (devspeed != MUSB_TYPE_SPEED_HIGH)) {
- /*
- * MUSB is in high speed and the destination device is full
- * speed device. So configure the hub address and port
- * address registers.
- */
- config_hub_port(dev, MUSB_BULK_EP);
- } else {
-#ifndef MUSB_NO_MULTIPOINT
- if (dir_out) {
- writeb(0, &musbr->tar[MUSB_BULK_EP].txhubaddr);
- writeb(0, &musbr->tar[MUSB_BULK_EP].txhubport);
- } else {
- writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubaddr);
- writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubport);
- }
-#endif
- devspeed = musb_cfg.musb_speed;
- }
-
- /* Write the saved toggle bit value */
- write_toggle(dev, ep, dir_out);
-
- if (dir_out) { /* bulk-out transfer */
- /* Program the TxType register */
- type = (devspeed << MUSB_TYPE_SPEED_SHIFT) |
- (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) |
- (ep & MUSB_TYPE_REMOTE_END);
- writeb(type, &musbr->txtype);
-
- /* Write maximum packet size to the TxMaxp register */
- writew(dev->epmaxpacketout[ep], &musbr->txmaxp);
- while (txlen < len) {
- nextlen = ((len-txlen) < dev->epmaxpacketout[ep]) ?
- (len-txlen) : dev->epmaxpacketout[ep];
-
- /* Write the data to the FIFO */
- write_fifo(MUSB_BULK_EP, nextlen,
- (void *)(((u8 *)buffer) + txlen));
-
- /* Set the TxPktRdy bit */
- csr = readw(&musbr->txcsr);
- writew(csr | MUSB_TXCSR_TXPKTRDY, &musbr->txcsr);
-
- /* Wait until the TxPktRdy bit is cleared */
- if (wait_until_txep_ready(dev, MUSB_BULK_EP) != 1) {
- readw(&musbr->txcsr);
- usb_settoggle(dev, ep, dir_out,
- (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1);
- dev->act_len = txlen;
- return 0;
- }
- txlen += nextlen;
- }
-
- /* Keep a copy of the data toggle bit */
- csr = readw(&musbr->txcsr);
- usb_settoggle(dev, ep, dir_out,
- (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1);
- } else { /* bulk-in transfer */
- /* Write the saved toggle bit value */
- write_toggle(dev, ep, dir_out);
-
- /* Program the RxType register */
- type = (devspeed << MUSB_TYPE_SPEED_SHIFT) |
- (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) |
- (ep & MUSB_TYPE_REMOTE_END);
- writeb(type, &musbr->rxtype);
-
- /* Write the maximum packet size to the RxMaxp register */
- writew(dev->epmaxpacketin[ep], &musbr->rxmaxp);
- while (txlen < len) {
- nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ?
- (len-txlen) : dev->epmaxpacketin[ep];
-
- /* Set the ReqPkt bit */
- csr = readw(&musbr->rxcsr);
- writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr);
-
- /* Wait until the RxPktRdy bit is set */
- if (wait_until_rxep_ready(dev, MUSB_BULK_EP) != 1) {
- csr = readw(&musbr->rxcsr);
- usb_settoggle(dev, ep, dir_out,
- (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
- csr &= ~MUSB_RXCSR_RXPKTRDY;
- writew(csr, &musbr->rxcsr);
- dev->act_len = txlen;
- return 0;
- }
-
- /* Read the data from the FIFO */
- read_fifo(MUSB_BULK_EP, nextlen,
- (void *)(((u8 *)buffer) + txlen));
-
- /* Clear the RxPktRdy bit */
- csr = readw(&musbr->rxcsr);
- csr &= ~MUSB_RXCSR_RXPKTRDY;
- writew(csr, &musbr->rxcsr);
- txlen += nextlen;
- }
-
- /* Keep a copy of the data toggle bit */
- csr = readw(&musbr->rxcsr);
- usb_settoggle(dev, ep, dir_out,
- (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
- }
-
- /* bulk transfer is complete */
- dev->status = 0;
- dev->act_len = len;
- return 0;
-}
-
-/*
- * This function initializes the usb controller module.
- */
-int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
-{
- u8 power;
- u32 timeout;
-
- musb_rh_init();
-
- if (musb_platform_init() == -1)
- return -1;
-
- /* Configure all the endpoint FIFO's and start usb controller */
- musbr = musb_cfg.regs;
- musb_configure_ep(&epinfo[0], ARRAY_SIZE(epinfo));
- musb_start();
-
- /*
- * Wait until musb is enabled in host mode with a timeout. There
- * should be a usb device connected.
- */
- timeout = musb_cfg.timeout;
- while (--timeout)
- if (readb(&musbr->devctl) & MUSB_DEVCTL_HM)
- break;
-
- /* if musb core is not in host mode, then return */
- if (!timeout)
- return -1;
-
- /* start usb bus reset */
- power = readb(&musbr->power);
- writeb(power | MUSB_POWER_RESET, &musbr->power);
-
- /* After initiating a usb reset, wait for about 20ms to 30ms */
- udelay(30000);
-
- /* stop usb bus reset */
- power = readb(&musbr->power);
- power &= ~MUSB_POWER_RESET;
- writeb(power, &musbr->power);
-
- /* Determine if the connected device is a high/full/low speed device */
- musb_cfg.musb_speed = (readb(&musbr->power) & MUSB_POWER_HSMODE) ?
- MUSB_TYPE_SPEED_HIGH :
- ((readb(&musbr->devctl) & MUSB_DEVCTL_FSDEV) ?
- MUSB_TYPE_SPEED_FULL : MUSB_TYPE_SPEED_LOW);
- return 0;
-}
-
-/*
- * This function stops the operation of the davinci usb module.
- */
-int usb_lowlevel_stop(int index)
-{
- /* Reset the USB module */
- musb_platform_deinit();
- writeb(0, &musbr->devctl);
- return 0;
-}
-
-/*
- * This function supports usb interrupt transfers. Currently, usb interrupt
- * transfers are not supported.
- */
-int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int len, int interval, bool nonblock)
-{
- int dir_out = usb_pipeout(pipe);
- int ep = usb_pipeendpoint(pipe);
-#ifndef MUSB_NO_MULTIPOINT
- int devnum = usb_pipedevice(pipe);
-#endif
- u8 type;
- u16 csr;
- u32 txlen = 0;
- u32 nextlen = 0;
- u8 devspeed;
-
- /* select interrupt endpoint */
- writeb(MUSB_INTR_EP, &musbr->index);
-
-#ifndef MUSB_NO_MULTIPOINT
- /* write the address of the device */
- if (dir_out)
- writeb(devnum, &musbr->tar[MUSB_INTR_EP].txfuncaddr);
- else
- writeb(devnum, &musbr->tar[MUSB_INTR_EP].rxfuncaddr);
-#endif
-
- /* configure the hub address and the port number as required */
- devspeed = get_dev_speed(dev);
- if ((musb_ishighspeed()) && (dev->parent != NULL) &&
- (devspeed != MUSB_TYPE_SPEED_HIGH)) {
- /*
- * MUSB is in high speed and the destination device is full
- * speed device. So configure the hub address and port
- * address registers.
- */
- config_hub_port(dev, MUSB_INTR_EP);
- } else {
-#ifndef MUSB_NO_MULTIPOINT
- if (dir_out) {
- writeb(0, &musbr->tar[MUSB_INTR_EP].txhubaddr);
- writeb(0, &musbr->tar[MUSB_INTR_EP].txhubport);
- } else {
- writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubaddr);
- writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubport);
- }
-#endif
- devspeed = musb_cfg.musb_speed;
- }
-
- /* Write the saved toggle bit value */
- write_toggle(dev, ep, dir_out);
-
- if (!dir_out) { /* intrrupt-in transfer */
- /* Write the saved toggle bit value */
- write_toggle(dev, ep, dir_out);
- writeb(interval, &musbr->rxinterval);
-
- /* Program the RxType register */
- type = (devspeed << MUSB_TYPE_SPEED_SHIFT) |
- (MUSB_TYPE_PROTO_INTR << MUSB_TYPE_PROTO_SHIFT) |
- (ep & MUSB_TYPE_REMOTE_END);
- writeb(type, &musbr->rxtype);
-
- /* Write the maximum packet size to the RxMaxp register */
- writew(dev->epmaxpacketin[ep], &musbr->rxmaxp);
-
- while (txlen < len) {
- nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ?
- (len-txlen) : dev->epmaxpacketin[ep];
-
- /* Set the ReqPkt bit */
- csr = readw(&musbr->rxcsr);
- writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr);
-
- /* Wait until the RxPktRdy bit is set */
- if (wait_until_rxep_ready(dev, MUSB_INTR_EP) != 1) {
- csr = readw(&musbr->rxcsr);
- usb_settoggle(dev, ep, dir_out,
- (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
- csr &= ~MUSB_RXCSR_RXPKTRDY;
- writew(csr, &musbr->rxcsr);
- dev->act_len = txlen;
- return 0;
- }
-
- /* Read the data from the FIFO */
- read_fifo(MUSB_INTR_EP, nextlen,
- (void *)(((u8 *)buffer) + txlen));
-
- /* Clear the RxPktRdy bit */
- csr = readw(&musbr->rxcsr);
- csr &= ~MUSB_RXCSR_RXPKTRDY;
- writew(csr, &musbr->rxcsr);
- txlen += nextlen;
- }
-
- /* Keep a copy of the data toggle bit */
- csr = readw(&musbr->rxcsr);
- usb_settoggle(dev, ep, dir_out,
- (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
- }
-
- /* interrupt transfer is complete */
- dev->irq_status = 0;
- dev->irq_act_len = len;
- dev->irq_handle(dev);
- dev->status = 0;
- dev->act_len = len;
- return 0;
-}
diff --git a/drivers/usb/musb/musb_hcd.h b/drivers/usb/musb/musb_hcd.h
deleted file mode 100644
index a492e99ef9d..00000000000
--- a/drivers/usb/musb/musb_hcd.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Mentor USB OTG Core host controller driver.
- *
- * Copyright (c) 2008 Texas Instruments
- *
- * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
- */
-
-#ifndef __MUSB_HCD_H__
-#define __MUSB_HCD_H__
-
-#include "musb_core.h"
-#ifdef CONFIG_USB_KEYBOARD
-#include <stdio_dev.h>
-extern unsigned char new[];
-#endif
-
-#define MUSB_TIMEOUT 100000
-
-/* This defines the endpoint number used for control transfers */
-#define MUSB_CONTROL_EP 0
-
-/* This defines the endpoint number used for bulk transfer */
-#ifndef MUSB_BULK_EP
-# define MUSB_BULK_EP 1
-#endif
-
-/* This defines the endpoint number used for interrupt transfer */
-#define MUSB_INTR_EP 2
-
-/* Determine the operating speed of MUSB core */
-#define musb_ishighspeed() \
- ((readb(&musbr->power) & MUSB_POWER_HSMODE) \
- >> MUSB_POWER_HSMODE_SHIFT)
-
-/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
-
-/* destination of request */
-#define RH_INTERFACE 0x01
-#define RH_ENDPOINT 0x02
-#define RH_OTHER 0x03
-
-#define RH_CLASS 0x20
-#define RH_VENDOR 0x40
-
-/* Requests: bRequest << 8 | bmRequestType */
-#define RH_GET_STATUS 0x0080
-#define RH_CLEAR_FEATURE 0x0100
-#define RH_SET_FEATURE 0x0300
-#define RH_SET_ADDRESS 0x0500
-#define RH_GET_DESCRIPTOR 0x0680
-#define RH_SET_DESCRIPTOR 0x0700
-#define RH_GET_CONFIGURATION 0x0880
-#define RH_SET_CONFIGURATION 0x0900
-#define RH_GET_STATE 0x0280
-#define RH_GET_INTERFACE 0x0A80
-#define RH_SET_INTERFACE 0x0B00
-#define RH_SYNC_FRAME 0x0C80
-/* Our Vendor Specific Request */
-#define RH_SET_EP 0x2000
-
-/* Hub port features */
-#define RH_PORT_CONNECTION 0x00
-#define RH_PORT_ENABLE 0x01
-#define RH_PORT_SUSPEND 0x02
-#define RH_PORT_OVER_CURRENT 0x03
-#define RH_PORT_RESET 0x04
-#define RH_PORT_POWER 0x08
-#define RH_PORT_LOW_SPEED 0x09
-
-#define RH_C_PORT_CONNECTION 0x10
-#define RH_C_PORT_ENABLE 0x11
-#define RH_C_PORT_SUSPEND 0x12
-#define RH_C_PORT_OVER_CURRENT 0x13
-#define RH_C_PORT_RESET 0x14
-
-/* Hub features */
-#define RH_C_HUB_LOCAL_POWER 0x00
-#define RH_C_HUB_OVER_CURRENT 0x01
-
-#define RH_DEVICE_REMOTE_WAKEUP 0x00
-#define RH_ENDPOINT_STALL 0x01
-
-#define RH_ACK 0x01
-#define RH_REQ_ERR -1
-#define RH_NACK 0x00
-
-/* extern functions */
-extern int musb_platform_init(void);
-extern void musb_platform_deinit(void);
-
-#endif /* __MUSB_HCD_H__ */
diff --git a/drivers/usb/musb/musb_udc.c b/drivers/usb/musb/musb_udc.c
deleted file mode 100644
index 696855ee3a6..00000000000
--- a/drivers/usb/musb/musb_udc.c
+++ /dev/null
@@ -1,953 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (c) 2009 Wind River Systems, Inc.
- * Tom Rix <Tom.Rix@windriver.com>
- *
- * This file is a rewrite of the usb device part of
- * repository git.omapzoom.org/repo/u-boot.git, branch master,
- * file cpu/omap3/fastboot.c
- *
- * This is the unique part of its copyright :
- *
- * -------------------------------------------------------------------------
- *
- * (C) Copyright 2008 - 2009
- * Windriver, <www.windriver.com>
- * Tom Rix <Tom.Rix@windriver.com>
- *
- * -------------------------------------------------------------------------
- *
- * The details of connecting the device to the uboot usb device subsystem
- * came from the old omap3 repository www.sakoman.net/u-boot-omap3.git,
- * branch omap3-dev-usb, file drivers/usb/usbdcore_musb.c
- *
- * This is the unique part of its copyright :
- *
- * -------------------------------------------------------------------------
- *
- * (C) Copyright 2008 Texas Instruments Incorporated.
- *
- * Based on
- * u-boot OMAP1510 USB drivers (drivers/usbdcore_omap1510.c)
- * twl4030 init based on linux (drivers/i2c/chips/twl4030_usb.c)
- *
- * Author: Diego Dompe (diego.dompe@ridgerun.com)
- * Atin Malaviya (atin.malaviya@gmail.com)
- *
- * -------------------------------------------------------------------------
- */
-
-#include <hang.h>
-#include <serial.h>
-#include <usbdevice.h>
-#include <linux/delay.h>
-#include <usb/udc.h>
-#include "../gadget/ep0.h"
-#include "musb_core.h"
-#if defined(CONFIG_USB_OMAP3)
-#include "omap3.h"
-#elif defined(CONFIG_USB_AM35X)
-#include "am35x.h"
-#endif
-
-/* Define MUSB_DEBUG for debugging */
-/* #define MUSB_DEBUG */
-#include "musb_debug.h"
-
-#define MAX_ENDPOINT 15
-
-#define GET_ENDPOINT(dev,ep) \
-(((struct usb_device_instance *)(dev))->bus->endpoint_array + ep)
-
-#define SET_EP0_STATE(s) \
-do { \
- if ((0 <= (s)) && (SET_ADDRESS >= (s))) { \
- if ((s) != ep0_state) { \
- if ((debug_setup) && (debug_level > 1)) \
- serial_printf("INFO : Changing state " \
- "from %s to %s in %s at " \
- "line %d\n", \
- ep0_state_strings[ep0_state],\
- ep0_state_strings[s], \
- __PRETTY_FUNCTION__, \
- __LINE__); \
- ep0_state = s; \
- } \
- } else { \
- if (debug_level > 0) \
- serial_printf("Error at %s %d with setting " \
- "state %d is invalid\n", \
- __PRETTY_FUNCTION__, __LINE__, s); \
- } \
-} while (0)
-
-/* static implies these initialized to 0 or NULL */
-static int debug_setup;
-static int debug_level;
-static struct musb_epinfo epinfo[MAX_ENDPOINT * 2 + 2];
-static enum ep0_state_enum {
- IDLE = 0,
- TX,
- RX,
- SET_ADDRESS
-} ep0_state = IDLE;
-static char *ep0_state_strings[4] = {
- "IDLE",
- "TX",
- "RX",
- "SET_ADDRESS",
-};
-
-static struct urb *ep0_urb;
-struct usb_endpoint_instance *ep0_endpoint;
-static struct usb_device_instance *udc_device;
-static int enabled;
-
-static u16 pending_intrrx;
-
-#ifdef MUSB_DEBUG
-static void musb_db_regs(void)
-{
- u8 b;
- u16 w;
-
- b = readb(&musbr->faddr);
- serial_printf("\tfaddr 0x%2.2x\n", b);
-
- b = readb(&musbr->power);
- musb_print_pwr(b);
-
- w = readw(&musbr->ep[0].ep0.csr0);
- musb_print_csr0(w);
-
- b = readb(&musbr->devctl);
- musb_print_devctl(b);
-
- b = readb(&musbr->ep[0].ep0.configdata);
- musb_print_config(b);
-
- w = readw(&musbr->frame);
- serial_printf("\tframe 0x%4.4x\n", w);
-
- b = readb(&musbr->index);
- serial_printf("\tindex 0x%2.2x\n", b);
-
- w = readw(&musbr->ep[1].epN.rxmaxp);
- musb_print_rxmaxp(w);
-
- w = readw(&musbr->ep[1].epN.rxcsr);
- musb_print_rxcsr(w);
-
- w = readw(&musbr->ep[1].epN.txmaxp);
- musb_print_txmaxp(w);
-
- w = readw(&musbr->ep[1].epN.txcsr);
- musb_print_txcsr(w);
-}
-#else
-#define musb_db_regs()
-#endif /* DEBUG_MUSB */
-
-static void musb_peri_softconnect(void)
-{
- u8 power, devctl;
-
- /* Power off MUSB */
- power = readb(&musbr->power);
- power &= ~MUSB_POWER_SOFTCONN;
- writeb(power, &musbr->power);
-
- /* Read intr to clear */
- readb(&musbr->intrusb);
- readw(&musbr->intrrx);
- readw(&musbr->intrtx);
-
- udelay(1000 * 1000); /* 1 sec */
-
- /* Power on MUSB */
- power = readb(&musbr->power);
- power |= MUSB_POWER_SOFTCONN;
- /*
- * The usb device interface is usb 1.1
- * Disable 2.0 high speed by clearring the hsenable bit.
- */
- power &= ~MUSB_POWER_HSENAB;
- writeb(power, &musbr->power);
-
- /* Check if device is in b-peripheral mode */
- devctl = readb(&musbr->devctl);
- if (!(devctl & MUSB_DEVCTL_BDEVICE) ||
- (devctl & MUSB_DEVCTL_HM)) {
- serial_printf("ERROR : Unsupport USB mode\n");
- serial_printf("Check that mini-B USB cable is attached "
- "to the device\n");
- }
-
- if (debug_setup && (debug_level > 1))
- musb_db_regs();
-}
-
-static void musb_peri_reset(void)
-{
- if ((debug_setup) && (debug_level > 1))
- serial_printf("INFO : %s reset\n", __PRETTY_FUNCTION__);
-
- if (ep0_endpoint)
- ep0_endpoint->endpoint_address = 0xff;
-
- /* Sync sw and hw addresses */
- writeb(udc_device->address, &musbr->faddr);
-
- SET_EP0_STATE(IDLE);
-}
-
-static void musb_peri_resume(void)
-{
- /* noop */
-}
-
-static void musb_peri_ep0_stall(void)
-{
- u16 csr0;
-
- csr0 = readw(&musbr->ep[0].ep0.csr0);
- csr0 |= MUSB_CSR0_P_SENDSTALL;
- writew(csr0, &musbr->ep[0].ep0.csr0);
- if ((debug_setup) && (debug_level > 1))
- serial_printf("INFO : %s stall\n", __PRETTY_FUNCTION__);
-}
-
-static void musb_peri_ep0_ack_req(void)
-{
- u16 csr0;
-
- csr0 = readw(&musbr->ep[0].ep0.csr0);
- csr0 |= MUSB_CSR0_P_SVDRXPKTRDY;
- writew(csr0, &musbr->ep[0].ep0.csr0);
-}
-
-static void musb_ep0_tx_ready(void)
-{
- u16 csr0;
-
- csr0 = readw(&musbr->ep[0].ep0.csr0);
- csr0 |= MUSB_CSR0_TXPKTRDY;
- writew(csr0, &musbr->ep[0].ep0.csr0);
-}
-
-static void musb_ep0_tx_ready_and_last(void)
-{
- u16 csr0;
-
- csr0 = readw(&musbr->ep[0].ep0.csr0);
- csr0 |= (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_P_DATAEND);
- writew(csr0, &musbr->ep[0].ep0.csr0);
-}
-
-static void musb_peri_ep0_last(void)
-{
- u16 csr0;
-
- csr0 = readw(&musbr->ep[0].ep0.csr0);
- csr0 |= MUSB_CSR0_P_DATAEND;
- writew(csr0, &musbr->ep[0].ep0.csr0);
-}
-
-static void musb_peri_ep0_set_address(void)
-{
- u8 faddr;
- writeb(udc_device->address, &musbr->faddr);
-
- /* Verify */
- faddr = readb(&musbr->faddr);
- if (udc_device->address == faddr) {
- SET_EP0_STATE(IDLE);
- usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0);
- if ((debug_setup) && (debug_level > 1))
- serial_printf("INFO : %s Address set to %d\n",
- __PRETTY_FUNCTION__, udc_device->address);
- } else {
- if (debug_level > 0)
- serial_printf("ERROR : %s Address mismatch "
- "sw %d vs hw %d\n",
- __PRETTY_FUNCTION__,
- udc_device->address, faddr);
- }
-}
-
-static void musb_peri_rx_ack(unsigned int ep)
-{
- u16 peri_rxcsr;
-
- peri_rxcsr = readw(&musbr->ep[ep].epN.rxcsr);
- peri_rxcsr &= ~MUSB_RXCSR_RXPKTRDY;
- writew(peri_rxcsr, &musbr->ep[ep].epN.rxcsr);
-}
-
-static void musb_peri_tx_ready(unsigned int ep)
-{
- u16 peri_txcsr;
-
- peri_txcsr = readw(&musbr->ep[ep].epN.txcsr);
- peri_txcsr |= MUSB_TXCSR_TXPKTRDY;
- writew(peri_txcsr, &musbr->ep[ep].epN.txcsr);
-}
-
-static void musb_peri_ep0_zero_data_request(int err)
-{
- musb_peri_ep0_ack_req();
-
- if (err) {
- musb_peri_ep0_stall();
- SET_EP0_STATE(IDLE);
- } else {
-
- musb_peri_ep0_last();
-
- /* USBD state */
- switch (ep0_urb->device_request.bRequest) {
- case USB_REQ_SET_ADDRESS:
- if ((debug_setup) && (debug_level > 1))
- serial_printf("INFO : %s received set "
- "address\n", __PRETTY_FUNCTION__);
- break;
-
- case USB_REQ_SET_CONFIGURATION:
- if ((debug_setup) && (debug_level > 1))
- serial_printf("INFO : %s Configured\n",
- __PRETTY_FUNCTION__);
- usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
- break;
- }
-
- /* EP0 state */
- if (USB_REQ_SET_ADDRESS == ep0_urb->device_request.bRequest) {
- SET_EP0_STATE(SET_ADDRESS);
- } else {
- SET_EP0_STATE(IDLE);
- }
- }
-}
-
-static void musb_peri_ep0_rx_data_request(void)
-{
- /*
- * This is the completion of the data OUT / RX
- *
- * Host is sending data to ep0 that is not
- * part of setup. This comes from the cdc_recv_setup
- * op that is device specific.
- *
- */
- musb_peri_ep0_ack_req();
-
- ep0_endpoint->rcv_urb = ep0_urb;
- ep0_urb->actual_length = 0;
- SET_EP0_STATE(RX);
-}
-
-static void musb_peri_ep0_tx_data_request(int err)
-{
- if (err) {
- musb_peri_ep0_stall();
- SET_EP0_STATE(IDLE);
- } else {
- musb_peri_ep0_ack_req();
-
- ep0_endpoint->tx_urb = ep0_urb;
- ep0_endpoint->sent = 0;
- SET_EP0_STATE(TX);
- }
-}
-
-static void musb_peri_ep0_idle(void)
-{
- u16 count0;
- int err;
- u16 csr0;
-
- /*
- * Verify addresses
- * A lot of confusion can be caused if the address
- * in software, udc layer, does not agree with the
- * hardware. Since the setting of the hardware address
- * must be set after the set address request, the
- * usb state machine is out of sync for a few frame.
- * It is a good idea to run this check when changes
- * are made to the state machine.
- */
- if ((debug_level > 0) &&
- (ep0_state != SET_ADDRESS)) {
- u8 faddr;
-
- faddr = readb(&musbr->faddr);
- if (udc_device->address != faddr) {
- serial_printf("ERROR : %s addresses do not"
- "match sw %d vs hw %d\n",
- __PRETTY_FUNCTION__,
- udc_device->address, faddr);
- udelay(1000 * 1000);
- hang();
- }
- }
-
- csr0 = readw(&musbr->ep[0].ep0.csr0);
-
- if (!(MUSB_CSR0_RXPKTRDY & csr0))
- goto end;
-
- count0 = readw(&musbr->ep[0].ep0.count0);
- if (count0 == 0)
- goto end;
-
- if (count0 != 8) {
- if ((debug_setup) && (debug_level > 1))
- serial_printf("WARN : %s SETUP incorrect size %d\n",
- __PRETTY_FUNCTION__, count0);
- musb_peri_ep0_stall();
- goto end;
- }
-
- read_fifo(0, count0, &ep0_urb->device_request);
-
- if (debug_level > 2)
- print_usb_device_request(&ep0_urb->device_request);
-
- if (ep0_urb->device_request.wLength == 0) {
- err = ep0_recv_setup(ep0_urb);
-
- /* Zero data request */
- musb_peri_ep0_zero_data_request(err);
- } else {
- /* Is data coming or going ? */
- u8 reqType = ep0_urb->device_request.bmRequestType;
-
- if (USB_REQ_DEVICE2HOST == (reqType & USB_REQ_DIRECTION_MASK)) {
- err = ep0_recv_setup(ep0_urb);
- /* Device to host */
- musb_peri_ep0_tx_data_request(err);
- } else {
- /*
- * Host to device
- *
- * The RX routine will call ep0_recv_setup
- * when the data packet has arrived.
- */
- musb_peri_ep0_rx_data_request();
- }
- }
-
-end:
- return;
-}
-
-static void musb_peri_ep0_rx(void)
-{
- /*
- * This is the completion of the data OUT / RX
- *
- * Host is sending data to ep0 that is not
- * part of setup. This comes from the cdc_recv_setup
- * op that is device specific.
- *
- * Pass the data back to driver ep0_recv_setup which
- * should give the cdc_recv_setup the chance to handle
- * the rx
- */
- u16 csr0;
- u16 count0;
-
- if (debug_level > 3) {
- if (0 != ep0_urb->actual_length) {
- serial_printf("%s finished ? %d of %d\n",
- __PRETTY_FUNCTION__,
- ep0_urb->actual_length,
- ep0_urb->device_request.wLength);
- }
- }
-
- if (ep0_urb->device_request.wLength == ep0_urb->actual_length) {
- musb_peri_ep0_last();
- SET_EP0_STATE(IDLE);
- ep0_recv_setup(ep0_urb);
- return;
- }
-
- csr0 = readw(&musbr->ep[0].ep0.csr0);
- if (!(MUSB_CSR0_RXPKTRDY & csr0))
- return;
-
- count0 = readw(&musbr->ep[0].ep0.count0);
-
- if (count0) {
- struct usb_endpoint_instance *endpoint;
- u32 length;
- u8 *data;
-
- endpoint = ep0_endpoint;
- if (endpoint && endpoint->rcv_urb) {
- struct urb *urb = endpoint->rcv_urb;
- unsigned int remaining_space = urb->buffer_length -
- urb->actual_length;
-
- if (remaining_space) {
- int urb_bad = 0; /* urb is good */
-
- if (count0 > remaining_space)
- length = remaining_space;
- else
- length = count0;
-
- data = (u8 *) urb->buffer_data;
- data += urb->actual_length;
-
- /* The common musb fifo reader */
- read_fifo(0, length, data);
-
- musb_peri_ep0_ack_req();
-
- /*
- * urb's actual_length is updated in
- * usbd_rcv_complete
- */
- usbd_rcv_complete(endpoint, length, urb_bad);
-
- } else {
- if (debug_level > 0)
- serial_printf("ERROR : %s no space in "
- "rcv buffer\n",
- __PRETTY_FUNCTION__);
- }
- } else {
- if (debug_level > 0)
- serial_printf("ERROR : %s problem with "
- "endpoint\n",
- __PRETTY_FUNCTION__);
- }
- } else {
- if (debug_level > 0)
- serial_printf("ERROR : %s with nothing to do\n",
- __PRETTY_FUNCTION__);
- }
-}
-
-static void musb_peri_ep0_tx(void)
-{
- u16 csr0;
- int transfer_size = 0;
- unsigned int p, pm;
-
- csr0 = readw(&musbr->ep[0].ep0.csr0);
-
- /* Check for pending tx */
- if (csr0 & MUSB_CSR0_TXPKTRDY)
- goto end;
-
- /* Check if this is the last packet sent */
- if (ep0_endpoint->sent >= ep0_urb->actual_length) {
- SET_EP0_STATE(IDLE);
- goto end;
- }
-
- transfer_size = ep0_urb->actual_length - ep0_endpoint->sent;
- /* Is the transfer size negative ? */
- if (transfer_size <= 0) {
- if (debug_level > 0)
- serial_printf("ERROR : %s problem with the"
- " transfer size %d\n",
- __PRETTY_FUNCTION__,
- transfer_size);
- SET_EP0_STATE(IDLE);
- goto end;
- }
-
- /* Truncate large transfers to the fifo size */
- if (transfer_size > ep0_endpoint->tx_packetSize)
- transfer_size = ep0_endpoint->tx_packetSize;
-
- write_fifo(0, transfer_size, &ep0_urb->buffer[ep0_endpoint->sent]);
- ep0_endpoint->sent += transfer_size;
-
- /* Done or more to send ? */
- if (ep0_endpoint->sent >= ep0_urb->actual_length)
- musb_ep0_tx_ready_and_last();
- else
- musb_ep0_tx_ready();
-
- /* Wait a bit */
- pm = 10;
- for (p = 0; p < pm; p++) {
- csr0 = readw(&musbr->ep[0].ep0.csr0);
- if (!(csr0 & MUSB_CSR0_TXPKTRDY))
- break;
-
- /* Double the delay. */
- udelay(1 << pm);
- }
-
- if ((ep0_endpoint->sent >= ep0_urb->actual_length) && (p < pm))
- SET_EP0_STATE(IDLE);
-
-end:
- return;
-}
-
-static void musb_peri_ep0(void)
-{
- u16 csr0;
-
- if (SET_ADDRESS == ep0_state)
- return;
-
- csr0 = readw(&musbr->ep[0].ep0.csr0);
-
- /* Error conditions */
- if (MUSB_CSR0_P_SENTSTALL & csr0) {
- csr0 &= ~MUSB_CSR0_P_SENTSTALL;
- writew(csr0, &musbr->ep[0].ep0.csr0);
- SET_EP0_STATE(IDLE);
- }
- if (MUSB_CSR0_P_SETUPEND & csr0) {
- csr0 |= MUSB_CSR0_P_SVDSETUPEND;
- writew(csr0, &musbr->ep[0].ep0.csr0);
- SET_EP0_STATE(IDLE);
- if ((debug_setup) && (debug_level > 1))
- serial_printf("WARN: %s SETUPEND\n",
- __PRETTY_FUNCTION__);
- }
-
- /* Normal states */
- if (IDLE == ep0_state)
- musb_peri_ep0_idle();
-
- if (TX == ep0_state)
- musb_peri_ep0_tx();
-
- if (RX == ep0_state)
- musb_peri_ep0_rx();
-}
-
-static void musb_peri_rx_ep(unsigned int ep)
-{
- u16 peri_rxcount;
- u16 peri_rxcsr = readw(&musbr->ep[ep].epN.rxcsr);
-
- if (!(peri_rxcsr & MUSB_RXCSR_RXPKTRDY)) {
- if (debug_level > 0)
- serial_printf("ERROR : %s %d without MUSB_RXCSR_RXPKTRDY set\n",
- __PRETTY_FUNCTION__, ep);
- return;
- }
-
- peri_rxcount = readw(&musbr->ep[ep].epN.rxcount);
- if (peri_rxcount) {
- struct usb_endpoint_instance *endpoint;
- u32 length;
- u8 *data;
-
- endpoint = GET_ENDPOINT(udc_device, ep);
- if (endpoint && endpoint->rcv_urb) {
- struct urb *urb = endpoint->rcv_urb;
- unsigned int remaining_space = urb->buffer_length -
- urb->actual_length;
-
- if (remaining_space) {
- int urb_bad = 0; /* urb is good */
-
- if (peri_rxcount > remaining_space)
- length = remaining_space;
- else
- length = peri_rxcount;
-
- data = (u8 *) urb->buffer_data;
- data += urb->actual_length;
-
- /* The common musb fifo reader */
- read_fifo(ep, length, data);
-
- if (length == peri_rxcount)
- musb_peri_rx_ack(ep);
- else
- pending_intrrx |= (1 << ep);
-
- /*
- * urb's actual_length is updated in
- * usbd_rcv_complete
- */
- usbd_rcv_complete(endpoint, length, urb_bad);
-
- } else {
- if (debug_level > 0)
- serial_printf("ERROR : %s %d no space "
- "in rcv buffer\n",
- __PRETTY_FUNCTION__, ep);
-
- pending_intrrx |= (1 << ep);
- }
- } else {
- if (debug_level > 0)
- serial_printf("ERROR : %s %d problem with "
- "endpoint\n",
- __PRETTY_FUNCTION__, ep);
-
- pending_intrrx |= (1 << ep);
- }
-
- } else {
- if (debug_level > 0)
- serial_printf("ERROR : %s %d with nothing to do\n",
- __PRETTY_FUNCTION__, ep);
-
- musb_peri_rx_ack(ep);
- }
-}
-
-static void musb_peri_rx(u16 intr)
-{
- unsigned int ep;
-
- /* First bit is reserved and does not indicate interrupt for EP0 */
-
- for (ep = 1; ep < 16; ep++) {
- if ((1 << ep) & intr)
- musb_peri_rx_ep(ep);
- }
-}
-
-static void musb_peri_tx(u16 intr)
-{
- unsigned int ep;
-
- /* Check for EP0: first bit indicates interrupt for both RX and TX */
- if (0x01 & intr)
- musb_peri_ep0();
-
- for (ep = 1; ep < 16; ep++) {
- if ((1 << ep) & intr)
- udc_endpoint_write(GET_ENDPOINT(udc_device, ep));
- }
-}
-
-void udc_irq(void)
-{
- /* This is a high freq called function */
- if (enabled) {
- u8 intrusb;
-
- intrusb = readb(&musbr->intrusb);
-
- /*
- * See drivers/usb/gadget/mpc8xx_udc.c for
- * state diagram going from detached through
- * configuration.
- */
- if (MUSB_INTR_RESUME & intrusb) {
- usbd_device_event_irq(udc_device,
- DEVICE_BUS_ACTIVITY, 0);
- musb_peri_resume();
- }
-
- if (MUSB_INTR_RESET & intrusb) {
- usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
- musb_peri_reset();
- }
-
- if (MUSB_INTR_DISCONNECT & intrusb) {
- /* cable unplugged from hub/host */
- usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
- musb_peri_reset();
- usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0);
- }
-
- if (MUSB_INTR_SOF & intrusb) {
- usbd_device_event_irq(udc_device,
- DEVICE_BUS_ACTIVITY, 0);
- musb_peri_resume();
- }
-
- if (MUSB_INTR_SUSPEND & intrusb) {
- usbd_device_event_irq(udc_device,
- DEVICE_BUS_INACTIVE, 0);
- }
-
- if (ep0_state != SET_ADDRESS) {
- u16 intrrx, intrtx;
-
- intrrx = readw(&musbr->intrrx);
- intrtx = readw(&musbr->intrtx);
-
- intrrx |= pending_intrrx;
- pending_intrrx = 0;
-
- if (intrrx)
- musb_peri_rx(intrrx);
-
- if (intrtx)
- musb_peri_tx(intrtx);
- } else {
- if (readw(&musbr->intrtx) & 0x1) {
- u8 faddr;
- faddr = readb(&musbr->faddr);
- /*
- * Setting of the address can fail.
- * Normally it succeeds the second time.
- */
- if (udc_device->address != faddr)
- musb_peri_ep0_set_address();
- }
- }
- }
-}
-
-void udc_set_nak(int ep_num)
-{
- /* noop */
-}
-
-void udc_unset_nak(int ep_num)
-{
- /* noop */
-}
-
-int udc_endpoint_write(struct usb_endpoint_instance *endpoint)
-{
- int ret = 0;
-
- /* Transmit only if the hardware is available */
- if (endpoint->tx_urb && endpoint->state == 0) {
- unsigned int ep = endpoint->endpoint_address &
- USB_ENDPOINT_NUMBER_MASK;
-
- u16 peri_txcsr = readw(&musbr->ep[ep].epN.txcsr);
-
- /* Error conditions */
- if (peri_txcsr & MUSB_TXCSR_P_UNDERRUN) {
- peri_txcsr &= ~MUSB_TXCSR_P_UNDERRUN;
- writew(peri_txcsr, &musbr->ep[ep].epN.txcsr);
- }
-
- if (debug_level > 1)
- musb_print_txcsr(peri_txcsr);
-
- /* Check if a packet is waiting to be sent */
- if (!(peri_txcsr & MUSB_TXCSR_TXPKTRDY)) {
- u32 length;
- u8 *data;
- struct urb *urb = endpoint->tx_urb;
- unsigned int remaining_packet = urb->actual_length -
- endpoint->sent;
-
- if (endpoint->tx_packetSize < remaining_packet)
- length = endpoint->tx_packetSize;
- else
- length = remaining_packet;
-
- data = (u8 *) urb->buffer;
- data += endpoint->sent;
-
- /* common musb fifo function */
- write_fifo(ep, length, data);
-
- musb_peri_tx_ready(ep);
-
- endpoint->last = length;
- /* usbd_tx_complete will take care of updating 'sent' */
- usbd_tx_complete(endpoint);
- }
- } else {
- if (debug_level > 0)
- serial_printf("ERROR : %s Problem with urb %p "
- "or ep state %d\n",
- __PRETTY_FUNCTION__,
- endpoint->tx_urb, endpoint->state);
- }
-
- return ret;
-}
-
-void udc_setup_ep(struct usb_device_instance *device, unsigned int id,
- struct usb_endpoint_instance *endpoint)
-{
- if (0 == id) {
- /* EP0 */
- ep0_endpoint = endpoint;
- ep0_endpoint->endpoint_address = 0xff;
- ep0_urb = usbd_alloc_urb(device, endpoint);
- } else if (MAX_ENDPOINT >= id) {
- epinfo[(id * 2) + 0].epsize = endpoint->rcv_packetSize;
- epinfo[(id * 2) + 1].epsize = endpoint->tx_packetSize;
- musb_configure_ep(&epinfo[0], ARRAY_SIZE(epinfo));
- } else {
- if (debug_level > 0)
- serial_printf("ERROR : %s endpoint request %d "
- "exceeds maximum %d\n",
- __PRETTY_FUNCTION__, id, MAX_ENDPOINT);
- }
-}
-
-void udc_connect(void)
-{
- /* noop */
-}
-
-void udc_disconnect(void)
-{
- /* noop */
-}
-
-void udc_enable(struct usb_device_instance *device)
-{
- /* Save the device structure pointer */
- udc_device = device;
-
- enabled = 1;
-}
-
-void udc_disable(void)
-{
- enabled = 0;
-}
-
-void udc_startup_events(struct usb_device_instance *device)
-{
- /* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */
- usbd_device_event_irq(device, DEVICE_INIT, 0);
-
- /*
- * The DEVICE_CREATE event puts the USB device in the state
- * STATE_ATTACHED.
- */
- usbd_device_event_irq(device, DEVICE_CREATE, 0);
-
- /* Resets the address to 0 */
- usbd_device_event_irq(device, DEVICE_RESET, 0);
-
- udc_enable(device);
-}
-
-int udc_init(void)
-{
- int ret;
- int ep_loop;
-
- ret = musb_platform_init();
- if (ret < 0)
- goto end;
-
- /* Configure all the endpoint FIFO's and start usb controller */
- musbr = musb_cfg.regs;
-
- /* Initialize the endpoints */
- for (ep_loop = 0; ep_loop <= MAX_ENDPOINT * 2; ep_loop++) {
- epinfo[ep_loop].epnum = (ep_loop / 2) + 1;
- epinfo[ep_loop].epdir = ep_loop % 2; /* OUT, IN */
- epinfo[ep_loop].epsize = 0;
- }
-
- musb_peri_softconnect();
-
- ret = 0;
-end:
-
- return ret;
-}
diff --git a/drivers/usb/musb/omap3.c b/drivers/usb/musb/omap3.c
deleted file mode 100644
index e5238bc02f8..00000000000
--- a/drivers/usb/musb/omap3.c
+++ /dev/null
@@ -1,129 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (c) 2009 Wind River Systems, Inc.
- * Tom Rix <Tom.Rix@windriver.com>
- *
- * This is file is based on
- * repository git.gitorious.org/u-boot-omap3/mainline.git,
- * branch omap3-dev-usb, file drivers/usb/host/omap3530_usb.c
- *
- * This is the unique part of its copyright :
- *
- * ------------------------------------------------------------------------
- *
- * Copyright (c) 2009 Texas Instruments
- *
- * ------------------------------------------------------------------------
- */
-
-#include <serial.h>
-#include <asm/omap_common.h>
-#include <twl4030.h>
-#include "omap3.h"
-
-static int platform_needs_initialization = 1;
-
-struct musb_config musb_cfg = {
- .regs = (struct musb_regs *)MENTOR_USB0_BASE,
- .timeout = OMAP3_USB_TIMEOUT,
- .musb_speed = 0,
-};
-
-/*
- * OMAP3 USB OTG registers.
- */
-struct omap3_otg_regs {
- u32 revision;
- u32 sysconfig;
- u32 sysstatus;
- u32 interfsel;
- u32 simenable;
- u32 forcestdby;
-};
-
-static struct omap3_otg_regs *otg;
-
-#define OMAP3_OTG_SYSCONFIG_SMART_STANDBY_MODE 0x2000
-#define OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE 0x1000
-#define OMAP3_OTG_SYSCONFIG_SMART_IDLE_MODE 0x0010
-#define OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE 0x0008
-#define OMAP3_OTG_SYSCONFIG_ENABLEWAKEUP 0x0004
-#define OMAP3_OTG_SYSCONFIG_SOFTRESET 0x0002
-#define OMAP3_OTG_SYSCONFIG_AUTOIDLE 0x0001
-
-#define OMAP3_OTG_SYSSTATUS_RESETDONE 0x0001
-
-#define OMAP3_OTG_INTERFSEL_OMAP 0x0001
-
-#define OMAP3_OTG_FORCESTDBY_STANDBY 0x0001
-
-#ifdef DEBUG_MUSB_OMAP3
-static void musb_db_otg_regs(void)
-{
- u32 l;
- l = readl(&otg->revision);
- serial_printf("OTG_REVISION 0x%x\n", l);
- l = readl(&otg->sysconfig);
- serial_printf("OTG_SYSCONFIG 0x%x\n", l);
- l = readl(&otg->sysstatus);
- serial_printf("OTG_SYSSTATUS 0x%x\n", l);
- l = readl(&otg->interfsel);
- serial_printf("OTG_INTERFSEL 0x%x\n", l);
- l = readl(&otg->forcestdby);
- serial_printf("OTG_FORCESTDBY 0x%x\n", l);
-}
-#endif
-
-int musb_platform_init(void)
-{
- int ret = -1;
-
- if (platform_needs_initialization) {
- u32 stdby;
-
- /*
- * OMAP3EVM uses ISP1504 phy and so
- * twl4030 related init is not required.
- */
-#ifdef CONFIG_TWL4030_USB
- if (twl4030_usb_ulpi_init()) {
- serial_printf("ERROR: %s Could not initialize PHY\n",
- __PRETTY_FUNCTION__);
- goto end;
- }
-#endif
-
- otg = (struct omap3_otg_regs *)OMAP3_OTG_BASE;
-
- /* Set OTG to always be on */
- writel(OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE |
- OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE, &otg->sysconfig);
-
- /* Set the interface */
- writel(OMAP3_OTG_INTERFSEL_OMAP, &otg->interfsel);
-
- /* Clear force standby */
- stdby = readl(&otg->forcestdby);
- stdby &= ~OMAP3_OTG_FORCESTDBY_STANDBY;
- writel(stdby, &otg->forcestdby);
-
-#ifdef CONFIG_TARGET_OMAP3_EVM
- musb_cfg.extvbus = omap3_evm_need_extvbus();
-#endif
-
- platform_needs_initialization = 0;
- }
-
- ret = platform_needs_initialization;
-
-#ifdef CONFIG_TWL4030_USB
-end:
-#endif
- return ret;
-
-}
-
-void musb_platform_deinit(void)
-{
- /* noop */
-}
diff --git a/drivers/usb/musb/omap3.h b/drivers/usb/musb/omap3.h
deleted file mode 100644
index 78fdb2959bb..00000000000
--- a/drivers/usb/musb/omap3.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright (c) 2009 Wind River Systems, Inc.
- * Tom Rix <Tom.Rix@windriver.com>
- *
- * This file is based on the file drivers/usb/musb/davinci.h
- *
- * This is the unique part of its copyright:
- *
- * --------------------------------------------------------------------
- *
- * Copyright (c) 2008 Texas Instruments
- * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
- *
- * --------------------------------------------------------------------
- */
-#ifndef _MUSB_OMAP3_H_
-#define _MUSB_OMAP3_H_
-
-#include <asm/arch/cpu.h>
-#include "musb_core.h"
-
-/* Base address of MUSB registers */
-#define MENTOR_USB0_BASE MUSB_BASE
-
-/* Base address of OTG registers */
-#define OMAP3_OTG_BASE (MENTOR_USB0_BASE + 0x400)
-
-/* Timeout for USB module */
-#define OMAP3_USB_TIMEOUT 0x3FFFFFF
-
-int musb_platform_init(void);
-
-#ifdef CONFIG_TARGET_OMAP3_EVM
-extern u8 omap3_evm_need_extvbus(void);
-#endif
-
-#endif /* _MUSB_OMAP3_H */
diff --git a/drivers/usb/ulpi/ulpi.c b/drivers/usb/ulpi/ulpi.c
index 128adcbde13..0e0f0e4983d 100644
--- a/drivers/usb/ulpi/ulpi.c
+++ b/drivers/usb/ulpi/ulpi.c
@@ -127,7 +127,7 @@ int ulpi_set_vbus_indicator(struct ulpi_viewport *ulpi_vp, int external,
if (val == ULPI_ERROR)
return val;
- val = val & ~(ULPI_IFACE_PASSTHRU & ULPI_IFACE_EXTVBUS_COMPLEMENT);
+ val = val & ~(ULPI_IFACE_PASSTHRU | ULPI_IFACE_EXTVBUS_COMPLEMENT);
val |= flags;
val = ulpi_write(ulpi_vp, &ulpi->iface_ctrl, val);
if (val)
diff --git a/drivers/video/efi.c b/drivers/video/efi.c
index 78d123fad4b..8ce2ef9dc67 100644
--- a/drivers/video/efi.c
+++ b/drivers/video/efi.c
@@ -104,7 +104,7 @@ static int get_mode_info(struct vesa_mode_info *vesa, u64 *fbp,
static int get_mode_from_entry(struct vesa_mode_info *vesa, u64 *fbp,
struct efi_gop_mode_info **infop)
{
- struct efi_gop_mode *mode;
+ struct efi_entry_gopmode *mode;
int size;
int ret;
diff --git a/drivers/video/simple_panel.c b/drivers/video/simple_panel.c
index b6c5b058b2e..0f23df701bc 100644
--- a/drivers/video/simple_panel.c
+++ b/drivers/video/simple_panel.c
@@ -191,6 +191,7 @@ static const struct mipi_dsi_panel_plat panasonic_vvx10f004b00 = {
static const struct udevice_id simple_panel_ids[] = {
{ .compatible = "simple-panel" },
+ { .compatible = "panel-lvds" },
{ .compatible = "auo,b133xtn01" },
{ .compatible = "auo,b116xw03" },
{ .compatible = "auo,b133htn01" },
diff --git a/drivers/video/stm32/Kconfig b/drivers/video/stm32/Kconfig
index c354c402c28..4cb8a841caf 100644
--- a/drivers/video/stm32/Kconfig
+++ b/drivers/video/stm32/Kconfig
@@ -23,6 +23,15 @@ config VIDEO_STM32_DSI
This option enables support DSI internal bridge which can be used on
devices which have DSI devices connected.
+config VIDEO_STM32_LVDS
+ bool "Enable STM32 LVDS video support"
+ depends on VIDEO_STM32
+ select VIDEO_BRIDGE
+ select VIDEO_DW_MIPI_DSI
+ help
+ This enables Low Voltage Differential Signaling (LVDS) display
+ support.
+
config VIDEO_STM32_MAX_XRES
int "Maximum horizontal resolution (for memory allocation purposes)"
depends on VIDEO_STM32
diff --git a/drivers/video/stm32/Makefile b/drivers/video/stm32/Makefile
index f8b42d1a4d1..059d9000c1d 100644
--- a/drivers/video/stm32/Makefile
+++ b/drivers/video/stm32/Makefile
@@ -7,3 +7,4 @@
obj-${CONFIG_VIDEO_STM32} = stm32_ltdc.o
obj-${CONFIG_VIDEO_STM32_DSI} += stm32_dsi.o
+obj-${CONFIG_VIDEO_STM32_LVDS} += stm32_lvds.o
diff --git a/drivers/video/stm32/stm32_ltdc.c b/drivers/video/stm32/stm32_ltdc.c
index 0a062c8939d..834bfb625d2 100644
--- a/drivers/video/stm32/stm32_ltdc.c
+++ b/drivers/video/stm32/stm32_ltdc.c
@@ -17,6 +17,7 @@
#include <video_bridge.h>
#include <asm/io.h>
#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
#include <dm/device_compat.h>
#include <linux/bitops.h>
#include <linux/printk.h>
@@ -262,6 +263,7 @@ static const u32 layer_regs_a2[] = {
#define HWVER_10300 0x010300
#define HWVER_20101 0x020101
#define HWVER_40100 0x040100
+#define HWVER_40101 0x040101
enum stm32_ltdc_pix_fmt {
PF_ARGB8888 = 0, /* ARGB [32 bits] */
@@ -494,6 +496,101 @@ static void stm32_ltdc_set_layer1(struct stm32_ltdc_priv *priv, ulong fb_addr)
setbits_le32(priv->regs + LTDC_L1CR, LXCR_LEN);
}
+static int stm32_ltdc_get_remote_device(struct udevice *dev, ofnode ep_node,
+ enum uclass_id id, struct udevice **remote_dev)
+{
+ u32 remote_phandle;
+ ofnode remote;
+ int ret = 0;
+
+ ret = ofnode_read_u32(ep_node, "remote-endpoint", &remote_phandle);
+ if (ret) {
+ dev_err(dev, "%s(%s): Could not find remote-endpoint property\n",
+ __func__, dev_read_name(dev));
+ return ret;
+ }
+
+ remote = ofnode_get_by_phandle(remote_phandle);
+ if (!ofnode_valid(remote))
+ return -EINVAL;
+
+ while (ofnode_valid(remote)) {
+ remote = ofnode_get_parent(remote);
+ if (!ofnode_valid(remote)) {
+ dev_dbg(dev, "%s(%s): no uclass_id %d for remote-endpoint\n",
+ __func__, dev_read_name(dev), id);
+ continue;
+ }
+
+ ret = uclass_find_device_by_ofnode(id, remote, remote_dev);
+ if (*remote_dev && !ret) {
+ ret = uclass_get_device_by_ofnode(id, remote, remote_dev);
+ if (ret)
+ dev_dbg(dev, "%s(%s): failed to get remote device %s\n",
+ __func__, dev_read_name(dev), dev_read_name(*remote_dev));
+ break;
+ }
+ };
+
+ return ret;
+}
+
+static int stm32_ltdc_get_panel(struct udevice *dev, struct udevice **panel)
+{
+ ofnode ep_node, node, ports;
+ int ret = 0;
+
+ if (!dev)
+ return -EINVAL;
+
+ ports = ofnode_find_subnode(dev_ofnode(dev), "ports");
+ if (!ofnode_valid(ports)) {
+ dev_err(dev, "Remote bridge subnode\n");
+ return ret;
+ }
+
+ for (node = ofnode_first_subnode(ports);
+ ofnode_valid(node);
+ node = dev_read_next_subnode(node)) {
+ ep_node = ofnode_first_subnode(node);
+ if (!ofnode_valid(ep_node))
+ continue;
+
+ ret = stm32_ltdc_get_remote_device(dev, ep_node, UCLASS_PANEL, panel);
+ }
+
+ /* Sanity check, we can get out of the loop without having a clean ofnode */
+ if (!(*panel))
+ ret = -EINVAL;
+ else
+ if (!ofnode_valid(dev_ofnode(*panel)))
+ ret = -EINVAL;
+
+ return ret;
+}
+
+static int stm32_ltdc_display_init(struct udevice *dev, ofnode *ep_node,
+ struct udevice **panel, struct udevice **bridge)
+{
+ int ret;
+
+ if (*panel)
+ return -EINVAL;
+
+ if (IS_ENABLED(CONFIG_VIDEO_BRIDGE)) {
+ ret = stm32_ltdc_get_remote_device(dev, *ep_node, UCLASS_VIDEO_BRIDGE, bridge);
+ if (ret)
+ return ret;
+
+ ret = stm32_ltdc_get_panel(*bridge, panel);
+ } else {
+ /* no bridge, search a panel from display controller node */
+ ret = stm32_ltdc_get_remote_device(dev, *ep_node, UCLASS_PANEL, panel);
+ }
+
+ return ret;
+}
+
#if IS_ENABLED(CONFIG_TARGET_STM32F469_DISCOVERY)
static int stm32_ltdc_alloc_fb(struct udevice *dev)
{
@@ -529,8 +626,9 @@ static int stm32_ltdc_probe(struct udevice *dev)
struct udevice *bridge = NULL;
struct udevice *panel = NULL;
struct display_timing timings;
- struct clk pclk;
+ struct clk pclk, bclk;
struct reset_ctl rst;
+ ofnode node, port;
ulong rate;
int ret;
@@ -540,7 +638,21 @@ static int stm32_ltdc_probe(struct udevice *dev)
return -EINVAL;
}
- ret = clk_get_by_index(dev, 0, &pclk);
+ ret = clk_get_by_name(dev, "bus", &bclk);
+ if (ret) {
+ if (ret != -ENODATA) {
+ dev_err(dev, "bus clock get error %d\n", ret);
+ return ret;
+ }
+ } else {
+ ret = clk_enable(&bclk);
+ if (ret) {
+ dev_err(dev, "bus clock enable error %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = clk_get_by_name(dev, "lcd", &pclk);
if (ret) {
dev_err(dev, "peripheral clock get error %d\n", ret);
return ret;
@@ -553,7 +665,7 @@ static int stm32_ltdc_probe(struct udevice *dev)
}
priv->hw_version = readl(priv->regs + LTDC_IDR);
- debug("%s: LTDC hardware 0x%x\n", __func__, priv->hw_version);
+ dev_dbg(dev, "%s: LTDC hardware 0x%x\n", __func__, priv->hw_version);
switch (priv->hw_version) {
case HWVER_10200:
@@ -566,6 +678,7 @@ static int stm32_ltdc_probe(struct udevice *dev)
priv->pix_fmt_hw = pix_fmt_a1;
break;
case HWVER_40100:
+ case HWVER_40101:
priv->layer_regs = layer_regs_a2;
priv->pix_fmt_hw = pix_fmt_a2;
break;
@@ -573,13 +686,35 @@ static int stm32_ltdc_probe(struct udevice *dev)
return -ENODEV;
}
- ret = uclass_first_device_err(UCLASS_PANEL, &panel);
- if (ret) {
- if (ret != -ENODEV)
- dev_err(dev, "panel device error %d\n", ret);
- return ret;
+ /*
+ * Try all the ports until one working.
+ *
+ * This is done in two times. First is checks for the
+ * UCLASS_VIDEO_BRIDGE available, and then for this bridge
+ * it scans for a UCLASS_PANEL.
+ */
+
+ port = dev_read_subnode(dev, "port");
+ if (!ofnode_valid(port)) {
+ dev_err(dev, "%s(%s): 'port' subnode not found\n",
+ __func__, dev_read_name(dev));
+ return -EINVAL;
}
+ for (node = ofnode_first_subnode(port);
+ ofnode_valid(node);
+ node = dev_read_next_subnode(node)) {
+ ret = stm32_ltdc_display_init(dev, &node, &panel, &bridge);
+ if (ret)
+ dev_dbg(dev, "Device failed ret=%d\n", ret);
+ else
+ break;
+ }
+
+ /* Sanity check */
+ if (ret)
+ return ret;
+
ret = panel_get_display_timing(panel, &timings);
if (ret) {
ret = ofnode_decode_display_timing(dev_ofnode(panel),
@@ -608,11 +743,6 @@ static int stm32_ltdc_probe(struct udevice *dev)
reset_deassert(&rst);
if (IS_ENABLED(CONFIG_VIDEO_BRIDGE)) {
- ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &bridge);
- if (ret)
- dev_dbg(dev,
- "No video bridge, or no backlight on bridge\n");
-
if (bridge) {
ret = video_bridge_attach(bridge);
if (ret) {
@@ -688,6 +818,8 @@ static int stm32_ltdc_bind(struct udevice *dev)
static const struct udevice_id stm32_ltdc_ids[] = {
{ .compatible = "st,stm32-ltdc" },
+ { .compatible = "st,stm32mp251-ltdc" },
+ { .compatible = "st,stm32mp255-ltdc" },
{ }
};
diff --git a/drivers/video/stm32/stm32_lvds.c b/drivers/video/stm32/stm32_lvds.c
new file mode 100644
index 00000000000..bf1393c9e87
--- /dev/null
+++ b/drivers/video/stm32/stm32_lvds.c
@@ -0,0 +1,693 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause
+/*
+ * Copyright (C) 2025 STMicroelectronics - All Rights Reserved
+ * Author(s): Raphaƫl Gallais-Pou <raphael.gallais-pou@foss.st.com> for STMicroelectronics.
+ *
+ * This Low Voltage Differential Signal controller driver is based on the Linux Kernel driver from
+ * drivers/gpu/drm/stm/ltdc.c
+ */
+
+#define LOG_CATEGORY UCLASS_VIDEO_BRIDGE
+
+#include <clk.h>
+#include <dm.h>
+#include <log.h>
+#include <media_bus_format.h>
+#include <panel.h>
+#include <reset.h>
+#include <video.h>
+#include <video_bridge.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <dm/ofnode.h>
+#include <linux/iopoll.h>
+
+/* LVDS Host registers */
+#define LVDS_CR 0x0000 /* configuration register */
+#define LVDS_DMLCR0 0x0004 /* data mapping lsb configuration register 0 */
+#define LVDS_DMMCR0 0x0008 /* data mapping msb configuration register 0 */
+#define LVDS_DMLCR1 0x000C /* data mapping lsb configuration register 1 */
+#define LVDS_DMMCR1 0x0010 /* data mapping msb configuration register 1 */
+#define LVDS_DMLCR2 0x0014 /* data mapping lsb configuration register 2 */
+#define LVDS_DMMCR2 0x0018 /* data mapping msb configuration register 2 */
+#define LVDS_DMLCR3 0x001C /* data mapping lsb configuration register 3 */
+#define LVDS_DMMCR3 0x0020 /* data mapping msb configuration register 3 */
+#define LVDS_DMLCR4 0x0024 /* data mapping lsb configuration register 4 */
+#define LVDS_DMMCR4 0x0028 /* data mapping msb configuration register 4 */
+#define LVDS_DMLCR(id) (LVDS_DMLCR0 + 8U * (id))
+#define LVDS_DMMCR(id) (LVDS_DMMCR0 + 8U * (id))
+#define LVDS_CDL1CR 0x002C /* channel distrib link 1 configuration register */
+#define LVDS_CDL2CR 0x0030 /* channel distrib link 2 configuration register */
+
+#define CDL1CR_DEFAULT 0x4321
+#define CDL2CR_DEFAULT 0x59876
+
+/* LVDS Host registers */
+#define LVDS_PHY_MASTER 0x0
+#define LVDS_PHY_SLAVE 0x100
+
+/* phy parameter can only be one of those two above */
+#define LVDS_PXGCR(phy) ((phy) + 0x1000) /* Global Control Register */
+#define LVDS_PXCMCR1(phy) ((phy) + 0x100C) /* Current Mode Control Register 1 */
+#define LVDS_PXCMCR2(phy) ((phy) + 0x1010) /* Current Mode Control Register 2 */
+#define LVDS_PXSCR(phy) ((phy) + 0x1020) /* Serial Control Register */
+#define LVDS_PXBCR1(phy) ((phy) + 0x102C) /* Bias Control Register 1 */
+#define LVDS_PXBCR2(phy) ((phy) + 0x1030) /* Bias Control Register 2 */
+#define LVDS_PXBCR3(phy) ((phy) + 0x1034) /* Bias Control Register 3 */
+#define LVDS_PXMPLCR(phy) ((phy) + 0x1064) /* Monitor PLL Lock Control Register */
+#define LVDS_PXDCR(phy) ((phy) + 0x1084) /* Debug Control Register */
+#define LVDS_PXSSR1(phy) ((phy) + 0x1088) /* Spare Status Register 1 */
+#define LVDS_PXCFGCR(phy) ((phy) + 0x10A0) /* Configuration Control Register */
+#define LVDS_PXPLLCR1(phy) ((phy) + 0x10C0) /* PLL_MODE 1 Control Register */
+#define LVDS_PXPLLCR2(phy) ((phy) + 0x10C4) /* PLL_MODE 2 Control Register */
+#define LVDS_PXPLLSR(phy) ((phy) + 0x10C8) /* PLL Status Register */
+#define LVDS_PXPLLSDCR1(phy) ((phy) + 0x10CC) /* PLL_SD_1 Control Register */
+#define LVDS_PXPLLSDCR2(phy) ((phy) + 0x10D0) /* PLL_SD_2 Control Register */
+#define LVDS_PXPLLTWGCR1(phy) ((phy) + 0x10D4) /* PLL_TWG_1 Control Register */
+#define LVDS_PXPLLTWGCR2(phy) ((phy) + 0x10D8) /* PLL_TWG_2 Control Register */
+#define LVDS_PXPLLCPCR(phy) ((phy) + 0x10E0) /* PLL_CP Control Register */
+#define LVDS_PXPLLTESTCR(phy) ((phy) + 0x10E8) /* PLL_TEST Control Register */
+
+/* LVDS Wrapper registers */
+#define LVDS_WCLKCR 0x11B0 /* Wrapper clock control register */
+#define LVDS_HWCFGR 0x1FF0 /* HW configuration register */
+#define LVDS_VERR 0x1FF4 /* Version register */
+#define LVDS_IPIDR 0x1FF8 /* Identification register */
+#define LVDS_SIDR 0x1FFC /* Size Identification register */
+
+#define CR_LVDSEN BIT(0) /* LVDS PHY Enable */
+#define CR_HSPOL BIT(1) /* HS Polarity (horizontal sync) */
+#define CR_VSPOL BIT(2) /* VS Polarity (vertical sync) */
+#define CR_DEPOL BIT(3) /* DE Polarity (data enable) */
+#define CR_CI BIT(4) /* Control Internal (software controlled bit) */
+#define CR_LKMOD BIT(5) /* Link Mode, for both Links */
+#define CR_LKPHA BIT(6) /* Link Phase, for both Links */
+#define CR_LK1POL GENMASK(20, 16) /* Link-1 output Polarity */
+#define CR_LK2POL GENMASK(25, 21) /* Link-2 output Polarity */
+
+#define DMMCRX_MAP0 GENMASK(4, 0)
+#define DMMCRX_MAP1 GENMASK(9, 5)
+#define DMMCRX_MAP2 GENMASK(14, 10)
+#define DMMCRX_MAP3 GENMASK(19, 15)
+#define DMLCRX_MAP4 GENMASK(4, 0)
+#define DMLCRX_MAP5 GENMASK(9, 5)
+#define DMLCRX_MAP6 GENMASK(14, 10)
+
+#define CDLCRX_DISTR0 GENMASK(3, 0)
+#define CDLCRX_DISTR1 GENMASK(7, 4)
+#define CDLCRX_DISTR2 GENMASK(11, 8)
+#define CDLCRX_DISTR3 GENMASK(15, 12)
+#define CDLCRX_DISTR4 GENMASK(19, 16)
+
+#define FREF_INDEX 0
+#define NDIV_INDEX 1
+#define FPFD_INDEX 2
+#define MDIV_INDEX 3
+#define FVCO_INDEX 4
+#define BDIV_INDEX 5
+#define FBIT_INDEX 6
+#define FLS_INDEX 7
+#define FDP_INDEX 8
+
+#define PXGCR_BIT_CLK_OUT BIT(0)
+#define PXGCR_LS_CLK_OUT BIT(4)
+#define PXGCR_DP_CLK_OUT BIT(8)
+#define PXGCR_RSTZ BIT(24)
+#define PXGCR_DIV_RSTN BIT(25)
+
+#define PXCMCR1_CM_EN_DL (BIT(28) | BIT(20) | BIT(12) | BIT(4))
+#define PXCMCR2_CM_EN_DL4 BIT(4)
+#define PXSCR_SER_DATA_OK BIT(16)
+#define PXBCR1_EN_BIAS_DL (BIT(16) | BIT(12) | BIT(8) | BIT(4) | BIT(0))
+#define PXBCR2_BIAS_EN BIT(28)
+#define PXBCR3_VM_EN_DL (BIT(16) | BIT(12) | BIT(8) | BIT(4) | BIT(0))
+#define PXDCR_POWER_OK BIT(12)
+#define PXCFGCR_EN_DIG_DL GENMASK(4, 0)
+
+#define PXPLLCR1_PLL_EN BIT(0)
+#define PxPLLCR1_SD_EN BIT(1)
+#define PXPLLCR1_TWG_EN BIT(2)
+#define PXPLLCR1_PLL_DIVIDERS_EN BIT(8)
+#define PXPLLCR2_NDIV GENMASK(25, 16)
+#define PXPLLCR2_BDIV GENMASK(9, 0)
+#define PXPLLSR_PLL_LOCK BIT(0)
+#define PXPLLSDCR1_MDIV GENMASK(9, 0)
+#define PXPLLCPCR_CPCTRL_DEFAULT 0x1
+#define PXPLLTESTCR_PLL_TEST_CLK_EN BIT(0)
+#define PXPLLTESTCR_PLL_TDIV_EN BIT(8)
+#define PXPLLTESTCR_TDIV GENMASK(25, 16)
+#define PXPLLTESTCR_TDIV_VALUE 70
+
+#define WCLKCR_SLV_CLKPIX_SEL BIT(0)
+#define WCLKCR_SRCSEL BIT(8)
+
+/* Sleep & timeout for pll lock/unlock */
+#define SLEEP_US 1000
+#define TIMEOUT_US 20000000
+
+#define PHY_SLV_OFS 0x100
+
+/* PLL parameters */
+#define NDIV_MIN 2
+#define NDIV_MAX 6
+#define BDIV_MIN 2
+#define BDIV_MAX 6
+#define MDIV_MIN 1
+#define MDIV_MAX 1023
+
+struct stm32_lvds_plat {
+ void __iomem *base;
+ struct udevice *panel;
+ struct reset_ctl rst;
+ struct clk pclk;
+ struct clk refclk;
+};
+
+struct stm32_lvds_priv {
+ struct display_timing timings;
+ u32 refclk_rate;
+ int dual_link;
+ int bus_format;
+};
+
+/*
+ * enum lvds_pixels_order - Pixel order of an LVDS connection
+ * @LVDS_DUAL_LINK_EVEN_ODD_PIXELS: Even pixels are expected to be generated
+ * from the first port, odd pixels from the second port
+ * @LVDS_DUAL_LINK_ODD_EVEN_PIXELS: Odd pixels are expected to be generated
+ * from the first port, even pixels from the second port
+ */
+enum lvds_pixels_order {
+ LVDS_DUAL_LINK_EVEN_ODD_PIXELS = BIT(0),
+ LVDS_DUAL_LINK_ODD_EVEN_PIXELS = BIT(1),
+};
+
+enum lvds_pixel {
+ PIX_R_0 = 0x00,
+ PIX_R_1 = 0x01,
+ PIX_R_2 = 0x02,
+ PIX_R_3 = 0x03,
+ PIX_R_4 = 0x04,
+ PIX_R_5 = 0x05,
+ PIX_R_6 = 0x06,
+ PIX_R_7 = 0x07,
+ PIX_G_0 = 0x08,
+ PIX_G_1 = 0x09,
+ PIX_G_2 = 0x0A,
+ PIX_G_3 = 0x0B,
+ PIX_G_4 = 0x0C,
+ PIX_G_5 = 0x0D,
+ PIX_G_6 = 0x0E,
+ PIX_G_7 = 0x0F,
+ PIX_B_0 = 0x10,
+ PIX_B_1 = 0x11,
+ PIX_B_2 = 0x12,
+ PIX_B_3 = 0x13,
+ PIX_B_4 = 0x14,
+ PIX_B_5 = 0x15,
+ PIX_B_6 = 0x16,
+ PIX_B_7 = 0x17,
+ PIX_H_S = 0x18,
+ PIX_V_S = 0x19,
+ PIX_D_E = 0x1A,
+ PIX_C_E = 0x1B,
+ PIX_C_I = 0x1C,
+ PIX_TOG = 0x1D,
+ PIX_ONE = 0x1E,
+ PIX_ZER = 0x1F,
+};
+
+/*
+ * Expected JEIDA-RGB888 data to be sent in LSB format
+ * bit6 ............................bit0
+ */
+const enum lvds_pixel lvds_bitmap_jeida_rgb888[5][7] = {
+ { PIX_ONE, PIX_ONE, PIX_ZER, PIX_ZER, PIX_ZER, PIX_ONE, PIX_ONE },
+ { PIX_G_2, PIX_R_7, PIX_R_6, PIX_R_5, PIX_R_4, PIX_R_3, PIX_R_2 },
+ { PIX_B_3, PIX_B_2, PIX_G_7, PIX_G_6, PIX_G_5, PIX_G_4, PIX_G_3 },
+ { PIX_D_E, PIX_V_S, PIX_H_S, PIX_B_7, PIX_B_6, PIX_B_5, PIX_B_4 },
+ { PIX_C_E, PIX_B_1, PIX_B_0, PIX_G_1, PIX_G_0, PIX_R_1, PIX_R_0 }
+};
+
+/*
+ * Expected VESA-RGB888 data to be sent in LSB format
+ * bit6 ............................bit0
+ */
+const enum lvds_pixel lvds_bitmap_vesa_rgb888[5][7] = {
+ { PIX_ONE, PIX_ONE, PIX_ZER, PIX_ZER, PIX_ZER, PIX_ONE, PIX_ONE },
+ { PIX_G_0, PIX_R_5, PIX_R_4, PIX_R_3, PIX_R_2, PIX_R_1, PIX_R_0 },
+ { PIX_B_1, PIX_B_0, PIX_G_5, PIX_G_4, PIX_G_3, PIX_G_2, PIX_G_1 },
+ { PIX_D_E, PIX_V_S, PIX_H_S, PIX_B_5, PIX_B_4, PIX_B_3, PIX_B_2 },
+ { PIX_C_E, PIX_B_7, PIX_B_6, PIX_G_7, PIX_G_6, PIX_R_7, PIX_R_6 }
+};
+
+static inline void lvds_writel(void __iomem *base, u32 reg, u32 val)
+{
+ writel(val, base + reg);
+}
+
+static inline u32 lvds_readl(void __iomem *base, u32 reg)
+{
+ return readl(base + reg);
+}
+
+static inline void lvds_set(void __iomem *base, u32 reg, u32 mask)
+{
+ lvds_writel(base, reg, lvds_readl(base, reg) | mask);
+}
+
+static inline void lvds_clear(void __iomem *base, u32 reg, u32 mask)
+{
+ lvds_writel(base, reg, lvds_readl(base, reg) & ~mask);
+}
+
+static u32 pll_get_clkout_khz(u32 clkin_khz, u32 bdiv, u32 mdiv, u32 ndiv)
+{
+ int divisor = ndiv * bdiv;
+
+ /* Prevents from division by 0 */
+ if (!divisor)
+ return 0;
+
+ return clkin_khz * mdiv / divisor;
+}
+
+static int lvds_pll_get_params(u32 clkin_khz, u32 clkout_khz,
+ u32 *bdiv, u32 *mdiv, u32 *ndiv)
+{
+ u32 i, o, n;
+ u32 delta, best_delta; /* all in khz */
+
+ /* Early checks preventing division by 0 & odd results */
+ if (clkin_khz == 0 || clkout_khz == 0)
+ return -EINVAL;
+
+ best_delta = 1000000; /* big started value (1000000khz) */
+
+ for (i = NDIV_MIN; i <= NDIV_MAX; i++) {
+ for (o = BDIV_MIN; o <= BDIV_MAX; o++) {
+ n = DIV_ROUND_CLOSEST(i * o * clkout_khz, clkin_khz);
+ /* Check ndiv according to vco range */
+ if (n < MDIV_MIN || n > MDIV_MAX)
+ continue;
+ /* Check if new delta is better & saves parameters */
+ delta = abs(pll_get_clkout_khz(clkin_khz, i, n, o) - clkout_khz);
+ if (delta < best_delta) {
+ *ndiv = i;
+ *mdiv = n;
+ *bdiv = o;
+ best_delta = delta;
+ }
+ /* fast return in case of "perfect result" */
+ if (!delta)
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static int stm32_lvds_pll_enable(struct udevice *dev,
+ int phy)
+{
+ struct stm32_lvds_plat *plat = dev_get_plat(dev);
+ struct stm32_lvds_priv *priv = dev_get_priv(dev);
+ struct display_timing timings = priv->timings;
+ u32 pll_in_khz, bdiv = 0, mdiv = 0, ndiv = 0;
+ int ret, val, multiplier;
+
+ /* Release PHY from reset */
+ lvds_set(plat->base, LVDS_PXGCR(phy), PXGCR_DIV_RSTN | PXGCR_RSTZ);
+
+ /* lvds_pll_config */
+ /* Set PLL Slv & Mst configs and timings */
+ pll_in_khz = priv->refclk_rate / 1000;
+
+ if (priv->dual_link)
+ multiplier = 2;
+ else
+ multiplier = 1;
+
+ ret = lvds_pll_get_params(pll_in_khz, timings.pixelclock.typ * 7 / 1000 / multiplier,
+ &bdiv, &mdiv, &ndiv);
+ if (ret)
+ return ret;
+
+ /* Set PLL parameters */
+ lvds_writel(plat->base, LVDS_PXPLLCR2(phy), (ndiv << 16) | bdiv);
+ lvds_writel(plat->base, LVDS_PXPLLSDCR1(phy), mdiv);
+ lvds_writel(plat->base, LVDS_PXPLLTESTCR(phy), PXPLLTESTCR_TDIV_VALUE << 16);
+
+ /* Disable TWG and SD: for now, PLL just need to be in integer mode */
+ lvds_clear(plat->base, LVDS_PXPLLCR1(phy), PXPLLCR1_TWG_EN | PxPLLCR1_SD_EN);
+
+ /* Power up bias and PLL dividers */
+ lvds_set(plat->base, LVDS_PXDCR(phy), PXDCR_POWER_OK);
+
+ lvds_set(plat->base, LVDS_PXCMCR1(phy), PXCMCR1_CM_EN_DL);
+ lvds_set(plat->base, LVDS_PXCMCR2(phy), PXCMCR2_CM_EN_DL4);
+
+ lvds_set(plat->base, LVDS_PXPLLCPCR(phy), PXPLLCPCR_CPCTRL_DEFAULT);
+ lvds_set(plat->base, LVDS_PXBCR3(phy), PXBCR3_VM_EN_DL);
+ lvds_set(plat->base, LVDS_PXBCR1(phy), PXBCR1_EN_BIAS_DL);
+ lvds_set(plat->base, LVDS_PXCFGCR(phy), PXCFGCR_EN_DIG_DL);
+
+ /* lvds_pll_enable */
+ /* PLL lock timing control for the monitor unmask after startup (pll_en) */
+ /* Adjust the value so that the masking window is opened at start-up */
+ /* MST_MON_PLL_LOCK_UNMASK_TUNE */
+ lvds_writel(plat->base, LVDS_PXMPLCR(phy), (0x200 - 0x160) << 16);
+
+ lvds_writel(plat->base, LVDS_PXBCR2(phy), PXBCR2_BIAS_EN);
+
+ lvds_set(plat->base, LVDS_PXGCR(phy),
+ PXGCR_DP_CLK_OUT | PXGCR_LS_CLK_OUT | PXGCR_BIT_CLK_OUT);
+
+ lvds_set(plat->base, LVDS_PXPLLTESTCR(phy), PXPLLTESTCR_PLL_TDIV_EN);
+ lvds_set(plat->base, LVDS_PXPLLCR1(phy), PXPLLCR1_PLL_DIVIDERS_EN);
+ lvds_set(plat->base, LVDS_PXSCR(phy), PXSCR_SER_DATA_OK);
+
+ /* Enable the LVDS PLL & wait for its lock */
+ lvds_set(plat->base, LVDS_PXPLLCR1(phy), PXPLLCR1_PLL_EN);
+ ret = readl_poll_sleep_timeout(plat->base + LVDS_PXPLLSR(phy),
+ val, val & PXPLLSR_PLL_LOCK, SLEEP_US, TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ /* Select MST PHY clock as pixel clock for the LDITX instead of FREF */
+ /* WCLKCR_SLV_CLKPIX_SEL is for dual link */
+ lvds_writel(plat->base, LVDS_WCLKCR, WCLKCR_SLV_CLKPIX_SEL);
+
+ lvds_set(plat->base, LVDS_PXPLLTESTCR(phy), PXPLLTESTCR_PLL_TEST_CLK_EN);
+
+ return 0;
+}
+
+static int stm32_lvds_enable(struct udevice *dev)
+{
+ struct stm32_lvds_plat *plat = dev_get_plat(dev);
+ struct stm32_lvds_priv *priv = dev_get_priv(dev);
+ struct display_timing timings = priv->timings;
+ u32 lvds_cdl1cr = 0;
+ u32 lvds_cdl2cr = 0;
+ u32 lvds_dmlcr = 0;
+ u32 lvds_dmmcr = 0;
+ u32 lvds_cr = 0;
+ int i;
+
+ lvds_clear(plat->base, LVDS_CDL1CR, CDLCRX_DISTR0 | CDLCRX_DISTR1 | CDLCRX_DISTR2
+ | CDLCRX_DISTR3 | CDLCRX_DISTR4);
+ lvds_clear(plat->base, LVDS_CDL2CR, CDLCRX_DISTR0 | CDLCRX_DISTR1 | CDLCRX_DISTR2
+ | CDLCRX_DISTR3 | CDLCRX_DISTR4);
+
+ /* Set channel distribution */
+ lvds_cr &= ~CR_LKMOD;
+ lvds_cdl1cr = CDL1CR_DEFAULT;
+
+ if (priv->dual_link) {
+ lvds_cr |= CR_LKMOD;
+ lvds_cdl2cr = CDL2CR_DEFAULT;
+ }
+
+ /* Set signal polarity */
+ if (timings.flags & DISPLAY_FLAGS_DE_LOW)
+ lvds_cr |= CR_DEPOL;
+
+ if (timings.flags & DISPLAY_FLAGS_HSYNC_LOW)
+ lvds_cr |= CR_HSPOL;
+
+ if (timings.flags & DISPLAY_FLAGS_VSYNC_LOW)
+ lvds_cr |= CR_VSPOL;
+
+ /* Set link phase */
+ switch (priv->dual_link) {
+ case LVDS_DUAL_LINK_EVEN_ODD_PIXELS: /* LKPHA = 0 */
+ lvds_cr &= ~CR_LKPHA;
+ break;
+ case LVDS_DUAL_LINK_ODD_EVEN_PIXELS: /* LKPHA = 1 */
+ lvds_cr |= CR_LKPHA;
+ break;
+ default:
+ dev_dbg(dev, "No phase precised, setting default\n");
+ lvds_cr &= ~CR_LKPHA;
+ break;
+ }
+
+ /* Set Data Mapping */
+ switch (priv->bus_format) {
+ case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: /* VESA-RGB888 */
+ for (i = 0; i < 5; i++) {
+ lvds_dmlcr = ((lvds_bitmap_vesa_rgb888[i][0])
+ + (lvds_bitmap_vesa_rgb888[i][1] << 5)
+ + (lvds_bitmap_vesa_rgb888[i][2] << 10)
+ + (lvds_bitmap_vesa_rgb888[i][3] << 15));
+ lvds_dmmcr = ((lvds_bitmap_vesa_rgb888[i][4])
+ + (lvds_bitmap_vesa_rgb888[i][5] << 5)
+ + (lvds_bitmap_vesa_rgb888[i][6] << 10));
+
+ /* Write registers at the end of computations */
+ lvds_writel(plat->base, LVDS_DMLCR(i), lvds_dmlcr);
+ lvds_writel(plat->base, LVDS_DMMCR(i), lvds_dmmcr);
+ }
+ break;
+ case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: /* JEIDA-RGB888 */
+ for (i = 0; i < 5; i++) {
+ lvds_dmlcr = ((lvds_bitmap_jeida_rgb888[i][0])
+ + (lvds_bitmap_jeida_rgb888[i][1] << 5)
+ + (lvds_bitmap_jeida_rgb888[i][2] << 10)
+ + (lvds_bitmap_jeida_rgb888[i][3] << 15));
+ lvds_dmmcr = ((lvds_bitmap_jeida_rgb888[i][4])
+ + (lvds_bitmap_jeida_rgb888[i][5] << 5)
+ + (lvds_bitmap_jeida_rgb888[i][6] << 10));
+
+ /* Write registers at the end of computations */
+ lvds_writel(plat->base, LVDS_DMLCR(i), lvds_dmlcr);
+ lvds_writel(plat->base, LVDS_DMMCR(i), lvds_dmmcr);
+ }
+ break;
+ default:
+ dev_dbg(dev, "Unsupported LVDS bus format 0x%04x\n", priv->bus_format);
+ }
+
+ /* Turn the output on */
+ lvds_cr |= CR_LVDSEN;
+
+ /* Commit config to registers */
+ lvds_set(plat->base, LVDS_CR, lvds_cr);
+ lvds_writel(plat->base, LVDS_CDL1CR, lvds_cdl1cr);
+ lvds_writel(plat->base, LVDS_CDL2CR, lvds_cdl2cr);
+
+ return 0;
+}
+
+static int stm32_lvds_attach(struct udevice *dev)
+{
+ struct stm32_lvds_plat *plat = dev_get_plat(dev);
+ struct stm32_lvds_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = panel_get_display_timing(plat->panel, &priv->timings);
+ if (ret) {
+ ret = ofnode_decode_display_timing(dev_ofnode(plat->panel),
+ 0, &priv->timings);
+ if (ret) {
+ dev_err(dev, "decode display timing error %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = stm32_lvds_enable(dev);
+
+ return ret;
+}
+
+static int stm32_lvds_set_backlight(struct udevice *dev, int percent)
+{
+ struct stm32_lvds_plat *plat = dev_get_plat(dev);
+ int ret;
+
+ ret = panel_enable_backlight(plat->panel);
+ if (ret) {
+ dev_err(dev, "panel %s enable backlight error %d\n",
+ plat->panel->name, ret);
+ }
+
+ return ret;
+}
+
+static int lvds_handle_pixel_order(struct stm32_lvds_plat *plat)
+{
+ ofnode parent, panel_port0, panel_port1;
+ bool even_pixels, odd_pixels;
+ int port0, port1;
+
+ /*
+ * In case we are operating in single link,
+ * there is only one port linked to the LVDS.
+ * Check whether we are in this case and exit if yes.
+ */
+ parent = ofnode_find_subnode(dev_ofnode(plat->panel), "ports");
+ if (!ofnode_valid(parent))
+ return 0;
+
+ panel_port0 = ofnode_first_subnode(parent);
+ if (!ofnode_valid(panel_port0))
+ return -EPIPE;
+
+ even_pixels = ofnode_read_bool(panel_port0, "dual-lvds-even-pixels");
+ odd_pixels = ofnode_read_bool(panel_port0, "dual-lvds-odd-pixels");
+ if (even_pixels && odd_pixels)
+ return -EINVAL;
+
+ port0 = even_pixels ? LVDS_DUAL_LINK_EVEN_ODD_PIXELS :
+ LVDS_DUAL_LINK_ODD_EVEN_PIXELS;
+
+ panel_port1 = ofnode_next_subnode(panel_port0);
+ if (!ofnode_valid(panel_port1))
+ return -EPIPE;
+
+ even_pixels = ofnode_read_bool(panel_port1, "dual-lvds-even-pixels");
+ odd_pixels = ofnode_read_bool(panel_port1, "dual-lvds-odd-pixels");
+ if (even_pixels && odd_pixels)
+ return -EINVAL;
+
+ port1 = even_pixels ? LVDS_DUAL_LINK_EVEN_ODD_PIXELS :
+ LVDS_DUAL_LINK_ODD_EVEN_PIXELS;
+
+ /*
+ * A valid dual-LVDS bus is found when one port is marked with
+ * "dual-lvds-even-pixels", and the other port is marked with
+ * "dual-lvds-odd-pixels", bail out if the markers are not right.
+ */
+ if (port0 + port1 != LVDS_DUAL_LINK_EVEN_ODD_PIXELS + LVDS_DUAL_LINK_ODD_EVEN_PIXELS)
+ return -EINVAL;
+
+ return port0;
+}
+
+static int stm32_lvds_of_to_plat(struct udevice *dev)
+{
+ struct stm32_lvds_plat *plat = dev_get_plat(dev);
+ struct stm32_lvds_priv *priv = dev_get_priv(dev);
+ const char *data_mapping;
+ int ret;
+
+ plat->base = dev_read_addr_ptr(dev);
+ if ((fdt_addr_t)plat->base == FDT_ADDR_T_NONE) {
+ dev_err(dev, "Unable to read LVDS base address\n");
+ return -EINVAL;
+ }
+
+ ret = clk_get_by_name(dev, "pclk", &plat->pclk);
+ if (ret) {
+ dev_err(dev, "Unable to get peripheral clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_get_by_name(dev, "ref", &plat->refclk);
+ if (ret) {
+ dev_err(dev, "Unable to get reference clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = reset_get_by_index(dev, 0, &plat->rst);
+ if (ret) {
+ dev_err(dev, "Failed to get LVDS reset: %d\n", ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_driver(UCLASS_PANEL,
+ DM_DRIVER_GET(simple_panel), &plat->panel);
+ if (ret) {
+ dev_err(dev, "panel device error %d\n", ret);
+ return ret;
+ }
+
+ ret = panel_get_display_timing(plat->panel, &priv->timings);
+ if (ret) {
+ ret = ofnode_decode_display_timing(dev_ofnode(plat->panel),
+ 0, &priv->timings);
+ if (ret) {
+ dev_err(dev, "decode display timing error %d\n", ret);
+ return ret;
+ }
+ }
+
+ data_mapping = ofnode_read_string(dev_ofnode(plat->panel), "data-mapping");
+ if (!strcmp(data_mapping, "vesa-24"))
+ priv->bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG;
+ else if (!strcmp(data_mapping, "jeida-24"))
+ priv->bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA;
+ else
+ priv->bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG;
+
+ return 0;
+}
+
+static int stm32_lvds_probe(struct udevice *dev)
+{
+ struct stm32_lvds_plat *plat = dev_get_plat(dev);
+ struct stm32_lvds_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = clk_enable(&plat->pclk);
+ if (ret) {
+ dev_err(dev, "Failed to enable peripheral clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_enable(&plat->refclk);
+ if (ret) {
+ dev_err(dev, "Failed to enable reference clock: %d\n", ret);
+ goto err_clk;
+ }
+
+ priv->refclk_rate = (unsigned int)clk_get_rate(&plat->refclk);
+
+ reset_deassert(&plat->rst);
+
+ /* Handle dual link config */
+ priv->dual_link = lvds_handle_pixel_order(plat);
+ if (priv->dual_link < 0)
+ goto err_rst;
+
+ if (priv->dual_link > 0) {
+ ret = stm32_lvds_pll_enable(dev, LVDS_PHY_SLAVE);
+ if (ret)
+ goto err_rst;
+ }
+
+ ret = stm32_lvds_pll_enable(dev, LVDS_PHY_MASTER);
+ if (ret)
+ goto err_rst;
+
+ return 0;
+
+err_rst:
+ clk_disable(&plat->refclk);
+err_clk:
+ clk_disable(&plat->pclk);
+
+ return ret;
+}
+
+static const struct video_bridge_ops stm32_lvds_ops = {
+ .attach = stm32_lvds_attach,
+ .set_backlight = stm32_lvds_set_backlight,
+};
+
+static const struct udevice_id stm32_lvds_ids[] = {
+ {.compatible = "st,stm32mp25-lvds"},
+ {}
+};
+
+U_BOOT_DRIVER(stm32_lvds) = {
+ .name = "stm32-display-lvds",
+ .id = UCLASS_VIDEO_BRIDGE,
+ .of_match = stm32_lvds_ids,
+ .ops = &stm32_lvds_ops,
+ .of_to_plat = stm32_lvds_of_to_plat,
+ .probe = stm32_lvds_probe,
+ .plat_auto = sizeof(struct stm32_lvds_plat),
+ .priv_auto = sizeof(struct stm32_lvds_priv),
+};
diff --git a/drivers/video/tegra/tegra124/dp.c b/drivers/video/tegra/tegra124/dp.c
index b95b14da77d..611bf2f81a6 100644
--- a/drivers/video/tegra/tegra124/dp.c
+++ b/drivers/video/tegra/tegra124/dp.c
@@ -1515,7 +1515,6 @@ int tegra_dp_enable(struct udevice *dev, int panel_bpp,
if (ret || retry >= DP_POWER_ON_MAX_TRIES) {
debug("dp: failed to power on panel (0x%x)\n", ret);
return -ENETUNREACH;
- goto error_enable;
}
/* Confirm DP plugging status */
@@ -1561,7 +1560,6 @@ int tegra_dp_enable(struct udevice *dev, int panel_bpp,
}
priv->enabled = true;
-error_enable:
return 0;
}
diff --git a/drivers/video/tegra/tegra124/sor.c b/drivers/video/tegra/tegra124/sor.c
index 1ce5330c6bc..ccdeefbcbb1 100644
--- a/drivers/video/tegra/tegra124/sor.c
+++ b/drivers/video/tegra/tegra124/sor.c
@@ -336,7 +336,7 @@ static int tegra_dc_sor_io_set_dpd(struct tegra_dc_sor_data *sor, int up)
}
reg_val = readl(pmc_base + APBDEV_PMC_IO_DPD2_REQ);
- reg_val &= ~(APBDEV_PMC_IO_DPD2_REQ_LVDS_ON ||
+ reg_val &= ~(APBDEV_PMC_IO_DPD2_REQ_LVDS_ON |
APBDEV_PMC_IO_DPD2_REQ_CODE_DEFAULT_MASK);
reg_val = up ? APBDEV_PMC_IO_DPD2_REQ_LVDS_ON |
diff --git a/drivers/video/zynqmp/zynqmp_dpsub.c b/drivers/video/zynqmp/zynqmp_dpsub.c
index 52af23c3c83..a0efd3393f5 100644
--- a/drivers/video/zynqmp/zynqmp_dpsub.c
+++ b/drivers/video/zynqmp/zynqmp_dpsub.c
@@ -240,7 +240,6 @@ static void avbuf_video_select(struct udevice *dev, enum av_buf_video_stream vid
static void config_gfx_pipeline(struct udevice *dev)
{
struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev);
- u16 *csc_matrix, *offset_matrix;
u32 regval = 0, index = 0, *scaling_factors = NULL;
u16 rgb_coeffs[] = { 0x1000, 0x0000, 0x0000,
0x0000, 0x1000, 0x0000,
@@ -262,19 +261,18 @@ static void config_gfx_pipeline(struct udevice *dev)
video->sampling_en;
writel(regval, dp_sub->base_addr + AVBUF_V_BLEND_LAYER1_CONTROL);
- if (video->is_rgb) {
- csc_matrix = rgb_coeffs;
- offset_matrix = rgb_offset;
- }
+ if (!video->is_rgb)
+ return;
+
/* Program Colorspace conversion coefficients */
for (index = 9; index < 12; index++) {
- writel(offset_matrix[index - 9], dp_sub->base_addr +
+ writel(rgb_offset[index - 9], dp_sub->base_addr +
AVBUF_V_BLEND_IN2CSC_COEFF0 + (index * 4));
}
/* Program Colorspace conversion matrix */
for (index = 0; index < 9; index++) {
- writel(csc_matrix[index], dp_sub->base_addr +
+ writel(rgb_coeffs[index], dp_sub->base_addr +
AVBUF_V_BLEND_IN2CSC_COEFF0 + (index * 4));
}
}
diff --git a/drivers/virtio/virtio-uclass.c b/drivers/virtio/virtio-uclass.c
index 1dbc1a56aa2..ac563991b90 100644
--- a/drivers/virtio/virtio-uclass.c
+++ b/drivers/virtio/virtio-uclass.c
@@ -328,7 +328,7 @@ static int virtio_uclass_child_pre_probe(struct udevice *vdev)
debug("(%s): legacy virtio device\n", vdev->name);
uc_priv->features = driver_features_legacy & device_features;
} else {
- debug("(%s): v1.0 complaint virtio device\n", vdev->name);
+ debug("(%s): v1.0 compliant virtio device\n", vdev->name);
uc_priv->features = driver_features & device_features;
}
diff --git a/drivers/virtio/virtio_blk.c b/drivers/virtio/virtio_blk.c
index 4224e3c17f4..3dd0cf36268 100644
--- a/drivers/virtio/virtio_blk.c
+++ b/drivers/virtio/virtio_blk.c
@@ -16,7 +16,7 @@
#include "virtio_blk.h"
/**
- * struct virtio_blk_priv - private date for virtio block device
+ * struct virtio_blk_priv - private data for virtio block device
*/
struct virtio_blk_priv {
/** @virtqueue - virtqueue to process */
@@ -26,6 +26,7 @@ struct virtio_blk_priv {
};
static const u32 feature[] = {
+ VIRTIO_BLK_F_BLK_SIZE,
VIRTIO_BLK_F_WRITE_ZEROES
};
@@ -194,7 +195,7 @@ static int virtio_blk_probe(struct udevice *dev)
virtio_cread(dev, struct virtio_blk_config, capacity, &cap);
desc->lba = cap;
- if (!virtio_has_feature(dev, VIRTIO_BLK_F_BLK_SIZE)) {
+ if (virtio_has_feature(dev, VIRTIO_BLK_F_BLK_SIZE)) {
virtio_cread(dev, struct virtio_blk_config, blk_size, &blk_size);
desc->blksz = blk_size;
if (!is_power_of_2(blk_size) || desc->blksz < 512)
diff --git a/drivers/w1-eeprom/ds24xxx.c b/drivers/w1-eeprom/ds24xxx.c
index 413d8bc5881..801fade6f49 100644
--- a/drivers/w1-eeprom/ds24xxx.c
+++ b/drivers/w1-eeprom/ds24xxx.c
@@ -53,7 +53,7 @@ U_BOOT_DRIVER(ds24xxx) = {
.probe = ds24xxx_probe,
};
-u8 family_supported[] = {
+static u8 family_supported[] = {
W1_FAMILY_DS24B33,
W1_FAMILY_DS2431,
};
diff --git a/drivers/w1-eeprom/ds2502.c b/drivers/w1-eeprom/ds2502.c
index db9f41e9726..981b41a34b2 100644
--- a/drivers/w1-eeprom/ds2502.c
+++ b/drivers/w1-eeprom/ds2502.c
@@ -243,7 +243,7 @@ U_BOOT_DRIVER(ds2502) = {
.probe = ds2502_probe,
};
-u8 family_supported[] = {
+static u8 family_supported[] = {
W1_FAMILY_DS2502,
};
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 9e149a75e81..35ae7d106b1 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -44,6 +44,7 @@ config HW_WATCHDOG
config IMX_WATCHDOG
bool "Enable Watchdog Timer support for IMX and LSCH2 of NXP"
+ depends on MACH_IMX
select HW_WATCHDOG if !WDT
help
Select this to enable the IMX and LSCH2 of Layerscape watchdog
@@ -65,6 +66,7 @@ config OMAP_WATCHDOG
config ULP_WATCHDOG
bool "i.MX7ULP watchdog"
+ depends on MACH_IMX
help
Say Y here to enable i.MX7ULP watchdog driver.
@@ -117,8 +119,8 @@ config WDT_ARMADA_37XX
config WDT_ASPEED
bool "Aspeed ast2400/ast2500 watchdog timer support"
- depends on WDT
- default y if ARCH_ASPEED
+ depends on WDT && ARCH_ASPEED
+ default y
help
Select this to enable watchdog timer for Aspeed ast2500/ast2400 devices.
The watchdog timer is stopped when initialized. It performs reset, either
@@ -128,8 +130,8 @@ config WDT_ASPEED
config WDT_AST2600
bool "Aspeed AST2600 watchdog timer support"
- depends on WDT
- default y if ASPEED_AST2600
+ depends on WDT && ASPEED_AST2600
+ default y
help
Select this to enable watchdog timer for Aspeed ast2500/ast2400 devices.
The watchdog timer is stopped when initialized. It performs reset, either
@@ -137,7 +139,7 @@ config WDT_AST2600
config WDT_AT91
bool "AT91 watchdog timer support"
- depends on WDT
+ depends on WDT && ARCH_AT91
help
Select this to enable Microchip watchdog timer, which can be found on
some AT91 devices.
@@ -174,7 +176,7 @@ config WDT_CDNS
config WDT_CORTINA
bool "Cortina Access CAxxxx watchdog timer support"
- depends on WDT
+ depends on WDT && TARGET_PRESIDIO_ASIC
help
Cortina Access CAxxxx watchdog timer support.
This driver support all CPU ISAs supported by Cortina
@@ -188,7 +190,7 @@ config WDT_DA9063
config WDT_DAVINCI
bool "DaVinci watchdog timer support"
- depends on WDT
+ depends on WDT && (ARCH_DAVINCI || ARCH_KEYSTONE)
help
Select this to enable the watchdog timer for DaVinci SoCs such as the
OMAP-L138.
@@ -220,7 +222,7 @@ config WDT_MAX6370
config WDT_MCF
bool "ColdFire family watchdog timer support"
- depends on WDT
+ depends on WDT && M68K
help
Select this to enable ColdFire watchdog timer,
which supports mcf52x2 mcf532x mcf523x families.
@@ -304,7 +306,7 @@ config WDT_OMAP3
config WDT_ORION
bool "Orion watchdog timer support"
- depends on WDT
+ depends on WDT && ARCH_MVEBU
select CLK
help
Select this to enable Orion watchdog timer, which can be found on some
@@ -454,6 +456,12 @@ config WDT_TANGIER
Intel Tangier SoC. If you're using a board with Intel Tangier
SoC, say Y here.
+config WDT_TEGRA
+ bool "Tegra watchdog"
+ depends on WDT && ARCH_TEGRA
+ help
+ Enable support for the watchdog timer found in Tegra SoCs.
+
config WDT_ARM_SMC
bool "ARM SMC watchdog timer support"
depends on WDT && ARM_SMCCC
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index d52d17e1c90..02e2674f8af 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_WDT_STARFIVE) += starfive_wdt.o
obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o
obj-$(CONFIG_WDT_SUNXI) += sunxi_wdt.o
obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o
+obj-$(CONFIG_WDT_TEGRA) += tegra_wdt.o
obj-$(CONFIG_WDT_XILINX) += xilinx_wwdt.o
obj-$(CONFIG_WDT_ADI) += adi_wdt.o
obj-$(CONFIG_WDT_QCOM) += qcom-wdt.o
diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c
new file mode 100644
index 00000000000..adc30da579a
--- /dev/null
+++ b/drivers/watchdog/tegra_wdt.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NVIDIA Tegra Watchdog driver
+ *
+ * Copyright (C) 2025 NABLA Software Engineering
+ * Lukasz Majewski, NABLA Software Engineering, lukma@nabladev.com
+ */
+
+#include <dm.h>
+#include <wdt.h>
+#include <hang.h>
+#include <asm/io.h>
+#include <watchdog.h>
+
+/* Timer registers */
+#define TIMER_PTV 0x0
+#define TIMER_EN BIT(31)
+#define TIMER_PERIODIC BIT(30)
+
+/* WDT registers */
+#define WDT_CFG 0x0
+#define WDT_CFG_PERIOD_SHIFT 4
+#define WDT_CFG_PERIOD_MASK GENMASK(7, 0)
+#define WDT_CFG_INT_EN BIT(12)
+#define WDT_CFG_PMC2CAR_RST_EN BIT(15)
+#define WDT_CMD 0x8
+#define WDT_CMD_START_COUNTER BIT(0)
+#define WDT_CMD_DISABLE_COUNTER BIT(1)
+#define WDT_UNLOCK 0xc
+#define WDT_UNLOCK_PATTERN 0xc45a
+
+/* Use watchdog ID 0 */
+#define WDT_BASE 0x100
+
+/* Use Timer 5 as WDT counter */
+#define WDT_TIMER_BASE 0x60
+#define WDT_TIMER_ID 5
+
+struct tegra_wdt_priv {
+ void __iomem *wdt_base;
+ void __iomem *tmr_base;
+};
+
+static int tegra_wdt_reset(struct udevice *dev)
+{
+ struct tegra_wdt_priv *priv = dev_get_priv(dev);
+
+ writel(WDT_CMD_START_COUNTER, priv->wdt_base + WDT_CMD);
+
+ return 0;
+}
+
+static int tegra_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
+{
+ struct tegra_wdt_priv *priv = dev_get_priv(dev);
+ u32 timeout_sec = timeout / 1000;
+
+ /* Support for timeout from 1 to 255 seconds */
+ if (timeout_sec < 1 || timeout_sec > 255)
+ return -EINVAL;
+
+ /*
+ * Timer for WDT has a fixed 1MHz clock, so for 1 second period one
+ * shall write 1000000ul.
+ *
+ * On Tegra the watchdog reset actually occurs on the 4th expiration
+ * of this counter, so we set the period to 1/4.
+ */
+ writel(TIMER_EN | TIMER_PERIODIC | (1000000ul / 4),
+ priv->tmr_base + TIMER_PTV);
+
+ writel(WDT_CFG_PMC2CAR_RST_EN | (timeout_sec << WDT_CFG_PERIOD_SHIFT) |
+ WDT_TIMER_ID, priv->wdt_base + WDT_CFG);
+
+ writel(WDT_CMD_START_COUNTER, priv->wdt_base + WDT_CMD);
+
+ return 0;
+}
+
+static int tegra_wdt_stop(struct udevice *dev)
+{
+ struct tegra_wdt_priv *priv = dev_get_priv(dev);
+
+ writel(WDT_UNLOCK_PATTERN, priv->wdt_base + WDT_UNLOCK);
+ writel(WDT_CMD_DISABLE_COUNTER, priv->wdt_base + WDT_CMD);
+ writel(0, priv->tmr_base + TIMER_PTV);
+
+ return 0;
+}
+
+static int tegra_wdt_probe(struct udevice *dev)
+{
+ struct tegra_wdt_priv *priv = dev_get_priv(dev);
+ void __iomem *base;
+
+ base = dev_read_addr_ptr(dev);
+ if (!base)
+ return -ENOENT;
+
+ priv->wdt_base = base + WDT_BASE;
+ priv->tmr_base = base + WDT_TIMER_BASE;
+
+ return 0;
+}
+
+static const struct wdt_ops tegra_wdt_ops = {
+ .start = tegra_wdt_start,
+ .stop = tegra_wdt_stop,
+ .reset = tegra_wdt_reset,
+};
+
+U_BOOT_DRIVER(tegra_wdt) = {
+ .name = "tegra_wdt",
+ .id = UCLASS_WDT,
+ .probe = tegra_wdt_probe,
+ .ops = &tegra_wdt_ops,
+ .priv_auto = sizeof(struct tegra_wdt_priv),
+};