summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/adc/Kconfig1
-rw-r--r--drivers/ata/Kconfig18
-rw-r--r--drivers/ata/Makefile3
-rw-r--r--drivers/ata/ahci.c172
-rw-r--r--drivers/ata/ahci_sunxi.c9
-rw-r--r--drivers/ata/dwc_ahsata.c3
-rw-r--r--drivers/ata/fsl_sata.c3
-rw-r--r--drivers/ata/sata.c90
-rw-r--r--drivers/ata/sata_bootdev.c62
-rw-r--r--drivers/ata/sata_mv.c11
-rw-r--r--drivers/ata/sata_sandbox.c33
-rw-r--r--drivers/ata/sata_sil.c3
-rw-r--r--drivers/block/Kconfig10
-rw-r--r--drivers/block/Makefile5
-rw-r--r--drivers/block/blk-uclass.c56
-rw-r--r--drivers/block/blkmap.c31
-rw-r--r--drivers/block/blkmap_helper.c53
-rw-r--r--drivers/block/host-uclass.c15
-rw-r--r--drivers/block/host_dev.c11
-rw-r--r--drivers/block/rkmtd.c1152
-rw-r--r--drivers/bootcount/Kconfig34
-rw-r--r--drivers/bootcount/Makefile2
-rw-r--r--drivers/bootcount/bootcount_dm_i2c.c102
-rw-r--r--drivers/bootcount/bootcount_i2c.c43
-rw-r--r--drivers/clk/Makefile2
-rw-r--r--drivers/clk/at91/clk-main.c2
-rw-r--r--drivers/clk/clk-cdce9xx.c2
-rw-r--r--drivers/clk/clk-uclass.c13
-rw-r--r--drivers/clk/clk_k210.c1
-rw-r--r--drivers/clk/clk_scmi.c27
-rw-r--r--drivers/clk/clk_versal.c1
-rw-r--r--drivers/clk/exynos/clk-pll.h5
-rw-r--r--drivers/clk/imx/Kconfig18
-rw-r--r--drivers/clk/imx/Makefile2
-rw-r--r--drivers/clk/imx/clk-composite-93.c142
-rw-r--r--drivers/clk/imx/clk-fracn-gppll.c382
-rw-r--r--drivers/clk/imx/clk-gate-93.c148
-rw-r--r--drivers/clk/imx/clk-imx93.c343
-rw-r--r--drivers/clk/imx/clk.h42
-rw-r--r--drivers/clk/meson/Kconfig8
-rw-r--r--drivers/clk/meson/Makefile1
-rw-r--r--drivers/clk/meson/a1.c735
-rw-r--r--drivers/clk/renesas/Kconfig9
-rw-r--r--drivers/clk/renesas/Makefile2
-rw-r--r--drivers/clk/renesas/r9a07g044-cpg.c383
-rw-r--r--drivers/clk/renesas/rzg2l-cpg.c504
-rw-r--r--drivers/clk/renesas/rzg2l-cpg.h319
-rw-r--r--drivers/clk/rockchip/clk_pll.c102
-rw-r--r--drivers/clk/rockchip/clk_rk3568.c10
-rw-r--r--drivers/clk/rockchip/clk_rk3588.c35
-rw-r--r--drivers/clk/starfive/clk-jh7110.c10
-rw-r--r--drivers/clk/sunxi/Kconfig7
-rw-r--r--drivers/clk/sunxi/Makefile1
-rw-r--r--drivers/clk/sunxi/clk_d1.c84
-rw-r--r--drivers/clk/sunxi/clk_sunxi.c5
-rw-r--r--drivers/clk/ti/clk-k3-pll.c83
-rw-r--r--drivers/clk/ti/clk-k3.c11
-rw-r--r--drivers/clk/ti/clk-sci.c11
-rw-r--r--drivers/core/Kconfig17
-rw-r--r--drivers/core/Makefile1
-rw-r--r--drivers/core/fdtaddr.c31
-rw-r--r--drivers/core/of_access.c65
-rw-r--r--drivers/core/ofnode.c201
-rw-r--r--drivers/core/read.c27
-rw-r--r--drivers/core/root.c2
-rw-r--r--drivers/core/util.c2
-rw-r--r--drivers/crypto/fsl/Kconfig1
-rw-r--r--drivers/dfu/Kconfig10
-rw-r--r--drivers/dfu/dfu_mmc.c10
-rw-r--r--drivers/dfu/dfu_mtd.c34
-rw-r--r--drivers/dma/Kconfig1
-rw-r--r--drivers/dma/MCD_dmaApi.c1010
-rw-r--r--drivers/dma/MCD_tasks.c2413
-rw-r--r--drivers/dma/MCD_tasksInit.c225
-rw-r--r--drivers/dma/Makefile1
-rw-r--r--drivers/dma/ti/Makefile1
-rw-r--r--drivers/dma/ti/k3-psil-am62a.c196
-rw-r--r--drivers/dma/ti/k3-psil-am64.c2
-rw-r--r--drivers/dma/ti/k3-psil-am654.c2
-rw-r--r--drivers/dma/ti/k3-psil-priv.h3
-rw-r--r--drivers/dma/ti/k3-psil.c4
-rw-r--r--drivers/dma/ti/k3-psil.h2
-rw-r--r--drivers/dma/ti/k3-udma-hwdef.h2
-rw-r--r--drivers/dma/ti/k3-udma.c7
-rw-r--r--drivers/fastboot/Kconfig1
-rw-r--r--drivers/fastboot/fb_common.c14
-rw-r--r--drivers/firmware/arm-ffa/arm-ffa-uclass.c2
-rw-r--r--drivers/firmware/firmware-zynqmp.c2
-rw-r--r--drivers/firmware/scmi/Makefile2
-rw-r--r--drivers/firmware/scmi/base.c664
-rw-r--r--drivers/firmware/scmi/mailbox_agent.c5
-rw-r--r--drivers/firmware/scmi/optee_agent.c7
-rw-r--r--drivers/firmware/scmi/pwdom.c188
-rw-r--r--drivers/firmware/scmi/sandbox-scmi_agent.c756
-rw-r--r--drivers/firmware/scmi/sandbox-scmi_devices.c76
-rw-r--r--drivers/firmware/scmi/scmi_agent-uclass.c423
-rw-r--r--drivers/firmware/scmi/smccc_agent.c5
-rw-r--r--drivers/firmware/ti_sci.c2
-rw-r--r--drivers/firmware/ti_sci.h2
-rw-r--r--drivers/firmware/ti_sci_static_data.h2
-rw-r--r--drivers/fpga/zynqmppl.c2
-rw-r--r--drivers/gpio/Kconfig14
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/axp_gpio.c1
-rw-r--r--drivers/gpio/pcf8575_gpio.c2
-rw-r--r--drivers/gpio/rzg2l-gpio.c169
-rw-r--r--drivers/gpio/sunxi_gpio.c189
-rw-r--r--drivers/gpio/tegra186_gpio.c4
-rw-r--r--drivers/i2c/Makefile2
-rw-r--r--drivers/i2c/designware_i2c.c19
-rw-r--r--drivers/i2c/i2c-emul-uclass.c2
-rw-r--r--drivers/i2c/i2c-uclass.c75
-rw-r--r--drivers/i2c/mvtwsi.c3
-rw-r--r--drivers/i2c/npcm_i2c.c5
-rw-r--r--drivers/i2c/stm32f7_i2c.c11
-rw-r--r--drivers/i2c/sun6i_p2wi.c2
-rw-r--r--drivers/i2c/sun8i_rsb.c2
-rw-r--r--drivers/input/input.c25
-rw-r--r--drivers/mailbox/k3-sec-proxy.c20
-rw-r--r--drivers/memory/Kconfig1
-rw-r--r--drivers/memory/stm32-fmc2-ebi.c5
-rw-r--r--drivers/memory/ti-aemif.c1
-rw-r--r--drivers/memory/ti-gpmc.c2
-rw-r--r--drivers/memory/ti-gpmc.h2
-rw-r--r--drivers/misc/Kconfig1
-rw-r--r--drivers/misc/cros_ec_sandbox.c9
-rw-r--r--drivers/misc/cros_ec_spi.c2
-rw-r--r--drivers/misc/esm_pmic.c2
-rw-r--r--drivers/misc/fs_loader.c2
-rw-r--r--drivers/misc/i2c_eeprom.c21
-rw-r--r--drivers/misc/k3_avs.c106
-rw-r--r--drivers/misc/k3_esm.c2
-rw-r--r--drivers/misc/rockchip-otp.c76
-rw-r--r--drivers/misc/vexpress_config.c5
-rw-r--r--drivers/mmc/Kconfig7
-rw-r--r--drivers/mmc/Makefile1
-rw-r--r--drivers/mmc/am654_sdhci.c2
-rw-r--r--drivers/mmc/mmc-uclass.c2
-rw-r--r--drivers/mmc/octeontx_hsmmc.h2
-rw-r--r--drivers/mmc/pci_mmc.c4
-rw-r--r--drivers/mmc/renesas-sdhi.c98
-rw-r--r--drivers/mmc/sdhci.c19
-rw-r--r--drivers/mmc/sh_sdhi.c910
-rw-r--r--drivers/mmc/sunxi_mmc.c13
-rw-r--r--drivers/mmc/sunxi_mmc.h138
-rw-r--r--drivers/mmc/tegra_mmc.c52
-rw-r--r--drivers/mmc/tmio-common.c8
-rw-r--r--drivers/mtd/Makefile2
-rw-r--r--drivers/mtd/hbmc-am654.c2
-rw-r--r--drivers/mtd/nand/raw/Kconfig35
-rw-r--r--drivers/mtd/nand/raw/Makefile1
-rw-r--r--drivers/mtd/nand/raw/am335x_spl_bch.c8
-rw-r--r--drivers/mtd/nand/raw/atmel/nand-controller.c37
-rw-r--r--drivers/mtd/nand/raw/atmel_nand.c10
-rw-r--r--drivers/mtd/nand/raw/denali_spl.c5
-rw-r--r--drivers/mtd/nand/raw/fsl_ifc_spl.c8
-rw-r--r--drivers/mtd/nand/raw/lpc32xx_nand_mlc.c5
-rw-r--r--drivers/mtd/nand/raw/mt7621_nand_spl.c5
-rw-r--r--drivers/mtd/nand/raw/mxc_nand_spl.c10
-rw-r--r--drivers/mtd/nand/raw/mxs_nand.c3
-rw-r--r--drivers/mtd/nand/raw/mxs_nand_spl.c5
-rw-r--r--drivers/mtd/nand/raw/nand.c66
-rw-r--r--drivers/mtd/nand/raw/nand_base.c40
-rw-r--r--drivers/mtd/nand/raw/nand_spl_loaders.c5
-rw-r--r--drivers/mtd/nand/raw/nand_spl_simple.c10
-rw-r--r--drivers/mtd/nand/raw/octeontx_nand.c2
-rw-r--r--drivers/mtd/nand/raw/omap_gpmc.c3
-rw-r--r--drivers/mtd/nand/raw/rockchip_nfc.c3
-rw-r--r--drivers/mtd/nand/raw/sand_nand.c707
-rw-r--r--drivers/mtd/nand/raw/stm32_fmc2_nand.c5
-rw-r--r--drivers/mtd/nand/raw/sunxi_nand_spl.c8
-rw-r--r--drivers/mtd/nand/spi/Makefile2
-rw-r--r--drivers/mtd/nand/spi/core.c129
-rw-r--r--drivers/mtd/nand/spi/gigadevice.c253
-rw-r--r--drivers/mtd/nand/spi/macronix.c190
-rw-r--r--drivers/mtd/nand/spi/micron.c194
-rw-r--r--drivers/mtd/nand/spi/paragon.c133
-rw-r--r--drivers/mtd/nand/spi/toshiba.c104
-rw-r--r--drivers/mtd/nand/spi/winbond.c116
-rw-r--r--drivers/mtd/onenand/onenand_uboot.c2
-rw-r--r--drivers/mtd/spi/Kconfig9
-rw-r--r--drivers/mtd/spi/spi-nor-core.c8
-rw-r--r--drivers/mtd/spi/spi-nor-ids.c3
-rw-r--r--drivers/mux/mux-uclass.c2
-rw-r--r--drivers/net/Kconfig25
-rw-r--r--drivers/net/Makefile3
-rw-r--r--drivers/net/designware.c31
-rw-r--r--drivers/net/designware.h1
-rw-r--r--drivers/net/dwc_eth_qos.c36
-rw-r--r--drivers/net/e1000.c6
-rw-r--r--drivers/net/fm/fm.c1
-rw-r--r--drivers/net/fsl-mc/mc.c110
-rw-r--r--drivers/net/fsl_mcdmafec.c592
-rw-r--r--drivers/net/ftgmac100.c12
-rw-r--r--drivers/net/hifemac.c481
-rw-r--r--drivers/net/hifemac_mdio.c116
-rw-r--r--drivers/net/mv88e6xxx.c94
-rw-r--r--drivers/net/phy/dp83869.c53
-rw-r--r--drivers/net/phy/et1011c.c2
-rw-r--r--drivers/net/phy/xilinx_phy.c5
-rw-r--r--drivers/net/qe/uccf.c1
-rw-r--r--drivers/net/sun8i_emac.c17
-rw-r--r--drivers/net/sunxi_emac.c38
-rw-r--r--drivers/net/ti/Kconfig2
-rw-r--r--drivers/net/ti/Makefile2
-rw-r--r--drivers/net/ti/cpsw.c2
-rw-r--r--drivers/net/ti/cpsw_mdio.c2
-rw-r--r--drivers/net/ti/cpsw_mdio.h2
-rw-r--r--drivers/net/zynq_gem.c73
-rw-r--r--drivers/nvme/nvme.c2
-rw-r--r--drivers/pci/pci-uclass.c2
-rw-r--r--drivers/pci/pci_mvebu.c3
-rw-r--r--drivers/pci/pci_tegra.c2
-rw-r--r--drivers/pci/pcie_mediatek.c4
-rw-r--r--drivers/phy/Kconfig2
-rw-r--r--drivers/phy/Makefile2
-rw-r--r--drivers/phy/allwinner/phy-sun4i-usb.c12
-rw-r--r--drivers/phy/cadence/phy-cadence-sierra.c2
-rw-r--r--drivers/phy/keystone-usb-phy.c2
-rw-r--r--drivers/phy/meson-axg-mipi-dphy.c3
-rw-r--r--drivers/phy/meson-g12a-usb2.c235
-rw-r--r--drivers/phy/nop-phy.c2
-rw-r--r--drivers/phy/omap-usb2-phy.c2
-rw-r--r--drivers/phy/phy-bcm-sr-pcie.c4
-rw-r--r--drivers/phy/phy-core-mipi-dphy.c3
-rw-r--r--drivers/phy/phy-uclass.c2
-rw-r--r--drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c3
-rw-r--r--drivers/phy/sandbox-phy.c2
-rw-r--r--drivers/phy/ti-pipe3-phy.c2
-rw-r--r--drivers/phy/ti/phy-j721e-wiz.c2
-rw-r--r--drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c1
-rw-r--r--drivers/pinctrl/pinctrl-single.c34
-rw-r--r--drivers/pinctrl/pinctrl-zynqmp.c8
-rw-r--r--drivers/pinctrl/pinctrl_stm32.c2
-rw-r--r--drivers/pinctrl/renesas/Kconfig9
-rw-r--r--drivers/pinctrl/renesas/Makefile1
-rw-r--r--drivers/pinctrl/renesas/rzg2l-pfc.c624
-rw-r--r--drivers/pinctrl/sunxi/Kconfig5
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sunxi.c49
-rw-r--r--drivers/power/Kconfig19
-rw-r--r--drivers/power/Makefile1
-rw-r--r--drivers/power/axp313.c134
-rw-r--r--drivers/power/domain/Kconfig7
-rw-r--r--drivers/power/domain/Makefile1
-rw-r--r--drivers/power/domain/scmi-power-domain.c192
-rw-r--r--drivers/power/domain/ti-power-domain.c2
-rw-r--r--drivers/power/domain/ti-sci-power-domain.c2
-rw-r--r--drivers/power/pmic/Kconfig20
-rw-r--r--drivers/power/pmic/Makefile2
-rw-r--r--drivers/power/pmic/axp.c1
-rw-r--r--drivers/power/pmic/max77663.c90
-rw-r--r--drivers/power/pmic/palmas.c34
-rw-r--r--drivers/power/pmic/pmic_tps62362.c2
-rw-r--r--drivers/power/pmic/pmic_tps65910_dm.c27
-rw-r--r--drivers/power/pmic/tps80031.c91
-rw-r--r--drivers/power/regulator/Kconfig28
-rw-r--r--drivers/power/regulator/Makefile3
-rw-r--r--drivers/power/regulator/axp_regulator.c17
-rw-r--r--drivers/power/regulator/max77663_regulator.c375
-rw-r--r--drivers/power/regulator/palmas_regulator.c24
-rw-r--r--drivers/power/regulator/scmi_regulator.c26
-rw-r--r--drivers/power/regulator/tps62360_regulator.c2
-rw-r--r--drivers/power/regulator/tps65911_regulator.c395
-rw-r--r--drivers/power/regulator/tps80031_regulator.c347
-rw-r--r--drivers/pwm/pwm-aspeed.c3
-rw-r--r--drivers/pwm/pwm-at91.c2
-rw-r--r--drivers/pwm/pwm-cadence-ttc.c3
-rw-r--r--drivers/pwm/pwm-meson.c3
-rw-r--r--drivers/pwm/pwm-mtk.c3
-rw-r--r--drivers/pwm/pwm-ti-ehrpwm.c3
-rw-r--r--drivers/qe/fdt.c1
-rw-r--r--drivers/qe/qe.c4
-rw-r--r--drivers/ram/Kconfig3
-rw-r--r--drivers/ram/Makefile3
-rw-r--r--drivers/ram/k3-am654-ddrss.c22
-rw-r--r--drivers/ram/k3-am654-ddrss.h2
-rw-r--r--drivers/ram/k3-ddrss/Makefile2
-rw-r--r--drivers/ram/k3-ddrss/k3-ddrss.c25
-rw-r--r--drivers/ram/sunxi/Kconfig60
-rw-r--r--drivers/ram/sunxi/Makefile3
-rw-r--r--drivers/ram/sunxi/dram_sun20i_d1.c1441
-rw-r--r--drivers/ram/sunxi/dram_sun20i_d1.h73
-rw-r--r--drivers/remoteproc/Kconfig2
-rw-r--r--drivers/remoteproc/Makefile2
-rw-r--r--drivers/remoteproc/ipu_rproc.c2
-rw-r--r--drivers/remoteproc/k3_system_controller.c2
-rw-r--r--drivers/remoteproc/pru_rproc.c2
-rw-r--r--drivers/remoteproc/rproc-uclass.c2
-rw-r--r--drivers/remoteproc/sandbox_testproc.c2
-rw-r--r--drivers/remoteproc/ti_k3_arm64_rproc.c2
-rw-r--r--drivers/remoteproc/ti_k3_dsp_rproc.c2
-rw-r--r--drivers/remoteproc/ti_power_proc.c2
-rw-r--r--drivers/remoteproc/ti_sci_proc.h2
-rw-r--r--drivers/reset/reset-dra7.c2
-rw-r--r--drivers/reset/reset-meson.c42
-rw-r--r--drivers/reset/reset-scmi.c19
-rw-r--r--drivers/reset/reset-ti-sci.c2
-rw-r--r--drivers/rng/Kconfig20
-rw-r--r--drivers/rng/Makefile3
-rw-r--r--drivers/rng/arm_rndr.c82
-rw-r--r--drivers/rng/jh7110_rng.c274
-rw-r--r--drivers/rng/meson-rng.c72
-rw-r--r--drivers/rng/riscv_zkr_rng.c116
-rw-r--r--drivers/scsi/Kconfig43
-rw-r--r--drivers/scsi/Makefile17
-rw-r--r--drivers/scsi/scsi.c162
-rw-r--r--drivers/serial/Kconfig17
-rw-r--r--drivers/serial/ns16550.c21
-rw-r--r--drivers/serial/sandbox.c2
-rw-r--r--drivers/serial/serial-uclass.c79
-rw-r--r--drivers/serial/serial_lpuart.c14
-rw-r--r--drivers/serial/serial_meson.c1
-rw-r--r--drivers/serial/serial_msm_geni.c3
-rw-r--r--drivers/serial/serial_npcm.c39
-rw-r--r--drivers/serial/serial_omap.c2
-rw-r--r--drivers/serial/serial_s5p.c79
-rw-r--r--drivers/serial/serial_sh.c44
-rw-r--r--drivers/serial/serial_sh.h19
-rw-r--r--drivers/serial/serial_stm32.c23
-rw-r--r--drivers/serial/serial_stm32.h2
-rw-r--r--drivers/sm/Kconfig8
-rw-r--r--drivers/sm/Makefile5
-rw-r--r--drivers/sm/meson-sm.c199
-rw-r--r--drivers/sm/sandbox-sm.c76
-rw-r--r--drivers/sm/sm-uclass.c55
-rw-r--r--drivers/soc/soc-uclass.c2
-rw-r--r--drivers/soc/soc_sandbox.c2
-rw-r--r--drivers/soc/soc_ti_k3.c2
-rw-r--r--drivers/soc/ti/k3-navss-ringacc.c14
-rw-r--r--drivers/soc/ti/keystone_serdes.c1
-rw-r--r--drivers/spi/Kconfig10
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/cadence_ospi_versal.c4
-rw-r--r--drivers/spi/cadence_qspi.c5
-rw-r--r--drivers/spi/davinci_spi.c2
-rw-r--r--drivers/spi/fsl_dspi.c4
-rw-r--r--drivers/spi/meson_spifc_a1.c384
-rw-r--r--drivers/spi/mtk_spim.c7
-rw-r--r--drivers/spi/nxp_fspi.c7
-rw-r--r--drivers/spi/omap3_spi.c2
-rw-r--r--drivers/spi/spi-mem-nodm.c3
-rw-r--r--drivers/spi/zynqmp_gqspi.c82
-rw-r--r--drivers/sysinfo/Kconfig7
-rw-r--r--drivers/sysreset/Kconfig36
-rw-r--r--drivers/sysreset/Makefile5
-rw-r--r--drivers/sysreset/poweroff_gpio.c2
-rw-r--r--drivers/sysreset/sysreset-ti-sci.c2
-rw-r--r--drivers/sysreset/sysreset_max77663.c52
-rw-r--r--drivers/sysreset/sysreset_palmas.c52
-rw-r--r--drivers/sysreset/sysreset_psci.c2
-rw-r--r--drivers/sysreset/sysreset_sandbox.c6
-rw-r--r--drivers/sysreset/sysreset_tegra.c45
-rw-r--r--drivers/sysreset/sysreset_tps65910.c54
-rw-r--r--drivers/sysreset/sysreset_tps80031.c40
-rw-r--r--drivers/sysreset/sysreset_watchdog.c2
-rw-r--r--drivers/sysreset/sysreset_x86.c2
-rw-r--r--drivers/thermal/ti-bandgap.c2
-rw-r--r--drivers/timer/timer-uclass.c12
-rw-r--r--drivers/tpm/tpm2_tis_core.c3
-rw-r--r--drivers/tpm/tpm2_tis_sandbox.c100
-rw-r--r--drivers/ufs/Kconfig13
-rw-r--r--drivers/ufs/Makefile3
-rw-r--r--drivers/ufs/cdns-platform.c5
-rw-r--r--drivers/ufs/ti-j721e-ufs.c2
-rw-r--r--drivers/ufs/ufs-pci.c45
-rw-r--r--drivers/ufs/ufs-uclass.c4
-rw-r--r--drivers/ufs/ufs.c33
-rw-r--r--drivers/ufs/ufs.h1
-rw-r--r--drivers/usb/cdns3/cdns3-ti.c3
-rw-r--r--drivers/usb/dwc3/core.c5
-rw-r--r--drivers/usb/dwc3/core.h2
-rw-r--r--drivers/usb/dwc3/dwc3-generic.c1
-rw-r--r--drivers/usb/dwc3/dwc3-meson-g12a.c81
-rw-r--r--drivers/usb/dwc3/dwc3-meson-gxl.c2
-rw-r--r--drivers/usb/dwc3/dwc3-omap.c2
-rw-r--r--drivers/usb/dwc3/ep0.c2
-rw-r--r--drivers/usb/dwc3/gadget.c2
-rw-r--r--drivers/usb/dwc3/gadget.h2
-rw-r--r--drivers/usb/dwc3/io.h2
-rw-r--r--drivers/usb/dwc3/linux-compat.h2
-rw-r--r--drivers/usb/dwc3/ti_usb_phy.c2
-rw-r--r--drivers/usb/gadget/Kconfig1
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c11
-rw-r--r--drivers/usb/gadget/ci_udc.c38
-rw-r--r--drivers/usb/gadget/f_fastboot.c2
-rw-r--r--drivers/usb/gadget/f_mass_storage.c7
-rw-r--r--drivers/usb/gadget/f_sdp.c14
-rw-r--r--drivers/usb/gadget/udc/udc-core.c15
-rw-r--r--drivers/usb/gadget/udc/udc-uclass.c2
-rw-r--r--drivers/usb/host/Kconfig4
-rw-r--r--drivers/usb/host/dwc3-of-simple.c2
-rw-r--r--drivers/usb/host/ehci-mxs.c15
-rw-r--r--drivers/usb/host/xhci-ring.c72
-rw-r--r--drivers/usb/host/xhci.c9
-rw-r--r--drivers/usb/musb-new/musb_io.h24
-rw-r--r--drivers/usb/ulpi/omap-ulpi-viewport.c2
-rw-r--r--drivers/video/Kconfig1
-rw-r--r--drivers/video/console_core.c31
-rw-r--r--drivers/video/console_normal.c29
-rw-r--r--drivers/video/console_truetype.c191
-rw-r--r--drivers/video/dw_mipi_dsi.c3
-rw-r--r--drivers/video/hitachi_tx18d42vm_lcd.c1
-rw-r--r--drivers/video/pwm_backlight.c13
-rw-r--r--drivers/video/rockchip/dw_mipi_dsi_rockchip.c3
-rw-r--r--drivers/video/simple_panel.c10
-rw-r--r--drivers/video/ssd2828.c1
-rw-r--r--drivers/video/sunxi/sunxi_display.c1
-rw-r--r--drivers/video/sunxi/sunxi_lcd.c1
-rw-r--r--drivers/video/tegra20/tegra-dsi.c12
-rw-r--r--drivers/video/vidconsole-uclass.c71
-rw-r--r--drivers/video/vidconsole_internal.h24
-rw-r--r--drivers/virtio/Kconfig2
-rw-r--r--drivers/virtio/virtio_rng.c9
-rw-r--r--drivers/watchdog/npcm_wdt.c10
-rw-r--r--drivers/watchdog/s5p_wdt.c1
-rw-r--r--drivers/watchdog/sunxi_wdt.c3
-rw-r--r--drivers/watchdog/wdt-uclass.c3
-rw-r--r--drivers/xen/pvblock.c3
420 files changed, 18284 insertions, 7290 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index a25f6ae02fd..a073230c26d 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -118,6 +118,8 @@ source "drivers/scsi/Kconfig"
source "drivers/serial/Kconfig"
+source "drivers/sm/Kconfig"
+
source "drivers/smem/Kconfig"
source "drivers/sound/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index efc2a4afb24..bf73b7718ce 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_$(SPL_TPL_)VIRTIO) += virtio/
obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox/
obj-$(CONFIG_$(SPL_)REMOTEPROC) += remoteproc/
obj-$(CONFIG_$(SPL_)SYSINFO) += sysinfo/
+obj-$(CONFIG_$(SPL_TPL_)SM) += sm/
obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm/
obj-$(CONFIG_$(SPL_)NVME) += nvme/
obj-$(CONFIG_XEN) += xen/
@@ -56,6 +57,7 @@ obj-$(CONFIG_$(SPL_)ALTERA_SDRAM) += ddr/altera/
obj-$(CONFIG_ARCH_IMX8M) += ddr/imx/imx8m/
obj-$(CONFIG_IMX8ULP_DRAM) += ddr/imx/imx8ulp/
obj-$(CONFIG_ARCH_IMX9) += ddr/imx/imx9/
+obj-$(CONFIG_DRAM_SUN20I_D1) += ram/
obj-$(CONFIG_SPL_DM_RESET) += reset/
obj-$(CONFIG_SPL_MUSB_NEW) += usb/musb-new/
obj-$(CONFIG_SPL_USB_GADGET) += usb/gadget/
diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig
index 4336732dee5..a01d73846b7 100644
--- a/drivers/adc/Kconfig
+++ b/drivers/adc/Kconfig
@@ -66,6 +66,7 @@ config STM32_ADC
config ADC_IMX93
bool "Enable NXP IMX93 ADC driver"
+ depends on ADC
help
This enables basic driver for NXP IMX93 ADC.
It provides:
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 049f7efd10b..9bc5283c268 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -20,14 +20,6 @@ config SATA
See also CMD_SATA which provides command-line support.
-config SYS_SATA_MAX_PORTS
- int "Maximum supported SATA ports"
- depends on SCSI_AHCI && !DM_SCSI
- default 1
- help
- Sets the maximum number of ports to scan when looking for devices.
- Ports from 0 to (this value - 1) are scanned.
-
config LIBATA
bool
help
@@ -44,7 +36,7 @@ menu "SATA/SCSI device support"
config AHCI_PCI
bool "Support for PCI-based AHCI controller"
depends on PCI
- depends on DM_SCSI
+ depends on SCSI
depends on SCSI_AHCI
help
Enables support for the PCI-based AHCI controller.
@@ -55,13 +47,13 @@ config SPL_AHCI_PCI
bool "Support for PCI-based AHCI controller for SPL"
depends on SPL
depends on SPL_PCI
- depends on SPL_SATA && DM_SCSI
+ depends on SPL_SATA && SCSI
config DWC_AHCI
bool "Enable Synopsys DWC AHCI driver support"
select SCSI_AHCI
select PHY
- depends on DM_SCSI
+ depends on SCSI
help
Enable this driver to support Sata devices through
Synopsys DWC AHCI module.
@@ -91,7 +83,7 @@ config AHCI_MVEBU
bool "Marvell EBU AHCI SATA support"
depends on ARCH_MVEBU || ARCH_OCTEON
select SCSI_AHCI
- select DM_SCSI
+ select SCSI
help
This option enables support for the Marvell EBU SoC's
onboard AHCI SATA.
@@ -112,7 +104,7 @@ if SATA
config SATA_CEVA
bool "Ceva Sata controller"
depends on AHCI
- depends on DM_SCSI
+ depends on SCSI
help
This option enables Ceva Sata controller hard IP available on Xilinx
ZynqMP. Support up to 2 external devices. Compliant with SATA 3.1 and
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 6e30180b8b4..af6f0bf2780 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -10,11 +10,10 @@ obj-$(CONFIG_SCSI_AHCI) += ahci.o
obj-$(CONFIG_DWC_AHSATA) += dwc_ahsata.o
obj-$(CONFIG_FSL_SATA) += fsl_sata.o
obj-$(CONFIG_LIBATA) += libata.o
-obj-$(CONFIG_SATA) += sata.o
+obj-$(CONFIG_SATA) += sata.o sata_bootdev.o
obj-$(CONFIG_SATA_CEVA) += sata_ceva.o
obj-$(CONFIG_SATA_MV) += sata_mv.o
obj-$(CONFIG_SATA_SIL) += sata_sil.o
-obj-$(CONFIG_SANDBOX) += sata_sandbox.o
obj-$(CONFIG_AHCI_MVEBU) += ahci_mvebu.o
obj-$(CONFIG_SUNXI_AHCI) += ahci_sunxi.o
obj-$(CONFIG_MTK_AHCI) += mtk_ahci.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index cb2c648a91f..04ddc339464 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -33,10 +33,6 @@
static int ata_io_flush(struct ahci_uc_priv *uc_priv, u8 port);
-#ifndef CONFIG_DM_SCSI
-struct ahci_uc_priv *probe_ent = NULL;
-#endif
-
#define writel_with_flush(a,b) do { writel(a,b); readl(b); } while (0)
/*
@@ -169,11 +165,6 @@ int ahci_reset(void __iomem *base)
static int ahci_host_init(struct ahci_uc_priv *uc_priv)
{
-#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI)
- struct udevice *dev = uc_priv->dev;
- struct pci_child_plat *pplat = dev_get_parent_plat(dev);
- u16 tmp16;
-#endif
void __iomem *mmio = uc_priv->mmio_base;
u32 tmp, cap_save, cmd;
int i, j, ret;
@@ -194,14 +185,6 @@ static int ahci_host_init(struct ahci_uc_priv *uc_priv)
writel(cap_save, mmio + HOST_CAP);
writel_with_flush(0xf, mmio + HOST_PORTS_IMPL);
-#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI)
- if (pplat->vendor == PCI_VENDOR_ID_INTEL) {
- u16 tmp16;
-
- dm_pci_read_config16(dev, 0x92, &tmp16);
- dm_pci_write_config16(dev, 0x92, tmp16 | 0xf);
- }
-#endif
uc_priv->cap = readl(mmio + HOST_CAP);
uc_priv->port_map = readl(mmio + HOST_PORTS_IMPL);
port_map = uc_priv->port_map;
@@ -210,11 +193,6 @@ static int ahci_host_init(struct ahci_uc_priv *uc_priv)
debug("cap 0x%x port_map 0x%x n_ports %d\n",
uc_priv->cap, uc_priv->port_map, uc_priv->n_ports);
-#if !defined(CONFIG_DM_SCSI)
- if (uc_priv->n_ports > CONFIG_SYS_SATA_MAX_PORTS)
- uc_priv->n_ports = CONFIG_SYS_SATA_MAX_PORTS;
-#endif
-
for (i = 0; i < uc_priv->n_ports; i++) {
if (!(port_map & (1 << i)))
continue;
@@ -313,23 +291,12 @@ static int ahci_host_init(struct ahci_uc_priv *uc_priv)
writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
tmp = readl(mmio + HOST_CTL);
debug("HOST_CTL 0x%x\n", tmp);
-#if !defined(CONFIG_DM_SCSI)
-#ifndef CONFIG_SCSI_AHCI_PLAT
- dm_pci_read_config16(dev, PCI_COMMAND, &tmp16);
- tmp |= PCI_COMMAND_MASTER;
- dm_pci_write_config16(dev, PCI_COMMAND, tmp16);
-#endif
-#endif
return 0;
}
static void ahci_print_info(struct ahci_uc_priv *uc_priv)
{
-#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI)
- struct udevice *dev = uc_priv->dev;
- u16 cc;
-#endif
void __iomem *mmio = uc_priv->mmio_base;
u32 vers, cap, cap2, impl, speed;
const char *speed_s;
@@ -350,19 +317,7 @@ static void ahci_print_info(struct ahci_uc_priv *uc_priv)
else
speed_s = "?";
-#if defined(CONFIG_SCSI_AHCI_PLAT) || defined(CONFIG_DM_SCSI)
scc_s = "SATA";
-#else
- dm_pci_read_config16(dev, 0x0a, &cc);
- if (cc == 0x0101)
- scc_s = "IDE";
- else if (cc == 0x0106)
- scc_s = "SATA";
- else if (cc == 0x0104)
- scc_s = "RAID";
- else
- scc_s = "unknown";
-#endif
printf("AHCI %02x%02x.%02x%02x "
"%u slots %u ports %s Gbps 0x%x impl %s mode\n",
(vers >> 24) & 0xff,
@@ -397,12 +352,8 @@ static void ahci_print_info(struct ahci_uc_priv *uc_priv)
cap2 & (1 << 0) ? "boh " : "");
}
-#if defined(CONFIG_DM_SCSI) || !defined(CONFIG_SCSI_AHCI_PLAT)
static int ahci_init_one(struct ahci_uc_priv *uc_priv, struct udevice *dev)
{
-#if !defined(CONFIG_DM_SCSI)
- u16 vendor;
-#endif
int rc;
uc_priv->dev = dev;
@@ -415,21 +366,8 @@ static int ahci_init_one(struct ahci_uc_priv *uc_priv, struct udevice *dev)
uc_priv->pio_mask = 0x1f;
uc_priv->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */
-#if !defined(CONFIG_DM_SCSI)
- uc_priv->mmio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_5, 0, 0,
- PCI_REGION_TYPE, PCI_REGION_MEM);
-
- /* Take from kernel:
- * JMicron-specific fixup:
- * make sure we're in AHCI mode
- */
- dm_pci_read_config16(dev, PCI_VENDOR_ID, &vendor);
- if (vendor == 0x197b)
- dm_pci_write_config8(dev, 0x41, 0xa1);
-#else
struct scsi_plat *plat = dev_get_uclass_plat(dev);
uc_priv->mmio_base = (void *)plat->base;
-#endif
debug("ahci mmio_base=0x%p\n", uc_priv->mmio_base);
/* initialize adapter */
@@ -444,7 +382,6 @@ static int ahci_init_one(struct ahci_uc_priv *uc_priv, struct udevice *dev)
err_out:
return rc;
}
-#endif
#define MAX_DATA_BYTE_COUNT (4*1024*1024)
@@ -893,12 +830,7 @@ static int ata_scsiop_test_unit_ready(struct ahci_uc_priv *uc_priv,
static int ahci_scsi_exec(struct udevice *dev, struct scsi_cmd *pccb)
{
- struct ahci_uc_priv *uc_priv;
-#ifdef CONFIG_DM_SCSI
- uc_priv = dev_get_uclass_priv(dev->parent);
-#else
- uc_priv = probe_ent;
-#endif
+ struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev->parent);
int ret;
switch (pccb->cmd[0]) {
@@ -953,41 +885,12 @@ static int ahci_start_ports(struct ahci_uc_priv *uc_priv)
return 0;
}
-#ifndef CONFIG_DM_SCSI
-void scsi_low_level_init(int busdevfunc)
-{
- struct ahci_uc_priv *uc_priv;
-
-#ifndef CONFIG_SCSI_AHCI_PLAT
- probe_ent = calloc(1, sizeof(struct ahci_uc_priv));
- if (!probe_ent) {
- printf("%s: No memory for uc_priv\n", __func__);
- return;
- }
- uc_priv = probe_ent;
- struct udevice *dev;
- int ret;
-
- ret = dm_pci_bus_find_bdf(busdevfunc, &dev);
- if (ret)
- return;
- ahci_init_one(uc_priv, dev);
-#else
- uc_priv = probe_ent;
-#endif
-
- ahci_start_ports(uc_priv);
-}
-#endif
-
-#ifndef CONFIG_SCSI_AHCI_PLAT
int ahci_init_one_dm(struct udevice *dev)
{
struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev);
return ahci_init_one(uc_priv, dev);
}
-#endif
int ahci_start_ports_dm(struct udevice *dev)
{
@@ -996,65 +899,6 @@ int ahci_start_ports_dm(struct udevice *dev)
return ahci_start_ports(uc_priv);
}
-#ifdef CONFIG_SCSI_AHCI_PLAT
-static int ahci_init_common(struct ahci_uc_priv *uc_priv, void __iomem *base)
-{
- int rc;
-
- uc_priv->host_flags = ATA_FLAG_SATA
- | ATA_FLAG_NO_LEGACY
- | ATA_FLAG_MMIO
- | ATA_FLAG_PIO_DMA
- | ATA_FLAG_NO_ATAPI;
- uc_priv->pio_mask = 0x1f;
- uc_priv->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */
-
- uc_priv->mmio_base = base;
-
- /* initialize adapter */
- rc = ahci_host_init(uc_priv);
- if (rc)
- goto err_out;
-
- ahci_print_info(uc_priv);
-
- rc = ahci_start_ports(uc_priv);
-
-err_out:
- return rc;
-}
-
-#ifndef CONFIG_DM_SCSI
-int ahci_init(void __iomem *base)
-{
- struct ahci_uc_priv *uc_priv;
-
- probe_ent = malloc(sizeof(struct ahci_uc_priv));
- if (!probe_ent) {
- printf("%s: No memory for uc_priv\n", __func__);
- return -ENOMEM;
- }
-
- uc_priv = probe_ent;
- memset(uc_priv, 0, sizeof(struct ahci_uc_priv));
-
- return ahci_init_common(uc_priv, base);
-}
-#endif
-
-int ahci_init_dm(struct udevice *dev, void __iomem *base)
-{
- struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev);
-
- return ahci_init_common(uc_priv, base);
-}
-
-void __weak scsi_init(void)
-{
-}
-
-#endif /* CONFIG_SCSI_AHCI_PLAT */
-
/*
* In the general case of generic rotating media it makes sense to have a
* flush capability. It probably even makes sense in the case of SSDs because
@@ -1098,7 +942,6 @@ static int ahci_scsi_bus_reset(struct udevice *dev)
return 0;
}
-#ifdef CONFIG_DM_SCSI
int ahci_bind_scsi(struct udevice *ahci_dev, struct udevice **devp)
{
struct udevice *dev;
@@ -1190,16 +1033,3 @@ U_BOOT_DRIVER(ahci_scsi) = {
.id = UCLASS_SCSI,
.ops = &scsi_ops,
};
-#else
-int scsi_exec(struct udevice *dev, struct scsi_cmd *pccb)
-{
- return ahci_scsi_exec(dev, pccb);
-}
-
-__weak int scsi_bus_reset(struct udevice *dev)
-{
- return ahci_scsi_bus_reset(dev);
-
- return 0;
-}
-#endif
diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c
index 94a3379c532..9064774e661 100644
--- a/drivers/ata/ahci_sunxi.c
+++ b/drivers/ata/ahci_sunxi.c
@@ -7,6 +7,7 @@
#include <asm/io.h>
#include <asm/gpio.h>
#include <linux/delay.h>
+#include <power/regulator.h>
#define AHCI_PHYCS0R 0x00c0
#define AHCI_PHYCS1R 0x00c4
@@ -74,6 +75,7 @@ static int sunxi_ahci_phy_init(u8 *reg_base)
static int sunxi_sata_probe(struct udevice *dev)
{
+ struct udevice *reg_dev;
ulong base;
u8 *reg;
int ret;
@@ -89,6 +91,13 @@ static int sunxi_sata_probe(struct udevice *dev)
debug("%s: Failed to init phy (err=%d)\n", __func__, ret);
return ret;
}
+
+ ret = device_get_supply_regulator(dev, "target-supply", &reg_dev);
+ if (ret == 0) {
+ regulator_set_enable(reg_dev, true);
+ mdelay(500);
+ }
+
ret = ahci_probe_scsi(dev, base);
if (ret) {
debug("%s: Failed to probe (err=%d)\n", __func__, ret);
diff --git a/drivers/ata/dwc_ahsata.c b/drivers/ata/dwc_ahsata.c
index 6a4d861bf1e..b4d4e39c9b3 100644
--- a/drivers/ata/dwc_ahsata.c
+++ b/drivers/ata/dwc_ahsata.c
@@ -880,7 +880,8 @@ int dwc_ahsata_scan(struct udevice *dev)
device_find_first_child(dev, &blk);
if (!blk) {
ret = blk_create_devicef(dev, "dwc_ahsata_blk", "blk",
- UCLASS_AHCI, -1, 512, 0, &blk);
+ UCLASS_AHCI, -1, DEFAULT_BLKSZ,
+ 0, &blk);
if (ret) {
debug("Can't create device\n");
return ret;
diff --git a/drivers/ata/fsl_sata.c b/drivers/ata/fsl_sata.c
index 972101b29ce..969bc191f8e 100644
--- a/drivers/ata/fsl_sata.c
+++ b/drivers/ata/fsl_sata.c
@@ -888,7 +888,8 @@ static int fsl_ata_probe(struct udevice *dev)
for (i = 0; i < nr_ports; i++) {
snprintf(sata_name, sizeof(sata_name), "fsl_sata%d", i);
ret = blk_create_devicef(dev, "sata_fsl_blk", sata_name,
- UCLASS_AHCI, -1, 512, 0, &blk);
+ UCLASS_AHCI, -1, DEFAULT_BLKSZ,
+ 0, &blk);
if (ret) {
debug("Can't create device\n");
return ret;
diff --git a/drivers/ata/sata.c b/drivers/ata/sata.c
index ce3e9b5a400..784d9bbeacb 100644
--- a/drivers/ata/sata.c
+++ b/drivers/ata/sata.c
@@ -15,10 +15,8 @@
#include <dm.h>
#include <part.h>
#include <sata.h>
-
-#ifndef CONFIG_AHCI
-struct blk_desc sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE];
-#endif
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
int sata_reset(struct udevice *dev)
{
@@ -50,14 +48,41 @@ int sata_scan(struct udevice *dev)
return ops->scan(dev);
}
-#ifndef CONFIG_AHCI
-#ifdef CONFIG_PARTITIONS
-struct blk_desc *sata_get_dev(int dev)
+int sata_rescan(bool verbose)
{
- return (dev < CONFIG_SYS_SATA_MAX_DEVICE) ? &sata_dev_desc[dev] : NULL;
+ int ret;
+ struct udevice *dev;
+
+ if (verbose)
+ printf("Removing devices on SATA bus...\n");
+
+ blk_unbind_all(UCLASS_AHCI);
+
+ ret = uclass_find_first_device(UCLASS_AHCI, &dev);
+ if (ret || !dev) {
+ printf("Cannot find SATA device (err=%d)\n", ret);
+ return -ENOENT;
+ }
+
+ ret = device_remove(dev, DM_REMOVE_NORMAL);
+ if (ret) {
+ printf("Cannot remove SATA device '%s' (err=%d)\n", dev->name, ret);
+ return -ENOSYS;
+ }
+
+ if (verbose)
+ printf("Rescanning SATA bus for devices...\n");
+
+ ret = uclass_probe_all(UCLASS_AHCI);
+
+ if (ret == -ENODEV) {
+ if (verbose)
+ printf("No SATA block device found\n");
+ return 0;
+ }
+
+ return ret;
}
-#endif
-#endif
static unsigned long sata_bread(struct udevice *dev, lbaint_t start,
lbaint_t blkcnt, void *dst)
@@ -71,51 +96,6 @@ static unsigned long sata_bwrite(struct udevice *dev, lbaint_t start,
return -ENOSYS;
}
-#ifndef CONFIG_AHCI
-int __sata_initialize(void)
-{
- int rc, ret = -1;
- int i;
-
- for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++) {
- memset(&sata_dev_desc[i], 0, sizeof(struct blk_desc));
- sata_dev_desc[i].uclass_id = UCLASS_AHCI;
- sata_dev_desc[i].devnum = i;
- sata_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
- sata_dev_desc[i].type = DEV_TYPE_HARDDISK;
- sata_dev_desc[i].lba = 0;
- sata_dev_desc[i].blksz = 512;
- sata_dev_desc[i].log2blksz = LOG2(sata_dev_desc[i].blksz);
- rc = init_sata(i);
- if (!rc) {
- rc = scan_sata(i);
- if (!rc && sata_dev_desc[i].lba > 0 &&
- sata_dev_desc[i].blksz > 0) {
- part_init(&sata_dev_desc[i]);
- ret = i;
- }
- }
- }
-
- return ret;
-}
-int sata_initialize(void) __attribute__((weak, alias("__sata_initialize")));
-
-__weak int __sata_stop(void)
-{
- int i, err = 0;
-
- for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++)
- err |= reset_sata(i);
-
- if (err)
- printf("Could not reset some SATA devices\n");
-
- return err;
-}
-int sata_stop(void) __attribute__((weak, alias("__sata_stop")));
-#endif
-
static const struct blk_ops sata_blk_ops = {
.read = sata_bread,
.write = sata_bwrite,
diff --git a/drivers/ata/sata_bootdev.c b/drivers/ata/sata_bootdev.c
new file mode 100644
index 00000000000..f638493ce04
--- /dev/null
+++ b/drivers/ata/sata_bootdev.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Bootdev for sata
+ *
+ * Copyright 2023 Tony Dinh <mibodhi@gmail.com>
+ */
+
+#include <common.h>
+#include <ahci.h>
+#include <bootdev.h>
+#include <dm.h>
+#include <init.h>
+#include <sata.h>
+
+static int sata_bootdev_bind(struct udevice *dev)
+{
+ struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
+
+ ucp->prio = BOOTDEVP_4_SCAN_FAST;
+
+ return 0;
+}
+
+static int sata_bootdev_hunt(struct bootdev_hunter *info, bool show)
+{
+ int ret;
+
+ if (IS_ENABLED(CONFIG_PCI)) {
+ ret = pci_init();
+ if (ret)
+ return ret;
+ }
+
+ ret = sata_rescan(true);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct bootdev_ops sata_bootdev_ops = {
+};
+
+static const struct udevice_id sata_bootdev_ids[] = {
+ { .compatible = "u-boot,bootdev-sata" },
+ { }
+};
+
+U_BOOT_DRIVER(sata_bootdev) = {
+ .name = "sata_bootdev",
+ .id = UCLASS_BOOTDEV,
+ .ops = &sata_bootdev_ops,
+ .bind = sata_bootdev_bind,
+ .of_match = sata_bootdev_ids,
+};
+
+BOOTDEV_HUNTER(sata_bootdev_hunter) = {
+ .prio = BOOTDEVP_4_SCAN_FAST,
+ .uclass = UCLASS_AHCI,
+ .hunt = sata_bootdev_hunt,
+ .drv = DM_DRIVER_REF(sata_bootdev),
+};
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 18c7a66db1b..94d7369351a 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -34,6 +34,7 @@
#include <common.h>
#include <ahci.h>
#include <blk.h>
+#include <bootdev.h>
#include <cpu_func.h>
#include <dm.h>
#include <log.h>
@@ -1076,7 +1077,8 @@ static int sata_mv_probe(struct udevice *dev)
for (i = 0; i < nr_ports; i++) {
ret = blk_create_devicef(dev, "sata_mv_blk", "blk",
- UCLASS_AHCI, -1, 512, 0, &blk);
+ UCLASS_AHCI, -1, DEFAULT_BLKSZ,
+ 0, &blk);
if (ret) {
debug("Can't create device\n");
continue;
@@ -1104,6 +1106,12 @@ static int sata_mv_probe(struct udevice *dev)
/* TODO: undo create */
continue;
+ ret = bootdev_setup_for_sibling_blk(blk, "sata_bootdev");
+ if (ret) {
+ printf("%s: Failed to create bootdev\n", __func__);
+ continue;
+ }
+
/* If we got here, the current SATA port was probed
* successfully, so set the probe status to successful.
*/
@@ -1116,7 +1124,6 @@ static int sata_mv_probe(struct udevice *dev)
static int sata_mv_scan(struct udevice *dev)
{
/* Nothing to do here */
-
return 0;
}
diff --git a/drivers/ata/sata_sandbox.c b/drivers/ata/sata_sandbox.c
deleted file mode 100644
index e64cc4a5c10..00000000000
--- a/drivers/ata/sata_sandbox.c
+++ /dev/null
@@ -1,33 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2015 Google, Inc
- * Written by Simon Glass <sjg@chromium.org>
- */
-
-#include <common.h>
-#include <blk.h>
-
-int init_sata(int dev)
-{
- return 0;
-}
-
-int reset_sata(int dev)
-{
- return 0;
-}
-
-int scan_sata(int dev)
-{
- return 0;
-}
-
-ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer)
-{
- return 0;
-}
-
-ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer)
-{
- return 0;
-}
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index b5e150d568b..43a91a79120 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -730,7 +730,8 @@ static int sil_pci_probe(struct udevice *dev)
for (i = sata_info.portbase; i < sata_info.maxport; i++) {
snprintf(sata_name, sizeof(sata_name), "sil_sata%d", i);
ret = blk_create_devicef(dev, "sata_sil_blk", sata_name,
- UCLASS_AHCI, -1, 512, 0, &blk);
+ UCLASS_AHCI, -1, DEFAULT_BLKSZ,
+ 0, &blk);
if (ret) {
debug("Can't create device\n");
return ret;
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 1abea3f10db..6ad18889f61 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -13,7 +13,7 @@ config BLK
config SPL_LEGACY_BLOCK
bool # "Enable Legacy Block Device"
- depends on SPL && !DM_SPL
+ depends on SPL
default y if SPL_MMC || SPL_USB_STORAGE || SCSI || NVME || IDE
default y if SPL_AHCI_PCI
help
@@ -262,3 +262,11 @@ config SYS_64BIT_LBA
help
Make the block subsystem use 64bit sector addresses, rather than the
default of 32bit.
+
+config RKMTD
+ bool "Rockchip rkmtd virtual block device"
+ select RANDOM_UUID
+ help
+ Enable "rkmtd" class and driver to create a virtual block device
+ to transfer Rockchip boot block data to and from NAND with block
+ orientate tools like "ums" and "rockusb".
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index a161d145fd3..fe6a1fcf486 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -11,11 +11,14 @@ endif
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_IDE) += ide.o
+obj-$(CONFIG_RKMTD) += rkmtd.o
endif
obj-$(CONFIG_SANDBOX) += sandbox.o host-uclass.o host_dev.o
obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o
-obj-$(CONFIG_BLKMAP) += blkmap.o
+obj-$(CONFIG_$(SPL_TPL_)BLKMAP) += blkmap.o
+obj-$(CONFIG_$(SPL_TPL_)BLKMAP) += blkmap_helper.o
obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o
obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o
obj-$(CONFIG_EFI_MEDIA_BLK) += efi_blk.o
+
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c
index 885513893f6..77066da352a 100644
--- a/drivers/block/blk-uclass.c
+++ b/drivers/block/blk-uclass.c
@@ -36,6 +36,7 @@ static struct {
{ UCLASS_VIRTIO, "virtio" },
{ UCLASS_PVBLOCK, "pvblock" },
{ UCLASS_BLKMAP, "blkmap" },
+ { UCLASS_RKMTD, "rkmtd" },
};
static enum uclass_id uclass_name_to_iftype(const char *uclass_idname)
@@ -178,17 +179,7 @@ struct blk_desc *blk_get_by_device(struct udevice *dev)
return NULL;
}
-/**
- * get_desc() - Get the block device descriptor for the given device number
- *
- * @uclass_id: Interface type
- * @devnum: Device number (0 = first)
- * @descp: Returns block device descriptor on success
- * Return: 0 on success, -ENODEV if there is no such device and no device
- * with a higher device number, -ENOENT if there is no such device but there
- * is one with a higher number, or other -ve on other error.
- */
-static int get_desc(enum uclass_id uclass_id, int devnum, struct blk_desc **descp)
+int blk_get_desc(enum uclass_id uclass_id, int devnum, struct blk_desc **descp)
{
bool found_more = false;
struct udevice *dev;
@@ -240,7 +231,7 @@ int blk_list_part(enum uclass_id uclass_id)
int ret;
for (ok = 0, devnum = 0;; ++devnum) {
- ret = get_desc(uclass_id, devnum, &desc);
+ ret = blk_get_desc(uclass_id, devnum, &desc);
if (ret == -ENODEV)
break;
else if (ret)
@@ -263,7 +254,7 @@ int blk_print_part_devnum(enum uclass_id uclass_id, int devnum)
struct blk_desc *desc;
int ret;
- ret = get_desc(uclass_id, devnum, &desc);
+ ret = blk_get_desc(uclass_id, devnum, &desc);
if (ret)
return ret;
if (desc->type == DEV_TYPE_UNKNOWN)
@@ -280,7 +271,7 @@ void blk_list_devices(enum uclass_id uclass_id)
int i;
for (i = 0;; ++i) {
- ret = get_desc(uclass_id, i, &desc);
+ ret = blk_get_desc(uclass_id, i, &desc);
if (ret == -ENODEV)
break;
else if (ret)
@@ -297,7 +288,7 @@ int blk_print_device_num(enum uclass_id uclass_id, int devnum)
struct blk_desc *desc;
int ret;
- ret = get_desc(uclass_id, devnum, &desc);
+ ret = blk_get_desc(uclass_id, devnum, &desc);
if (ret)
return ret;
printf("\nIDE device %d: ", devnum);
@@ -312,7 +303,7 @@ int blk_show_device(enum uclass_id uclass_id, int devnum)
int ret;
printf("\nDevice %d: ", devnum);
- ret = get_desc(uclass_id, devnum, &desc);
+ ret = blk_get_desc(uclass_id, devnum, &desc);
if (ret == -ENODEV || ret == -ENOENT) {
printf("unknown device\n");
return -ENODEV;
@@ -327,35 +318,6 @@ int blk_show_device(enum uclass_id uclass_id, int devnum)
return 0;
}
-ulong blk_read_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
- lbaint_t blkcnt, void *buffer)
-{
- struct blk_desc *desc;
- ulong n;
- int ret;
-
- ret = get_desc(uclass_id, devnum, &desc);
- if (ret)
- return ret;
- n = blk_dread(desc, start, blkcnt, buffer);
- if (IS_ERR_VALUE(n))
- return n;
-
- return n;
-}
-
-ulong blk_write_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
- lbaint_t blkcnt, const void *buffer)
-{
- struct blk_desc *desc;
- int ret;
-
- ret = get_desc(uclass_id, devnum, &desc);
- if (ret)
- return ret;
- return blk_dwrite(desc, start, blkcnt, buffer);
-}
-
int blk_select_hwpart(struct udevice *dev, int hwpart)
{
const struct blk_ops *ops = blk_get_ops(dev);
@@ -479,7 +441,7 @@ long blk_read(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *buf)
start, blkcnt, desc->blksz, buf))
return blkcnt;
- if (IS_ENABLED(CONFIG_BOUNCE_BUFFER)) {
+ if (IS_ENABLED(CONFIG_BOUNCE_BUFFER) && desc->bb) {
struct blk_bounce_buffer bbstate = { .dev = dev };
int ret;
@@ -516,7 +478,7 @@ long blk_write(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
blkcache_invalidate(desc->uclass_id, desc->devnum);
- if (IS_ENABLED(CONFIG_BOUNCE_BUFFER)) {
+ if (IS_ENABLED(CONFIG_BOUNCE_BUFFER) && desc->bb) {
struct blk_bounce_buffer bbstate = { .dev = dev };
int ret;
diff --git a/drivers/block/blkmap.c b/drivers/block/blkmap.c
index 2bb0acc20f2..21201409ed4 100644
--- a/drivers/block/blkmap.c
+++ b/drivers/block/blkmap.c
@@ -66,21 +66,6 @@ struct blkmap_slice {
void (*destroy)(struct blkmap *bm, struct blkmap_slice *bms);
};
-/**
- * struct blkmap - Block map
- *
- * Data associated with a blkmap.
- *
- * @label: Human readable name of this blkmap
- * @blk: Underlying block device
- * @slices: List of slices associated with this blkmap
- */
-struct blkmap {
- char *label;
- struct udevice *blk;
- struct list_head slices;
-};
-
static bool blkmap_slice_contains(struct blkmap_slice *bms, lbaint_t blknr)
{
return (blknr >= bms->blknr) && (blknr < (bms->blknr + bms->blkcnt));
@@ -171,11 +156,11 @@ int blkmap_map_linear(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
bd = dev_get_uclass_plat(bm->blk);
lbd = dev_get_uclass_plat(lblk);
- if (lbd->blksz != bd->blksz)
- /* We could support block size translation, but we
- * don't yet.
- */
- return -EINVAL;
+ if (lbd->blksz != bd->blksz) {
+ /* update to match the mapped device */
+ bd->blksz = lbd->blksz;
+ bd->log2blksz = LOG2(bd->blksz);
+ }
linear = malloc(sizeof(*linear));
if (!linear)
@@ -383,14 +368,14 @@ U_BOOT_DRIVER(blkmap_blk) = {
.ops = &blkmap_blk_ops,
};
-int blkmap_dev_bind(struct udevice *dev)
+static int blkmap_dev_bind(struct udevice *dev)
{
struct blkmap *bm = dev_get_plat(dev);
struct blk_desc *bd;
int err;
err = blk_create_devicef(dev, "blkmap_blk", "blk", UCLASS_BLKMAP,
- dev_seq(dev), 512, 0, &bm->blk);
+ dev_seq(dev), DEFAULT_BLKSZ, 0, &bm->blk);
if (err)
return log_msg_ret("blk", err);
@@ -410,7 +395,7 @@ int blkmap_dev_bind(struct udevice *dev)
return 0;
}
-int blkmap_dev_unbind(struct udevice *dev)
+static int blkmap_dev_unbind(struct udevice *dev)
{
struct blkmap *bm = dev_get_plat(dev);
struct blkmap_slice *bms, *tmp;
diff --git a/drivers/block/blkmap_helper.c b/drivers/block/blkmap_helper.c
new file mode 100644
index 00000000000..bfba14110d2
--- /dev/null
+++ b/drivers/block/blkmap_helper.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * blkmap helper function
+ *
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#include <blk.h>
+#include <blkmap.h>
+#include <dm/device.h>
+#include <dm/device-internal.h>
+
+int blkmap_create_ramdisk(const char *label, ulong image_addr, ulong image_size,
+ struct udevice **devp)
+{
+ int ret;
+ lbaint_t blknum;
+ struct blkmap *bm;
+ struct blk_desc *desc;
+ struct udevice *bm_dev;
+
+ ret = blkmap_create(label, &bm_dev);
+ if (ret) {
+ log_err("failed to create blkmap\n");
+ return ret;
+ }
+
+ bm = dev_get_plat(bm_dev);
+ desc = dev_get_uclass_plat(bm->blk);
+ blknum = image_size >> desc->log2blksz;
+ ret = blkmap_map_pmem(bm_dev, 0, blknum, image_addr);
+ if (ret) {
+ log_err("Unable to map %#llx at block %d : %d\n",
+ (unsigned long long)image_addr, 0, ret);
+ goto err;
+ }
+ log_info("Block %d+0x" LBAF " mapped to %#llx\n", 0, blknum,
+ (unsigned long long)image_addr);
+
+ ret = device_probe(bm->blk);
+ if (ret)
+ goto err;
+
+ if (devp)
+ *devp = bm_dev;
+
+ return 0;
+
+err:
+ blkmap_destroy(bm_dev);
+
+ return ret;
+}
diff --git a/drivers/block/host-uclass.c b/drivers/block/host-uclass.c
index 6460d968c23..b3647e3ce33 100644
--- a/drivers/block/host-uclass.c
+++ b/drivers/block/host-uclass.c
@@ -13,6 +13,7 @@
#include <blk.h>
#include <dm.h>
#include <malloc.h>
+#include <part.h>
#include <sandbox_host.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
@@ -29,7 +30,8 @@ struct host_priv {
struct udevice *cur_dev;
};
-int host_create_device(const char *label, bool removable, struct udevice **devp)
+int host_create_device(const char *label, bool removable, unsigned long blksz,
+ struct udevice **devp)
{
char dev_name[30], *str, *label_new;
struct host_sb_plat *plat;
@@ -68,6 +70,12 @@ int host_create_device(const char *label, bool removable, struct udevice **devp)
struct blk_desc *desc = dev_get_uclass_plat(blk);
desc->removable = removable;
+
+ /* update blk device's block size with the provided one */
+ if (blksz != desc->blksz) {
+ desc->blksz = blksz;
+ desc->log2blksz = LOG2(desc->blksz);
+ }
}
plat = dev_get_plat(dev);
@@ -95,12 +103,13 @@ int host_attach_file(struct udevice *dev, const char *filename)
}
int host_create_attach_file(const char *label, const char *filename,
- bool removable, struct udevice **devp)
+ bool removable, unsigned long blksz,
+ struct udevice **devp)
{
struct udevice *dev;
int ret;
- ret = host_create_device(label, removable, &dev);
+ ret = host_create_device(label, removable, blksz, &dev);
if (ret)
return log_msg_ret("cre", ret);
diff --git a/drivers/block/host_dev.c b/drivers/block/host_dev.c
index 64422417b74..30c74157934 100644
--- a/drivers/block/host_dev.c
+++ b/drivers/block/host_dev.c
@@ -58,6 +58,11 @@ static int host_sb_attach_file(struct udevice *dev, const char *filename)
size = os_filesize(fd);
desc = dev_get_uclass_plat(blk);
+ if (size % desc->blksz) {
+ printf("The size of host backing file '%s' is not multiple of "
+ "the device block size\n", filename);
+ goto err_fname;
+ }
desc->lba = size / desc->blksz;
/* write this in last, when nothing can go wrong */
@@ -73,7 +78,7 @@ err_fname:
return ret;
}
-int host_sb_detach_file(struct udevice *dev)
+static int host_sb_detach_file(struct udevice *dev)
{
struct host_sb_plat *plat = dev_get_plat(dev);
int ret;
@@ -105,7 +110,7 @@ static int host_sb_bind(struct udevice *dev)
int ret;
ret = blk_create_devicef(dev, "sandbox_host_blk", "blk", UCLASS_HOST,
- dev_seq(dev), 512, 0, &blk);
+ dev_seq(dev), DEFAULT_BLKSZ, 0, &blk);
if (ret)
return log_msg_ret("blk", ret);
@@ -123,7 +128,7 @@ static int host_sb_bind(struct udevice *dev)
return 0;
}
-struct host_ops host_sb_ops = {
+static struct host_ops host_sb_ops = {
.attach_file = host_sb_attach_file,
.detach_file = host_sb_detach_file,
};
diff --git a/drivers/block/rkmtd.c b/drivers/block/rkmtd.c
new file mode 100644
index 00000000000..c55f052e51b
--- /dev/null
+++ b/drivers/block/rkmtd.c
@@ -0,0 +1,1152 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Some functions are derived from:
+ * https://github.com/rockchip-linux/u-boot/blob/next-dev/drivers/rknand/rk_ftl_arm_v7.S
+ * Copyright (c) 2016-2018, Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * Driver interface derived from:
+ * /drivers/block/host_dev.c
+ * /drivers/block/host-uclass.c
+ * Copyright 2022 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * Copyright (C) 2023 Johan Jonker <jbx6244@gmail.com>
+ */
+
+#include <blk.h>
+#include <dm.h>
+#include <nand.h>
+#include <part.h>
+#include <rkmtd.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dm/device-internal.h>
+#include <dm/devres.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+#include <dm/uclass-internal.h>
+#include <linux/mtd/mtd.h>
+#if !IS_ENABLED(CONFIG_SANDBOX)
+#include <linux/mtd/rawnand.h>
+#endif
+#include <u-boot/crc.h>
+
+struct nand_para_info nand_para_tbl[] = {
+ {6, {0x2c, 0x64, 0x44, 0x4b, 0xa9, 0x00}, 4, 1, 16, 256, 2, 2, 2048, 0x01df, 3, 17, 40, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x2c, 0x44, 0x44, 0x4b, 0xa9, 0x00}, 4, 1, 16, 256, 2, 2, 1064, 0x01df, 3, 17, 40, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x2c, 0x68, 0x04, 0x4a, 0xa9, 0x00}, 4, 1, 8, 256, 2, 2, 2048, 0x011f, 1, 0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {5, {0x2c, 0x88, 0x04, 0x4b, 0xa9, 0x00}, 4, 1, 16, 256, 2, 2, 2048, 0x011f, 1, 0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x2c, 0xa8, 0x05, 0xcb, 0xa9, 0x00}, 4, 2, 16, 256, 2, 2, 2048, 0x011f, 1, 0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x2c, 0x68, 0x04, 0x46, 0x89, 0x00}, 4, 1, 8, 256, 2, 2, 2048, 0x011f, 1, 0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x2c, 0x48, 0x04, 0x4a, 0xa5, 0x00}, 4, 1, 8, 256, 2, 2, 1024, 0x011f, 1, 0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x2c, 0x84, 0x64, 0x3c, 0xa5, 0x00}, 4, 1, 32, 512, 2, 2, 1024, 0x01df, 3, 17, 40, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {5, {0x2c, 0x84, 0x64, 0x54, 0xa9, 0x00}, 4, 1, 32, 512, 2, 2, 1024, 0x01df, 4, 18, 60, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x2c, 0xd7, 0x94, 0x3e, 0x84, 0x00}, 4, 1, 8, 128, 2, 2, 4096, 0x0117, 1, 0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x2c, 0x48, 0x04, 0x46, 0x85, 0x00}, 4, 1, 8, 256, 2, 2, 1024, 0x011f, 1, 0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x2c, 0x88, 0x05, 0xc6, 0x89, 0x00}, 4, 2, 8, 256, 2, 2, 2048, 0x011f, 1, 0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {5, {0x2c, 0x88, 0x24, 0x4b, 0xa9, 0x00}, 4, 1, 16, 256, 2, 2, 2048, 0x011f, 1, 0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x2c, 0x68, 0x00, 0x27, 0xa9, 0x00}, 4, 1, 16, 128, 1, 2, 2048, 0x011f, 0, 0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {5, {0x2c, 0x64, 0x64, 0x56, 0xa5, 0x00}, 4, 1, 24, 512, 2, 2, 700, 0x01df, 4, 18, 60, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x2c, 0x84, 0xc5, 0x4b, 0xa9, 0x00}, 4, 2, 16, 256, 2, 2, 2048, 0x01df, 3, 17, 40, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x2c, 0xd5, 0xd1, 0xa6, 0x68, 0x00}, 4, 2, 8, 64, 1, 2, 2048, 0x0117, 0, 0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x2c, 0xdc, 0x90, 0xa6, 0x54, 0x00}, 4, 1, 8, 64, 1, 2, 1024, 0x0117, 0, 0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {5, {0x2c, 0x64, 0x64, 0x54, 0xa4, 0x00}, 4, 1, 32, 512, 2, 1, 1024, 0x01df, 4, 18, 60, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {5, {0x2c, 0x84, 0x44, 0x32, 0xaa, 0x00}, 4, 1, 32, 512, 2, 1, 2184, 0x05c7, 5, 19, 60, 32, 1, 0, 1, 0, 1, {0, 0, 0, 0, 0}},
+ {5, {0x2c, 0x64, 0x44, 0x32, 0xa5, 0x00}, 4, 1, 32, 512, 2, 1, 1048, 0x05c7, 5, 19, 60, 32, 1, 0, 1, 0, 1, {0, 0, 0, 0, 0}},
+ {5, {0x2c, 0x64, 0x64, 0x3c, 0xa5, 0x00}, 4, 1, 32, 512, 2, 1, 1044, 0x01df, 3, 17, 40, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {5, {0x2c, 0x84, 0x44, 0x32, 0xaa, 0x00}, 4, 1, 32, 512, 2, 1, 2184, 0x05c7, 5, 19, 60, 32, 1, 0, 4, 0, 1, {0, 0, 0, 0, 0}},
+ {5, {0x2c, 0x84, 0x44, 0x34, 0xaa, 0x00}, 4, 1, 32, 512, 2, 1, 2184, 0x05c7, 5, 19, 60, 32, 1, 0, 4, 0, 1, {0, 0, 0, 0, 0}},
+ {5, {0x2c, 0x84, 0xc4, 0x34, 0xaa, 0x00}, 4, 1, 32, 512, 2, 1, 2184, 0x05c7, 5, 19, 60, 32, 1, 0, 1, 0, 1, {0, 0, 0, 0, 0}},
+ {5, {0x2c, 0x84, 0x44, 0x34, 0xa4, 0x00}, 4, 1, 32, 512, 2, 1, 2184, 0x05c7, 5, 19, 60, 32, 1, 0, 1, 0, 1, {0, 0, 0, 0, 0}},
+ {5, {0x2c, 0x84, 0x64, 0x3c, 0xa9, 0x00}, 4, 1, 32, 512, 2, 2, 1024, 0x01df, 3, 17, 40, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x2c, 0xa4, 0x64, 0x32, 0xaa, 0x04}, 4, 1, 32, 1024, 2, 1, 2192, 0x05c7, 10, 19, 60, 32, 1, 0, 4, 0, 1, {0, 0, 0, 0, 0}},
+ {6, {0xad, 0xde, 0x94, 0xd2, 0x04, 0x43}, 2, 1, 16, 256, 2, 2, 2048, 0x01d9, 1, 1, 24, 32, 4, 0, 3, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0xad, 0xd7, 0x94, 0xda, 0x74, 0xc3}, 2, 1, 16, 256, 2, 2, 1024, 0x01d9, 1, 2, 40, 32, 4, 0, 3, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0xad, 0xd7, 0x94, 0x91, 0x60, 0x44}, 2, 1, 16, 256, 2, 2, 1046, 0x01d9, 1, 3, 40, 32, 4, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4}, 2, 1, 16, 256, 2, 2, 2090, 0x01d9, 1, 4, 40, 32, 4, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0xad, 0xde, 0x94, 0xeb, 0x74, 0x44}, 2, 1, 32, 256, 2, 2, 1066, 0x01d9, 1, 7, 40, 32, 4, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0xad, 0xd5, 0x94, 0xda, 0x74, 0xc4}, 2, 1, 16, 256, 2, 2, 530, 0x01d9, 1, 3, 40, 32, 4, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0xad, 0xd7, 0x94, 0x9a, 0x74, 0x42}, 2, 1, 16, 256, 2, 2, 1024, 0x0119, 1, 0, 24, 32, 4, 0, 3, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0xad, 0xde, 0x14, 0xa7, 0x42, 0x4a}, 2, 1, 32, 256, 2, 2, 1060, 0x01d9, 2, 5, 40, 32, 4, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0xad, 0xd7, 0x14, 0x9e, 0x34, 0x4a}, 2, 1, 16, 256, 2, 2, 1056, 0x01d9, 2, 5, 40, 32, 4, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0xad, 0xde, 0x94, 0xa7, 0x42, 0x48}, 2, 1, 32, 256, 2, 2, 1060, 0x01d9, 2, 5, 40, 32, 4, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0xad, 0xde, 0x14, 0xab, 0x42, 0x4a}, 2, 1, 32, 256, 2, 2, 1056, 0x01d9, 2, 6, 40, 32, 3, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0xad, 0x3a, 0x14, 0xab, 0x42, 0x4a}, 2, 1, 32, 256, 2, 2, 2092, 0x01d9, 2, 5, 40, 32, 3, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0xad, 0xd5, 0x94, 0x9a, 0x74, 0x42}, 2, 1, 16, 256, 2, 1, 1024, 0x0111, 1, 0, 24, 32, 4, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0xad, 0x3a, 0x14, 0x03, 0x08, 0x50}, 2, 1, 32, 388, 2, 2, 1362, 0x01d9, 9, 8, 40, 32, 3, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x89, 0x64, 0x44, 0x4b, 0xa9, 0x00}, 7, 1, 16, 256, 2, 2, 2048, 0x01df, 3, 17, 40, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x89, 0x88, 0x24, 0x4b, 0xa9, 0x84}, 7, 1, 16, 256, 2, 2, 2048, 0x01df, 3, 17, 40, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x89, 0x88, 0x24, 0x4b, 0xa9, 0x00}, 7, 1, 16, 256, 2, 2, 2048, 0x0117, 1, 0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x89, 0x68, 0x24, 0x4a, 0xa9, 0x00}, 7, 1, 8, 256, 2, 2, 2048, 0x0117, 1, 0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x89, 0x68, 0x04, 0x4a, 0xa9, 0x00}, 7, 1, 8, 256, 2, 2, 2048, 0x0117, 1, 0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x89, 0xd7, 0x94, 0x3e, 0x84, 0x00}, 7, 1, 8, 256, 2, 2, 2048, 0x0117, 1, 0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x89, 0x68, 0x04, 0x46, 0xa9, 0x00}, 7, 1, 8, 256, 2, 2, 2048, 0x0117, 1, 0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {5, {0x89, 0x64, 0x64, 0x3c, 0xa1, 0x00}, 7, 1, 32, 512, 2, 1, 1024, 0x01c7, 4, 17, 40, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {5, {0x89, 0x84, 0x64, 0x3c, 0xa5, 0x00}, 7, 1, 32, 512, 2, 2, 1024, 0x01c7, 4, 17, 40, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x89, 0x88, 0x24, 0x3b, 0xa9, 0x00}, 7, 1, 16, 192, 2, 2, 2048, 0x0117, 12, 0, 24, 32, 1, 0, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x98, 0xd7, 0x84, 0x93, 0x72, 0x57}, 1, 1, 32, 256, 2, 1, 1060, 0x05c1, 2, 33, 40, 32, 2, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x98, 0xde, 0x84, 0x93, 0x72, 0x57}, 1, 1, 32, 256, 2, 1, 2092, 0x05c1, 2, 33, 40, 32, 2, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x98, 0x3a, 0x85, 0x93, 0x76, 0x57}, 1, 2, 32, 256, 2, 1, 2092, 0x05e1, 2, 33, 40, 32, 2, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x98, 0xd5, 0x84, 0x32, 0x72, 0x56}, 1, 1, 16, 128, 2, 1, 2056, 0x05c1, 2, 33, 40, 32, 2, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x98, 0xd7, 0x94, 0x32, 0x76, 0x56}, 1, 1, 16, 128, 2, 2, 2058, 0x05d1, 2, 33, 40, 32, 2, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x98, 0xde, 0x94, 0x82, 0x76, 0x56}, 1, 1, 16, 256, 2, 2, 2062, 0x05d1, 1, 33, 40, 32, 2, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x98, 0xde, 0x94, 0x93, 0x76, 0x50}, 1, 1, 32, 256, 2, 2, 1066, 0x05d9, 2, 34, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x98, 0x3a, 0x95, 0x93, 0x7a, 0x50}, 1, 2, 32, 256, 2, 2, 1066, 0x05d9, 2, 34, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x98, 0xd7, 0x94, 0x32, 0x76, 0x55}, 1, 1, 16, 128, 2, 2, 2050, 0x0191, 2, 0, 24, 32, 1, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x98, 0xde, 0x94, 0x93, 0x76, 0x57}, 1, 1, 32, 256, 2, 2, 1058, 0x05d9, 2, 33, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x98, 0xd7, 0x84, 0x93, 0x72, 0x50}, 1, 1, 32, 256, 2, 1, 1060, 0x05c1, 2, 34, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x98, 0xde, 0x94, 0x93, 0x76, 0x51}, 1, 1, 32, 256, 2, 2, 1074, 0x05d9, 2, 35, 40, 32, 3, 1, 4, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x98, 0x3a, 0x94, 0x93, 0x76, 0x51}, 1, 1, 32, 256, 2, 2, 2106, 0x05d9, 2, 35, 40, 32, 3, 1, 4, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x98, 0xd7, 0x84, 0x93, 0x72, 0x51}, 1, 1, 32, 256, 2, 1, 1056, 0x05d9, 2, 35, 40, 32, 3, 1, 4, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x98, 0xde, 0x94, 0x93, 0x76, 0xd1}, 1, 1, 32, 256, 2, 2, 1074, 0x05d9, 2, 35, 40, 32, 3, 1, 4, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x45, 0xde, 0x94, 0x93, 0x76, 0x57}, 8, 1, 32, 256, 2, 2, 1058, 0x05d9, 2, 66, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x45, 0xd7, 0x84, 0x93, 0x72, 0x57}, 8, 1, 32, 256, 2, 1, 1060, 0x05c1, 2, 66, 40, 32, 2, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x45, 0xde, 0xa4, 0x82, 0x76, 0x56}, 8, 1, 16, 256, 2, 2, 2082, 0x01d9, 1, 65, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x45, 0xde, 0x94, 0x93, 0x76, 0x50}, 8, 1, 32, 256, 2, 2, 1066, 0x05d9, 2, 67, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x45, 0xd7, 0x84, 0x93, 0x72, 0x50}, 8, 1, 32, 256, 2, 1, 1060, 0x05c1, 2, 67, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x45, 0xde, 0xa4, 0x82, 0x76, 0xd7}, 8, 1, 16, 256, 2, 2, 2090, 0x04d9, 1, 66, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x45, 0xde, 0x84, 0x93, 0x72, 0x57}, 8, 1, 32, 256, 2, 1, 2092, 0x05c1, 2, 66, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x45, 0x3a, 0x94, 0x93, 0x76, 0x51}, 8, 1, 32, 256, 2, 2, 2106, 0x01d9, 2, 68, 40, 32, 3, 1, 4, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x45, 0xde, 0x94, 0x93, 0x76, 0x51}, 8, 1, 32, 256, 2, 2, 1074, 0x01d9, 2, 68, 40, 32, 3, 1, 4, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x45, 0x3a, 0xa4, 0x93, 0x7a, 0x50}, 8, 1, 32, 256, 2, 2, 2138, 0x05d9, 2, 0, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x45, 0xde, 0x94, 0x82, 0x76, 0x56}, 8, 1, 16, 256, 2, 2, 2062, 0x01d9, 1, 0, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0x45, 0xde, 0x94, 0x93, 0x76, 0xd7}, 8, 1, 32, 256, 2, 2, 1058, 0x05d9, 2, 66, 40, 32, 3, 1, 1, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0xec, 0xd7, 0x94, 0x7e, 0x64, 0x44}, 0, 1, 16, 128, 2, 2, 2048, 0x01d9, 2, 49, 60, 36, 3, 0, 3, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0xec, 0xde, 0xd5, 0x7e, 0x68, 0x44}, 0, 2, 16, 128, 2, 2, 2048, 0x01f9, 2, 49, 60, 36, 3, 0, 3, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0xec, 0xd7, 0x94, 0x7a, 0x54, 0x43}, 0, 1, 16, 128, 2, 2, 2076, 0x0199, 2, 0, 40, 36, 3, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0xec, 0xde, 0xd5, 0x7a, 0x58, 0x43}, 0, 2, 16, 128, 2, 2, 2076, 0x01b9, 2, 0, 40, 36, 3, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0xec, 0xd5, 0x94, 0x76, 0x54, 0x43}, 0, 1, 16, 128, 2, 2, 1038, 0x0119, 2, 0, 24, 36, 3, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0xec, 0xd7, 0x14, 0x76, 0x54, 0xc2}, 0, 1, 16, 128, 2, 2, 2076, 0x0491, 2, 0, 24, 40, 3, 1, 3, 0, 0, {0, 0, 0, 0, 0}},
+ {6, {0xec, 0xde, 0x94, 0xc3, 0xa4, 0xca}, 0, 1, 32, 792, 2, 1, 688, 0x04c1, 11, 50, 40, 32, 3, 1, 1, 0, 1, {0, 0, 0, 0, 0}},
+};
+
+#if !IS_ENABLED(CONFIG_SANDBOX)
+static int rkmtd_write_oob(struct rkmtd_dev *plat, ulong off, u_char *datbuf, u_char *oobbuf)
+{
+ struct mtd_info *mtd = plat->mtd;
+ struct mtd_oob_ops ops;
+ loff_t addr;
+ int ret;
+
+ off &= ~(mtd->writesize - 1);
+ addr = (loff_t)off;
+
+ memset(&ops, 0, sizeof(ops));
+ ops.datbuf = datbuf;
+ ops.oobbuf = oobbuf;
+ ops.len = mtd->writesize;
+ ops.ooblen = mtd->oobsize;
+ ops.mode = MTD_OPS_PLACE_OOB;
+ ret = mtd_write_oob(mtd, addr, &ops);
+ if (ret < 0) {
+ debug("Error (%d) writing page %08lx\n", ret, off);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int rkmtd_read_oob(struct rkmtd_dev *plat, ulong off, u_char *datbuf, u_char *oobbuf)
+{
+ struct mtd_info *mtd = plat->mtd;
+ struct mtd_oob_ops ops;
+ loff_t addr;
+ int ret;
+
+ off &= ~(mtd->writesize - 1);
+ addr = (loff_t)off;
+
+ memset(&ops, 0, sizeof(ops));
+ ops.datbuf = datbuf;
+ ops.oobbuf = oobbuf;
+ ops.len = mtd->writesize;
+ ops.ooblen = mtd->oobsize;
+ ops.mode = MTD_OPS_PLACE_OOB;
+ ret = mtd_read_oob(mtd, addr, &ops);
+ if (ret < 0) {
+ debug("Error (%d) reading page %08lx\n", ret, off);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int rkmtd_erase(struct rkmtd_dev *plat, ulong off)
+{
+ struct mtd_info *mtd = plat->mtd;
+ struct erase_info info;
+ loff_t addr;
+ int ret;
+
+ off &= ~(mtd->writesize - 1);
+ addr = (loff_t)off;
+
+ memset(&info, 0, sizeof(info));
+ info.mtd = mtd;
+ info.addr = addr;
+ info.len = mtd->erasesize;
+ info.scrub = 1;
+ ret = mtd_erase(mtd, &info);
+ if (ret) {
+ debug("Error (%d) erasing page %08lx\n", ret, off);
+ return 1;
+ }
+
+ return 0;
+}
+#endif
+void rkmtd_scan_block(struct rkmtd_dev *plat)
+{
+ plat->blk_counter = 0;
+
+#if !IS_ENABLED(CONFIG_SANDBOX)
+ u32 blk;
+
+ for (blk = 0; blk < plat->boot_blks; blk++) {
+ rkmtd_read_oob(plat, blk * plat->mtd->erasesize, plat->datbuf, plat->oobbuf);
+ if (*(u32 *)plat->datbuf == RK_TAG) {
+ struct sector0 *sec0 = (struct sector0 *)plat->datbuf;
+
+ rkmtd_rc4(plat->datbuf, 512);
+
+ plat->idblock[plat->blk_counter].blk = blk;
+ plat->idblock[plat->blk_counter].offset = sec0->boot_code1_offset;
+ plat->idblock[plat->blk_counter].boot_size = sec0->flash_boot_size;
+
+ debug("\nblk : %d\n", plat->idblock[plat->blk_counter].blk);
+ debug("offset : %d\n", plat->idblock[plat->blk_counter].offset);
+ debug("boot_size : %d\n", plat->idblock[plat->blk_counter].boot_size);
+
+ plat->blk_counter += 1;
+
+ if (plat->blk_counter >= ARRAY_SIZE(plat->idblock))
+ return;
+ }
+ }
+#endif
+}
+
+void rkmtd_read_block(struct rkmtd_dev *plat, u32 idx, u8 *buf)
+{
+#if !IS_ENABLED(CONFIG_SANDBOX)
+ ulong off = plat->idblock[idx].blk * plat->mtd->erasesize;
+ struct nand_chip *chip = mtd_to_nand(plat->mtd);
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ int counter = 0;
+ u32 spare0 = 0;
+ u32 *p_spare;
+ int sector;
+ int page;
+
+ rkmtd_read_oob(plat, off,
+ plat->datbuf, plat->oobbuf);
+
+ memcpy(buf, plat->datbuf, BLK_SIZE);
+
+ while (counter < plat->idblock[idx].boot_size) {
+ if (spare0)
+ page = (plat->idblock[idx].offset + spare0) / 4;
+ else
+ page = (plat->idblock[idx].offset + counter) / 4;
+
+ rkmtd_read_oob(plat,
+ off + page * plat->mtd->writesize,
+ plat->datbuf, plat->oobbuf);
+
+ sector = plat->idblock[idx].offset + counter;
+
+ memcpy(&buf[(sector / 4) * BLK_SIZE], plat->datbuf, BLK_SIZE);
+
+ p_spare = (u32 *)&plat->oobbuf[(ecc->steps - 1) * NFC_SYS_DATA_SIZE];
+
+ spare0 = *p_spare;
+ if (spare0 == -1)
+ break;
+
+ counter += 4;
+ }
+#endif
+}
+
+void rkmtd_write_block(struct rkmtd_dev *plat, u32 idx, u8 *buf)
+{
+#if !IS_ENABLED(CONFIG_SANDBOX)
+ ulong off = plat->idblock[idx].blk * plat->mtd->erasesize;
+ struct nand_chip *chip = mtd_to_nand(plat->mtd);
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ int counter = 0;
+ u32 *p_spare;
+ int sector;
+ int page;
+ int j, w, r;
+
+ rkmtd_erase(plat, off);
+
+ memset(plat->datbuf, 0xff, plat->mtd->writesize);
+ memcpy(plat->datbuf, buf, BLK_SIZE);
+ memset(plat->oobbuf, 0xff, plat->mtd->oobsize);
+
+ rkmtd_write_oob(plat, off,
+ plat->datbuf, plat->oobbuf);
+
+ while (counter < plat->idblock[idx].boot_size) {
+ sector = plat->idblock[idx].offset + counter;
+
+ memset(plat->datbuf, 0xff, plat->mtd->writesize);
+ memcpy(plat->datbuf, &buf[(sector / 4) * BLK_SIZE], BLK_SIZE);
+ memset(plat->oobbuf, 0xff, plat->mtd->oobsize);
+
+ p_spare = (u32 *)&plat->oobbuf[(ecc->steps - 1) * NFC_SYS_DATA_SIZE];
+
+ *p_spare = (plat->page_table[sector / 4 + 1] - 1) * 4;
+
+ page = plat->page_table[sector / 4];
+
+ rkmtd_write_oob(plat,
+ off + page * plat->mtd->writesize,
+ plat->datbuf, plat->oobbuf);
+
+ counter += 4;
+ }
+
+ memset(plat->check, 0, BUF_SIZE);
+ rkmtd_read_block(plat, idx, plat->check);
+
+ for (j = 0; j < BLK_SIZE; j++) {
+ w = *(buf + j);
+ r = *(plat->check + j);
+
+ if (r != w)
+ goto dumpblock;
+ }
+
+ for (j = 0; j < (plat->idblock[idx].boot_size * 512); j++) {
+ w = *(buf + plat->idblock[idx].offset * 512 + j);
+ r = *(plat->check + plat->idblock[idx].offset * 512 + j);
+
+ if (r != w)
+ goto dumpblock;
+ }
+
+ debug("write OK\n");
+ return;
+
+dumpblock:
+ debug("write and check error:%x r=%x w=%x\n", j, r, w);
+
+ plat->idblock[idx].offset = 0;
+ plat->idblock[idx].boot_size = 0;
+
+ memset(plat->datbuf, 0xff, plat->mtd->writesize);
+ memset(plat->datbuf, 0, BLK_SIZE);
+ memset(plat->oobbuf, 0xff, plat->mtd->oobsize);
+
+ rkmtd_write_oob(plat, off, plat->datbuf, plat->oobbuf);
+#endif
+}
+
+ulong rkmtd_bread(struct udevice *udev, lbaint_t start,
+ lbaint_t blkcnt, void *dst)
+{
+ struct blk_desc *block_dev = dev_get_uclass_plat(udev);
+ struct udevice *parent_dev = dev_get_parent(udev);
+ struct rkmtd_dev *plat = dev_get_plat(parent_dev);
+ char *buf = dst;
+ int i;
+
+ if (blkcnt == 0)
+ return 0;
+
+ if (start > (block_dev->lba - 1) ||
+ (start + blkcnt) > block_dev->lba)
+ return 0;
+
+ memset(dst, 0, blkcnt * block_dev->blksz);
+
+ for (i = start; i < (start + blkcnt); i++) {
+ if (i == 0) {
+ debug("mbr : %d\n", i);
+
+ memcpy(&buf[(i - start) * block_dev->blksz],
+ plat->mbr, sizeof(legacy_mbr));
+ } else if (i == 1) {
+ debug("gpt_h : %d\n", i);
+
+ memcpy(&buf[(i - start) * block_dev->blksz],
+ plat->gpt_h, sizeof(gpt_header));
+ } else if (i == (block_dev->lba - 1)) {
+ debug("gpt_h2 : %d\n", i);
+
+ memcpy(&buf[(i - start) * block_dev->blksz],
+ plat->gpt_h2, sizeof(gpt_header));
+ } else if (i == 2 || i == (block_dev->lba - 33)) {
+ debug("gpt_e : %d\n", i);
+
+ memcpy(&buf[(i - start) * block_dev->blksz],
+ plat->gpt_e, sizeof(gpt_entry));
+ } else if (i >= 64 && i < (block_dev->lba - 33)) {
+ debug("rd : %d\n", i);
+
+ memcpy(&buf[(i - start) * block_dev->blksz],
+ &plat->idb[(i - 64) * block_dev->blksz], block_dev->blksz);
+ }
+ }
+
+ return blkcnt;
+}
+
+ulong rkmtd_bwrite(struct udevice *udev, lbaint_t start,
+ lbaint_t blkcnt, const void *src)
+{
+ struct blk_desc *block_dev = dev_get_uclass_plat(udev);
+ struct udevice *parent_dev = dev_get_parent(udev);
+ struct rkmtd_dev *plat = dev_get_plat(parent_dev);
+ struct sector0 *sec0;
+ int i, j;
+
+ if (blkcnt == 0)
+ return 0;
+
+ if (start > (block_dev->lba - 1) ||
+ (start + blkcnt) > block_dev->lba)
+ return 0;
+
+ for (i = start; i < (start + blkcnt); i++) {
+ debug("wr : %d\n", i);
+
+ if (i >= 64 && i < (block_dev->lba - 33)) {
+ if (i == 64) {
+ debug("first block\n");
+
+ plat->idb_need_write_back = 1;
+ memset(plat->idb, 0, BUF_SIZE);
+ }
+
+ if (plat->idb_need_write_back) {
+ char *buf = (char *)src;
+
+ memcpy(&plat->idb[(i - 64) * block_dev->blksz],
+ &buf[(i - start) * block_dev->blksz],
+ block_dev->blksz);
+
+ if (i == 64) {
+ memcpy(plat->check, plat->idb, 512);
+
+ if (*(u32 *)plat->check == RK_TAG) {
+ rkmtd_rc4(plat->check, 512);
+
+ sec0 = (struct sector0 *)plat->check;
+ plat->offset = sec0->boot_code1_offset;
+ plat->boot_size = sec0->flash_boot_size;
+
+ if (plat->offset + plat->boot_size > 512) {
+ debug("max size limit\n");
+ plat->idb_need_write_back = 0;
+ }
+ } else {
+ debug("no IDB block found\n");
+ plat->idb_need_write_back = 0;
+ }
+ }
+
+ if (i == (64 + plat->offset + plat->boot_size - 1)) {
+ debug("last block\n");
+
+ plat->idb_need_write_back = 0;
+
+ if (!plat->blk_counter) {
+ plat->idblock[0].blk = 2;
+ plat->idblock[1].blk = 3;
+ plat->idblock[2].blk = 4;
+ plat->idblock[3].blk = 5;
+ plat->idblock[4].blk = 6;
+ plat->blk_counter = 5;
+ }
+
+ for (j = 0; j < plat->blk_counter; j++) {
+ if (plat->idblock[j].blk < plat->boot_blks) {
+ plat->idblock[j].offset = plat->offset;
+ plat->idblock[j].boot_size = plat->boot_size;
+ rkmtd_write_block(plat, j, plat->idb);
+ }
+ }
+
+ rkmtd_scan_block(plat);
+
+ if (!IS_ENABLED(CONFIG_SANDBOX))
+ memset(plat->idb, 0, BUF_SIZE);
+
+ if (plat->blk_counter)
+ rkmtd_read_block(plat, 0, plat->idb);
+ }
+ }
+ } else if (plat->idb_need_write_back) {
+ plat->idb_need_write_back = 0;
+
+ memset(plat->idb, 0, BUF_SIZE);
+
+ if (plat->blk_counter)
+ rkmtd_read_block(plat, 0, plat->idb);
+ }
+ }
+
+ return blkcnt;
+}
+
+static const struct blk_ops rkmtd_blk_ops = {
+ .read = rkmtd_bread,
+ .write = rkmtd_bwrite,
+};
+
+U_BOOT_DRIVER(rkmtd_blk) = {
+ .name = "rkmtd_blk",
+ .id = UCLASS_BLK,
+ .ops = &rkmtd_blk_ops,
+};
+
+void rkmtd_build_page_table(struct rkmtd_dev *plat)
+{
+ u32 counter;
+ u32 counter2;
+
+ switch (plat->lsb_mode) {
+ case 0:
+ counter = 0;
+ do {
+ u16 val = counter;
+
+ plat->page_table[counter++] = val;
+ } while (counter != 512);
+ break;
+ case 1:
+ counter = 0;
+ do {
+ u16 val = counter;
+
+ if (counter > 3) {
+ u16 offset;
+
+ if (counter & 1)
+ offset = 3;
+ else
+ offset = 2;
+ val = 2 * counter - offset;
+ }
+ plat->page_table[counter++] = val;
+ } while (counter != 512);
+ break;
+ case 2:
+ counter = 0;
+ do {
+ u16 val = counter;
+
+ if (counter > 1)
+ val = 2 * counter - 1;
+ plat->page_table[counter++] = val;
+ } while (counter != 512);
+ break;
+ case 3:
+ counter = 0;
+ do {
+ u16 val = counter;
+
+ if (counter > 5) {
+ u16 offset;
+
+ if (counter & 1)
+ offset = 5;
+ else
+ offset = 4;
+ val = 2 * counter - offset;
+ }
+ plat->page_table[counter++] = val;
+ } while (counter != 512);
+ break;
+ case 4:
+ counter = 8;
+ plat->page_table[0] = 0;
+ plat->page_table[1] = 1;
+ plat->page_table[2] = 2;
+ plat->page_table[3] = 3;
+ plat->page_table[4] = 4;
+ plat->page_table[5] = 5;
+ plat->page_table[6] = 7;
+ plat->page_table[7] = 8;
+ do {
+ u32 offset;
+ u32 val;
+
+ if (counter & 1)
+ offset = 7;
+ else
+ offset = 6;
+ val = 2 * counter - offset;
+ plat->page_table[counter++] = val;
+ } while (counter != 512);
+ break;
+ case 5:
+ counter = 0;
+ counter2 = 16;
+ do {
+ u16 val = counter;
+
+ plat->page_table[counter++] = val;
+ } while (counter != 16);
+ do {
+ plat->page_table[counter++] = counter2;
+ counter2 = counter2 + 2;
+ } while (counter != 512);
+ break;
+ case 6:
+ counter = 0;
+ counter2 = 0;
+ do {
+ u16 val = counter;
+
+ if (counter > 5) {
+ u16 offset;
+
+ if (counter & 1)
+ offset = 12;
+ else
+ offset = 10;
+ val = counter2 - offset;
+ }
+ plat->page_table[counter++] = val;
+ counter2 = counter2 + 3;
+ } while (counter != 512);
+ break;
+ case 9:
+ counter = 3;
+ counter2 = 3;
+ plat->page_table[0] = 0;
+ plat->page_table[1] = 1;
+ plat->page_table[2] = 2;
+ do {
+ plat->page_table[counter++] = counter2;
+ counter2 = counter2 + 2;
+ } while (counter != 512);
+ break;
+ case 10:
+ counter = 0;
+ counter2 = 63;
+ do {
+ u16 val = counter;
+
+ plat->page_table[counter++] = val;
+ } while (counter != 63);
+ do {
+ plat->page_table[counter++] = counter2;
+ counter2 = counter2 + 2;
+ } while (counter != 512);
+ break;
+ case 11:
+ counter = 0;
+ do {
+ u16 val = counter;
+
+ plat->page_table[counter++] = val;
+ } while (counter != 8);
+ do {
+ u32 offset;
+ u32 val;
+
+ if (counter & 1)
+ offset = 7;
+ else
+ offset = 6;
+ val = 2 * counter - offset;
+ plat->page_table[counter++] = val;
+ } while (counter != 512);
+ break;
+ case 12:
+ counter = 4;
+ plat->page_table[0] = 0;
+ plat->page_table[1] = 1;
+ plat->page_table[2] = 2;
+ plat->page_table[3] = 3;
+ do {
+ u32 val = counter - 1 + (counter >> 1);
+
+ plat->page_table[counter++] = val;
+ } while (counter != 512);
+ break;
+ }
+}
+
+static inline u32 efi_crc32(const void *buf, u32 len)
+{
+ return crc32(0, buf, len);
+}
+
+int rkmtd_init_plat(struct udevice *dev)
+{
+ static const efi_guid_t partition_basic_data_guid = PARTITION_BASIC_DATA_GUID;
+ struct rkmtd_dev *plat = dev_get_plat(dev);
+ size_t efiname_len, dosname_len;
+ uchar name[] = "loader1";
+ u32 calc_crc32;
+ int k;
+
+ gen_rand_uuid_str(plat->uuid_disk_str, UUID_STR_FORMAT_GUID);
+ gen_rand_uuid_str(plat->uuid_part_str, UUID_STR_FORMAT_GUID);
+
+ debug("uuid_part_str : %s\n", plat->uuid_part_str);
+ debug("uuid_disk_str : %s\n", plat->uuid_disk_str);
+
+ plat->idb = devm_kzalloc(plat->dev, BUF_SIZE, GFP_KERNEL);
+ if (!plat->idb)
+ return -ENOMEM;
+
+ plat->check = devm_kzalloc(plat->dev, BUF_SIZE, GFP_KERNEL);
+ if (!plat->check)
+ return -ENOMEM;
+
+ plat->mbr = devm_kzalloc(plat->dev, sizeof(legacy_mbr), GFP_KERNEL);
+ if (!plat->mbr)
+ return -ENOMEM;
+
+ plat->gpt_e = devm_kzalloc(plat->dev, sizeof(gpt_entry), GFP_KERNEL);
+ if (!plat->gpt_e)
+ return -ENOMEM;
+
+ plat->gpt_h = devm_kzalloc(plat->dev, sizeof(gpt_header), GFP_KERNEL);
+ if (!plat->gpt_h)
+ return -ENOMEM;
+
+ plat->gpt_h2 = devm_kzalloc(plat->dev, sizeof(gpt_header), GFP_KERNEL);
+ if (!plat->gpt_h2)
+ return -ENOMEM;
+
+ /* Init mbr */
+ plat->mbr->signature = MSDOS_MBR_SIGNATURE;
+ plat->mbr->partition_record[0].sys_ind = EFI_PMBR_OSTYPE_EFI_GPT;
+ plat->mbr->partition_record[0].start_sect = 1;
+ plat->mbr->partition_record[0].nr_sects = LBA - 1;
+
+ /* Init gpt_e */
+ plat->gpt_e->starting_lba = cpu_to_le64(64);
+ plat->gpt_e->ending_lba = cpu_to_le64(LBA - 34);
+
+ debug("starting_lba : %llu\n", le64_to_cpu(plat->gpt_e->starting_lba));
+ debug("ending_lba : %llu\n", le64_to_cpu(plat->gpt_e->ending_lba));
+
+ memcpy(plat->gpt_e->partition_type_guid.b, &partition_basic_data_guid, 16);
+
+ uuid_str_to_bin(plat->uuid_part_str, plat->gpt_e->unique_partition_guid.b,
+ UUID_STR_FORMAT_GUID);
+
+ efiname_len = sizeof(plat->gpt_e->partition_name) / sizeof(efi_char16_t);
+ dosname_len = sizeof(name);
+
+ for (k = 0; k < min(dosname_len, efiname_len); k++)
+ plat->gpt_e->partition_name[k] = (efi_char16_t)(name[k]);
+
+ /* Init gpt_h */
+ plat->gpt_h->signature = cpu_to_le64(GPT_HEADER_SIGNATURE_UBOOT);
+ plat->gpt_h->revision = cpu_to_le32(GPT_HEADER_REVISION_V1);
+ plat->gpt_h->header_size = cpu_to_le32(sizeof(gpt_header));
+ plat->gpt_h->first_usable_lba = cpu_to_le64(64);
+ plat->gpt_h->last_usable_lba = cpu_to_le64(LBA - 34);
+ plat->gpt_h->num_partition_entries = cpu_to_le32(1);
+ plat->gpt_h->sizeof_partition_entry = cpu_to_le32(sizeof(gpt_entry));
+
+ uuid_str_to_bin(plat->uuid_disk_str, plat->gpt_h->disk_guid.b,
+ UUID_STR_FORMAT_GUID);
+
+ plat->gpt_h->partition_entry_array_crc32 = 0;
+ calc_crc32 = efi_crc32((const unsigned char *)plat->gpt_e,
+ le32_to_cpu(plat->gpt_h->num_partition_entries) *
+ le32_to_cpu(plat->gpt_h->sizeof_partition_entry));
+ plat->gpt_h->partition_entry_array_crc32 = cpu_to_le32(calc_crc32);
+
+ debug("partition crc32 : 0x%08x\n", calc_crc32);
+
+ plat->gpt_h->my_lba = cpu_to_le64(1);
+ plat->gpt_h->partition_entry_lba = cpu_to_le64(2);
+ plat->gpt_h->alternate_lba = cpu_to_le64(LBA - 1);
+
+ plat->gpt_h->header_crc32 = 0;
+ calc_crc32 = efi_crc32((const unsigned char *)plat->gpt_h,
+ le32_to_cpu(plat->gpt_h->header_size));
+ plat->gpt_h->header_crc32 = cpu_to_le32(calc_crc32);
+
+ debug("header h1 crc32 : 0x%08x\n", calc_crc32);
+
+ /* Init gpt_h2 */
+ memcpy(plat->gpt_h2, plat->gpt_h, sizeof(gpt_header));
+
+ plat->gpt_h2->my_lba = cpu_to_le64(LBA - 1);
+ plat->gpt_h2->partition_entry_lba =
+ cpu_to_le64(le64_to_cpu(plat->gpt_h2->last_usable_lba) + 1);
+ plat->gpt_h2->alternate_lba = cpu_to_le64(1);
+
+ plat->gpt_h2->header_crc32 = 0;
+ calc_crc32 = efi_crc32((const unsigned char *)plat->gpt_h2,
+ le32_to_cpu(plat->gpt_h2->header_size));
+ plat->gpt_h2->header_crc32 = cpu_to_le32(calc_crc32);
+
+ debug("header h2 crc32 : 0x%08x\n", calc_crc32);
+
+ part_init(plat->desc);
+
+ return 0;
+}
+
+static void rkmtd_blk_kmalloc_release(struct udevice *dev, void *res)
+{
+ /* noop */
+}
+
+static int rkmtd_bind(struct udevice *dev)
+{
+ struct rkmtd_dev *plat = dev_get_plat(dev);
+ char dev_name[30], *str;
+ struct blk_desc *desc;
+ struct udevice *bdev;
+ int ret;
+
+ snprintf(dev_name, sizeof(dev_name), "%s.%s", dev->name, "blk");
+
+ str = devres_alloc(rkmtd_blk_kmalloc_release, strlen(dev_name) + 1, GFP_KERNEL);
+ if (unlikely(!str))
+ return -ENOMEM;
+
+ strcpy(str, dev_name);
+
+ ret = blk_create_device(dev, "rkmtd_blk", str, UCLASS_RKMTD,
+ -1, 512, LBA, &bdev);
+ if (ret) {
+ free(str);
+ return log_msg_ret("blk", ret);
+ }
+
+ devres_add(dev, str);
+
+ desc = dev_get_uclass_plat(bdev);
+ sprintf(desc->vendor, "0x%.4x", 0x2207);
+ memcpy(desc->product, "RKMTD", sizeof("RKMTD"));
+ memcpy(desc->revision, "V1.00", sizeof("V1.00"));
+ plat->desc = desc;
+
+ return 0;
+}
+
+static int rkmtd_attach_mtd(struct udevice *dev)
+{
+ struct rkmtd_dev *plat = dev_get_plat(dev);
+ struct mtd_info *mtd;
+ struct udevice *blk;
+ int ret;
+
+ plat->dev = dev;
+
+ /* Sanity check that rkmtd_bind() has been used */
+ ret = blk_find_from_parent(dev, &blk);
+ if (ret)
+ return ret;
+
+#if IS_ENABLED(CONFIG_SANDBOX)
+ plat->mtd = devm_kzalloc(dev, sizeof(struct mtd_info), GFP_KERNEL);
+ if (!plat->mtd)
+ return -ENOMEM;
+
+ mtd = plat->mtd;
+ mtd->erasesize = 2 ^ 3 * BLK_SIZE;
+ mtd->writesize = BLK_SIZE;
+ mtd->oobsize = BLK_SIZE / STEP_SIZE * NFC_SYS_DATA_SIZE;
+ plat->boot_blks = 0;
+ plat->lsb_mode = 0;
+#else
+ struct nand_chip *chip;
+ u8 id[6];
+ int i, j;
+ u32 tmp;
+
+ mtd = get_nand_dev_by_index(0);
+ if (!mtd)
+ return -ENOSYS;
+
+ chip = mtd_to_nand(mtd);
+
+ ret = ofnode_read_u32(chip->flash_node, "rockchip,boot-blks", &tmp);
+ plat->boot_blks = ret ? 0 : tmp;
+ plat->mtd = mtd;
+
+ if (chip->select_chip)
+ chip->select_chip(mtd, 0);
+
+ nand_readid_op(chip, 0, id, 6);
+
+ if (chip->select_chip)
+ chip->select_chip(mtd, -1);
+
+ for (i = 0; i < ARRAY_SIZE(nand_para_tbl); i++) {
+ plat->info = (struct nand_para_info *)&nand_para_tbl[i];
+ for (j = 0; j < plat->info->id_bytes; j++) {
+ if (plat->info->nand_id[j] != id[j])
+ break;
+ if (j == plat->info->id_bytes - 1)
+ goto valid;
+ }
+ }
+
+ debug("no nand_para_info found\n");
+ return -ENODEV;
+valid:
+ plat->lsb_mode = plat->info->lsb_mode;
+
+ debug("FLASH ID :");
+
+ for (j = 0; j < plat->info->id_bytes; j++)
+ debug(" %x", id[j]);
+
+ debug("\n");
+#endif
+
+ rkmtd_build_page_table(plat);
+
+ plat->datbuf = devm_kzalloc(dev, mtd->writesize, GFP_KERNEL);
+ if (!plat->datbuf)
+ return -ENOMEM;
+
+ plat->oobbuf = devm_kzalloc(dev, mtd->oobsize, GFP_KERNEL);
+ if (!plat->oobbuf)
+ return -ENOMEM;
+
+ debug("erasesize %8d\n", mtd->erasesize);
+ debug("writesize %8d\n", mtd->writesize);
+ debug("oobsize %8d\n", mtd->oobsize);
+ debug("boot_blks %8d\n", plat->boot_blks);
+ debug("lsb_mode %8d\n", plat->lsb_mode);
+
+ ret = rkmtd_init_plat(dev);
+ if (ret) {
+ debug("rkmtd_init_plat failed\n");
+ return -ENOENT;
+ }
+
+ rkmtd_scan_block(plat);
+
+ memset(plat->idb, 0, BUF_SIZE);
+
+ if (plat->blk_counter)
+ rkmtd_read_block(plat, 0, plat->idb);
+
+ return 0;
+}
+
+int rkmtd_detach_mtd(struct udevice *dev)
+{
+ int ret;
+
+ ret = device_remove(dev, DM_REMOVE_NORMAL);
+ if (ret)
+ return log_msg_ret("rem", ret);
+
+ ret = device_chld_unbind(dev, NULL);
+ if (ret)
+ return log_msg_ret("unb", ret);
+
+ return 0;
+}
+
+struct rkmtd_ops rkmtd_ops = {
+ .attach_mtd = rkmtd_attach_mtd,
+ .detach_mtd = rkmtd_detach_mtd,
+};
+
+U_BOOT_DRIVER(rkmtd_drv) = {
+ .name = "rkmtd_drv",
+ .id = UCLASS_RKMTD,
+ .ops = &rkmtd_ops,
+ .bind = rkmtd_bind,
+ .plat_auto = sizeof(struct rkmtd_dev),
+};
+
+struct rkmtd_priv {
+ struct udevice *cur_dev;
+};
+
+void rkmtd_rc4(u8 *buf, u32 len)
+{
+ u8 S[256], K[256], temp;
+ u32 i, j, t, x;
+ u8 key[16] = { 124, 78, 3, 4, 85, 5, 9, 7, 45, 44, 123, 56, 23, 13, 23, 17};
+
+ j = 0;
+ for (i = 0; i < 256; i++) {
+ S[i] = (u8)i;
+ j &= 0x0f;
+ K[i] = key[j];
+ j++;
+ }
+
+ j = 0;
+ for (i = 0; i < 256; i++) {
+ j = (j + S[i] + K[i]) % 256;
+ temp = S[i];
+ S[i] = S[j];
+ S[j] = temp;
+ }
+
+ i = 0;
+ j = 0;
+ for (x = 0; x < len; x++) {
+ i = (i + 1) % 256;
+ j = (j + S[i]) % 256;
+ temp = S[i];
+ S[i] = S[j];
+ S[j] = temp;
+ t = (S[i] + (S[j] % 256)) % 256;
+ buf[x] = buf[x] ^ S[t];
+ }
+}
+
+struct udevice *rkmtd_get_cur_dev(void)
+{
+ struct uclass *uc = uclass_find(UCLASS_RKMTD);
+
+ if (uc) {
+ struct rkmtd_priv *priv = uclass_get_priv(uc);
+
+ return priv->cur_dev;
+ }
+
+ return NULL;
+}
+
+void rkmtd_set_cur_dev(struct udevice *dev)
+{
+ struct uclass *uc = uclass_find(UCLASS_RKMTD);
+
+ if (uc) {
+ struct rkmtd_priv *priv = uclass_get_priv(uc);
+
+ priv->cur_dev = dev;
+ }
+}
+
+struct udevice *rkmtd_find_by_label(const char *label)
+{
+ struct udevice *dev;
+ struct uclass *uc;
+
+ uclass_id_foreach_dev(UCLASS_RKMTD, dev, uc) {
+ struct rkmtd_dev *plat = dev_get_plat(dev);
+
+ if (plat->label && !strcmp(label, plat->label))
+ return dev;
+ }
+
+ return NULL;
+}
+
+int rkmtd_attach(struct udevice *dev)
+{
+ struct rkmtd_ops *ops = rkmtd_get_ops(dev);
+
+ if (!ops->attach_mtd)
+ return -ENOSYS;
+
+ return ops->attach_mtd(dev);
+}
+
+int rkmtd_detach(struct udevice *dev)
+{
+ struct rkmtd_ops *ops = rkmtd_get_ops(dev);
+
+ if (!ops->detach_mtd)
+ return -ENOSYS;
+
+ if (dev == rkmtd_get_cur_dev())
+ rkmtd_set_cur_dev(NULL);
+
+ return ops->detach_mtd(dev);
+}
+
+static void rkmtd_drv_kmalloc_release(struct udevice *dev, void *res)
+{
+ /* noop */
+}
+
+int rkmtd_create_device(const char *label, struct udevice **devp)
+{
+ char dev_name[30], *str, *label_new;
+ struct udevice *dev, *blk;
+ struct rkmtd_dev *plat;
+ int ret;
+
+ /* unbind any existing device with this label */
+ dev = rkmtd_find_by_label(label);
+ if (dev) {
+ ret = rkmtd_detach(dev);
+ if (ret)
+ return log_msg_ret("det", ret);
+
+ ret = device_unbind(dev);
+ if (ret)
+ return log_msg_ret("unb", ret);
+ }
+
+ snprintf(dev_name, sizeof(dev_name), "rkmtd-%s", label);
+
+ str = devres_alloc(rkmtd_drv_kmalloc_release, strlen(dev_name) + 1, GFP_KERNEL);
+ if (unlikely(!str))
+ return -ENOMEM;
+
+ strcpy(str, dev_name);
+
+ ret = device_bind_driver(dm_root(), "rkmtd_drv", str, &dev);
+ if (ret) {
+ free(str);
+ return log_msg_ret("drv", ret);
+ }
+
+ devres_add(dev, str);
+
+ if (!blk_find_from_parent(dev, &blk)) {
+ struct blk_desc *desc = dev_get_uclass_plat(blk);
+
+ desc->removable = true;
+ }
+
+ label_new = devm_kzalloc(dev, strlen(label) + 1, GFP_KERNEL);
+ if (!label_new)
+ return -ENOMEM;
+
+ strcpy(label_new, label);
+
+ plat = dev_get_plat(dev);
+ plat->label = label_new;
+ *devp = dev;
+
+ return 0;
+}
+
+int rkmtd_create_attach_mtd(const char *label, struct udevice **devp)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = rkmtd_create_device(label, &dev);
+ if (ret)
+ return log_msg_ret("cre", ret);
+
+ ret = rkmtd_attach(dev);
+ if (ret) {
+ device_unbind(dev);
+ return log_msg_ret("att", ret);
+ }
+ *devp = dev;
+
+ return 0;
+}
+
+UCLASS_DRIVER(rkmtd) = {
+ .name = "rkmtd",
+ .id = UCLASS_RKMTD,
+ .post_bind = dm_scan_fdt_dev,
+ .priv_auto = sizeof(struct rkmtd_priv),
+};
diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig
index 570252d186a..3c56253b1ea 100644
--- a/drivers/bootcount/Kconfig
+++ b/drivers/bootcount/Kconfig
@@ -79,14 +79,6 @@ config BOOTCOUNT_RAM
Store the bootcount in DRAM protected against bit errors
due to short power loss or holding a system in RESET.
-config BOOTCOUNT_I2C
- bool "Boot counter on I2C device"
- help
- Enable support for the bootcounter on an i2c (like RTC) device.
- CFG_SYS_I2C_RTC_ADDR = i2c chip address
- CONFIG_SYS_BOOTCOUNT_ADDR = i2c addr which is used for
- the bootcounter.
-
config BOOTCOUNT_AT91
bool "Boot counter for Atmel AT91SAM9XE"
depends on AT91SAM9XE
@@ -117,6 +109,16 @@ config DM_BOOTCOUNT_RTC
Accesses to the backing store are performed using the write16
and read16 ops of DM RTC devices.
+config DM_BOOTCOUNT_I2C
+ bool "Driver Model boot counter on I2C device"
+ depends on DM_I2C
+ help
+ Enable support for the bootcounter on a generic i2c device, like a RTC
+ or PMIC. The bootcounter is configured in the device tree using the
+ "u-boot,bootcount-i2c" compatible string. It requires a phandle
+ 'i2cbcdev' for the i2c device and an 'offset' property used within the
+ device.
+
config DM_BOOTCOUNT_I2C_EEPROM
bool "Support i2c eeprom devices as a backing store for bootcount"
depends on I2C_EEPROM
@@ -175,14 +177,6 @@ config BOOTCOUNT_BOOTLIMIT
counter being cleared.
If set to 0, do not set a boot limit in the environment.
-config BOOTCOUNT_ALEN
- int "I2C address length"
- default 1
- depends on BOOTCOUNT_I2C
- help
- Length of the the I2C address at SYS_BOOTCOUNT_ADDR for storing
- the boot counter.
-
config SYS_BOOTCOUNT_SINGLEWORD
bool "Use single word to pack boot count and magic value"
depends on BOOTCOUNT_GENERIC
@@ -218,7 +212,7 @@ config SYS_BOOTCOUNT_ADDR
default 0x44E3E000 if BOOTCOUNT_AM33XX || BOOTCOUNT_AM33XX_NVMEM
default 0xE0115FF8 if ARCH_LS1043A || ARCH_LS1021A
depends on BOOTCOUNT_AM33XX || BOOTCOUNT_GENERIC || BOOTCOUNT_EXT || \
- BOOTCOUNT_I2C || BOOTCOUNT_AM33XX_NVMEM
+ BOOTCOUNT_AM33XX_NVMEM
help
Set the address used for reading and writing the boot counter.
@@ -226,13 +220,11 @@ config SYS_BOOTCOUNT_MAGIC
hex "Magic value for the boot counter"
default 0xB001C041 if BOOTCOUNT_GENERIC || BOOTCOUNT_EXT || \
BOOTCOUNT_AM33XX || BOOTCOUNT_ENV || \
- BOOTCOUNT_RAM || BOOTCOUNT_I2C || \
- BOOTCOUNT_AT91 || DM_BOOTCOUNT
+ BOOTCOUNT_RAM || BOOTCOUNT_AT91 || DM_BOOTCOUNT
default 0xB0 if BOOTCOUNT_AM33XX_NVMEM
depends on BOOTCOUNT_GENERIC || BOOTCOUNT_EXT || \
BOOTCOUNT_AM33XX || BOOTCOUNT_ENV || \
- BOOTCOUNT_RAM || BOOTCOUNT_I2C || \
- BOOTCOUNT_AT91 || DM_BOOTCOUNT || \
+ BOOTCOUNT_RAM || BOOTCOUNT_AT91 || DM_BOOTCOUNT || \
BOOTCOUNT_AM33XX_NVMEM
help
Set the magic value used for the boot counter.
diff --git a/drivers/bootcount/Makefile b/drivers/bootcount/Makefile
index b65959a384b..e7771f5b36d 100644
--- a/drivers/bootcount/Makefile
+++ b/drivers/bootcount/Makefile
@@ -6,7 +6,6 @@ obj-$(CONFIG_BOOTCOUNT_AT91) += bootcount_at91.o
obj-$(CONFIG_BOOTCOUNT_AM33XX) += bootcount_davinci.o
obj-$(CONFIG_BOOTCOUNT_RAM) += bootcount_ram.o
obj-$(CONFIG_BOOTCOUNT_ENV) += bootcount_env.o
-obj-$(CONFIG_BOOTCOUNT_I2C) += bootcount_i2c.o
obj-$(CONFIG_BOOTCOUNT_EXT) += bootcount_ext.o
obj-$(CONFIG_BOOTCOUNT_AM33XX_NVMEM) += bootcount_nvmem.o
@@ -14,5 +13,6 @@ obj-$(CONFIG_DM_BOOTCOUNT) += bootcount-uclass.o
obj-$(CONFIG_DM_BOOTCOUNT_PMIC_PFUZE100) += pmic_pfuze100.o
obj-$(CONFIG_DM_BOOTCOUNT_RTC) += rtc.o
obj-$(CONFIG_DM_BOOTCOUNT_I2C_EEPROM) += i2c-eeprom.o
+obj-$(CONFIG_DM_BOOTCOUNT_I2C) += bootcount_dm_i2c.o
obj-$(CONFIG_DM_BOOTCOUNT_SPI_FLASH) += spi-flash.o
obj-$(CONFIG_DM_BOOTCOUNT_SYSCON) += bootcount_syscon.o
diff --git a/drivers/bootcount/bootcount_dm_i2c.c b/drivers/bootcount/bootcount_dm_i2c.c
new file mode 100644
index 00000000000..e27034cbeb0
--- /dev/null
+++ b/drivers/bootcount/bootcount_dm_i2c.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2023
+ * Philip Richard Oberfichtner <pro@denx.de>
+ *
+ * Based on previous work from Heiko Schocher (legacy bootcount_i2c.c driver)
+ */
+
+#include <bootcount.h>
+#include <dm.h>
+#include <i2c.h>
+
+#define BC_MAGIC 0x55
+
+struct bootcount_i2c_priv {
+ struct udevice *bcdev;
+ unsigned int offset;
+};
+
+static int bootcount_i2c_set(struct udevice *dev, const u32 val)
+{
+ int ret;
+ struct bootcount_i2c_priv *priv = dev_get_priv(dev);
+
+ ret = dm_i2c_reg_write(priv->bcdev, priv->offset, BC_MAGIC);
+ if (ret < 0)
+ goto err_exit;
+
+ ret = dm_i2c_reg_write(priv->bcdev, priv->offset + 1, val & 0xff);
+ if (ret < 0)
+ goto err_exit;
+
+ return 0;
+
+err_exit:
+ log_debug("%s: Error writing to I2C device (%d)\n", __func__, ret);
+ return ret;
+}
+
+static int bootcount_i2c_get(struct udevice *dev, u32 *val)
+{
+ int ret;
+ struct bootcount_i2c_priv *priv = dev_get_priv(dev);
+
+ ret = dm_i2c_reg_read(priv->bcdev, priv->offset);
+ if (ret < 0)
+ goto err_exit;
+
+ if ((ret & 0xff) != BC_MAGIC) {
+ log_debug("%s: Invalid Magic, reset bootcounter.\n", __func__);
+ *val = 0;
+ return bootcount_i2c_set(dev, 0);
+ }
+
+ ret = dm_i2c_reg_read(priv->bcdev, priv->offset + 1);
+ if (ret < 0)
+ goto err_exit;
+
+ *val = ret;
+ return 0;
+
+err_exit:
+ log_debug("%s: Error reading from I2C device (%d)\n", __func__, ret);
+ return ret;
+}
+
+static int bootcount_i2c_probe(struct udevice *dev)
+{
+ struct bootcount_i2c_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = dev_read_u32(dev, "offset", &priv->offset);
+ if (ret)
+ goto exit;
+
+ ret = i2c_get_chip_by_phandle(dev, "i2cbcdev", &priv->bcdev);
+
+exit:
+ if (ret)
+ log_debug("%s failed, ret = %d\n", __func__, ret);
+
+ return ret;
+}
+
+static const struct bootcount_ops bootcount_i2c_ops = {
+ .get = bootcount_i2c_get,
+ .set = bootcount_i2c_set,
+};
+
+static const struct udevice_id bootcount_i2c_ids[] = {
+ { .compatible = "u-boot,bootcount-i2c" },
+ { }
+};
+
+U_BOOT_DRIVER(bootcount_i2c) = {
+ .name = "bootcount-i2c",
+ .id = UCLASS_BOOTCOUNT,
+ .priv_auto = sizeof(struct bootcount_i2c_priv),
+ .probe = bootcount_i2c_probe,
+ .of_match = bootcount_i2c_ids,
+ .ops = &bootcount_i2c_ops,
+};
diff --git a/drivers/bootcount/bootcount_i2c.c b/drivers/bootcount/bootcount_i2c.c
deleted file mode 100644
index b3ac67ea35d..00000000000
--- a/drivers/bootcount/bootcount_i2c.c
+++ /dev/null
@@ -1,43 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * (C) Copyright 2013
- * Heiko Schocher, DENX Software Engineering, hs@denx.de.
- */
-
-#include <bootcount.h>
-#include <linux/compiler.h>
-#include <i2c.h>
-
-#define BC_MAGIC 0xbc
-
-void bootcount_store(ulong a)
-{
- unsigned char buf[3];
- int ret;
-
- buf[0] = BC_MAGIC;
- buf[1] = (a & 0xff);
- ret = i2c_write(CFG_SYS_I2C_RTC_ADDR, CONFIG_SYS_BOOTCOUNT_ADDR,
- CONFIG_BOOTCOUNT_ALEN, buf, 2);
- if (ret != 0)
- puts("Error writing bootcount\n");
-}
-
-ulong bootcount_load(void)
-{
- unsigned char buf[3];
- int ret;
-
- ret = i2c_read(CFG_SYS_I2C_RTC_ADDR, CONFIG_SYS_BOOTCOUNT_ADDR,
- CONFIG_BOOTCOUNT_ALEN, buf, 2);
- if (ret != 0) {
- puts("Error loading bootcount\n");
- return 0;
- }
- if (buf[0] == BC_MAGIC)
- return buf[1];
-
- bootcount_store(0);
-
- return 0;
-}
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 26bf429acbc..af27ceb27da 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -27,7 +27,6 @@ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_ARCH_SOCFPGA) += altera/
obj-$(CONFIG_ARCH_STM32) += stm32/
obj-$(CONFIG_ARCH_STM32MP) += stm32/
-obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_CLK_AT91) += at91/
obj-$(CONFIG_CLK_BCM6345) += clk_bcm6345.o
obj-$(CONFIG_CLK_BOSTON) += clk_boston.o
@@ -43,6 +42,7 @@ obj-$(CONFIG_CLK_OWL) += owl/
obj-$(CONFIG_CLK_RENESAS) += renesas/
obj-$(CONFIG_$(SPL_TPL_)CLK_SCMI) += clk_scmi.o
obj-$(CONFIG_CLK_SIFIVE) += sifive/
+obj-$(CONFIG_CLK_SUNXI) += sunxi/
obj-$(CONFIG_CLK_UNIPHIER) += uniphier/
obj-$(CONFIG_CLK_VERSACLOCK) += clk_versaclock.o
obj-$(CONFIG_CLK_VERSAL) += clk_versal.o
diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c
index b52d926f339..025c7a7aa26 100644
--- a/drivers/clk/at91/clk-main.c
+++ b/drivers/clk/at91/clk-main.c
@@ -17,6 +17,7 @@
#include <linux/clk/at91_pmc.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/time.h>
#include "pmc.h"
#define UBOOT_DM_CLK_AT91_MAIN_RC "at91-main-rc-clk"
@@ -25,7 +26,6 @@
#define UBOOT_DM_CLK_AT91_SAM9X5_MAIN "at91-sam9x5-main-clk"
#define MOR_KEY_MASK GENMASK(23, 16)
-#define USEC_PER_SEC 1000000UL
#define SLOW_CLOCK_FREQ 32768
#define clk_main_parent_select(s) (((s) & \
diff --git a/drivers/clk/clk-cdce9xx.c b/drivers/clk/clk-cdce9xx.c
index f23465d7e1f..b8700f517fc 100644
--- a/drivers/clk/clk-cdce9xx.c
+++ b/drivers/clk/clk-cdce9xx.c
@@ -2,7 +2,7 @@
/*
* Texas Instruments CDCE913/925/937/949 clock synthesizer driver
*
- * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
* Tero Kristo <t-kristo@ti.com>
*
* Based on Linux kernel clk-cdce925.c.
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index f186fcbcdb8..3b5e3f9c86b 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -422,12 +422,13 @@ int clk_get_by_name_nodev(ofnode node, const char *name, struct clk *clk)
return clk_get_by_index_nodev(node, index, clk);
}
-int clk_release_all(struct clk *clk, int count)
+int clk_release_all(struct clk *clk, unsigned int count)
{
- int i, ret;
+ unsigned int i;
+ int ret;
for (i = 0; i < count; i++) {
- debug("%s(clk[%d]=%p)\n", __func__, i, &clk[i]);
+ debug("%s(clk[%u]=%p)\n", __func__, i, &clk[i]);
/* check if clock has been previously requested */
if (!clk[i].dev)
@@ -477,7 +478,7 @@ void clk_free(struct clk *clk)
ulong clk_get_rate(struct clk *clk)
{
const struct clk_ops *ops;
- int ret;
+ ulong ret;
debug("%s(clk=%p)\n", __func__, clk);
if (!clk_valid(clk))
@@ -655,7 +656,7 @@ int clk_enable(struct clk *clk)
}
if (ops->enable) {
- ret = ops->enable(clk);
+ ret = ops->enable(clkp ? clkp : clk);
if (ret) {
printf("Enable %s failed\n", clk->dev->name);
return ret;
@@ -712,7 +713,7 @@ int clk_disable(struct clk *clk)
}
if (ops->disable) {
- ret = ops->disable(clk);
+ ret = ops->disable(clkp ? clkp : clk);
if (ret)
return ret;
}
diff --git a/drivers/clk/clk_k210.c b/drivers/clk/clk_k210.c
index c534cc07e09..b9469b93853 100644
--- a/drivers/clk/clk_k210.c
+++ b/drivers/clk/clk_k210.c
@@ -16,6 +16,7 @@
#include <dt-bindings/mfd/k210-sysctl.h>
#include <k210/pll.h>
#include <linux/bitfield.h>
+#include <asm/barrier.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c
index d172fed24c9..34a49363a51 100644
--- a/drivers/clk/clk_scmi.c
+++ b/drivers/clk/clk_scmi.c
@@ -13,17 +13,8 @@
#include <asm/types.h>
#include <linux/clk-provider.h>
-/**
- * struct scmi_clk_priv - Private data for SCMI clocks
- * @channel: Reference to the SCMI channel to use
- */
-struct scmi_clk_priv {
- struct scmi_channel *channel;
-};
-
static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks)
{
- struct scmi_clk_priv *priv = dev_get_priv(dev);
struct scmi_clk_protocol_attr_out out;
struct scmi_msg msg = {
.protocol_id = SCMI_PROTOCOL_ID_CLOCK,
@@ -33,7 +24,7 @@ static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks)
};
int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
+ ret = devm_scmi_process_msg(dev, &msg);
if (ret)
return ret;
@@ -44,7 +35,6 @@ static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks)
static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name)
{
- struct scmi_clk_priv *priv = dev_get_priv(dev);
struct scmi_clk_attribute_in in = {
.clock_id = clkid,
};
@@ -59,7 +49,7 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name)
};
int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
+ ret = devm_scmi_process_msg(dev, &msg);
if (ret)
return ret;
@@ -70,7 +60,6 @@ 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_priv *priv = dev_get_priv(clk->dev);
struct scmi_clk_state_in in = {
.clock_id = clk->id,
.attributes = enable,
@@ -81,7 +70,7 @@ static int scmi_clk_gate(struct clk *clk, int enable)
in, out);
int ret;
- ret = devm_scmi_process_msg(clk->dev, priv->channel, &msg);
+ ret = devm_scmi_process_msg(clk->dev, &msg);
if (ret)
return ret;
@@ -100,7 +89,6 @@ static int scmi_clk_disable(struct clk *clk)
static ulong scmi_clk_get_rate(struct clk *clk)
{
- struct scmi_clk_priv *priv = dev_get_priv(clk->dev);
struct scmi_clk_rate_get_in in = {
.clock_id = clk->id,
};
@@ -110,7 +98,7 @@ static ulong scmi_clk_get_rate(struct clk *clk)
in, out);
int ret;
- ret = devm_scmi_process_msg(clk->dev, priv->channel, &msg);
+ ret = devm_scmi_process_msg(clk->dev, &msg);
if (ret < 0)
return ret;
@@ -123,7 +111,6 @@ static ulong scmi_clk_get_rate(struct clk *clk)
static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
{
- struct scmi_clk_priv *priv = dev_get_priv(clk->dev);
struct scmi_clk_rate_set_in in = {
.clock_id = clk->id,
.flags = SCMI_CLK_RATE_ROUND_CLOSEST,
@@ -136,7 +123,7 @@ static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
in, out);
int ret;
- ret = devm_scmi_process_msg(clk->dev, priv->channel, &msg);
+ ret = devm_scmi_process_msg(clk->dev, &msg);
if (ret < 0)
return ret;
@@ -149,12 +136,11 @@ static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
static int scmi_clk_probe(struct udevice *dev)
{
- struct scmi_clk_priv *priv = dev_get_priv(dev);
struct clk *clk;
size_t num_clocks, i;
int ret;
- ret = devm_scmi_of_get_channel(dev, &priv->channel);
+ ret = devm_scmi_of_get_channel(dev);
if (ret)
return ret;
@@ -205,5 +191,4 @@ U_BOOT_DRIVER(scmi_clock) = {
.id = UCLASS_CLK,
.ops = &scmi_clk_ops,
.probe = scmi_clk_probe,
- .priv_auto = sizeof(struct scmi_clk_priv *),
};
diff --git a/drivers/clk/clk_versal.c b/drivers/clk/clk_versal.c
index 2e004beca2f..c473643603a 100644
--- a/drivers/clk/clk_versal.c
+++ b/drivers/clk/clk_versal.c
@@ -773,7 +773,6 @@ static struct clk_ops versal_clk_ops = {
static const struct udevice_id versal_clk_ids[] = {
{ .compatible = "xlnx,versal-clk" },
- { .compatible = "xlnx,versal-net-clk" },
{ }
};
diff --git a/drivers/clk/exynos/clk-pll.h b/drivers/clk/exynos/clk-pll.h
index c79aac44258..7b7af5e6761 100644
--- a/drivers/clk/exynos/clk-pll.h
+++ b/drivers/clk/exynos/clk-pll.h
@@ -5,4 +5,9 @@
* Thomas Abraham <thomas.ab@samsung.com>
*/
+#ifndef __EXYNOS_CLK_PLL_H
+#define __EXYNOS_CLK_PLL_H
+
unsigned long pll145x_get_rate(unsigned int *con1, unsigned long fin_freq);
+
+#endif /* __EXYNOS_CLK_PLL_H */
diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig
index abcb19ce6d5..56d893e0579 100644
--- a/drivers/clk/imx/Kconfig
+++ b/drivers/clk/imx/Kconfig
@@ -89,6 +89,24 @@ config CLK_IMX8MQ
help
This enables support clock driver for i.MX8MQ platforms.
+config SPL_CLK_IMX93
+ bool "SPL clock support for i.MX93"
+ depends on ARCH_IMX9 && SPL
+ select SPL_CLK
+ select SPL_CLK_CCF
+ select SPL_CLK_COMPOSITE_CCF
+ help
+ This enables SPL DM/DTS support for clock driver in i.MX93
+
+config CLK_IMX93
+ bool "Clock support for i.MX93"
+ depends on ARCH_IMX9
+ select CLK
+ select CLK_CCF
+ select CLK_COMPOSITE_CCF
+ help
+ This enables support for clock driver in i.MX93
+
config SPL_CLK_IMXRT1020
bool "SPL clock support for i.MXRT1020"
depends on ARCH_IMXRT && SPL
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index b9c197f952e..6d4bcd35714 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -18,6 +18,8 @@ obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MP) += clk-imx8mp.o clk-pll14xx.o \
clk-composite-8m.o
obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MQ) += clk-imx8mq.o clk-pll14xx.o \
clk-composite-8m.o
+obj-$(CONFIG_$(SPL_TPL_)CLK_IMX93) += clk-imx93.o clk-fracn-gppll.o \
+ clk-gate-93.o clk-composite-93.o
obj-$(CONFIG_$(SPL_TPL_)CLK_IMXRT1020) += clk-imxrt1020.o
obj-$(CONFIG_$(SPL_TPL_)CLK_IMXRT1050) += clk-imxrt1050.o
diff --git a/drivers/clk/imx/clk-composite-93.c b/drivers/clk/imx/clk-composite-93.c
new file mode 100644
index 00000000000..6d71c0c03ff
--- /dev/null
+++ b/drivers/clk/imx/clk-composite-93.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021 NXP
+ *
+ * Peng Fan <peng.fan@nxp.com>
+ */
+#include <common.h>
+#include <log.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <dm/devres.h>
+#include <linux/iopoll.h>
+#include <linux/clk-provider.h>
+#include <clk.h>
+#include "clk.h"
+#include <linux/err.h>
+
+#define TIMEOUT_US 500U
+
+#define CCM_DIV_SHIFT 0
+#define CCM_DIV_WIDTH 8
+#define CCM_MUX_SHIFT 8
+#define CCM_MUX_MASK 3
+#define CCM_OFF_SHIFT 24
+#define CCM_BUSY_SHIFT 28
+
+#define STAT_OFFSET 0x4
+#define AUTHEN_OFFSET 0x30
+#define TZ_NS_SHIFT 9
+#define TZ_NS_MASK BIT(9)
+
+#define WHITE_LIST_SHIFT 16
+
+#define readl_poll_timeout_atomic readl_poll_timeout
+
+static int imx93_clk_composite_wait_ready(struct clk *clk, void __iomem *reg)
+{
+ int ret;
+ u32 val;
+
+ ret = readl_poll_timeout_atomic(reg + STAT_OFFSET, val, !(val & BIT(CCM_BUSY_SHIFT)),
+ TIMEOUT_US);
+ if (ret)
+ pr_err("Slice[%s] busy timeout\n", "TODO");
+
+ return ret;
+}
+
+static void imx93_clk_composite_gate_endisable(struct clk *clk, int enable)
+{
+ struct clk_gate *gate = to_clk_gate(clk);
+ u32 reg;
+
+ reg = readl(gate->reg);
+
+ if (enable)
+ reg &= ~BIT(gate->bit_idx);
+ else
+ reg |= BIT(gate->bit_idx);
+
+ writel(reg, gate->reg);
+
+ imx93_clk_composite_wait_ready(clk, gate->reg);
+}
+
+static int imx93_clk_composite_gate_enable(struct clk *clk)
+{
+ imx93_clk_composite_gate_endisable(clk, 1);
+
+ return 0;
+}
+
+static int imx93_clk_composite_gate_disable(struct clk *clk)
+{
+ imx93_clk_composite_gate_endisable(clk, 0);
+
+ return 0;
+}
+
+static const struct clk_ops imx93_clk_composite_gate_ops = {
+ .enable = imx93_clk_composite_gate_enable,
+ .disable = imx93_clk_composite_gate_disable,
+};
+
+struct clk *imx93_clk_composite_flags(const char *name,
+ const char * const *parent_names,
+ int num_parents, void __iomem *reg, u32 domain_id,
+ unsigned long flags)
+{
+ struct clk *clk = ERR_PTR(-ENOMEM);
+ struct clk_divider *div = NULL;
+ struct clk_gate *gate = NULL;
+ struct clk_mux *mux = NULL;
+
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ if (!mux)
+ goto fail;
+
+ mux->reg = reg;
+ mux->shift = CCM_MUX_SHIFT;
+ mux->mask = CCM_MUX_MASK;
+ mux->num_parents = num_parents;
+ mux->parent_names = parent_names;
+ mux->flags = flags;
+
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+ if (!div)
+ goto fail;
+
+ div->reg = reg;
+ div->shift = CCM_DIV_SHIFT;
+ div->width = CCM_DIV_WIDTH;
+ div->flags = CLK_DIVIDER_ROUND_CLOSEST | flags;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ goto fail;
+
+ gate->reg = reg;
+ gate->bit_idx = CCM_OFF_SHIFT;
+ gate->flags = flags;
+
+ clk = clk_register_composite(NULL, name,
+ parent_names, num_parents,
+ &mux->clk, &clk_mux_ops,
+ &div->clk, &clk_divider_ops,
+ &gate->clk, &imx93_clk_composite_gate_ops,
+ flags);
+
+ if (IS_ERR(clk))
+ goto fail;
+
+ return clk;
+
+fail:
+ kfree(gate);
+ kfree(div);
+ kfree(mux);
+ return ERR_CAST(clk);
+}
diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c
new file mode 100644
index 00000000000..9228f279e27
--- /dev/null
+++ b/drivers/clk/imx/clk-fracn-gppll.c
@@ -0,0 +1,382 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2021 NXP
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <dm/devres.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <clk.h>
+#include <div64.h>
+
+#include "clk.h"
+
+#define UBOOT_DM_CLK_IMX_FRACN_GPPLL "imx_clk_fracn_gppll"
+
+#define PLL_CTRL 0x0
+#define HW_CTRL_SEL BIT(16)
+#define CLKMUX_BYPASS BIT(2)
+#define CLKMUX_EN BIT(1)
+#define POWERUP_MASK BIT(0)
+
+#define PLL_ANA_PRG 0x10
+#define PLL_SPREAD_SPECTRUM 0x30
+
+#define PLL_NUMERATOR 0x40
+#define PLL_MFN_MASK GENMASK(31, 2)
+
+#define PLL_DENOMINATOR 0x50
+#define PLL_MFD_MASK GENMASK(29, 0)
+
+#define PLL_DIV 0x60
+#define PLL_MFI_MASK GENMASK(24, 16)
+#define PLL_RDIV_MASK GENMASK(15, 13)
+#define PLL_ODIV_MASK GENMASK(7, 0)
+
+#define PLL_DFS_CTRL(x) (0x70 + (x) * 0x10)
+
+#define PLL_STATUS 0xF0
+#define LOCK_STATUS BIT(0)
+
+#define DFS_STATUS 0xF4
+
+#define LOCK_TIMEOUT_US 200
+
+#define PLL_FRACN_GP(_rate, _mfi, _mfn, _mfd, _rdiv, _odiv) \
+ { \
+ .rate = (_rate), \
+ .mfi = (_mfi), \
+ .mfn = (_mfn), \
+ .mfd = (_mfd), \
+ .rdiv = (_rdiv), \
+ .odiv = (_odiv), \
+ }
+
+#define PLL_FRACN_GP_INTEGER(_rate, _mfi, _rdiv, _odiv) \
+ { \
+ .rate = (_rate), \
+ .mfi = (_mfi), \
+ .mfn = 0, \
+ .mfd = 0, \
+ .rdiv = (_rdiv), \
+ .odiv = (_odiv), \
+ }
+
+struct clk_fracn_gppll {
+ struct clk clk;
+ void __iomem *base;
+ const struct imx_fracn_gppll_rate_table *rate_table;
+ int rate_count;
+ u32 flags;
+};
+
+/*
+ * Fvco = (Fref / rdiv) * (MFI + MFN / MFD)
+ * Fout = Fvco / odiv
+ * The (Fref / rdiv) should be in range 20MHz to 40MHz
+ * The Fvco should be in range 2.5Ghz to 5Ghz
+ */
+static const struct imx_fracn_gppll_rate_table fracn_tbl[] = {
+ PLL_FRACN_GP(650000000U, 162, 50, 100, 0, 6),
+ PLL_FRACN_GP(594000000U, 198, 0, 1, 0, 8),
+ PLL_FRACN_GP(560000000U, 140, 0, 1, 0, 6),
+ PLL_FRACN_GP(498000000U, 166, 0, 1, 0, 8),
+ PLL_FRACN_GP(484000000U, 121, 0, 1, 0, 6),
+ PLL_FRACN_GP(445333333U, 167, 0, 1, 0, 9),
+ PLL_FRACN_GP(400000000U, 200, 0, 1, 0, 12),
+ PLL_FRACN_GP(393216000U, 163, 84, 100, 0, 10),
+ PLL_FRACN_GP(300000000U, 150, 0, 1, 0, 12)
+};
+
+struct imx_fracn_gppll_clk imx_fracn_gppll = {
+ .rate_table = fracn_tbl,
+ .rate_count = ARRAY_SIZE(fracn_tbl),
+};
+
+/*
+ * Fvco = (Fref / rdiv) * MFI
+ * Fout = Fvco / odiv
+ * The (Fref / rdiv) should be in range 20MHz to 40MHz
+ * The Fvco should be in range 2.5Ghz to 5Ghz
+ */
+static const struct imx_fracn_gppll_rate_table int_tbl[] = {
+ PLL_FRACN_GP_INTEGER(1700000000U, 141, 1, 2),
+ PLL_FRACN_GP_INTEGER(1400000000U, 175, 1, 3),
+ PLL_FRACN_GP_INTEGER(900000000U, 150, 1, 4),
+};
+
+struct imx_fracn_gppll_clk imx_fracn_gppll_integer = {
+ .rate_table = int_tbl,
+ .rate_count = ARRAY_SIZE(int_tbl),
+};
+
+#define to_clk_fracn_gppll(_clk) container_of(_clk, struct clk_fracn_gppll, clk)
+
+static const struct imx_fracn_gppll_rate_table *
+imx_get_pll_settings(struct clk_fracn_gppll *pll, unsigned long rate)
+{
+ const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table;
+ int i;
+
+ for (i = 0; i < pll->rate_count; i++)
+ if (rate == rate_table[i].rate)
+ return &rate_table[i];
+
+ return NULL;
+}
+
+static unsigned long clk_fracn_gppll_round_rate(struct clk *clk, unsigned long rate)
+{
+ struct clk_fracn_gppll *pll = to_clk_fracn_gppll(clk);
+ const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table;
+ int i;
+
+ /* Assuming rate_table is in descending order */
+ for (i = 0; i < pll->rate_count; i++)
+ if (rate >= rate_table[i].rate)
+ return rate_table[i].rate;
+
+ /* return minimum supported value */
+ return rate_table[pll->rate_count - 1].rate;
+}
+
+static unsigned long clk_fracn_gppll_recalc_rate(struct clk *clk)
+{
+ struct clk_fracn_gppll *pll = to_clk_fracn_gppll(clk);
+ const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table;
+ u32 pll_numerator, pll_denominator, pll_div;
+ u32 mfi, mfn, mfd, rdiv, odiv;
+ u64 fvco = clk_get_parent_rate(clk);
+ long rate = 0;
+ int i;
+
+ pll_numerator = readl_relaxed(pll->base + PLL_NUMERATOR);
+ mfn = FIELD_GET(PLL_MFN_MASK, pll_numerator);
+
+ pll_denominator = readl_relaxed(pll->base + PLL_DENOMINATOR);
+ mfd = FIELD_GET(PLL_MFD_MASK, pll_denominator);
+
+ pll_div = readl_relaxed(pll->base + PLL_DIV);
+ mfi = FIELD_GET(PLL_MFI_MASK, pll_div);
+
+ rdiv = FIELD_GET(PLL_RDIV_MASK, pll_div);
+ odiv = FIELD_GET(PLL_ODIV_MASK, pll_div);
+
+ /*
+ * Sometimes, the recalculated rate has deviation due to
+ * the frac part. So find the accurate pll rate from the table
+ * first, if no match rate in the table, use the rate calculated
+ * from the equation below.
+ */
+ for (i = 0; i < pll->rate_count; i++) {
+ if (rate_table[i].mfn == mfn && rate_table[i].mfi == mfi &&
+ rate_table[i].mfd == mfd && rate_table[i].rdiv == rdiv &&
+ rate_table[i].odiv == odiv)
+ rate = rate_table[i].rate;
+ }
+
+ if (rate)
+ return (unsigned long)rate;
+
+ if (!rdiv)
+ rdiv = rdiv + 1;
+
+ switch (odiv) {
+ case 0:
+ odiv = 2;
+ break;
+ case 1:
+ odiv = 3;
+ break;
+ default:
+ break;
+ }
+
+ if (pll->flags & CLK_FRACN_GPPLL_INTEGER) {
+ /* Fvco = (Fref / rdiv) * MFI */
+ fvco = fvco * mfi;
+ do_div(fvco, rdiv * odiv);
+ } else {
+ /* Fvco = (Fref / rdiv) * (MFI + MFN / MFD) */
+ fvco = fvco * mfi * mfd + fvco * mfn;
+ do_div(fvco, mfd * rdiv * odiv);
+ }
+
+ return (unsigned long)fvco;
+}
+
+static int clk_fracn_gppll_wait_lock(struct clk_fracn_gppll *pll)
+{
+ u32 val;
+
+ return readl_poll_timeout(pll->base + PLL_STATUS, val,
+ val & LOCK_STATUS, LOCK_TIMEOUT_US);
+}
+
+static ulong clk_fracn_gppll_set_rate(struct clk *clk, unsigned long drate)
+{
+ struct clk_fracn_gppll *pll = to_clk_fracn_gppll(clk);
+ const struct imx_fracn_gppll_rate_table *rate;
+ u32 tmp, pll_div, ana_mfn;
+ int ret;
+
+ rate = imx_get_pll_settings(pll, drate);
+
+ /* Hardware control select disable. PLL is control by register */
+ tmp = readl_relaxed(pll->base + PLL_CTRL);
+ tmp &= ~HW_CTRL_SEL;
+ writel_relaxed(tmp, pll->base + PLL_CTRL);
+
+ /* Disable output */
+ tmp = readl_relaxed(pll->base + PLL_CTRL);
+ tmp &= ~CLKMUX_EN;
+ writel_relaxed(tmp, pll->base + PLL_CTRL);
+
+ /* Power Down */
+ tmp &= ~POWERUP_MASK;
+ writel_relaxed(tmp, pll->base + PLL_CTRL);
+
+ /* Disable BYPASS */
+ tmp &= ~CLKMUX_BYPASS;
+ writel_relaxed(tmp, pll->base + PLL_CTRL);
+
+ pll_div = FIELD_PREP(PLL_RDIV_MASK, rate->rdiv) | rate->odiv |
+ FIELD_PREP(PLL_MFI_MASK, rate->mfi);
+ writel_relaxed(pll_div, pll->base + PLL_DIV);
+ if (pll->flags & CLK_FRACN_GPPLL_FRACN) {
+ writel_relaxed(rate->mfd, pll->base + PLL_DENOMINATOR);
+ writel_relaxed(FIELD_PREP(PLL_MFN_MASK, rate->mfn), pll->base + PLL_NUMERATOR);
+ }
+
+ /* Wait for 5us according to fracn mode pll doc */
+ udelay(5);
+
+ /* Enable Powerup */
+ tmp |= POWERUP_MASK;
+ writel_relaxed(tmp, pll->base + PLL_CTRL);
+
+ /* Wait Lock */
+ ret = clk_fracn_gppll_wait_lock(pll);
+ if (ret)
+ return ret;
+
+ /* Enable output */
+ tmp |= CLKMUX_EN;
+ writel_relaxed(tmp, pll->base + PLL_CTRL);
+
+ ana_mfn = readl_relaxed(pll->base + PLL_STATUS);
+ ana_mfn = FIELD_GET(PLL_MFN_MASK, ana_mfn);
+
+ WARN(ana_mfn != rate->mfn, "ana_mfn != rate->mfn\n");
+
+ return 0;
+}
+
+static int clk_fracn_gppll_prepare(struct clk *clk)
+{
+ struct clk_fracn_gppll *pll = to_clk_fracn_gppll(clk);
+ u32 val;
+ int ret;
+
+ val = readl_relaxed(pll->base + PLL_CTRL);
+ if (val & POWERUP_MASK)
+ return 0;
+
+ val |= CLKMUX_BYPASS;
+ writel_relaxed(val, pll->base + PLL_CTRL);
+
+ val |= POWERUP_MASK;
+ writel_relaxed(val, pll->base + PLL_CTRL);
+
+ val |= CLKMUX_EN;
+ writel_relaxed(val, pll->base + PLL_CTRL);
+
+ ret = clk_fracn_gppll_wait_lock(pll);
+ if (ret)
+ return ret;
+
+ val &= ~CLKMUX_BYPASS;
+ writel_relaxed(val, pll->base + PLL_CTRL);
+
+ return 0;
+}
+
+static int clk_fracn_gppll_unprepare(struct clk *clk)
+{
+ struct clk_fracn_gppll *pll = to_clk_fracn_gppll(dev_get_clk_ptr(clk->dev));
+ u32 val;
+
+ val = readl_relaxed(pll->base + PLL_CTRL);
+ val &= ~POWERUP_MASK;
+ writel_relaxed(val, pll->base + PLL_CTRL);
+
+ return 0;
+}
+
+static const struct clk_ops clk_fracn_gppll_ops = {
+ .enable = clk_fracn_gppll_prepare,
+ .disable = clk_fracn_gppll_unprepare,
+ .get_rate = clk_fracn_gppll_recalc_rate,
+ .set_rate = clk_fracn_gppll_set_rate,
+ .round_rate = clk_fracn_gppll_round_rate,
+};
+
+static struct clk *_imx_clk_fracn_gppll(const char *name, const char *parent_name,
+ void __iomem *base,
+ const struct imx_fracn_gppll_clk *pll_clk,
+ u32 pll_flags)
+{
+ struct clk_fracn_gppll *pll;
+ struct clk *clk;
+ int ret;
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
+ pll->base = base;
+ pll->rate_table = pll_clk->rate_table;
+ pll->rate_count = pll_clk->rate_count;
+ pll->flags = pll_flags;
+
+ clk = &pll->clk;
+
+ ret = clk_register(clk, UBOOT_DM_CLK_IMX_FRACN_GPPLL,
+ name, parent_name);
+ if (ret) {
+ pr_err("%s: failed to register pll %s %d\n", __func__, name, ret);
+ kfree(pll);
+ return ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+struct clk *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base,
+ const struct imx_fracn_gppll_clk *pll_clk)
+{
+ return _imx_clk_fracn_gppll(name, parent_name, base, pll_clk, CLK_FRACN_GPPLL_FRACN);
+}
+
+struct clk *imx_clk_fracn_gppll_integer(const char *name, const char *parent_name,
+ void __iomem *base,
+ const struct imx_fracn_gppll_clk *pll_clk)
+{
+ return _imx_clk_fracn_gppll(name, parent_name, base, pll_clk, CLK_FRACN_GPPLL_INTEGER);
+}
+
+U_BOOT_DRIVER(clk_fracn_gppll) = {
+ .name = UBOOT_DM_CLK_IMX_FRACN_GPPLL,
+ .id = UCLASS_CLK,
+ .ops = &clk_fracn_gppll_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/imx/clk-gate-93.c b/drivers/clk/imx/clk-gate-93.c
new file mode 100644
index 00000000000..bc857413713
--- /dev/null
+++ b/drivers/clk/imx/clk-gate-93.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2022 NXP
+ *
+ * Peng Fan <peng.fan@nxp.com>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <dm/devres.h>
+#include <linux/bug.h>
+#include <linux/clk-provider.h>
+#include <clk.h>
+#include "clk.h"
+#include <linux/err.h>
+
+#define UBOOT_DM_CLK_IMX_GATE93 "imx_clk_gate93"
+
+#define DIRECT_OFFSET 0x0
+
+/*
+ * 0b000 - LPCG will be OFF in any CPU mode.
+ * 0b100 - LPCG will be ON in any CPU mode.
+ */
+#define LPM_SETTING_OFF 0x0
+#define LPM_SETTING_ON 0x4
+
+#define LPM_CUR_OFFSET 0x1c
+
+#define AUTHEN_OFFSET 0x30
+#define CPULPM_EN BIT(2)
+#define TZ_NS_SHIFT 9
+#define TZ_NS_MASK BIT(9)
+
+#define WHITE_LIST_SHIFT 16
+
+struct imx93_clk_gate {
+ struct clk clk;
+ void __iomem *reg;
+ u32 bit_idx;
+ u32 val;
+ u32 mask;
+ unsigned int *share_count;
+};
+
+#define to_imx93_clk_gate(_clk) container_of(_clk, struct imx93_clk_gate, clk)
+
+static void imx93_clk_gate_do_hardware(struct clk *clk, bool enable)
+{
+ struct imx93_clk_gate *gate = to_imx93_clk_gate(clk);
+ u32 val;
+
+ val = readl(gate->reg + AUTHEN_OFFSET);
+ if (val & CPULPM_EN) {
+ val = enable ? LPM_SETTING_ON : LPM_SETTING_OFF;
+ writel(val, gate->reg + LPM_CUR_OFFSET);
+ } else {
+ val = readl(gate->reg + DIRECT_OFFSET);
+ val &= ~(gate->mask << gate->bit_idx);
+ if (enable)
+ val |= (gate->val & gate->mask) << gate->bit_idx;
+ writel(val, gate->reg + DIRECT_OFFSET);
+ }
+}
+
+static int imx93_clk_gate_enable(struct clk *clk)
+{
+ struct imx93_clk_gate *gate = to_imx93_clk_gate(clk);
+
+ if (gate->share_count && (*gate->share_count)++ > 0)
+ return 0;
+
+ imx93_clk_gate_do_hardware(clk, true);
+
+ return 0;
+}
+
+static int imx93_clk_gate_disable(struct clk *clk)
+{
+ struct imx93_clk_gate *gate = to_imx93_clk_gate(clk);
+
+ if (gate->share_count) {
+ if (WARN_ON(*gate->share_count == 0))
+ return 0;
+ else if (--(*gate->share_count) > 0)
+ return 0;
+ }
+
+ imx93_clk_gate_do_hardware(clk, false);
+
+ return 0;
+}
+
+static ulong imx93_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct clk *parent = clk_get_parent(clk);
+
+ if (parent)
+ return clk_set_rate(parent, rate);
+
+ return -ENODEV;
+}
+
+static const struct clk_ops imx93_clk_gate_ops = {
+ .enable = imx93_clk_gate_enable,
+ .disable = imx93_clk_gate_disable,
+ .get_rate = clk_generic_get_rate,
+ .set_rate = imx93_clk_set_rate,
+};
+
+struct clk *imx93_clk_gate(struct device *dev, const char *name, const char *parent_name,
+ unsigned long flags, void __iomem *reg, u32 bit_idx, u32 val,
+ u32 mask, u32 domain_id, unsigned int *share_count)
+{
+ struct imx93_clk_gate *gate;
+ struct clk *clk;
+ int ret;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ return ERR_PTR(-ENOMEM);
+
+ gate->reg = reg;
+ gate->bit_idx = bit_idx;
+ gate->val = val;
+ gate->mask = mask;
+ gate->share_count = share_count;
+
+ clk = &gate->clk;
+
+ ret = clk_register(clk, UBOOT_DM_CLK_IMX_GATE93, name, parent_name);
+ if (ret) {
+ kfree(gate);
+ return ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(clk_gate93) = {
+ .name = UBOOT_DM_CLK_IMX_GATE93,
+ .id = UCLASS_CLK,
+ .ops = &imx93_clk_gate_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/imx/clk-imx93.c b/drivers/clk/imx/clk-imx93.c
new file mode 100644
index 00000000000..ce10d795316
--- /dev/null
+++ b/drivers/clk/imx/clk-imx93.c
@@ -0,0 +1,343 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2021 NXP.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <log.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+#include <dt-bindings/clock/imx93-clock.h>
+
+#include "clk.h"
+
+enum clk_sel {
+ LOW_SPEED_IO_SEL,
+ NON_IO_SEL,
+ FAST_SEL,
+ AUDIO_SEL,
+ VIDEO_SEL,
+ TPM_SEL,
+ CKO1_SEL,
+ CKO2_SEL,
+ MISC_SEL,
+ MAX_SEL
+};
+
+static u32 share_count_sai1;
+static u32 share_count_sai2;
+static u32 share_count_sai3;
+static u32 share_count_mub;
+
+static const char * const a55_core_sels[] = {"a55_alt", "arm_pll"};
+static const char *parent_names[MAX_SEL][4] = {
+ {"clock-osc-24m", "sys_pll_pfd0_div2", "sys_pll_pfd1_div2", "video_pll"},
+ {"clock-osc-24m", "sys_pll_pfd0_div2", "sys_pll_pfd1_div2", "sys_pll_pfd2_div2"},
+ {"clock-osc-24m", "sys_pll_pfd0", "sys_pll_pfd1", "sys_pll_pfd2"},
+ {"clock-osc-24m", "audio_pll", "video_pll", "clk_ext1"},
+ {"clock-osc-24m", "audio_pll", "video_pll", "sys_pll_pfd0"},
+ {"clock-osc-24m", "sys_pll_pfd0", "audio_pll", "clk_ext1"},
+ {"clock-osc-24m", "sys_pll_pfd0", "sys_pll_pfd1", "audio_pll"},
+ {"clock-osc-24m", "sys_pll_pfd0", "sys_pll_pfd1", "video_pll"},
+ {"clock-osc-24m", "audio_pll", "video_pll", "sys_pll_pfd2"},
+};
+
+static const struct imx93_clk_root {
+ u32 clk;
+ char *name;
+ u32 off;
+ enum clk_sel sel;
+ unsigned long flags;
+} root_array[] = {
+ /* a55/m33/bus critical clk for system run */
+ { IMX93_CLK_A55_PERIPH, "a55_periph_root", 0x0000, FAST_SEL, CLK_IS_CRITICAL },
+ { IMX93_CLK_A55_MTR_BUS, "a55_mtr_bus_root", 0x0080, LOW_SPEED_IO_SEL, CLK_IS_CRITICAL },
+ { IMX93_CLK_A55, "a55_alt_root", 0x0100, FAST_SEL, CLK_IS_CRITICAL },
+ { IMX93_CLK_M33, "m33_root", 0x0180, LOW_SPEED_IO_SEL, CLK_IS_CRITICAL },
+ { IMX93_CLK_BUS_WAKEUP, "bus_wakeup_root", 0x0280, LOW_SPEED_IO_SEL, CLK_IS_CRITICAL },
+ { IMX93_CLK_BUS_AON, "bus_aon_root", 0x0300, LOW_SPEED_IO_SEL, CLK_IS_CRITICAL },
+ { IMX93_CLK_WAKEUP_AXI, "wakeup_axi_root", 0x0380, FAST_SEL, CLK_IS_CRITICAL },
+ { IMX93_CLK_SWO_TRACE, "swo_trace_root", 0x0400, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_M33_SYSTICK, "m33_systick_root", 0x0480, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_FLEXIO1, "flexio1_root", 0x0500, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_FLEXIO2, "flexio2_root", 0x0580, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPTMR1, "lptmr1_root", 0x0700, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPTMR2, "lptmr2_root", 0x0780, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_TPM2, "tpm2_root", 0x0880, TPM_SEL, },
+ { IMX93_CLK_TPM4, "tpm4_root", 0x0980, TPM_SEL, },
+ { IMX93_CLK_TPM5, "tpm5_root", 0x0a00, TPM_SEL, },
+ { IMX93_CLK_TPM6, "tpm6_root", 0x0a80, TPM_SEL, },
+ { IMX93_CLK_FLEXSPI1, "flexspi1_root", 0x0b00, FAST_SEL, },
+ { IMX93_CLK_CAN1, "can1_root", 0x0b80, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_CAN2, "can2_root", 0x0c00, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPUART1, "lpuart1_root", 0x0c80, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPUART2, "lpuart2_root", 0x0d00, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPUART3, "lpuart3_root", 0x0d80, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPUART4, "lpuart4_root", 0x0e00, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPUART5, "lpuart5_root", 0x0e80, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPUART6, "lpuart6_root", 0x0f00, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPUART7, "lpuart7_root", 0x0f80, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPUART8, "lpuart8_root", 0x1000, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPI2C1, "lpi2c1_root", 0x1080, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPI2C2, "lpi2c2_root", 0x1100, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPI2C3, "lpi2c3_root", 0x1180, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPI2C4, "lpi2c4_root", 0x1200, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPI2C5, "lpi2c5_root", 0x1280, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPI2C6, "lpi2c6_root", 0x1300, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPI2C7, "lpi2c7_root", 0x1380, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPI2C8, "lpi2c8_root", 0x1400, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPSPI1, "lpspi1_root", 0x1480, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPSPI2, "lpspi2_root", 0x1500, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPSPI3, "lpspi3_root", 0x1580, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPSPI4, "lpspi4_root", 0x1600, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPSPI5, "lpspi5_root", 0x1680, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPSPI6, "lpspi6_root", 0x1700, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPSPI7, "lpspi7_root", 0x1780, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_LPSPI8, "lpspi8_root", 0x1800, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_I3C1, "i3c1_root", 0x1880, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_I3C2, "i3c2_root", 0x1900, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_USDHC1, "usdhc1_root", 0x1980, FAST_SEL, },
+ { IMX93_CLK_USDHC2, "usdhc2_root", 0x1a00, FAST_SEL, },
+ { IMX93_CLK_USDHC3, "usdhc3_root", 0x1a80, FAST_SEL, },
+ { IMX93_CLK_SAI1, "sai1_root", 0x1b00, AUDIO_SEL, },
+ { IMX93_CLK_SAI2, "sai2_root", 0x1b80, AUDIO_SEL, },
+ { IMX93_CLK_SAI3, "sai3_root", 0x1c00, AUDIO_SEL, },
+ { IMX93_CLK_CCM_CKO1, "ccm_cko1_root", 0x1c80, CKO1_SEL, },
+ { IMX93_CLK_CCM_CKO2, "ccm_cko2_root", 0x1d00, CKO2_SEL, },
+ { IMX93_CLK_CCM_CKO3, "ccm_cko3_root", 0x1d80, CKO1_SEL, },
+ { IMX93_CLK_CCM_CKO4, "ccm_cko4_root", 0x1e00, CKO2_SEL, },
+ /*
+ * Critical because clk is used for handshake between HSIOMIX and NICMIX when
+ * NICMIX power down/on during system suspend/resume
+ */
+ { IMX93_CLK_HSIO, "hsio_root", 0x1e80, LOW_SPEED_IO_SEL, CLK_IS_CRITICAL},
+ { IMX93_CLK_HSIO_USB_TEST_60M, "hsio_usb_test_60m_root", 0x1f00, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_HSIO_ACSCAN_80M, "hsio_acscan_80m_root", 0x1f80, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_HSIO_ACSCAN_480M, "hsio_acscan_480m_root", 0x2000, MISC_SEL, },
+ { IMX93_CLK_NIC_AXI, "nic_axi_root", 0x2080, FAST_SEL, CLK_IS_CRITICAL, },
+ { IMX93_CLK_ML_APB, "ml_apb_root", 0x2180, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_ML, "ml_root", 0x2200, FAST_SEL, },
+ { IMX93_CLK_MEDIA_AXI, "media_axi_root", 0x2280, FAST_SEL, },
+ { IMX93_CLK_MEDIA_APB, "media_apb_root", 0x2300, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_MEDIA_LDB, "media_ldb_root", 0x2380, VIDEO_SEL, },
+ { IMX93_CLK_MEDIA_DISP_PIX, "media_disp_pix_root", 0x2400, VIDEO_SEL, },
+ { IMX93_CLK_CAM_PIX, "cam_pix_root", 0x2480, VIDEO_SEL, },
+ { IMX93_CLK_MIPI_TEST_BYTE, "mipi_test_byte_root", 0x2500, VIDEO_SEL, },
+ { IMX93_CLK_MIPI_PHY_CFG, "mipi_phy_cfg_root", 0x2580, VIDEO_SEL, },
+ { IMX93_CLK_ADC, "adc_root", 0x2700, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_PDM, "pdm_root", 0x2780, AUDIO_SEL, },
+ { IMX93_CLK_TSTMR1, "tstmr1_root", 0x2800, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_TSTMR2, "tstmr2_root", 0x2880, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_MQS1, "mqs1_root", 0x2900, AUDIO_SEL, },
+ { IMX93_CLK_MQS2, "mqs2_root", 0x2980, AUDIO_SEL, },
+ { IMX93_CLK_AUDIO_XCVR, "audio_xcvr_root", 0x2a00, NON_IO_SEL, },
+ { IMX93_CLK_SPDIF, "spdif_root", 0x2a80, AUDIO_SEL, },
+ { IMX93_CLK_ENET, "enet_root", 0x2b00, NON_IO_SEL, },
+ { IMX93_CLK_ENET_TIMER1, "enet_timer1_root", 0x2b80, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_ENET_TIMER2, "enet_timer2_root", 0x2c00, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_ENET_REF, "enet_ref_root", 0x2c80, NON_IO_SEL, },
+ { IMX93_CLK_ENET_REF_PHY, "enet_ref_phy_root", 0x2d00, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_I3C1_SLOW, "i3c1_slow_root", 0x2d80, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_I3C2_SLOW, "i3c2_slow_root", 0x2e00, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_USB_PHY_BURUNIN, "usb_phy_root", 0x2e80, LOW_SPEED_IO_SEL, },
+ { IMX93_CLK_PAL_CAME_SCAN, "pal_came_scan_root", 0x2f00, MISC_SEL, }
+};
+
+static const struct imx93_clk_ccgr {
+ u32 clk;
+ char *name;
+ char *parent_name;
+ u32 off;
+ unsigned long flags;
+ u32 *shared_count;
+} ccgr_array[] = {
+ { IMX93_CLK_A55_GATE, "a55_alt", "a55_alt_root", 0x8000, },
+ /* M33 critical clk for system run */
+ { IMX93_CLK_CM33_GATE, "cm33", "m33_root", 0x8040, CLK_IS_CRITICAL },
+ { IMX93_CLK_ADC1_GATE, "adc1", "adc_root", 0x82c0, },
+ { IMX93_CLK_WDOG1_GATE, "wdog1", "clock-osc-24m", 0x8300, },
+ { IMX93_CLK_WDOG2_GATE, "wdog2", "clock-osc-24m", 0x8340, },
+ { IMX93_CLK_WDOG3_GATE, "wdog3", "clock-osc-24m", 0x8380, },
+ { IMX93_CLK_WDOG4_GATE, "wdog4", "clock-osc-24m", 0x83c0, },
+ { IMX93_CLK_WDOG5_GATE, "wdog5", "clock-osc-24m", 0x8400, },
+ { IMX93_CLK_SEMA1_GATE, "sema1", "bus_aon_root", 0x8440, },
+ { IMX93_CLK_SEMA2_GATE, "sema2", "bus_wakeup_root", 0x8480, },
+ { IMX93_CLK_MU1_A_GATE, "mu1_a", "bus_aon_root", 0x84c0, CLK_IGNORE_UNUSED },
+ { IMX93_CLK_MU2_A_GATE, "mu2_a", "bus_wakeup_root", 0x84c0, CLK_IGNORE_UNUSED },
+ { IMX93_CLK_MU1_B_GATE, "mu1_b", "bus_aon_root", 0x8500, 0, &share_count_mub },
+ { IMX93_CLK_MU2_B_GATE, "mu2_b", "bus_wakeup_root", 0x8500, 0, &share_count_mub },
+ { IMX93_CLK_EDMA1_GATE, "edma1", "m33_root", 0x8540, },
+ { IMX93_CLK_EDMA2_GATE, "edma2", "wakeup_axi_root", 0x8580, },
+ { IMX93_CLK_FLEXSPI1_GATE, "flexspi1", "flexspi1_root", 0x8640, },
+ { IMX93_CLK_GPIO1_GATE, "gpio1", "m33_root", 0x8880, },
+ { IMX93_CLK_GPIO2_GATE, "gpio2", "bus_wakeup_root", 0x88c0, },
+ { IMX93_CLK_GPIO3_GATE, "gpio3", "bus_wakeup_root", 0x8900, },
+ { IMX93_CLK_GPIO4_GATE, "gpio4", "bus_wakeup_root", 0x8940, },
+ { IMX93_CLK_FLEXIO1_GATE, "flexio1", "flexio1_root", 0x8980, },
+ { IMX93_CLK_FLEXIO2_GATE, "flexio2", "flexio2_root", 0x89c0, },
+ { IMX93_CLK_LPIT1_GATE, "lpit1", "bus_aon_root", 0x8a00, },
+ { IMX93_CLK_LPIT2_GATE, "lpit2", "bus_wakeup_root", 0x8a40, },
+ { IMX93_CLK_LPTMR1_GATE, "lptmr1", "lptmr1_root", 0x8a80, },
+ { IMX93_CLK_LPTMR2_GATE, "lptmr2", "lptmr2_root", 0x8ac0, },
+ { IMX93_CLK_TPM1_GATE, "tpm1", "bus_aon_root", 0x8b00, },
+ { IMX93_CLK_TPM2_GATE, "tpm2", "tpm2_root", 0x8b40, },
+ { IMX93_CLK_TPM3_GATE, "tpm3", "bus_wakeup_root", 0x8b80, },
+ { IMX93_CLK_TPM4_GATE, "tpm4", "tpm4_root", 0x8bc0, },
+ { IMX93_CLK_TPM5_GATE, "tpm5", "tpm5_root", 0x8c00, },
+ { IMX93_CLK_TPM6_GATE, "tpm6", "tpm6_root", 0x8c40, },
+ { IMX93_CLK_CAN1_GATE, "can1", "can1_root", 0x8c80, },
+ { IMX93_CLK_CAN2_GATE, "can2", "can2_root", 0x8cc0, },
+ { IMX93_CLK_LPUART1_GATE, "lpuart1", "lpuart1_root", 0x8d00, },
+ { IMX93_CLK_LPUART2_GATE, "lpuart2", "lpuart2_root", 0x8d40, },
+ { IMX93_CLK_LPUART3_GATE, "lpuart3", "lpuart3_root", 0x8d80, },
+ { IMX93_CLK_LPUART4_GATE, "lpuart4", "lpuart4_root", 0x8dc0, },
+ { IMX93_CLK_LPUART5_GATE, "lpuart5", "lpuart5_root", 0x8e00, },
+ { IMX93_CLK_LPUART6_GATE, "lpuart6", "lpuart6_root", 0x8e40, },
+ { IMX93_CLK_LPUART7_GATE, "lpuart7", "lpuart7_root", 0x8e80, },
+ { IMX93_CLK_LPUART8_GATE, "lpuart8", "lpuart8_root", 0x8ec0, },
+ { IMX93_CLK_LPI2C1_GATE, "lpi2c1", "lpi2c1_root", 0x8f00, },
+ { IMX93_CLK_LPI2C2_GATE, "lpi2c2", "lpi2c2_root", 0x8f40, },
+ { IMX93_CLK_LPI2C3_GATE, "lpi2c3", "lpi2c3_root", 0x8f80, },
+ { IMX93_CLK_LPI2C4_GATE, "lpi2c4", "lpi2c4_root", 0x8fc0, },
+ { IMX93_CLK_LPI2C5_GATE, "lpi2c5", "lpi2c5_root", 0x9000, },
+ { IMX93_CLK_LPI2C6_GATE, "lpi2c6", "lpi2c6_root", 0x9040, },
+ { IMX93_CLK_LPI2C7_GATE, "lpi2c7", "lpi2c7_root", 0x9080, },
+ { IMX93_CLK_LPI2C8_GATE, "lpi2c8", "lpi2c8_root", 0x90c0, },
+ { IMX93_CLK_LPSPI1_GATE, "lpspi1", "lpspi1_root", 0x9100, },
+ { IMX93_CLK_LPSPI2_GATE, "lpspi2", "lpspi2_root", 0x9140, },
+ { IMX93_CLK_LPSPI3_GATE, "lpspi3", "lpspi3_root", 0x9180, },
+ { IMX93_CLK_LPSPI4_GATE, "lpspi4", "lpspi4_root", 0x91c0, },
+ { IMX93_CLK_LPSPI5_GATE, "lpspi5", "lpspi5_root", 0x9200, },
+ { IMX93_CLK_LPSPI6_GATE, "lpspi6", "lpspi6_root", 0x9240, },
+ { IMX93_CLK_LPSPI7_GATE, "lpspi7", "lpspi7_root", 0x9280, },
+ { IMX93_CLK_LPSPI8_GATE, "lpspi8", "lpspi8_root", 0x92c0, },
+ { IMX93_CLK_I3C1_GATE, "i3c1", "i3c1_root", 0x9300, },
+ { IMX93_CLK_I3C2_GATE, "i3c2", "i3c2_root", 0x9340, },
+ { IMX93_CLK_USDHC1_GATE, "usdhc1", "usdhc1_root", 0x9380, },
+ { IMX93_CLK_USDHC2_GATE, "usdhc2", "usdhc2_root", 0x93c0, },
+ { IMX93_CLK_USDHC3_GATE, "usdhc3", "usdhc3_root", 0x9400, },
+ { IMX93_CLK_SAI1_GATE, "sai1", "sai1_root", 0x9440, 0, &share_count_sai1},
+ { IMX93_CLK_SAI1_IPG, "sai1_ipg_clk", "bus_aon_root", 0x9440, 0, &share_count_sai1},
+ { IMX93_CLK_SAI2_GATE, "sai2", "sai2_root", 0x9480, 0, &share_count_sai2},
+ { IMX93_CLK_SAI2_IPG, "sai2_ipg_clk", "bus_wakeup_root", 0x9480, 0, &share_count_sai2},
+ { IMX93_CLK_SAI3_GATE, "sai3", "sai3_root", 0x94c0, 0, &share_count_sai3},
+ { IMX93_CLK_SAI3_IPG, "sai3_ipg_clk", "bus_wakeup_root", 0x94c0, 0, &share_count_sai3},
+ { IMX93_CLK_MIPI_CSI_GATE, "mipi_csi", "media_apb_root", 0x9580, },
+ { IMX93_CLK_MIPI_DSI_GATE, "mipi_dsi", "media_apb_root", 0x95c0, },
+ { IMX93_CLK_LVDS_GATE, "lvds", "media_ldb_root", 0x9600, },
+ { IMX93_CLK_LCDIF_GATE, "lcdif", "media_apb_root", 0x9640, },
+ { IMX93_CLK_PXP_GATE, "pxp", "media_apb_root", 0x9680, },
+ { IMX93_CLK_ISI_GATE, "isi", "media_apb_root", 0x96c0, },
+ { IMX93_CLK_NIC_MEDIA_GATE, "nic_media", "media_axi_root", 0x9700, },
+ { IMX93_CLK_USB_CONTROLLER_GATE, "usb_controller", "hsio_root", 0x9a00, },
+ { IMX93_CLK_USB_TEST_60M_GATE, "usb_test_60m", "hsio_usb_test_60m_root", 0x9a40, },
+ { IMX93_CLK_HSIO_TROUT_24M_GATE, "hsio_trout_24m", "clock-osc-24m", 0x9a80, },
+ { IMX93_CLK_PDM_GATE, "pdm", "pdm_root", 0x9ac0, },
+ { IMX93_CLK_MQS1_GATE, "mqs1", "sai1_root", 0x9b00, },
+ { IMX93_CLK_MQS2_GATE, "mqs2", "sai3_root", 0x9b40, },
+ { IMX93_CLK_AUD_XCVR_GATE, "aud_xcvr", "audio_xcvr_root", 0x9b80, },
+ { IMX93_CLK_SPDIF_GATE, "spdif", "spdif_root", 0x9c00, },
+ { IMX93_CLK_HSIO_32K_GATE, "hsio_32k", "clock-osc-24m", 0x9dc0, },
+ { IMX93_CLK_ENET1_GATE, "enet1", "wakeup_axi_root", 0x9e00, },
+ { IMX93_CLK_ENET_QOS_GATE, "enet_qos", "wakeup_axi_root", 0x9e40, },
+ /* Critical because clk accessed during CPU idle */
+ { IMX93_CLK_SYS_CNT_GATE, "sys_cnt", "clock-osc-24m", 0x9e80, CLK_IS_CRITICAL},
+ { IMX93_CLK_TSTMR1_GATE, "tstmr1", "bus_aon_root", 0x9ec0, },
+ { IMX93_CLK_TSTMR2_GATE, "tstmr2", "bus_wakeup_root", 0x9f00, },
+ { IMX93_CLK_TMC_GATE, "tmc", "clock-osc-24m", 0x9f40, },
+ { IMX93_CLK_PMRO_GATE, "pmro", "clock-osc-24m", 0x9f80, }
+};
+
+static int imx93_clk_probe(struct udevice *dev)
+{
+ const struct imx93_clk_root *root;
+ const struct imx93_clk_ccgr *ccgr;
+ struct clk osc_24m_clk, osc_32k_clk, ext1_clk;
+ void __iomem *base, *anatop_base;
+ int i, ret;
+
+ clk_dm(IMX93_CLK_DUMMY, clk_register_fixed_rate(NULL, "dummy", 0UL));
+
+ ret = clk_get_by_name(dev, "osc_24m", &osc_24m_clk);
+ if (ret)
+ return ret;
+ clk_dm(IMX93_CLK_24M, dev_get_clk_ptr(osc_24m_clk.dev));
+
+ ret = clk_get_by_name(dev, "osc_32k", &osc_32k_clk);
+ if (ret)
+ return ret;
+ clk_dm(IMX93_CLK_32K, dev_get_clk_ptr(osc_32k_clk.dev));
+
+ ret = clk_get_by_name(dev, "clk_ext1", &ext1_clk);
+ if (ret)
+ return ret;
+ clk_dm(IMX93_CLK_EXT1, dev_get_clk_ptr(ext1_clk.dev));
+
+ clk_dm(IMX93_CLK_SYS_PLL_PFD0,
+ clk_register_fixed_rate(NULL, "sys_pll_pfd0", 1000000000));
+ clk_dm(IMX93_CLK_SYS_PLL_PFD0_DIV2,
+ imx_clk_fixed_factor("sys_pll_pfd0_div2", "sys_pll_pfd0", 1, 2));
+ clk_dm(IMX93_CLK_SYS_PLL_PFD1,
+ clk_register_fixed_rate(NULL, "sys_pll_pfd1", 800000000));
+ clk_dm(IMX93_CLK_SYS_PLL_PFD1_DIV2,
+ imx_clk_fixed_factor("sys_pll_pfd1_div2", "sys_pll_pfd1", 1, 2));
+ clk_dm(IMX93_CLK_SYS_PLL_PFD2,
+ clk_register_fixed_rate(NULL, "sys_pll_pfd2", 625000000));
+ clk_dm(IMX93_CLK_SYS_PLL_PFD2_DIV2,
+ imx_clk_fixed_factor("sys_pll_pfd2_div2", "sys_pll_pfd2", 1, 2));
+
+ base = (void *)ANATOP_BASE_ADDR;
+
+ clk_dm(IMX93_CLK_ARM_PLL,
+ imx_clk_fracn_gppll_integer("arm_pll", "clock-osc-24m",
+ anatop_base + 0x1000,
+ &imx_fracn_gppll_integer));
+ clk_dm(IMX93_CLK_AUDIO_PLL,
+ imx_clk_fracn_gppll("audio_pll", "clock-osc-24m",
+ anatop_base + 0x1200, &imx_fracn_gppll));
+ clk_dm(IMX93_CLK_VIDEO_PLL,
+ imx_clk_fracn_gppll("video_pll", "clock-osc-24m",
+ anatop_base + 0x1400, &imx_fracn_gppll));
+
+ base = dev_read_addr_ptr(dev);
+ if (!base)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(root_array); i++) {
+ root = &root_array[i];
+ clk_dm(root->clk, imx93_clk_composite_flags(root->name,
+ parent_names[root->sel],
+ 4, base + root->off, 3,
+ root->flags));
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ccgr_array); i++) {
+ ccgr = &ccgr_array[i];
+ clk_dm(ccgr->clk, imx93_clk_gate(NULL, ccgr->name, ccgr->parent_name,
+ ccgr->flags, base + ccgr->off, 0, 1, 1, 3,
+ ccgr->shared_count));
+ }
+
+ clk_dm(IMX93_CLK_A55_SEL,
+ imx_clk_mux2("a55_sel", base + 0x4820, 0, 1,
+ a55_core_sels, ARRAY_SIZE(a55_core_sels)));
+
+ return 0;
+}
+
+static const struct udevice_id imx93_clk_ids[] = {
+ { .compatible = "fsl,imx93-ccm" },
+ { /* Sentinel */ },
+};
+
+U_BOOT_DRIVER(imx93_clk) = {
+ .name = "clk_imx93",
+ .id = UCLASS_CLK,
+ .of_match = imx93_clk_ids,
+ .ops = &ccf_clk_ops,
+ .probe = imx93_clk_probe,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
index 11f5dca1175..27a53ae5583 100644
--- a/drivers/clk/imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -46,6 +46,34 @@ extern struct imx_pll14xx_clk imx_1416x_pll;
extern struct imx_pll14xx_clk imx_1443x_pll;
extern struct imx_pll14xx_clk imx_1443x_dram_pll;
+#define CLK_FRACN_GPPLL_INTEGER BIT(0)
+#define CLK_FRACN_GPPLL_FRACN BIT(1)
+
+/* NOTE: Rate table should be kept sorted in descending order. */
+struct imx_fracn_gppll_rate_table {
+ unsigned int rate;
+ unsigned int mfi;
+ unsigned int mfn;
+ unsigned int mfd;
+ unsigned int rdiv;
+ unsigned int odiv;
+};
+
+struct imx_fracn_gppll_clk {
+ const struct imx_fracn_gppll_rate_table *rate_table;
+ int rate_count;
+ int flags;
+};
+
+struct clk *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base,
+ const struct imx_fracn_gppll_clk *pll_clk);
+struct clk *imx_clk_fracn_gppll_integer(const char *name, const char *parent_name,
+ void __iomem *base,
+ const struct imx_fracn_gppll_clk *pll_clk);
+
+extern struct imx_fracn_gppll_clk imx_fracn_gppll;
+extern struct imx_fracn_gppll_clk imx_fracn_gppll_integer;
+
struct clk *imx_clk_pll14xx(const char *name, const char *parent_name,
void __iomem *base,
const struct imx_pll14xx_clk *pll_clk);
@@ -224,4 +252,18 @@ struct clk *imx8m_clk_composite_flags(const char *name,
#define imx8m_clk_composite_critical(name, parent_names, reg) \
__imx8m_clk_composite(name, parent_names, reg, CLK_IS_CRITICAL)
+struct clk *imx93_clk_composite_flags(const char *name,
+ const char * const *parent_names,
+ int num_parents,
+ void __iomem *reg,
+ u32 domain_id,
+ unsigned long flags);
+#define imx93_clk_composite(name, parent_names, num_parents, reg, domain_id) \
+ imx93_clk_composite_flags(name, parent_names, num_parents, reg, domain_id \
+ CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE)
+
+struct clk *imx93_clk_gate(struct device *dev, const char *name, const char *parent_name,
+ unsigned long flags, void __iomem *reg, u32 bit_idx, u32 val,
+ u32 mask, u32 domain_id, unsigned int *share_count);
+
#endif /* __MACH_IMX_CLK_H */
diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index 994b44ad7ab..cdc9d6f76ce 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -21,3 +21,11 @@ config CLK_MESON_G12A
help
Enable clock support for the Amlogic G12A SoC family, such as
the S905X/D2
+
+config CLK_MESON_A1
+ bool "Enable clock support for Amlogic A1"
+ depends on CLK && ARCH_MESON
+ default MESON_A1
+ help
+ Enable clock support for the Amlogic A1 SoC family, such as
+ the A113L
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index a486b13e9ce..d975f07aab0 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_CLK_MESON_AXG) += axg.o
obj-$(CONFIG_CLK_MESON_AXG) += axg-ao.o
obj-$(CONFIG_CLK_MESON_G12A) += g12a.o
obj-$(CONFIG_CLK_MESON_G12A) += g12a-ao.o
+obj-$(CONFIG_CLK_MESON_A1) += a1.o
diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
new file mode 100644
index 00000000000..d0f5bb37530
--- /dev/null
+++ b/drivers/clk/meson/a1.c
@@ -0,0 +1,735 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2023 SberDevices, Inc.
+ * Author: Igor Prusov <ivprusov@salutedevices.com>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <regmap.h>
+#include <asm/arch/clock-a1.h>
+#include <dt-bindings/clock/amlogic,a1-pll-clkc.h>
+#include <dt-bindings/clock/amlogic,a1-peripherals-clkc.h>
+#include "clk_meson.h"
+
+/*
+ * This driver supports both PLL and peripherals clock sources.
+ * Following operations are supported:
+ * - calculating clock frequency on a limited tree
+ * - reading muxes and dividers
+ * - enabling/disabling gates without propagation
+ * - reparenting without rate propagation, only on muxes
+ * - setting rates with limited reparenting, only on dividers with mux parent
+ */
+
+#define NR_CLKS 154
+#define NR_PLL_CLKS 11
+
+/* External clock IDs. Those should not overlap with regular IDs */
+#define EXTERNAL_XTAL (NR_CLKS + 0)
+#define EXTERNAL_FCLK_DIV2 (NR_CLKS + 1)
+#define EXTERNAL_FCLK_DIV3 (NR_CLKS + 2)
+#define EXTERNAL_FCLK_DIV5 (NR_CLKS + 3)
+#define EXTERNAL_FCLK_DIV7 (NR_CLKS + 4)
+
+#define EXTERNAL_FIXPLL_IN (NR_PLL_CLKS + 1)
+
+#define SET_PARM_VALUE(_priv, _parm, _val) \
+ regmap_update_bits((_priv)->map, (_parm)->reg_off, \
+ SETPMASK((_parm)->width, (_parm)->shift), \
+ (_val) << (_parm)->shift)
+
+#define GET_PARM_VALUE(_priv, _parm) \
+({ \
+ uint _reg; \
+ regmap_read((_priv)->map, (_parm)->reg_off, &_reg); \
+ PARM_GET((_parm)->width, (_parm)->shift, _reg); \
+})
+
+struct meson_clk {
+ struct regmap *map;
+};
+
+/**
+ * enum meson_clk_type - The type of clock
+ * @MESON_CLK_ANY: Special value that matches any clock type
+ * @MESON_CLK_GATE: This clock is a gate
+ * @MESON_CLK_MUX: This clock is a multiplexer
+ * @MESON_CLK_DIV: This clock is a configurable divider
+ * @MESON_CLK_FIXED_DIV: This clock is a configurable divider
+ * @MESON_CLK_EXTERNAL: This is an external clock from different clock provider
+ * @MESON_CLK_PLL: This is a PLL
+ */
+enum meson_clk_type {
+ MESON_CLK_ANY = 0,
+ MESON_CLK_GATE,
+ MESON_CLK_MUX,
+ MESON_CLK_DIV,
+ MESON_CLK_FIXED_DIV,
+ MESON_CLK_EXTERNAL,
+ MESON_CLK_PLL,
+};
+
+/**
+ * struct meson_clk_info - The parameters defining a clock
+ * @name: Name of the clock
+ * @parm: Register bits description for muxes and dividers
+ * @div: Fixed divider value
+ * @parents: List of parent clock IDs
+ * @type: Clock type
+ */
+struct meson_clk_info {
+ const char *name;
+ union {
+ const struct parm *parm;
+ u8 div;
+ };
+ const unsigned int *parents;
+ const enum meson_clk_type type;
+};
+
+/**
+ * struct meson_clk_data - Clocks supported by clock provider
+ * @num_clocks: Number of clocks
+ * @clocks: Array of clock descriptions
+ *
+ */
+struct meson_clk_data {
+ const u8 num_clocks;
+ const struct meson_clk_info **clocks;
+};
+
+/* Clock description initialization macros */
+
+/* A multiplexer */
+#define CLK_MUX(_name, _reg, _shift, _width, ...) \
+ (&(struct meson_clk_info){ \
+ .parents = (const unsigned int[])__VA_ARGS__, \
+ .parm = &(struct parm) { \
+ .reg_off = (_reg), \
+ .shift = (_shift), \
+ .width = (_width), \
+ }, \
+ .name = (_name), \
+ .type = MESON_CLK_MUX, \
+ })
+
+/* A divider with an integral divisor */
+#define CLK_DIV(_name, _reg, _shift, _width, _parent) \
+ (&(struct meson_clk_info){ \
+ .parents = (const unsigned int[]) { (_parent) }, \
+ .parm = &(struct parm) { \
+ .reg_off = (_reg), \
+ .shift = (_shift), \
+ .width = (_width), \
+ }, \
+ .name = (_name), \
+ .type = MESON_CLK_DIV, \
+ })
+
+/* A fixed divider */
+#define CLK_DIV_FIXED(_name, _div, _parent) \
+ (&(struct meson_clk_info){ \
+ .parents = (const unsigned int[]) { (_parent) }, \
+ .div = (_div), \
+ .name = (_name), \
+ .type = MESON_CLK_FIXED_DIV, \
+ })
+
+/* An external clock */
+#define CLK_EXTERNAL(_name) \
+ (&(struct meson_clk_info){ \
+ .name = (_name), \
+ .parents = (const unsigned int[]) { -ENOENT }, \
+ .type = MESON_CLK_EXTERNAL, \
+ })
+
+/* A clock gate */
+#define CLK_GATE(_name, _reg, _shift, _parent) \
+ (&(struct meson_clk_info){ \
+ .parents = (const unsigned int[]) { (_parent) }, \
+ .parm = &(struct parm) { \
+ .reg_off = (_reg), \
+ .shift = (_shift), \
+ .width = 1, \
+ }, \
+ .name = (_name), \
+ .type = MESON_CLK_GATE, \
+ })
+
+/* A PLL clock */
+#define CLK_PLL(_name, _parent, ...) \
+ (&(struct meson_clk_info){ \
+ .name = (_name), \
+ .parents = (const unsigned int[]) { (_parent) }, \
+ .parm = (const struct parm[])__VA_ARGS__, \
+ .type = MESON_CLK_PLL, \
+ })
+
+/* A1 peripherals clocks */
+static const struct meson_clk_info *meson_clocks[] = {
+ [CLKID_SPIFC_SEL] = CLK_MUX("spifc_sel", A1_SPIFC_CLK_CTRL, 9, 2, {
+ EXTERNAL_FCLK_DIV2,
+ EXTERNAL_FCLK_DIV3,
+ EXTERNAL_FCLK_DIV5,
+ -ENOENT,
+ }),
+ [CLKID_SPIFC_SEL2] = CLK_MUX("spifc_sel2", A1_SPIFC_CLK_CTRL, 15, 1, {
+ CLKID_SPIFC_DIV,
+ EXTERNAL_XTAL,
+ }),
+ [CLKID_USB_BUS_SEL] = CLK_MUX("usb_bus_sel", A1_USB_BUSCLK_CTRL, 9, 2, {
+ -ENOENT,
+ CLKID_SYS,
+ EXTERNAL_FCLK_DIV3,
+ EXTERNAL_FCLK_DIV5,
+ }),
+ [CLKID_SYS] = CLK_MUX("sys", A1_SYS_CLK_CTRL0, 31, 1, {
+ CLKID_SYS_A,
+ CLKID_SYS_B,
+ }),
+ [CLKID_SYS_A_SEL] = CLK_MUX("sys_a_sel", A1_SYS_CLK_CTRL0, 10, 3, {
+ -ENOENT,
+ EXTERNAL_FCLK_DIV2,
+ EXTERNAL_FCLK_DIV3,
+ EXTERNAL_FCLK_DIV5,
+ -ENOENT,
+ -ENOENT,
+ -ENOENT,
+ -ENOENT,
+ }),
+ [CLKID_SYS_B_SEL] = CLK_MUX("sys_b_sel", A1_SYS_CLK_CTRL0, 26, 3, {
+ -ENOENT,
+ EXTERNAL_FCLK_DIV2,
+ EXTERNAL_FCLK_DIV3,
+ EXTERNAL_FCLK_DIV5,
+ -ENOENT,
+ -ENOENT,
+ -ENOENT,
+ -ENOENT,
+ }),
+
+ [CLKID_SPIFC_DIV] = CLK_DIV("spifc_div", A1_SPIFC_CLK_CTRL, 0, 8,
+ CLKID_SPIFC_SEL
+ ),
+ [CLKID_USB_BUS_DIV] = CLK_DIV("usb_bus_div", A1_USB_BUSCLK_CTRL, 0, 8,
+ CLKID_USB_BUS_SEL
+ ),
+ [CLKID_SYS_A_DIV] = CLK_DIV("sys_a_div", A1_SYS_CLK_CTRL0, 0, 10,
+ CLKID_SYS_A_SEL
+ ),
+ [CLKID_SYS_B_DIV] = CLK_DIV("sys_b_div", A1_SYS_CLK_CTRL0, 16, 10,
+ CLKID_SYS_B_SEL
+ ),
+
+ [CLKID_SPIFC] = CLK_GATE("spifc", A1_SPIFC_CLK_CTRL, 8,
+ CLKID_SPIFC_SEL2
+ ),
+ [CLKID_USB_BUS] = CLK_GATE("usb_bus", A1_USB_BUSCLK_CTRL, 8,
+ CLKID_USB_BUS_DIV
+ ),
+ [CLKID_SYS_A] = CLK_GATE("sys_a", A1_SYS_CLK_CTRL0, 13,
+ CLKID_SYS_A_DIV
+ ),
+ [CLKID_SYS_B] = CLK_GATE("sys_b", A1_SYS_CLK_CTRL0, 29,
+ CLKID_SYS_B_DIV
+ ),
+ [CLKID_FIXPLL_IN] = CLK_GATE("fixpll_in", A1_SYS_OSCIN_CTRL, 1,
+ EXTERNAL_XTAL
+ ),
+ [CLKID_USB_PHY_IN] = CLK_GATE("usb_phy_in", A1_SYS_OSCIN_CTRL, 2,
+ EXTERNAL_XTAL
+ ),
+ [CLKID_USB_CTRL_IN] = CLK_GATE("usb_ctrl_in", A1_SYS_OSCIN_CTRL, 3,
+ EXTERNAL_XTAL
+ ),
+ [CLKID_USB_CTRL] = CLK_GATE("usb_ctrl", A1_SYS_CLK_EN0, 28,
+ CLKID_SYS
+ ),
+ [CLKID_USB_PHY] = CLK_GATE("usb_phy", A1_SYS_CLK_EN0, 27,
+ CLKID_SYS
+ ),
+ [CLKID_SARADC] = CLK_GATE("saradc", A1_SAR_ADC_CLK_CTR, 8,
+ -ENOENT
+ ),
+ [CLKID_SARADC_EN] = CLK_GATE("saradc_en", A1_SYS_CLK_EN0, 13,
+ CLKID_SYS
+ ),
+
+ [EXTERNAL_XTAL] = CLK_EXTERNAL("xtal"),
+ [EXTERNAL_FCLK_DIV2] = CLK_EXTERNAL("fclk_div2"),
+ [EXTERNAL_FCLK_DIV3] = CLK_EXTERNAL("fclk_div3"),
+ [EXTERNAL_FCLK_DIV5] = CLK_EXTERNAL("fclk_div5"),
+ [EXTERNAL_FCLK_DIV7] = CLK_EXTERNAL("fclk_div7"),
+};
+
+/* A1 PLL clocks */
+static const struct meson_clk_info *meson_pll_clocks[] = {
+ [EXTERNAL_FIXPLL_IN] = CLK_EXTERNAL("fixpll_in"),
+
+ [CLKID_FIXED_PLL_DCO] = CLK_PLL("fixed_pll_dco", EXTERNAL_FIXPLL_IN, {
+ {A1_ANACTRL_FIXPLL_CTRL0, 0, 8},
+ {A1_ANACTRL_FIXPLL_CTRL0, 10, 5},
+ }),
+
+ [CLKID_FCLK_DIV2_DIV] = CLK_DIV_FIXED("fclk_div2_div", 2,
+ CLKID_FIXED_PLL
+ ),
+ [CLKID_FCLK_DIV3_DIV] = CLK_DIV_FIXED("fclk_div3_div", 3,
+ CLKID_FIXED_PLL
+ ),
+ [CLKID_FCLK_DIV5_DIV] = CLK_DIV_FIXED("fclk_div5_div", 5,
+ CLKID_FIXED_PLL
+ ),
+ [CLKID_FCLK_DIV7_DIV] = CLK_DIV_FIXED("fclk_div7_div", 7,
+ CLKID_FIXED_PLL
+ ),
+
+ [CLKID_FIXED_PLL] = CLK_GATE("fixed_pll", A1_ANACTRL_FIXPLL_CTRL0, 20,
+ CLKID_FIXED_PLL_DCO
+ ),
+ [CLKID_FCLK_DIV2] = CLK_GATE("fclk_div2", A1_ANACTRL_FIXPLL_CTRL0, 21,
+ CLKID_FCLK_DIV2_DIV
+ ),
+ [CLKID_FCLK_DIV3] = CLK_GATE("fclk_div3", A1_ANACTRL_FIXPLL_CTRL0, 22,
+ CLKID_FCLK_DIV3_DIV
+ ),
+ [CLKID_FCLK_DIV5] = CLK_GATE("fclk_div5", A1_ANACTRL_FIXPLL_CTRL0, 23,
+ CLKID_FCLK_DIV5_DIV
+ ),
+ [CLKID_FCLK_DIV7] = CLK_GATE("fclk_div7", A1_ANACTRL_FIXPLL_CTRL0, 24,
+ CLKID_FCLK_DIV7_DIV
+ ),
+};
+
+static const struct meson_clk_info *meson_clk_get_info(struct clk *clk, ulong id,
+ enum meson_clk_type type)
+{
+ struct meson_clk_data *data;
+ const struct meson_clk_info *info;
+
+ data = (struct meson_clk_data *)dev_get_driver_data(clk->dev);
+ if (id >= data->num_clocks)
+ return ERR_PTR(-EINVAL);
+
+ info = data->clocks[id];
+ if (!info)
+ return ERR_PTR(-ENOENT);
+
+ if (type != MESON_CLK_ANY && type != info->type)
+ return ERR_PTR(-EINVAL);
+
+ return info;
+}
+
+static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id);
+
+static int meson_set_gate(struct clk *clk, bool on)
+{
+ struct meson_clk *priv = dev_get_priv(clk->dev);
+ const struct meson_clk_info *info;
+
+ debug("%s: %sabling %lu\n", __func__, on ? "en" : "dis", clk->id);
+
+ info = meson_clk_get_info(clk, clk->id, MESON_CLK_ANY);
+ if (IS_ERR(info))
+ return PTR_ERR(info);
+
+ SET_PARM_VALUE(priv, info->parm, on);
+
+ return 0;
+}
+
+static int meson_clk_enable(struct clk *clk)
+{
+ return meson_set_gate(clk, true);
+}
+
+static int meson_clk_disable(struct clk *clk)
+{
+ return meson_set_gate(clk, false);
+}
+
+static ulong meson_div_get_rate(struct clk *clk, unsigned long id)
+{
+ struct meson_clk *priv = dev_get_priv(clk->dev);
+ u16 n;
+ ulong rate;
+ const struct meson_clk_info *info;
+
+ info = meson_clk_get_info(clk, id, MESON_CLK_DIV);
+ if (IS_ERR(info))
+ return PTR_ERR(info);
+
+ /* Actual divider value is (field value + 1), hence the increment */
+ n = GET_PARM_VALUE(priv, info->parm) + 1;
+
+ rate = meson_clk_get_rate_by_id(clk, info->parents[0]);
+
+ return rate / n;
+}
+
+static int meson_clk_get_parent(struct clk *clk, unsigned long id)
+{
+ uint reg = 0;
+ struct meson_clk *priv = dev_get_priv(clk->dev);
+ const struct meson_clk_info *info;
+
+ info = meson_clk_get_info(clk, id, MESON_CLK_ANY);
+ if (IS_ERR(info))
+ return PTR_ERR(info);
+
+ /* For muxes we read currently selected parent from register,
+ * for other types there is always only one element in parents array.
+ */
+ if (info->type == MESON_CLK_MUX) {
+ reg = GET_PARM_VALUE(priv, info->parm);
+ if (IS_ERR_VALUE(reg))
+ return reg;
+ }
+
+ return info->parents[reg];
+}
+
+static ulong meson_pll_get_rate(struct clk *clk, unsigned long id)
+{
+ struct meson_clk *priv = dev_get_priv(clk->dev);
+ const struct meson_clk_info *info;
+ const struct parm *pm, *pn;
+ ulong parent_rate_mhz;
+ unsigned int parent;
+ u16 n, m;
+
+ info = meson_clk_get_info(clk, id, MESON_CLK_ANY);
+ if (IS_ERR(info))
+ return PTR_ERR(info);
+
+ pm = &info->parm[0];
+ pn = &info->parm[1];
+
+ n = GET_PARM_VALUE(priv, pn);
+ m = GET_PARM_VALUE(priv, pm);
+
+ if (n == 0)
+ return -EINVAL;
+
+ parent = info->parents[0];
+ parent_rate_mhz = meson_clk_get_rate_by_id(clk, parent) / 1000000;
+
+ return parent_rate_mhz * m / n * 1000000;
+}
+
+static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id)
+{
+ ulong rate, parent;
+ const struct meson_clk_info *info;
+
+ if (IS_ERR_VALUE(id))
+ return id;
+
+ info = meson_clk_get_info(clk, id, MESON_CLK_ANY);
+ if (IS_ERR(info))
+ return PTR_ERR(info);
+
+ switch (info->type) {
+ case MESON_CLK_PLL:
+ rate = meson_pll_get_rate(clk, id);
+ break;
+ case MESON_CLK_GATE:
+ case MESON_CLK_MUX:
+ parent = meson_clk_get_parent(clk, id);
+ rate = meson_clk_get_rate_by_id(clk, parent);
+ break;
+ case MESON_CLK_DIV:
+ rate = meson_div_get_rate(clk, id);
+ break;
+ case MESON_CLK_FIXED_DIV:
+ parent = meson_clk_get_parent(clk, id);
+ rate = meson_clk_get_rate_by_id(clk, parent) / info->div;
+ break;
+ case MESON_CLK_EXTERNAL: {
+ int ret;
+ struct clk external_clk;
+
+ ret = clk_get_by_name(clk->dev, info->name, &external_clk);
+ if (ret)
+ return ret;
+
+ rate = clk_get_rate(&external_clk);
+ break;
+ }
+ default:
+ rate = -EINVAL;
+ break;
+ }
+
+ return rate;
+}
+
+static ulong meson_clk_get_rate(struct clk *clk)
+{
+ return meson_clk_get_rate_by_id(clk, clk->id);
+}
+
+/* This implements rate propagation for dividers placed after multiplexer:
+ * ---------|\
+ * ..... | |---DIV--
+ * ---------|/
+ */
+static ulong meson_composite_set_rate(struct clk *clk, ulong id, ulong rate)
+{
+ unsigned int i, best_div_val;
+ unsigned long best_delta, best_parent;
+ const struct meson_clk_info *div;
+ const struct meson_clk_info *mux;
+ struct meson_clk *priv = dev_get_priv(clk->dev);
+
+ div = meson_clk_get_info(clk, id, MESON_CLK_DIV);
+ if (IS_ERR(div))
+ return PTR_ERR(div);
+
+ mux = meson_clk_get_info(clk, div->parents[0], MESON_CLK_MUX);
+ if (IS_ERR(mux))
+ return PTR_ERR(mux);
+
+ best_parent = -EINVAL;
+ best_delta = ULONG_MAX;
+ for (i = 0; i < (1 << mux->parm->width); i++) {
+ unsigned long parent_rate, delta;
+ unsigned int div_val;
+
+ parent_rate = meson_clk_get_rate_by_id(clk, mux->parents[i]);
+ if (IS_ERR_VALUE(parent_rate))
+ continue;
+
+ /* If overflow, try to use max divider value */
+ div_val = min(DIV_ROUND_CLOSEST(parent_rate, rate),
+ (1UL << div->parm->width));
+
+ delta = abs(rate - (parent_rate / div_val));
+ if (delta < best_delta) {
+ best_delta = delta;
+ best_div_val = div_val;
+ best_parent = i;
+ }
+ }
+
+ if (IS_ERR_VALUE(best_parent))
+ return best_parent;
+
+ SET_PARM_VALUE(priv, mux->parm, best_parent);
+ /* Divider is set to (field value + 1), hence the decrement */
+ SET_PARM_VALUE(priv, div->parm, best_div_val - 1);
+
+ return 0;
+}
+
+static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned int id, ulong rate);
+
+static ulong meson_mux_set_rate(struct clk *clk, unsigned long id, ulong rate)
+{
+ int i;
+ ulong ret = -EINVAL;
+ struct meson_clk *priv = dev_get_priv(clk->dev);
+ const struct meson_clk_info *info;
+
+ info = meson_clk_get_info(clk, id, MESON_CLK_MUX);
+ if (IS_ERR(info))
+ return PTR_ERR(info);
+
+ for (i = 0; i < (1 << info->parm->width); i++) {
+ ret = meson_clk_set_rate_by_id(clk, info->parents[i], rate);
+ if (!ret) {
+ SET_PARM_VALUE(priv, info->parm, i);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/* Rate propagation is implemented for a subcection of a clock tree, that is
+ * required at boot stage.
+ */
+static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned int id, ulong rate)
+{
+ switch (id) {
+ case CLKID_SPIFC_DIV:
+ case CLKID_USB_BUS_DIV:
+ return meson_composite_set_rate(clk, id, rate);
+ case CLKID_SPIFC:
+ case CLKID_USB_BUS: {
+ unsigned long parent = meson_clk_get_parent(clk, id);
+
+ return meson_clk_set_rate_by_id(clk, parent, rate);
+ }
+ case CLKID_SPIFC_SEL2:
+ return meson_mux_set_rate(clk, id, rate);
+ }
+
+ return -EINVAL;
+}
+
+static ulong meson_clk_set_rate(struct clk *clk, ulong rate)
+{
+ return meson_clk_set_rate_by_id(clk, clk->id, rate);
+}
+
+static int meson_mux_set_parent_by_id(struct clk *clk, unsigned int parent_id)
+{
+ unsigned int i, parent_index;
+ struct meson_clk *priv = dev_get_priv(clk->dev);
+ const struct meson_clk_info *info;
+
+ info = meson_clk_get_info(clk, clk->id, MESON_CLK_MUX);
+ if (IS_ERR(info))
+ return PTR_ERR(info);
+
+ parent_index = -EINVAL;
+ for (i = 0; i < (1 << info->parm->width); i++) {
+ if (parent_id == info->parents[i]) {
+ parent_index = i;
+ break;
+ }
+ }
+
+ if (IS_ERR_VALUE(parent_index))
+ return parent_index;
+
+ SET_PARM_VALUE(priv, info->parm, parent_index);
+
+ return 0;
+}
+
+static int meson_clk_set_parent(struct clk *clk, struct clk *parent_clk)
+{
+ return meson_mux_set_parent_by_id(clk, parent_clk->id);
+}
+
+static struct clk_ops meson_clk_ops = {
+ .disable = meson_clk_disable,
+ .enable = meson_clk_enable,
+ .get_rate = meson_clk_get_rate,
+ .set_rate = meson_clk_set_rate,
+ .set_parent = meson_clk_set_parent,
+};
+
+static int meson_clk_probe(struct udevice *dev)
+{
+ struct meson_clk *priv = dev_get_priv(dev);
+
+ return regmap_init_mem(dev_ofnode(dev), &priv->map);
+}
+
+struct meson_clk_data meson_a1_peripherals_info = {
+ .clocks = meson_clocks,
+ .num_clocks = ARRAY_SIZE(meson_clocks),
+};
+
+struct meson_clk_data meson_a1_pll_info = {
+ .clocks = meson_pll_clocks,
+ .num_clocks = ARRAY_SIZE(meson_pll_clocks),
+};
+
+static const struct udevice_id meson_clk_ids[] = {
+ {
+ .compatible = "amlogic,a1-peripherals-clkc",
+ .data = (ulong)&meson_a1_peripherals_info,
+ },
+ {
+ .compatible = "amlogic,a1-pll-clkc",
+ .data = (ulong)&meson_a1_pll_info,
+ },
+ { }
+};
+
+U_BOOT_DRIVER(meson_clk) = {
+ .name = "meson-clk-a1",
+ .id = UCLASS_CLK,
+ .of_match = meson_clk_ids,
+ .priv_auto = sizeof(struct meson_clk),
+ .ops = &meson_clk_ops,
+ .probe = meson_clk_probe,
+};
+
+static const char *meson_clk_get_name(struct clk *clk, int id)
+{
+ const struct meson_clk_info *info;
+
+ info = meson_clk_get_info(clk, id, MESON_CLK_ANY);
+
+ return IS_ERR(info) ? "unknown" : info->name;
+}
+
+static int meson_clk_dump(struct clk *clk)
+{
+ const struct meson_clk_info *info;
+ struct meson_clk *priv;
+ unsigned long rate;
+ char *state, frequency[80];
+ int parent;
+
+ priv = dev_get_priv(clk->dev);
+
+ info = meson_clk_get_info(clk, clk->id, MESON_CLK_ANY);
+ if (IS_ERR(info) || !info->name)
+ return -EINVAL;
+
+ rate = clk_get_rate(clk);
+ if (IS_ERR_VALUE(rate))
+ sprintf(frequency, "unknown");
+ else
+ sprintf(frequency, "%lu", rate);
+
+ if (info->type == MESON_CLK_GATE)
+ state = GET_PARM_VALUE(priv, info->parm) ? "enabled" : "disabled";
+ else
+ state = "N/A";
+
+ parent = meson_clk_get_parent(clk, clk->id);
+ printf("%15s%20s%20s%15s\n",
+ info->name,
+ frequency,
+ meson_clk_get_name(clk, parent),
+ state);
+
+ return 0;
+}
+
+static int meson_clk_dump_dev(struct udevice *dev)
+{
+ int i;
+ struct meson_clk_data *data;
+ const char *sep = "--------------------";
+
+ printf("%s:\n", dev->name);
+ printf("%.15s%s%s%.15s\n", sep, sep, sep, sep);
+ printf("%15s%20s%20s%15s\n", "clk", "frequency", "parent", "state");
+ printf("%.15s%s%s%.15s\n", sep, sep, sep, sep);
+
+ data = (struct meson_clk_data *)dev_get_driver_data(dev);
+ for (i = 0; i < data->num_clocks; i++) {
+ meson_clk_dump(&(struct clk){
+ .dev = dev,
+ .id = i
+ });
+ }
+
+ return 0;
+}
+
+int soc_clk_dump(void)
+{
+ struct udevice *dev;
+ int i = 0;
+
+ while (!uclass_get_device(UCLASS_CLK, i++, &dev)) {
+ if (dev->driver == DM_DRIVER_GET(meson_clk)) {
+ meson_clk_dump_dev(dev);
+ printf("\n");
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig
index 437a82cd48b..927d62cf99a 100644
--- a/drivers/clk/renesas/Kconfig
+++ b/drivers/clk/renesas/Kconfig
@@ -156,3 +156,12 @@ config CLK_R9A06G032
depends on CLK_RENESAS
help
Enable this to support the clocks on Renesas R9A06G032 SoC.
+
+config CLK_RZG2L
+ bool "Renesas RZ/G2L family clock support"
+ depends on CLK_RENESAS
+ select DM_RESET
+
+config CLK_R9A07G044
+ bool "RZ/G2L (R9A07G044L) clock support"
+ depends on CLK_RZG2L
diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile
index 48373e61b90..df7e225e9ca 100644
--- a/drivers/clk/renesas/Makefile
+++ b/drivers/clk/renesas/Makefile
@@ -23,3 +23,5 @@ obj-$(CONFIG_CLK_R8A779A0) += r8a779a0-cpg-mssr.o
obj-$(CONFIG_CLK_R8A779F0) += r8a779f0-cpg-mssr.o
obj-$(CONFIG_CLK_R8A779G0) += r8a779g0-cpg-mssr.o
obj-$(CONFIG_CLK_R9A06G032) += r9a06g032-clocks.o
+obj-$(CONFIG_CLK_RZG2L) += rzg2l-cpg.o
+obj-$(CONFIG_CLK_R9A07G044) += r9a07g044-cpg.o
diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c
new file mode 100644
index 00000000000..c8baad1a6c8
--- /dev/null
+++ b/drivers/clk/renesas/r9a07g044-cpg.c
@@ -0,0 +1,383 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/G2L CPG driver
+ *
+ * Copyright (C) 2021-2023 Renesas Electronics Corp.
+ */
+
+#include <dm/device.h>
+#include <dt-bindings/clock/r9a07g044-cpg.h>
+#include <linux/clk-provider.h>
+
+#include "rzg2l-cpg.h"
+
+/* Divider tables */
+static const struct clk_div_table dtable_1_8[] = {
+ {0, 1},
+ {1, 2},
+ {2, 4},
+ {3, 8},
+ {0, 0},
+};
+
+static const struct clk_div_table dtable_1_32[] = {
+ {0, 1},
+ {1, 2},
+ {2, 4},
+ {3, 8},
+ {4, 32},
+ {0, 0},
+};
+
+static const struct clk_div_table dtable_16_128[] = {
+ {0, 16},
+ {1, 32},
+ {2, 64},
+ {3, 128},
+ {0, 0},
+};
+
+/* Mux clock tables */
+static const char * const sel_pll3_3[] = { ".pll3_533", ".pll3_400" };
+static const char * const sel_pll5_4[] = { ".pll5_foutpostdiv", ".pll5_fout1ph0" };
+static const char * const sel_pll6_2[] = { ".pll6_250", ".pll5_250" };
+static const char * const sel_shdi[] = { ".clk_533", ".clk_400", ".clk_266" };
+static const char * const sel_gpu2[] = { ".pll6", ".pll3_div2_2" };
+
+static const struct {
+ struct cpg_core_clk common[56];
+} core_clks = {
+ .common = {
+ /* External Clock Inputs */
+ DEF_INPUT("extal", CLK_EXTAL),
+
+ /* Internal Core Clocks */
+ DEF_FIXED(".osc", R9A07G044_OSCCLK, CLK_EXTAL, 1, 1),
+ DEF_FIXED(".osc_div1000", CLK_OSC_DIV1000, CLK_EXTAL, 1, 1000),
+ DEF_SAMPLL(".pll1", CLK_PLL1, CLK_EXTAL, PLL146_CONF(0)),
+ DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 200, 3),
+ DEF_FIXED(".pll2_533", CLK_PLL2_533, CLK_PLL2, 1, 3),
+ DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 200, 3),
+ DEF_FIXED(".pll3_400", CLK_PLL3_400, CLK_PLL3, 1, 4),
+ DEF_FIXED(".pll3_533", CLK_PLL3_533, CLK_PLL3, 1, 3),
+
+ DEF_FIXED(".pll5", CLK_PLL5, CLK_EXTAL, 125, 1),
+ DEF_FIXED(".pll5_fout3", CLK_PLL5_FOUT3, CLK_PLL5, 1, 6),
+
+ DEF_FIXED(".pll6", CLK_PLL6, CLK_EXTAL, 125, 6),
+
+ DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 1, 2),
+ DEF_FIXED(".clk_800", CLK_PLL2_800, CLK_PLL2, 1, 2),
+ DEF_FIXED(".clk_533", CLK_PLL2_SDHI_533, CLK_PLL2, 1, 3),
+ DEF_FIXED(".clk_400", CLK_PLL2_SDHI_400, CLK_PLL2_800, 1, 2),
+ DEF_FIXED(".clk_266", CLK_PLL2_SDHI_266, CLK_PLL2_SDHI_533, 1, 2),
+
+ DEF_FIXED(".pll2_div2_8", CLK_PLL2_DIV2_8, CLK_PLL2_DIV2, 1, 8),
+ DEF_FIXED(".pll2_div2_10", CLK_PLL2_DIV2_10, CLK_PLL2_DIV2, 1, 10),
+
+ DEF_FIXED(".pll2_533_div2", CLK_PLL2_533_DIV2, CLK_PLL2_533, 1, 2),
+
+ DEF_FIXED(".pll3_div2", CLK_PLL3_DIV2, CLK_PLL3, 1, 2),
+ DEF_FIXED(".pll3_div2_2", CLK_PLL3_DIV2_2, CLK_PLL3_DIV2, 1, 2),
+ DEF_FIXED(".pll3_div2_4", CLK_PLL3_DIV2_4, CLK_PLL3_DIV2, 1, 4),
+ DEF_FIXED(".pll3_div2_4_2", CLK_PLL3_DIV2_4_2, CLK_PLL3_DIV2_4, 1, 2),
+ DEF_MUX_RO(".sel_pll3_3", CLK_SEL_PLL3_3, SEL_PLL3_3, sel_pll3_3),
+ DEF_DIV("divpl3c", CLK_DIV_PLL3_C, CLK_SEL_PLL3_3, DIVPL3C, dtable_1_32),
+
+ DEF_FIXED(".pll5_250", CLK_PLL5_250, CLK_PLL5_FOUT3, 1, 2),
+ DEF_FIXED(".pll6_250", CLK_PLL6_250, CLK_PLL6, 1, 2),
+ DEF_MUX_RO(".sel_gpu2", CLK_SEL_GPU2, SEL_GPU2, sel_gpu2),
+ DEF_PLL5_FOUTPOSTDIV(".pll5_foutpostdiv", CLK_PLL5_FOUTPOSTDIV, CLK_EXTAL),
+ DEF_FIXED(".pll5_fout1ph0", CLK_PLL5_FOUT1PH0, CLK_PLL5_FOUTPOSTDIV, 1, 2),
+ DEF_PLL5_4_MUX(".sel_pll5_4", CLK_SEL_PLL5_4, SEL_PLL5_4, sel_pll5_4),
+ DEF_DIV(".div_dsi_lpclk", CLK_DIV_DSI_LPCLK, CLK_PLL2_533_DIV2,
+ DIVDSILPCLK, dtable_16_128),
+
+ /* Core output clk */
+ DEF_DIV("I", R9A07G044_CLK_I, CLK_PLL1, DIVPL1A, dtable_1_8),
+ DEF_DIV("P0", R9A07G044_CLK_P0, CLK_PLL2_DIV2_8, DIVPL2A, dtable_1_32),
+ DEF_FIXED("P0_DIV2", R9A07G044_CLK_P0_DIV2, R9A07G044_CLK_P0, 1, 2),
+ DEF_FIXED("TSU", R9A07G044_CLK_TSU, CLK_PLL2_DIV2_10, 1, 1),
+ DEF_DIV("P1", R9A07G044_CLK_P1, CLK_PLL3_DIV2_4, DIVPL3B, dtable_1_32),
+ DEF_FIXED("P1_DIV2", CLK_P1_DIV2, R9A07G044_CLK_P1, 1, 2),
+ DEF_DIV("P2", R9A07G044_CLK_P2, CLK_PLL3_DIV2_4_2, DIVPL3A, dtable_1_32),
+ DEF_FIXED("M0", R9A07G044_CLK_M0, CLK_PLL3_DIV2_4, 1, 1),
+ DEF_FIXED("ZT", R9A07G044_CLK_ZT, CLK_PLL3_DIV2_4_2, 1, 1),
+ DEF_MUX("HP", R9A07G044_CLK_HP, SEL_PLL6_2, sel_pll6_2),
+ DEF_FIXED("SPI0", R9A07G044_CLK_SPI0, CLK_DIV_PLL3_C, 1, 2),
+ DEF_FIXED("SPI1", R9A07G044_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4),
+ DEF_SD_MUX("SD0", R9A07G044_CLK_SD0, SEL_SDHI0, sel_shdi),
+ DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1, sel_shdi),
+ DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G044_CLK_SD0, 1, 4),
+ DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G044_CLK_SD1, 1, 4),
+ DEF_DIV("G", R9A07G044_CLK_G, CLK_SEL_GPU2, DIVGPU, dtable_1_8),
+ DEF_FIXED("M1", R9A07G044_CLK_M1, CLK_PLL5_FOUTPOSTDIV, 1, 1),
+ DEF_FIXED("M2", R9A07G044_CLK_M2, CLK_PLL3_533, 1, 2),
+ DEF_FIXED("M2_DIV2", CLK_M2_DIV2, R9A07G044_CLK_M2, 1, 2),
+ DEF_DSI_DIV("DSI_DIV", CLK_DSI_DIV, CLK_SEL_PLL5_4, CLK_SET_RATE_PARENT),
+ DEF_FIXED("M3", R9A07G044_CLK_M3, CLK_DSI_DIV, 1, 1),
+ DEF_FIXED("M4", R9A07G044_CLK_M4, CLK_DIV_DSI_LPCLK, 1, 1),
+ },
+};
+
+static const struct {
+ struct rzg2l_mod_clk common[79];
+} mod_clks = {
+ .common = {
+ DEF_MOD("gic", R9A07G044_GIC600_GICCLK, R9A07G044_CLK_P1,
+ 0x514, 0),
+ DEF_MOD("ia55_pclk", R9A07G044_IA55_PCLK, R9A07G044_CLK_P2,
+ 0x518, 0),
+ DEF_MOD("ia55_clk", R9A07G044_IA55_CLK, R9A07G044_CLK_P1,
+ 0x518, 1),
+ DEF_MOD("dmac_aclk", R9A07G044_DMAC_ACLK, R9A07G044_CLK_P1,
+ 0x52c, 0),
+ DEF_MOD("dmac_pclk", R9A07G044_DMAC_PCLK, CLK_P1_DIV2,
+ 0x52c, 1),
+ DEF_MOD("ostm0_pclk", R9A07G044_OSTM0_PCLK, R9A07G044_CLK_P0,
+ 0x534, 0),
+ DEF_MOD("ostm1_pclk", R9A07G044_OSTM1_PCLK, R9A07G044_CLK_P0,
+ 0x534, 1),
+ DEF_MOD("ostm2_pclk", R9A07G044_OSTM2_PCLK, R9A07G044_CLK_P0,
+ 0x534, 2),
+ DEF_MOD("mtu_x_mck", R9A07G044_MTU_X_MCK_MTU3, R9A07G044_CLK_P0,
+ 0x538, 0),
+ DEF_MOD("gpt_pclk", R9A07G044_GPT_PCLK, R9A07G044_CLK_P0,
+ 0x540, 0),
+ DEF_MOD("poeg_a_clkp", R9A07G044_POEG_A_CLKP, R9A07G044_CLK_P0,
+ 0x544, 0),
+ DEF_MOD("poeg_b_clkp", R9A07G044_POEG_B_CLKP, R9A07G044_CLK_P0,
+ 0x544, 1),
+ DEF_MOD("poeg_c_clkp", R9A07G044_POEG_C_CLKP, R9A07G044_CLK_P0,
+ 0x544, 2),
+ DEF_MOD("poeg_d_clkp", R9A07G044_POEG_D_CLKP, R9A07G044_CLK_P0,
+ 0x544, 3),
+ DEF_MOD("wdt0_pclk", R9A07G044_WDT0_PCLK, R9A07G044_CLK_P0,
+ 0x548, 0),
+ DEF_MOD("wdt0_clk", R9A07G044_WDT0_CLK, R9A07G044_OSCCLK,
+ 0x548, 1),
+ DEF_MOD("wdt1_pclk", R9A07G044_WDT1_PCLK, R9A07G044_CLK_P0,
+ 0x548, 2),
+ DEF_MOD("wdt1_clk", R9A07G044_WDT1_CLK, R9A07G044_OSCCLK,
+ 0x548, 3),
+ DEF_MOD("spi_clk2", R9A07G044_SPI_CLK2, R9A07G044_CLK_SPI1,
+ 0x550, 0),
+ DEF_MOD("spi_clk", R9A07G044_SPI_CLK, R9A07G044_CLK_SPI0,
+ 0x550, 1),
+ DEF_MOD("sdhi0_imclk", R9A07G044_SDHI0_IMCLK, CLK_SD0_DIV4,
+ 0x554, 0),
+ DEF_MOD("sdhi0_imclk2", R9A07G044_SDHI0_IMCLK2, CLK_SD0_DIV4,
+ 0x554, 1),
+ DEF_MOD("sdhi0_clk_hs", R9A07G044_SDHI0_CLK_HS, R9A07G044_CLK_SD0,
+ 0x554, 2),
+ DEF_MOD("sdhi0_aclk", R9A07G044_SDHI0_ACLK, R9A07G044_CLK_P1,
+ 0x554, 3),
+ DEF_MOD("sdhi1_imclk", R9A07G044_SDHI1_IMCLK, CLK_SD1_DIV4,
+ 0x554, 4),
+ DEF_MOD("sdhi1_imclk2", R9A07G044_SDHI1_IMCLK2, CLK_SD1_DIV4,
+ 0x554, 5),
+ DEF_MOD("sdhi1_clk_hs", R9A07G044_SDHI1_CLK_HS, R9A07G044_CLK_SD1,
+ 0x554, 6),
+ DEF_MOD("sdhi1_aclk", R9A07G044_SDHI1_ACLK, R9A07G044_CLK_P1,
+ 0x554, 7),
+ DEF_MOD("gpu_clk", R9A07G044_GPU_CLK, R9A07G044_CLK_G,
+ 0x558, 0),
+ DEF_MOD("gpu_axi_clk", R9A07G044_GPU_AXI_CLK, R9A07G044_CLK_P1,
+ 0x558, 1),
+ DEF_MOD("gpu_ace_clk", R9A07G044_GPU_ACE_CLK, R9A07G044_CLK_P1,
+ 0x558, 2),
+ DEF_MOD("cru_sysclk", R9A07G044_CRU_SYSCLK, CLK_M2_DIV2,
+ 0x564, 0),
+ DEF_MOD("cru_vclk", R9A07G044_CRU_VCLK, R9A07G044_CLK_M2,
+ 0x564, 1),
+ DEF_MOD("cru_pclk", R9A07G044_CRU_PCLK, R9A07G044_CLK_ZT,
+ 0x564, 2),
+ DEF_MOD("cru_aclk", R9A07G044_CRU_ACLK, R9A07G044_CLK_M0,
+ 0x564, 3),
+ DEF_MOD("dsi_pll_clk", R9A07G044_MIPI_DSI_PLLCLK, R9A07G044_CLK_M1,
+ 0x568, 0),
+ DEF_MOD("dsi_sys_clk", R9A07G044_MIPI_DSI_SYSCLK, CLK_M2_DIV2,
+ 0x568, 1),
+ DEF_MOD("dsi_aclk", R9A07G044_MIPI_DSI_ACLK, R9A07G044_CLK_P1,
+ 0x568, 2),
+ DEF_MOD("dsi_pclk", R9A07G044_MIPI_DSI_PCLK, R9A07G044_CLK_P2,
+ 0x568, 3),
+ DEF_MOD("dsi_vclk", R9A07G044_MIPI_DSI_VCLK, R9A07G044_CLK_M3,
+ 0x568, 4),
+ DEF_MOD("dsi_lpclk", R9A07G044_MIPI_DSI_LPCLK, R9A07G044_CLK_M4,
+ 0x568, 5),
+ DEF_COUPLED("lcdc_a", R9A07G044_LCDC_CLK_A, R9A07G044_CLK_M0,
+ 0x56c, 0),
+ DEF_COUPLED("lcdc_p", R9A07G044_LCDC_CLK_P, R9A07G044_CLK_ZT,
+ 0x56c, 0),
+ DEF_MOD("lcdc_clk_d", R9A07G044_LCDC_CLK_D, R9A07G044_CLK_M3,
+ 0x56c, 1),
+ DEF_MOD("ssi0_pclk", R9A07G044_SSI0_PCLK2, R9A07G044_CLK_P0,
+ 0x570, 0),
+ DEF_MOD("ssi0_sfr", R9A07G044_SSI0_PCLK_SFR, R9A07G044_CLK_P0,
+ 0x570, 1),
+ DEF_MOD("ssi1_pclk", R9A07G044_SSI1_PCLK2, R9A07G044_CLK_P0,
+ 0x570, 2),
+ DEF_MOD("ssi1_sfr", R9A07G044_SSI1_PCLK_SFR, R9A07G044_CLK_P0,
+ 0x570, 3),
+ DEF_MOD("ssi2_pclk", R9A07G044_SSI2_PCLK2, R9A07G044_CLK_P0,
+ 0x570, 4),
+ DEF_MOD("ssi2_sfr", R9A07G044_SSI2_PCLK_SFR, R9A07G044_CLK_P0,
+ 0x570, 5),
+ DEF_MOD("ssi3_pclk", R9A07G044_SSI3_PCLK2, R9A07G044_CLK_P0,
+ 0x570, 6),
+ DEF_MOD("ssi3_sfr", R9A07G044_SSI3_PCLK_SFR, R9A07G044_CLK_P0,
+ 0x570, 7),
+ DEF_MOD("usb0_host", R9A07G044_USB_U2H0_HCLK, R9A07G044_CLK_P1,
+ 0x578, 0),
+ DEF_MOD("usb1_host", R9A07G044_USB_U2H1_HCLK, R9A07G044_CLK_P1,
+ 0x578, 1),
+ DEF_MOD("usb0_func", R9A07G044_USB_U2P_EXR_CPUCLK, R9A07G044_CLK_P1,
+ 0x578, 2),
+ DEF_MOD("usb_pclk", R9A07G044_USB_PCLK, R9A07G044_CLK_P1,
+ 0x578, 3),
+ DEF_COUPLED("eth0_axi", R9A07G044_ETH0_CLK_AXI, R9A07G044_CLK_M0,
+ 0x57c, 0),
+ DEF_COUPLED("eth0_chi", R9A07G044_ETH0_CLK_CHI, R9A07G044_CLK_ZT,
+ 0x57c, 0),
+ DEF_COUPLED("eth1_axi", R9A07G044_ETH1_CLK_AXI, R9A07G044_CLK_M0,
+ 0x57c, 1),
+ DEF_COUPLED("eth1_chi", R9A07G044_ETH1_CLK_CHI, R9A07G044_CLK_ZT,
+ 0x57c, 1),
+ DEF_MOD("i2c0", R9A07G044_I2C0_PCLK, R9A07G044_CLK_P0,
+ 0x580, 0),
+ DEF_MOD("i2c1", R9A07G044_I2C1_PCLK, R9A07G044_CLK_P0,
+ 0x580, 1),
+ DEF_MOD("i2c2", R9A07G044_I2C2_PCLK, R9A07G044_CLK_P0,
+ 0x580, 2),
+ DEF_MOD("i2c3", R9A07G044_I2C3_PCLK, R9A07G044_CLK_P0,
+ 0x580, 3),
+ DEF_MOD("scif0", R9A07G044_SCIF0_CLK_PCK, R9A07G044_CLK_P0,
+ 0x584, 0),
+ DEF_MOD("scif1", R9A07G044_SCIF1_CLK_PCK, R9A07G044_CLK_P0,
+ 0x584, 1),
+ DEF_MOD("scif2", R9A07G044_SCIF2_CLK_PCK, R9A07G044_CLK_P0,
+ 0x584, 2),
+ DEF_MOD("scif3", R9A07G044_SCIF3_CLK_PCK, R9A07G044_CLK_P0,
+ 0x584, 3),
+ DEF_MOD("scif4", R9A07G044_SCIF4_CLK_PCK, R9A07G044_CLK_P0,
+ 0x584, 4),
+ DEF_MOD("sci0", R9A07G044_SCI0_CLKP, R9A07G044_CLK_P0,
+ 0x588, 0),
+ DEF_MOD("sci1", R9A07G044_SCI1_CLKP, R9A07G044_CLK_P0,
+ 0x588, 1),
+ DEF_MOD("rspi0", R9A07G044_RSPI0_CLKB, R9A07G044_CLK_P0,
+ 0x590, 0),
+ DEF_MOD("rspi1", R9A07G044_RSPI1_CLKB, R9A07G044_CLK_P0,
+ 0x590, 1),
+ DEF_MOD("rspi2", R9A07G044_RSPI2_CLKB, R9A07G044_CLK_P0,
+ 0x590, 2),
+ DEF_MOD("canfd", R9A07G044_CANFD_PCLK, R9A07G044_CLK_P0,
+ 0x594, 0),
+ DEF_MOD("gpio", R9A07G044_GPIO_HCLK, R9A07G044_OSCCLK,
+ 0x598, 0),
+ DEF_MOD("adc_adclk", R9A07G044_ADC_ADCLK, R9A07G044_CLK_TSU,
+ 0x5a8, 0),
+ DEF_MOD("adc_pclk", R9A07G044_ADC_PCLK, R9A07G044_CLK_P0,
+ 0x5a8, 1),
+ DEF_MOD("tsu_pclk", R9A07G044_TSU_PCLK, R9A07G044_CLK_TSU,
+ 0x5ac, 0),
+ },
+};
+
+static const struct rzg2l_reset r9a07g044_resets[] = {
+ DEF_RST(R9A07G044_GIC600_GICRESET_N, 0x814, 0),
+ DEF_RST(R9A07G044_GIC600_DBG_GICRESET_N, 0x814, 1),
+ DEF_RST(R9A07G044_IA55_RESETN, 0x818, 0),
+ DEF_RST(R9A07G044_DMAC_ARESETN, 0x82c, 0),
+ DEF_RST(R9A07G044_DMAC_RST_ASYNC, 0x82c, 1),
+ DEF_RST(R9A07G044_OSTM0_PRESETZ, 0x834, 0),
+ DEF_RST(R9A07G044_OSTM1_PRESETZ, 0x834, 1),
+ DEF_RST(R9A07G044_OSTM2_PRESETZ, 0x834, 2),
+ DEF_RST(R9A07G044_MTU_X_PRESET_MTU3, 0x838, 0),
+ DEF_RST(R9A07G044_GPT_RST_C, 0x840, 0),
+ DEF_RST(R9A07G044_POEG_A_RST, 0x844, 0),
+ DEF_RST(R9A07G044_POEG_B_RST, 0x844, 1),
+ DEF_RST(R9A07G044_POEG_C_RST, 0x844, 2),
+ DEF_RST(R9A07G044_POEG_D_RST, 0x844, 3),
+ DEF_RST(R9A07G044_WDT0_PRESETN, 0x848, 0),
+ DEF_RST(R9A07G044_WDT1_PRESETN, 0x848, 1),
+ DEF_RST(R9A07G044_SPI_RST, 0x850, 0),
+ DEF_RST(R9A07G044_SDHI0_IXRST, 0x854, 0),
+ DEF_RST(R9A07G044_SDHI1_IXRST, 0x854, 1),
+ DEF_RST(R9A07G044_GPU_RESETN, 0x858, 0),
+ DEF_RST(R9A07G044_GPU_AXI_RESETN, 0x858, 1),
+ DEF_RST(R9A07G044_GPU_ACE_RESETN, 0x858, 2),
+ DEF_RST(R9A07G044_CRU_CMN_RSTB, 0x864, 0),
+ DEF_RST(R9A07G044_CRU_PRESETN, 0x864, 1),
+ DEF_RST(R9A07G044_CRU_ARESETN, 0x864, 2),
+ DEF_RST(R9A07G044_MIPI_DSI_CMN_RSTB, 0x868, 0),
+ DEF_RST(R9A07G044_MIPI_DSI_ARESET_N, 0x868, 1),
+ DEF_RST(R9A07G044_MIPI_DSI_PRESET_N, 0x868, 2),
+ DEF_RST(R9A07G044_LCDC_RESET_N, 0x86c, 0),
+ DEF_RST(R9A07G044_SSI0_RST_M2_REG, 0x870, 0),
+ DEF_RST(R9A07G044_SSI1_RST_M2_REG, 0x870, 1),
+ DEF_RST(R9A07G044_SSI2_RST_M2_REG, 0x870, 2),
+ DEF_RST(R9A07G044_SSI3_RST_M2_REG, 0x870, 3),
+ DEF_RST(R9A07G044_USB_U2H0_HRESETN, 0x878, 0),
+ DEF_RST(R9A07G044_USB_U2H1_HRESETN, 0x878, 1),
+ DEF_RST(R9A07G044_USB_U2P_EXL_SYSRST, 0x878, 2),
+ DEF_RST(R9A07G044_USB_PRESETN, 0x878, 3),
+ DEF_RST(R9A07G044_ETH0_RST_HW_N, 0x87c, 0),
+ DEF_RST(R9A07G044_ETH1_RST_HW_N, 0x87c, 1),
+ DEF_RST(R9A07G044_I2C0_MRST, 0x880, 0),
+ DEF_RST(R9A07G044_I2C1_MRST, 0x880, 1),
+ DEF_RST(R9A07G044_I2C2_MRST, 0x880, 2),
+ DEF_RST(R9A07G044_I2C3_MRST, 0x880, 3),
+ DEF_RST(R9A07G044_SCIF0_RST_SYSTEM_N, 0x884, 0),
+ DEF_RST(R9A07G044_SCIF1_RST_SYSTEM_N, 0x884, 1),
+ DEF_RST(R9A07G044_SCIF2_RST_SYSTEM_N, 0x884, 2),
+ DEF_RST(R9A07G044_SCIF3_RST_SYSTEM_N, 0x884, 3),
+ DEF_RST(R9A07G044_SCIF4_RST_SYSTEM_N, 0x884, 4),
+ DEF_RST(R9A07G044_SCI0_RST, 0x888, 0),
+ DEF_RST(R9A07G044_SCI1_RST, 0x888, 1),
+ DEF_RST(R9A07G044_RSPI0_RST, 0x890, 0),
+ DEF_RST(R9A07G044_RSPI1_RST, 0x890, 1),
+ DEF_RST(R9A07G044_RSPI2_RST, 0x890, 2),
+ DEF_RST(R9A07G044_CANFD_RSTP_N, 0x894, 0),
+ DEF_RST(R9A07G044_CANFD_RSTC_N, 0x894, 1),
+ DEF_RST(R9A07G044_GPIO_RSTN, 0x898, 0),
+ DEF_RST(R9A07G044_GPIO_PORT_RESETN, 0x898, 1),
+ DEF_RST(R9A07G044_GPIO_SPARE_RESETN, 0x898, 2),
+ DEF_RST(R9A07G044_ADC_PRESETN, 0x8a8, 0),
+ DEF_RST(R9A07G044_ADC_ADRST_N, 0x8a8, 1),
+ DEF_RST(R9A07G044_TSU_PRESETN, 0x8ac, 0),
+};
+
+const struct rzg2l_cpg_info r9a07g044_cpg_info = {
+ /* Core Clocks */
+ .core_clks = core_clks.common,
+ .num_core_clks = ARRAY_SIZE(core_clks.common),
+
+ /* Module Clocks */
+ .mod_clks = mod_clks.common,
+ .num_mod_clks = ARRAY_SIZE(mod_clks.common),
+ .num_hw_mod_clks = R9A07G044_TSU_PCLK + 1,
+
+ /* Resets */
+ .resets = r9a07g044_resets,
+ .num_resets = R9A07G044_TSU_PRESETN + 1, /* Last reset ID + 1 */
+
+ .has_clk_mon_regs = true,
+};
+
+static const struct udevice_id r9a07g044_cpg_ids[] = {
+ {
+ .compatible = "renesas,r9a07g044-cpg",
+ .data = (unsigned long)&r9a07g044_cpg_info,
+ },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(r9a07g044_cpg) = {
+ .name = "r9a07g044-cpg",
+ .id = UCLASS_NOP,
+ .of_match = r9a07g044_cpg_ids,
+ .bind = rzg2l_cpg_bind,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c
new file mode 100644
index 00000000000..e54508c35ce
--- /dev/null
+++ b/drivers/clk/renesas/rzg2l-cpg.c
@@ -0,0 +1,504 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/G2L Clock Pulse Generator
+ *
+ * Copyright (C) 2021-2023 Renesas Electronics Corp.
+ *
+ * Based on renesas-cpg-mssr.c
+ *
+ * Copyright (C) 2015 Glider bvba
+ * Copyright (C) 2013 Ideas On Board SPRL
+ * Copyright (C) 2015 Renesas Electronics Corp.
+ */
+
+#include <asm/io.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <dm/lists.h>
+#include <dt-bindings/clock/renesas-cpg-mssr.h>
+#include <linux/clk-provider.h>
+#include <linux/iopoll.h>
+#include <reset-uclass.h>
+#include <reset.h>
+
+#include "rzg2l-cpg.h"
+
+#define CLK_MON_R(reg) (0x180 + (reg))
+
+static ulong rzg2l_cpg_clk_get_rate_by_id(struct udevice *dev, unsigned int id);
+static ulong rzg2l_cpg_clk_get_rate_by_name(struct udevice *dev, const char *name);
+
+struct rzg2l_cpg_data {
+ void __iomem *base;
+ struct rzg2l_cpg_info *info;
+};
+
+/*
+ * The top 16 bits of the clock ID are used to identify if it is a core clock or
+ * a module clock.
+ */
+#define CPG_CLK_TYPE_SHIFT 16
+#define CPG_CLK_ID_MASK 0xffff
+#define CPG_CLK_ID(x) ((x) & CPG_CLK_ID_MASK)
+#define CPG_CLK_PACK(type, id) (((type) << CPG_CLK_TYPE_SHIFT) | CPG_CLK_ID(id))
+
+static inline bool is_mod_clk(unsigned int id)
+{
+ return (id >> CPG_CLK_TYPE_SHIFT) == CPG_MOD;
+}
+
+static int rzg2l_cpg_clk_set(struct clk *clk, bool enable)
+{
+ struct rzg2l_cpg_data *data =
+ (struct rzg2l_cpg_data *)dev_get_driver_data(clk->dev);
+ const unsigned int cpg_clk_id = CPG_CLK_ID(clk->id);
+ const struct rzg2l_mod_clk *mod_clk = NULL;
+ u32 value;
+ unsigned int i;
+
+ dev_dbg(clk->dev, "%s %s clock %u\n", enable ? "enable" : "disable",
+ is_mod_clk(clk->id) ? "module" : "core", cpg_clk_id);
+ if (!is_mod_clk(clk->id)) {
+ dev_err(clk->dev, "ID %lu is not a module clock\n", clk->id);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < data->info->num_mod_clks; i++) {
+ if (data->info->mod_clks[i].id == cpg_clk_id) {
+ mod_clk = &data->info->mod_clks[i];
+ break;
+ }
+ }
+
+ if (!mod_clk) {
+ dev_err(clk->dev, "Module clock %u not found\n", cpg_clk_id);
+ return -ENODEV;
+ }
+
+ value = BIT(mod_clk->bit) << 16;
+ if (enable)
+ value |= BIT(mod_clk->bit);
+ writel(value, data->base + mod_clk->off);
+
+ if (enable && readl_poll_timeout(data->base + CLK_MON_R(mod_clk->off),
+ value, (value & BIT(mod_clk->bit)),
+ 10)) {
+ dev_err(clk->dev, "Timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int rzg2l_cpg_clk_enable(struct clk *clk)
+{
+ return rzg2l_cpg_clk_set(clk, true);
+}
+
+static int rzg2l_cpg_clk_disable(struct clk *clk)
+{
+ return rzg2l_cpg_clk_set(clk, false);
+}
+
+static int rzg2l_cpg_clk_of_xlate(struct clk *clk,
+ struct ofnode_phandle_args *args)
+{
+ struct rzg2l_cpg_data *data =
+ (struct rzg2l_cpg_data *)dev_get_driver_data(clk->dev);
+ u32 cpg_clk_type, cpg_clk_id;
+ bool found = false;
+ unsigned int i;
+
+ if (args->args_count != 2) {
+ dev_dbg(clk->dev, "Invalid args_count: %d\n", args->args_count);
+ return -EINVAL;
+ }
+
+ cpg_clk_type = args->args[0];
+ cpg_clk_id = args->args[1];
+
+ switch (cpg_clk_type) {
+ case CPG_CORE:
+ for (i = 0; i < data->info->num_core_clks; i++) {
+ if (data->info->core_clks[i].id == cpg_clk_id) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ dev_dbg(clk->dev,
+ "Invalid second argument %u: Must be a valid core clock ID\n",
+ cpg_clk_id);
+ return -EINVAL;
+ }
+ break;
+ case CPG_MOD:
+ for (i = 0; i < data->info->num_mod_clks; i++) {
+ if (data->info->mod_clks[i].id == cpg_clk_id) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ dev_dbg(clk->dev,
+ "Invalid second argument %u: Must be a valid module clock ID\n",
+ cpg_clk_id);
+ return -EINVAL;
+ }
+ break;
+ default:
+ dev_dbg(clk->dev,
+ "Invalid first argument %u: Must be CPG_CORE or CPG_MOD\n",
+ cpg_clk_type);
+ return -EINVAL;
+ }
+
+ clk->id = CPG_CLK_PACK(cpg_clk_type, cpg_clk_id);
+
+ return 0;
+}
+
+static ulong rzg2l_sdhi_clk_get_rate(struct udevice *dev, const struct cpg_core_clk *cc)
+{
+ struct rzg2l_cpg_data *data =
+ (struct rzg2l_cpg_data *)dev_get_driver_data(dev);
+ const ulong offset = CPG_CONF_OFFSET(cc->conf);
+ const int shift = CPG_CONF_BITPOS(cc->conf);
+ const u32 mask = CPG_CONF_BITMASK(cc->conf);
+ unsigned int sel;
+
+ sel = (readl(data->base + offset) >> shift) & mask;
+
+ if (!sel || sel > cc->num_parents) {
+ dev_err(dev, "Invalid SEL_SDHI%d_SET value %u\n", shift / 4, sel);
+ return -EIO;
+ }
+ return rzg2l_cpg_clk_get_rate_by_name(dev, cc->parent_names[sel - 1]);
+}
+
+static ulong rzg2l_div_clk_get_rate(struct udevice *dev, const struct cpg_core_clk *cc)
+{
+ struct rzg2l_cpg_data *data =
+ (struct rzg2l_cpg_data *)dev_get_driver_data(dev);
+ const ulong offset = CPG_CONF_OFFSET(cc->conf);
+ const int shift = CPG_CONF_BITPOS(cc->conf);
+ const u32 mask = CPG_CONF_BITMASK(cc->conf);
+ unsigned int sel, i;
+
+ sel = (readl(data->base + offset) >> shift) & mask;
+
+ for (i = 0; cc->dtable[i].div; i++) {
+ if (cc->dtable[i].val == sel)
+ return rzg2l_cpg_clk_get_rate_by_id(dev, cc->parent) / cc->dtable[i].div;
+ }
+ dev_err(dev, "Invalid selector value %u for clock %s\n", sel, cc->name);
+ return -EINVAL;
+}
+
+static ulong rzg2l_core_clk_get_rate(struct udevice *dev, const struct cpg_core_clk *cc)
+{
+ switch (cc->type) {
+ case CLK_TYPE_FF:
+ const ulong parent_rate = rzg2l_cpg_clk_get_rate_by_id(dev, cc->parent);
+ return parent_rate * cc->mult / cc->div;
+ case CLK_TYPE_IN:
+ struct clk clk_in;
+ clk_get_by_name(dev, cc->name, &clk_in);
+ return clk_get_rate(&clk_in);
+ case CLK_TYPE_SD_MUX:
+ return rzg2l_sdhi_clk_get_rate(dev, cc);
+ case CLK_TYPE_DIV:
+ return rzg2l_div_clk_get_rate(dev, cc);
+ default:
+ dev_err(dev, "get_rate needed for clock %u, type %d\n", cc->id, cc->type);
+ return -ENOSYS;
+ }
+}
+
+static ulong rzg2l_cpg_clk_get_rate_by_id(struct udevice *dev, unsigned int id)
+{
+ struct rzg2l_cpg_data *data =
+ (struct rzg2l_cpg_data *)dev_get_driver_data(dev);
+ const unsigned int cpg_clk_id = CPG_CLK_ID(id);
+ unsigned int i;
+
+ if (is_mod_clk(id)) {
+ for (i = 0; i < data->info->num_mod_clks; i++) {
+ if (data->info->mod_clks[i].id == cpg_clk_id)
+ return rzg2l_cpg_clk_get_rate_by_id(dev,
+ data->info->mod_clks[i].parent);
+ }
+
+ dev_err(dev, "Module clock ID %u not found\n", cpg_clk_id);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < data->info->num_core_clks; i++) {
+ if (data->info->core_clks[i].id == cpg_clk_id)
+ return rzg2l_core_clk_get_rate(dev, &data->info->core_clks[i]);
+ }
+
+ dev_err(dev, "Core clock ID %u not found\n", cpg_clk_id);
+ return -ENODEV;
+}
+
+static ulong rzg2l_cpg_clk_get_rate_by_name(struct udevice *dev, const char *name)
+{
+ struct rzg2l_cpg_data *data =
+ (struct rzg2l_cpg_data *)dev_get_driver_data(dev);
+ unsigned int i;
+
+ for (i = 0; i < data->info->num_mod_clks; i++) {
+ if (!strcmp(name, data->info->mod_clks[i].name))
+ return rzg2l_cpg_clk_get_rate_by_id(dev, data->info->mod_clks[i].parent);
+ }
+ for (i = 0; i < data->info->num_core_clks; i++) {
+ if (!strcmp(name, data->info->core_clks[i].name))
+ return rzg2l_core_clk_get_rate(dev, &data->info->core_clks[i]);
+ }
+
+ dev_err(dev, "Clock name %s not found\n", name);
+ return -EINVAL;
+}
+
+static ulong rzg2l_cpg_clk_get_rate(struct clk *clk)
+{
+ return rzg2l_cpg_clk_get_rate_by_id(clk->dev, clk->id);
+}
+
+static ulong rzg2l_sdhi_clk_set_rate(struct udevice *dev, const struct cpg_core_clk *cc, ulong rate)
+{
+ struct rzg2l_cpg_data *data =
+ (struct rzg2l_cpg_data *)dev_get_driver_data(dev);
+ const ulong offset = CPG_CONF_OFFSET(cc->conf);
+ const int shift = CPG_CONF_BITPOS(cc->conf);
+ int channel, new_sel, prev_sel;
+ ulong target_rate;
+ unsigned int i;
+ u32 value;
+
+ prev_sel = (readl(data->base + offset) >> shift) & 0x3;
+ channel = shift / 4;
+
+ /*
+ * Round the requested rate down, unless it is below the minimum
+ * supported rate. Assume that the parent clock names are listed in
+ * order of descending rate.
+ */
+ for (i = 0; i < cc->num_parents; i++) {
+ target_rate = rzg2l_cpg_clk_get_rate_by_name(dev, cc->parent_names[i]);
+ if (rate >= target_rate) {
+ new_sel = i + 1;
+ break;
+ }
+ }
+ if (!new_sel)
+ new_sel = cc->num_parents - 1;
+
+ if (new_sel == prev_sel)
+ return target_rate;
+ dev_dbg(dev, "sdhi set_rate rate=%lu target_rate=%lu sel=%d\n",
+ rate, target_rate, new_sel);
+
+ /*
+ * As per the HW manual, we should not directly switch from 533 MHz to
+ * 400 MHz and vice versa. To change the setting from 2’b01 (533 MHz)
+ * to 2’b10 (400 MHz) or vice versa, Switch to 2’b11 (266 MHz) first,
+ * and then switch to the target setting (2’b01 (533 MHz) or 2’b10
+ * (400 MHz)).
+ */
+ if (new_sel != SEL_SDHI_266MHz && prev_sel != SEL_SDHI_266MHz) {
+ u32 waitbit;
+ int ret;
+
+ dev_dbg(dev, "sdhi set_rate via 266MHz\n");
+ value = (SEL_SDHI_WRITE_ENABLE | SEL_SDHI_266MHz) << shift;
+ writel(value, data->base + offset);
+
+ /* Wait for the switch to complete. */
+ waitbit = channel ? CPG_CLKSTATUS_SELSDHI1_STS : CPG_CLKSTATUS_SELSDHI0_STS;
+ ret = readl_poll_timeout(data->base + CPG_CLKSTATUS, value,
+ !(value & waitbit),
+ CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US);
+ if (ret) {
+ dev_err(dev, "Failed to switch SDHI%d clock source\n", channel);
+ return -EIO;
+ }
+ }
+
+ value = (SEL_SDHI_WRITE_ENABLE | new_sel) << shift;
+ writel(value, data->base + offset);
+
+ return target_rate;
+}
+
+static ulong rzg2l_core_clk_set_rate(struct udevice *dev, const struct cpg_core_clk *cc, ulong rate)
+{
+ if (cc->type == CLK_TYPE_SD_MUX)
+ return rzg2l_sdhi_clk_set_rate(dev, cc, rate);
+
+ /*
+ * The sdhi driver calls clk_set_rate for SD0_DIV4 and SD1_DIV4, even
+ * though they're in a fixed relationship with SD0 and SD1 respectively.
+ * To allow the driver to proceed, simply return the current rates
+ * without making any change.
+ */
+ if (cc->id == CLK_SD0_DIV4 || cc->id == CLK_SD1_DIV4)
+ return rzg2l_core_clk_get_rate(dev, cc);
+
+ dev_err(dev, "set_rate needed for clock %u, type %d\n", cc->id, cc->type);
+ return -ENOSYS;
+}
+
+static ulong rzg2l_cpg_clk_set_rate_by_id(struct udevice *dev, unsigned int id, ulong rate)
+{
+ struct rzg2l_cpg_data *data =
+ (struct rzg2l_cpg_data *)dev_get_driver_data(dev);
+ const unsigned int cpg_clk_id = CPG_CLK_ID(id);
+ unsigned int i;
+
+ if (is_mod_clk(id)) {
+ for (i = 0; i < data->info->num_mod_clks; i++) {
+ if (data->info->mod_clks[i].id == cpg_clk_id)
+ return rzg2l_cpg_clk_set_rate_by_id(dev,
+ data->info->mod_clks[i].parent,
+ rate);
+ }
+
+ dev_err(dev, "Module clock ID %u not found\n", cpg_clk_id);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < data->info->num_core_clks; i++) {
+ if (data->info->core_clks[i].id == cpg_clk_id)
+ return rzg2l_core_clk_set_rate(dev, &data->info->core_clks[i], rate);
+ }
+
+ dev_err(dev, "Core clock ID %u not found\n", cpg_clk_id);
+ return -ENODEV;
+}
+
+static ulong rzg2l_cpg_clk_set_rate(struct clk *clk, ulong rate)
+{
+ return rzg2l_cpg_clk_set_rate_by_id(clk->dev, clk->id, rate);
+}
+
+static const struct clk_ops rzg2l_cpg_clk_ops = {
+ .enable = rzg2l_cpg_clk_enable,
+ .disable = rzg2l_cpg_clk_disable,
+ .of_xlate = rzg2l_cpg_clk_of_xlate,
+ .get_rate = rzg2l_cpg_clk_get_rate,
+ .set_rate = rzg2l_cpg_clk_set_rate,
+};
+
+U_BOOT_DRIVER(rzg2l_cpg_clk) = {
+ .name = "rzg2l-cpg-clk",
+ .id = UCLASS_CLK,
+ .ops = &rzg2l_cpg_clk_ops,
+ .flags = DM_FLAG_VITAL,
+};
+
+static int rzg2l_cpg_rst_set(struct reset_ctl *reset_ctl, bool asserted)
+{
+ struct rzg2l_cpg_data *data =
+ (struct rzg2l_cpg_data *)dev_get_driver_data(reset_ctl->dev);
+ const struct rzg2l_reset *rst;
+ u32 value;
+
+ dev_dbg(reset_ctl->dev, "%s %lu\n", asserted ? "assert" : "deassert", reset_ctl->id);
+ if (reset_ctl->id >= data->info->num_resets) {
+ dev_err(reset_ctl->dev, "Invalid reset id %lu\n", reset_ctl->id);
+ return -EINVAL;
+ }
+ rst = &data->info->resets[reset_ctl->id];
+
+ value = BIT(rst->bit) << 16;
+ if (!asserted)
+ value |= BIT(rst->bit);
+ writel(value, data->base + rst->off);
+
+ return 0;
+}
+
+static int rzg2l_cpg_rst_assert(struct reset_ctl *reset_ctl)
+{
+ return rzg2l_cpg_rst_set(reset_ctl, true);
+}
+
+static int rzg2l_cpg_rst_deassert(struct reset_ctl *reset_ctl)
+{
+ return rzg2l_cpg_rst_set(reset_ctl, false);
+}
+
+static int rzg2l_cpg_rst_of_xlate(struct reset_ctl *reset_ctl,
+ struct ofnode_phandle_args *args)
+{
+ struct rzg2l_cpg_data *data =
+ (struct rzg2l_cpg_data *)dev_get_driver_data(reset_ctl->dev);
+
+ if (args->args[0] >= data->info->num_resets)
+ return -EINVAL;
+
+ reset_ctl->id = args->args[0];
+ return 0;
+}
+
+static const struct reset_ops rzg2l_cpg_rst_ops = {
+ .rst_assert = rzg2l_cpg_rst_assert,
+ .rst_deassert = rzg2l_cpg_rst_deassert,
+ .of_xlate = rzg2l_cpg_rst_of_xlate,
+};
+
+U_BOOT_DRIVER(rzg2l_cpg_rst) = {
+ .name = "rzg2l-cpg-rst",
+ .id = UCLASS_RESET,
+ .ops = &rzg2l_cpg_rst_ops,
+ .flags = DM_FLAG_VITAL,
+};
+
+int rzg2l_cpg_bind(struct udevice *parent)
+{
+ struct udevice *cdev, *rdev;
+ struct rzg2l_cpg_data *data;
+ struct driver *drv;
+ int ret;
+
+ data = devm_kmalloc(parent, sizeof(*data), 0);
+ if (!data)
+ return -ENOMEM;
+
+ data->base = dev_read_addr_ptr(parent);
+ if (!data->base)
+ return -EINVAL;
+
+ data->info = (struct rzg2l_cpg_info *)dev_get_driver_data(parent);
+ if (!data->info)
+ return -EINVAL;
+
+ drv = lists_driver_lookup_name("rzg2l-cpg-clk");
+ if (!drv)
+ return -ENOENT;
+
+ ret = device_bind_with_driver_data(parent, drv, parent->name,
+ (ulong)data, dev_ofnode(parent),
+ &cdev);
+ if (ret)
+ return ret;
+
+ drv = lists_driver_lookup_name("rzg2l-cpg-rst");
+ if (!drv) {
+ device_unbind(cdev);
+ return -ENOENT;
+ }
+
+ ret = device_bind_with_driver_data(parent, drv, parent->name,
+ (ulong)data, dev_ofnode(parent),
+ &rdev);
+ if (ret)
+ device_unbind(cdev);
+
+ return ret;
+}
diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h
new file mode 100644
index 00000000000..7cb6c481a62
--- /dev/null
+++ b/drivers/clk/renesas/rzg2l-cpg.h
@@ -0,0 +1,319 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * RZ/G2L Clock Pulse Generator
+ *
+ * Copyright (C) 2021-2023 Renesas Electronics Corp.
+ *
+ */
+
+#ifndef __RENESAS_RZG2L_CPG_H__
+#define __RENESAS_RZG2L_CPG_H__
+
+#define CPG_SIPLL5_STBY 0x140
+#define CPG_SIPLL5_CLK1 0x144
+#define CPG_SIPLL5_CLK3 0x14C
+#define CPG_SIPLL5_CLK4 0x150
+#define CPG_SIPLL5_CLK5 0x154
+#define CPG_SIPLL5_MON 0x15C
+#define CPG_PL1_DDIV 0x200
+#define CPG_PL2_DDIV 0x204
+#define CPG_PL3A_DDIV 0x208
+#define CPG_PL6_DDIV 0x210
+#define CPG_PL2SDHI_DSEL 0x218
+#define CPG_CLKSTATUS 0x280
+#define CPG_PL3_SSEL 0x408
+#define CPG_PL6_SSEL 0x414
+#define CPG_PL6_ETH_SSEL 0x418
+#define CPG_PL5_SDIV 0x420
+#define CPG_RST_MON 0x680
+#define CPG_OTHERFUNC1_REG 0xBE8
+
+#define CPG_SIPLL5_STBY_RESETB BIT(0)
+#define CPG_SIPLL5_STBY_RESETB_WEN BIT(16)
+#define CPG_SIPLL5_STBY_SSCG_EN_WEN BIT(18)
+#define CPG_SIPLL5_STBY_DOWNSPREAD_WEN BIT(20)
+#define CPG_SIPLL5_CLK4_RESV_LSB 0xFF
+#define CPG_SIPLL5_MON_PLL5_LOCK BIT(4)
+
+#define CPG_OTHERFUNC1_REG_RES0_ON_WEN BIT(16)
+
+#define CPG_PL5_SDIV_DIV_DSI_A_WEN BIT(16)
+#define CPG_PL5_SDIV_DIV_DSI_B_WEN BIT(24)
+
+#define CPG_CLKSTATUS_SELSDHI0_STS BIT(28)
+#define CPG_CLKSTATUS_SELSDHI1_STS BIT(29)
+
+#define CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US 20000
+
+/* n = 0/1/2 for PLL1/4/6 */
+#define CPG_SAMPLL_CLK1(n) (0x04 + (16 * (n)))
+#define CPG_SAMPLL_CLK2(n) (0x08 + (16 * (n)))
+
+#define PLL146_CONF(n) (CPG_SAMPLL_CLK1(n) << 22 | CPG_SAMPLL_CLK2(n) << 12)
+
+#define DDIV_PACK(offset, bitpos, size) \
+ (((offset) << 20) | ((bitpos) << 12) | ((size) << 8))
+#define DIVPL1A DDIV_PACK(CPG_PL1_DDIV, 0, 2)
+#define DIVPL2A DDIV_PACK(CPG_PL2_DDIV, 0, 3)
+#define DIVDSILPCLK DDIV_PACK(CPG_PL2_DDIV, 12, 2)
+#define DIVPL3A DDIV_PACK(CPG_PL3A_DDIV, 0, 3)
+#define DIVPL3B DDIV_PACK(CPG_PL3A_DDIV, 4, 3)
+#define DIVPL3C DDIV_PACK(CPG_PL3A_DDIV, 8, 3)
+#define DIVGPU DDIV_PACK(CPG_PL6_DDIV, 0, 2)
+
+#define SEL_PLL_PACK(offset, bitpos, size) \
+ (((offset) << 20) | ((bitpos) << 12) | ((size) << 8))
+
+#define SEL_PLL3_3 SEL_PLL_PACK(CPG_PL3_SSEL, 8, 1)
+#define SEL_PLL5_4 SEL_PLL_PACK(CPG_OTHERFUNC1_REG, 0, 1)
+#define SEL_PLL6_2 SEL_PLL_PACK(CPG_PL6_ETH_SSEL, 0, 1)
+#define SEL_GPU2 SEL_PLL_PACK(CPG_PL6_SSEL, 12, 1)
+
+#define SEL_SDHI0 DDIV_PACK(CPG_PL2SDHI_DSEL, 0, 2)
+#define SEL_SDHI1 DDIV_PACK(CPG_PL2SDHI_DSEL, 4, 2)
+
+#define SEL_SDHI_533MHz 1
+#define SEL_SDHI_400MHz 2
+#define SEL_SDHI_266MHz 3
+#define SEL_SDHI_WRITE_ENABLE 0x10000
+
+/* Unpack CPG conf value create by DDIV_PACK() or SEL_PLL_PACK(). */
+#define CPG_CONF_OFFSET(x) ((x) >> 20)
+#define CPG_CONF_BITPOS(x) (((x) >> 12) & 0xff)
+#define CPG_CONF_SIZE(x) (((x) >> 8) & 0xf)
+#define CPG_CONF_BITMASK(x) GENMASK(CPG_CONF_SIZE(x) - 1, 0)
+
+#define EXTAL_FREQ_IN_MEGA_HZ 24
+
+/**
+ * Definitions of CPG Core Clocks
+ *
+ * These include:
+ * - Clock outputs exported to DT
+ * - External input clocks
+ * - Internal CPG clocks
+ */
+struct cpg_core_clk {
+ const char *name;
+ unsigned int id;
+ unsigned int parent;
+ unsigned int div;
+ unsigned int mult;
+ unsigned int type;
+ unsigned int conf;
+ const struct clk_div_table *dtable;
+ const char * const *parent_names;
+ int flag;
+ int mux_flags;
+ int num_parents;
+};
+
+enum clk_types {
+ /* Generic */
+ CLK_TYPE_IN, /* External Clock Input */
+ CLK_TYPE_FF, /* Fixed Factor Clock */
+ CLK_TYPE_SAM_PLL,
+
+ /* Clock with divider */
+ CLK_TYPE_DIV,
+
+ /* Clock with clock source selector */
+ CLK_TYPE_MUX,
+
+ /* Clock with SD clock source selector */
+ CLK_TYPE_SD_MUX,
+
+ /* Clock for SIPLL5 */
+ CLK_TYPE_SIPLL5,
+
+ /* Clock for PLL5_4 clock source selector */
+ CLK_TYPE_PLL5_4_MUX,
+
+ /* Clock for DSI divider */
+ CLK_TYPE_DSI_DIV,
+
+};
+
+#define DEF_TYPE(_name, _id, _type...) \
+ { .name = _name, .id = _id, .type = _type }
+#define DEF_BASE(_name, _id, _type, _parent...) \
+ DEF_TYPE(_name, _id, _type, .parent = _parent)
+#define DEF_SAMPLL(_name, _id, _parent, _conf) \
+ DEF_TYPE(_name, _id, CLK_TYPE_SAM_PLL, .parent = _parent, .conf = _conf)
+#define DEF_INPUT(_name, _id) \
+ DEF_TYPE(_name, _id, CLK_TYPE_IN)
+#define DEF_FIXED(_name, _id, _parent, _mult, _div) \
+ DEF_BASE(_name, _id, CLK_TYPE_FF, _parent, .div = _div, .mult = _mult)
+#define DEF_DIV(_name, _id, _parent, _conf, _dtable) \
+ DEF_TYPE(_name, _id, CLK_TYPE_DIV, .conf = _conf, \
+ .parent = _parent, .dtable = _dtable, \
+ .flag = CLK_DIVIDER_HIWORD_MASK)
+#define DEF_DIV_RO(_name, _id, _parent, _conf, _dtable) \
+ DEF_TYPE(_name, _id, CLK_TYPE_DIV, .conf = _conf, \
+ .parent = _parent, .dtable = _dtable, \
+ .flag = CLK_DIVIDER_READ_ONLY)
+#define DEF_MUX(_name, _id, _conf, _parent_names) \
+ DEF_TYPE(_name, _id, CLK_TYPE_MUX, .conf = _conf, \
+ .parent_names = _parent_names, \
+ .num_parents = ARRAY_SIZE(_parent_names), \
+ .mux_flags = CLK_MUX_HIWORD_MASK)
+#define DEF_MUX_RO(_name, _id, _conf, _parent_names) \
+ DEF_TYPE(_name, _id, CLK_TYPE_MUX, .conf = _conf, \
+ .parent_names = _parent_names, \
+ .num_parents = ARRAY_SIZE(_parent_names), \
+ .mux_flags = CLK_MUX_READ_ONLY)
+#define DEF_SD_MUX(_name, _id, _conf, _parent_names) \
+ DEF_TYPE(_name, _id, CLK_TYPE_SD_MUX, .conf = _conf, \
+ .parent_names = _parent_names, \
+ .num_parents = ARRAY_SIZE(_parent_names))
+#define DEF_PLL5_FOUTPOSTDIV(_name, _id, _parent) \
+ DEF_TYPE(_name, _id, CLK_TYPE_SIPLL5, .parent = _parent)
+#define DEF_PLL5_4_MUX(_name, _id, _conf, _parent_names) \
+ DEF_TYPE(_name, _id, CLK_TYPE_PLL5_4_MUX, .conf = _conf, \
+ .parent_names = _parent_names, \
+ .num_parents = ARRAY_SIZE(_parent_names))
+#define DEF_DSI_DIV(_name, _id, _parent, _flag) \
+ DEF_TYPE(_name, _id, CLK_TYPE_DSI_DIV, .parent = _parent, .flag = _flag)
+
+/**
+ * struct rzg2l_mod_clk - Module Clocks definitions
+ *
+ * @name: handle between common and hardware-specific interfaces
+ * @id: clock index in array containing all Core and Module Clocks
+ * @parent: id of parent clock
+ * @off: register offset
+ * @bit: ON/MON bit
+ * @is_coupled: flag to indicate coupled clock
+ */
+struct rzg2l_mod_clk {
+ const char *name;
+ unsigned int id;
+ unsigned int parent;
+ u16 off;
+ u8 bit;
+ bool is_coupled;
+};
+
+#define DEF_MOD_BASE(_name, _id, _parent, _off, _bit, _is_coupled) \
+ { \
+ .name = (_name), \
+ .id = (_id), \
+ .parent = (_parent), \
+ .off = (_off), \
+ .bit = (_bit), \
+ .is_coupled = (_is_coupled), \
+ }
+
+#define DEF_MOD(_name, _id, _parent, _off, _bit) \
+ DEF_MOD_BASE(_name, _id, _parent, _off, _bit, false)
+
+#define DEF_COUPLED(_name, _id, _parent, _off, _bit) \
+ DEF_MOD_BASE(_name, _id, _parent, _off, _bit, true)
+
+/**
+ * struct rzg2l_reset - Reset definitions
+ *
+ * @off: register offset
+ * @bit: reset bit
+ * @monbit: monitor bit in CPG_RST_MON register, -1 if none
+ */
+struct rzg2l_reset {
+ u16 off;
+ u8 bit;
+ s8 monbit;
+};
+
+#define DEF_RST_MON(_id, _off, _bit, _monbit) \
+ [_id] = { \
+ .off = (_off), \
+ .bit = (_bit), \
+ .monbit = (_monbit) \
+ }
+#define DEF_RST(_id, _off, _bit) \
+ DEF_RST_MON(_id, _off, _bit, -1)
+
+/**
+ * struct rzg2l_cpg_info - SoC-specific CPG Description
+ *
+ * @core_clks: Array of Core Clock definitions
+ * @num_core_clks: Number of entries in core_clks[]
+ *
+ * @mod_clks: Array of Module Clock definitions
+ * @num_mod_clks: Number of entries in mod_clks[]
+ * @num_hw_mod_clks: Number of Module Clocks supported by the hardware
+ *
+ * @resets: Array of Module Reset definitions
+ * @num_resets: Number of entries in resets[]
+ *
+ * @has_clk_mon_regs: Flag indicating whether the SoC has CLK_MON registers
+ */
+struct rzg2l_cpg_info {
+ /* Core Clocks */
+ const struct cpg_core_clk *core_clks;
+ unsigned int num_core_clks;
+
+ /* Module Clocks */
+ const struct rzg2l_mod_clk *mod_clks;
+ unsigned int num_mod_clks;
+ unsigned int num_hw_mod_clks;
+
+ /* Resets */
+ const struct rzg2l_reset *resets;
+ unsigned int num_resets;
+
+ bool has_clk_mon_regs;
+};
+
+extern const struct rzg2l_cpg_info r9a07g044_cpg_info;
+
+int rzg2l_cpg_bind(struct udevice *parent);
+
+/*
+ * Clock IDs start at an offset to avoid overlapping with core & module clock
+ * IDs defined in the dt-bindings headers.
+ */
+enum clk_ids {
+ /* External Input Clocks */
+ CLK_EXTAL = 0x100,
+
+ /* Internal Core Clocks */
+ CLK_OSC_DIV1000 = 0x200,
+ CLK_PLL1,
+ CLK_PLL2,
+ CLK_PLL2_DIV2,
+ CLK_PLL2_DIV2_8,
+ CLK_PLL2_DIV2_10,
+ CLK_PLL3,
+ CLK_PLL3_400,
+ CLK_PLL3_533,
+ CLK_M2_DIV2,
+ CLK_PLL3_DIV2,
+ CLK_PLL3_DIV2_2,
+ CLK_PLL3_DIV2_4,
+ CLK_PLL3_DIV2_4_2,
+ CLK_SEL_PLL3_3,
+ CLK_DIV_PLL3_C,
+ CLK_PLL4,
+ CLK_PLL5,
+ CLK_PLL5_FOUTPOSTDIV,
+ CLK_PLL5_FOUT1PH0,
+ CLK_PLL5_FOUT3,
+ CLK_PLL5_250,
+ CLK_PLL6,
+ CLK_PLL6_250,
+ CLK_P1_DIV2,
+ CLK_PLL2_800,
+ CLK_PLL2_SDHI_533,
+ CLK_PLL2_SDHI_400,
+ CLK_PLL2_SDHI_266,
+ CLK_SD0_DIV4,
+ CLK_SD1_DIV4,
+ CLK_SEL_GPU2,
+ CLK_SEL_PLL5_4,
+ CLK_DSI_DIV,
+ CLK_PLL2_533,
+ CLK_PLL2_533_DIV2,
+ CLK_DIV_DSI_LPCLK,
+};
+
+#endif
diff --git a/drivers/clk/rockchip/clk_pll.c b/drivers/clk/rockchip/clk_pll.c
index d657ef38f3c..1bb31b3313b 100644
--- a/drivers/clk/rockchip/clk_pll.c
+++ b/drivers/clk/rockchip/clk_pll.c
@@ -168,13 +168,71 @@ rockchip_pll_clk_set_by_auto(ulong fin_hz,
return rate_table;
}
+static u32
+rockchip_rk3588_pll_k_get(u32 m, u32 p, u32 s, u64 fin_hz, u64 fvco)
+{
+ u64 fref, fout, ffrac;
+ u32 k = 0;
+
+ fref = fin_hz / p;
+ ffrac = fvco - (m * fref);
+ fout = ffrac * 65536;
+ k = fout / fref;
+ if (k > 32767) {
+ fref = fin_hz / p;
+ ffrac = ((m + 1) * fref) - fvco;
+ fout = ffrac * 65536;
+ k = ((fout * 10 / fref) + 7) / 10;
+ if (k > 32767)
+ k = 0;
+ else
+ k = ~k + 1;
+ }
+ return k;
+}
+
+static struct rockchip_pll_rate_table *
+rockchip_rk3588_pll_frac_by_auto(unsigned long fin_hz, unsigned long fout_hz)
+{
+ struct rockchip_pll_rate_table *rate_table = &rockchip_auto_table;
+ u32 p, m, s, k;
+ u64 fvco;
+
+ for (s = 0; s <= 6; s++) {
+ fvco = (u64)fout_hz << s;
+ if (fvco < RK3588_VCO_MIN_HZ || fvco > RK3588_VCO_MAX_HZ)
+ continue;
+ for (p = 1; p <= 4; p++) {
+ for (m = 64; m <= 1023; m++) {
+ if ((fvco >= m * fin_hz / p) &&
+ (fvco < (m + 1) * fin_hz / p)) {
+ k = rockchip_rk3588_pll_k_get(m, p, s,
+ fin_hz,
+ fvco);
+ if (!k)
+ continue;
+ rate_table->p = p;
+ rate_table->s = s;
+ rate_table->k = k;
+ if (k > 32767)
+ rate_table->m = m + 1;
+ else
+ rate_table->m = m;
+ return rate_table;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
static struct rockchip_pll_rate_table *
rk3588_pll_clk_set_by_auto(unsigned long fin_hz,
unsigned long fout_hz)
{
struct rockchip_pll_rate_table *rate_table = &rockchip_auto_table;
u32 p, m, s;
- ulong fvco, fref, fout, ffrac;
+ ulong fvco;
if (fin_hz == 0 || fout_hz == 0 || fout_hz == fin_hz)
return NULL;
@@ -202,27 +260,12 @@ rk3588_pll_clk_set_by_auto(unsigned long fin_hz,
}
pr_err("CANNOT FIND Fout by auto,fout = %lu\n", fout_hz);
} else {
- for (s = 0; s <= 6; s++) {
- fvco = fout_hz << s;
- if (fvco < RK3588_VCO_MIN_HZ ||
- fvco > RK3588_VCO_MAX_HZ)
- continue;
- for (p = 1; p <= 4; p++) {
- for (m = 64; m <= 1023; m++) {
- if ((fvco >= m * fin_hz / p) && (fvco < (m + 1) * fin_hz / p)) {
- rate_table->p = p;
- rate_table->m = m;
- rate_table->s = s;
- fref = fin_hz / p;
- ffrac = fvco - (m * fref);
- fout = ffrac * 65536;
- rate_table->k = fout / fref;
- return rate_table;
- }
- }
- }
- }
- pr_err("CANNOT FIND Fout by auto,fout = %lu\n", fout_hz);
+ rate_table = rockchip_rk3588_pll_frac_by_auto(fin_hz, fout_hz);
+ if (!rate_table)
+ pr_err("CANNOT FIND Fout by auto,fout = %lu\n",
+ fout_hz);
+ else
+ return rate_table;
}
return NULL;
}
@@ -533,11 +576,22 @@ static ulong rk3588_pll_get_rate(struct rockchip_pll_clock *pll,
rate = OSC_HZ / p;
rate *= m;
- if (k) {
+ if (k & BIT(15)) {
+ /* fractional mode */
+ u64 frac_rate64;
+
+ k = (~(k - 1)) & RK3588_PLLCON2_K_MASK;
+ frac_rate64 = OSC_HZ * k;
+ postdiv = p;
+ postdiv *= 65536;
+ do_div(frac_rate64, postdiv);
+ rate -= frac_rate64;
+ } else {
/* fractional mode */
u64 frac_rate64 = OSC_HZ * k;
- postdiv = p * 65536;
+ postdiv = p;
+ postdiv *= 65536;
do_div(frac_rate64, postdiv);
rate += frac_rate64;
}
diff --git a/drivers/clk/rockchip/clk_rk3568.c b/drivers/clk/rockchip/clk_rk3568.c
index 599b7b130eb..68f5bbbb9e5 100644
--- a/drivers/clk/rockchip/clk_rk3568.c
+++ b/drivers/clk/rockchip/clk_rk3568.c
@@ -1838,7 +1838,7 @@ static ulong rk3568_dclk_vop_set_clk(struct rk3568_clk_priv *priv,
rockchip_pll_set_rate(&rk3568_pll_clks[VPLL],
priv->cru, VPLL, div * rate);
} else {
- for (i = 0; i <= DCLK_VOP_SEL_CPLL; i++) {
+ for (i = sel; i <= DCLK_VOP_SEL_CPLL; i++) {
switch (i) {
case DCLK_VOP_SEL_GPLL:
pll_rate = priv->gpll_hz;
@@ -2785,9 +2785,15 @@ static int rk3568_dclk_vop_set_parent(struct clk *clk, struct clk *parent)
if (parent->id == PLL_VPLL) {
rk_clrsetreg(&cru->clksel_con[con_id], DCLK0_VOP_SEL_MASK,
DCLK_VOP_SEL_VPLL << DCLK0_VOP_SEL_SHIFT);
- } else {
+ } else if (parent->id == PLL_HPLL) {
rk_clrsetreg(&cru->clksel_con[con_id], DCLK0_VOP_SEL_MASK,
DCLK_VOP_SEL_HPLL << DCLK0_VOP_SEL_SHIFT);
+ } else if (parent->id == PLL_CPLL) {
+ rk_clrsetreg(&cru->clksel_con[con_id], DCLK0_VOP_SEL_MASK,
+ DCLK_VOP_SEL_CPLL << DCLK0_VOP_SEL_SHIFT);
+ } else {
+ rk_clrsetreg(&cru->clksel_con[con_id], DCLK0_VOP_SEL_MASK,
+ DCLK_VOP_SEL_GPLL << DCLK0_VOP_SEL_SHIFT);
}
return 0;
diff --git a/drivers/clk/rockchip/clk_rk3588.c b/drivers/clk/rockchip/clk_rk3588.c
index 119b1337bdf..a995dd5591d 100644
--- a/drivers/clk/rockchip/clk_rk3588.c
+++ b/drivers/clk/rockchip/clk_rk3588.c
@@ -36,6 +36,7 @@ static struct rockchip_pll_rate_table rk3588_pll_rates[] = {
RK3588_PLL_RATE(816000000, 2, 272, 2, 0),
RK3588_PLL_RATE(786432000, 2, 262, 2, 9437),
RK3588_PLL_RATE(786000000, 1, 131, 2, 0),
+ RK3588_PLL_RATE(742500000, 4, 495, 2, 0),
RK3588_PLL_RATE(722534400, 8, 963, 2, 24850),
RK3588_PLL_RATE(600000000, 2, 200, 2, 0),
RK3588_PLL_RATE(594000000, 2, 198, 2, 0),
@@ -305,12 +306,18 @@ static ulong rk3588_top_set_clk(struct rk3588_clk_priv *priv,
switch (clk_id) {
case ACLK_TOP_ROOT:
- src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
+ if (!(priv->cpll_hz % rate)) {
+ src_clk = ACLK_TOP_ROOT_SRC_SEL_CPLL;
+ src_clk_div = DIV_ROUND_UP(priv->cpll_hz, rate);
+ } else {
+ src_clk = ACLK_TOP_ROOT_SRC_SEL_GPLL;
+ src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
+ }
assert(src_clk_div - 1 <= 31);
rk_clrsetreg(&cru->clksel_con[8],
ACLK_TOP_ROOT_DIV_MASK |
ACLK_TOP_ROOT_SRC_SEL_MASK,
- (ACLK_TOP_ROOT_SRC_SEL_GPLL <<
+ (src_clk <<
ACLK_TOP_ROOT_SRC_SEL_SHIFT) |
(src_clk_div - 1) << ACLK_TOP_ROOT_DIV_SHIFT);
break;
@@ -1123,13 +1130,23 @@ static ulong rk3588_dclk_vop_set_clk(struct rk3588_clk_priv *priv,
}
if (sel == DCLK_VOP_SRC_SEL_V0PLL) {
- div = DIV_ROUND_UP(RK3588_VOP_PLL_LIMIT_FREQ, rate);
- rk_clrsetreg(&cru->clksel_con[conid],
- mask,
- DCLK_VOP_SRC_SEL_V0PLL << sel_shift |
- ((div - 1) << div_shift));
- rockchip_pll_set_rate(&rk3588_pll_clks[V0PLL],
- priv->cru, V0PLL, div * rate);
+ pll_rate = rockchip_pll_get_rate(&rk3588_pll_clks[V0PLL],
+ priv->cru, V0PLL);
+ if (pll_rate >= RK3588_VOP_PLL_LIMIT_FREQ && pll_rate % rate == 0) {
+ div = DIV_ROUND_UP(pll_rate, rate);
+ rk_clrsetreg(&cru->clksel_con[conid],
+ mask,
+ DCLK_VOP_SRC_SEL_V0PLL << sel_shift |
+ ((div - 1) << div_shift));
+ } else {
+ div = DIV_ROUND_UP(RK3588_VOP_PLL_LIMIT_FREQ, rate);
+ rk_clrsetreg(&cru->clksel_con[conid],
+ mask,
+ DCLK_VOP_SRC_SEL_V0PLL << sel_shift |
+ ((div - 1) << div_shift));
+ rockchip_pll_set_rate(&rk3588_pll_clks[V0PLL],
+ priv->cru, V0PLL, div * rate);
+ }
} else {
for (i = 0; i <= DCLK_VOP_SRC_SEL_AUPLL; i++) {
switch (i) {
diff --git a/drivers/clk/starfive/clk-jh7110.c b/drivers/clk/starfive/clk-jh7110.c
index 31aaf3340f9..a835541e48e 100644
--- a/drivers/clk/starfive/clk-jh7110.c
+++ b/drivers/clk/starfive/clk-jh7110.c
@@ -539,6 +539,16 @@ static int jh7110_stgcrg_init(struct udevice *dev)
"pcie1_tl", "stg_axiahb",
OFFSET(JH7110_STGCLK_PCIE1_TL)));
+ /* Security clocks */
+ clk_dm(JH7110_STG_ID_TRANS(JH7110_STGCLK_SEC_HCLK),
+ starfive_clk_gate(priv->reg,
+ "sec_ahb", "stg_axiahb",
+ OFFSET(JH7110_STGCLK_SEC_HCLK)));
+ clk_dm(JH7110_STG_ID_TRANS(JH7110_STGCLK_SEC_MISCAHB),
+ starfive_clk_gate(priv->reg,
+ "sec_misc_ahb", "stg_axiahb",
+ OFFSET(JH7110_STGCLK_SEC_MISCAHB)));
+
return 0;
}
diff --git a/drivers/clk/sunxi/Kconfig b/drivers/clk/sunxi/Kconfig
index bf11fad6eef..8bdc0944896 100644
--- a/drivers/clk/sunxi/Kconfig
+++ b/drivers/clk/sunxi/Kconfig
@@ -87,6 +87,13 @@ config CLK_SUN8I_H3
This enables common clock driver support for platforms based
on Allwinner H3/H5 SoC.
+config CLK_SUN20I_D1
+ bool "Clock driver for Allwinner D1"
+ default MACH_SUN8I_R528
+ help
+ This enables common clock driver support for platforms based
+ on Allwinner D1 SoC.
+
config CLK_SUN50I_H6
bool "Clock driver for Allwinner H6"
default MACH_SUN50I_H6
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index 895da02ebea..90a277489dc 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_CLK_SUN8I_R40) += clk_r40.o
obj-$(CONFIG_CLK_SUN8I_V3S) += clk_v3s.o
obj-$(CONFIG_CLK_SUN9I_A80) += clk_a80.o
obj-$(CONFIG_CLK_SUN8I_H3) += clk_h3.o
+obj-$(CONFIG_CLK_SUN20I_D1) += clk_d1.o
obj-$(CONFIG_CLK_SUN50I_H6) += clk_h6.o
obj-$(CONFIG_CLK_SUN50I_H6_R) += clk_h6_r.o
obj-$(CONFIG_CLK_SUN50I_H616) += clk_h616.o
diff --git a/drivers/clk/sunxi/clk_d1.c b/drivers/clk/sunxi/clk_d1.c
new file mode 100644
index 00000000000..9dae761de83
--- /dev/null
+++ b/drivers/clk/sunxi/clk_d1.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <clk/sunxi.h>
+#include <dt-bindings/clock/sun20i-d1-ccu.h>
+#include <dt-bindings/reset/sun20i-d1-ccu.h>
+#include <linux/bitops.h>
+
+static struct ccu_clk_gate d1_gates[] = {
+ [CLK_APB0] = GATE_DUMMY,
+
+ [CLK_BUS_MMC0] = GATE(0x84c, BIT(0)),
+ [CLK_BUS_MMC1] = GATE(0x84c, BIT(1)),
+ [CLK_BUS_MMC2] = GATE(0x84c, BIT(2)),
+ [CLK_BUS_UART0] = GATE(0x90c, BIT(0)),
+ [CLK_BUS_UART1] = GATE(0x90c, BIT(1)),
+ [CLK_BUS_UART2] = GATE(0x90c, BIT(2)),
+ [CLK_BUS_UART3] = GATE(0x90c, BIT(3)),
+ [CLK_BUS_UART4] = GATE(0x90c, BIT(4)),
+ [CLK_BUS_UART5] = GATE(0x90c, BIT(5)),
+ [CLK_BUS_I2C0] = GATE(0x91c, BIT(0)),
+ [CLK_BUS_I2C1] = GATE(0x91c, BIT(1)),
+ [CLK_BUS_I2C2] = GATE(0x91c, BIT(2)),
+ [CLK_BUS_I2C3] = GATE(0x91c, BIT(3)),
+ [CLK_SPI0] = GATE(0x940, BIT(31)),
+ [CLK_SPI1] = GATE(0x944, BIT(31)),
+ [CLK_BUS_SPI0] = GATE(0x96c, BIT(0)),
+ [CLK_BUS_SPI1] = GATE(0x96c, BIT(1)),
+
+ [CLK_BUS_EMAC] = GATE(0x97c, BIT(0)),
+
+ [CLK_USB_OHCI0] = GATE(0xa70, BIT(31)),
+ [CLK_USB_OHCI1] = GATE(0xa74, BIT(31)),
+ [CLK_BUS_OHCI0] = GATE(0xa8c, BIT(0)),
+ [CLK_BUS_OHCI1] = GATE(0xa8c, BIT(1)),
+ [CLK_BUS_EHCI0] = GATE(0xa8c, BIT(4)),
+ [CLK_BUS_EHCI1] = GATE(0xa8c, BIT(5)),
+ [CLK_BUS_OTG] = GATE(0xa8c, BIT(8)),
+ [CLK_BUS_LRADC] = GATE(0xa9c, BIT(0)),
+
+ [CLK_RISCV] = GATE(0xd04, BIT(31)),
+};
+
+static struct ccu_reset d1_resets[] = {
+ [RST_BUS_MMC0] = RESET(0x84c, BIT(16)),
+ [RST_BUS_MMC1] = RESET(0x84c, BIT(17)),
+ [RST_BUS_MMC2] = RESET(0x84c, BIT(18)),
+ [RST_BUS_UART0] = RESET(0x90c, BIT(16)),
+ [RST_BUS_UART1] = RESET(0x90c, BIT(17)),
+ [RST_BUS_UART2] = RESET(0x90c, BIT(18)),
+ [RST_BUS_UART3] = RESET(0x90c, BIT(19)),
+ [RST_BUS_UART4] = RESET(0x90c, BIT(20)),
+ [RST_BUS_UART5] = RESET(0x90c, BIT(21)),
+ [RST_BUS_I2C0] = RESET(0x91c, BIT(16)),
+ [RST_BUS_I2C1] = RESET(0x91c, BIT(17)),
+ [RST_BUS_I2C2] = RESET(0x91c, BIT(18)),
+ [RST_BUS_I2C3] = RESET(0x91c, BIT(19)),
+ [RST_BUS_SPI0] = RESET(0x96c, BIT(16)),
+ [RST_BUS_SPI1] = RESET(0x96c, BIT(17)),
+
+ [RST_BUS_EMAC] = RESET(0x97c, BIT(16)),
+
+ [RST_USB_PHY0] = RESET(0xa70, BIT(30)),
+ [RST_USB_PHY1] = RESET(0xa74, BIT(30)),
+ [RST_BUS_OHCI0] = RESET(0xa8c, BIT(16)),
+ [RST_BUS_OHCI1] = RESET(0xa8c, BIT(17)),
+ [RST_BUS_EHCI0] = RESET(0xa8c, BIT(20)),
+ [RST_BUS_EHCI1] = RESET(0xa8c, BIT(21)),
+ [RST_BUS_OTG] = RESET(0xa8c, BIT(24)),
+ [RST_BUS_LRADC] = RESET(0xa9c, BIT(16)),
+};
+
+const struct ccu_desc d1_ccu_desc = {
+ .gates = d1_gates,
+ .resets = d1_resets,
+ .num_gates = ARRAY_SIZE(d1_gates),
+ .num_resets = ARRAY_SIZE(d1_resets),
+};
diff --git a/drivers/clk/sunxi/clk_sunxi.c b/drivers/clk/sunxi/clk_sunxi.c
index ec02a2d0370..1782cffc404 100644
--- a/drivers/clk/sunxi/clk_sunxi.c
+++ b/drivers/clk/sunxi/clk_sunxi.c
@@ -118,6 +118,7 @@ extern const struct ccu_desc a64_ccu_desc;
extern const struct ccu_desc a80_ccu_desc;
extern const struct ccu_desc a80_mmc_clk_desc;
extern const struct ccu_desc a83t_ccu_desc;
+extern const struct ccu_desc d1_ccu_desc;
extern const struct ccu_desc f1c100s_ccu_desc;
extern const struct ccu_desc h3_ccu_desc;
extern const struct ccu_desc h6_ccu_desc;
@@ -195,6 +196,10 @@ static const struct udevice_id sunxi_clk_ids[] = {
{ .compatible = "allwinner,sun50i-h5-ccu",
.data = (ulong)&h3_ccu_desc },
#endif
+#ifdef CONFIG_CLK_SUN20I_D1
+ { .compatible = "allwinner,sun20i-d1-ccu",
+ .data = (ulong)&d1_ccu_desc },
+#endif
#ifdef CONFIG_CLK_SUN50I_H6
{ .compatible = "allwinner,sun50i-h6-ccu",
.data = (ulong)&h6_ccu_desc },
diff --git a/drivers/clk/ti/clk-k3-pll.c b/drivers/clk/ti/clk-k3-pll.c
index bf762c558ef..8323e6e6919 100644
--- a/drivers/clk/ti/clk-k3-pll.c
+++ b/drivers/clk/ti/clk-k3-pll.c
@@ -2,7 +2,7 @@
/*
* Texas Instruments K3 SoC PLL clock driver
*
- * Copyright (C) 2020-2021 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/
* Tero Kristo <t-kristo@ti.com>
*/
@@ -25,6 +25,23 @@
#define PLL_16FFT_FREQ_CTRL0 0x30
#define PLL_16FFT_FREQ_CTRL1 0x34
#define PLL_16FFT_DIV_CTRL 0x38
+#define PLL_16FFT_CAL_CTRL 0x60
+#define PLL_16FFT_CAL_STAT 0x64
+
+/* CAL STAT register bits */
+#define PLL_16FFT_CAL_STAT_CAL_LOCK BIT(31)
+
+/* CFG register bits */
+#define PLL_16FFT_CFG_PLL_TYPE_SHIFT (0)
+#define PLL_16FFT_CFG_PLL_TYPE_MASK (0x3 << 0)
+#define PLL_16FFT_CFG_PLL_TYPE_FRACF 1
+
+/* CAL CTRL register bits */
+#define PLL_16FFT_CAL_CTRL_CAL_EN BIT(31)
+#define PLL_16FFT_CAL_CTRL_FAST_CAL BIT(20)
+#define PLL_16FFT_CAL_CTRL_CAL_BYP BIT(15)
+#define PLL_16FFT_CAL_CTRL_CAL_CNT_SHIFT 16
+#define PLL_16FFT_CAL_CTRL_CAL_CNT_MASK (0x7 << 16)
/* CTRL register bits */
#define PLL_16FFT_CTRL_BYPASS_EN BIT(31)
@@ -40,9 +57,14 @@
/* DIV CTRL register bits */
#define PLL_16FFT_DIV_CTRL_REF_DIV_MASK 0x3f
-#define PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_BITS 24
+/* HSDIV register bits*/
#define PLL_16FFT_HSDIV_CTRL_CLKOUT_EN BIT(15)
+/* FREQ_CTRL1 bits */
+#define PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_BITS 24
+#define PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_MASK 0xffffff
+#define PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_SHIFT 0
+
/* KICK register magic values */
#define PLL_KICK0_VALUE 0x68ef3490
#define PLL_KICK1_VALUE 0xd172bc5a
@@ -63,18 +85,65 @@ static int ti_pll_wait_for_lock(struct clk *clk)
{
struct ti_pll_clk *pll = to_clk_pll(clk);
u32 stat;
+ u32 cfg;
+ u32 cal;
+ u32 freq_ctrl1;
int i;
+ u32 pllfm;
+ u32 pll_type;
+ int success;
for (i = 0; i < 100000; i++) {
stat = readl(pll->reg + PLL_16FFT_STAT);
- if (stat & PLL_16FFT_STAT_LOCK)
- return 0;
+ if (stat & PLL_16FFT_STAT_LOCK) {
+ success = 1;
+ break;
+ }
}
- printf("%s: pll (%s) failed to lock\n", __func__,
- clk->dev->name);
+ /* Enable calibration if not in fractional mode of the FRACF PLL */
+ freq_ctrl1 = readl(pll->reg + PLL_16FFT_FREQ_CTRL1);
+ pllfm = freq_ctrl1 & PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_MASK;
+ pllfm >>= PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_SHIFT;
+ cfg = readl(pll->reg + PLL_16FFT_CFG);
+ pll_type = (cfg & PLL_16FFT_CFG_PLL_TYPE_MASK) >> PLL_16FFT_CFG_PLL_TYPE_SHIFT;
+
+ if (success && pll_type == PLL_16FFT_CFG_PLL_TYPE_FRACF && pllfm == 0) {
+ cal = readl(pll->reg + PLL_16FFT_CAL_CTRL);
- return -EBUSY;
+ /* Enable calibration for FRACF */
+ cal |= PLL_16FFT_CAL_CTRL_CAL_EN;
+
+ /* Enable fast cal mode */
+ cal |= PLL_16FFT_CAL_CTRL_FAST_CAL;
+
+ /* Disable calibration bypass */
+ cal &= ~PLL_16FFT_CAL_CTRL_CAL_BYP;
+
+ /* Set CALCNT to 2 */
+ cal &= ~PLL_16FFT_CAL_CTRL_CAL_CNT_MASK;
+ cal |= 2 << PLL_16FFT_CAL_CTRL_CAL_CNT_SHIFT;
+
+ /* Note this register does not readback the written value. */
+ writel(cal, pll->reg + PLL_16FFT_CAL_CTRL);
+
+ success = 0;
+ for (i = 0; i < 100000; i++) {
+ stat = readl(pll->reg + PLL_16FFT_CAL_STAT);
+ if (stat & PLL_16FFT_CAL_STAT_CAL_LOCK) {
+ success = 1;
+ break;
+ }
+ }
+ }
+
+ if (success == 0) {
+ printf("%s: pll (%s) failed to lock\n", __func__,
+ clk->dev->name);
+ return -EBUSY;
+ } else {
+ return 0;
+ }
}
static ulong ti_pll_clk_get_rate(struct clk *clk)
diff --git a/drivers/clk/ti/clk-k3.c b/drivers/clk/ti/clk-k3.c
index ba925fa3c48..eb76195bd75 100644
--- a/drivers/clk/ti/clk-k3.c
+++ b/drivers/clk/ti/clk-k3.c
@@ -2,7 +2,7 @@
/*
* Texas Instruments K3 clock driver
*
- * Copyright (C) 2020-2021 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/
* Tero Kristo <t-kristo@ti.com>
*/
@@ -11,6 +11,7 @@
#include <errno.h>
#include <soc.h>
#include <clk-uclass.h>
+#include <k3-avs.h>
#include "k3-clk.h"
#define PLL_MIN_FREQ 800000000
@@ -242,7 +243,11 @@ static ulong ti_clk_set_rate(struct clk *clk, ulong rate)
const struct clk_ops *ops;
ulong new_rate, rem;
ulong diff, new_diff;
+ int freq_scale_up = rate >= ti_clk_get_rate(clk) ? 1 : 0;
+ if (IS_ENABLED(CONFIG_K3_AVS0) && freq_scale_up)
+ k3_avs_notify_freq(data->map[clk->id].dev_id,
+ data->map[clk->id].clk_id, rate);
/*
* We must propagate rate change to parent if current clock type
* does not allow setting it.
@@ -339,6 +344,10 @@ static ulong ti_clk_set_rate(struct clk *clk, ulong rate)
}
}
+ if (IS_ENABLED(CONFIG_K3_AVS0) && !freq_scale_up)
+ k3_avs_notify_freq(data->map[clk->id].dev_id,
+ data->map[clk->id].clk_id, rate);
+
return new_rate;
}
diff --git a/drivers/clk/ti/clk-sci.c b/drivers/clk/ti/clk-sci.c
index 74df5a397bf..9e5760d3354 100644
--- a/drivers/clk/ti/clk-sci.c
+++ b/drivers/clk/ti/clk-sci.c
@@ -2,7 +2,7 @@
/*
* Texas Instruments System Control Interface (TI SCI) clock driver
*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
* Andreas Dannenberg <dannenberg@ti.com>
*
* Loosely based on Linux kernel sci-clk.c...
@@ -91,12 +91,12 @@ static ulong ti_sci_clk_set_rate(struct clk *clk, ulong rate)
const struct ti_sci_handle *sci = data->sci;
const struct ti_sci_clk_ops *cops = &sci->ops.clk_ops;
int ret;
+ int freq_scale_up = rate >= ti_sci_clk_get_rate(clk) ? 1 : 0;
debug("%s(clk=%p, rate=%lu)\n", __func__, clk, rate);
-#ifdef CONFIG_K3_AVS0
- k3_avs_notify_freq(clk->id, clk->data, rate);
-#endif
+ if (IS_ENABLED(CONFIG_K3_AVS0) && freq_scale_up)
+ k3_avs_notify_freq(clk->id, clk->data, rate);
ret = cops->set_freq(sci, clk->id, clk->data, 0, rate, ULONG_MAX);
if (ret) {
@@ -104,6 +104,9 @@ static ulong ti_sci_clk_set_rate(struct clk *clk, ulong rate)
return ret;
}
+ if (IS_ENABLED(CONFIG_K3_AVS0) && !freq_scale_up)
+ k3_avs_notify_freq(clk->id, clk->data, rate);
+
return rate;
}
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index f0d848f45d8..1081d61fcf0 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -14,7 +14,7 @@ config SPL_DM
help
Enable driver model in SPL. You will need to provide a
suitable malloc() implementation. If you are not using the
- full malloc() enabled by CFG_SYS_SPL_MALLOC_START,
+ full malloc() enabled by CFG_SPL_SYS_MALLOC_START,
consider using CONFIG_SPL_SYS_MALLOC_SIMPLE. In that case you
must provide CONFIG_SPL_SYS_MALLOC_F_LEN to set the size.
In most cases driver model will only allocate a few uclasses
@@ -27,12 +27,12 @@ config TPL_DM
help
Enable driver model in TPL. You will need to provide a
suitable malloc() implementation. If you are not using the
- full malloc() enabled by CFG_SYS_SPL_MALLOC_START,
+ full malloc() enabled by CFG_TPL_SYS_MALLOC_START,
consider using CONFIG_TPL_SYS_MALLOC_SIMPLE. In that case you
- must provide CONFIG_SPL_SYS_MALLOC_F_LEN to set the size.
+ must provide CONFIG_TPL_SYS_MALLOC_F_LEN to set the size.
In most cases driver model will only allocate a few uclasses
- and devices in SPL, so 1KB should be enough. See
- CONFIG_SPL_SYS_MALLOC_F_LEN for more details on how to enable it.
+ and devices in TPL, so 1KB should be enough. See
+ CONFIG_TPL_SYS_MALLOC_F_LEN for more details on how to enable it.
Disable this for very small implementations.
config VPL_DM
@@ -42,13 +42,12 @@ config VPL_DM
help
Enable driver model in VPL. You will need to provide a
suitable malloc() implementation. If you are not using the
- full malloc() enabled by CFG_SYS_SPL_MALLOC_START,
- consider using CONFIG_SPL_SYS_MALLOC_SIMPLE.
+ full malloc() enabled by CFG_TPL_SYS_MALLOC_START,
+ consider using CONFIG_TPL_SYS_MALLOC_SIMPLE.
config DM_WARN
bool "Enable warnings in driver model"
depends on DM
- default y
help
Enable this to see warnings related to driver model.
@@ -88,7 +87,7 @@ config DM_STATS
config SPL_DM_STATS
bool "Collect and show driver model stats in SPL"
- depends on DM_SPL
+ depends on SPL_DM
help
Enable this to collect and display memory statistics about driver
model. This can help to figure out where all the memory is going and
diff --git a/drivers/core/Makefile b/drivers/core/Makefile
index bce0a3f65cb..acbd2bf2cef 100644
--- a/drivers/core/Makefile
+++ b/drivers/core/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_$(SPL_)OF_LIVE) += of_access.o of_addr.o
ifndef CONFIG_DM_DEV_READ_INLINE
obj-$(CONFIG_OF_CONTROL) += read.o
endif
+obj-$(CONFIG_$(SPL_)OF_PLATDATA) += read.o
obj-$(CONFIG_OF_CONTROL) += of_extra.o ofnode.o read_extra.o
ccflags-$(CONFIG_DM_DEBUG) += -DDEBUG
diff --git a/drivers/core/fdtaddr.c b/drivers/core/fdtaddr.c
index 546db675aaf..8e774d49ce6 100644
--- a/drivers/core/fdtaddr.c
+++ b/drivers/core/fdtaddr.c
@@ -145,7 +145,7 @@ fdt_addr_t devfdt_get_addr_name(const struct udevice *dev, const char *name)
index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev),
"reg-names", name);
if (index < 0)
- return index;
+ return FDT_ADDR_T_NONE;
return devfdt_get_addr_index(dev, index);
#else
@@ -153,6 +153,16 @@ fdt_addr_t devfdt_get_addr_name(const struct udevice *dev, const char *name)
#endif
}
+void *devfdt_get_addr_name_ptr(const struct udevice *dev, const char *name)
+{
+ fdt_addr_t addr = devfdt_get_addr_name(dev, name);
+
+ if (addr == FDT_ADDR_T_NONE)
+ return NULL;
+
+ return map_sysmem(addr, 0);
+}
+
fdt_addr_t devfdt_get_addr_size_name(const struct udevice *dev,
const char *name, fdt_size_t *size)
{
@@ -162,7 +172,7 @@ fdt_addr_t devfdt_get_addr_size_name(const struct udevice *dev,
index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev),
"reg-names", name);
if (index < 0)
- return index;
+ return FDT_ADDR_T_NONE;
return devfdt_get_addr_size_index(dev, index, size);
#else
@@ -170,6 +180,17 @@ fdt_addr_t devfdt_get_addr_size_name(const struct udevice *dev,
#endif
}
+void *devfdt_get_addr_size_name_ptr(const struct udevice *dev,
+ const char *name, fdt_size_t *size)
+{
+ fdt_addr_t addr = devfdt_get_addr_size_name(dev, name, size);
+
+ if (addr == FDT_ADDR_T_NONE)
+ return NULL;
+
+ return map_sysmem(addr, 0);
+}
+
fdt_addr_t devfdt_get_addr(const struct udevice *dev)
{
return devfdt_get_addr_index(dev, 0);
@@ -215,7 +236,7 @@ void *devfdt_map_physmem(const struct udevice *dev, unsigned long size)
return map_physmem(addr, size, MAP_NOCACHE);
}
-fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev)
+fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev, fdt_size_t *sizep)
{
ulong addr;
@@ -226,12 +247,12 @@ fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev)
int ret;
ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_MEM32,
- "reg", &pci_addr);
+ "reg", &pci_addr, sizep);
if (ret) {
/* try if there is any i/o-mapped register */
ret = ofnode_read_pci_addr(dev_ofnode(dev),
FDT_PCI_SPACE_IO, "reg",
- &pci_addr);
+ &pci_addr, sizep);
if (ret)
return FDT_ADDR_T_NONE;
}
diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c
index 1bb4d8eab70..c8db743f529 100644
--- a/drivers/core/of_access.c
+++ b/drivers/core/of_access.c
@@ -1040,3 +1040,68 @@ int of_add_subnode(struct device_node *parent, const char *name, int len,
return 0;
}
+
+int __of_remove_property(struct device_node *np, struct property *prop)
+{
+ struct property **next;
+
+ for (next = &np->properties; *next; next = &(*next)->next) {
+ if (*next == prop)
+ break;
+ }
+ if (!*next)
+ return -ENODEV;
+
+ /* found the node */
+ *next = prop->next;
+
+ return 0;
+}
+
+int of_remove_property(struct device_node *np, struct property *prop)
+{
+ int rc;
+
+ mutex_lock(&of_mutex);
+
+ rc = __of_remove_property(np, prop);
+
+ mutex_unlock(&of_mutex);
+
+ return rc;
+}
+
+int of_remove_node(struct device_node *to_remove)
+{
+ struct device_node *parent = to_remove->parent;
+ struct device_node *np, *prev;
+
+ if (!parent)
+ return -EPERM;
+ prev = NULL;
+ __for_each_child_of_node(parent, np) {
+ if (np == to_remove)
+ break;
+ prev = np;
+ }
+ if (!np)
+ return -EFAULT;
+
+ /* if there is a previous node, link it to this one's sibling */
+ if (prev)
+ prev->sibling = np->sibling;
+ else
+ parent->child = np->sibling;
+
+ /*
+ * don't free it, since if this is an unflattened tree, all the memory
+ * was alloced in one block; this pointer will be somewhere in the
+ * middle of that
+ *
+ * TODO(sjg@chromium.org): Consider marking nodes as 'allocated'?
+ *
+ * free(np);
+ */
+
+ return 0;
+}
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 2cafa7bca5b..f72ea416cf1 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -47,6 +47,17 @@ static int oftree_find(const void *fdt)
return -1;
}
+static int check_tree_count(void)
+{
+ if (oftree_count == CONFIG_OFNODE_MULTI_TREE_MAX) {
+ log_warning("Too many registered device trees (max %d)\n",
+ CONFIG_OFNODE_MULTI_TREE_MAX);
+ return -E2BIG;
+ }
+
+ return 0;
+}
+
static oftree oftree_ensure(void *fdt)
{
oftree tree;
@@ -69,11 +80,8 @@ static oftree oftree_ensure(void *fdt)
if (gd->flags & GD_FLG_RELOC) {
i = oftree_find(fdt);
if (i == -1) {
- if (oftree_count == CONFIG_OFNODE_MULTI_TREE_MAX) {
- log_warning("Too many registered device trees (max %d)\n",
- CONFIG_OFNODE_MULTI_TREE_MAX);
+ if (check_tree_count())
return oftree_null();
- }
/* register the new tree */
i = oftree_count++;
@@ -92,6 +100,41 @@ static oftree oftree_ensure(void *fdt)
return tree;
}
+int oftree_new(oftree *treep)
+{
+ oftree tree = oftree_null();
+ int ret;
+
+ if (of_live_active()) {
+ struct device_node *root;
+
+ ret = of_live_create_empty(&root);
+ if (ret)
+ return log_msg_ret("liv", ret);
+ tree = oftree_from_np(root);
+ } else {
+ const int size = 1024;
+ void *fdt;
+
+ ret = check_tree_count();
+ if (ret)
+ return log_msg_ret("fla", ret);
+
+ /* register the new tree with a small size */
+ fdt = malloc(size);
+ if (!fdt)
+ return log_msg_ret("fla", -ENOMEM);
+ ret = fdt_create_empty_tree(fdt, size);
+ if (ret)
+ return log_msg_ret("fla", -EINVAL);
+ oftree_list[oftree_count++] = fdt;
+ tree.fdt = fdt;
+ }
+ *treep = tree;
+
+ return 0;
+}
+
void oftree_dispose(oftree tree)
{
if (of_live_active())
@@ -193,8 +236,31 @@ static inline int oftree_find(const void *fdt)
return 0;
}
+int oftree_new(oftree *treep)
+{
+ return -ENOSYS;
+}
+
#endif /* OFNODE_MULTI_TREE */
+int oftree_to_fdt(oftree tree, struct abuf *buf)
+{
+ int ret;
+
+ if (of_live_active()) {
+ ret = of_live_flatten(ofnode_to_np(oftree_root(tree)), buf);
+ if (ret)
+ return log_msg_ret("flt", ret);
+ } else {
+ void *fdt = oftree_lookup_fdt(tree);
+
+ abuf_init(buf);
+ abuf_set(buf, fdt, fdt_totalsize(fdt));
+ }
+
+ return 0;
+}
+
/**
* ofnode_from_tree_offset() - get an ofnode from a tree offset (flat tree)
*
@@ -425,12 +491,12 @@ u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def)
bool ofnode_read_bool(ofnode node, const char *propname)
{
- const void *prop;
+ bool prop;
assert(ofnode_valid(node));
debug("%s: %s: ", __func__, propname);
- prop = ofnode_get_property(node, propname, NULL);
+ prop = ofnode_has_property(node, propname);
debug("%s\n", prop ? "true" : "false");
@@ -925,6 +991,24 @@ ofnode ofnode_get_chosen_node(const char *name)
return ofnode_path(prop);
}
+int ofnode_read_baud(void)
+{
+ const char *str, *p;
+ u32 baud;
+
+ str = ofnode_read_chosen_string("stdout-path");
+ if (!str)
+ return -EINVAL;
+
+ /* Parse string serial0:115200n8 */
+ p = strchr(str, ':');
+ if (!p)
+ return -EINVAL;
+
+ baud = dectoul(p + 1, NULL);
+ return baud;
+}
+
const void *ofnode_read_aliases_prop(const char *propname, int *sizep)
{
ofnode node;
@@ -1102,6 +1186,14 @@ const void *ofnode_get_property(ofnode node, const char *propname, int *lenp)
propname, lenp);
}
+bool ofnode_has_property(ofnode node, const char *propname)
+{
+ if (ofnode_is_np(node))
+ return of_find_property(ofnode_to_np(node), propname, NULL);
+ else
+ return ofnode_get_property(node, propname, NULL);
+}
+
int ofnode_first_property(ofnode node, struct ofprop *prop)
{
prop->node = node;
@@ -1196,7 +1288,8 @@ const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
}
int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
- const char *propname, struct fdt_pci_addr *addr)
+ const char *propname, struct fdt_pci_addr *addr,
+ fdt_size_t *size)
{
const fdt32_t *cell;
int len;
@@ -1224,14 +1317,18 @@ int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
(ulong)fdt32_to_cpu(cell[1]),
(ulong)fdt32_to_cpu(cell[2]));
if ((fdt32_to_cpu(*cell) & type) == type) {
+ const unaligned_fdt64_t *ptr;
+
addr->phys_hi = fdt32_to_cpu(cell[0]);
addr->phys_mid = fdt32_to_cpu(cell[1]);
addr->phys_lo = fdt32_to_cpu(cell[2]);
+ ptr = (const unaligned_fdt64_t *)(cell + 3);
+ if (size)
+ *size = fdt64_to_cpu(*ptr);
break;
}
- cell += (FDT_PCI_ADDR_CELLS +
- FDT_PCI_SIZE_CELLS);
+ cell += FDT_PCI_ADDR_CELLS + FDT_PCI_SIZE_CELLS;
}
if (i == num) {
@@ -1547,7 +1644,46 @@ int ofnode_write_u32(ofnode node, const char *propname, u32 value)
return -ENOMEM;
*val = cpu_to_fdt32(value);
- return ofnode_write_prop(node, propname, val, sizeof(value), false);
+ return ofnode_write_prop(node, propname, val, sizeof(value), true);
+}
+
+int ofnode_write_u64(ofnode node, const char *propname, u64 value)
+{
+ fdt64_t *val;
+
+ assert(ofnode_valid(node));
+
+ log_debug("%s = %llx", propname, (unsigned long long)value);
+ val = malloc(sizeof(*val));
+ if (!val)
+ return -ENOMEM;
+ *val = cpu_to_fdt64(value);
+
+ return ofnode_write_prop(node, propname, val, sizeof(value), true);
+}
+
+int ofnode_write_bool(ofnode node, const char *propname, bool value)
+{
+ if (value)
+ return ofnode_write_prop(node, propname, NULL, 0, false);
+ else
+ return ofnode_delete_prop(node, propname);
+}
+
+int ofnode_delete_prop(ofnode node, const char *propname)
+{
+ if (ofnode_is_np(node)) {
+ struct property *prop;
+ int len;
+
+ prop = of_find_property(ofnode_to_np(node), propname, &len);
+ if (prop)
+ return of_remove_property(ofnode_to_np(node), prop);
+ return 0;
+ } else {
+ return fdt_delprop(ofnode_to_fdt(node), ofnode_to_offset(node),
+ propname);
+ }
}
int ofnode_set_enabled(ofnode node, bool value)
@@ -1731,7 +1867,30 @@ int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep)
return ret; /* 0 or -EEXIST */
}
-int ofnode_copy_props(ofnode src, ofnode dst)
+int ofnode_delete(ofnode *nodep)
+{
+ ofnode node = *nodep;
+ int ret;
+
+ assert(ofnode_valid(node));
+ if (ofnode_is_np(node)) {
+ ret = of_remove_node(ofnode_to_np(node));
+ } else {
+ void *fdt = ofnode_to_fdt(node);
+ int offset = ofnode_to_offset(node);
+
+ ret = fdt_del_node(fdt, offset);
+ if (ret)
+ ret = -EFAULT;
+ }
+ if (ret)
+ return ret;
+ *nodep = ofnode_null();
+
+ return 0;
+}
+
+int ofnode_copy_props(ofnode dst, ofnode src)
{
struct ofprop prop;
@@ -1754,3 +1913,23 @@ int ofnode_copy_props(ofnode src, ofnode dst)
return 0;
}
+
+int ofnode_copy_node(ofnode dst_parent, const char *name, ofnode src,
+ ofnode *nodep)
+{
+ ofnode node;
+ int ret;
+
+ ret = ofnode_add_subnode(dst_parent, name, &node);
+ if (ret) {
+ if (ret == -EEXIST)
+ *nodep = node;
+ return log_msg_ret("add", ret);
+ }
+ ret = ofnode_copy_props(node, src);
+ if (ret)
+ return log_msg_ret("cpy", ret);
+ *nodep = node;
+
+ return 0;
+}
diff --git a/drivers/core/read.c b/drivers/core/read.c
index 49066b59cda..1a4a95cddea 100644
--- a/drivers/core/read.c
+++ b/drivers/core/read.c
@@ -181,6 +181,16 @@ fdt_addr_t dev_read_addr_name(const struct udevice *dev, const char *name)
return dev_read_addr_index(dev, index);
}
+void *dev_read_addr_name_ptr(const struct udevice *dev, const char *name)
+{
+ fdt_addr_t addr = dev_read_addr_name(dev, name);
+
+ if (addr == FDT_ADDR_T_NONE)
+ return NULL;
+
+ return map_sysmem(addr, 0);
+}
+
fdt_addr_t dev_read_addr_size_name(const struct udevice *dev, const char *name,
fdt_size_t *size)
{
@@ -192,6 +202,17 @@ fdt_addr_t dev_read_addr_size_name(const struct udevice *dev, const char *name,
return dev_read_addr_size_index(dev, index, size);
}
+void *dev_read_addr_size_name_ptr(const struct udevice *dev, const char *name,
+ fdt_size_t *size)
+{
+ fdt_addr_t addr = dev_read_addr_size_name(dev, name, size);
+
+ if (addr == FDT_ADDR_T_NONE)
+ return NULL;
+
+ return map_sysmem(addr, 0);
+}
+
void *dev_remap_addr_name(const struct udevice *dev, const char *name)
{
fdt_addr_t addr = dev_read_addr_name(dev, name);
@@ -405,13 +426,15 @@ int dev_read_alias_highest_id(const char *stem)
return fdtdec_get_alias_highest_id(gd->fdt_blob, stem);
}
-fdt_addr_t dev_read_addr_pci(const struct udevice *dev)
+fdt_addr_t dev_read_addr_pci(const struct udevice *dev, fdt_size_t *sizep)
{
ulong addr;
addr = dev_read_addr(dev);
+ if (sizep)
+ *sizep = 0;
if (addr == FDT_ADDR_T_NONE && !of_live_active())
- addr = devfdt_get_addr_pci(dev);
+ addr = devfdt_get_addr_pci(dev, sizep);
return addr;
}
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 126b3140666..d4ae652bcfb 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -426,7 +426,7 @@ void dm_get_mem(struct dm_stats *stats)
stats->tag_size;
}
-#ifdef CONFIG_ACPIGEN
+#if CONFIG_IS_ENABLED(ACPIGEN)
static int root_acpi_get_name(const struct udevice *dev, char *out_name)
{
return acpi_copy_name(out_name, "\\_SB");
diff --git a/drivers/core/util.c b/drivers/core/util.c
index aa60fdd15bc..81497df85ff 100644
--- a/drivers/core/util.c
+++ b/drivers/core/util.c
@@ -30,7 +30,7 @@ int pci_get_devfn(struct udevice *dev)
/* Extract the devfn from fdt_pci_addr */
ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_CONFIG,
- "reg", &addr);
+ "reg", &addr, NULL);
if (ret) {
if (ret != -ENOENT)
return -EINVAL;
diff --git a/drivers/crypto/fsl/Kconfig b/drivers/crypto/fsl/Kconfig
index 91a51cc5fe7..eaad19633f1 100644
--- a/drivers/crypto/fsl/Kconfig
+++ b/drivers/crypto/fsl/Kconfig
@@ -77,7 +77,6 @@ endif
config FSL_DCP_RNG
bool "Enable Random Number Generator support"
depends on DM_RNG
- default n
help
Enable support for the hardware based random number generator
module of the DCP. It uses the True Random Number Generator (TRNG)
diff --git a/drivers/dfu/Kconfig b/drivers/dfu/Kconfig
index 4e80e85d10d..0360d9da142 100644
--- a/drivers/dfu/Kconfig
+++ b/drivers/dfu/Kconfig
@@ -19,6 +19,7 @@ config DFU_WRITE_ALT
config DFU_TFTP
bool "DFU via TFTP"
+ depends on NETDEVICES
select UPDATE_COMMON
select DFU_OVER_TFTP
help
@@ -111,5 +112,14 @@ config SYS_DFU_MAX_FILE_SIZE
the buffer once we've been given the whole file. Define
this to the maximum filesize (in bytes) for the buffer.
If undefined it defaults to the CONFIG_SYS_DFU_DATA_BUF_SIZE.
+
+config DFU_NAME_MAX_SIZE
+ int "Size of the name to be added in dfu entity"
+ default 32
+ depends on DFU
+ help
+ This value is used to maximum size. If name is longer than default size,
+ we need to change the proper maximum size.
+
endif
endmenu
diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c
index cdb3c18b01d..12c54e90ef7 100644
--- a/drivers/dfu/dfu_mmc.c
+++ b/drivers/dfu/dfu_mmc.c
@@ -387,6 +387,16 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *devstr, char **argv, int a
dfu->data.mmc.lba_blk_size = mmc->read_bl_len;
/*
+ * In case the size is zero (i.e. mmc raw 0x10 0),
+ * assume the user intends to use whole device.
+ */
+ if (third_arg == 0) {
+ struct blk_desc *blk_dev = mmc_get_blk_desc(mmc);
+
+ dfu->data.mmc.lba_size = blk_dev->lba;
+ }
+
+ /*
* Check for an extra entry at dfu_alt_info env variable
* specifying the mmc HW defined partition number
*/
diff --git a/drivers/dfu/dfu_mtd.c b/drivers/dfu/dfu_mtd.c
index 75e2f6a4215..485586989c8 100644
--- a/drivers/dfu/dfu_mtd.c
+++ b/drivers/dfu/dfu_mtd.c
@@ -85,27 +85,41 @@ static int mtd_block_op(enum dfu_op op, struct dfu_entity *dfu,
while (remaining) {
if (erase_op.addr + remaining > lim) {
- printf("Limit reached 0x%llx while erasing at offset 0x%llx\n",
- lim, off);
+ printf("Limit reached 0x%llx while erasing at offset 0x%llx, remaining 0x%llx\n",
+ lim, erase_op.addr, remaining);
return -EIO;
}
+ /* Skip the block if it is bad, don't erase it again */
+ ret = mtd_block_isbad(mtd, erase_op.addr);
+ if (ret) {
+ printf("Skipping %s at 0x%08llx\n",
+ ret == 1 ? "bad block" : "bbt reserved",
+ erase_op.addr);
+ erase_op.addr += mtd->erasesize;
+ continue;
+ }
+
ret = mtd_erase(mtd, &erase_op);
if (ret) {
- /* Abort if its not a bad block error */
- if (ret != -EIO) {
- printf("Failure while erasing at offset 0x%llx\n",
- erase_op.fail_addr);
- return 0;
+ /* If this is not -EIO, we have no idea what to do. */
+ if (ret == -EIO) {
+ printf("Marking bad block at 0x%08llx (%d)\n",
+ erase_op.fail_addr, ret);
+ ret = mtd_block_markbad(mtd, erase_op.addr);
+ }
+ /* Abort if it is not -EIO or can't mark bad */
+ if (ret) {
+ printf("Failure while erasing at offset 0x%llx (%d)\n",
+ erase_op.fail_addr, ret);
+ return ret;
}
- printf("Skipping bad block at 0x%08llx\n",
- erase_op.addr);
} else {
remaining -= mtd->erasesize;
}
- /* Continue erase behind bad block */
+ /* Continue erase behind the current block */
erase_op.addr += mtd->erasesize;
}
}
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 0af54604211..3c64e894646 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -87,7 +87,6 @@ endif
config DMA_LEGACY
bool "Legacy DMA support"
- default y if FSLDMAFEC
help
Enable legacy DMA support. This does not use driver model and should
be migrated to the new API.
diff --git a/drivers/dma/MCD_dmaApi.c b/drivers/dma/MCD_dmaApi.c
deleted file mode 100644
index af0e1345220..00000000000
--- a/drivers/dma/MCD_dmaApi.c
+++ /dev/null
@@ -1,1010 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
- */
-
-/*Main C file for multi-channel DMA API. */
-
-#include <common.h>
-
-#include <MCD_dma.h>
-#include <MCD_tasksInit.h>
-#include <MCD_progCheck.h>
-
-/********************************************************************/
-/* This is an API-internal pointer to the DMA's registers */
-dmaRegs *MCD_dmaBar;
-
-/*
- * These are the real and model task tables as generated by the
- * build process
- */
-extern TaskTableEntry MCD_realTaskTableSrc[NCHANNELS];
-extern TaskTableEntry MCD_modelTaskTableSrc[NUMOFVARIANTS];
-
-/*
- * However, this (usually) gets relocated to on-chip SRAM, at which
- * point we access them as these tables
- */
-volatile TaskTableEntry *MCD_taskTable;
-TaskTableEntry *MCD_modelTaskTable;
-
-/*
- * MCD_chStatus[] is an array of status indicators for remembering
- * whether a DMA has ever been attempted on each channel, pausing
- * status, etc.
- */
-static int MCD_chStatus[NCHANNELS] = {
- MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA,
- MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA,
- MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA,
- MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA
-};
-
-/* Prototypes for local functions */
-static void MCD_memcpy(int *dest, int *src, u32 size);
-static void MCD_resmActions(int channel);
-
-/*
- * Buffer descriptors used for storage of progress info for single Dmas
- * Also used as storage for the DMA for CRCs for single DMAs
- * Otherwise, the DMA does not parse these buffer descriptors
- */
-#ifdef MCD_INCLUDE_EU
-extern MCD_bufDesc MCD_singleBufDescs[NCHANNELS];
-#else
-MCD_bufDesc MCD_singleBufDescs[NCHANNELS];
-#endif
-MCD_bufDesc *MCD_relocBuffDesc;
-
-/* Defines for the debug control register's functions */
-#define DBG_CTL_COMP1_TASK (0x00002000)
-#define DBG_CTL_ENABLE (DBG_CTL_AUTO_ARM | \
- DBG_CTL_BREAK | \
- DBG_CTL_INT_BREAK | \
- DBG_CTL_COMP1_TASK)
-#define DBG_CTL_DISABLE (DBG_CTL_AUTO_ARM | \
- DBG_CTL_INT_BREAK | \
- DBG_CTL_COMP1_TASK)
-#define DBG_KILL_ALL_STAT (0xFFFFFFFF)
-
-/* Offset to context save area where progress info is stored */
-#define CSAVE_OFFSET 10
-
-/* Defines for Byte Swapping */
-#define MCD_BYTE_SWAP_KILLER 0xFFF8888F
-#define MCD_NO_BYTE_SWAP_ATALL 0x00040000
-
-/* Execution Unit Identifiers */
-#define MAC 0 /* legacy - not used */
-#define LUAC 1 /* legacy - not used */
-#define CRC 2 /* legacy - not used */
-#define LURC 3 /* Logic Unit with CRC */
-
-/* Task Identifiers */
-#define TASK_CHAINNOEU 0
-#define TASK_SINGLENOEU 1
-#ifdef MCD_INCLUDE_EU
-#define TASK_CHAINEU 2
-#define TASK_SINGLEEU 3
-#define TASK_FECRX 4
-#define TASK_FECTX 5
-#else
-#define TASK_CHAINEU 0
-#define TASK_SINGLEEU 1
-#define TASK_FECRX 2
-#define TASK_FECTX 3
-#endif
-
-/*
- * Structure to remember which variant is on which channel
- * TBD- need this?
- */
-typedef struct MCD_remVariants_struct MCD_remVariant;
-struct MCD_remVariants_struct {
- int remDestRsdIncr[NCHANNELS]; /* -1,0,1 */
- int remSrcRsdIncr[NCHANNELS]; /* -1,0,1 */
- s16 remDestIncr[NCHANNELS]; /* DestIncr */
- s16 remSrcIncr[NCHANNELS]; /* srcIncr */
- u32 remXferSize[NCHANNELS]; /* xferSize */
-};
-
-/* Structure to remember the startDma parameters for each channel */
-MCD_remVariant MCD_remVariants;
-/********************************************************************/
-/* Function: MCD_initDma
- * Purpose: Initializes the DMA API by setting up a pointer to the DMA
- * registers, relocating and creating the appropriate task
- * structures, and setting up some global settings
- * Arguments:
- * dmaBarAddr - pointer to the multichannel DMA registers
- * taskTableDest - location to move DMA task code and structs to
- * flags - operational parameters
- * Return Value:
- * MCD_TABLE_UNALIGNED if taskTableDest is not 512-byte aligned
- * MCD_OK otherwise
- */
-extern u32 MCD_funcDescTab0[];
-
-int MCD_initDma(dmaRegs * dmaBarAddr, void *taskTableDest, u32 flags)
-{
- int i;
- TaskTableEntry *entryPtr;
-
- /* setup the local pointer to register set */
- MCD_dmaBar = dmaBarAddr;
-
- /* do we need to move/create a task table */
- if ((flags & MCD_RELOC_TASKS) != 0) {
- int fixedSize;
- u32 *fixedPtr;
- /*int *tablePtr = taskTableDest;TBD */
- int varTabsOffset, funcDescTabsOffset, contextSavesOffset;
- int taskDescTabsOffset;
- int taskTableSize, varTabsSize, funcDescTabsSize,
- contextSavesSize;
- int taskDescTabSize;
-
- int i;
-
- /* check if physical address is aligned on 512 byte boundary */
- if (((u32) taskTableDest & 0x000001ff) != 0)
- return (MCD_TABLE_UNALIGNED);
-
- /* set up local pointer to task Table */
- MCD_taskTable = taskTableDest;
-
- /*
- * Create a task table:
- * - compute aligned base offsets for variable tables and
- * function descriptor tables, then
- * - loop through the task table and setup the pointers
- * - copy over model task table with the the actual task
- * descriptor tables
- */
-
- taskTableSize = NCHANNELS * sizeof(TaskTableEntry);
- /* align variable tables to size */
- varTabsOffset = taskTableSize + (u32) taskTableDest;
- if ((varTabsOffset & (VAR_TAB_SIZE - 1)) != 0)
- varTabsOffset =
- (varTabsOffset + VAR_TAB_SIZE) & (~VAR_TAB_SIZE);
- /* align function descriptor tables */
- varTabsSize = NCHANNELS * VAR_TAB_SIZE;
- funcDescTabsOffset = varTabsOffset + varTabsSize;
-
- if ((funcDescTabsOffset & (FUNCDESC_TAB_SIZE - 1)) != 0)
- funcDescTabsOffset =
- (funcDescTabsOffset +
- FUNCDESC_TAB_SIZE) & (~FUNCDESC_TAB_SIZE);
-
- funcDescTabsSize = FUNCDESC_TAB_NUM * FUNCDESC_TAB_SIZE;
- contextSavesOffset = funcDescTabsOffset + funcDescTabsSize;
- contextSavesSize = (NCHANNELS * CONTEXT_SAVE_SIZE);
- fixedSize =
- taskTableSize + varTabsSize + funcDescTabsSize +
- contextSavesSize;
-
- /* zero the thing out */
- fixedPtr = (u32 *) taskTableDest;
- for (i = 0; i < (fixedSize / 4); i++)
- fixedPtr[i] = 0;
-
- entryPtr = (TaskTableEntry *) MCD_taskTable;
- /* set up fixed pointers */
- for (i = 0; i < NCHANNELS; i++) {
- /* update ptr to local value */
- entryPtr[i].varTab = (u32) varTabsOffset;
- entryPtr[i].FDTandFlags =
- (u32) funcDescTabsOffset | MCD_TT_FLAGS_DEF;
- entryPtr[i].contextSaveSpace = (u32) contextSavesOffset;
- varTabsOffset += VAR_TAB_SIZE;
-#ifdef MCD_INCLUDE_EU
- /* if not there is only one, just point to the
- same one */
- funcDescTabsOffset += FUNCDESC_TAB_SIZE;
-#endif
- contextSavesOffset += CONTEXT_SAVE_SIZE;
- }
- /* copy over the function descriptor table */
- for (i = 0; i < FUNCDESC_TAB_NUM; i++) {
- MCD_memcpy((void *)(entryPtr[i].
- FDTandFlags & ~MCD_TT_FLAGS_MASK),
- (void *)MCD_funcDescTab0, FUNCDESC_TAB_SIZE);
- }
-
- /* copy model task table to where the context saves stuff
- leaves off */
- MCD_modelTaskTable = (TaskTableEntry *) contextSavesOffset;
-
- MCD_memcpy((void *)MCD_modelTaskTable,
- (void *)MCD_modelTaskTableSrc,
- NUMOFVARIANTS * sizeof(TaskTableEntry));
-
- /* point to local version of model task table */
- entryPtr = MCD_modelTaskTable;
- taskDescTabsOffset = (u32) MCD_modelTaskTable +
- (NUMOFVARIANTS * sizeof(TaskTableEntry));
-
- /* copy actual task code and update TDT ptrs in local
- model task table */
- for (i = 0; i < NUMOFVARIANTS; i++) {
- taskDescTabSize =
- entryPtr[i].TDTend - entryPtr[i].TDTstart + 4;
- MCD_memcpy((void *)taskDescTabsOffset,
- (void *)entryPtr[i].TDTstart,
- taskDescTabSize);
- entryPtr[i].TDTstart = (u32) taskDescTabsOffset;
- taskDescTabsOffset += taskDescTabSize;
- entryPtr[i].TDTend = (u32) taskDescTabsOffset - 4;
- }
-#ifdef MCD_INCLUDE_EU
- /* Tack single DMA BDs onto end of code so API controls
- where they are since DMA might write to them */
- MCD_relocBuffDesc =
- (MCD_bufDesc *) (entryPtr[NUMOFVARIANTS - 1].TDTend + 4);
-#else
- /* DMA does not touch them so they can be wherever and we
- don't need to waste SRAM on them */
- MCD_relocBuffDesc = MCD_singleBufDescs;
-#endif
- } else {
- /* point the would-be relocated task tables and the
- buffer descriptors to the ones the linker generated */
-
- if (((u32) MCD_realTaskTableSrc & 0x000001ff) != 0)
- return (MCD_TABLE_UNALIGNED);
-
- /* need to add code to make sure that every thing else is
- aligned properly TBD. this is problematic if we init
- more than once or after running tasks, need to add
- variable to see if we have aleady init'd */
- entryPtr = MCD_realTaskTableSrc;
- for (i = 0; i < NCHANNELS; i++) {
- if (((entryPtr[i].varTab & (VAR_TAB_SIZE - 1)) != 0) ||
- ((entryPtr[i].
- FDTandFlags & (FUNCDESC_TAB_SIZE - 1)) != 0))
- return (MCD_TABLE_UNALIGNED);
- }
-
- MCD_taskTable = MCD_realTaskTableSrc;
- MCD_modelTaskTable = MCD_modelTaskTableSrc;
- MCD_relocBuffDesc = MCD_singleBufDescs;
- }
-
- /* Make all channels as totally inactive, and remember them as such: */
-
- MCD_dmaBar->taskbar = (u32) MCD_taskTable;
- for (i = 0; i < NCHANNELS; i++) {
- MCD_dmaBar->taskControl[i] = 0x0;
- MCD_chStatus[i] = MCD_NO_DMA;
- }
-
- /* Set up pausing mechanism to inactive state: */
- /* no particular values yet for either comparator registers */
- MCD_dmaBar->debugComp1 = 0;
- MCD_dmaBar->debugComp2 = 0;
- MCD_dmaBar->debugControl = DBG_CTL_DISABLE;
- MCD_dmaBar->debugStatus = DBG_KILL_ALL_STAT;
-
- /* enable or disable commbus prefetch, really need an ifdef or
- something to keep from trying to set this in the 8220 */
- if ((flags & MCD_COMM_PREFETCH_EN) != 0)
- MCD_dmaBar->ptdControl &= ~PTD_CTL_COMM_PREFETCH;
- else
- MCD_dmaBar->ptdControl |= PTD_CTL_COMM_PREFETCH;
-
- return (MCD_OK);
-}
-
-/*********************** End of MCD_initDma() ***********************/
-
-/********************************************************************/
-/* Function: MCD_dmaStatus
- * Purpose: Returns the status of the DMA on the requested channel
- * Arguments: channel - channel number
- * Returns: Predefined status indicators
- */
-int MCD_dmaStatus(int channel)
-{
- u16 tcrValue;
-
- if ((channel < 0) || (channel >= NCHANNELS))
- return (MCD_CHANNEL_INVALID);
-
- tcrValue = MCD_dmaBar->taskControl[channel];
- if ((tcrValue & TASK_CTL_EN) == 0) { /* nothing running */
- /* if last reported with task enabled */
- if (MCD_chStatus[channel] == MCD_RUNNING
- || MCD_chStatus[channel] == MCD_IDLE)
- MCD_chStatus[channel] = MCD_DONE;
- } else { /* something is running */
-
- /* There are three possibilities: paused, running or idle. */
- if (MCD_chStatus[channel] == MCD_RUNNING
- || MCD_chStatus[channel] == MCD_IDLE) {
- MCD_dmaBar->ptdDebug = PTD_DBG_TSK_VLD_INIT;
- /* This register is selected to know which initiator is
- actually asserted. */
- if ((MCD_dmaBar->ptdDebug >> channel) & 0x1)
- MCD_chStatus[channel] = MCD_RUNNING;
- else
- MCD_chStatus[channel] = MCD_IDLE;
- /* do not change the status if it is already paused. */
- }
- }
- return MCD_chStatus[channel];
-}
-
-/******************** End of MCD_dmaStatus() ************************/
-
-/********************************************************************/
-/* Function: MCD_startDma
- * Ppurpose: Starts a particular kind of DMA
- * Arguments:
- * srcAddr - the channel on which to run the DMA
- * srcIncr - the address to move data from, or buffer-descriptor address
- * destAddr - the amount to increment the source address per transfer
- * destIncr - the address to move data to
- * dmaSize - the amount to increment the destination address per transfer
- * xferSize - the number bytes in of each data movement (1, 2, or 4)
- * initiator - what device initiates the DMA
- * priority - priority of the DMA
- * flags - flags describing the DMA
- * funcDesc - description of byte swapping, bit swapping, and CRC actions
- * srcAddrVirt - virtual buffer descriptor address TBD
- * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
- */
-
-int MCD_startDma(int channel, s8 * srcAddr, s16 srcIncr, s8 * destAddr,
- s16 destIncr, u32 dmaSize, u32 xferSize, u32 initiator,
- int priority, u32 flags, u32 funcDesc
-#ifdef MCD_NEED_ADDR_TRANS
- s8 * srcAddrVirt
-#endif
- )
-{
- int srcRsdIncr, destRsdIncr;
- int *cSave;
- short xferSizeIncr;
- int tcrCount = 0;
-#ifdef MCD_INCLUDE_EU
- u32 *realFuncArray;
-#endif
-
- if ((channel < 0) || (channel >= NCHANNELS))
- return (MCD_CHANNEL_INVALID);
-
- /* tbd - need to determine the proper response to a bad funcDesc when
- not including EU functions, for now, assign a benign funcDesc, but
- maybe should return an error */
-#ifndef MCD_INCLUDE_EU
- funcDesc = MCD_FUNC_NOEU1;
-#endif
-
-#ifdef MCD_DEBUG
- printf("startDma:Setting up params\n");
-#endif
- /* Set us up for task-wise priority. We don't technically need to do
- this on every start, but since the register involved is in the same
- longword as other registers that users are in control of, setting
- it more than once is probably preferable. That since the
- documentation doesn't seem to be completely consistent about the
- nature of the PTD control register. */
- MCD_dmaBar->ptdControl |= (u16) 0x8000;
-
- /* Not sure what we need to keep here rtm TBD */
-#if 1
- /* Calculate additional parameters to the regular DMA calls. */
- srcRsdIncr = srcIncr < 0 ? -1 : (srcIncr > 0 ? 1 : 0);
- destRsdIncr = destIncr < 0 ? -1 : (destIncr > 0 ? 1 : 0);
-
- xferSizeIncr = (xferSize & 0xffff) | 0x20000000;
-
- /* Remember for each channel which variant is running. */
- MCD_remVariants.remSrcRsdIncr[channel] = srcRsdIncr;
- MCD_remVariants.remDestRsdIncr[channel] = destRsdIncr;
- MCD_remVariants.remDestIncr[channel] = destIncr;
- MCD_remVariants.remSrcIncr[channel] = srcIncr;
- MCD_remVariants.remXferSize[channel] = xferSize;
-#endif
-
- cSave =
- (int *)(MCD_taskTable[channel].contextSaveSpace) + CSAVE_OFFSET +
- CURRBD;
-
-#ifdef MCD_INCLUDE_EU
- /* may move this to EU specific calls */
- realFuncArray =
- (u32 *) (MCD_taskTable[channel].FDTandFlags & 0xffffff00);
- /* Modify the LURC's normal and byte-residue-loop functions according
- to parameter. */
- realFuncArray[(LURC * 16)] = xferSize == 4 ?
- funcDesc : xferSize == 2 ?
- funcDesc & 0xfffff00f : funcDesc & 0xffff000f;
- realFuncArray[(LURC * 16 + 1)] =
- (funcDesc & MCD_BYTE_SWAP_KILLER) | MCD_NO_BYTE_SWAP_ATALL;
-#endif
- /* Write the initiator field in the TCR, and also set the
- initiator-hold bit. Note that,due to a hardware quirk, this could
- collide with an MDE access to the initiator-register file, so we
- have to verify that the write reads back correctly. */
-
- MCD_dmaBar->taskControl[channel] =
- (initiator << 8) | TASK_CTL_HIPRITSKEN | TASK_CTL_HLDINITNUM;
-
- while (((MCD_dmaBar->taskControl[channel] & 0x1fff) !=
- ((initiator << 8) | TASK_CTL_HIPRITSKEN | TASK_CTL_HLDINITNUM))
- && (tcrCount < 1000)) {
- tcrCount++;
- /*MCD_dmaBar->ptd_tcr[channel] = (initiator << 8) | 0x0020; */
- MCD_dmaBar->taskControl[channel] =
- (initiator << 8) | TASK_CTL_HIPRITSKEN |
- TASK_CTL_HLDINITNUM;
- }
-
- MCD_dmaBar->priority[channel] = (u8) priority & PRIORITY_PRI_MASK;
- /* should be albe to handle this stuff with only one write to ts reg
- - tbd */
- if (channel < 8 && channel >= 0) {
- MCD_dmaBar->taskSize0 &= ~(0xf << (7 - channel) * 4);
- MCD_dmaBar->taskSize0 |=
- (xferSize & 3) << (((7 - channel) * 4) + 2);
- MCD_dmaBar->taskSize0 |= (xferSize & 3) << ((7 - channel) * 4);
- } else {
- MCD_dmaBar->taskSize1 &= ~(0xf << (15 - channel) * 4);
- MCD_dmaBar->taskSize1 |=
- (xferSize & 3) << (((15 - channel) * 4) + 2);
- MCD_dmaBar->taskSize1 |= (xferSize & 3) << ((15 - channel) * 4);
- }
-
- /* setup task table flags/options which mostly control the line
- buffers */
- MCD_taskTable[channel].FDTandFlags &= ~MCD_TT_FLAGS_MASK;
- MCD_taskTable[channel].FDTandFlags |= (MCD_TT_FLAGS_MASK & flags);
-
- if (flags & MCD_FECTX_DMA) {
- /* TDTStart and TDTEnd */
- MCD_taskTable[channel].TDTstart =
- MCD_modelTaskTable[TASK_FECTX].TDTstart;
- MCD_taskTable[channel].TDTend =
- MCD_modelTaskTable[TASK_FECTX].TDTend;
- MCD_startDmaENetXmit((char *)srcAddr, (char *)srcAddr,
- (char *)destAddr, MCD_taskTable,
- channel);
- } else if (flags & MCD_FECRX_DMA) {
- /* TDTStart and TDTEnd */
- MCD_taskTable[channel].TDTstart =
- MCD_modelTaskTable[TASK_FECRX].TDTstart;
- MCD_taskTable[channel].TDTend =
- MCD_modelTaskTable[TASK_FECRX].TDTend;
- MCD_startDmaENetRcv((char *)srcAddr, (char *)srcAddr,
- (char *)destAddr, MCD_taskTable,
- channel);
- } else if (flags & MCD_SINGLE_DMA) {
- /* this buffer descriptor is used for storing off initial
- parameters for later progress query calculation and for the
- DMA to write the resulting checksum. The DMA does not use
- this to determine how to operate, that info is passed with
- the init routine */
- MCD_relocBuffDesc[channel].srcAddr = srcAddr;
- MCD_relocBuffDesc[channel].destAddr = destAddr;
-
- /* definitely not its final value */
- MCD_relocBuffDesc[channel].lastDestAddr = destAddr;
-
- MCD_relocBuffDesc[channel].dmaSize = dmaSize;
- MCD_relocBuffDesc[channel].flags = 0; /* not used */
- MCD_relocBuffDesc[channel].csumResult = 0; /* not used */
- MCD_relocBuffDesc[channel].next = 0; /* not used */
-
- /* Initialize the progress-querying stuff to show no
- progress: */
- ((volatile int *)MCD_taskTable[channel].
- contextSaveSpace)[SRCPTR + CSAVE_OFFSET] = (int)srcAddr;
- ((volatile int *)MCD_taskTable[channel].
- contextSaveSpace)[DESTPTR + CSAVE_OFFSET] = (int)destAddr;
- ((volatile int *)MCD_taskTable[channel].
- contextSaveSpace)[DCOUNT + CSAVE_OFFSET] = 0;
- ((volatile int *)MCD_taskTable[channel].
- contextSaveSpace)[CURRBD + CSAVE_OFFSET] =
-(u32) & (MCD_relocBuffDesc[channel]);
- /* tbd - need to keep the user from trying to call the EU
- routine when MCD_INCLUDE_EU is not defined */
- if (funcDesc == MCD_FUNC_NOEU1 || funcDesc == MCD_FUNC_NOEU2) {
- /* TDTStart and TDTEnd */
- MCD_taskTable[channel].TDTstart =
- MCD_modelTaskTable[TASK_SINGLENOEU].TDTstart;
- MCD_taskTable[channel].TDTend =
- MCD_modelTaskTable[TASK_SINGLENOEU].TDTend;
- MCD_startDmaSingleNoEu((char *)srcAddr, srcIncr,
- (char *)destAddr, destIncr,
- (int)dmaSize, xferSizeIncr,
- flags, (int *)
- &(MCD_relocBuffDesc[channel]),
- cSave, MCD_taskTable, channel);
- } else {
- /* TDTStart and TDTEnd */
- MCD_taskTable[channel].TDTstart =
- MCD_modelTaskTable[TASK_SINGLEEU].TDTstart;
- MCD_taskTable[channel].TDTend =
- MCD_modelTaskTable[TASK_SINGLEEU].TDTend;
- MCD_startDmaSingleEu((char *)srcAddr, srcIncr,
- (char *)destAddr, destIncr,
- (int)dmaSize, xferSizeIncr,
- flags, (int *)
- &(MCD_relocBuffDesc[channel]),
- cSave, MCD_taskTable, channel);
- }
- } else { /* chained DMAS */
- /* Initialize the progress-querying stuff to show no
- progress: */
-#if 1
- /* (!defined(MCD_NEED_ADDR_TRANS)) */
- ((volatile int *)MCD_taskTable[channel].
- contextSaveSpace)[SRCPTR + CSAVE_OFFSET]
- = (int)((MCD_bufDesc *) srcAddr)->srcAddr;
- ((volatile int *)MCD_taskTable[channel].
- contextSaveSpace)[DESTPTR + CSAVE_OFFSET]
- = (int)((MCD_bufDesc *) srcAddr)->destAddr;
-#else
- /* if using address translation, need the virtual addr of the
- first buffdesc */
- ((volatile int *)MCD_taskTable[channel].
- contextSaveSpace)[SRCPTR + CSAVE_OFFSET]
- = (int)((MCD_bufDesc *) srcAddrVirt)->srcAddr;
- ((volatile int *)MCD_taskTable[channel].
- contextSaveSpace)[DESTPTR + CSAVE_OFFSET]
- = (int)((MCD_bufDesc *) srcAddrVirt)->destAddr;
-#endif
- ((volatile int *)MCD_taskTable[channel].
- contextSaveSpace)[DCOUNT + CSAVE_OFFSET] = 0;
- ((volatile int *)MCD_taskTable[channel].
- contextSaveSpace)[CURRBD + CSAVE_OFFSET] = (u32) srcAddr;
-
- if (funcDesc == MCD_FUNC_NOEU1 || funcDesc == MCD_FUNC_NOEU2) {
- /*TDTStart and TDTEnd */
- MCD_taskTable[channel].TDTstart =
- MCD_modelTaskTable[TASK_CHAINNOEU].TDTstart;
- MCD_taskTable[channel].TDTend =
- MCD_modelTaskTable[TASK_CHAINNOEU].TDTend;
- MCD_startDmaChainNoEu((int *)srcAddr, srcIncr,
- destIncr, xferSize,
- xferSizeIncr, cSave,
- MCD_taskTable, channel);
- } else {
- /*TDTStart and TDTEnd */
- MCD_taskTable[channel].TDTstart =
- MCD_modelTaskTable[TASK_CHAINEU].TDTstart;
- MCD_taskTable[channel].TDTend =
- MCD_modelTaskTable[TASK_CHAINEU].TDTend;
- MCD_startDmaChainEu((int *)srcAddr, srcIncr, destIncr,
- xferSize, xferSizeIncr, cSave,
- MCD_taskTable, channel);
- }
- }
- MCD_chStatus[channel] = MCD_IDLE;
- return (MCD_OK);
-}
-
-/************************ End of MCD_startDma() *********************/
-
-/********************************************************************/
-/* Function: MCD_XferProgrQuery
- * Purpose: Returns progress of DMA on requested channel
- * Arguments: channel - channel to retrieve progress for
- * progRep - pointer to user supplied MCD_XferProg struct
- * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
- *
- * Notes:
- * MCD_XferProgrQuery() upon completing or after aborting a DMA, or
- * while the DMA is in progress, this function returns the first
- * DMA-destination address not (or not yet) used in the DMA. When
- * encountering a non-ready buffer descriptor, the information for
- * the last completed descriptor is returned.
- *
- * MCD_XferProgQuery() has to avoid the possibility of getting
- * partially-updated information in the event that we should happen
- * to query DMA progress just as the DMA is updating it. It does that
- * by taking advantage of the fact context is not saved frequently for
- * the most part. We therefore read it at least twice until we get the
- * same information twice in a row.
- *
- * Because a small, but not insignificant, amount of time is required
- * to write out the progress-query information, especially upon
- * completion of the DMA, it would be wise to guarantee some time lag
- * between successive readings of the progress-query information.
- */
-
-/* How many iterations of the loop below to execute to stabilize values */
-#define STABTIME 0
-
-int MCD_XferProgrQuery(int channel, MCD_XferProg * progRep)
-{
- MCD_XferProg prevRep;
- int again; /* true if we are to try again to ge
- consistent results */
- int i; /* used as a time-waste counter */
- int destDiffBytes; /* Total no of bytes that we think actually
- got xfered. */
- int numIterations; /* number of iterations */
- int bytesNotXfered; /* bytes that did not get xfered. */
- s8 *LWAlignedInitDestAddr, *LWAlignedCurrDestAddr;
- int subModVal, addModVal; /* Mode values to added and subtracted
- from the final destAddr */
-
- if ((channel < 0) || (channel >= NCHANNELS))
- return (MCD_CHANNEL_INVALID);
-
- /* Read a trial value for the progress-reporting values */
- prevRep.lastSrcAddr =
- (s8 *) ((volatile int *)MCD_taskTable[channel].
- contextSaveSpace)[SRCPTR + CSAVE_OFFSET];
- prevRep.lastDestAddr =
- (s8 *) ((volatile int *)MCD_taskTable[channel].
- contextSaveSpace)[DESTPTR + CSAVE_OFFSET];
- prevRep.dmaSize =
- ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[DCOUNT +
- CSAVE_OFFSET];
- prevRep.currBufDesc =
- (MCD_bufDesc *) ((volatile int *)MCD_taskTable[channel].
- contextSaveSpace)[CURRBD + CSAVE_OFFSET];
- /* Repeatedly reread those values until they match previous values: */
- do {
- /* Waste a little bit of time to ensure stability: */
- for (i = 0; i < STABTIME; i++) {
- /* make sure this loop does something so that it
- doesn't get optimized out */
- i += i >> 2;
- }
- /* Check them again: */
- progRep->lastSrcAddr =
- (s8 *) ((volatile int *)MCD_taskTable[channel].
- contextSaveSpace)[SRCPTR + CSAVE_OFFSET];
- progRep->lastDestAddr =
- (s8 *) ((volatile int *)MCD_taskTable[channel].
- contextSaveSpace)[DESTPTR + CSAVE_OFFSET];
- progRep->dmaSize =
- ((volatile int *)MCD_taskTable[channel].
- contextSaveSpace)[DCOUNT + CSAVE_OFFSET];
- progRep->currBufDesc =
- (MCD_bufDesc *) ((volatile int *)MCD_taskTable[channel].
- contextSaveSpace)[CURRBD + CSAVE_OFFSET];
- /* See if they match: */
- if (prevRep.lastSrcAddr != progRep->lastSrcAddr
- || prevRep.lastDestAddr != progRep->lastDestAddr
- || prevRep.dmaSize != progRep->dmaSize
- || prevRep.currBufDesc != progRep->currBufDesc) {
- /* If they don't match, remember previous values and
- try again: */
- prevRep.lastSrcAddr = progRep->lastSrcAddr;
- prevRep.lastDestAddr = progRep->lastDestAddr;
- prevRep.dmaSize = progRep->dmaSize;
- prevRep.currBufDesc = progRep->currBufDesc;
- again = MCD_TRUE;
- } else
- again = MCD_FALSE;
- } while (again == MCD_TRUE);
-
- /* Update the dCount, srcAddr and destAddr */
- /* To calculate dmaCount, we consider destination address. C
- overs M1,P1,Z for destination */
- switch (MCD_remVariants.remDestRsdIncr[channel]) {
- case MINUS1:
- subModVal =
- ((int)progRep->
- lastDestAddr) & ((MCD_remVariants.remXferSize[channel]) -
- 1);
- addModVal =
- ((int)progRep->currBufDesc->
- destAddr) & ((MCD_remVariants.remXferSize[channel]) - 1);
- LWAlignedInitDestAddr =
- (progRep->currBufDesc->destAddr) - addModVal;
- LWAlignedCurrDestAddr = (progRep->lastDestAddr) - subModVal;
- destDiffBytes = LWAlignedInitDestAddr - LWAlignedCurrDestAddr;
- bytesNotXfered =
- (destDiffBytes / MCD_remVariants.remDestIncr[channel]) *
- (MCD_remVariants.remDestIncr[channel]
- + MCD_remVariants.remXferSize[channel]);
- progRep->dmaSize =
- destDiffBytes - bytesNotXfered + addModVal - subModVal;
- break;
- case ZERO:
- progRep->lastDestAddr = progRep->currBufDesc->destAddr;
- break;
- case PLUS1:
- /* This value has to be subtracted from the final
- calculated dCount. */
- subModVal =
- ((int)progRep->currBufDesc->
- destAddr) & ((MCD_remVariants.remXferSize[channel]) - 1);
- /* These bytes are already in lastDestAddr. */
- addModVal =
- ((int)progRep->
- lastDestAddr) & ((MCD_remVariants.remXferSize[channel]) -
- 1);
- LWAlignedInitDestAddr =
- (progRep->currBufDesc->destAddr) - subModVal;
- LWAlignedCurrDestAddr = (progRep->lastDestAddr) - addModVal;
- destDiffBytes = (progRep->lastDestAddr - LWAlignedInitDestAddr);
- numIterations =
- (LWAlignedCurrDestAddr -
- LWAlignedInitDestAddr) /
- MCD_remVariants.remDestIncr[channel];
- bytesNotXfered =
- numIterations * (MCD_remVariants.remDestIncr[channel]
- - MCD_remVariants.remXferSize[channel]);
- progRep->dmaSize = destDiffBytes - bytesNotXfered - subModVal;
- break;
- default:
- break;
- }
-
- /* This covers M1,P1,Z for source */
- switch (MCD_remVariants.remSrcRsdIncr[channel]) {
- case MINUS1:
- progRep->lastSrcAddr =
- progRep->currBufDesc->srcAddr +
- (MCD_remVariants.remSrcIncr[channel] *
- (progRep->dmaSize / MCD_remVariants.remXferSize[channel]));
- break;
- case ZERO:
- progRep->lastSrcAddr = progRep->currBufDesc->srcAddr;
- break;
- case PLUS1:
- progRep->lastSrcAddr =
- progRep->currBufDesc->srcAddr +
- (MCD_remVariants.remSrcIncr[channel] *
- (progRep->dmaSize / MCD_remVariants.remXferSize[channel]));
- break;
- default:
- break;
- }
-
- return (MCD_OK);
-}
-
-/******************* End of MCD_XferProgrQuery() ********************/
-
-/********************************************************************/
-/* MCD_resmActions() does the majority of the actions of a DMA resume.
- * It is called from MCD_killDma() and MCD_resumeDma(). It has to be
- * a separate function because the kill function has to negate the task
- * enable before resuming it, but the resume function has to do nothing
- * if there is no DMA on that channel (i.e., if the enable bit is 0).
- */
-static void MCD_resmActions(int channel)
-{
- MCD_dmaBar->debugControl = DBG_CTL_DISABLE;
- MCD_dmaBar->debugStatus = MCD_dmaBar->debugStatus;
- /* This register is selected to know which initiator is
- actually asserted. */
- MCD_dmaBar->ptdDebug = PTD_DBG_TSK_VLD_INIT;
-
- if ((MCD_dmaBar->ptdDebug >> channel) & 0x1)
- MCD_chStatus[channel] = MCD_RUNNING;
- else
- MCD_chStatus[channel] = MCD_IDLE;
-}
-
-/********************* End of MCD_resmActions() *********************/
-
-/********************************************************************/
-/* Function: MCD_killDma
- * Purpose: Halt the DMA on the requested channel, without any
- * intention of resuming the DMA.
- * Arguments: channel - requested channel
- * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
- *
- * Notes:
- * A DMA may be killed from any state, including paused state, and it
- * always goes to the MCD_HALTED state even if it is killed while in
- * the MCD_NO_DMA or MCD_IDLE states.
- */
-int MCD_killDma(int channel)
-{
- /* MCD_XferProg progRep; */
-
- if ((channel < 0) || (channel >= NCHANNELS))
- return (MCD_CHANNEL_INVALID);
-
- MCD_dmaBar->taskControl[channel] = 0x0;
- MCD_resumeDma(channel);
- /*
- * This must be after the write to the TCR so that the task doesn't
- * start up again momentarily, and before the status assignment so
- * as to override whatever MCD_resumeDma() may do to the channel
- * status.
- */
- MCD_chStatus[channel] = MCD_HALTED;
-
- /*
- * Update the current buffer descriptor's lastDestAddr field
- *
- * MCD_XferProgrQuery (channel, &progRep);
- * progRep.currBufDesc->lastDestAddr = progRep.lastDestAddr;
- */
- return (MCD_OK);
-}
-
-/************************ End of MCD_killDma() **********************/
-
-/********************************************************************/
-/* Function: MCD_continDma
- * Purpose: Continue a DMA which as stopped due to encountering an
- * unready buffer descriptor.
- * Arguments: channel - channel to continue the DMA on
- * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
- *
- * Notes:
- * This routine does not check to see if there is a task which can
- * be continued. Also this routine should not be used with single DMAs.
- */
-int MCD_continDma(int channel)
-{
- if ((channel < 0) || (channel >= NCHANNELS))
- return (MCD_CHANNEL_INVALID);
-
- MCD_dmaBar->taskControl[channel] |= TASK_CTL_EN;
- MCD_chStatus[channel] = MCD_RUNNING;
-
- return (MCD_OK);
-}
-
-/********************** End of MCD_continDma() **********************/
-
-/*********************************************************************
- * MCD_pauseDma() and MCD_resumeDma() below use the DMA's debug unit
- * to freeze a task and resume it. We freeze a task by breakpointing
- * on the stated task. That is, not any specific place in the task,
- * but any time that task executes. In particular, when that task
- * executes, we want to freeze that task and only that task.
- *
- * The bits of the debug control register influence interrupts vs.
- * breakpoints as follows:
- * - Bits 14 and 0 enable or disable debug functions. If enabled, you
- * will get the interrupt but you may or may not get a breakpoint.
- * - Bits 2 and 1 decide whether you also get a breakpoint in addition
- * to an interrupt.
- *
- * The debug unit can do these actions in response to either internally
- * detected breakpoint conditions from the comparators, or in response
- * to the external breakpoint pin, or both.
- * - Bits 14 and 1 perform the above-described functions for
- * internally-generated conditions, i.e., the debug comparators.
- * - Bits 0 and 2 perform the above-described functions for external
- * conditions, i.e., the breakpoint external pin.
- *
- * Note that, although you "always" get the interrupt when you turn
- * the debug functions, the interrupt can nevertheless, if desired, be
- * masked by the corresponding bit in the PTD's IMR. Note also that
- * this means that bits 14 and 0 must enable debug functions before
- * bits 1 and 2, respectively, have any effect.
- *
- * NOTE: It's extremely important to not pause more than one DMA channel
- * at a time.
- ********************************************************************/
-
-/********************************************************************/
-/* Function: MCD_pauseDma
- * Purpose: Pauses the DMA on a given channel (if any DMA is running
- * on that channel).
- * Arguments: channel
- * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
- */
-int MCD_pauseDma(int channel)
-{
- /* MCD_XferProg progRep; */
-
- if ((channel < 0) || (channel >= NCHANNELS))
- return (MCD_CHANNEL_INVALID);
-
- if (MCD_dmaBar->taskControl[channel] & TASK_CTL_EN) {
- MCD_dmaBar->debugComp1 = channel;
- MCD_dmaBar->debugControl =
- DBG_CTL_ENABLE | (1 << (channel + 16));
- MCD_chStatus[channel] = MCD_PAUSED;
-
- /*
- * Update the current buffer descriptor's lastDestAddr field
- *
- * MCD_XferProgrQuery (channel, &progRep);
- * progRep.currBufDesc->lastDestAddr = progRep.lastDestAddr;
- */
- }
- return (MCD_OK);
-}
-
-/************************* End of MCD_pauseDma() ********************/
-
-/********************************************************************/
-/* Function: MCD_resumeDma
- * Purpose: Resumes the DMA on a given channel (if any DMA is
- * running on that channel).
- * Arguments: channel - channel on which to resume DMA
- * Returns: MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
- */
-int MCD_resumeDma(int channel)
-{
- if ((channel < 0) || (channel >= NCHANNELS))
- return (MCD_CHANNEL_INVALID);
-
- if (MCD_dmaBar->taskControl[channel] & TASK_CTL_EN)
- MCD_resmActions(channel);
-
- return (MCD_OK);
-}
-
-/************************ End of MCD_resumeDma() ********************/
-
-/********************************************************************/
-/* Function: MCD_csumQuery
- * Purpose: Provide the checksum after performing a non-chained DMA
- * Arguments: channel - channel to report on
- * csum - pointer to where to write the checksum/CRC
- * Returns: MCD_ERROR if the channel is invalid, else MCD_OK
- *
- * Notes:
- *
- */
-int MCD_csumQuery(int channel, u32 * csum)
-{
-#ifdef MCD_INCLUDE_EU
- if ((channel < 0) || (channel >= NCHANNELS))
- return (MCD_CHANNEL_INVALID);
-
- *csum = MCD_relocBuffDesc[channel].csumResult;
- return (MCD_OK);
-#else
- return (MCD_ERROR);
-#endif
-}
-
-/*********************** End of MCD_resumeDma() *********************/
-
-/********************************************************************/
-/* Function: MCD_getCodeSize
- * Purpose: Provide the size requirements of the microcoded tasks
- * Returns: Size in bytes
- */
-int MCD_getCodeSize(void)
-{
-#ifdef MCD_INCLUDE_EU
- return (0x2b5c);
-#else
- return (0x173c);
-#endif
-}
-
-/********************** End of MCD_getCodeSize() ********************/
-
-/********************************************************************/
-/* Function: MCD_getVersion
- * Purpose: Provide the version string and number
- * Arguments: longVersion - user supplied pointer to a pointer to a char
- * which points to the version string
- * Returns: Version number and version string (by reference)
- */
-char MCD_versionString[] = "Multi-channel DMA API Alpha v0.3 (2004-04-26)";
-#define MCD_REV_MAJOR 0x00
-#define MCD_REV_MINOR 0x03
-
-int MCD_getVersion(char **longVersion)
-{
- *longVersion = MCD_versionString;
- return ((MCD_REV_MAJOR << 8) | MCD_REV_MINOR);
-}
-
-/********************** End of MCD_getVersion() *********************/
-
-/********************************************************************/
-/* Private version of memcpy()
- * Note that everything this is used for is longword-aligned.
- */
-static void MCD_memcpy(int *dest, int *src, u32 size)
-{
- u32 i;
-
- for (i = 0; i < size; i += sizeof(int), dest++, src++)
- *dest = *src;
-}
diff --git a/drivers/dma/MCD_tasks.c b/drivers/dma/MCD_tasks.c
deleted file mode 100644
index 453d95413da..00000000000
--- a/drivers/dma/MCD_tasks.c
+++ /dev/null
@@ -1,2413 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
- */
-
-/* Contains task code and structures for Multi-channel DMA */
-
-#include <common.h>
-
-#include <MCD_dma.h>
-
-u32 MCD_varTab0[];
-u32 MCD_varTab1[];
-u32 MCD_varTab2[];
-u32 MCD_varTab3[];
-u32 MCD_varTab4[];
-u32 MCD_varTab5[];
-u32 MCD_varTab6[];
-u32 MCD_varTab7[];
-u32 MCD_varTab8[];
-u32 MCD_varTab9[];
-u32 MCD_varTab10[];
-u32 MCD_varTab11[];
-u32 MCD_varTab12[];
-u32 MCD_varTab13[];
-u32 MCD_varTab14[];
-u32 MCD_varTab15[];
-
-u32 MCD_funcDescTab0[];
-#ifdef MCD_INCLUDE_EU
-u32 MCD_funcDescTab1[];
-u32 MCD_funcDescTab2[];
-u32 MCD_funcDescTab3[];
-u32 MCD_funcDescTab4[];
-u32 MCD_funcDescTab5[];
-u32 MCD_funcDescTab6[];
-u32 MCD_funcDescTab7[];
-u32 MCD_funcDescTab8[];
-u32 MCD_funcDescTab9[];
-u32 MCD_funcDescTab10[];
-u32 MCD_funcDescTab11[];
-u32 MCD_funcDescTab12[];
-u32 MCD_funcDescTab13[];
-u32 MCD_funcDescTab14[];
-u32 MCD_funcDescTab15[];
-#endif
-
-u32 MCD_contextSave0[];
-u32 MCD_contextSave1[];
-u32 MCD_contextSave2[];
-u32 MCD_contextSave3[];
-u32 MCD_contextSave4[];
-u32 MCD_contextSave5[];
-u32 MCD_contextSave6[];
-u32 MCD_contextSave7[];
-u32 MCD_contextSave8[];
-u32 MCD_contextSave9[];
-u32 MCD_contextSave10[];
-u32 MCD_contextSave11[];
-u32 MCD_contextSave12[];
-u32 MCD_contextSave13[];
-u32 MCD_contextSave14[];
-u32 MCD_contextSave15[];
-
-u32 MCD_realTaskTableSrc[] = {
- 0x00000000,
- 0x00000000,
- (u32) MCD_varTab0, /* Task 0 Variable Table */
- (u32) MCD_funcDescTab0, /* Task 0 Fn Desc. Table & Flags */
- 0x00000000,
- 0x00000000,
- (u32) MCD_contextSave0, /* Task 0 context save space */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- (u32) MCD_varTab1, /* Task 1 Variable Table */
-#ifdef MCD_INCLUDE_EU
- (u32) MCD_funcDescTab1, /* Task 1 Fn Desc. Table & Flags */
-#else
- (u32) MCD_funcDescTab0, /* Task 0 Fn Desc. Table & Flags */
-#endif
- 0x00000000,
- 0x00000000,
- (u32) MCD_contextSave1, /* Task 1 context save space */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- (u32) MCD_varTab2, /* Task 2 Variable Table */
-#ifdef MCD_INCLUDE_EU
- (u32) MCD_funcDescTab2, /* Task 2 Fn Desc. Table & Flags */
-#else
- (u32) MCD_funcDescTab0, /* Task 0 Fn Desc. Table & Flags */
-#endif
- 0x00000000,
- 0x00000000,
- (u32) MCD_contextSave2, /* Task 2 context save space */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- (u32) MCD_varTab3, /* Task 3 Variable Table */
-#ifdef MCD_INCLUDE_EU
- (u32) MCD_funcDescTab3, /* Task 3 Fn Desc. Table & Flags */
-#else
- (u32) MCD_funcDescTab0, /* Task 0 Fn Desc. Table & Flags */
-#endif
- 0x00000000,
- 0x00000000,
- (u32) MCD_contextSave3, /* Task 3 context save space */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- (u32) MCD_varTab4, /* Task 4 Variable Table */
-#ifdef MCD_INCLUDE_EU
- (u32) MCD_funcDescTab4, /* Task 4 Fn Desc. Table & Flags */
-#else
- (u32) MCD_funcDescTab0, /* Task 0 Fn Desc. Table & Flags */
-#endif
- 0x00000000,
- 0x00000000,
- (u32) MCD_contextSave4, /* Task 4 context save space */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- (u32) MCD_varTab5, /* Task 5 Variable Table */
-#ifdef MCD_INCLUDE_EU
- (u32) MCD_funcDescTab5, /* Task 5 Fn Desc. Table & Flags */
-#else
- (u32) MCD_funcDescTab0, /* Task 0 Fn Desc. Table & Flags */
-#endif
- 0x00000000,
- 0x00000000,
- (u32) MCD_contextSave5, /* Task 5 context save space */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- (u32) MCD_varTab6, /* Task 6 Variable Table */
-#ifdef MCD_INCLUDE_EU
- (u32) MCD_funcDescTab6, /* Task 6 Fn Desc. Table & Flags */
-#else
- (u32) MCD_funcDescTab0, /* Task 0 Fn Desc. Table & Flags */
-#endif
- 0x00000000,
- 0x00000000,
- (u32) MCD_contextSave6, /* Task 6 context save space */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- (u32) MCD_varTab7, /* Task 7 Variable Table */
-#ifdef MCD_INCLUDE_EU
- (u32) MCD_funcDescTab7, /* Task 7 Fn Desc. Table & Flags */
-#else
- (u32) MCD_funcDescTab0, /* Task 0 Fn Desc. Table & Flags */
-#endif
- 0x00000000,
- 0x00000000,
- (u32) MCD_contextSave7, /* Task 7 context save space */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- (u32) MCD_varTab8, /* Task 8 Variable Table */
-#ifdef MCD_INCLUDE_EU
- (u32) MCD_funcDescTab8, /* Task 8 Fn Desc. Table & Flags */
-#else
- (u32) MCD_funcDescTab0, /* Task 0 Fn Desc. Table & Flags */
-#endif
- 0x00000000,
- 0x00000000,
- (u32) MCD_contextSave8, /* Task 8 context save space */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- (u32) MCD_varTab9, /* Task 9 Variable Table */
-#ifdef MCD_INCLUDE_EU
- (u32) MCD_funcDescTab9, /* Task 9 Fn Desc. Table & Flags */
-#else
- (u32) MCD_funcDescTab0, /* Task 0 Fn Desc. Table & Flags */
-#endif
- 0x00000000,
- 0x00000000,
- (u32) MCD_contextSave9, /* Task 9 context save space */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- (u32) MCD_varTab10, /* Task 10 Variable Table */
-#ifdef MCD_INCLUDE_EU
- (u32) MCD_funcDescTab10, /* Task 10 Fn Desc. Table & Flags */
-#else
- (u32) MCD_funcDescTab0, /* Task 0 Fn Desc. Table & Flags */
-#endif
- 0x00000000,
- 0x00000000,
- (u32) MCD_contextSave10, /* Task 10 context save space */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- (u32) MCD_varTab11, /* Task 11 Variable Table */
-#ifdef MCD_INCLUDE_EU
- (u32) MCD_funcDescTab11, /* Task 11 Fn Desc. Table & Flags */
-#else
- (u32) MCD_funcDescTab0, /* Task 0 Fn Desc. Table & Flags */
-#endif
- 0x00000000,
- 0x00000000,
- (u32) MCD_contextSave11, /* Task 11 context save space */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- (u32) MCD_varTab12, /* Task 12 Variable Table */
-#ifdef MCD_INCLUDE_EU
- (u32) MCD_funcDescTab12, /* Task 12 Fn Desc. Table & Flags */
-#else
- (u32) MCD_funcDescTab0, /* Task 0 Fn Desc. Table & Flags */
-#endif
- 0x00000000,
- 0x00000000,
- (u32) MCD_contextSave12, /* Task 12 context save space */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- (u32) MCD_varTab13, /* Task 13 Variable Table */
-#ifdef MCD_INCLUDE_EU
- (u32) MCD_funcDescTab13, /* Task 13 Fn Desc. Table & Flags */
-#else
- (u32) MCD_funcDescTab0, /* Task 0 Fn Desc. Table & Flags */
-#endif
- 0x00000000,
- 0x00000000,
- (u32) MCD_contextSave13, /* Task 13 context save space */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- (u32) MCD_varTab14, /* Task 14 Variable Table */
-#ifdef MCD_INCLUDE_EU
- (u32) MCD_funcDescTab14, /* Task 14 Fn Desc. Table & Flags */
-#else
- (u32) MCD_funcDescTab0, /* Task 0 Fn Desc. Table & Flags */
-#endif
- 0x00000000,
- 0x00000000,
- (u32) MCD_contextSave14, /* Task 14 context save space */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- (u32) MCD_varTab15, /* Task 15 Variable Table */
-#ifdef MCD_INCLUDE_EU
- (u32) MCD_funcDescTab15, /* Task 15 Fn Desc. Table & Flags */
-#else
- (u32) MCD_funcDescTab0, /* Task 0 Fn Desc. Table & Flags */
-#endif
- 0x00000000,
- 0x00000000,
- (u32) MCD_contextSave15, /* Task 15 context save space */
- 0x00000000,
-};
-
-u32 MCD_varTab0[] = { /* Task 0 Variable Table */
- 0x00000000, /* var[0] */
- 0x00000000, /* var[1] */
- 0x00000000, /* var[2] */
- 0x00000000, /* var[3] */
- 0x00000000, /* var[4] */
- 0x00000000, /* var[5] */
- 0x00000000, /* var[6] */
- 0x00000000, /* var[7] */
- 0x00000000, /* var[8] */
- 0x00000000, /* var[9] */
- 0x00000000, /* var[10] */
- 0x00000000, /* var[11] */
- 0x00000000, /* var[12] */
- 0x00000000, /* var[13] */
- 0x00000000, /* var[14] */
- 0x00000000, /* var[15] */
- 0x00000000, /* var[16] */
- 0x00000000, /* var[17] */
- 0x00000000, /* var[18] */
- 0x00000000, /* var[19] */
- 0x00000000, /* var[20] */
- 0x00000000, /* var[21] */
- 0x00000000, /* var[22] */
- 0x00000000, /* var[23] */
- 0xe0000000, /* inc[0] */
- 0x20000000, /* inc[1] */
- 0x2000ffff, /* inc[2] */
- 0x00000000, /* inc[3] */
- 0x00000000, /* inc[4] */
- 0x00000000, /* inc[5] */
- 0x00000000, /* inc[6] */
- 0x00000000, /* inc[7] */
-};
-
-u32 MCD_varTab1[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xe0000000,
- 0x20000000,
- 0x2000ffff,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-u32 MCD_varTab2[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xe0000000,
- 0x20000000,
- 0x2000ffff,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-u32 MCD_varTab3[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xe0000000,
- 0x20000000,
- 0x2000ffff,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-u32 MCD_varTab4[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xe0000000,
- 0x20000000,
- 0x2000ffff,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-u32 MCD_varTab5[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xe0000000,
- 0x20000000,
- 0x2000ffff,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-u32 MCD_varTab6[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xe0000000,
- 0x20000000,
- 0x2000ffff,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-u32 MCD_varTab7[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xe0000000,
- 0x20000000,
- 0x2000ffff,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-u32 MCD_varTab8[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xe0000000,
- 0x20000000,
- 0x2000ffff,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-u32 MCD_varTab9[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xe0000000,
- 0x20000000,
- 0x2000ffff,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-u32 MCD_varTab10[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xe0000000,
- 0x20000000,
- 0x2000ffff,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-u32 MCD_varTab11[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xe0000000,
- 0x20000000,
- 0x2000ffff,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-u32 MCD_varTab12[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xe0000000,
- 0x20000000,
- 0x2000ffff,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-u32 MCD_varTab13[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xe0000000,
- 0x20000000,
- 0x2000ffff,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-u32 MCD_varTab14[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xe0000000,
- 0x20000000,
- 0x2000ffff,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-u32 MCD_varTab15[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xe0000000,
- 0x20000000,
- 0x2000ffff,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-u32 MCD_funcDescTab0[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xa0045670,
- 0xa0000000,
- 0xa0000000,
- 0x20000000,
- 0x21800000,
- 0x21e00000,
- 0x20400000,
- 0x20500000,
- 0x205a0000,
- 0x20a00000,
- 0x202fa000,
- 0x202f9000,
- 0x202ea000,
- 0x202da000,
- 0x202e2000,
- 0x202f2000,
-};
-
-#ifdef MCD_INCLUDE_EU
-u32 MCD_funcDescTab1[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xa0045670,
- 0xa0000000,
- 0xa0000000,
- 0x20000000,
- 0x21800000,
- 0x21e00000,
- 0x20400000,
- 0x20500000,
- 0x205a0000,
- 0x20a00000,
- 0x202fa000,
- 0x202f9000,
- 0x202ea000,
- 0x202da000,
- 0x202e2000,
- 0x202f2000,
-};
-
-u32 MCD_funcDescTab2[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xa0045670,
- 0xa0000000,
- 0xa0000000,
- 0x20000000,
- 0x21800000,
- 0x21e00000,
- 0x20400000,
- 0x20500000,
- 0x205a0000,
- 0x20a00000,
- 0x202fa000,
- 0x202f9000,
- 0x202ea000,
- 0x202da000,
- 0x202e2000,
- 0x202f2000,
-};
-
-u32 MCD_funcDescTab3[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xa0045670,
- 0xa0000000,
- 0xa0000000,
- 0x20000000,
- 0x21800000,
- 0x21e00000,
- 0x20400000,
- 0x20500000,
- 0x205a0000,
- 0x20a00000,
- 0x202fa000,
- 0x202f9000,
- 0x202ea000,
- 0x202da000,
- 0x202e2000,
- 0x202f2000,
-};
-
-u32 MCD_funcDescTab4[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xa0045670,
- 0xa0000000,
- 0xa0000000,
- 0x20000000,
- 0x21800000,
- 0x21e00000,
- 0x20400000,
- 0x20500000,
- 0x205a0000,
- 0x20a00000,
- 0x202fa000,
- 0x202f9000,
- 0x202ea000,
- 0x202da000,
- 0x202e2000,
- 0x202f2000,
-};
-
-u32 MCD_funcDescTab5[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xa0045670,
- 0xa0000000,
- 0xa0000000,
- 0x20000000,
- 0x21800000,
- 0x21e00000,
- 0x20400000,
- 0x20500000,
- 0x205a0000,
- 0x20a00000,
- 0x202fa000,
- 0x202f9000,
- 0x202ea000,
- 0x202da000,
- 0x202e2000,
- 0x202f2000,
-};
-
-u32 MCD_funcDescTab6[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xa0045670,
- 0xa0000000,
- 0xa0000000,
- 0x20000000,
- 0x21800000,
- 0x21e00000,
- 0x20400000,
- 0x20500000,
- 0x205a0000,
- 0x20a00000,
- 0x202fa000,
- 0x202f9000,
- 0x202ea000,
- 0x202da000,
- 0x202e2000,
- 0x202f2000,
-};
-
-u32 MCD_funcDescTab7[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xa0045670,
- 0xa0000000,
- 0xa0000000,
- 0x20000000,
- 0x21800000,
- 0x21e00000,
- 0x20400000,
- 0x20500000,
- 0x205a0000,
- 0x20a00000,
- 0x202fa000,
- 0x202f9000,
- 0x202ea000,
- 0x202da000,
- 0x202e2000,
- 0x202f2000,
-};
-
-u32 MCD_funcDescTab8[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xa0045670,
- 0xa0000000,
- 0xa0000000,
- 0x20000000,
- 0x21800000,
- 0x21e00000,
- 0x20400000,
- 0x20500000,
- 0x205a0000,
- 0x20a00000,
- 0x202fa000,
- 0x202f9000,
- 0x202ea000,
- 0x202da000,
- 0x202e2000,
- 0x202f2000,
-};
-
-u32 MCD_funcDescTab9[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xa0045670,
- 0xa0000000,
- 0xa0000000,
- 0x20000000,
- 0x21800000,
- 0x21e00000,
- 0x20400000,
- 0x20500000,
- 0x205a0000,
- 0x20a00000,
- 0x202fa000,
- 0x202f9000,
- 0x202ea000,
- 0x202da000,
- 0x202e2000,
- 0x202f2000,
-};
-
-u32 MCD_funcDescTab10[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xa0045670,
- 0xa0000000,
- 0xa0000000,
- 0x20000000,
- 0x21800000,
- 0x21e00000,
- 0x20400000,
- 0x20500000,
- 0x205a0000,
- 0x20a00000,
- 0x202fa000,
- 0x202f9000,
- 0x202ea000,
- 0x202da000,
- 0x202e2000,
- 0x202f2000,
-};
-
-u32 MCD_funcDescTab11[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xa0045670,
- 0xa0000000,
- 0xa0000000,
- 0x20000000,
- 0x21800000,
- 0x21e00000,
- 0x20400000,
- 0x20500000,
- 0x205a0000,
- 0x20a00000,
- 0x202fa000,
- 0x202f9000,
- 0x202ea000,
- 0x202da000,
- 0x202e2000,
- 0x202f2000,
-};
-
-u32 MCD_funcDescTab12[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xa0045670,
- 0xa0000000,
- 0xa0000000,
- 0x20000000,
- 0x21800000,
- 0x21e00000,
- 0x20400000,
- 0x20500000,
- 0x205a0000,
- 0x20a00000,
- 0x202fa000,
- 0x202f9000,
- 0x202ea000,
- 0x202da000,
- 0x202e2000,
- 0x202f2000,
-};
-
-u32 MCD_funcDescTab13[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xa0045670,
- 0xa0000000,
- 0xa0000000,
- 0x20000000,
- 0x21800000,
- 0x21e00000,
- 0x20400000,
- 0x20500000,
- 0x205a0000,
- 0x20a00000,
- 0x202fa000,
- 0x202f9000,
- 0x202ea000,
- 0x202da000,
- 0x202e2000,
- 0x202f2000,
-};
-
-u32 MCD_funcDescTab14[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xa0045670,
- 0xa0000000,
- 0xa0000000,
- 0x20000000,
- 0x21800000,
- 0x21e00000,
- 0x20400000,
- 0x20500000,
- 0x205a0000,
- 0x20a00000,
- 0x202fa000,
- 0x202f9000,
- 0x202ea000,
- 0x202da000,
- 0x202e2000,
- 0x202f2000,
-};
-
-u32 MCD_funcDescTab15[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0xa0045670,
- 0xa0000000,
- 0xa0000000,
- 0x20000000,
- 0x21800000,
- 0x21e00000,
- 0x20400000,
- 0x20500000,
- 0x205a0000,
- 0x20a00000,
- 0x202fa000,
- 0x202f9000,
- 0x202ea000,
- 0x202da000,
- 0x202e2000,
- 0x202f2000,
-};
-#endif /*MCD_INCLUDE_EU */
-
-u32 MCD_contextSave0[128]; /* Task 0 context save space */
-u32 MCD_contextSave1[128]; /* Task 1 context save space */
-u32 MCD_contextSave2[128]; /* Task 2 context save space */
-u32 MCD_contextSave3[128]; /* Task 3 context save space */
-u32 MCD_contextSave4[128]; /* Task 4 context save space */
-u32 MCD_contextSave5[128]; /* Task 5 context save space */
-u32 MCD_contextSave6[128]; /* Task 6 context save space */
-u32 MCD_contextSave7[128]; /* Task 7 context save space */
-u32 MCD_contextSave8[128]; /* Task 8 context save space */
-u32 MCD_contextSave9[128]; /* Task 9 context save space */
-u32 MCD_contextSave10[128]; /* Task 10 context save space */
-u32 MCD_contextSave11[128]; /* Task 11 context save space */
-u32 MCD_contextSave12[128]; /* Task 12 context save space */
-u32 MCD_contextSave13[128]; /* Task 13 context save space */
-u32 MCD_contextSave14[128]; /* Task 14 context save space */
-u32 MCD_contextSave15[128]; /* Task 15 context save space */
-
-u32 MCD_ChainNoEu_TDT[];
-u32 MCD_SingleNoEu_TDT[];
-#ifdef MCD_INCLUDE_EU
-u32 MCD_ChainEu_TDT[];
-u32 MCD_SingleEu_TDT[];
-#endif
-u32 MCD_ENetRcv_TDT[];
-u32 MCD_ENetXmit_TDT[];
-
-u32 MCD_modelTaskTableSrc[] = {
- (u32) MCD_ChainNoEu_TDT,
- (u32) & ((u8 *) MCD_ChainNoEu_TDT)[0x0000016c],
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- (u32) MCD_SingleNoEu_TDT,
- (u32) & ((u8 *) MCD_SingleNoEu_TDT)[0x000000d4],
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-#ifdef MCD_INCLUDE_EU
- (u32) MCD_ChainEu_TDT,
- (u32) & ((u8 *) MCD_ChainEu_TDT)[0x000001b4],
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- (u32) MCD_SingleEu_TDT,
- (u32) & ((u8 *) MCD_SingleEu_TDT)[0x00000124],
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-#endif
- (u32) MCD_ENetRcv_TDT,
- (u32) & ((u8 *) MCD_ENetRcv_TDT)[0x0000009c],
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- (u32) MCD_ENetXmit_TDT,
- (u32) & ((u8 *) MCD_ENetXmit_TDT)[0x000000d0],
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-u32 MCD_ChainNoEu_TDT[] = {
- 0x80004000,
- 0x8118801b,
- 0xb8c60018,
- 0x10002b10,
- 0x7000000d,
- 0x018cf89f,
- 0x6000000a,
- 0x080cf89f,
- 0x000001f8,
- 0x98180364,
- 0x8118801b,
- 0xf8c6001a,
- 0xb8c6601b,
- 0x10002710,
- 0x00000f18,
- 0xb8c6001d,
- 0x10001310,
- 0x60000007,
- 0x014cf88b,
- 0x98c6001c,
- 0x00000710,
- 0x98c70018,
- 0x10001f10,
- 0x0000c818,
- 0x000001f8,
- 0xc1476018,
- 0xc003231d,
- 0x811a601b,
- 0xc1862102,
- 0x849be009,
- 0x03fed7b8,
- 0xda9b001b,
- 0x9b9be01b,
- 0x1000cb20,
- 0x70000006,
- 0x088cf88f,
- 0x1000cb28,
- 0x70000006,
- 0x088cf88f,
- 0x1000cb30,
- 0x70000006,
- 0x088cf88f,
- 0x1000cb38,
- 0x0000c728,
- 0x000001f8,
- 0xc1476018,
- 0xc003241d,
- 0x811a601b,
- 0xda9b001b,
- 0x9b9be01b,
- 0x0000d3a0,
- 0xc1862102,
- 0x849be009,
- 0x0bfed7b8,
- 0xda9b001b,
- 0x9b9be01b,
- 0x1000cb20,
- 0x70000006,
- 0x088cf88f,
- 0x1000cb28,
- 0x70000006,
- 0x088cf88f,
- 0x1000cb30,
- 0x70000006,
- 0x088cf88f,
- 0x1000cb38,
- 0x0000c728,
- 0x000001f8,
- 0x8118801b,
- 0xd8c60018,
- 0x98c6601c,
- 0x6000000b,
- 0x0c8cfc9f,
- 0x000001f8,
- 0xa146001e,
- 0x10000b08,
- 0x10002050,
- 0xb8c60018,
- 0x10002b10,
- 0x7000000a,
- 0x080cf89f,
- 0x6000000d,
- 0x018cf89f,
- 0x000001f8,
- 0x8618801b,
- 0x7000000e,
- 0x084cf21f,
- 0xd8990336,
- 0x8019801b,
- 0x040001f8,
- 0x000001f8,
- 0x000001f8,
-};
-
-u32 MCD_SingleNoEu_TDT[] = {
- 0x8198001b,
- 0x7000000d,
- 0x080cf81f,
- 0x8198801b,
- 0x6000000e,
- 0x084cf85f,
- 0x000001f8,
- 0x8298001b,
- 0x7000000d,
- 0x010cf81f,
- 0x6000000e,
- 0x018cf81f,
- 0xc202601b,
- 0xc002221c,
- 0x809a601b,
- 0xc10420c2,
- 0x839be009,
- 0x03fed7b8,
- 0xda9b001b,
- 0x9b9be01b,
- 0x70000006,
- 0x088cf889,
- 0x1000cb28,
- 0x70000006,
- 0x088cf889,
- 0x1000cb30,
- 0x70000006,
- 0x088cf889,
- 0x0000cb38,
- 0x000001f8,
- 0xc202601b,
- 0xc002229c,
- 0x809a601b,
- 0xda9b001b,
- 0x9b9be01b,
- 0x0000d3a0,
- 0xc10420c2,
- 0x839be009,
- 0x0bfed7b8,
- 0xda9b001b,
- 0x9b9be01b,
- 0x70000006,
- 0x088cf889,
- 0x1000cb28,
- 0x70000006,
- 0x088cf889,
- 0x1000cb30,
- 0x70000006,
- 0x088cf889,
- 0x0000cb38,
- 0x000001f8,
- 0xc318022d,
- 0x8018801b,
- 0x040001f8,
-};
-
-#ifdef MCD_INCLUDE_EU
-u32 MCD_ChainEu_TDT[] = {
- 0x80004000,
- 0x8198801b,
- 0xb8c68018,
- 0x10002f10,
- 0x7000000d,
- 0x01ccf89f,
- 0x6000000a,
- 0x080cf89f,
- 0x000001f8,
- 0x981803a4,
- 0x8198801b,
- 0xf8c6801a,
- 0xb8c6e01b,
- 0x10002b10,
- 0x00001318,
- 0xb8c6801d,
- 0x10001710,
- 0x60000007,
- 0x018cf88c,
- 0x98c6801c,
- 0x00000b10,
- 0x98c78018,
- 0x10002310,
- 0x0000c820,
- 0x000001f8,
- 0x8698801b,
- 0x7000000f,
- 0x084cf2df,
- 0xd899042d,
- 0x8019801b,
- 0x60000003,
- 0x2cd7c7df,
- 0xd8990364,
- 0x8019801b,
- 0x60000003,
- 0x2c17c7df,
- 0x000001f8,
- 0xc1c7e018,
- 0xc003a35e,
- 0x819a601b,
- 0xc206a142,
- 0x851be009,
- 0x63fe0000,
- 0x0d4cfddf,
- 0xda9b001b,
- 0x9b9be01b,
- 0x70000002,
- 0x004cf81f,
- 0x1000cb20,
- 0x70000006,
- 0x088cf891,
- 0x1000cb28,
- 0x70000006,
- 0x088cf891,
- 0x1000cb30,
- 0x70000006,
- 0x088cf891,
- 0x1000cb38,
- 0x0000c728,
- 0x000001f8,
- 0xc1c7e018,
- 0xc003a49e,
- 0x819a601b,
- 0xda9b001b,
- 0x9b9be01b,
- 0x0000d3a0,
- 0xc206a142,
- 0x851be009,
- 0x6bfe0000,
- 0x0d4cfddf,
- 0xda9b001b,
- 0x9b9be01b,
- 0x70000002,
- 0x004cf81f,
- 0x1000cb20,
- 0x70000006,
- 0x088cf891,
- 0x1000cb28,
- 0x70000006,
- 0x088cf891,
- 0x1000cb30,
- 0x70000006,
- 0x088cf891,
- 0x1000cb38,
- 0x0000c728,
- 0x000001f8,
- 0x8198801b,
- 0xd8c68018,
- 0x98c6e01c,
- 0x6000000b,
- 0x0c8cfc9f,
- 0x0000cc08,
- 0xa1c6801e,
- 0x10000f08,
- 0x10002458,
- 0xb8c68018,
- 0x10002f10,
- 0x7000000a,
- 0x080cf89f,
- 0x6000000d,
- 0x01ccf89f,
- 0x000001f8,
- 0x8698801b,
- 0x7000000e,
- 0x084cf25f,
- 0xd899037f,
- 0x8019801b,
- 0x040001f8,
- 0x000001f8,
- 0x000001f8,
-};
-
-u32 MCD_SingleEu_TDT[] = {
- 0x8218001b,
- 0x7000000d,
- 0x080cf81f,
- 0x8218801b,
- 0x6000000e,
- 0x084cf85f,
- 0x000001f8,
- 0x8318001b,
- 0x7000000d,
- 0x014cf81f,
- 0x6000000e,
- 0x01ccf81f,
- 0x8498001b,
- 0x7000000f,
- 0x080cf19f,
- 0xd81882a4,
- 0x8019001b,
- 0x60000003,
- 0x2c97c7df,
- 0xd818826d,
- 0x8019001b,
- 0x60000003,
- 0x2c17c7df,
- 0x000001f8,
- 0xc282e01b,
- 0xc002a25e,
- 0x811a601b,
- 0xc184a102,
- 0x841be009,
- 0x63fe0000,
- 0x0d4cfddf,
- 0xda9b001b,
- 0x9b9be01b,
- 0x70000002,
- 0x004cf99f,
- 0x70000006,
- 0x088cf88b,
- 0x1000cb28,
- 0x70000006,
- 0x088cf88b,
- 0x1000cb30,
- 0x70000006,
- 0x088cf88b,
- 0x0000cb38,
- 0x000001f8,
- 0xc282e01b,
- 0xc002a31e,
- 0x811a601b,
- 0xda9b001b,
- 0x9b9be01b,
- 0x0000d3a0,
- 0xc184a102,
- 0x841be009,
- 0x6bfe0000,
- 0x0d4cfddf,
- 0xda9b001b,
- 0x9b9be01b,
- 0x70000002,
- 0x004cf99f,
- 0x70000006,
- 0x088cf88b,
- 0x1000cb28,
- 0x70000006,
- 0x088cf88b,
- 0x1000cb30,
- 0x70000006,
- 0x088cf88b,
- 0x0000cb38,
- 0x000001f8,
- 0x8144801c,
- 0x0000c008,
- 0xc398027f,
- 0x8018801b,
- 0x040001f8,
-};
-#endif
-u32 MCD_ENetRcv_TDT[] = {
- 0x80004000,
- 0x81988000,
- 0x10000788,
- 0x6000000a,
- 0x080cf05f,
- 0x98180209,
- 0x81c40004,
- 0x7000000e,
- 0x010cf05f,
- 0x7000000c,
- 0x01ccf05f,
- 0x70000004,
- 0x014cf049,
- 0x70000004,
- 0x004cf04a,
- 0x00000b88,
- 0xc4030150,
- 0x8119e012,
- 0x03e0cf90,
- 0x81188000,
- 0x000ac788,
- 0xc4030000,
- 0x8199e000,
- 0x70000004,
- 0x084cfc8b,
- 0x60000005,
- 0x0cccf841,
- 0x81c60000,
- 0xc399021b,
- 0x80198000,
- 0x00008400,
- 0x00000f08,
- 0x81988000,
- 0x10000788,
- 0x6000000a,
- 0x080cf05f,
- 0xc2188209,
- 0x80190000,
- 0x040001f8,
- 0x000001f8,
-};
-
-u32 MCD_ENetXmit_TDT[] = {
- 0x80004000,
- 0x81988000,
- 0x10000788,
- 0x6000000a,
- 0x080cf05f,
- 0x98180309,
- 0x80004003,
- 0x81c60004,
- 0x7000000e,
- 0x014cf05f,
- 0x7000000c,
- 0x028cf05f,
- 0x7000000d,
- 0x018cf05f,
- 0x70000004,
- 0x01ccf04d,
- 0x10000b90,
- 0x60000004,
- 0x020cf0a1,
- 0xc3188312,
- 0x83c70000,
- 0x00001f10,
- 0xc583a3c3,
- 0x81042325,
- 0x03e0c798,
- 0xd8990000,
- 0x9999e000,
- 0x000acf98,
- 0xd8992306,
- 0x9999e03f,
- 0x03eac798,
- 0xd8990000,
- 0x9999e000,
- 0x000acf98,
- 0xd8990000,
- 0x99832302,
- 0x0beac798,
- 0x81988000,
- 0x6000000b,
- 0x0c4cfc5f,
- 0x81c80000,
- 0xc5190312,
- 0x80198000,
- 0x00008400,
- 0x00000f08,
- 0x81988000,
- 0x10000788,
- 0x6000000a,
- 0x080cf05f,
- 0xc2988309,
- 0x80190000,
- 0x040001f8,
- 0x000001f8,
-};
-
-#ifdef MCD_INCLUDE_EU
-MCD_bufDesc MCD_singleBufDescs[NCHANNELS];
-#endif
diff --git a/drivers/dma/MCD_tasksInit.c b/drivers/dma/MCD_tasksInit.c
deleted file mode 100644
index 079cd0af3c0..00000000000
--- a/drivers/dma/MCD_tasksInit.c
+++ /dev/null
@@ -1,225 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
- */
-
-#include <common.h>
-
-/* Functions for initializing variable tables of different types of tasks. */
-
-/*
- * Do not edit!
- */
-
-#include <MCD_dma.h>
-
-extern dmaRegs *MCD_dmaBar;
-
-/* Task 0 */
-
-void MCD_startDmaChainNoEu(int *currBD, short srcIncr, short destIncr,
- int xferSize, short xferSizeIncr, int *cSave,
- volatile TaskTableEntry * taskTable, int channel)
-{
- volatile TaskTableEntry *taskChan = taskTable + channel;
-
- MCD_SET_VAR(taskChan, 2, (u32) currBD); /* var[2] */
- MCD_SET_VAR(taskChan, 25, (u32) (0xe000 << 16) | (0xffff & srcIncr)); /* inc[1] */
- MCD_SET_VAR(taskChan, 24, (u32) (0xe000 << 16) | (0xffff & destIncr)); /* inc[0] */
- MCD_SET_VAR(taskChan, 11, (u32) xferSize); /* var[11] */
- MCD_SET_VAR(taskChan, 26, (u32) (0x2000 << 16) | (0xffff & xferSizeIncr)); /* inc[2] */
- MCD_SET_VAR(taskChan, 0, (u32) cSave); /* var[0] */
- MCD_SET_VAR(taskChan, 1, (u32) 0x00000000); /* var[1] */
- MCD_SET_VAR(taskChan, 3, (u32) 0x00000000); /* var[3] */
- MCD_SET_VAR(taskChan, 4, (u32) 0x00000000); /* var[4] */
- MCD_SET_VAR(taskChan, 5, (u32) 0x00000000); /* var[5] */
- MCD_SET_VAR(taskChan, 6, (u32) 0x00000000); /* var[6] */
- MCD_SET_VAR(taskChan, 7, (u32) 0x00000000); /* var[7] */
- MCD_SET_VAR(taskChan, 8, (u32) 0x00000000); /* var[8] */
- MCD_SET_VAR(taskChan, 9, (u32) 0x00000000); /* var[9] */
- MCD_SET_VAR(taskChan, 10, (u32) 0x00000000); /* var[10] */
- MCD_SET_VAR(taskChan, 12, (u32) 0x00000000); /* var[12] */
- MCD_SET_VAR(taskChan, 13, (u32) 0x80000000); /* var[13] */
- MCD_SET_VAR(taskChan, 14, (u32) 0x00000010); /* var[14] */
- MCD_SET_VAR(taskChan, 15, (u32) 0x00000004); /* var[15] */
- MCD_SET_VAR(taskChan, 16, (u32) 0x08000000); /* var[16] */
- MCD_SET_VAR(taskChan, 27, (u32) 0x00000000); /* inc[3] */
- MCD_SET_VAR(taskChan, 28, (u32) 0x80000000); /* inc[4] */
- MCD_SET_VAR(taskChan, 29, (u32) 0x80000001); /* inc[5] */
- MCD_SET_VAR(taskChan, 30, (u32) 0x40000000); /* inc[6] */
-
- /* Set the task's Enable bit in its Task Control Register */
- MCD_dmaBar->taskControl[channel] |= (u16) 0x8000;
-}
-
-/* Task 1 */
-
-void MCD_startDmaSingleNoEu(char *srcAddr, short srcIncr, char *destAddr,
- short destIncr, int dmaSize, short xferSizeIncr,
- int flags, int *currBD, int *cSave,
- volatile TaskTableEntry * taskTable, int channel)
-{
- volatile TaskTableEntry *taskChan = taskTable + channel;
-
- MCD_SET_VAR(taskChan, 7, (u32) srcAddr); /* var[7] */
- MCD_SET_VAR(taskChan, 25, (u32) (0xe000 << 16) | (0xffff & srcIncr)); /* inc[1] */
- MCD_SET_VAR(taskChan, 2, (u32) destAddr); /* var[2] */
- MCD_SET_VAR(taskChan, 24, (u32) (0xe000 << 16) | (0xffff & destIncr)); /* inc[0] */
- MCD_SET_VAR(taskChan, 3, (u32) dmaSize); /* var[3] */
- MCD_SET_VAR(taskChan, 26, (u32) (0x2000 << 16) | (0xffff & xferSizeIncr)); /* inc[2] */
- MCD_SET_VAR(taskChan, 5, (u32) flags); /* var[5] */
- MCD_SET_VAR(taskChan, 1, (u32) currBD); /* var[1] */
- MCD_SET_VAR(taskChan, 0, (u32) cSave); /* var[0] */
- MCD_SET_VAR(taskChan, 4, (u32) 0x00000000); /* var[4] */
- MCD_SET_VAR(taskChan, 6, (u32) 0x00000000); /* var[6] */
- MCD_SET_VAR(taskChan, 8, (u32) 0x00000000); /* var[8] */
- MCD_SET_VAR(taskChan, 9, (u32) 0x00000004); /* var[9] */
- MCD_SET_VAR(taskChan, 10, (u32) 0x08000000); /* var[10] */
- MCD_SET_VAR(taskChan, 27, (u32) 0x00000000); /* inc[3] */
- MCD_SET_VAR(taskChan, 28, (u32) 0x80000001); /* inc[4] */
- MCD_SET_VAR(taskChan, 29, (u32) 0x40000000); /* inc[5] */
-
- /* Set the task's Enable bit in its Task Control Register */
- MCD_dmaBar->taskControl[channel] |= (u16) 0x8000;
-}
-
-/* Task 2 */
-
-void MCD_startDmaChainEu(int *currBD, short srcIncr, short destIncr,
- int xferSize, short xferSizeIncr, int *cSave,
- volatile TaskTableEntry * taskTable, int channel)
-{
- volatile TaskTableEntry *taskChan = taskTable + channel;
-
- MCD_SET_VAR(taskChan, 3, (u32) currBD); /* var[3] */
- MCD_SET_VAR(taskChan, 25, (u32) (0xe000 << 16) | (0xffff & srcIncr)); /* inc[1] */
- MCD_SET_VAR(taskChan, 24, (u32) (0xe000 << 16) | (0xffff & destIncr)); /* inc[0] */
- MCD_SET_VAR(taskChan, 12, (u32) xferSize); /* var[12] */
- MCD_SET_VAR(taskChan, 26, (u32) (0x2000 << 16) | (0xffff & xferSizeIncr)); /* inc[2] */
- MCD_SET_VAR(taskChan, 0, (u32) cSave); /* var[0] */
- MCD_SET_VAR(taskChan, 1, (u32) 0x00000000); /* var[1] */
- MCD_SET_VAR(taskChan, 2, (u32) 0x00000000); /* var[2] */
- MCD_SET_VAR(taskChan, 4, (u32) 0x00000000); /* var[4] */
- MCD_SET_VAR(taskChan, 5, (u32) 0x00000000); /* var[5] */
- MCD_SET_VAR(taskChan, 6, (u32) 0x00000000); /* var[6] */
- MCD_SET_VAR(taskChan, 7, (u32) 0x00000000); /* var[7] */
- MCD_SET_VAR(taskChan, 8, (u32) 0x00000000); /* var[8] */
- MCD_SET_VAR(taskChan, 9, (u32) 0x00000000); /* var[9] */
- MCD_SET_VAR(taskChan, 10, (u32) 0x00000000); /* var[10] */
- MCD_SET_VAR(taskChan, 11, (u32) 0x00000000); /* var[11] */
- MCD_SET_VAR(taskChan, 13, (u32) 0x00000000); /* var[13] */
- MCD_SET_VAR(taskChan, 14, (u32) 0x80000000); /* var[14] */
- MCD_SET_VAR(taskChan, 15, (u32) 0x00000010); /* var[15] */
- MCD_SET_VAR(taskChan, 16, (u32) 0x00000001); /* var[16] */
- MCD_SET_VAR(taskChan, 17, (u32) 0x00000004); /* var[17] */
- MCD_SET_VAR(taskChan, 18, (u32) 0x08000000); /* var[18] */
- MCD_SET_VAR(taskChan, 27, (u32) 0x00000000); /* inc[3] */
- MCD_SET_VAR(taskChan, 28, (u32) 0x80000000); /* inc[4] */
- MCD_SET_VAR(taskChan, 29, (u32) 0xc0000000); /* inc[5] */
- MCD_SET_VAR(taskChan, 30, (u32) 0x80000001); /* inc[6] */
- MCD_SET_VAR(taskChan, 31, (u32) 0x40000000); /* inc[7] */
-
- /* Set the task's Enable bit in its Task Control Register */
- MCD_dmaBar->taskControl[channel] |= (u16) 0x8000;
-}
-
-/* Task 3 */
-
-void MCD_startDmaSingleEu(char *srcAddr, short srcIncr, char *destAddr,
- short destIncr, int dmaSize, short xferSizeIncr,
- int flags, int *currBD, int *cSave,
- volatile TaskTableEntry * taskTable, int channel)
-{
- volatile TaskTableEntry *taskChan = taskTable + channel;
-
- MCD_SET_VAR(taskChan, 8, (u32) srcAddr); /* var[8] */
- MCD_SET_VAR(taskChan, 25, (u32) (0xe000 << 16) | (0xffff & srcIncr)); /* inc[1] */
- MCD_SET_VAR(taskChan, 3, (u32) destAddr); /* var[3] */
- MCD_SET_VAR(taskChan, 24, (u32) (0xe000 << 16) | (0xffff & destIncr)); /* inc[0] */
- MCD_SET_VAR(taskChan, 4, (u32) dmaSize); /* var[4] */
- MCD_SET_VAR(taskChan, 26, (u32) (0x2000 << 16) | (0xffff & xferSizeIncr)); /* inc[2] */
- MCD_SET_VAR(taskChan, 6, (u32) flags); /* var[6] */
- MCD_SET_VAR(taskChan, 2, (u32) currBD); /* var[2] */
- MCD_SET_VAR(taskChan, 0, (u32) cSave); /* var[0] */
- MCD_SET_VAR(taskChan, 1, (u32) 0x00000000); /* var[1] */
- MCD_SET_VAR(taskChan, 5, (u32) 0x00000000); /* var[5] */
- MCD_SET_VAR(taskChan, 7, (u32) 0x00000000); /* var[7] */
- MCD_SET_VAR(taskChan, 9, (u32) 0x00000000); /* var[9] */
- MCD_SET_VAR(taskChan, 10, (u32) 0x00000001); /* var[10] */
- MCD_SET_VAR(taskChan, 11, (u32) 0x00000004); /* var[11] */
- MCD_SET_VAR(taskChan, 12, (u32) 0x08000000); /* var[12] */
- MCD_SET_VAR(taskChan, 27, (u32) 0x00000000); /* inc[3] */
- MCD_SET_VAR(taskChan, 28, (u32) 0xc0000000); /* inc[4] */
- MCD_SET_VAR(taskChan, 29, (u32) 0x80000000); /* inc[5] */
- MCD_SET_VAR(taskChan, 30, (u32) 0x80000001); /* inc[6] */
- MCD_SET_VAR(taskChan, 31, (u32) 0x40000000); /* inc[7] */
-
- /* Set the task's Enable bit in its Task Control Register */
- MCD_dmaBar->taskControl[channel] |= (u16) 0x8000;
-}
-
-/* Task 4 */
-
-void MCD_startDmaENetRcv(char *bDBase, char *currBD, char *rcvFifoPtr,
- volatile TaskTableEntry * taskTable, int channel)
-{
- volatile TaskTableEntry *taskChan = taskTable + channel;
-
- MCD_SET_VAR(taskChan, 0, (u32) bDBase); /* var[0] */
- MCD_SET_VAR(taskChan, 3, (u32) currBD); /* var[3] */
- MCD_SET_VAR(taskChan, 6, (u32) rcvFifoPtr); /* var[6] */
- MCD_SET_VAR(taskChan, 1, (u32) 0x00000000); /* var[1] */
- MCD_SET_VAR(taskChan, 2, (u32) 0x00000000); /* var[2] */
- MCD_SET_VAR(taskChan, 4, (u32) 0x00000000); /* var[4] */
- MCD_SET_VAR(taskChan, 5, (u32) 0x00000000); /* var[5] */
- MCD_SET_VAR(taskChan, 7, (u32) 0x00000000); /* var[7] */
- MCD_SET_VAR(taskChan, 8, (u32) 0x00000000); /* var[8] */
- MCD_SET_VAR(taskChan, 9, (u32) 0x0000ffff); /* var[9] */
- MCD_SET_VAR(taskChan, 10, (u32) 0x30000000); /* var[10] */
- MCD_SET_VAR(taskChan, 11, (u32) 0x0fffffff); /* var[11] */
- MCD_SET_VAR(taskChan, 12, (u32) 0x00000008); /* var[12] */
- MCD_SET_VAR(taskChan, 24, (u32) 0x00000000); /* inc[0] */
- MCD_SET_VAR(taskChan, 25, (u32) 0x60000000); /* inc[1] */
- MCD_SET_VAR(taskChan, 26, (u32) 0x20000004); /* inc[2] */
- MCD_SET_VAR(taskChan, 27, (u32) 0x40000000); /* inc[3] */
-
- /* Set the task's Enable bit in its Task Control Register */
- MCD_dmaBar->taskControl[channel] |= (u16) 0x8000;
-}
-
-/* Task 5 */
-
-void MCD_startDmaENetXmit(char *bDBase, char *currBD, char *xmitFifoPtr,
- volatile TaskTableEntry * taskTable, int channel)
-{
- volatile TaskTableEntry *taskChan = taskTable + channel;
-
- MCD_SET_VAR(taskChan, 0, (u32) bDBase); /* var[0] */
- MCD_SET_VAR(taskChan, 3, (u32) currBD); /* var[3] */
- MCD_SET_VAR(taskChan, 11, (u32) xmitFifoPtr); /* var[11] */
- MCD_SET_VAR(taskChan, 1, (u32) 0x00000000); /* var[1] */
- MCD_SET_VAR(taskChan, 2, (u32) 0x00000000); /* var[2] */
- MCD_SET_VAR(taskChan, 4, (u32) 0x00000000); /* var[4] */
- MCD_SET_VAR(taskChan, 5, (u32) 0x00000000); /* var[5] */
- MCD_SET_VAR(taskChan, 6, (u32) 0x00000000); /* var[6] */
- MCD_SET_VAR(taskChan, 7, (u32) 0x00000000); /* var[7] */
- MCD_SET_VAR(taskChan, 8, (u32) 0x00000000); /* var[8] */
- MCD_SET_VAR(taskChan, 9, (u32) 0x00000000); /* var[9] */
- MCD_SET_VAR(taskChan, 10, (u32) 0x00000000); /* var[10] */
- MCD_SET_VAR(taskChan, 12, (u32) 0x00000000); /* var[12] */
- MCD_SET_VAR(taskChan, 13, (u32) 0x0000ffff); /* var[13] */
- MCD_SET_VAR(taskChan, 14, (u32) 0xffffffff); /* var[14] */
- MCD_SET_VAR(taskChan, 15, (u32) 0x00000004); /* var[15] */
- MCD_SET_VAR(taskChan, 16, (u32) 0x00000008); /* var[16] */
- MCD_SET_VAR(taskChan, 24, (u32) 0x00000000); /* inc[0] */
- MCD_SET_VAR(taskChan, 25, (u32) 0x60000000); /* inc[1] */
- MCD_SET_VAR(taskChan, 26, (u32) 0x40000000); /* inc[2] */
- MCD_SET_VAR(taskChan, 27, (u32) 0xc000fffc); /* inc[3] */
- MCD_SET_VAR(taskChan, 28, (u32) 0xe0000004); /* inc[4] */
- MCD_SET_VAR(taskChan, 29, (u32) 0x80000000); /* inc[5] */
- MCD_SET_VAR(taskChan, 30, (u32) 0x4000ffff); /* inc[6] */
- MCD_SET_VAR(taskChan, 31, (u32) 0xe0000001); /* inc[7] */
-
- /* Set the task's Enable bit in its Task Control Register */
- MCD_dmaBar->taskControl[channel] |= (u16) 0x8000;
-}
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index a75572fe5de..48811eaaeb3 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -5,7 +5,6 @@
obj-$(CONFIG_DMA) += dma-uclass.o
-obj-$(CONFIG_FSLDMAFEC) += MCD_tasksInit.o MCD_dmaApi.o MCD_tasks.o
obj-$(CONFIG_APBH_DMA) += apbh_dma.o
obj-$(CONFIG_BCM6348_IUDMA) += bcm6348-iudma.o
obj-$(CONFIG_FSL_DMA) += fsl_dma.o
diff --git a/drivers/dma/ti/Makefile b/drivers/dma/ti/Makefile
index 6807eb8e8b2..f4e0271efbf 100644
--- a/drivers/dma/ti/Makefile
+++ b/drivers/dma/ti/Makefile
@@ -8,3 +8,4 @@ k3-psil-data-$(CONFIG_SOC_K3_J721E) += k3-psil-j721e.o
k3-psil-data-$(CONFIG_SOC_K3_J721S2) += k3-psil-j721s2.o
k3-psil-data-$(CONFIG_SOC_K3_AM642) += k3-psil-am64.o
k3-psil-data-$(CONFIG_SOC_K3_AM625) += k3-psil-am62.o
+k3-psil-data-$(CONFIG_SOC_K3_AM62A7) += k3-psil-am62a.o
diff --git a/drivers/dma/ti/k3-psil-am62a.c b/drivers/dma/ti/k3-psil-am62a.c
new file mode 100644
index 00000000000..ca9d71f9142
--- /dev/null
+++ b/drivers/dma/ti/k3-psil-am62a.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com
+ */
+
+#include <linux/kernel.h>
+
+#include "k3-psil-priv.h"
+
+#define PSIL_PDMA_XY_TR(x) \
+ { \
+ .thread_id = x, \
+ .ep_config = { \
+ .ep_type = PSIL_EP_PDMA_XY, \
+ .mapped_channel_id = -1, \
+ .default_flow_id = -1, \
+ }, \
+ }
+
+#define PSIL_PDMA_XY_PKT(x) \
+ { \
+ .thread_id = x, \
+ .ep_config = { \
+ .ep_type = PSIL_EP_PDMA_XY, \
+ .mapped_channel_id = -1, \
+ .default_flow_id = -1, \
+ .pkt_mode = 1, \
+ }, \
+ }
+
+#define PSIL_ETHERNET(x, ch, flow_base, flow_cnt) \
+ { \
+ .thread_id = x, \
+ .ep_config = { \
+ .ep_type = PSIL_EP_NATIVE, \
+ .pkt_mode = 1, \
+ .needs_epib = 1, \
+ .psd_size = 16, \
+ .mapped_channel_id = ch, \
+ .flow_start = flow_base, \
+ .flow_num = flow_cnt, \
+ .default_flow_id = flow_base, \
+ }, \
+ }
+
+#define PSIL_SAUL(x, ch, flow_base, flow_cnt, default_flow, tx) \
+ { \
+ .thread_id = x, \
+ .ep_config = { \
+ .ep_type = PSIL_EP_NATIVE, \
+ .pkt_mode = 1, \
+ .needs_epib = 1, \
+ .psd_size = 64, \
+ .mapped_channel_id = ch, \
+ .flow_start = flow_base, \
+ .flow_num = flow_cnt, \
+ .default_flow_id = default_flow, \
+ .notdpkt = tx, \
+ }, \
+ }
+
+#define PSIL_PDMA_MCASP(x) \
+ { \
+ .thread_id = x, \
+ .ep_config = { \
+ .ep_type = PSIL_EP_PDMA_XY, \
+ .pdma_acc32 = 1, \
+ .pdma_burst = 1, \
+ }, \
+ }
+
+#define PSIL_CSI2RX(x) \
+ { \
+ .thread_id = x, \
+ .ep_config = { \
+ .ep_type = PSIL_EP_NATIVE, \
+ }, \
+ }
+
+/* PSI-L source thread IDs, used for RX (DMA_DEV_TO_MEM) */
+static struct psil_ep am62a_src_ep_map[] = {
+ /* SAUL */
+ PSIL_SAUL(0x7504, 20, 35, 8, 35, 0),
+ PSIL_SAUL(0x7505, 21, 35, 8, 36, 0),
+ PSIL_SAUL(0x7506, 22, 43, 8, 43, 0),
+ PSIL_SAUL(0x7507, 23, 43, 8, 44, 0),
+ /* PDMA_MAIN0 - SPI0-3 */
+ PSIL_PDMA_XY_PKT(0x4302),
+ PSIL_PDMA_XY_PKT(0x4303),
+ PSIL_PDMA_XY_PKT(0x4304),
+ PSIL_PDMA_XY_PKT(0x4305),
+ PSIL_PDMA_XY_PKT(0x4306),
+ PSIL_PDMA_XY_PKT(0x4307),
+ PSIL_PDMA_XY_PKT(0x4308),
+ PSIL_PDMA_XY_PKT(0x4309),
+ PSIL_PDMA_XY_PKT(0x430a),
+ PSIL_PDMA_XY_PKT(0x430b),
+ PSIL_PDMA_XY_PKT(0x430c),
+ PSIL_PDMA_XY_PKT(0x430d),
+ /* PDMA_MAIN1 - UART0-6 */
+ PSIL_PDMA_XY_PKT(0x4400),
+ PSIL_PDMA_XY_PKT(0x4401),
+ PSIL_PDMA_XY_PKT(0x4402),
+ PSIL_PDMA_XY_PKT(0x4403),
+ PSIL_PDMA_XY_PKT(0x4404),
+ PSIL_PDMA_XY_PKT(0x4405),
+ PSIL_PDMA_XY_PKT(0x4406),
+ /* PDMA_MAIN2 - MCASP0-2 */
+ PSIL_PDMA_MCASP(0x4500),
+ PSIL_PDMA_MCASP(0x4501),
+ PSIL_PDMA_MCASP(0x4502),
+ /* CPSW3G */
+ PSIL_ETHERNET(0x4600, 19, 19, 16),
+ /* CSI2RX */
+ PSIL_CSI2RX(0x5000),
+ PSIL_CSI2RX(0x5001),
+ PSIL_CSI2RX(0x5002),
+ PSIL_CSI2RX(0x5003),
+ PSIL_CSI2RX(0x5004),
+ PSIL_CSI2RX(0x5005),
+ PSIL_CSI2RX(0x5006),
+ PSIL_CSI2RX(0x5007),
+ PSIL_CSI2RX(0x5008),
+ PSIL_CSI2RX(0x5009),
+ PSIL_CSI2RX(0x500a),
+ PSIL_CSI2RX(0x500b),
+ PSIL_CSI2RX(0x500c),
+ PSIL_CSI2RX(0x500d),
+ PSIL_CSI2RX(0x500e),
+ PSIL_CSI2RX(0x500f),
+ PSIL_CSI2RX(0x5010),
+ PSIL_CSI2RX(0x5011),
+ PSIL_CSI2RX(0x5012),
+ PSIL_CSI2RX(0x5013),
+ PSIL_CSI2RX(0x5014),
+ PSIL_CSI2RX(0x5015),
+ PSIL_CSI2RX(0x5016),
+ PSIL_CSI2RX(0x5017),
+ PSIL_CSI2RX(0x5018),
+ PSIL_CSI2RX(0x5019),
+ PSIL_CSI2RX(0x501a),
+ PSIL_CSI2RX(0x501b),
+ PSIL_CSI2RX(0x501c),
+ PSIL_CSI2RX(0x501d),
+ PSIL_CSI2RX(0x501e),
+ PSIL_CSI2RX(0x501f),
+};
+
+/* PSI-L destination thread IDs, used for TX (DMA_MEM_TO_DEV) */
+static struct psil_ep am62a_dst_ep_map[] = {
+ /* SAUL */
+ PSIL_SAUL(0xf500, 27, 83, 8, 83, 1),
+ PSIL_SAUL(0xf501, 28, 91, 8, 91, 1),
+ /* PDMA_MAIN0 - SPI0-3 */
+ PSIL_PDMA_XY_PKT(0xc302),
+ PSIL_PDMA_XY_PKT(0xc303),
+ PSIL_PDMA_XY_PKT(0xc304),
+ PSIL_PDMA_XY_PKT(0xc305),
+ PSIL_PDMA_XY_PKT(0xc306),
+ PSIL_PDMA_XY_PKT(0xc307),
+ PSIL_PDMA_XY_PKT(0xc308),
+ PSIL_PDMA_XY_PKT(0xc309),
+ PSIL_PDMA_XY_PKT(0xc30a),
+ PSIL_PDMA_XY_PKT(0xc30b),
+ PSIL_PDMA_XY_PKT(0xc30c),
+ PSIL_PDMA_XY_PKT(0xc30d),
+ /* PDMA_MAIN1 - UART0-6 */
+ PSIL_PDMA_XY_PKT(0xc400),
+ PSIL_PDMA_XY_PKT(0xc401),
+ PSIL_PDMA_XY_PKT(0xc402),
+ PSIL_PDMA_XY_PKT(0xc403),
+ PSIL_PDMA_XY_PKT(0xc404),
+ PSIL_PDMA_XY_PKT(0xc405),
+ PSIL_PDMA_XY_PKT(0xc406),
+ /* PDMA_MAIN2 - MCASP0-2 */
+ PSIL_PDMA_MCASP(0xc500),
+ PSIL_PDMA_MCASP(0xc501),
+ PSIL_PDMA_MCASP(0xc502),
+ /* CPSW3G */
+ PSIL_ETHERNET(0xc600, 19, 19, 8),
+ PSIL_ETHERNET(0xc601, 20, 27, 8),
+ PSIL_ETHERNET(0xc602, 21, 35, 8),
+ PSIL_ETHERNET(0xc603, 22, 43, 8),
+ PSIL_ETHERNET(0xc604, 23, 51, 8),
+ PSIL_ETHERNET(0xc605, 24, 59, 8),
+ PSIL_ETHERNET(0xc606, 25, 67, 8),
+ PSIL_ETHERNET(0xc607, 26, 75, 8),
+};
+
+struct psil_ep_map am62a_ep_map = {
+ .name = "am62a",
+ .src = am62a_src_ep_map,
+ .src_count = ARRAY_SIZE(am62a_src_ep_map),
+ .dst = am62a_dst_ep_map,
+ .dst_count = ARRAY_SIZE(am62a_dst_ep_map),
+};
diff --git a/drivers/dma/ti/k3-psil-am64.c b/drivers/dma/ti/k3-psil-am64.c
index 15742c3723d..6180e2a1996 100644
--- a/drivers/dma/ti/k3-psil-am64.c
+++ b/drivers/dma/ti/k3-psil-am64.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2020 Texas Instruments Incorporated - https://www.ti.com
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
*/
diff --git a/drivers/dma/ti/k3-psil-am654.c b/drivers/dma/ti/k3-psil-am654.c
index d16c07566b5..ce86600e556 100644
--- a/drivers/dma/ti/k3-psil-am654.c
+++ b/drivers/dma/ti/k3-psil-am654.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
*/
diff --git a/drivers/dma/ti/k3-psil-priv.h b/drivers/dma/ti/k3-psil-priv.h
index 28078c6bd8d..83f873b84ce 100644
--- a/drivers/dma/ti/k3-psil-priv.h
+++ b/drivers/dma/ti/k3-psil-priv.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com
*/
#ifndef K3_PSIL_PRIV_H_
@@ -42,5 +42,6 @@ extern struct psil_ep_map j721e_ep_map;
extern struct psil_ep_map j721s2_ep_map;
extern struct psil_ep_map am64_ep_map;
extern struct psil_ep_map am62_ep_map;
+extern struct psil_ep_map am62a_ep_map;
#endif /* K3_PSIL_PRIV_H_ */
diff --git a/drivers/dma/ti/k3-psil.c b/drivers/dma/ti/k3-psil.c
index f23c8ca2b74..d4d4fede8fa 100644
--- a/drivers/dma/ti/k3-psil.c
+++ b/drivers/dma/ti/k3-psil.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
*/
@@ -26,6 +26,8 @@ struct psil_endpoint_config *psil_get_ep_config(u32 thread_id)
soc_ep_map = &am64_ep_map;
else if (IS_ENABLED(CONFIG_SOC_K3_AM625))
soc_ep_map = &am62_ep_map;
+ else if (IS_ENABLED(CONFIG_SOC_K3_AM62A7))
+ soc_ep_map = &am62a_ep_map;
}
if (thread_id & K3_PSIL_DST_THREAD_ID_OFFSET && soc_ep_map->dst) {
diff --git a/drivers/dma/ti/k3-psil.h b/drivers/dma/ti/k3-psil.h
index 1e0fe06c0a4..af60a9924e2 100644
--- a/drivers/dma/ti/k3-psil.h
+++ b/drivers/dma/ti/k3-psil.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com
*/
#ifndef K3_PSIL_H_
diff --git a/drivers/dma/ti/k3-udma-hwdef.h b/drivers/dma/ti/k3-udma-hwdef.h
index 5d50bbcb031..3d6b4d10fff 100644
--- a/drivers/dma/ti/k3-udma-hwdef.h
+++ b/drivers/dma/ti/k3-udma-hwdef.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c
index 4f2effd39a8..8a62d63dfef 100644
--- a/drivers/dma/ti/k3-udma.c
+++ b/drivers/dma/ti/k3-udma.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
*/
#define pr_fmt(fmt) "udma: " fmt
@@ -1287,7 +1287,7 @@ static int udma_get_mmrs(struct udevice *dev)
u32 cap2, cap3, cap4;
int i;
- ud->mmrs[MMR_GCFG] = (uint32_t *)devfdt_get_addr_name(dev, mmr_names[MMR_GCFG]);
+ ud->mmrs[MMR_GCFG] = dev_read_addr_name_ptr(dev, mmr_names[MMR_GCFG]);
if (!ud->mmrs[MMR_GCFG])
return -EINVAL;
@@ -1325,8 +1325,7 @@ static int udma_get_mmrs(struct udevice *dev)
if (i == MMR_RCHANRT && ud->rchan_cnt == 0)
continue;
- ud->mmrs[i] = (uint32_t *)devfdt_get_addr_name(dev,
- mmr_names[i]);
+ ud->mmrs[i] = dev_read_addr_name_ptr(dev, mmr_names[i]);
if (!ud->mmrs[i])
return -EINVAL;
}
diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig
index 837c6f1180d..11fc0fe1c80 100644
--- a/drivers/fastboot/Kconfig
+++ b/drivers/fastboot/Kconfig
@@ -1,4 +1,5 @@
menu "Fastboot support"
+ depends on CMDLINE
config FASTBOOT
bool
diff --git a/drivers/fastboot/fb_common.c b/drivers/fastboot/fb_common.c
index 4e9d9b719c6..3576b067729 100644
--- a/drivers/fastboot/fb_common.c
+++ b/drivers/fastboot/fb_common.c
@@ -91,6 +91,7 @@ void fastboot_okay(const char *reason, char *response)
*/
int __weak fastboot_set_reboot_flag(enum fastboot_reboot_reason reason)
{
+ int ret;
static const char * const boot_cmds[] = {
[FASTBOOT_REBOOT_REASON_BOOTLOADER] = "bootonce-bootloader",
[FASTBOOT_REBOOT_REASON_FASTBOOTD] = "boot-fastboot",
@@ -105,7 +106,18 @@ int __weak fastboot_set_reboot_flag(enum fastboot_reboot_reason reason)
if (reason >= FASTBOOT_REBOOT_REASONS_COUNT)
return -EINVAL;
- return bcb_write_reboot_reason(mmc_dev, "misc", boot_cmds[reason]);
+ ret = bcb_find_partition_and_load("mmc", mmc_dev, "misc");
+ if (ret)
+ goto out;
+
+ ret = bcb_set(BCB_FIELD_COMMAND, boot_cmds[reason]);
+ if (ret)
+ goto out;
+
+ ret = bcb_store();
+out:
+ bcb_reset();
+ return ret;
}
/**
diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
index 8c17b19eaf5..f1e91d151ea 100644
--- a/drivers/firmware/arm-ffa/arm-ffa-uclass.c
+++ b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
@@ -144,8 +144,6 @@ static int ffa_print_error_log(u32 ffa_id, int ffa_errno)
return -EINVAL;
abi_idx = FFA_ID_TO_ERRMAP_ID(ffa_id);
- if (abi_idx < 0 || abi_idx >= FFA_ERRMAP_COUNT)
- return -EINVAL;
if (!err_msg_map[abi_idx].err_str[err_idx])
return -EINVAL;
diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c
index 43fb7fa7787..8ea15c7ed33 100644
--- a/drivers/firmware/firmware-zynqmp.c
+++ b/drivers/firmware/firmware-zynqmp.c
@@ -203,6 +203,8 @@ 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);
+ if (ret)
+ return ret;
/* Return feature check version */
return ret_payload[1] & FIRMWARE_VERSION_MASK;
diff --git a/drivers/firmware/scmi/Makefile b/drivers/firmware/scmi/Makefile
index b2ff483c75a..dae42863589 100644
--- a/drivers/firmware/scmi/Makefile
+++ b/drivers/firmware/scmi/Makefile
@@ -1,6 +1,8 @@
obj-y += scmi_agent-uclass.o
+obj-y += base.o
obj-y += smt.o
obj-$(CONFIG_SCMI_AGENT_SMCCC) += smccc_agent.o
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
diff --git a/drivers/firmware/scmi/base.c b/drivers/firmware/scmi/base.c
new file mode 100644
index 00000000000..1d41a8a98fc
--- /dev/null
+++ b/drivers/firmware/scmi/base.c
@@ -0,0 +1,664 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * SCMI Base protocol as U-Boot device
+ *
+ * Copyright (C) 2023 Linaro Limited
+ * author: AKASHI Takahiro <takahiro.akashi@linaro.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <scmi_agent.h>
+#include <scmi_protocols.h>
+#include <stdlib.h>
+#include <string.h>
+#include <asm/types.h>
+#include <dm/device_compat.h>
+#include <linux/kernel.h>
+
+/**
+ * scmi_generic_protocol_version - get protocol version
+ * @dev: SCMI device
+ * @id: SCMI protocol ID
+ * @version: Pointer to SCMI protocol version
+ *
+ * Obtain the protocol version number in @version.
+ *
+ * Return: 0 on success, error code on failure
+ */
+int scmi_generic_protocol_version(struct udevice *dev,
+ enum scmi_std_protocol id, u32 *version)
+{
+ struct scmi_protocol_version_out out;
+ struct scmi_msg msg = {
+ .protocol_id = id,
+ .message_id = SCMI_PROTOCOL_VERSION,
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int ret;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+ if (out.status)
+ return scmi_to_linux_errno(out.status);
+
+ *version = out.version;
+
+ return 0;
+}
+
+/**
+ * scmi_base_protocol_version_int - get Base protocol version
+ * @dev: SCMI device
+ * @version: Pointer to SCMI protocol version
+ *
+ * Obtain the protocol version number in @version for Base protocol.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_base_protocol_version_int(struct udevice *dev, u32 *version)
+{
+ return scmi_generic_protocol_version(dev, SCMI_PROTOCOL_ID_BASE,
+ version);
+}
+
+/**
+ * scmi_protocol_attrs_int - get protocol attributes
+ * @dev: SCMI device
+ * @num_agents: Number of SCMI agents
+ * @num_protocols: Number of SCMI protocols
+ *
+ * Obtain the protocol attributes, the number of agents and the number
+ * of protocols, in @num_agents and @num_protocols respectively, that
+ * the device provides.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_protocol_attrs_int(struct udevice *dev, u32 *num_agents,
+ u32 *num_protocols)
+{
+ struct scmi_protocol_attrs_out out;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_BASE,
+ .message_id = SCMI_PROTOCOL_ATTRIBUTES,
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int ret;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+ if (out.status)
+ return scmi_to_linux_errno(out.status);
+
+ *num_agents = SCMI_PROTOCOL_ATTRS_NUM_AGENTS(out.attributes);
+ *num_protocols = SCMI_PROTOCOL_ATTRS_NUM_PROTOCOLS(out.attributes);
+
+ return 0;
+}
+
+/**
+ * scmi_protocol_message_attrs_int - get message-specific attributes
+ * @dev: SCMI device
+ * @message_id: SCMI message ID
+ * @attributes: Message-specific attributes
+ *
+ * Obtain the message-specific attributes in @attributes.
+ * This command succeeds if the message is implemented and available.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_protocol_message_attrs_int(struct udevice *dev, u32 message_id,
+ u32 *attributes)
+{
+ struct scmi_protocol_msg_attrs_out out;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_BASE,
+ .message_id = SCMI_PROTOCOL_MESSAGE_ATTRIBUTES,
+ .in_msg = (u8 *)&message_id,
+ .in_msg_sz = sizeof(message_id),
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int ret;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+ if (out.status)
+ return scmi_to_linux_errno(out.status);
+
+ *attributes = out.attributes;
+
+ return 0;
+}
+
+/**
+ * scmi_base_discover_vendor_int - get vendor name
+ * @dev: SCMI device
+ * @vendor: Pointer to vendor name
+ *
+ * Obtain the vendor's name in @vendor.
+ * It is a caller's responsibility to free @vendor.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_base_discover_vendor_int(struct udevice *dev, u8 **vendor)
+{
+ struct scmi_base_discover_vendor_out out;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_BASE,
+ .message_id = SCMI_BASE_DISCOVER_VENDOR,
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int ret;
+
+ if (!vendor)
+ return -EINVAL;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+ if (out.status)
+ return scmi_to_linux_errno(out.status);
+
+ *vendor = strdup(out.vendor_identifier);
+ if (!*vendor)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/**
+ * scmi_base_discover_sub_vendor_int - get sub-vendor name
+ * @dev: SCMI device
+ * @sub_vendor: Pointer to sub-vendor name
+ *
+ * Obtain the sub-vendor's name in @sub_vendor.
+ * It is a caller's responsibility to free @sub_vendor.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_base_discover_sub_vendor_int(struct udevice *dev,
+ u8 **sub_vendor)
+{
+ struct scmi_base_discover_vendor_out out;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_BASE,
+ .message_id = SCMI_BASE_DISCOVER_SUB_VENDOR,
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int ret;
+
+ if (!sub_vendor)
+ return -EINVAL;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+ if (out.status)
+ return scmi_to_linux_errno(out.status);
+
+ *sub_vendor = strdup(out.vendor_identifier);
+ if (!*sub_vendor)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/**
+ * scmi_base_discover_impl_version_int - get implementation version
+ * @dev: SCMI device
+ * @impl_version: Pointer to implementation version
+ *
+ * Obtain the implementation version number in @impl_version.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_base_discover_impl_version_int(struct udevice *dev,
+ u32 *impl_version)
+{
+ struct scmi_base_discover_impl_version_out out;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_BASE,
+ .message_id = SCMI_BASE_DISCOVER_IMPL_VERSION,
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int ret;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+ if (out.status)
+ return scmi_to_linux_errno(out.status);
+
+ *impl_version = out.impl_version;
+
+ return 0;
+}
+
+/**
+ * scmi_base_discover_list_protocols_int - get list of protocols
+ * @dev: SCMI device
+ * @protocols: Pointer to array of SCMI protocols
+ *
+ * Obtain the list of protocols provided in @protocols.
+ * The number of elements in @protocols always match to the number of
+ * protocols returned by smci_protocol_attrs() when this function succeeds.
+ * It is a caller's responsibility to free @protocols.
+ *
+ * Return: the number of protocols in @protocols on success, error code on
+ * failure
+ */
+static int scmi_base_discover_list_protocols_int(struct udevice *dev,
+ u8 **protocols)
+{
+ struct scmi_base_discover_list_protocols_out out;
+ int cur;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_BASE,
+ .message_id = SCMI_BASE_DISCOVER_LIST_PROTOCOLS,
+ .in_msg = (u8 *)&cur,
+ .in_msg_sz = sizeof(cur),
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ u32 num_agents, num_protocols;
+ u8 *buf;
+ int i, ret;
+
+ ret = scmi_base_protocol_attrs(dev, &num_agents, &num_protocols);
+ if (ret)
+ return ret;
+
+ buf = calloc(sizeof(u8), num_protocols);
+ if (!buf)
+ return -ENOMEM;
+
+ cur = 0;
+ do {
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ goto err;
+ if (out.status) {
+ ret = scmi_to_linux_errno(out.status);
+ goto err;
+ }
+
+ for (i = 0; i < out.num_protocols; i++, cur++)
+ buf[cur] = out.protocols[i / 4] >> ((i % 4) * 8);
+ } while (cur < num_protocols);
+
+ *protocols = buf;
+
+ return num_protocols;
+err:
+ free(buf);
+
+ return ret;
+}
+
+/**
+ * scmi_base_discover_agent_int - identify agent
+ * @dev: SCMI device
+ * @agent_id: SCMI agent ID
+ * @ret_agent_id: Pointer to SCMI agent ID
+ * @name: Pointer to SCMI agent name
+ *
+ * Obtain the agent's name in @name. If @agent_id is equal to 0xffffffff,
+ * this function returns the caller's agent id in @ret_agent_id.
+ * It is a caller's responsibility to free @name.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_base_discover_agent_int(struct udevice *dev, u32 agent_id,
+ u32 *ret_agent_id, u8 **name)
+{
+ struct scmi_base_discover_agent_out out;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_BASE,
+ .message_id = SCMI_BASE_DISCOVER_AGENT,
+ .in_msg = (u8 *)&agent_id,
+ .in_msg_sz = sizeof(agent_id),
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int ret;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+ if (out.status)
+ return scmi_to_linux_errno(out.status);
+
+ if (ret_agent_id)
+ *ret_agent_id = out.agent_id;
+ if (name) {
+ *name = strdup(out.name);
+ if (!*name)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/**
+ * scmi_base_set_device_permissions_int - configure access permission to device
+ * @dev: SCMI device
+ * @agent_id: SCMI agent ID
+ * @device_id: ID of device to access
+ * @flags: A set of flags
+ *
+ * Ask for allowing or denying access permission to the device, @device_id.
+ * The meaning of @flags is defined in SCMI specification.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_base_set_device_permissions_int(struct udevice *dev, u32 agent_id,
+ u32 device_id, u32 flags)
+{
+ struct scmi_base_set_device_permissions_in in = {
+ .agent_id = agent_id,
+ .device_id = device_id,
+ .flags = flags,
+ };
+ s32 status;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_BASE,
+ .message_id = SCMI_BASE_SET_DEVICE_PERMISSIONS,
+ .in_msg = (u8 *)&in,
+ .in_msg_sz = sizeof(in),
+ .out_msg = (u8 *)&status,
+ .out_msg_sz = sizeof(status),
+ };
+ int ret;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+ if (status)
+ return scmi_to_linux_errno(status);
+
+ return 0;
+}
+
+/**
+ * scmi_base_set_protocol_permissions_int - configure access permission to
+ * protocol on device
+ * @dev: SCMI device
+ * @agent_id: SCMI agent ID
+ * @device_id: ID of device to access
+ * @command_id: SCMI command ID
+ * @flags: A set of flags
+ *
+ * Ask for allowing or denying access permission to the protocol, @command_id,
+ * on the device, @device_id.
+ * The meaning of @flags is defined in SCMI specification.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_base_set_protocol_permissions_int(struct udevice *dev,
+ u32 agent_id, u32 device_id,
+ u32 command_id, u32 flags)
+{
+ struct scmi_base_set_protocol_permissions_in in = {
+ .agent_id = agent_id,
+ .device_id = device_id,
+ .command_id = command_id,
+ .flags = flags,
+ };
+ s32 status;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_BASE,
+ .message_id = SCMI_BASE_SET_PROTOCOL_PERMISSIONS,
+ .in_msg = (u8 *)&in,
+ .in_msg_sz = sizeof(in),
+ .out_msg = (u8 *)&status,
+ .out_msg_sz = sizeof(status),
+ };
+ int ret;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+ if (status)
+ return scmi_to_linux_errno(status);
+
+ return 0;
+}
+
+/**
+ * scmi_base_reset_agent_configuration_int - reset resource settings
+ * @dev: SCMI device
+ * @agent_id: SCMI agent ID
+ * @flags: A set of flags
+ *
+ * Reset all the resource settings against @agent_id.
+ * The meaning of @flags is defined in SCMI specification.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_base_reset_agent_configuration_int(struct udevice *dev,
+ u32 agent_id, u32 flags)
+{
+ struct scmi_base_reset_agent_configuration_in in = {
+ .agent_id = agent_id,
+ .flags = flags,
+ };
+ s32 status;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_BASE,
+ .message_id = SCMI_BASE_RESET_AGENT_CONFIGURATION,
+ .in_msg = (u8 *)&in,
+ .in_msg_sz = sizeof(in),
+ .out_msg = (u8 *)&status,
+ .out_msg_sz = sizeof(status),
+ };
+ int ret;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+ if (status)
+ return scmi_to_linux_errno(status);
+
+ return 0;
+}
+
+/**
+ * scmi_base_probe - probe base protocol device
+ * @dev: SCMI device
+ *
+ * Probe the device for SCMI base protocol and initialize the private data.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_base_probe(struct udevice *dev)
+{
+ u32 version;
+ int ret;
+
+ ret = devm_scmi_of_get_channel(dev);
+ if (ret) {
+ dev_err(dev, "get_channel failed\n");
+ return ret;
+ }
+ ret = scmi_base_protocol_version_int(dev, &version);
+ if (ret) {
+ dev_err(dev, "getting protocol version failed\n");
+ return ret;
+ }
+ if (version < SCMI_BASE_PROTOCOL_VERSION)
+ return -EINVAL;
+
+ return ret;
+}
+
+static struct scmi_base_ops scmi_base_ops = {
+ /* Commands */
+ .protocol_version = scmi_base_protocol_version_int,
+ .protocol_attrs = scmi_protocol_attrs_int,
+ .protocol_message_attrs = scmi_protocol_message_attrs_int,
+ .base_discover_vendor = scmi_base_discover_vendor_int,
+ .base_discover_sub_vendor = scmi_base_discover_sub_vendor_int,
+ .base_discover_impl_version = scmi_base_discover_impl_version_int,
+ .base_discover_list_protocols = scmi_base_discover_list_protocols_int,
+ .base_discover_agent = scmi_base_discover_agent_int,
+ .base_notify_errors = NULL,
+ .base_set_device_permissions = scmi_base_set_device_permissions_int,
+ .base_set_protocol_permissions = scmi_base_set_protocol_permissions_int,
+ .base_reset_agent_configuration =
+ scmi_base_reset_agent_configuration_int,
+};
+
+int scmi_base_protocol_version(struct udevice *dev, u32 *version)
+{
+ const struct scmi_base_ops *ops = device_get_ops(dev);
+
+ if (ops->protocol_version)
+ return (*ops->protocol_version)(dev, version);
+
+ return -EOPNOTSUPP;
+}
+
+int scmi_base_protocol_attrs(struct udevice *dev, u32 *num_agents,
+ u32 *num_protocols)
+{
+ const struct scmi_base_ops *ops = device_get_ops(dev);
+
+ if (ops->protocol_attrs)
+ return (*ops->protocol_attrs)(dev, num_agents, num_protocols);
+
+ return -EOPNOTSUPP;
+}
+
+int scmi_base_protocol_message_attrs(struct udevice *dev, u32 message_id,
+ u32 *attributes)
+{
+ const struct scmi_base_ops *ops = device_get_ops(dev);
+
+ if (ops->protocol_message_attrs)
+ return (*ops->protocol_message_attrs)(dev, message_id,
+ attributes);
+
+ return -EOPNOTSUPP;
+}
+
+int scmi_base_discover_vendor(struct udevice *dev, u8 **vendor)
+{
+ const struct scmi_base_ops *ops = device_get_ops(dev);
+
+ if (ops->base_discover_vendor)
+ return (*ops->base_discover_vendor)(dev, vendor);
+
+ return -EOPNOTSUPP;
+}
+
+int scmi_base_discover_sub_vendor(struct udevice *dev, u8 **sub_vendor)
+{
+ const struct scmi_base_ops *ops = device_get_ops(dev);
+
+ if (ops->base_discover_sub_vendor)
+ return (*ops->base_discover_sub_vendor)(dev, sub_vendor);
+
+ return -EOPNOTSUPP;
+}
+
+int scmi_base_discover_impl_version(struct udevice *dev, u32 *impl_version)
+{
+ const struct scmi_base_ops *ops = device_get_ops(dev);
+
+ if (ops->base_discover_impl_version)
+ return (*ops->base_discover_impl_version)(dev, impl_version);
+
+ return -EOPNOTSUPP;
+}
+
+int scmi_base_discover_list_protocols(struct udevice *dev, u8 **protocols)
+{
+ const struct scmi_base_ops *ops = device_get_ops(dev);
+
+ if (ops->base_discover_list_protocols)
+ return (*ops->base_discover_list_protocols)(dev, protocols);
+
+ return -EOPNOTSUPP;
+}
+
+int scmi_base_discover_agent(struct udevice *dev, u32 agent_id,
+ u32 *ret_agent_id, u8 **name)
+{
+ const struct scmi_base_ops *ops = device_get_ops(dev);
+
+ if (ops->base_discover_agent)
+ return (*ops->base_discover_agent)(dev, agent_id, ret_agent_id,
+ name);
+
+ return -EOPNOTSUPP;
+}
+
+int scmi_base_notify_errors(struct udevice *dev, u32 enable)
+{
+ const struct scmi_base_ops *ops = device_get_ops(dev);
+
+ if (ops->base_notify_errors)
+ return (*ops->base_notify_errors)(dev, enable);
+
+ return -EOPNOTSUPP;
+}
+
+int scmi_base_set_device_permissions(struct udevice *dev, u32 agent_id,
+ u32 device_id, u32 flags)
+{
+ const struct scmi_base_ops *ops = device_get_ops(dev);
+
+ if (ops->base_set_device_permissions)
+ return (*ops->base_set_device_permissions)(dev, agent_id,
+ device_id, flags);
+
+ return -EOPNOTSUPP;
+}
+
+int scmi_base_set_protocol_permissions(struct udevice *dev,
+ u32 agent_id, u32 device_id,
+ u32 command_id, u32 flags)
+{
+ const struct scmi_base_ops *ops = device_get_ops(dev);
+
+ if (ops->base_set_protocol_permissions)
+ return (*ops->base_set_protocol_permissions)(dev, agent_id,
+ device_id,
+ command_id,
+ flags);
+
+ return -EOPNOTSUPP;
+}
+
+int scmi_base_reset_agent_configuration(struct udevice *dev, u32 agent_id,
+ u32 flags)
+{
+ const struct scmi_base_ops *ops = device_get_ops(dev);
+
+ if (ops->base_reset_agent_configuration)
+ return (*ops->base_reset_agent_configuration)(dev, agent_id,
+ flags);
+
+ return -EOPNOTSUPP;
+}
+
+U_BOOT_DRIVER(scmi_base_drv) = {
+ .id = UCLASS_SCMI_BASE,
+ .name = "scmi_base_drv",
+ .ops = &scmi_base_ops,
+ .probe = scmi_base_probe,
+};
+
+UCLASS_DRIVER(scmi_base) = {
+ .id = UCLASS_SCMI_BASE,
+ .name = "scmi_base",
+};
diff --git a/drivers/firmware/scmi/mailbox_agent.c b/drivers/firmware/scmi/mailbox_agent.c
index 8277c186060..7ad3e8da9f0 100644
--- a/drivers/firmware/scmi/mailbox_agent.c
+++ b/drivers/firmware/scmi/mailbox_agent.c
@@ -94,13 +94,14 @@ static int setup_channel(struct udevice *dev, struct scmi_mbox_channel *chan)
}
static int scmi_mbox_get_channel(struct udevice *dev,
+ struct udevice *protocol,
struct scmi_channel **channel)
{
struct scmi_mbox_channel *base_chan = dev_get_plat(dev);
struct scmi_mbox_channel *chan;
int ret;
- if (!dev_read_prop(dev, "shmem", NULL)) {
+ if (!dev_read_prop(protocol, "shmem", NULL)) {
/* Uses agent base channel */
*channel = container_of(base_chan, struct scmi_channel, ref);
@@ -112,7 +113,7 @@ static int scmi_mbox_get_channel(struct udevice *dev,
return -ENOMEM;
/* Setup a dedicated channel for the protocol */
- ret = setup_channel(dev, chan);
+ ret = setup_channel(protocol, chan);
if (ret) {
free(chan);
return ret;
diff --git a/drivers/firmware/scmi/optee_agent.c b/drivers/firmware/scmi/optee_agent.c
index db927fb2140..48dbb88a3fb 100644
--- a/drivers/firmware/scmi/optee_agent.c
+++ b/drivers/firmware/scmi/optee_agent.c
@@ -149,7 +149,7 @@ static int open_channel(struct udevice *dev, struct scmi_optee_channel *chan,
struct tee_param param[1] = { };
int ret;
- memset(sess, 0, sizeof(sess));
+ memset(sess, 0, sizeof(*sess));
sess->tee = tee_find_device(NULL, NULL, NULL, NULL);
if (!sess->tee)
@@ -324,6 +324,7 @@ static int setup_channel(struct udevice *dev, struct scmi_optee_channel *chan)
}
static int scmi_optee_get_channel(struct udevice *dev,
+ struct udevice *protocol,
struct scmi_channel **channel)
{
struct scmi_optee_channel *base_chan = dev_get_plat(dev);
@@ -331,7 +332,7 @@ static int scmi_optee_get_channel(struct udevice *dev,
u32 channel_id;
int ret;
- if (dev_read_u32(dev, "linaro,optee-channel-id", &channel_id)) {
+ if (dev_read_u32(protocol, "linaro,optee-channel-id", &channel_id)) {
/* Uses agent base channel */
*channel = container_of(base_chan, struct scmi_channel, ref);
@@ -343,7 +344,7 @@ static int scmi_optee_get_channel(struct udevice *dev,
if (!chan)
return -ENOMEM;
- ret = setup_channel(dev, chan);
+ ret = setup_channel(protocol, chan);
if (ret) {
free(chan);
return ret;
diff --git a/drivers/firmware/scmi/pwdom.c b/drivers/firmware/scmi/pwdom.c
new file mode 100644
index 00000000000..de2ba4755ac
--- /dev/null
+++ b/drivers/firmware/scmi/pwdom.c
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * SCMI Power domain management protocol
+ *
+ * Copyright (C) 2023 Linaro Limited
+ * author: AKASHI Takahiro <takahiro.akashi@linaro.org>
+ */
+
+#include <dm.h>
+#include <malloc.h>
+#include <scmi_agent.h>
+#include <scmi_protocols.h>
+#include <string.h>
+#include <asm/types.h>
+
+int scmi_pwd_protocol_attrs(struct udevice *dev, int *num_pwdoms,
+ u64 *stats_addr, size_t *stats_len)
+{
+ struct scmi_pwd_protocol_attrs_out out;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_POWER_DOMAIN,
+ .message_id = SCMI_PROTOCOL_ATTRIBUTES,
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int ret;
+
+ if (!dev || !num_pwdoms || !stats_addr || !stats_len)
+ return -EINVAL;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+ if (out.status)
+ return scmi_to_linux_errno(out.status);
+
+ *num_pwdoms = SCMI_PWD_PROTO_ATTRS_NUM_PWD(out.attributes);
+ *stats_addr = ((u64)out.stats_addr_high << 32) + out.stats_addr_low;
+ *stats_len = out.stats_len;
+
+ return 0;
+}
+
+int scmi_pwd_protocol_message_attrs(struct udevice *dev, s32 message_id,
+ u32 *attributes)
+{
+ struct scmi_pwd_protocol_msg_attrs_out out;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_POWER_DOMAIN,
+ .message_id = SCMI_PROTOCOL_MESSAGE_ATTRIBUTES,
+ .in_msg = (u8 *)&message_id,
+ .in_msg_sz = sizeof(message_id),
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int ret;
+
+ if (!dev || !attributes)
+ return -EINVAL;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+ if (out.status)
+ return scmi_to_linux_errno(out.status);
+
+ *attributes = out.attributes;
+
+ return 0;
+}
+
+int scmi_pwd_attrs(struct udevice *dev, u32 domain_id, u32 *attributes,
+ u8 **name)
+{
+ struct scmi_pwd_attrs_out out;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_POWER_DOMAIN,
+ .message_id = SCMI_PWD_ATTRIBUTES,
+ .in_msg = (u8 *)&domain_id,
+ .in_msg_sz = sizeof(domain_id),
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int ret;
+
+ if (!dev || !attributes || !name)
+ return -EINVAL;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+ if (out.status)
+ return scmi_to_linux_errno(out.status);
+
+ *name = strdup(out.name);
+ if (!*name)
+ return -ENOMEM;
+
+ *attributes = out.attributes;
+
+ return 0;
+}
+
+int scmi_pwd_state_set(struct udevice *dev, u32 flags, u32 domain_id,
+ u32 pstate)
+{
+ struct scmi_pwd_state_set_in in;
+ s32 status;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_POWER_DOMAIN,
+ .message_id = SCMI_PWD_STATE_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.flags = flags;
+ in.domain_id = domain_id;
+ in.pstate = pstate;
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+ if (status)
+ return scmi_to_linux_errno(status);
+
+ return 0;
+}
+
+int scmi_pwd_state_get(struct udevice *dev, u32 domain_id, u32 *pstate)
+{
+ struct scmi_pwd_state_get_out out;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_POWER_DOMAIN,
+ .message_id = SCMI_PWD_STATE_GET,
+ .in_msg = (u8 *)&domain_id,
+ .in_msg_sz = sizeof(domain_id),
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int ret;
+
+ if (!dev || !pstate)
+ return -EINVAL;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+ if (out.status)
+ return scmi_to_linux_errno(out.status);
+
+ *pstate = out.pstate;
+
+ return 0;
+}
+
+int scmi_pwd_name_get(struct udevice *dev, u32 domain_id, u8 **name)
+{
+ struct scmi_pwd_name_get_out out;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_POWER_DOMAIN,
+ .message_id = SCMI_PWD_NAME_GET,
+ .in_msg = (u8 *)&domain_id,
+ .in_msg_sz = sizeof(domain_id),
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int ret;
+
+ if (!dev || !name)
+ return -EINVAL;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+ if (out.status)
+ return scmi_to_linux_errno(out.status);
+
+ *name = strdup(out.extended_name);
+ if (!*name)
+ return -ENOMEM;
+
+ return 0;
+}
diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c
index 031882998df..cc9011c7312 100644
--- a/drivers/firmware/scmi/sandbox-scmi_agent.c
+++ b/drivers/firmware/scmi/sandbox-scmi_agent.c
@@ -14,11 +14,14 @@
#include <asm/io.h>
#include <asm/scmi_test.h>
#include <dm/device_compat.h>
+#include <linux/bitfield.h>
+#include <linux/kernel.h>
/*
* The sandbox SCMI agent driver simulates to some extend a SCMI message
* processing. It simulates few of the SCMI services for some of the
* SCMI protocols embedded in U-Boot. Currently:
+ * - SCMI base protocol
* - SCMI clock protocol emulates an agent exposing 2 clocks
* - SCMI reset protocol emulates an agent exposing a reset controller
* - SCMI voltage domain protocol emulates an agent exposing 2 regulators
@@ -33,6 +36,50 @@
* various uclass devices, as clocks and reset controllers.
*/
+#define SANDBOX_SCMI_BASE_PROTOCOL_VERSION SCMI_BASE_PROTOCOL_VERSION
+#define SANDBOX_SCMI_VENDOR "U-Boot"
+#define SANDBOX_SCMI_SUB_VENDOR "Sandbox"
+#define SANDBOX_SCMI_IMPL_VERSION 0x1
+#define SANDBOX_SCMI_AGENT_NAME "OSPM"
+#define SANDBOX_SCMI_PLATFORM_NAME "platform"
+
+#define SANDBOX_SCMI_PWD_PROTOCOL_VERSION SCMI_PWD_PROTOCOL_VERSION
+
+/**
+ * struct sandbox_channel - Description of sandbox transport
+ * @channel_id: Channel identifier
+ *
+ * Dummy channel. This will be used to test if a protocol-specific
+ * channel is properly used.
+ * Id 0 means a channel for the sandbox agent.
+ */
+struct sandbox_channel {
+ unsigned int channel_id;
+};
+
+/**
+ * struct scmi_channel - Channel instance referenced in SCMI drivers
+ * @ref: Reference to local channel instance
+ **/
+struct scmi_channel {
+ struct sandbox_channel ref;
+};
+
+static u8 protocols[] = {
+ CONFIG_IS_ENABLED(SCMI_POWER_DOMAIN, (SCMI_PROTOCOL_ID_POWER_DOMAIN,))
+ CONFIG_IS_ENABLED(CLK_SCMI, (SCMI_PROTOCOL_ID_CLOCK,))
+ CONFIG_IS_ENABLED(RESET_SCMI, (SCMI_PROTOCOL_ID_RESET_DOMAIN,))
+ CONFIG_IS_ENABLED(DM_REGULATOR_SCMI, (SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,))
+};
+
+#define NUM_PROTOCOLS ARRAY_SIZE(protocols)
+
+static struct sandbox_scmi_pwd scmi_pwdom[] = {
+ { .id = 0 },
+ { .id = 1 },
+ { .id = 2 },
+};
+
static struct sandbox_scmi_clk scmi_clk[] = {
{ .rate = 333 },
{ .rate = 200 },
@@ -48,11 +95,9 @@ static struct sandbox_scmi_voltd scmi_voltd[] = {
{ .id = 1, .voltage_uv = 1800000 },
};
-static struct sandbox_scmi_service sandbox_scmi_service_state;
-
-struct sandbox_scmi_service *sandbox_scmi_service_ctx(void)
+struct sandbox_scmi_agent *sandbox_scmi_agent_ctx(struct udevice *dev)
{
- return &sandbox_scmi_service_state;
+ return dev_get_priv(dev);
}
static void debug_print_agent_state(struct udevice *dev, char *str)
@@ -114,6 +159,548 @@ static struct sandbox_scmi_voltd *get_scmi_voltd_state(uint domain_id)
* Sandbox SCMI agent ops
*/
+/* Base Protocol */
+
+/**
+ * sandbox_scmi_base_protocol_version - implement SCMI_BASE_PROTOCOL_VERSION
+ * @dev: SCMI device
+ * @msg: SCMI message
+ *
+ * Implement SCMI_BASE_PROTOCOL_VERSION command.
+ */
+static int sandbox_scmi_base_protocol_version(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct scmi_protocol_version_out *out = NULL;
+
+ if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ out = (struct scmi_protocol_version_out *)msg->out_msg;
+ out->version = SANDBOX_SCMI_BASE_PROTOCOL_VERSION;
+ out->status = SCMI_SUCCESS;
+
+ return 0;
+}
+
+/**
+ * sandbox_scmi_base_protocol_attrs - implement SCMI_BASE_PROTOCOL_ATTRIBUTES
+ * @dev: SCMI device
+ * @msg: SCMI message
+ *
+ * Implement SCMI_BASE_PROTOCOL_ATTRIBUTES command.
+ */
+static int sandbox_scmi_base_protocol_attrs(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct scmi_protocol_attrs_out *out = NULL;
+
+ if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ out = (struct scmi_protocol_attrs_out *)msg->out_msg;
+ out->attributes = FIELD_PREP(0xff00, 2) | NUM_PROTOCOLS;
+ out->status = SCMI_SUCCESS;
+
+ return 0;
+}
+
+/**
+ * sandbox_scmi_base_message_attrs - implement
+ * SCMI_BASE_PROTOCOL_MESSAGE_ATTRIBUTES
+ * @dev: SCMI device
+ * @msg: SCMI message
+ *
+ * Implement SCMI_BASE_PROTOCOL_MESSAGE_ATTRIBUTES command.
+ */
+static int sandbox_scmi_base_message_attrs(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ u32 message_id;
+ struct scmi_protocol_msg_attrs_out *out = NULL;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(message_id) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ message_id = *(u32 *)msg->in_msg;
+ out = (struct scmi_protocol_msg_attrs_out *)msg->out_msg;
+
+ if (message_id >= SCMI_PROTOCOL_VERSION &&
+ message_id <= SCMI_BASE_RESET_AGENT_CONFIGURATION &&
+ message_id != SCMI_BASE_NOTIFY_ERRORS) {
+ out->attributes = 0;
+ out->status = SCMI_SUCCESS;
+ } else {
+ out->status = SCMI_NOT_FOUND;
+ }
+
+ return 0;
+}
+
+/**
+ * sandbox_scmi_base_discover_vendor - implement SCMI_BASE_DISCOVER_VENDOR
+ * @dev: SCMI device
+ * @msg: SCMI message
+ *
+ * Implement SCMI_BASE_DISCOVER_VENDOR command
+ */
+static int sandbox_scmi_base_discover_vendor(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct scmi_base_discover_vendor_out *out = NULL;
+
+ if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ out = (struct scmi_base_discover_vendor_out *)msg->out_msg;
+ strcpy(out->vendor_identifier, SANDBOX_SCMI_VENDOR);
+ out->status = SCMI_SUCCESS;
+
+ return 0;
+}
+
+/**
+ * sandbox_scmi_base_discover_sub_vendor - implement
+ * SCMI_BASE_DISCOVER_SUB_VENDOR
+ * @dev: SCMI device
+ * @msg: SCMI message
+ *
+ * Implement SCMI_BASE_DISCOVER_SUB_VENDOR command
+ */
+static int sandbox_scmi_base_discover_sub_vendor(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct scmi_base_discover_vendor_out *out = NULL;
+
+ if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ out = (struct scmi_base_discover_vendor_out *)msg->out_msg;
+ strcpy(out->vendor_identifier, SANDBOX_SCMI_SUB_VENDOR);
+ out->status = SCMI_SUCCESS;
+
+ return 0;
+}
+
+/**
+ * sandbox_scmi_base_discover_impl_version - implement
+ * SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION
+ * @dev: SCMI device
+ * @msg: SCMI message
+ *
+ * Implement SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION command
+ */
+static int sandbox_scmi_base_discover_impl_version(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct scmi_base_discover_impl_version_out *out = NULL;
+
+ if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ out = (struct scmi_base_discover_impl_version_out *)msg->out_msg;
+ out->impl_version = SANDBOX_SCMI_IMPL_VERSION;
+ out->status = SCMI_SUCCESS;
+
+ return 0;
+}
+
+/**
+ * sandbox_scmi_base_discover_list_protocols - implement
+ * SCMI_BASE_DISCOVER_LIST_PROTOCOLS
+ * @dev: SCMI device
+ * @msg: SCMI message
+ *
+ * Implement SCMI_BASE_DISCOVER_LIST_PROTOCOLS command
+ */
+static int sandbox_scmi_base_discover_list_protocols(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct scmi_base_discover_list_protocols_out *out = NULL;
+
+ if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ out = (struct scmi_base_discover_list_protocols_out *)msg->out_msg;
+ memcpy(out->protocols, protocols, sizeof(protocols));
+ out->num_protocols = NUM_PROTOCOLS;
+ out->status = SCMI_SUCCESS;
+
+ return 0;
+}
+
+/**
+ * sandbox_scmi_base_discover_agent - implement SCMI_BASE_DISCOVER_AGENT
+ * @dev: SCMI device
+ * @msg: SCMI message
+ *
+ * Implement SCMI_BASE_DISCOVER_AGENT command
+ */
+static int sandbox_scmi_base_discover_agent(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ u32 agent_id;
+ struct scmi_base_discover_agent_out *out = NULL;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(agent_id) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ agent_id = *(u32 *)msg->in_msg;
+ out = (struct scmi_base_discover_agent_out *)msg->out_msg;
+ out->status = SCMI_SUCCESS;
+ if (agent_id == 0xffffffff || agent_id == 1) {
+ out->agent_id = 1;
+ strcpy(out->name, SANDBOX_SCMI_AGENT_NAME);
+ } else if (!agent_id) {
+ out->agent_id = agent_id;
+ strcpy(out->name, SANDBOX_SCMI_PLATFORM_NAME);
+ } else {
+ out->status = SCMI_NOT_FOUND;
+ }
+
+ return 0;
+}
+
+/**
+ * sandbox_scmi_base_set_device_permissions - implement
+ * SCMI_BASE_SET_DEVICE_PERMISSIONS
+ * @dev: SCMI device
+ * @msg: SCMI message
+ *
+ * Implement SCMI_BASE_SET_DEVICE_PERMISSIONS command
+ */
+static int sandbox_scmi_base_set_device_permissions(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct scmi_base_set_device_permissions_in *in = NULL;
+ u32 *status;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*status))
+ return -EINVAL;
+
+ in = (struct scmi_base_set_device_permissions_in *)msg->in_msg;
+ status = (u32 *)msg->out_msg;
+
+ if (in->agent_id != 1 || in->device_id != 0)
+ *status = SCMI_NOT_FOUND;
+ else if (in->flags & ~SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS)
+ *status = SCMI_INVALID_PARAMETERS;
+ else if (in->flags & SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS)
+ *status = SCMI_SUCCESS;
+ else
+ /* unset not allowed */
+ *status = SCMI_DENIED;
+
+ return 0;
+}
+
+/**
+ * sandbox_scmi_base_set_protocol_permissions - implement
+ * SCMI_BASE_SET_PROTOCOL_PERMISSIONS
+ * @dev: SCMI device
+ * @msg: SCMI message
+ *
+ * Implement SCMI_BASE_SET_PROTOCOL_PERMISSIONS command
+ */
+static int sandbox_scmi_base_set_protocol_permissions(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct scmi_base_set_protocol_permissions_in *in = NULL;
+ u32 *status;
+ int i;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*status))
+ return -EINVAL;
+
+ in = (struct scmi_base_set_protocol_permissions_in *)msg->in_msg;
+ status = (u32 *)msg->out_msg;
+
+ for (i = 0; i < ARRAY_SIZE(protocols); i++)
+ if (protocols[i] == in->command_id)
+ break;
+ if (in->agent_id != 1 || in->device_id != 0 ||
+ i == ARRAY_SIZE(protocols))
+ *status = SCMI_NOT_FOUND;
+ else if (in->flags & ~SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS)
+ *status = SCMI_INVALID_PARAMETERS;
+ else if (in->flags & SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS)
+ *status = SCMI_SUCCESS;
+ else
+ /* unset not allowed */
+ *status = SCMI_DENIED;
+
+ return 0;
+}
+
+/**
+ * sandbox_scmi_base_reset_agent_configuration - implement
+ * SCMI_BASE_RESET_AGENT_CONFIGURATION
+ * @dev: SCMI device
+ * @msg: SCMI message
+ *
+ * Implement SCMI_BASE_RESET_AGENT_CONFIGURATION command
+ */
+static int sandbox_scmi_base_reset_agent_configuration(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct scmi_base_reset_agent_configuration_in *in = NULL;
+ u32 *status;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*status))
+ return -EINVAL;
+
+ in = (struct scmi_base_reset_agent_configuration_in *)msg->in_msg;
+ status = (u32 *)msg->out_msg;
+
+ if (in->agent_id != 1)
+ *status = SCMI_NOT_FOUND;
+ else if (in->flags & ~SCMI_BASE_RESET_ALL_ACCESS_PERMISSIONS)
+ *status = SCMI_INVALID_PARAMETERS;
+ else
+ *status = SCMI_DENIED;
+
+ return 0;
+}
+
+/* Power Domain Management Protocol */
+
+/**
+ * sandbox_scmi_pwd_protocol_version - implement SCMI_PROTOCOL_VERSION
+ * @dev: SCMI device
+ * @msg: SCMI message
+ *
+ * Implement SCMI_PROTOCOL_VERSION command.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int sandbox_scmi_pwd_protocol_version(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct scmi_protocol_version_out *out = NULL;
+
+ if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ out = (struct scmi_protocol_version_out *)msg->out_msg;
+ out->version = SANDBOX_SCMI_PWD_PROTOCOL_VERSION;
+ out->status = SCMI_SUCCESS;
+
+ return 0;
+}
+
+/**
+ * sandbox_scmi_pwd_protocol_attribs - implement SCMI_PWD_PROTOCOL_ATTRS
+ * @dev: SCMI device
+ * @msg: SCMI message
+ *
+ * Implement SCMI_PWD_PROTOCOL_ATTRS command.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int sandbox_scmi_pwd_protocol_attribs(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct scmi_pwd_protocol_attrs_out *out;
+
+ if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ out = (struct scmi_pwd_protocol_attrs_out *)msg->out_msg;
+
+ out->attributes = ARRAY_SIZE(scmi_pwdom);
+ out->stats_addr_low = 0;
+ out->stats_addr_high = 0;
+ out->stats_len = 0;
+ out->status = SCMI_SUCCESS;
+
+ return 0;
+}
+
+/**
+ * sandbox_scmi_pwd_protocol_msg_attribs - implement
+ SCMI_PWD_PROTOCOL_MESSAGE_ATTRS
+ * @dev: SCMI device
+ * @msg: SCMI message
+ *
+ * Implement SCMI_PWD_PROTOCOL_MESSAGE_ATTRS command.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int sandbox_scmi_pwd_protocol_msg_attribs(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ u32 message_id;
+ struct scmi_pwd_protocol_msg_attrs_out *out;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(message_id) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ message_id = *(u32 *)msg->in_msg;
+
+ out = (struct scmi_pwd_protocol_msg_attrs_out *)msg->out_msg;
+ if (message_id <= SCMI_PWD_STATE_GET ||
+ message_id == SCMI_PWD_NAME_GET) {
+ out->attributes = 0;
+ out->status = SCMI_SUCCESS;
+ } else {
+ out->status = SCMI_NOT_FOUND;
+ }
+
+ return 0;
+}
+
+/**
+ * sandbox_scmi_pwd_attribs - implement SCMI_PWD_ATTRS
+ * @dev: SCMI device
+ * @msg: SCMI message
+ *
+ * Implement SCMI_PWD_ATTRS command.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int sandbox_scmi_pwd_attribs(struct udevice *dev, struct scmi_msg *msg)
+{
+ u32 domain_id;
+ struct scmi_pwd_attrs_out *out;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(domain_id) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ domain_id = *(u32 *)msg->in_msg;
+ out = (struct scmi_pwd_attrs_out *)msg->out_msg;
+
+ if (domain_id >= ARRAY_SIZE(scmi_pwdom)) {
+ out->status = SCMI_NOT_FOUND;
+
+ return 0;
+ }
+
+ out->attributes =
+ SCMI_PWD_ATTR_PSTATE_SYNC | SCMI_PWD_ATTR_EXTENDED_NAME;
+ /* just 15-char + NULL */
+ snprintf(out->name, SCMI_PWD_NAME_LENGTH_MAX, "power-domain--%d",
+ domain_id);
+ out->status = SCMI_SUCCESS;
+
+ return 0;
+}
+
+/**
+ * sandbox_scmi_pwd_state_set - implement SCMI_PWD_STATE_SET
+ * @dev: SCMI device
+ * @msg: SCMI message
+ *
+ * Implement SCMI_PWD_STATE_SET command.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int sandbox_scmi_pwd_state_set(struct udevice *dev, struct scmi_msg *msg)
+{
+ struct scmi_pwd_state_set_in *in;
+ s32 *status;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(in) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*status))
+ return -EINVAL;
+
+ in = (struct scmi_pwd_state_set_in *)msg->in_msg;
+ status = (s32 *)msg->out_msg;
+
+ if (in->domain_id >= ARRAY_SIZE(scmi_pwdom)) {
+ *status = SCMI_NOT_FOUND;
+
+ return 0;
+ }
+
+ if ((in->flags & SCMI_PWD_SET_FLAGS_ASYNC) ||
+ (in->pstate != SCMI_PWD_PSTATE_TYPE_LOST && in->pstate)) {
+ *status = SCMI_INVALID_PARAMETERS;
+
+ return 0;
+ }
+
+ scmi_pwdom[in->domain_id].pstate = in->pstate;
+ *status = SCMI_SUCCESS;
+
+ return 0;
+}
+
+/**
+ * sandbox_scmi_pwd_state_get - implement SCMI_PWD_STATE_GET
+ * @dev: SCMI device
+ * @msg: SCMI message
+ *
+ * Implement SCMI_PWD_STATE_GET command.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int sandbox_scmi_pwd_state_get(struct udevice *dev, struct scmi_msg *msg)
+{
+ u32 domain_id;
+ struct scmi_pwd_state_get_out *out;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(domain_id) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ domain_id = *(u32 *)msg->in_msg;
+ out = (struct scmi_pwd_state_get_out *)msg->out_msg;
+
+ if (domain_id >= ARRAY_SIZE(scmi_pwdom)) {
+ out->status = SCMI_NOT_FOUND;
+
+ return 0;
+ }
+
+ out->pstate = scmi_pwdom[domain_id].pstate;
+ out->status = SCMI_SUCCESS;
+
+ return 0;
+}
+
+/**
+ * sandbox_scmi_pwd_name_get - implement SCMI_PWD_NAME_GET
+ * @dev: SCMI device
+ * @msg: SCMI message
+ *
+ * Implement SCMI_PWD_NAME_GET command.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int sandbox_scmi_pwd_name_get(struct udevice *dev, struct scmi_msg *msg)
+{
+ u32 domain_id;
+ struct scmi_pwd_name_get_out *out;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(domain_id) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ domain_id = *(u32 *)msg->in_msg;
+ out = (struct scmi_pwd_name_get_out *)msg->out_msg;
+
+ if (domain_id >= ARRAY_SIZE(scmi_pwdom)) {
+ out->status = SCMI_NOT_FOUND;
+
+ return 0;
+ }
+
+ snprintf(out->extended_name, SCMI_PWD_EXTENDED_NAME_MAX,
+ "power-domain--%d-extended", domain_id);
+ out->status = SCMI_SUCCESS;
+
+ return 0;
+}
+
+/* Clock Protocol */
+
static int sandbox_scmi_clock_protocol_attribs(struct udevice *dev,
struct scmi_msg *msg)
{
@@ -470,12 +1057,142 @@ static int sandbox_scmi_voltd_level_get(struct udevice *dev,
return 0;
}
+/**
+ * sandbox_scmi_of_get_channel - assigne a channel
+ * @dev: SCMI agent device
+ * @protocol: SCMI protocol device
+ * @channel: Pointer to channel info
+ *
+ * Assign a channel for the protocol, @protocol, in @channel,
+ * based on a device tree's property.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int sandbox_scmi_of_get_channel(struct udevice *dev,
+ struct udevice *protocol,
+ struct scmi_channel **channel)
+{
+ struct sandbox_channel *agent_chan = dev_get_plat(dev);
+ struct sandbox_channel *chan;
+ u32 channel_id;
+
+ if (dev_read_u32(protocol, "linaro,sandbox-channel-id", &channel_id)) {
+ /* Uses agent channel */
+ *channel = container_of(agent_chan, struct scmi_channel, ref);
+
+ return 0;
+ }
+
+ /* Setup a dedicated channel */
+ chan = calloc(1, sizeof(*chan));
+ if (!chan)
+ return -ENOMEM;
+
+ chan->channel_id = channel_id;
+
+ *channel = container_of(chan, struct scmi_channel, ref);
+
+ return 0;
+}
+
+/**
+ * sandbox_scmi_of_to_plat - assigne a channel to agent
+ * @dev: SCMI agent device
+ *
+ * Assign a channel for the agent, @protocol.
+ *
+ * Return: always 0
+ */
+static int sandbox_scmi_of_to_plat(struct udevice *dev)
+{
+ struct sandbox_channel *chan = dev_get_plat(dev);
+
+ /* The channel for agent is always 0 */
+ chan->channel_id = 0;
+
+ return 0;
+}
+
+unsigned int sandbox_scmi_channel_id(struct udevice *dev)
+{
+ struct scmi_agent_proto_priv *priv;
+ struct sandbox_channel *chan;
+
+ priv = dev_get_parent_priv(dev);
+ chan = (struct sandbox_channel *)&priv->channel->ref;
+
+ return chan->channel_id;
+}
+
+static int sandbox_proto_not_supported(struct scmi_msg *msg)
+{
+ *(u32 *)msg->out_msg = SCMI_NOT_SUPPORTED;
+
+ return 0;
+}
+
static int sandbox_scmi_test_process_msg(struct udevice *dev,
struct scmi_channel *channel,
struct scmi_msg *msg)
{
switch (msg->protocol_id) {
+ case SCMI_PROTOCOL_ID_BASE:
+ switch (msg->message_id) {
+ case SCMI_PROTOCOL_VERSION:
+ return sandbox_scmi_base_protocol_version(dev, msg);
+ case SCMI_PROTOCOL_ATTRIBUTES:
+ return sandbox_scmi_base_protocol_attrs(dev, msg);
+ case SCMI_PROTOCOL_MESSAGE_ATTRIBUTES:
+ return sandbox_scmi_base_message_attrs(dev, msg);
+ case SCMI_BASE_DISCOVER_VENDOR:
+ return sandbox_scmi_base_discover_vendor(dev, msg);
+ case SCMI_BASE_DISCOVER_SUB_VENDOR:
+ return sandbox_scmi_base_discover_sub_vendor(dev, msg);
+ case SCMI_BASE_DISCOVER_IMPL_VERSION:
+ return sandbox_scmi_base_discover_impl_version(dev, msg);
+ case SCMI_BASE_DISCOVER_LIST_PROTOCOLS:
+ return sandbox_scmi_base_discover_list_protocols(dev, msg);
+ case SCMI_BASE_DISCOVER_AGENT:
+ return sandbox_scmi_base_discover_agent(dev, msg);
+ case SCMI_BASE_NOTIFY_ERRORS:
+ break;
+ case SCMI_BASE_SET_DEVICE_PERMISSIONS:
+ return sandbox_scmi_base_set_device_permissions(dev, msg);
+ case SCMI_BASE_SET_PROTOCOL_PERMISSIONS:
+ return sandbox_scmi_base_set_protocol_permissions(dev, msg);
+ case SCMI_BASE_RESET_AGENT_CONFIGURATION:
+ return sandbox_scmi_base_reset_agent_configuration(dev, msg);
+ default:
+ break;
+ }
+ break;
+ case SCMI_PROTOCOL_ID_POWER_DOMAIN:
+ if (!CONFIG_IS_ENABLED(SCMI_POWER_DOMAIN))
+ return sandbox_proto_not_supported(msg);
+
+ switch (msg->message_id) {
+ case SCMI_PROTOCOL_VERSION:
+ return sandbox_scmi_pwd_protocol_version(dev, msg);
+ case SCMI_PROTOCOL_ATTRIBUTES:
+ return sandbox_scmi_pwd_protocol_attribs(dev, msg);
+ case SCMI_PROTOCOL_MESSAGE_ATTRIBUTES:
+ return sandbox_scmi_pwd_protocol_msg_attribs(dev, msg);
+ case SCMI_PWD_ATTRIBUTES:
+ return sandbox_scmi_pwd_attribs(dev, msg);
+ case SCMI_PWD_STATE_SET:
+ return sandbox_scmi_pwd_state_set(dev, msg);
+ case SCMI_PWD_STATE_GET:
+ return sandbox_scmi_pwd_state_get(dev, msg);
+ case SCMI_PWD_NAME_GET:
+ return sandbox_scmi_pwd_name_get(dev, msg);
+ default:
+ break;
+ }
+ break;
case SCMI_PROTOCOL_ID_CLOCK:
+ if (!CONFIG_IS_ENABLED(CLK_SCMI))
+ return sandbox_proto_not_supported(msg);
+
switch (msg->message_id) {
case SCMI_PROTOCOL_ATTRIBUTES:
return sandbox_scmi_clock_protocol_attribs(dev, msg);
@@ -492,6 +1209,9 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev,
}
break;
case SCMI_PROTOCOL_ID_RESET_DOMAIN:
+ if (!CONFIG_IS_ENABLED(RESET_SCMI))
+ return sandbox_proto_not_supported(msg);
+
switch (msg->message_id) {
case SCMI_RESET_DOMAIN_ATTRIBUTES:
return sandbox_scmi_rd_attribs(dev, msg);
@@ -502,6 +1222,9 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev,
}
break;
case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
+ if (!CONFIG_IS_ENABLED(DM_REGULATOR_SCMI))
+ return sandbox_proto_not_supported(msg);
+
switch (msg->message_id) {
case SCMI_VOLTAGE_DOMAIN_ATTRIBUTES:
return sandbox_scmi_voltd_attribs(dev, msg);
@@ -517,13 +1240,10 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev,
break;
}
break;
- case SCMI_PROTOCOL_ID_BASE:
- case SCMI_PROTOCOL_ID_POWER_DOMAIN:
case SCMI_PROTOCOL_ID_SYSTEM:
case SCMI_PROTOCOL_ID_PERF:
case SCMI_PROTOCOL_ID_SENSOR:
- *(u32 *)msg->out_msg = SCMI_NOT_SUPPORTED;
- return 0;
+ return sandbox_proto_not_supported(msg);
default:
break;
}
@@ -541,16 +1261,8 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev,
static int sandbox_scmi_test_remove(struct udevice *dev)
{
- struct sandbox_scmi_agent *agent = dev_get_priv(dev);
-
- if (agent != sandbox_scmi_service_ctx()->agent)
- return -EINVAL;
-
debug_print_agent_state(dev, "removed");
- /* We only need to dereference the agent in the context */
- sandbox_scmi_service_ctx()->agent = NULL;
-
return 0;
}
@@ -558,10 +1270,10 @@ static int sandbox_scmi_test_probe(struct udevice *dev)
{
struct sandbox_scmi_agent *agent = dev_get_priv(dev);
- if (sandbox_scmi_service_ctx()->agent)
- return -EINVAL;
-
*agent = (struct sandbox_scmi_agent){
+ .pwdom_version = SANDBOX_SCMI_PWD_PROTOCOL_VERSION,
+ .pwdom = scmi_pwdom,
+ .pwdom_count = ARRAY_SIZE(scmi_pwdom),
.clk = scmi_clk,
.clk_count = ARRAY_SIZE(scmi_clk),
.reset = scmi_reset,
@@ -572,9 +1284,6 @@ static int sandbox_scmi_test_probe(struct udevice *dev)
debug_print_agent_state(dev, "probed");
- /* Save reference for tests purpose */
- sandbox_scmi_service_ctx()->agent = agent;
-
return 0;
};
@@ -584,6 +1293,7 @@ static const struct udevice_id sandbox_scmi_test_ids[] = {
};
struct scmi_agent_ops sandbox_scmi_test_ops = {
+ .of_get_channel = sandbox_scmi_of_get_channel,
.process_msg = sandbox_scmi_test_process_msg,
};
@@ -592,6 +1302,8 @@ U_BOOT_DRIVER(sandbox_scmi_agent) = {
.id = UCLASS_SCMI_AGENT,
.of_match = sandbox_scmi_test_ids,
.priv_auto = sizeof(struct sandbox_scmi_agent),
+ .plat_auto = sizeof(struct sandbox_channel),
+ .of_to_plat = sandbox_scmi_of_to_plat,
.probe = sandbox_scmi_test_probe,
.remove = sandbox_scmi_test_remove,
.ops = &sandbox_scmi_test_ops,
diff --git a/drivers/firmware/scmi/sandbox-scmi_devices.c b/drivers/firmware/scmi/sandbox-scmi_devices.c
index 9baeb469ec0..603e2bb40af 100644
--- a/drivers/firmware/scmi/sandbox-scmi_devices.c
+++ b/drivers/firmware/scmi/sandbox-scmi_devices.c
@@ -29,12 +29,14 @@
/*
* struct sandbox_scmi_device_priv - Storage for device handles used by test
+ * @pwdom: Power domain device
* @clk: Array of clock instances used by tests
* @reset_clt: Array of the reset controller instances used by tests
* @regulators: Array of regulator device references used by the tests
* @devices: Resources exposed by sandbox_scmi_devices_ctx()
*/
struct sandbox_scmi_device_priv {
+ struct power_domain pwdom;
struct clk clk[SCMI_TEST_DEVICES_CLK_COUNT];
struct reset_ctl reset_ctl[SCMI_TEST_DEVICES_RD_COUNT];
struct udevice *regulators[SCMI_TEST_DEVICES_VOLTD_COUNT];
@@ -60,12 +62,13 @@ static int sandbox_scmi_devices_remove(struct udevice *dev)
if (!devices)
return 0;
- for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) {
- int ret2 = reset_free(devices->reset + n);
+ if (CONFIG_IS_ENABLED(RESET_SCMI))
+ for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) {
+ int ret2 = reset_free(devices->reset + n);
- if (ret2 && !ret)
- ret = ret2;
- }
+ if (ret2 && !ret)
+ ret = ret2;
+ }
return ret;
}
@@ -77,6 +80,8 @@ static int sandbox_scmi_devices_probe(struct udevice *dev)
size_t n;
priv->devices = (struct sandbox_scmi_devices){
+ .pwdom = &priv->pwdom,
+ .pwdom_count = 1,
.clk = priv->clk,
.clk_count = SCMI_TEST_DEVICES_CLK_COUNT,
.reset = priv->reset_ctl,
@@ -85,33 +90,53 @@ static int sandbox_scmi_devices_probe(struct udevice *dev)
.regul_count = SCMI_TEST_DEVICES_VOLTD_COUNT,
};
- for (n = 0; n < SCMI_TEST_DEVICES_CLK_COUNT; n++) {
- ret = clk_get_by_index(dev, n, priv->devices.clk + n);
+ if (CONFIG_IS_ENABLED(SCMI_POWER_DOMAIN)) {
+ ret = power_domain_get_by_index(dev, priv->devices.pwdom, 0);
if (ret) {
- dev_err(dev, "%s: Failed on clk %zu\n", __func__, n);
+ dev_err(dev, "%s: Failed on power domain\n", __func__);
return ret;
}
}
- for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) {
- ret = reset_get_by_index(dev, n, priv->devices.reset + n);
- if (ret) {
- dev_err(dev, "%s: Failed on reset %zu\n", __func__, n);
- goto err_reset;
+ if (CONFIG_IS_ENABLED(CLK_SCMI)) {
+ for (n = 0; n < SCMI_TEST_DEVICES_CLK_COUNT; n++) {
+ ret = clk_get_by_index(dev, n, priv->devices.clk + n);
+ if (ret) {
+ dev_err(dev, "%s: Failed on clk %zu\n",
+ __func__, n);
+ return ret;
+ }
}
}
- for (n = 0; n < SCMI_TEST_DEVICES_VOLTD_COUNT; n++) {
- char name[32];
-
- ret = snprintf(name, sizeof(name), "regul%zu-supply", n);
- assert(ret >= 0 && ret < sizeof(name));
+ if (CONFIG_IS_ENABLED(RESET_SCMI)) {
+ for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) {
+ ret = reset_get_by_index(dev, n,
+ priv->devices.reset + n);
+ if (ret) {
+ dev_err(dev, "%s: Failed on reset %zu\n",
+ __func__, n);
+ goto err_reset;
+ }
+ }
+ }
- ret = device_get_supply_regulator(dev, name,
- priv->devices.regul + n);
- if (ret) {
- dev_err(dev, "%s: Failed on voltd %zu\n", __func__, n);
- goto err_regul;
+ if (CONFIG_IS_ENABLED(DM_REGULATOR_SCMI)) {
+ for (n = 0; n < SCMI_TEST_DEVICES_VOLTD_COUNT; n++) {
+ char name[32];
+
+ ret = snprintf(name, sizeof(name), "regul%zu-supply",
+ n);
+ assert(ret >= 0 && ret < sizeof(name));
+
+ ret = device_get_supply_regulator(dev, name,
+ priv->devices.regul
+ + n);
+ if (ret) {
+ dev_err(dev, "%s: Failed on voltd %zu\n",
+ __func__, n);
+ goto err_regul;
+ }
}
}
@@ -120,8 +145,9 @@ static int sandbox_scmi_devices_probe(struct udevice *dev)
err_regul:
n = SCMI_TEST_DEVICES_RD_COUNT;
err_reset:
- for (; n > 0; n--)
- reset_free(priv->devices.reset + n - 1);
+ if (CONFIG_IS_ENABLED(RESET_SCMI))
+ for (; n > 0; n--)
+ reset_free(priv->devices.reset + n - 1);
return ret;
}
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c
index 02de692d66f..0f1003e167e 100644
--- a/drivers/firmware/scmi/scmi_agent-uclass.c
+++ b/drivers/firmware/scmi/scmi_agent-uclass.c
@@ -8,6 +8,7 @@
#include <common.h>
#include <dm.h>
#include <errno.h>
+#include <scmi_agent.h>
#include <scmi_agent-uclass.h>
#include <scmi_protocols.h>
#include <dm/device_compat.h>
@@ -37,6 +38,124 @@ static const struct error_code scmi_linux_errmap[] = {
{ .scmi = SCMI_PROTOCOL_ERROR, .errno = -EPROTO, },
};
+/**
+ * scmi_protocol_is_supported - check availability of protocol
+ * @dev: SCMI agent device
+ * @proto_id: Identifier of protocol
+ *
+ * check if the protocol, @proto_id, is provided by the SCMI agent,
+ * @dev.
+ *
+ * Return: 0 on success, error code otherwise
+ */
+static bool scmi_protocol_is_supported(struct udevice *dev,
+ enum scmi_std_protocol proto_id)
+{
+ struct scmi_agent_priv *priv;
+ int i;
+
+ if (proto_id == SCMI_PROTOCOL_ID_BASE)
+ return true;
+
+ priv = dev_get_uclass_plat(dev);
+ if (!priv) {
+ dev_err(dev, "No priv data found\n");
+ return false;
+ }
+
+ for (i = 0; i < priv->num_protocols; i++)
+ if (priv->protocols[i] == proto_id)
+ return true;
+
+ return false;
+}
+
+struct udevice *scmi_get_protocol(struct udevice *dev,
+ enum scmi_std_protocol id)
+{
+ struct scmi_agent_priv *priv;
+ struct udevice *proto;
+
+ priv = dev_get_uclass_plat(dev);
+ if (!priv) {
+ dev_err(dev, "No priv data found\n");
+ return NULL;
+ }
+
+ switch (id) {
+ case SCMI_PROTOCOL_ID_BASE:
+ proto = priv->base_dev;
+ break;
+ case SCMI_PROTOCOL_ID_POWER_DOMAIN:
+ proto = priv->pwdom_dev;
+ break;
+ case SCMI_PROTOCOL_ID_CLOCK:
+ proto = priv->clock_dev;
+ break;
+ case SCMI_PROTOCOL_ID_RESET_DOMAIN:
+ proto = priv->resetdom_dev;
+ break;
+ case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
+ proto = priv->voltagedom_dev;
+ break;
+ default:
+ dev_err(dev, "Protocol not supported\n");
+ proto = NULL;
+ break;
+ }
+ if (proto && device_probe(proto))
+ dev_err(dev, "Probe failed\n");
+
+ return proto;
+}
+
+/**
+ * scmi_add_protocol - add protocol to agent
+ * @dev: SCMI agent device
+ * @proto_id: SCMI protocol ID
+ * @proto: SCMI protocol device
+ *
+ * Associate the protocol instance, @proto, to the agent, @dev,
+ * for later use.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_add_protocol(struct udevice *dev,
+ enum scmi_std_protocol proto_id,
+ struct udevice *proto)
+{
+ struct scmi_agent_priv *priv;
+
+ priv = dev_get_uclass_plat(dev);
+ if (!priv) {
+ dev_err(dev, "No priv data found\n");
+ return -ENODEV;
+ }
+
+ switch (proto_id) {
+ case SCMI_PROTOCOL_ID_BASE:
+ priv->base_dev = proto;
+ break;
+ case SCMI_PROTOCOL_ID_POWER_DOMAIN:
+ priv->pwdom_dev = proto;
+ break;
+ case SCMI_PROTOCOL_ID_CLOCK:
+ priv->clock_dev = proto;
+ break;
+ case SCMI_PROTOCOL_ID_RESET_DOMAIN:
+ priv->resetdom_dev = proto;
+ break;
+ case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
+ priv->voltagedom_dev = proto;
+ break;
+ default:
+ dev_err(dev, "Protocol not supported\n");
+ return -EPROTO;
+ }
+
+ return 0;
+}
+
int scmi_to_linux_errno(s32 scmi_code)
{
int n;
@@ -51,8 +170,191 @@ int scmi_to_linux_errno(s32 scmi_code)
return -EPROTO;
}
+static struct udevice *find_scmi_protocol_device(struct udevice *dev)
+{
+ struct udevice *parent = NULL, *protocol;
+
+ for (protocol = dev; protocol; protocol = parent) {
+ parent = dev_get_parent(protocol);
+ if (!parent ||
+ device_get_uclass_id(parent) == UCLASS_SCMI_AGENT)
+ break;
+ }
+
+ if (!parent) {
+ dev_err(dev, "Invalid SCMI device, agent not found\n");
+ return NULL;
+ }
+
+ return protocol;
+}
+
+static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev)
+{
+ return (const struct scmi_agent_ops *)dev->driver->ops;
+}
+
+/**
+ * scmi_of_get_channel() - Get SCMI channel handle
+ *
+ * @dev: SCMI agent device
+ * @channel: Output reference to the SCMI channel upon success
+ *
+ * On return, @channel will be set.
+ * Return 0 on success and a negative errno on failure
+ */
+static int scmi_of_get_channel(struct udevice *dev, struct udevice *protocol,
+ struct scmi_channel **channel)
+{
+ const struct scmi_agent_ops *ops;
+
+ ops = transport_dev_ops(dev);
+ if (ops->of_get_channel)
+ return ops->of_get_channel(dev, protocol, channel);
+ else
+ return -EPROTONOSUPPORT;
+}
+
+int devm_scmi_of_get_channel(struct udevice *dev)
+{
+ struct udevice *protocol;
+ struct scmi_agent_proto_priv *priv;
+ int ret;
+
+ protocol = find_scmi_protocol_device(dev);
+ if (!protocol)
+ return -ENODEV;
+
+ priv = dev_get_parent_priv(protocol);
+ ret = scmi_of_get_channel(protocol->parent, protocol, &priv->channel);
+ if (ret == -EPROTONOSUPPORT) {
+ /* Drivers without a get_channel operator don't need a channel ref */
+ priv->channel = NULL;
+
+ return 0;
+ }
+
+ return ret;
+}
+
+/**
+ * scmi_process_msg() - Send and process an SCMI message
+ *
+ * Send a message to an SCMI server.
+ * Caller sets scmi_msg::out_msg_sz to the output message buffer size.
+ *
+ * @dev: SCMI agent device
+ * @channel: Communication channel for the device
+ * @msg: Message structure reference
+ *
+ * On return, scmi_msg::out_msg_sz stores the response payload size.
+ * Return: 0 on success and a negative errno on failure
+ */
+static int scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
+ struct scmi_msg *msg)
+{
+ const struct scmi_agent_ops *ops;
+
+ ops = transport_dev_ops(dev);
+ if (ops->process_msg)
+ return ops->process_msg(dev, channel, msg);
+ else
+ return -EPROTONOSUPPORT;
+}
+
+int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg)
+{
+ struct udevice *protocol;
+ struct scmi_agent_proto_priv *priv;
+
+ protocol = find_scmi_protocol_device(dev);
+ if (!protocol)
+ return -ENODEV;
+
+ priv = dev_get_parent_priv(protocol);
+
+ return scmi_process_msg(protocol->parent, priv->channel, msg);
+}
+
+/**
+ * scmi_fill_base_info - get base information about SCMI server
+ * @agent: SCMI agent device
+ * @dev: SCMI protocol device
+ *
+ * By using Base protocol commands, collect the base information
+ * about SCMI server.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_fill_base_info(struct udevice *agent, struct udevice *dev)
+{
+ struct scmi_agent_priv *priv = dev_get_uclass_plat(agent);
+ int ret;
+
+ ret = scmi_base_protocol_version(dev, &priv->version);
+ if (ret) {
+ dev_err(dev, "protocol_version() failed (%d)\n", ret);
+ return ret;
+ }
+ /* check for required version */
+ if (priv->version < SCMI_BASE_PROTOCOL_VERSION) {
+ dev_err(dev, "base protocol version (%d) lower than expected\n",
+ priv->version);
+ return -EPROTO;
+ }
+
+ ret = scmi_base_protocol_attrs(dev, &priv->num_agents,
+ &priv->num_protocols);
+ if (ret) {
+ dev_err(dev, "protocol_attrs() failed (%d)\n", ret);
+ return ret;
+ }
+ ret = scmi_base_discover_vendor(dev, &priv->vendor);
+ if (ret) {
+ dev_err(dev, "base_discover_vendor() failed (%d)\n", ret);
+ return ret;
+ }
+ ret = scmi_base_discover_sub_vendor(dev, &priv->sub_vendor);
+ if (ret) {
+ if (ret != -EOPNOTSUPP) {
+ dev_err(dev, "base_discover_sub_vendor() failed (%d)\n",
+ ret);
+ return ret;
+ }
+ priv->sub_vendor = "NA";
+ }
+ ret = scmi_base_discover_impl_version(dev, &priv->impl_version);
+ if (ret) {
+ dev_err(dev, "base_discover_impl_version() failed (%d)\n",
+ ret);
+ return ret;
+ }
+
+ ret = scmi_base_discover_agent(dev, 0xffffffff,
+ &priv->agent_id, &priv->agent_name);
+ if (ret) {
+ if (ret != -EOPNOTSUPP) {
+ dev_err(dev,
+ "base_discover_agent() failed for myself (%d)\n",
+ ret);
+ return ret;
+ }
+ priv->agent_id = 0xffffffff;
+ priv->agent_name = "NA";
+ }
+
+ ret = scmi_base_discover_list_protocols(dev, &priv->protocols);
+ if (ret != priv->num_protocols) {
+ dev_err(dev, "base_discover_list_protocols() failed (%d)\n",
+ ret);
+ return -EPROTO;
+ }
+
+ return 0;
+}
+
/*
- * SCMI agent devices binds devices of various uclasses depeding on
+ * SCMI agent devices binds devices of various uclasses depending on
* the FDT description. scmi_bind_protocol() is a generic bind sequence
* called by the uclass at bind stage, that is uclass post_bind.
*/
@@ -61,9 +363,43 @@ static int scmi_bind_protocols(struct udevice *dev)
int ret = 0;
ofnode node;
const char *name;
+ struct driver *drv;
+ struct udevice *agent, *proto;
+
+ if (!uclass_get_device(UCLASS_SCMI_AGENT, 1, &agent)) {
+ /* This is a second SCMI agent */
+ dev_err(dev, "Cannot have more than one SCMI agent\n");
+ return -EEXIST;
+ }
+
+ /* initialize the device from device tree */
+ drv = DM_DRIVER_GET(scmi_base_drv);
+ name = "scmi-base.0";
+ ret = device_bind(dev, drv, name, NULL, ofnode_null(), &proto);
+ if (ret) {
+ dev_err(dev, "failed to bind base protocol\n");
+ return ret;
+ }
+ ret = scmi_add_protocol(dev, SCMI_PROTOCOL_ID_BASE, proto);
+ if (ret) {
+ dev_err(dev, "failed to add protocol: %s, ret: %d\n",
+ proto->name, ret);
+ return ret;
+ }
+
+ ret = device_probe(proto);
+ if (ret) {
+ dev_err(dev, "failed to probe base protocol\n");
+ return ret;
+ }
+
+ ret = scmi_fill_base_info(dev, proto);
+ if (ret) {
+ dev_err(dev, "failed to get base information\n");
+ return ret;
+ }
dev_for_each_subnode(node, dev) {
- struct driver *drv = NULL;
u32 protocol_id;
if (!ofnode_is_enabled(node))
@@ -72,18 +408,27 @@ static int scmi_bind_protocols(struct udevice *dev)
if (ofnode_read_u32(node, "reg", &protocol_id))
continue;
+ drv = NULL;
name = ofnode_get_name(node);
switch (protocol_id) {
+ case SCMI_PROTOCOL_ID_POWER_DOMAIN:
+ if (CONFIG_IS_ENABLED(SCMI_POWER_DOMAIN) &&
+ scmi_protocol_is_supported(dev, protocol_id))
+ drv = DM_DRIVER_GET(scmi_power_domain);
+ break;
case SCMI_PROTOCOL_ID_CLOCK:
- if (CONFIG_IS_ENABLED(CLK_SCMI))
+ if (CONFIG_IS_ENABLED(CLK_SCMI) &&
+ scmi_protocol_is_supported(dev, protocol_id))
drv = DM_DRIVER_GET(scmi_clock);
break;
case SCMI_PROTOCOL_ID_RESET_DOMAIN:
- if (IS_ENABLED(CONFIG_RESET_SCMI))
+ if (IS_ENABLED(CONFIG_RESET_SCMI) &&
+ scmi_protocol_is_supported(dev, protocol_id))
drv = DM_DRIVER_GET(scmi_reset_domain);
break;
case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
- if (IS_ENABLED(CONFIG_DM_REGULATOR_SCMI)) {
+ if (IS_ENABLED(CONFIG_DM_REGULATOR_SCMI) &&
+ scmi_protocol_is_supported(dev, protocol_id)) {
node = ofnode_find_subnode(node, "regulators");
if (!ofnode_valid(node)) {
dev_err(dev, "no regulators node\n");
@@ -102,70 +447,26 @@ static int scmi_bind_protocols(struct udevice *dev)
continue;
}
- ret = device_bind(dev, drv, name, NULL, node, NULL);
- if (ret)
+ ret = device_bind(dev, drv, name, NULL, node, &proto);
+ if (ret) {
+ dev_err(dev, "failed to bind %s protocol\n", drv->name);
+ break;
+ }
+ ret = scmi_add_protocol(dev, protocol_id, proto);
+ if (ret) {
+ dev_err(dev, "failed to add protocol: %s, ret: %d\n",
+ proto->name, ret);
break;
+ }
}
return ret;
}
-static struct udevice *find_scmi_transport_device(struct udevice *dev)
-{
- struct udevice *parent = dev;
-
- do {
- parent = dev_get_parent(parent);
- } while (parent && device_get_uclass_id(parent) != UCLASS_SCMI_AGENT);
-
- if (!parent)
- dev_err(dev, "Invalid SCMI device, agent not found\n");
-
- return parent;
-}
-
-static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev)
-{
- return (const struct scmi_agent_ops *)dev->driver->ops;
-}
-
-int devm_scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel)
-{
- struct udevice *parent;
-
- parent = find_scmi_transport_device(dev);
- if (!parent)
- return -ENODEV;
-
- if (transport_dev_ops(parent)->of_get_channel)
- return transport_dev_ops(parent)->of_get_channel(parent, channel);
-
- /* Drivers without a get_channel operator don't need a channel ref */
- *channel = NULL;
-
- return 0;
-}
-
-int devm_scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
- struct scmi_msg *msg)
-{
- const struct scmi_agent_ops *ops;
- struct udevice *parent;
-
- parent = find_scmi_transport_device(dev);
- if (!parent)
- return -ENODEV;
-
- ops = transport_dev_ops(parent);
-
- if (ops->process_msg)
- return ops->process_msg(parent, channel, msg);
-
- return -EPROTONOSUPPORT;
-}
-
UCLASS_DRIVER(scmi_agent) = {
.id = UCLASS_SCMI_AGENT,
.name = "scmi_agent",
.post_bind = scmi_bind_protocols,
+ .per_device_plat_auto = sizeof(struct scmi_agent_priv),
+ .per_child_auto = sizeof(struct scmi_agent_proto_priv),
};
diff --git a/drivers/firmware/scmi/smccc_agent.c b/drivers/firmware/scmi/smccc_agent.c
index 6a52cd75d67..972c6addde2 100644
--- a/drivers/firmware/scmi/smccc_agent.c
+++ b/drivers/firmware/scmi/smccc_agent.c
@@ -81,6 +81,7 @@ static int setup_channel(struct udevice *dev, struct scmi_smccc_channel *chan)
}
static int scmi_smccc_get_channel(struct udevice *dev,
+ struct udevice *protocol,
struct scmi_channel **channel)
{
struct scmi_smccc_channel *base_chan = dev_get_plat(dev);
@@ -88,7 +89,7 @@ static int scmi_smccc_get_channel(struct udevice *dev,
u32 func_id;
int ret;
- if (dev_read_u32(dev, "arm,smc-id", &func_id)) {
+ if (dev_read_u32(protocol, "arm,smc-id", &func_id)) {
/* Uses agent base channel */
*channel = container_of(base_chan, struct scmi_channel, ref);
@@ -100,7 +101,7 @@ static int scmi_smccc_get_channel(struct udevice *dev,
if (!chan)
return -ENOMEM;
- ret = setup_channel(dev, chan);
+ ret = setup_channel(protocol, chan);
if (ret) {
free(chan);
return ret;
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 166bd78ca50..6e9f93e9a30 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -3,7 +3,7 @@
* Texas Instruments System Control Interface Protocol Driver
* Based on drivers/firmware/ti_sci.c from Linux.
*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com>
*/
diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h
index 101210eb215..bb8bc7beead 100644
--- a/drivers/firmware/ti_sci.h
+++ b/drivers/firmware/ti_sci.h
@@ -6,7 +6,7 @@
* The system works in a message response protocol
* See: http://processors.wiki.ti.com/index.php/TISCI for details
*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
* Based on drivers/firmware/ti_sci.h from Linux.
*
*/
diff --git a/drivers/firmware/ti_sci_static_data.h b/drivers/firmware/ti_sci_static_data.h
index 1a461fab619..567ce8911a7 100644
--- a/drivers/firmware/ti_sci_static_data.h
+++ b/drivers/firmware/ti_sci_static_data.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
- * Copyright (C) 2021 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/
*
*/
diff --git a/drivers/fpga/zynqmppl.c b/drivers/fpga/zynqmppl.c
index b1f201fb18b..2656f5fc5ec 100644
--- a/drivers/fpga/zynqmppl.c
+++ b/drivers/fpga/zynqmppl.c
@@ -2,7 +2,7 @@
/*
* (C) Copyright 2015 - 2016, Xilinx, Inc,
* Michal Simek <michal.simek@amd.com>
- * Siva Durga Prasad <siva.durga.prasad.paladugu@amd.com>>
+ * Siva Durga Prasad Paladugu <siva.durga.prasad.paladugu@amd.com>
*/
#include <console.h>
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 9bf6e428ded..ba42b0768e1 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -372,6 +372,13 @@ config SUNXI_GPIO
help
Support the GPIO device in Allwinner SoCs.
+config SUNXI_NEW_PINCTRL
+ bool
+ depends on SUNXI_GPIO
+ ---help---
+ The Allwinner D1 and other new SoCs use a different register map
+ for the GPIO block, which we need to know about in the SPL.
+
config XILINX_GPIO
bool "Xilinx GPIO driver"
depends on DM_GPIO
@@ -659,4 +666,11 @@ config ADP5585_GPIO
help
Support ADP5585 GPIO expander.
+config RZG2L_GPIO
+ bool "Renesas RZ/G2L family GPIO driver"
+ depends on DM_GPIO && PINCTRL_RZG2L
+ help
+ Support the gpio functionality of the pin function controller (PFC)
+ on the Renesas RZ/G2L SoC family.
+
endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 64a36c472eb..c8b3fd78141 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -74,3 +74,4 @@ obj-$(CONFIG_SLG7XL45106_I2C_GPO) += gpio_slg7xl45106.o
obj-$(CONFIG_$(SPL_TPL_)TURRIS_OMNIA_MCU) += turris_omnia_mcu.o
obj-$(CONFIG_FTGPIO010) += ftgpio010.o
obj-$(CONFIG_ADP5585_GPIO) += adp5585_gpio.o
+obj-$(CONFIG_RZG2L_GPIO) += rzg2l-gpio.o
diff --git a/drivers/gpio/axp_gpio.c b/drivers/gpio/axp_gpio.c
index 49672193ffc..af6631697f5 100644
--- a/drivers/gpio/axp_gpio.c
+++ b/drivers/gpio/axp_gpio.c
@@ -14,6 +14,7 @@
#include <dm/lists.h>
#include <dm/root.h>
#include <errno.h>
+#include <sunxi_gpio.h>
static int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val);
diff --git a/drivers/gpio/pcf8575_gpio.c b/drivers/gpio/pcf8575_gpio.c
index d5930d941fc..f38e215c4d6 100644
--- a/drivers/gpio/pcf8575_gpio.c
+++ b/drivers/gpio/pcf8575_gpio.c
@@ -2,7 +2,7 @@
/*
* PCF8575 I2C GPIO EXPANDER DRIVER
*
- * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com/
*
* Vignesh R <vigneshr@ti.com>
*
diff --git a/drivers/gpio/rzg2l-gpio.c b/drivers/gpio/rzg2l-gpio.c
new file mode 100644
index 00000000000..2477af7874b
--- /dev/null
+++ b/drivers/gpio/rzg2l-gpio.c
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/G2L Pin Function Controller
+ *
+ * Copyright (C) 2021-2023 Renesas Electronics Corp.
+ */
+
+#include <asm-generic/gpio.h>
+#include <asm/io.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <renesas/rzg2l-pfc.h>
+
+static void rzg2l_gpio_set(const struct rzg2l_pfc_data *data, u32 port, u8 pin,
+ bool value)
+{
+ if (value)
+ setbits_8(data->base + P(port), BIT(pin));
+ else
+ clrbits_8(data->base + P(port), BIT(pin));
+}
+
+static int rzg2l_gpio_get_value(struct udevice *dev, unsigned int offset)
+{
+ const struct rzg2l_pfc_data *data =
+ (const struct rzg2l_pfc_data *)dev_get_driver_data(dev);
+ const u32 port = RZG2L_PINMUX_TO_PORT(offset);
+ const u8 pin = RZG2L_PINMUX_TO_PIN(offset);
+ u16 pm_state;
+
+ pm_state = (readw(data->base + PM(port)) >> (pin * 2)) & PM_MASK;
+ switch (pm_state) {
+ case PM_INPUT:
+ return !!(readb(data->base + PIN(port)) & BIT(pin));
+ case PM_OUTPUT:
+ case PM_OUTPUT_IEN:
+ return !!(readb(data->base + P(port)) & BIT(pin));
+ default: /* PM_HIGH_Z */
+ return 0;
+ }
+}
+
+static int rzg2l_gpio_set_value(struct udevice *dev, unsigned int offset,
+ int value)
+{
+ const struct rzg2l_pfc_data *data =
+ (const struct rzg2l_pfc_data *)dev_get_driver_data(dev);
+ const u32 port = RZG2L_PINMUX_TO_PORT(offset);
+ const u8 pin = RZG2L_PINMUX_TO_PIN(offset);
+
+ rzg2l_gpio_set(data, port, pin, (bool)value);
+ return 0;
+}
+
+static void rzg2l_gpio_set_direction(const struct rzg2l_pfc_data *data,
+ u32 port, u8 pin, bool output)
+{
+ clrsetbits_le16(data->base + PM(port), PM_MASK << (pin * 2),
+ (output ? PM_OUTPUT : PM_INPUT) << (pin * 2));
+}
+
+static int rzg2l_gpio_direction_input(struct udevice *dev, unsigned int offset)
+{
+ const struct rzg2l_pfc_data *data =
+ (const struct rzg2l_pfc_data *)dev_get_driver_data(dev);
+ const u32 port = RZG2L_PINMUX_TO_PORT(offset);
+ const u8 pin = RZG2L_PINMUX_TO_PIN(offset);
+
+ rzg2l_gpio_set_direction(data, port, pin, false);
+ return 0;
+}
+
+static int rzg2l_gpio_direction_output(struct udevice *dev, unsigned int offset,
+ int value)
+{
+ const struct rzg2l_pfc_data *data =
+ (const struct rzg2l_pfc_data *)dev_get_driver_data(dev);
+ const u32 port = RZG2L_PINMUX_TO_PORT(offset);
+ const u8 pin = RZG2L_PINMUX_TO_PIN(offset);
+
+ rzg2l_gpio_set(data, port, pin, (bool)value);
+ rzg2l_gpio_set_direction(data, port, pin, true);
+ return 0;
+}
+
+static int rzg2l_gpio_request(struct udevice *dev, unsigned int offset,
+ const char *label)
+{
+ const struct rzg2l_pfc_data *data =
+ (const struct rzg2l_pfc_data *)dev_get_driver_data(dev);
+ const u32 port = RZG2L_PINMUX_TO_PORT(offset);
+ const u8 pin = RZG2L_PINMUX_TO_PIN(offset);
+
+ if (!rzg2l_port_validate(data, port, pin)) {
+ dev_err(dev, "Invalid GPIO %u:%u\n", port, pin);
+ return -EINVAL;
+ }
+
+ /* Select GPIO mode in PMC Register */
+ clrbits_8(data->base + PMC(port), BIT(pin));
+
+ return 0;
+}
+
+static int rzg2l_gpio_get_function(struct udevice *dev, unsigned int offset)
+{
+ const struct rzg2l_pfc_data *data =
+ (const struct rzg2l_pfc_data *)dev_get_driver_data(dev);
+ const u32 port = RZG2L_PINMUX_TO_PORT(offset);
+ const u8 pin = RZG2L_PINMUX_TO_PIN(offset);
+ u16 pm_state;
+ u8 pmc_state;
+
+ if (!rzg2l_port_validate(data, port, pin)) {
+ /* This offset does not correspond to a valid GPIO pin. */
+ return -ENOENT;
+ }
+
+ /* Check if the pin is in GPIO or function mode. */
+ pmc_state = readb(data->base + PMC(port)) & BIT(pin);
+ if (pmc_state)
+ return GPIOF_FUNC;
+
+ /* Check the pin direction. */
+ pm_state = (readw(data->base + PM(port)) >> (pin * 2)) & PM_MASK;
+ switch (pm_state) {
+ case PM_INPUT:
+ return GPIOF_INPUT;
+ case PM_OUTPUT:
+ case PM_OUTPUT_IEN:
+ return GPIOF_OUTPUT;
+ default: /* PM_HIGH_Z */
+ return GPIOF_UNUSED;
+ }
+}
+
+static const struct dm_gpio_ops rzg2l_gpio_ops = {
+ .direction_input = rzg2l_gpio_direction_input,
+ .direction_output = rzg2l_gpio_direction_output,
+ .get_value = rzg2l_gpio_get_value,
+ .set_value = rzg2l_gpio_set_value,
+ .request = rzg2l_gpio_request,
+ .get_function = rzg2l_gpio_get_function,
+};
+
+static int rzg2l_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct ofnode_phandle_args args;
+ int ret;
+
+ uc_priv->bank_name = "rzg2l-pfc-gpio";
+ ret = ofnode_parse_phandle_with_args(dev_ofnode(dev), "gpio-ranges",
+ NULL, 3, 0, &args);
+ if (ret < 0) {
+ dev_err(dev, "Failed to parse gpio-ranges: %d\n", ret);
+ return -EINVAL;
+ }
+
+ uc_priv->gpio_count = args.args[2];
+ return rzg2l_pfc_enable(dev);
+}
+
+U_BOOT_DRIVER(rzg2l_pfc_gpio) = {
+ .name = "rzg2l-pfc-gpio",
+ .id = UCLASS_GPIO,
+ .ops = &rzg2l_gpio_ops,
+ .probe = rzg2l_gpio_probe,
+};
diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c
index f0b42e4fdb7..e4463a223f7 100644
--- a/drivers/gpio/sunxi_gpio.c
+++ b/drivers/gpio/sunxi_gpio.c
@@ -17,37 +17,165 @@
#include <asm/io.h>
#include <asm/gpio.h>
#include <dt-bindings/gpio/gpio.h>
+#include <sunxi_gpio.h>
-#if !CONFIG_IS_ENABLED(DM_GPIO)
-static int sunxi_gpio_output(u32 pin, u32 val)
+/*
+ * =======================================================================
+ * Low level GPIO/pin controller access functions, to be shared by non-DM
+ * SPL code and the DM pinctrl/GPIO drivers.
+ * The functions ending in "bank" take a base pointer to a GPIO bank, and
+ * the pin offset is relative to that bank.
+ * The functions without "bank" in their name take a linear GPIO number,
+ * covering all ports, and starting at 0 for PortA.
+ * =======================================================================
+ */
+
+#define GPIO_BANK(pin) ((pin) >> 5)
+#define GPIO_NUM(pin) ((pin) & 0x1f)
+
+#define GPIO_CFG_REG_OFFSET 0x00
+#define GPIO_CFG_INDEX(pin) (((pin) & 0x1f) >> 3)
+#define GPIO_CFG_OFFSET(pin) ((((pin) & 0x1f) & 0x7) << 2)
+
+#define GPIO_DAT_REG_OFFSET 0x10
+
+#define GPIO_DRV_REG_OFFSET 0x14
+
+/* Newer SoCs use a slightly different register layout */
+#ifdef CONFIG_SUNXI_NEW_PINCTRL
+/* pin drive strength: 4 bits per pin */
+#define GPIO_DRV_INDEX(pin) ((pin) / 8)
+#define GPIO_DRV_OFFSET(pin) (((pin) % 8) * 4)
+
+#define GPIO_PULL_REG_OFFSET 0x24
+
+#else /* older generation pin controllers */
+/* pin drive strength: 2 bits per pin */
+#define GPIO_DRV_INDEX(pin) ((pin) / 16)
+#define GPIO_DRV_OFFSET(pin) (((pin) % 16) * 2)
+
+#define GPIO_PULL_REG_OFFSET 0x1c
+#endif
+
+#define GPIO_PULL_INDEX(pin) (((pin) & 0x1f) >> 4)
+#define GPIO_PULL_OFFSET(pin) ((((pin) & 0x1f) & 0xf) << 1)
+
+static void* BANK_TO_GPIO(int bank)
+{
+ void *pio_base;
+
+ if (bank < SUNXI_GPIO_L) {
+ pio_base = (void *)(uintptr_t)SUNXI_PIO_BASE;
+ } else {
+ pio_base = (void *)(uintptr_t)SUNXI_R_PIO_BASE;
+ bank -= SUNXI_GPIO_L;
+ }
+
+ return pio_base + bank * SUNXI_PINCTRL_BANK_SIZE;
+}
+
+void sunxi_gpio_set_cfgbank(void *bank_base, int pin_offset, u32 val)
+{
+ u32 index = GPIO_CFG_INDEX(pin_offset);
+ u32 offset = GPIO_CFG_OFFSET(pin_offset);
+
+ clrsetbits_le32(bank_base + GPIO_CFG_REG_OFFSET + index * 4,
+ 0xfU << offset, val << offset);
+}
+
+void sunxi_gpio_set_cfgpin(u32 pin, u32 val)
{
- u32 dat;
u32 bank = GPIO_BANK(pin);
- u32 num = GPIO_NUM(pin);
- struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
+ void *pio = BANK_TO_GPIO(bank);
- dat = readl(&pio->dat);
- if (val)
- dat |= 0x1 << num;
- else
- dat &= ~(0x1 << num);
+ sunxi_gpio_set_cfgbank(pio, GPIO_NUM(pin), val);
+}
+
+int sunxi_gpio_get_cfgbank(void *bank_base, int pin_offset)
+{
+ u32 index = GPIO_CFG_INDEX(pin_offset);
+ u32 offset = GPIO_CFG_OFFSET(pin_offset);
+ u32 cfg;
- writel(dat, &pio->dat);
+ cfg = readl(bank_base + GPIO_CFG_REG_OFFSET + index * 4);
+ cfg >>= offset;
- return 0;
+ return cfg & 0xf;
+}
+
+int sunxi_gpio_get_cfgpin(u32 pin)
+{
+ u32 bank = GPIO_BANK(pin);
+ void *bank_base = BANK_TO_GPIO(bank);
+
+ return sunxi_gpio_get_cfgbank(bank_base, GPIO_NUM(pin));
+}
+
+static void sunxi_gpio_set_value_bank(void *bank_base, int pin, bool set)
+{
+ u32 mask = 1U << pin;
+
+ clrsetbits_le32(bank_base + GPIO_DAT_REG_OFFSET,
+ set ? 0 : mask, set ? mask : 0);
+}
+
+static int sunxi_gpio_get_value_bank(void *bank_base, int pin)
+{
+ return !!(readl(bank_base + GPIO_DAT_REG_OFFSET) & (1U << pin));
+}
+
+void sunxi_gpio_set_drv(u32 pin, u32 val)
+{
+ u32 bank = GPIO_BANK(pin);
+ void *bank_base = BANK_TO_GPIO(bank);
+
+ sunxi_gpio_set_drv_bank(bank_base, GPIO_NUM(pin), val);
+}
+
+void sunxi_gpio_set_drv_bank(void *bank_base, u32 pin_offset, u32 val)
+{
+ u32 index = GPIO_DRV_INDEX(pin_offset);
+ u32 offset = GPIO_DRV_OFFSET(pin_offset);
+
+ clrsetbits_le32(bank_base + GPIO_DRV_REG_OFFSET + index * 4,
+ 0x3U << offset, val << offset);
+}
+
+void sunxi_gpio_set_pull(u32 pin, u32 val)
+{
+ u32 bank = GPIO_BANK(pin);
+ void *bank_base = BANK_TO_GPIO(bank);
+
+ sunxi_gpio_set_pull_bank(bank_base, GPIO_NUM(pin), val);
}
-static int sunxi_gpio_input(u32 pin)
+void sunxi_gpio_set_pull_bank(void *bank_base, int pin_offset, u32 val)
+{
+ u32 index = GPIO_PULL_INDEX(pin_offset);
+ u32 offset = GPIO_PULL_OFFSET(pin_offset);
+
+ clrsetbits_le32(bank_base + GPIO_PULL_REG_OFFSET + index * 4,
+ 0x3U << offset, val << offset);
+}
+
+
+/* =========== Non-DM code, used by the SPL. ============ */
+
+#if !CONFIG_IS_ENABLED(DM_GPIO)
+static void sunxi_gpio_set_value(u32 pin, bool set)
{
- u32 dat;
u32 bank = GPIO_BANK(pin);
- u32 num = GPIO_NUM(pin);
- struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
+ void *pio = BANK_TO_GPIO(bank);
+
+ sunxi_gpio_set_value_bank(pio, GPIO_NUM(pin), set);
+}
- dat = readl(&pio->dat);
- dat >>= num;
+static int sunxi_gpio_get_value(u32 pin)
+{
+ u32 bank = GPIO_BANK(pin);
+ void *pio = BANK_TO_GPIO(bank);
- return dat & 0x1;
+ return sunxi_gpio_get_value_bank(pio, GPIO_NUM(pin));
}
int gpio_request(unsigned gpio, const char *label)
@@ -70,18 +198,21 @@ int gpio_direction_input(unsigned gpio)
int gpio_direction_output(unsigned gpio, int value)
{
sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT);
+ sunxi_gpio_set_value(gpio, value);
- return sunxi_gpio_output(gpio, value);
+ return 0;
}
int gpio_get_value(unsigned gpio)
{
- return sunxi_gpio_input(gpio);
+ return sunxi_gpio_get_value(gpio);
}
int gpio_set_value(unsigned gpio, int value)
{
- return sunxi_gpio_output(gpio, value);
+ sunxi_gpio_set_value(gpio, value);
+
+ return 0;
}
int sunxi_name_to_gpio(const char *name)
@@ -106,7 +237,9 @@ int sunxi_name_to_gpio(const char *name)
return -1;
return group * 32 + pin;
}
-#endif /* DM_GPIO */
+#endif /* !DM_GPIO */
+
+/* =========== DM code, used by U-Boot proper. ============ */
#if CONFIG_IS_ENABLED(DM_GPIO)
/* TODO(sjg@chromium.org): Remove this function and use device tree */
@@ -131,13 +264,8 @@ int sunxi_name_to_gpio(const char *name)
static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset)
{
struct sunxi_gpio_plat *plat = dev_get_plat(dev);
- u32 num = GPIO_NUM(offset);
- unsigned dat;
-
- dat = readl(&plat->regs->dat);
- dat >>= num;
- return dat & 0x1;
+ return sunxi_gpio_get_value_bank(plat->regs, offset);
}
static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset)
@@ -175,9 +303,8 @@ static int sunxi_gpio_set_flags(struct udevice *dev, unsigned int offset,
if (flags & GPIOD_IS_OUT) {
u32 value = !!(flags & GPIOD_IS_OUT_ACTIVE);
- u32 num = GPIO_NUM(offset);
- clrsetbits_le32(&plat->regs->dat, 1 << num, value << num);
+ sunxi_gpio_set_value_bank(plat->regs, offset, value);
sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT);
} else if (flags & GPIOD_IS_IN) {
u32 pull = 0;
diff --git a/drivers/gpio/tegra186_gpio.c b/drivers/gpio/tegra186_gpio.c
index 82dcaf96312..94a20d143e1 100644
--- a/drivers/gpio/tegra186_gpio.c
+++ b/drivers/gpio/tegra186_gpio.c
@@ -176,8 +176,8 @@ static int tegra186_gpio_bind(struct udevice *parent)
if (parent_plat)
return 0;
- regs = (uint32_t *)devfdt_get_addr_name(parent, "gpio");
- if (regs == (uint32_t *)FDT_ADDR_T_NONE)
+ regs = dev_read_addr_name_ptr(parent, "gpio");
+ if (!regs)
return -EINVAL;
for (port = 0; port < ctlr_data->port_count; port++) {
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index d5b85f398db..a96a8c7e955 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -3,7 +3,7 @@
# (C) Copyright 2000-2007
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-$(CONFIG_$(SPL_)DM_I2C) += i2c-uclass.o
-ifdef CONFIG_ACPIGEN
+ifdef CONFIG_$(SPL_)ACPIGEN
obj-$(CONFIG_$(SPL_)DM_I2C) += acpi_i2c.o
endif
obj-$(CONFIG_$(SPL_)DM_I2C_GPIO) += i2c-gpio.o
diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c
index e54de42abc3..215ce010cb7 100644
--- a/drivers/i2c/designware_i2c.c
+++ b/drivers/i2c/designware_i2c.c
@@ -24,6 +24,17 @@
*/
#define DW_I2C_COMP_TYPE 0x44570140
+/*
+ * This constant is used to calculate when during the clock high phase the data
+ * bit shall be read. The value was copied from the Linux v6.5 function
+ * i2c_dw_scl_hcnt() which provides the following explanation:
+ *
+ * "This is just an experimental rule: the tHD;STA period turned out to be
+ * proportinal to (_HCNT + 3). With this setting, we could meet both tHIGH and
+ * tHD;STA timing specs."
+ */
+#define T_HD_STA_OFFSET 3
+
static int dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
{
u32 ena = enable ? IC_ENABLE_0B : 0;
@@ -155,10 +166,10 @@ static int dw_i2c_calc_timing(struct dw_i2c *priv, enum i2c_speed_mode mode,
/*
* Back-solve for hcnt and lcnt according to the following equations:
- * SCL_High_time = [(HCNT + IC_*_SPKLEN + 7) * ic_clk] + SCL_Fall_time
+ * SCL_High_time = [(HCNT + IC_*_SPKLEN + T_HD_STA_OFFSET) * ic_clk] + SCL_Fall_time
* SCL_Low_time = [(LCNT + 1) * ic_clk] - SCL_Fall_time + SCL_Rise_time
*/
- hcnt = min_thigh_cnt - fall_cnt - 7 - spk_cnt;
+ hcnt = min_thigh_cnt - fall_cnt - T_HD_STA_OFFSET - spk_cnt;
lcnt = min_tlow_cnt - rise_cnt + fall_cnt - 1;
if (hcnt < 0 || lcnt < 0) {
@@ -170,13 +181,13 @@ static int dw_i2c_calc_timing(struct dw_i2c *priv, enum i2c_speed_mode mode,
* Now add things back up to ensure the period is hit. If it is off,
* split the difference and bias to lcnt for remainder
*/
- tot = hcnt + lcnt + 7 + spk_cnt + rise_cnt + 1;
+ tot = hcnt + lcnt + T_HD_STA_OFFSET + spk_cnt + rise_cnt + 1;
if (tot < period_cnt) {
diff = (period_cnt - tot) / 2;
hcnt += diff;
lcnt += diff;
- tot = hcnt + lcnt + 7 + spk_cnt + rise_cnt + 1;
+ tot = hcnt + lcnt + T_HD_STA_OFFSET + spk_cnt + rise_cnt + 1;
lcnt += period_cnt - tot;
}
diff --git a/drivers/i2c/i2c-emul-uclass.c b/drivers/i2c/i2c-emul-uclass.c
index 1107cf309fc..d421ddfcbe2 100644
--- a/drivers/i2c/i2c-emul-uclass.c
+++ b/drivers/i2c/i2c-emul-uclass.c
@@ -46,7 +46,7 @@ int i2c_emul_find(struct udevice *dev, struct udevice **emulp)
struct udevice *emul;
int ret;
- if (!CONFIG_IS_ENABLED(OF_PLATDATA)) {
+ if (CONFIG_IS_ENABLED(OF_REAL)) {
ret = uclass_find_device_by_phandle(UCLASS_I2C_EMUL, dev,
"sandbox,emul", &emul);
} else {
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c
index 8867a560bd8..98f95859f3b 100644
--- a/drivers/i2c/i2c-uclass.c
+++ b/drivers/i2c/i2c-uclass.c
@@ -388,6 +388,81 @@ int i2c_get_chip_for_busnum(int busnum, int chip_addr, uint offset_len,
return 0;
}
+/* Find and probe I2C bus based on a chip attached to it */
+static int i2c_get_parent_bus(ofnode chip, struct udevice **devp)
+{
+ ofnode node;
+ struct udevice *dev;
+ int ret;
+
+ node = ofnode_get_parent(chip);
+ if (!ofnode_valid(node))
+ return -ENODEV;
+
+ ret = uclass_get_device_by_ofnode(UCLASS_I2C, node, &dev);
+ if (ret) {
+ *devp = NULL;
+ return ret;
+ }
+
+ *devp = dev;
+ return 0;
+}
+
+int i2c_get_chip_by_phandle(const struct udevice *parent, const char *prop_name,
+ struct udevice **devp)
+{
+ ofnode node;
+ uint phandle;
+ struct udevice *bus, *chip;
+ char *dev_name;
+ int ret;
+
+ debug("%s: Searching I2C chip for phandle \"%s\"\n",
+ __func__, prop_name);
+
+ dev_name = strdup(prop_name);
+ if (!dev_name) {
+ ret = -ENOMEM;
+ goto err_exit;
+ }
+
+ ret = dev_read_u32(parent, prop_name, &phandle);
+ if (ret)
+ goto err_exit;
+
+ node = ofnode_get_by_phandle(phandle);
+ if (!ofnode_valid(node)) {
+ ret = -ENODEV;
+ goto err_exit;
+ }
+
+ ret = i2c_get_parent_bus(node, &bus);
+ if (ret)
+ goto err_exit;
+
+ ret = device_bind_driver_to_node(bus, "i2c_generic_chip_drv",
+ dev_name, node, &chip);
+ if (ret)
+ goto err_exit;
+
+ ret = device_probe(chip);
+ if (ret) {
+ device_unbind(chip);
+ goto err_exit;
+ }
+
+ debug("%s succeeded\n", __func__);
+ *devp = chip;
+ return 0;
+
+err_exit:
+ free(dev_name);
+ debug("%s failed, ret = %d\n", __func__, ret);
+ *devp = NULL;
+ return ret;
+}
+
int dm_i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,
struct udevice **devp)
{
diff --git a/drivers/i2c/mvtwsi.c b/drivers/i2c/mvtwsi.c
index 14cdb0f6635..c38330f758a 100644
--- a/drivers/i2c/mvtwsi.c
+++ b/drivers/i2c/mvtwsi.c
@@ -124,7 +124,8 @@ enum mvtwsi_ctrl_register_fields {
* on other platforms, it is a normal r/w bit, which is cleared by writing 0.
*/
-#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6)
+#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) || \
+ defined(CONFIG_SUNXI_GEN_NCAT2)
#define MVTWSI_CONTROL_CLEAR_IFLG 0x00000008
#else
#define MVTWSI_CONTROL_CLEAR_IFLG 0x00000000
diff --git a/drivers/i2c/npcm_i2c.c b/drivers/i2c/npcm_i2c.c
index ea4ef532565..b867b6c8e91 100644
--- a/drivers/i2c/npcm_i2c.c
+++ b/drivers/i2c/npcm_i2c.c
@@ -517,11 +517,6 @@ static int npcm_i2c_init_clk(struct npcm_i2c_bus *bus, u32 bus_freq)
u32 sclfrq;
u8 hldt, val;
- if (bus_freq > I2C_FREQ_100K) {
- printf("Support standard mode only\n");
- return -EINVAL;
- }
-
/* SCLFRQ = T(SCL)/4/T(CLK) = FREQ(CLK)/4/FREQ(SCL) */
sclfrq = freq / (bus_freq * 4);
if (sclfrq < SCLFRQ_MIN || sclfrq > SCLFRQ_MAX)
diff --git a/drivers/i2c/stm32f7_i2c.c b/drivers/i2c/stm32f7_i2c.c
index b6c71789eec..eaa1d692898 100644
--- a/drivers/i2c/stm32f7_i2c.c
+++ b/drivers/i2c/stm32f7_i2c.c
@@ -20,6 +20,7 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/printk.h>
+#include <linux/time.h>
/* STM32 I2C registers */
struct stm32_i2c_regs {
@@ -121,8 +122,6 @@ struct stm32_i2c_regs {
#define STM32_SCLH_MAX BIT(8)
#define STM32_SCLL_MAX BIT(8)
-#define STM32_NSEC_PER_SEC 1000000000L
-
/**
* struct stm32_i2c_spec - private i2c specification timing
* @rate: I2C bus speed (Hz)
@@ -591,7 +590,7 @@ static int stm32_i2c_choose_solution(u32 i2cclk,
struct stm32_i2c_timings *s)
{
struct stm32_i2c_timings *v;
- u32 i2cbus = DIV_ROUND_CLOSEST(STM32_NSEC_PER_SEC,
+ u32 i2cbus = DIV_ROUND_CLOSEST(NSEC_PER_SEC,
setup->speed_freq);
u32 clk_error_prev = i2cbus;
u32 clk_min, clk_max;
@@ -607,8 +606,8 @@ static int stm32_i2c_choose_solution(u32 i2cclk,
dnf_delay = setup->dnf * i2cclk;
tsync = af_delay_min + dnf_delay + (2 * i2cclk);
- clk_max = STM32_NSEC_PER_SEC / specs->rate_min;
- clk_min = STM32_NSEC_PER_SEC / specs->rate_max;
+ clk_max = NSEC_PER_SEC / specs->rate_min;
+ clk_min = NSEC_PER_SEC / specs->rate_max;
/*
* Among Prescaler possibilities discovered above figures out SCL Low
@@ -686,7 +685,7 @@ static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv,
const struct stm32_i2c_spec *specs;
struct stm32_i2c_timings *v, *_v;
struct list_head solutions;
- u32 i2cclk = DIV_ROUND_CLOSEST(STM32_NSEC_PER_SEC, setup->clock_src);
+ u32 i2cclk = DIV_ROUND_CLOSEST(NSEC_PER_SEC, setup->clock_src);
int ret;
specs = get_specs(setup->speed_freq);
diff --git a/drivers/i2c/sun6i_p2wi.c b/drivers/i2c/sun6i_p2wi.c
index d221323295d..b8e07a533ca 100644
--- a/drivers/i2c/sun6i_p2wi.c
+++ b/drivers/i2c/sun6i_p2wi.c
@@ -20,10 +20,10 @@
#include <errno.h>
#include <i2c.h>
#include <reset.h>
+#include <sunxi_gpio.h>
#include <time.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
-#include <asm/arch/gpio.h>
#include <asm/arch/p2wi.h>
#include <asm/arch/prcm.h>
#include <asm/arch/sys_proto.h>
diff --git a/drivers/i2c/sun8i_rsb.c b/drivers/i2c/sun8i_rsb.c
index 47fa05b6d1c..f36f2c7afac 100644
--- a/drivers/i2c/sun8i_rsb.c
+++ b/drivers/i2c/sun8i_rsb.c
@@ -14,10 +14,10 @@
#include <dm.h>
#include <errno.h>
#include <i2c.h>
+#include <sunxi_gpio.h>
#include <reset.h>
#include <time.h>
#include <asm/arch/cpu.h>
-#include <asm/arch/gpio.h>
#include <asm/arch/prcm.h>
#include <asm/arch/rsb.h>
diff --git a/drivers/input/input.c b/drivers/input/input.c
index a4341e8c7ce..8a6506e7c6f 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -669,17 +669,22 @@ int input_stdio_register(struct stdio_dev *dev)
int error;
error = stdio_register(dev);
-#if !defined(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(ENV_SUPPORT)
- /* check if this is the standard input device */
- if (!error && strcmp(env_get("stdin"), dev->name) == 0) {
- /* reassign the console */
- if (OVERWRITE_CONSOLE ||
- console_assign(stdin, dev->name))
- return -1;
+
+ if (!CONFIG_IS_ENABLED(ENV_SUPPORT))
+ return 0;
+
+ if (!error) {
+ const char *cstdin;
+
+ /* check if this is the standard input device */
+ cstdin = env_get("stdin");
+ if (cstdin && !strcmp(cstdin, dev->name)) {
+ /* reassign the console */
+ if (OVERWRITE_CONSOLE ||
+ console_assign(stdin, dev->name))
+ return -1;
+ }
}
-#else
- error = error;
-#endif
return 0;
}
diff --git a/drivers/mailbox/k3-sec-proxy.c b/drivers/mailbox/k3-sec-proxy.c
index 815808498f2..05f6b1795d6 100644
--- a/drivers/mailbox/k3-sec-proxy.c
+++ b/drivers/mailbox/k3-sec-proxy.c
@@ -2,7 +2,7 @@
/*
* Texas Instruments' K3 Secure proxy Driver
*
- * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2017-2018 Texas Instruments Incorporated - https://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com>
*/
@@ -84,9 +84,9 @@ struct k3_sec_proxy_mbox {
struct mbox_chan chan;
struct k3_sec_proxy_desc *desc;
struct k3_sec_proxy_thread *chans;
- phys_addr_t target_data;
- phys_addr_t scfg;
- phys_addr_t rt;
+ void *target_data;
+ void *scfg;
+ void *rt;
};
static inline u32 sp_readl(void __iomem *addr, unsigned int offset)
@@ -319,20 +319,20 @@ static int k3_sec_proxy_of_to_priv(struct udevice *dev,
return -ENODEV;
}
- spm->target_data = devfdt_get_addr_name(dev, "target_data");
- if (spm->target_data == FDT_ADDR_T_NONE) {
+ spm->target_data = dev_read_addr_name_ptr(dev, "target_data");
+ if (!spm->target_data) {
dev_err(dev, "No reg property for target data base\n");
return -EINVAL;
}
- spm->scfg = devfdt_get_addr_name(dev, "scfg");
- if (spm->rt == FDT_ADDR_T_NONE) {
+ spm->scfg = dev_read_addr_name_ptr(dev, "scfg");
+ if (!spm->scfg) {
dev_err(dev, "No reg property for Secure Cfg base\n");
return -EINVAL;
}
- spm->rt = devfdt_get_addr_name(dev, "rt");
- if (spm->rt == FDT_ADDR_T_NONE) {
+ spm->rt = dev_read_addr_name_ptr(dev, "rt");
+ if (!spm->rt) {
dev_err(dev, "No reg property for Real Time Cfg base\n");
return -EINVAL;
}
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index 22cb9d637c5..d10edd27746 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -61,7 +61,6 @@ config TI_GPMC
if TI_GPMC
config TI_GPMC_DEBUG
bool "Debug Texas Instruments GPMC timings"
- default n
help
Enable this to print GPMC timings before and after the GPMC registers
are programmed. This should not be left enabled on production systems.
diff --git a/drivers/memory/stm32-fmc2-ebi.c b/drivers/memory/stm32-fmc2-ebi.c
index 212bb4f5dc0..a722a3836f7 100644
--- a/drivers/memory/stm32-fmc2-ebi.c
+++ b/drivers/memory/stm32-fmc2-ebi.c
@@ -14,6 +14,7 @@
#include <linux/err.h>
#include <linux/iopoll.h>
#include <linux/ioport.h>
+#include <linux/time.h>
/* FMC2 Controller Registers */
#define FMC2_BCR1 0x0
@@ -90,8 +91,6 @@
#define FMC2_BTR_DATLAT_MAX 0xf
#define FMC2_PCSCNTR_CSCOUNT_MAX 0xff
-#define FMC2_NSEC_PER_SEC 1000000000L
-
enum stm32_fmc2_ebi_bank {
FMC2_EBI1 = 0,
FMC2_EBI2,
@@ -279,7 +278,7 @@ static u32 stm32_fmc2_ebi_ns_to_clock_cycles(struct stm32_fmc2_ebi *ebi,
int cs, u32 setup)
{
unsigned long hclk = clk_get_rate(&ebi->clk);
- unsigned long hclkp = FMC2_NSEC_PER_SEC / (hclk / 1000);
+ unsigned long hclkp = NSEC_PER_SEC / (hclk / 1000);
return DIV_ROUND_UP(setup * 1000, hclkp);
}
diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c
index c4bc88c1510..41325eb0f94 100644
--- a/drivers/memory/ti-aemif.c
+++ b/drivers/memory/ti-aemif.c
@@ -7,6 +7,7 @@
*/
#include <common.h>
+#include <asm/arch/hardware.h>
#include <asm/ti-common/ti-aemif.h>
#define AEMIF_WAITCYCLE_CONFIG (KS2_AEMIF_CNTRL_BASE + 0x4)
diff --git a/drivers/memory/ti-gpmc.c b/drivers/memory/ti-gpmc.c
index f511a529b1e..775e78c9a5b 100644
--- a/drivers/memory/ti-gpmc.c
+++ b/drivers/memory/ti-gpmc.c
@@ -2,7 +2,7 @@
/*
* Texas Instruments GPMC Driver
*
- * Copyright (C) 2021 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/
*/
#include <asm/io.h>
diff --git a/drivers/memory/ti-gpmc.h b/drivers/memory/ti-gpmc.h
index 90f8e656c8f..6fe098af0ec 100644
--- a/drivers/memory/ti-gpmc.h
+++ b/drivers/memory/ti-gpmc.h
@@ -2,7 +2,7 @@
/*
* Texas Instruments GPMC Driver
*
- * Copyright (C) 2021 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/
*/
/* GPMC register offsets */
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index fccd9b89b81..97057de8bf9 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -375,7 +375,6 @@ config SPL_MXC_OCOTP
config NPCM_OTP
bool "Nnvoton NPCM BMC On-Chip OTP Memory Support"
depends on (ARM && ARCH_NPCM)
- default n
help
Support NPCM BMC OTP memory (fuse).
To compile this driver as a module, choose M here: the module
diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c
index 8dbe0b188a4..1201535f4af 100644
--- a/drivers/misc/cros_ec_sandbox.c
+++ b/drivers/misc/cros_ec_sandbox.c
@@ -81,6 +81,7 @@ struct ec_pwm_channel {
/**
* struct ec_state - Information about the EC state
*
+ * @valid: true if this struct contains valid state data
* @vbnv_context: Vboot context data stored by EC
* @ec_config: FDT config information about the EC (e.g. flashmap)
* @flash_data: Contents of flash memory
@@ -95,6 +96,7 @@ struct ec_pwm_channel {
* @pwm: Information per PWM channel
*/
struct ec_state {
+ bool valid;
u8 vbnv_context[EC_VBNV_BLOCK_SIZE_V2];
struct fdt_cros_ec ec_config;
uint8_t *flash_data;
@@ -145,6 +147,7 @@ static int cros_ec_read_state(const void *blob, int node)
memcpy(ec->flash_data, prop, len);
debug("%s: Loaded EC flash data size %#x\n", __func__, len);
}
+ ec->valid = true;
return 0;
}
@@ -589,6 +592,7 @@ static int process_cmd(struct ec_state *ec,
printf(" ** Unknown EC command %#02x\n", req_hdr->command);
return -1;
}
+ debug(" - EC command %#0x, result %d\n", req_hdr->command, len);
return len;
}
@@ -675,7 +679,10 @@ int cros_ec_probe(struct udevice *dev)
ofnode node;
int err;
- memcpy(ec, &s_state, sizeof(*ec));
+ if (s_state.valid)
+ memcpy(ec, &s_state, sizeof(*ec));
+ else
+ ec->current_image = EC_IMAGE_RO;
err = cros_ec_decode_ec_flash(dev, &ec->ec_config);
if (err) {
debug("%s: Cannot device EC flash\n", __func__);
diff --git a/drivers/misc/cros_ec_spi.c b/drivers/misc/cros_ec_spi.c
index 001f0a85ca9..591ff30df89 100644
--- a/drivers/misc/cros_ec_spi.c
+++ b/drivers/misc/cros_ec_spi.c
@@ -151,7 +151,7 @@ int cros_ec_spi_command(struct udevice *udev, uint8_t cmd, int cmd_version,
/* Response code is first byte of message */
if (p[0] != EC_RES_SUCCESS) {
- printf("%s: Returned status %d\n", __func__, p[0]);
+ log_debug("Returned status %d\n", p[0]);
return -(int)(p[0]);
}
diff --git a/drivers/misc/esm_pmic.c b/drivers/misc/esm_pmic.c
index b971f32f6a1..a518f750611 100644
--- a/drivers/misc/esm_pmic.c
+++ b/drivers/misc/esm_pmic.c
@@ -2,7 +2,7 @@
/*
* PMIC Error Signal Monitor driver
*
- * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
* Tero Kristo <t-kristo@ti.com>
*
*/
diff --git a/drivers/misc/fs_loader.c b/drivers/misc/fs_loader.c
index ccf5c7a8037..1ffc199ba1e 100644
--- a/drivers/misc/fs_loader.c
+++ b/drivers/misc/fs_loader.c
@@ -316,7 +316,7 @@ int get_fs_loader(struct udevice **dev)
return ret;
/* Just create a new device */
- ret = device_bind(dm_root(), DM_DRIVER_GET(fs_loader), "default-loader",
+ ret = device_bind(dm_root(), DM_DRIVER_REF(fs_loader), "default-loader",
&default_plat, ofnode_null(), dev);
if (ret)
return ret;
diff --git a/drivers/misc/i2c_eeprom.c b/drivers/misc/i2c_eeprom.c
index bdd7e018cc6..9111bd724cb 100644
--- a/drivers/misc/i2c_eeprom.c
+++ b/drivers/misc/i2c_eeprom.c
@@ -60,6 +60,17 @@ static int i2c_eeprom_std_read(struct udevice *dev, int offset, uint8_t *buf,
return dm_i2c_read(dev, offset, buf, size);
}
+static int i2c_eeprom_len(int offset, int len, int pagesize)
+{
+ int page_offset = offset & (pagesize - 1);
+ int maxlen = pagesize - page_offset;
+
+ if (len > maxlen)
+ len = maxlen;
+
+ return len;
+}
+
static int i2c_eeprom_std_write(struct udevice *dev, int offset,
const uint8_t *buf, int size)
{
@@ -67,7 +78,7 @@ static int i2c_eeprom_std_write(struct udevice *dev, int offset,
int ret;
while (size > 0) {
- int write_size = min_t(int, size, priv->pagesize);
+ int write_size = i2c_eeprom_len(offset, size, priv->pagesize);
ret = dm_i2c_write(dev, offset, buf, write_size);
if (ret)
@@ -227,6 +238,13 @@ static const struct i2c_eeprom_drv_data atmel24c32_data = {
.offset_len = 2,
};
+static const struct i2c_eeprom_drv_data atmel24c32d_wlp_data = {
+ .size = 32,
+ .pagesize = 32,
+ .addr_offset_mask = 0,
+ .offset_len = 2,
+};
+
static const struct i2c_eeprom_drv_data atmel24c64_data = {
.size = 8192,
.pagesize = 32,
@@ -266,6 +284,7 @@ static const struct udevice_id i2c_eeprom_std_ids[] = {
{ .compatible = "atmel,24c16a", (ulong)&atmel24c16a_data },
{ .compatible = "atmel,24mac402", (ulong)&atmel24mac402_data },
{ .compatible = "atmel,24c32", (ulong)&atmel24c32_data },
+ { .compatible = "atmel,24c32d-wl", (ulong)&atmel24c32d_wlp_data },
{ .compatible = "atmel,24c64", (ulong)&atmel24c64_data },
{ .compatible = "atmel,24c128", (ulong)&atmel24c128_data },
{ .compatible = "atmel,24c256", (ulong)&atmel24c256_data },
diff --git a/drivers/misc/k3_avs.c b/drivers/misc/k3_avs.c
index acfc7318452..0d29eff1ac0 100644
--- a/drivers/misc/k3_avs.c
+++ b/drivers/misc/k3_avs.c
@@ -2,7 +2,7 @@
/*
* Texas Instruments' K3 Clas 0 Adaptive Voltage Scaling driver
*
- * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
* Tero Kristo <t-kristo@ti.com>
*
*/
@@ -15,6 +15,7 @@
#include <k3-avs.h>
#include <dm/device_compat.h>
#include <linux/bitops.h>
+#include <linux/delay.h>
#include <power/regulator.h>
#define AM6_VTM_DEVINFO(i) (priv->base + 0x100 + 0x20 * (i))
@@ -25,11 +26,28 @@
#define AM6_VTM_OPP_SHIFT(opp) (8 * (opp))
#define AM6_VTM_OPP_MASK 0xff
+#define K3_VTM_DEVINFO_PWR0_OFFSET 0x4
+#define K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK 0xf0
+#define K3_VTM_TMPSENS0_CTRL_OFFSET 0x300
+#define K3_VTM_TMPSENS_STAT_OFFSET 0x8
+#define K3_VTM_ANYMAXT_OUTRG_ALERT_EN 0x1
+#define K3_VTM_LOW_TEMP_OFFSET 0x10
+#define K3_VTM_MISC_CTRL2_OFFSET 0x10
+#define K3_VTM_MISC_CTRL1_OFFSET 0xc
+#define K3_VTM_TMPSENS_CTRL1_SOC BIT(5)
+#define K3_VTM_TMPSENS_CTRL_CLRZ BIT(6)
+#define K3_VTM_TMPSENS_CTRL_MAXT_OUTRG_EN BIT(11)
+#define K3_VTM_ADC_COUNT_FOR_123C 0x2f8
+#define K3_VTM_ADC_COUNT_FOR_105C 0x288
+#define K3_VTM_ADC_WA_VALUE 0x2c
+#define K3_VTM_FUSE_MASK 0xc0000000
+
#define VD_FLAG_INIT_DONE BIT(0)
struct k3_avs_privdata {
void *base;
struct vd_config *vd_config;
+ struct udevice *dev;
};
struct opp {
@@ -237,6 +255,88 @@ static int k3_avs_configure(struct udevice *dev, struct k3_avs_privdata *priv)
return 0;
}
+/* k3_avs_program_tshut : Program thermal shutdown value for SOC
+ * set the values corresponding to thresholds to ~123C and 105C
+ * This is optional feature, Few times OS driver takes care of
+ * tshut programing.
+ */
+
+static void k3_avs_program_tshut(struct k3_avs_privdata *priv)
+{
+ int cnt, id, val;
+ int workaround_needed = 0;
+ u32 ctrl_offset;
+ void __iomem *cfg2_base;
+ void __iomem *fuse_base;
+
+ cfg2_base = (void __iomem *)devfdt_get_addr_index(priv->dev, 1);
+ if (IS_ERR(cfg2_base)) {
+ dev_err(priv->dev, "cfg base is not defined\n");
+ return;
+ }
+
+ /*
+ * Some of TI's J721E SoCs require a software trimming procedure
+ * for the temperature monitors to function properly. To determine
+ * if this particular SoC is NOT affected, both bits in the
+ * WKUP_SPARE_FUSE0[31:30] will be set (0xC0000000) indicating
+ * when software trimming should NOT be applied.
+ *
+ * https://www.ti.com/lit/er/sprz455c/sprz455c.pdf
+ * This routine checks if workaround_needed to be applied or not
+ * based upon workaround_needed, adjust fixed value of tshut high and low
+ */
+
+ if (device_is_compatible(priv->dev, "ti,j721e-vtm")) {
+ fuse_base = (void __iomem *)devfdt_get_addr_index(priv->dev, 2);
+ if (IS_ERR(fuse_base)) {
+ dev_err(priv->dev, "fuse-base is not defined for J721E Soc\n");
+ return;
+ }
+
+ if (!((readl(fuse_base) & K3_VTM_FUSE_MASK) == K3_VTM_FUSE_MASK))
+ workaround_needed = 1;
+ }
+
+ dev_dbg(priv->dev, "Work around %sneeded\n", workaround_needed ? "" : "not ");
+
+ /* Get the sensor count in the VTM */
+ val = readl(priv->base + K3_VTM_DEVINFO_PWR0_OFFSET);
+ cnt = val & K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK;
+ cnt >>= __ffs(K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK);
+
+ /* Program the thermal sensors */
+ for (id = 0; id < cnt; id++) {
+ ctrl_offset = K3_VTM_TMPSENS0_CTRL_OFFSET + id * 0x20;
+
+ val = readl(cfg2_base + ctrl_offset);
+ val |= (K3_VTM_TMPSENS_CTRL_MAXT_OUTRG_EN |
+ K3_VTM_TMPSENS_CTRL1_SOC |
+ K3_VTM_TMPSENS_CTRL_CLRZ | BIT(4));
+ writel(val, cfg2_base + ctrl_offset);
+ }
+
+ /*
+ * Program TSHUT thresholds
+ * Step 1: set the thresholds to ~123C and 105C WKUP_VTM_MISC_CTRL2
+ * Step 2: WKUP_VTM_TMPSENS_CTRL_j set the MAXT_OUTRG_EN bit
+ * This is already taken care as per of init
+ * Step 3: WKUP_VTM_MISC_CTRL set the ANYMAXT_OUTRG_ALERT_EN bit
+ */
+
+ /* Low thresholds for tshut*/
+ val = (K3_VTM_ADC_COUNT_FOR_105C - workaround_needed * K3_VTM_ADC_WA_VALUE)
+ << K3_VTM_LOW_TEMP_OFFSET;
+ /* high thresholds */
+ val |= K3_VTM_ADC_COUNT_FOR_123C - workaround_needed * K3_VTM_ADC_WA_VALUE;
+
+ writel(val, cfg2_base + K3_VTM_MISC_CTRL2_OFFSET);
+ /* ramp-up delay from Linux code */
+ mdelay(100);
+ val = readl(cfg2_base + K3_VTM_MISC_CTRL1_OFFSET) | K3_VTM_ANYMAXT_OUTRG_ALERT_EN;
+ writel(val, cfg2_base + K3_VTM_MISC_CTRL1_OFFSET);
+}
+
/**
* k3_avs_probe: parses VD info from VTM, and re-configures the OPP data
*
@@ -255,6 +355,7 @@ static int k3_avs_probe(struct udevice *dev)
int ret;
priv = dev_get_priv(dev);
+ priv->dev = dev;
k3_avs_priv = priv;
@@ -294,6 +395,9 @@ static int k3_avs_probe(struct udevice *dev)
k3_avs_program_voltage(priv, vd, vd->opp);
}
+ if (!device_is_compatible(priv->dev, "ti,am654-avs"))
+ k3_avs_program_tshut(priv);
+
return 0;
}
diff --git a/drivers/misc/k3_esm.c b/drivers/misc/k3_esm.c
index 41faeb3d858..f6ac18bdc75 100644
--- a/drivers/misc/k3_esm.c
+++ b/drivers/misc/k3_esm.c
@@ -2,7 +2,7 @@
/*
* Texas Instruments' K3 Error Signalling Module driver
*
- * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
* Tero Kristo <t-kristo@ti.com>
*
*/
diff --git a/drivers/misc/rockchip-otp.c b/drivers/misc/rockchip-otp.c
index 4814e0e501c..4f757083a1b 100644
--- a/drivers/misc/rockchip-otp.c
+++ b/drivers/misc/rockchip-otp.c
@@ -61,11 +61,20 @@
#define RK3588_OTPC_INT_ST 0x0084
#define RK3588_RD_DONE BIT(1)
+#define RV1126_OTP_NVM_CEB 0x00
+#define RV1126_OTP_NVM_RSTB 0x04
+#define RV1126_OTP_NVM_ST 0x18
+#define RV1126_OTP_NVM_RADDR 0x1C
+#define RV1126_OTP_NVM_RSTART 0x20
+#define RV1126_OTP_NVM_RDATA 0x24
+#define RV1126_OTP_READ_ST 0x30
+
struct rockchip_otp_plat {
void __iomem *base;
};
struct rockchip_otp_data {
+ int (*init)(struct udevice *dev);
int (*read)(struct udevice *dev, int offset, void *buf, int size);
int offset;
int size;
@@ -232,6 +241,48 @@ static int rockchip_rk3588_otp_read(struct udevice *dev, int offset,
return 0;
}
+static int rockchip_rv1126_otp_init(struct udevice *dev)
+{
+ struct rockchip_otp_plat *otp = dev_get_plat(dev);
+ int ret;
+
+ writel(0x0, otp->base + RV1126_OTP_NVM_CEB);
+ ret = rockchip_otp_poll_timeout(otp, 0x1, RV1126_OTP_NVM_ST);
+
+ if (ret)
+ return ret;
+
+ writel(0x1, otp->base + RV1126_OTP_NVM_RSTB);
+ ret = rockchip_otp_poll_timeout(otp, 0x4, RV1126_OTP_NVM_ST);
+
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int rockchip_rv1126_otp_read(struct udevice *dev, int offset, void *buf,
+ int size)
+{
+ struct rockchip_otp_plat *otp = dev_get_plat(dev);
+ u32 status = 0;
+ u8 *buffer = buf;
+ int ret = 0;
+
+ while (size--) {
+ writel(offset++, otp->base + RV1126_OTP_NVM_RADDR);
+ writel(0x1, otp->base + RV1126_OTP_NVM_RSTART);
+ ret = readl_poll_timeout(otp->base + RV1126_OTP_READ_ST,
+ status, !status, OTPC_TIMEOUT);
+ if (ret)
+ return ret;
+
+ *buffer++ = (u8)(readl(otp->base + RV1126_OTP_NVM_RDATA) & 0xFF);
+ }
+
+ return 0;
+}
+
static int rockchip_otp_read(struct udevice *dev, int offset,
void *buf, int size)
{
@@ -286,6 +337,20 @@ static int rockchip_otp_of_to_plat(struct udevice *dev)
return 0;
}
+static int rockchip_otp_probe(struct udevice *dev)
+{
+ struct rockchip_otp_data *data;
+
+ data = (struct rockchip_otp_data *)dev_get_driver_data(dev);
+ if (!data)
+ return -EINVAL;
+
+ if (data->init)
+ return data->init(dev);
+
+ return 0;
+}
+
static const struct rockchip_otp_data px30_data = {
.read = rockchip_px30_otp_read,
.size = 0x40,
@@ -304,6 +369,12 @@ static const struct rockchip_otp_data rk3588_data = {
.block_size = 4,
};
+static const struct rockchip_otp_data rv1126_data = {
+ .init = rockchip_rv1126_otp_init,
+ .read = rockchip_rv1126_otp_read,
+ .size = 0x40,
+};
+
static const struct udevice_id rockchip_otp_ids[] = {
{
.compatible = "rockchip,px30-otp",
@@ -321,6 +392,10 @@ static const struct udevice_id rockchip_otp_ids[] = {
.compatible = "rockchip,rk3588-otp",
.data = (ulong)&rk3588_data,
},
+ {
+ .compatible = "rockchip,rv1126-otp",
+ .data = (ulong)&rv1126_data,
+ },
{}
};
@@ -331,4 +406,5 @@ U_BOOT_DRIVER(rockchip_otp) = {
.of_to_plat = rockchip_otp_of_to_plat,
.plat_auto = sizeof(struct rockchip_otp_plat),
.ops = &rockchip_otp_ops,
+ .probe = rockchip_otp_probe,
};
diff --git a/drivers/misc/vexpress_config.c b/drivers/misc/vexpress_config.c
index 2baca48109f..99aad1412ae 100644
--- a/drivers/misc/vexpress_config.c
+++ b/drivers/misc/vexpress_config.c
@@ -92,7 +92,7 @@ static struct misc_ops vexpress_config_ops = {
static int vexpress_config_probe(struct udevice *dev)
{
struct ofnode_phandle_args args;
- struct vexpress_config_sysreg *priv;
+ struct vexpress_config_sysreg *priv = dev_get_priv(dev);
const char *prop;
int err, prop_size;
@@ -105,11 +105,9 @@ static int vexpress_config_probe(struct udevice *dev)
if (!prop || (strncmp(prop, "arm,vexpress-sysreg", 19) != 0))
return -ENOENT;
- priv = calloc(1, sizeof(*priv));
if (!priv)
return -ENOMEM;
- dev_get_uclass_priv(dev) = priv;
priv->addr = ofnode_get_addr(args.node);
return dev_read_u32(dev, "arm,vexpress,site", &priv->site);
@@ -127,4 +125,5 @@ U_BOOT_DRIVER(vexpress_config_drv) = {
.bind = dm_scan_fdt_dev,
.probe = vexpress_config_probe,
.ops = &vexpress_config_ops,
+ .priv_auto = sizeof(struct vexpress_config_sysreg),
};
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index de01b9687ba..17618c3bdcc 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -46,6 +46,7 @@ config SPL_DM_MMC
depends on SPL_DM && DM_MMC
default n if ARCH_MVEBU && !MVEBU_SPL_BOOT_DEVICE_MMC
default y
+ select SPL_BLK
help
This enables the MultiMediaCard (MMC) uclass which supports MMC and
Secure Digital I/O (SDIO) cards. Both removable (SD, micro-SD, etc.)
@@ -390,12 +391,6 @@ config HSMMC2_8BIT
depends on MMC_OMAP_HS && (OMAP44XX || OMAP54XX || DRA7XX || AM33XX || \
AM43XX || ARCH_KEYSTONE)
-config SH_SDHI
- bool "SuperH/Renesas ARM SoCs on-chip SDHI host controller support"
- depends on ARCH_RMOBILE
- help
- Support for the on-chip SDHI host controller on SuperH/Renesas ARM SoCs platform
-
config SH_MMCIF
bool "SuperH/Renesas ARM SoCs on-chip MMCIF host controller support"
depends on ARCH_RMOBILE || SH
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 2c65c4765ab..e9cf1fcc640 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -49,7 +49,6 @@ obj-$(CONFIG_MMC_PCI) += pci_mmc.o
obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o
obj-$(CONFIG_MMC_SANDBOX) += sandbox_mmc.o
obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
-obj-$(CONFIG_SH_SDHI) += sh_sdhi.o
obj-$(CONFIG_STM32_SDMMC2) += stm32_sdmmc2.o
obj-$(CONFIG_JZ47XX_MMC) += jz_mmc.o
obj-$(CONFIG_NEXELL_DWMMC) += nexell_dw_mmc.o
diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c
index fd667aeafda..05595bdac39 100644
--- a/drivers/mmc/am654_sdhci.c
+++ b/drivers/mmc/am654_sdhci.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
*
* Texas Instruments' K3 SD Host Controller Interface
*/
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
index 0e157672eae..328456831dd 100644
--- a/drivers/mmc/mmc-uclass.c
+++ b/drivers/mmc/mmc-uclass.c
@@ -412,7 +412,7 @@ int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg)
debug("%s: alias devnum=%d\n", __func__, dev_seq(dev));
ret = blk_create_devicef(dev, "mmc_blk", "blk", UCLASS_MMC,
- dev_seq(dev), 512, 0, &bdev);
+ dev_seq(dev), DEFAULT_BLKSZ, 0, &bdev);
if (ret) {
debug("Cannot create block device\n");
return ret;
diff --git a/drivers/mmc/octeontx_hsmmc.h b/drivers/mmc/octeontx_hsmmc.h
index 70844b1cbab..9849121f174 100644
--- a/drivers/mmc/octeontx_hsmmc.h
+++ b/drivers/mmc/octeontx_hsmmc.h
@@ -32,8 +32,6 @@
*/
#define MMC_TIMEOUT_SHORT 20
-#define NSEC_PER_SEC 1000000000L
-
#define MAX_NO_OF_TAPS 64
#define EXT_CSD_POWER_CLASS 187 /* R/W */
diff --git a/drivers/mmc/pci_mmc.c b/drivers/mmc/pci_mmc.c
index 9fb70440293..4d163ccba04 100644
--- a/drivers/mmc/pci_mmc.c
+++ b/drivers/mmc/pci_mmc.c
@@ -50,8 +50,8 @@ static int pci_mmc_probe(struct udevice *dev)
desc = mmc_get_blk_desc(&plat->mmc);
desc->removable = !(plat->cfg.host_caps & MMC_CAP_NONREMOVABLE);
- host->ioaddr = (void *)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE,
- PCI_REGION_MEM);
+ host->ioaddr = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0,
+ PCI_REGION_TYPE, PCI_REGION_MEM);
host->name = dev->name;
host->cd_gpio = priv->cd_gpio;
host->mmc = &plat->mmc;
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c
index 8e716f74491..97aaf1e4ec3 100644
--- a/drivers/mmc/renesas-sdhi.c
+++ b/drivers/mmc/renesas-sdhi.c
@@ -3,7 +3,6 @@
* Copyright (C) 2018 Marek Vasut <marek.vasut@gmail.com>
*/
-#include <common.h>
#include <bouncebuf.h>
#include <clk.h>
#include <fdtdec.h>
@@ -20,6 +19,7 @@
#include <linux/io.h>
#include <linux/sizes.h>
#include <power/regulator.h>
+#include <reset.h>
#include <asm/unaligned.h>
#include "tmio-common.h"
@@ -318,7 +318,7 @@ static unsigned int renesas_sdhi_init_tuning(struct tmio_sd_priv *priv)
RENESAS_SDHI_SCC_DTCNTL_TAPNUM_MASK;
}
-static void renesas_sdhi_reset_tuning(struct tmio_sd_priv *priv)
+static void renesas_sdhi_reset_tuning(struct tmio_sd_priv *priv, bool clk_disable)
{
u32 reg;
@@ -350,6 +350,12 @@ static void renesas_sdhi_reset_tuning(struct tmio_sd_priv *priv)
reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL);
reg &= ~RENESAS_SDHI_SCC_RVSCNTL_RVSEN;
tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL);
+
+ if (clk_disable) {
+ reg = tmio_sd_readl(priv, TMIO_SD_CLKCTL);
+ reg &= ~TMIO_SD_CLKCTL_SCLKEN;
+ tmio_sd_writel(priv, reg, TMIO_SD_CLKCTL);
+ }
}
static int renesas_sdhi_hs400(struct udevice *dev)
@@ -629,7 +635,7 @@ int renesas_sdhi_execute_tuning(struct udevice *dev, uint opcode)
out:
if (ret < 0) {
dev_warn(dev, "Tuning procedure failed\n");
- renesas_sdhi_reset_tuning(priv);
+ renesas_sdhi_reset_tuning(priv, true);
}
return ret;
@@ -668,7 +674,7 @@ static int renesas_sdhi_set_ios(struct udevice *dev)
(mmc->selected_mode != UHS_SDR104) &&
(mmc->selected_mode != MMC_HS_200) &&
(mmc->selected_mode != MMC_HS_400)) {
- renesas_sdhi_reset_tuning(priv);
+ renesas_sdhi_reset_tuning(priv, mmc->clk_disable);
}
#endif
@@ -958,17 +964,87 @@ static void renesas_sdhi_filter_caps(struct udevice *dev)
priv->needs_clkh_fallback = false;
}
+static int rzg2l_sdhi_setup(struct udevice *dev)
+{
+ struct tmio_sd_priv *priv = dev_get_priv(dev);
+ struct clk imclk2, aclk;
+ struct reset_ctl rst;
+ int ret;
+
+ /*
+ * On members of the RZ/G2L SoC family, we need to enable
+ * additional chip detect and bus clocks, then release the SDHI
+ * module from reset.
+ */
+ ret = clk_get_by_name(dev, "cd", &imclk2);
+ if (ret < 0) {
+ dev_err(dev, "failed to get imclk2 (chip detect clk)\n");
+ goto err_get_imclk2;
+ }
+
+ ret = clk_get_by_name(dev, "aclk", &aclk);
+ if (ret < 0) {
+ dev_err(dev, "failed to get aclk\n");
+ goto err_get_aclk;
+ }
+
+ ret = clk_enable(&imclk2);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable imclk2 (chip detect clk)\n");
+ goto err_imclk2;
+ }
+
+ ret = clk_enable(&aclk);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable aclk\n");
+ goto err_aclk;
+ }
+
+ ret = reset_get_by_index(dev, 0, &rst);
+ if (ret < 0) {
+ dev_err(dev, "failed to get reset line\n");
+ goto err_get_reset;
+ }
+
+ ret = reset_deassert(&rst);
+ if (ret < 0) {
+ dev_err(dev, "failed to de-assert reset line\n");
+ goto err_reset;
+ }
+
+ ret = tmio_sd_probe(dev, priv->quirks);
+ if (ret)
+ goto err_tmio_probe;
+
+ return 0;
+
+err_tmio_probe:
+ reset_assert(&rst);
+err_reset:
+ reset_free(&rst);
+err_get_reset:
+ clk_disable(&aclk);
+err_aclk:
+ clk_disable(&imclk2);
+err_imclk2:
+ clk_free(&aclk);
+err_get_aclk:
+ clk_free(&imclk2);
+err_get_imclk2:
+ return ret;
+}
+
static int renesas_sdhi_probe(struct udevice *dev)
{
struct tmio_sd_priv *priv = dev_get_priv(dev);
- u32 quirks = dev_get_driver_data(dev);
struct fdt_resource reg_res;
DECLARE_GLOBAL_DATA_PTR;
int ret;
priv->clk_get_rate = renesas_sdhi_clk_get_rate;
- if (quirks == RENESAS_GEN2_QUIRKS) {
+ priv->quirks = dev_get_driver_data(dev);
+ if (priv->quirks == RENESAS_GEN2_QUIRKS) {
ret = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev),
"reg", 0, &reg_res);
if (ret < 0) {
@@ -978,7 +1054,7 @@ static int renesas_sdhi_probe(struct udevice *dev)
}
if (fdt_resource_size(&reg_res) == 0x100)
- quirks |= TMIO_SD_CAP_16BIT;
+ priv->quirks |= TMIO_SD_CAP_16BIT;
}
ret = clk_get_by_index(dev, 0, &priv->clk);
@@ -1012,8 +1088,10 @@ static int renesas_sdhi_probe(struct udevice *dev)
goto err_clkh;
}
- priv->quirks = quirks;
- ret = tmio_sd_probe(dev, quirks);
+ if (device_is_compatible(dev, "renesas,sdhi-r9a07g044"))
+ ret = rzg2l_sdhi_setup(dev);
+ else
+ ret = tmio_sd_probe(dev, priv->quirks);
if (ret)
goto err_tmio_probe;
@@ -1023,7 +1101,7 @@ static int renesas_sdhi_probe(struct udevice *dev)
CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
if (priv->caps & TMIO_SD_CAP_RCAR_UHS)
- renesas_sdhi_reset_tuning(priv);
+ renesas_sdhi_reset_tuning(priv, true);
#endif
return 0;
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index fc9c6c37996..0178ed8a11e 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -306,14 +306,19 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
if (stat & SDHCI_INT_ERROR)
break;
- if (get_timer(start) >= SDHCI_READ_STATUS_TIMEOUT) {
- if (host->quirks & SDHCI_QUIRK_BROKEN_R1B) {
+ if (host->quirks & SDHCI_QUIRK_BROKEN_R1B &&
+ cmd->resp_type & MMC_RSP_BUSY && !data) {
+ unsigned int state =
+ sdhci_readl(host, SDHCI_PRESENT_STATE);
+
+ if (!(state & SDHCI_DAT_ACTIVE))
return 0;
- } else {
- printf("%s: Timeout for status update!\n",
- __func__);
- return -ETIMEDOUT;
- }
+ }
+
+ if (get_timer(start) >= SDHCI_READ_STATUS_TIMEOUT) {
+ printf("%s: Timeout for status update: %08x %08x\n",
+ __func__, stat, mask);
+ return -ETIMEDOUT;
}
} while ((stat & mask) != mask);
diff --git a/drivers/mmc/sh_sdhi.c b/drivers/mmc/sh_sdhi.c
deleted file mode 100644
index 3ce7cbf71f8..00000000000
--- a/drivers/mmc/sh_sdhi.c
+++ /dev/null
@@ -1,910 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * drivers/mmc/sh_sdhi.c
- *
- * SD/MMC driver for Renesas rmobile ARM SoCs.
- *
- * Copyright (C) 2011,2013-2017 Renesas Electronics Corporation
- * Copyright (C) 2014 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
- * Copyright (C) 2008-2009 Renesas Solutions Corp.
- */
-
-#include <common.h>
-#include <log.h>
-#include <malloc.h>
-#include <mmc.h>
-#include <dm.h>
-#include <part.h>
-#include <dm/device_compat.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/compat.h>
-#include <linux/io.h>
-#include <linux/sizes.h>
-#include <asm/arch/rmobile.h>
-#include <asm/arch/sh_sdhi.h>
-#include <asm/global_data.h>
-#include <clk.h>
-
-#define DRIVER_NAME "sh-sdhi"
-
-struct sh_sdhi_host {
- void __iomem *addr;
- int ch;
- int bus_shift;
- unsigned long quirks;
- unsigned char wait_int;
- unsigned char sd_error;
- unsigned char detect_waiting;
- unsigned char app_cmd;
-};
-
-static inline void sh_sdhi_writeq(struct sh_sdhi_host *host, int reg, u64 val)
-{
- writeq(val, host->addr + (reg << host->bus_shift));
-}
-
-static inline u64 sh_sdhi_readq(struct sh_sdhi_host *host, int reg)
-{
- return readq(host->addr + (reg << host->bus_shift));
-}
-
-static inline void sh_sdhi_writew(struct sh_sdhi_host *host, int reg, u16 val)
-{
- writew(val, host->addr + (reg << host->bus_shift));
-}
-
-static inline u16 sh_sdhi_readw(struct sh_sdhi_host *host, int reg)
-{
- return readw(host->addr + (reg << host->bus_shift));
-}
-
-static void sh_sdhi_detect(struct sh_sdhi_host *host)
-{
- sh_sdhi_writew(host, SDHI_OPTION,
- OPT_BUS_WIDTH_1 | sh_sdhi_readw(host, SDHI_OPTION));
-
- host->detect_waiting = 0;
-}
-
-static int sh_sdhi_intr(void *dev_id)
-{
- struct sh_sdhi_host *host = dev_id;
- int state1 = 0, state2 = 0;
-
- state1 = sh_sdhi_readw(host, SDHI_INFO1);
- state2 = sh_sdhi_readw(host, SDHI_INFO2);
-
- debug("%s: state1 = %x, state2 = %x\n", __func__, state1, state2);
-
- /* CARD Insert */
- if (state1 & INFO1_CARD_IN) {
- sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_CARD_IN);
- if (!host->detect_waiting) {
- host->detect_waiting = 1;
- sh_sdhi_detect(host);
- }
- sh_sdhi_writew(host, SDHI_INFO1_MASK, INFO1M_RESP_END |
- INFO1M_ACCESS_END | INFO1M_CARD_IN |
- INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
- return -EAGAIN;
- }
- /* CARD Removal */
- if (state1 & INFO1_CARD_RE) {
- sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_CARD_RE);
- if (!host->detect_waiting) {
- host->detect_waiting = 1;
- sh_sdhi_detect(host);
- }
- sh_sdhi_writew(host, SDHI_INFO1_MASK, INFO1M_RESP_END |
- INFO1M_ACCESS_END | INFO1M_CARD_RE |
- INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
- sh_sdhi_writew(host, SDHI_SDIO_INFO1_MASK, SDIO_INFO1M_ON);
- sh_sdhi_writew(host, SDHI_SDIO_MODE, SDIO_MODE_OFF);
- return -EAGAIN;
- }
-
- if (state2 & INFO2_ALL_ERR) {
- sh_sdhi_writew(host, SDHI_INFO2,
- (unsigned short)~(INFO2_ALL_ERR));
- sh_sdhi_writew(host, SDHI_INFO2_MASK,
- INFO2M_ALL_ERR |
- sh_sdhi_readw(host, SDHI_INFO2_MASK));
- host->sd_error = 1;
- host->wait_int = 1;
- return 0;
- }
- /* Respons End */
- if (state1 & INFO1_RESP_END) {
- sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_RESP_END);
- sh_sdhi_writew(host, SDHI_INFO1_MASK,
- INFO1M_RESP_END |
- sh_sdhi_readw(host, SDHI_INFO1_MASK));
- host->wait_int = 1;
- return 0;
- }
- /* SD_BUF Read Enable */
- if (state2 & INFO2_BRE_ENABLE) {
- sh_sdhi_writew(host, SDHI_INFO2, ~INFO2_BRE_ENABLE);
- sh_sdhi_writew(host, SDHI_INFO2_MASK,
- INFO2M_BRE_ENABLE | INFO2M_BUF_ILL_READ |
- sh_sdhi_readw(host, SDHI_INFO2_MASK));
- host->wait_int = 1;
- return 0;
- }
- /* SD_BUF Write Enable */
- if (state2 & INFO2_BWE_ENABLE) {
- sh_sdhi_writew(host, SDHI_INFO2, ~INFO2_BWE_ENABLE);
- sh_sdhi_writew(host, SDHI_INFO2_MASK,
- INFO2_BWE_ENABLE | INFO2M_BUF_ILL_WRITE |
- sh_sdhi_readw(host, SDHI_INFO2_MASK));
- host->wait_int = 1;
- return 0;
- }
- /* Access End */
- if (state1 & INFO1_ACCESS_END) {
- sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_ACCESS_END);
- sh_sdhi_writew(host, SDHI_INFO1_MASK,
- INFO1_ACCESS_END |
- sh_sdhi_readw(host, SDHI_INFO1_MASK));
- host->wait_int = 1;
- return 0;
- }
- return -EAGAIN;
-}
-
-static int sh_sdhi_wait_interrupt_flag(struct sh_sdhi_host *host)
-{
- int timeout = 10000000;
-
- while (1) {
- timeout--;
- if (timeout < 0) {
- debug(DRIVER_NAME": %s timeout\n", __func__);
- return 0;
- }
-
- if (!sh_sdhi_intr(host))
- break;
-
- udelay(1); /* 1 usec */
- }
-
- return 1; /* Return value: NOT 0 = complete waiting */
-}
-
-static int sh_sdhi_clock_control(struct sh_sdhi_host *host, unsigned long clk)
-{
- u32 clkdiv, i, timeout;
-
- if (sh_sdhi_readw(host, SDHI_INFO2) & (1 << 14)) {
- printf(DRIVER_NAME": Busy state ! Cannot change the clock\n");
- return -EBUSY;
- }
-
- sh_sdhi_writew(host, SDHI_CLK_CTRL,
- ~CLK_ENABLE & sh_sdhi_readw(host, SDHI_CLK_CTRL));
-
- if (clk == 0)
- return -EIO;
-
- clkdiv = 0x80;
- i = CONFIG_SH_SDHI_FREQ >> (0x8 + 1);
- for (; clkdiv && clk >= (i << 1); (clkdiv >>= 1))
- i <<= 1;
-
- sh_sdhi_writew(host, SDHI_CLK_CTRL, clkdiv);
-
- timeout = 100000;
- /* Waiting for SD Bus busy to be cleared */
- while (timeout--) {
- if ((sh_sdhi_readw(host, SDHI_INFO2) & 0x2000))
- break;
- }
-
- if (timeout)
- sh_sdhi_writew(host, SDHI_CLK_CTRL,
- CLK_ENABLE | sh_sdhi_readw(host, SDHI_CLK_CTRL));
- else
- return -EBUSY;
-
- return 0;
-}
-
-static int sh_sdhi_sync_reset(struct sh_sdhi_host *host)
-{
- u32 timeout;
- sh_sdhi_writew(host, SDHI_SOFT_RST, SOFT_RST_ON);
- sh_sdhi_writew(host, SDHI_SOFT_RST, SOFT_RST_OFF);
- sh_sdhi_writew(host, SDHI_CLK_CTRL,
- CLK_ENABLE | sh_sdhi_readw(host, SDHI_CLK_CTRL));
-
- timeout = 100000;
- while (timeout--) {
- if (!(sh_sdhi_readw(host, SDHI_INFO2) & INFO2_CBUSY))
- break;
- udelay(100);
- }
-
- if (!timeout)
- return -EBUSY;
-
- if (host->quirks & SH_SDHI_QUIRK_16BIT_BUF)
- sh_sdhi_writew(host, SDHI_HOST_MODE, 1);
-
- return 0;
-}
-
-static int sh_sdhi_error_manage(struct sh_sdhi_host *host)
-{
- unsigned short e_state1, e_state2;
- int ret;
-
- host->sd_error = 0;
- host->wait_int = 0;
-
- e_state1 = sh_sdhi_readw(host, SDHI_ERR_STS1);
- e_state2 = sh_sdhi_readw(host, SDHI_ERR_STS2);
- if (e_state2 & ERR_STS2_SYS_ERROR) {
- if (e_state2 & ERR_STS2_RES_STOP_TIMEOUT)
- ret = -ETIMEDOUT;
- else
- ret = -EILSEQ;
- debug("%s: ERR_STS2 = %04x\n",
- DRIVER_NAME, sh_sdhi_readw(host, SDHI_ERR_STS2));
- sh_sdhi_sync_reset(host);
-
- sh_sdhi_writew(host, SDHI_INFO1_MASK,
- INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
- return ret;
- }
- if (e_state1 & ERR_STS1_CRC_ERROR || e_state1 & ERR_STS1_CMD_ERROR)
- ret = -EILSEQ;
- else
- ret = -ETIMEDOUT;
-
- debug("%s: ERR_STS1 = %04x\n",
- DRIVER_NAME, sh_sdhi_readw(host, SDHI_ERR_STS1));
- sh_sdhi_sync_reset(host);
- sh_sdhi_writew(host, SDHI_INFO1_MASK,
- INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
- return ret;
-}
-
-static int sh_sdhi_single_read(struct sh_sdhi_host *host, struct mmc_data *data)
-{
- long time;
- unsigned short blocksize, i;
- unsigned short *p = (unsigned short *)data->dest;
- u64 *q = (u64 *)data->dest;
-
- if ((unsigned long)p & 0x00000001) {
- debug(DRIVER_NAME": %s: The data pointer is unaligned.",
- __func__);
- return -EIO;
- }
-
- host->wait_int = 0;
- sh_sdhi_writew(host, SDHI_INFO2_MASK,
- ~(INFO2M_BRE_ENABLE | INFO2M_BUF_ILL_READ) &
- sh_sdhi_readw(host, SDHI_INFO2_MASK));
- sh_sdhi_writew(host, SDHI_INFO1_MASK,
- ~INFO1M_ACCESS_END &
- sh_sdhi_readw(host, SDHI_INFO1_MASK));
- time = sh_sdhi_wait_interrupt_flag(host);
- if (time == 0 || host->sd_error != 0)
- return sh_sdhi_error_manage(host);
-
- host->wait_int = 0;
- blocksize = sh_sdhi_readw(host, SDHI_SIZE);
- if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
- for (i = 0; i < blocksize / 8; i++)
- *q++ = sh_sdhi_readq(host, SDHI_BUF0);
- else
- for (i = 0; i < blocksize / 2; i++)
- *p++ = sh_sdhi_readw(host, SDHI_BUF0);
-
- time = sh_sdhi_wait_interrupt_flag(host);
- if (time == 0 || host->sd_error != 0)
- return sh_sdhi_error_manage(host);
-
- host->wait_int = 0;
- return 0;
-}
-
-static int sh_sdhi_multi_read(struct sh_sdhi_host *host, struct mmc_data *data)
-{
- long time;
- unsigned short blocksize, i, sec;
- unsigned short *p = (unsigned short *)data->dest;
- u64 *q = (u64 *)data->dest;
-
- if ((unsigned long)p & 0x00000001) {
- debug(DRIVER_NAME": %s: The data pointer is unaligned.",
- __func__);
- return -EIO;
- }
-
- debug("%s: blocks = %d, blocksize = %d\n",
- __func__, data->blocks, data->blocksize);
-
- host->wait_int = 0;
- for (sec = 0; sec < data->blocks; sec++) {
- sh_sdhi_writew(host, SDHI_INFO2_MASK,
- ~(INFO2M_BRE_ENABLE | INFO2M_BUF_ILL_READ) &
- sh_sdhi_readw(host, SDHI_INFO2_MASK));
-
- time = sh_sdhi_wait_interrupt_flag(host);
- if (time == 0 || host->sd_error != 0)
- return sh_sdhi_error_manage(host);
-
- host->wait_int = 0;
- blocksize = sh_sdhi_readw(host, SDHI_SIZE);
- if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
- for (i = 0; i < blocksize / 8; i++)
- *q++ = sh_sdhi_readq(host, SDHI_BUF0);
- else
- for (i = 0; i < blocksize / 2; i++)
- *p++ = sh_sdhi_readw(host, SDHI_BUF0);
- }
-
- return 0;
-}
-
-static int sh_sdhi_single_write(struct sh_sdhi_host *host,
- struct mmc_data *data)
-{
- long time;
- unsigned short blocksize, i;
- const unsigned short *p = (const unsigned short *)data->src;
- const u64 *q = (const u64 *)data->src;
-
- if ((unsigned long)p & 0x00000001) {
- debug(DRIVER_NAME": %s: The data pointer is unaligned.",
- __func__);
- return -EIO;
- }
-
- debug("%s: blocks = %d, blocksize = %d\n",
- __func__, data->blocks, data->blocksize);
-
- host->wait_int = 0;
- sh_sdhi_writew(host, SDHI_INFO2_MASK,
- ~(INFO2M_BWE_ENABLE | INFO2M_BUF_ILL_WRITE) &
- sh_sdhi_readw(host, SDHI_INFO2_MASK));
- sh_sdhi_writew(host, SDHI_INFO1_MASK,
- ~INFO1M_ACCESS_END &
- sh_sdhi_readw(host, SDHI_INFO1_MASK));
-
- time = sh_sdhi_wait_interrupt_flag(host);
- if (time == 0 || host->sd_error != 0)
- return sh_sdhi_error_manage(host);
-
- host->wait_int = 0;
- blocksize = sh_sdhi_readw(host, SDHI_SIZE);
- if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
- for (i = 0; i < blocksize / 8; i++)
- sh_sdhi_writeq(host, SDHI_BUF0, *q++);
- else
- for (i = 0; i < blocksize / 2; i++)
- sh_sdhi_writew(host, SDHI_BUF0, *p++);
-
- time = sh_sdhi_wait_interrupt_flag(host);
- if (time == 0 || host->sd_error != 0)
- return sh_sdhi_error_manage(host);
-
- host->wait_int = 0;
- return 0;
-}
-
-static int sh_sdhi_multi_write(struct sh_sdhi_host *host, struct mmc_data *data)
-{
- long time;
- unsigned short i, sec, blocksize;
- const unsigned short *p = (const unsigned short *)data->src;
- const u64 *q = (const u64 *)data->src;
-
- debug("%s: blocks = %d, blocksize = %d\n",
- __func__, data->blocks, data->blocksize);
-
- host->wait_int = 0;
- for (sec = 0; sec < data->blocks; sec++) {
- sh_sdhi_writew(host, SDHI_INFO2_MASK,
- ~(INFO2M_BWE_ENABLE | INFO2M_BUF_ILL_WRITE) &
- sh_sdhi_readw(host, SDHI_INFO2_MASK));
-
- time = sh_sdhi_wait_interrupt_flag(host);
- if (time == 0 || host->sd_error != 0)
- return sh_sdhi_error_manage(host);
-
- host->wait_int = 0;
- blocksize = sh_sdhi_readw(host, SDHI_SIZE);
- if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
- for (i = 0; i < blocksize / 8; i++)
- sh_sdhi_writeq(host, SDHI_BUF0, *q++);
- else
- for (i = 0; i < blocksize / 2; i++)
- sh_sdhi_writew(host, SDHI_BUF0, *p++);
- }
-
- return 0;
-}
-
-static void sh_sdhi_get_response(struct sh_sdhi_host *host, struct mmc_cmd *cmd)
-{
- unsigned short i, j, cnt = 1;
- unsigned short resp[8];
-
- if (cmd->resp_type & MMC_RSP_136) {
- cnt = 4;
- resp[0] = sh_sdhi_readw(host, SDHI_RSP00);
- resp[1] = sh_sdhi_readw(host, SDHI_RSP01);
- resp[2] = sh_sdhi_readw(host, SDHI_RSP02);
- resp[3] = sh_sdhi_readw(host, SDHI_RSP03);
- resp[4] = sh_sdhi_readw(host, SDHI_RSP04);
- resp[5] = sh_sdhi_readw(host, SDHI_RSP05);
- resp[6] = sh_sdhi_readw(host, SDHI_RSP06);
- resp[7] = sh_sdhi_readw(host, SDHI_RSP07);
-
- /* SDHI REGISTER SPECIFICATION */
- for (i = 7, j = 6; i > 0; i--) {
- resp[i] = (resp[i] << 8) & 0xff00;
- resp[i] |= (resp[j--] >> 8) & 0x00ff;
- }
- resp[0] = (resp[0] << 8) & 0xff00;
- } else {
- resp[0] = sh_sdhi_readw(host, SDHI_RSP00);
- resp[1] = sh_sdhi_readw(host, SDHI_RSP01);
- }
-
-#if defined(__BIG_ENDIAN_BITFIELD)
- if (cnt == 4) {
- cmd->response[0] = (resp[6] << 16) | resp[7];
- cmd->response[1] = (resp[4] << 16) | resp[5];
- cmd->response[2] = (resp[2] << 16) | resp[3];
- cmd->response[3] = (resp[0] << 16) | resp[1];
- } else {
- cmd->response[0] = (resp[0] << 16) | resp[1];
- }
-#else
- if (cnt == 4) {
- cmd->response[0] = (resp[7] << 16) | resp[6];
- cmd->response[1] = (resp[5] << 16) | resp[4];
- cmd->response[2] = (resp[3] << 16) | resp[2];
- cmd->response[3] = (resp[1] << 16) | resp[0];
- } else {
- cmd->response[0] = (resp[1] << 16) | resp[0];
- }
-#endif /* __BIG_ENDIAN_BITFIELD */
-}
-
-static unsigned short sh_sdhi_set_cmd(struct sh_sdhi_host *host,
- struct mmc_data *data, unsigned short opc)
-{
- if (host->app_cmd) {
- if (!data)
- host->app_cmd = 0;
- return opc | BIT(6);
- }
-
- switch (opc) {
- case MMC_CMD_SWITCH:
- return opc | (data ? 0x1c00 : 0x40);
- case MMC_CMD_SEND_EXT_CSD:
- return opc | (data ? 0x1c00 : 0);
- case MMC_CMD_SEND_OP_COND:
- return opc | 0x0700;
- case MMC_CMD_APP_CMD:
- host->app_cmd = 1;
- default:
- return opc;
- }
-}
-
-static unsigned short sh_sdhi_data_trans(struct sh_sdhi_host *host,
- struct mmc_data *data, unsigned short opc)
-{
- if (host->app_cmd) {
- host->app_cmd = 0;
- switch (opc) {
- case SD_CMD_APP_SEND_SCR:
- case SD_CMD_APP_SD_STATUS:
- return sh_sdhi_single_read(host, data);
- default:
- printf(DRIVER_NAME": SD: NOT SUPPORT APP CMD = d'%04d\n",
- opc);
- return -EINVAL;
- }
- } else {
- switch (opc) {
- case MMC_CMD_WRITE_MULTIPLE_BLOCK:
- return sh_sdhi_multi_write(host, data);
- case MMC_CMD_READ_MULTIPLE_BLOCK:
- return sh_sdhi_multi_read(host, data);
- case MMC_CMD_WRITE_SINGLE_BLOCK:
- return sh_sdhi_single_write(host, data);
- case MMC_CMD_READ_SINGLE_BLOCK:
- case MMC_CMD_SWITCH:
- case MMC_CMD_SEND_EXT_CSD:;
- return sh_sdhi_single_read(host, data);
- default:
- printf(DRIVER_NAME": SD: NOT SUPPORT CMD = d'%04d\n", opc);
- return -EINVAL;
- }
- }
-}
-
-static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
- struct mmc_data *data, struct mmc_cmd *cmd)
-{
- long time;
- unsigned short shcmd, opc = cmd->cmdidx;
- int ret = 0;
- unsigned long timeout;
-
- debug("opc = %d, arg = %x, resp_type = %x\n",
- opc, cmd->cmdarg, cmd->resp_type);
-
- if (opc == MMC_CMD_STOP_TRANSMISSION) {
- /* SDHI sends the STOP command automatically by STOP reg */
- sh_sdhi_writew(host, SDHI_INFO1_MASK, ~INFO1M_ACCESS_END &
- sh_sdhi_readw(host, SDHI_INFO1_MASK));
-
- time = sh_sdhi_wait_interrupt_flag(host);
- if (time == 0 || host->sd_error != 0)
- return sh_sdhi_error_manage(host);
-
- sh_sdhi_get_response(host, cmd);
- return 0;
- }
-
- if (data) {
- if ((opc == MMC_CMD_READ_MULTIPLE_BLOCK) ||
- opc == MMC_CMD_WRITE_MULTIPLE_BLOCK) {
- sh_sdhi_writew(host, SDHI_STOP, STOP_SEC_ENABLE);
- sh_sdhi_writew(host, SDHI_SECCNT, data->blocks);
- }
- sh_sdhi_writew(host, SDHI_SIZE, data->blocksize);
- }
-
- shcmd = sh_sdhi_set_cmd(host, data, opc);
-
- /*
- * U-Boot cannot use interrupt.
- * So this flag may not be clear by timing
- */
- sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_RESP_END);
-
- sh_sdhi_writew(host, SDHI_INFO1_MASK,
- INFO1M_RESP_END | sh_sdhi_readw(host, SDHI_INFO1_MASK));
- sh_sdhi_writew(host, SDHI_ARG0,
- (unsigned short)(cmd->cmdarg & ARG0_MASK));
- sh_sdhi_writew(host, SDHI_ARG1,
- (unsigned short)((cmd->cmdarg >> 16) & ARG1_MASK));
-
- timeout = 100000;
- /* Waiting for SD Bus busy to be cleared */
- while (timeout--) {
- if ((sh_sdhi_readw(host, SDHI_INFO2) & 0x2000))
- break;
- }
-
- host->wait_int = 0;
- sh_sdhi_writew(host, SDHI_INFO1_MASK,
- ~INFO1M_RESP_END & sh_sdhi_readw(host, SDHI_INFO1_MASK));
- sh_sdhi_writew(host, SDHI_INFO2_MASK,
- ~(INFO2M_CMD_ERROR | INFO2M_CRC_ERROR |
- INFO2M_END_ERROR | INFO2M_TIMEOUT |
- INFO2M_RESP_TIMEOUT | INFO2M_ILA) &
- sh_sdhi_readw(host, SDHI_INFO2_MASK));
-
- sh_sdhi_writew(host, SDHI_CMD, (unsigned short)(shcmd & CMD_MASK));
- time = sh_sdhi_wait_interrupt_flag(host);
- if (!time) {
- host->app_cmd = 0;
- return sh_sdhi_error_manage(host);
- }
-
- if (host->sd_error) {
- switch (cmd->cmdidx) {
- case MMC_CMD_ALL_SEND_CID:
- case MMC_CMD_SELECT_CARD:
- case SD_CMD_SEND_IF_COND:
- case MMC_CMD_APP_CMD:
- ret = -ETIMEDOUT;
- break;
- default:
- debug(DRIVER_NAME": Cmd(d'%d) err\n", opc);
- debug(DRIVER_NAME": cmdidx = %d\n", cmd->cmdidx);
- ret = sh_sdhi_error_manage(host);
- break;
- }
- host->sd_error = 0;
- host->wait_int = 0;
- host->app_cmd = 0;
- return ret;
- }
-
- if (sh_sdhi_readw(host, SDHI_INFO1) & INFO1_RESP_END) {
- host->app_cmd = 0;
- return -EINVAL;
- }
-
- if (host->wait_int) {
- sh_sdhi_get_response(host, cmd);
- host->wait_int = 0;
- }
-
- if (data)
- ret = sh_sdhi_data_trans(host, data, opc);
-
- debug("ret = %d, resp = %08x, %08x, %08x, %08x\n",
- ret, cmd->response[0], cmd->response[1],
- cmd->response[2], cmd->response[3]);
- return ret;
-}
-
-static int sh_sdhi_send_cmd_common(struct sh_sdhi_host *host,
- struct mmc_cmd *cmd, struct mmc_data *data)
-{
- host->sd_error = 0;
-
- return sh_sdhi_start_cmd(host, data, cmd);
-}
-
-static int sh_sdhi_set_ios_common(struct sh_sdhi_host *host, struct mmc *mmc)
-{
- int ret;
-
- ret = sh_sdhi_clock_control(host, mmc->clock);
- if (ret)
- return -EINVAL;
-
- if (mmc->bus_width == 8)
- sh_sdhi_writew(host, SDHI_OPTION,
- OPT_BUS_WIDTH_8 | (~OPT_BUS_WIDTH_M &
- sh_sdhi_readw(host, SDHI_OPTION)));
- else if (mmc->bus_width == 4)
- sh_sdhi_writew(host, SDHI_OPTION,
- OPT_BUS_WIDTH_4 | (~OPT_BUS_WIDTH_M &
- sh_sdhi_readw(host, SDHI_OPTION)));
- else
- sh_sdhi_writew(host, SDHI_OPTION,
- OPT_BUS_WIDTH_1 | (~OPT_BUS_WIDTH_M &
- sh_sdhi_readw(host, SDHI_OPTION)));
-
- debug("clock = %d, buswidth = %d\n", mmc->clock, mmc->bus_width);
-
- return 0;
-}
-
-static int sh_sdhi_initialize_common(struct sh_sdhi_host *host)
-{
- int ret = sh_sdhi_sync_reset(host);
-
- sh_sdhi_writew(host, SDHI_PORTSEL, USE_1PORT);
-
-#if defined(__BIG_ENDIAN_BITFIELD)
- sh_sdhi_writew(host, SDHI_EXT_SWAP, SET_SWAP);
-#endif
-
- sh_sdhi_writew(host, SDHI_INFO1_MASK, INFO1M_RESP_END |
- INFO1M_ACCESS_END | INFO1M_CARD_RE |
- INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
-
- return ret;
-}
-
-#ifndef CONFIG_DM_MMC
-static void *mmc_priv(struct mmc *mmc)
-{
- return (void *)mmc->priv;
-}
-
-static int sh_sdhi_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
- struct mmc_data *data)
-{
- struct sh_sdhi_host *host = mmc_priv(mmc);
-
- return sh_sdhi_send_cmd_common(host, cmd, data);
-}
-
-static int sh_sdhi_set_ios(struct mmc *mmc)
-{
- struct sh_sdhi_host *host = mmc_priv(mmc);
-
- return sh_sdhi_set_ios_common(host, mmc);
-}
-
-static int sh_sdhi_initialize(struct mmc *mmc)
-{
- struct sh_sdhi_host *host = mmc_priv(mmc);
-
- return sh_sdhi_initialize_common(host);
-}
-
-static const struct mmc_ops sh_sdhi_ops = {
- .send_cmd = sh_sdhi_send_cmd,
- .set_ios = sh_sdhi_set_ios,
- .init = sh_sdhi_initialize,
-};
-
-#ifdef CONFIG_RCAR_GEN3
-static struct mmc_config sh_sdhi_cfg = {
- .name = DRIVER_NAME,
- .ops = &sh_sdhi_ops,
- .f_min = CLKDEV_INIT,
- .f_max = CLKDEV_HS_DATA,
- .voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34,
- .host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT | MMC_MODE_HS |
- MMC_MODE_HS_52MHz,
- .part_type = PART_TYPE_DOS,
- .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT,
-};
-#else
-static struct mmc_config sh_sdhi_cfg = {
- .name = DRIVER_NAME,
- .ops = &sh_sdhi_ops,
- .f_min = CLKDEV_INIT,
- .f_max = CLKDEV_HS_DATA,
- .voltages = MMC_VDD_32_33 | MMC_VDD_33_34,
- .host_caps = MMC_MODE_4BIT | MMC_MODE_HS,
- .part_type = PART_TYPE_DOS,
- .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT,
-};
-#endif
-
-int sh_sdhi_init(unsigned long addr, int ch, unsigned long quirks)
-{
- int ret = 0;
- struct mmc *mmc;
- struct sh_sdhi_host *host = NULL;
-
- if (ch >= CFG_SYS_SH_SDHI_NR_CHANNEL)
- return -ENODEV;
-
- host = malloc(sizeof(struct sh_sdhi_host));
- if (!host)
- return -ENOMEM;
-
- mmc = mmc_create(&sh_sdhi_cfg, host);
- if (!mmc) {
- ret = -1;
- goto error;
- }
-
- host->ch = ch;
- host->addr = (void __iomem *)addr;
- host->quirks = quirks;
-
- if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
- host->bus_shift = 2;
- else if (host->quirks & SH_SDHI_QUIRK_16BIT_BUF)
- host->bus_shift = 1;
-
- return ret;
-error:
- free(host);
- return ret;
-}
-
-#else
-
-struct sh_sdhi_plat {
- struct mmc_config cfg;
- struct mmc mmc;
-};
-
-int sh_sdhi_dm_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
- struct mmc_data *data)
-{
- struct sh_sdhi_host *host = dev_get_priv(dev);
-
- return sh_sdhi_send_cmd_common(host, cmd, data);
-}
-
-int sh_sdhi_dm_set_ios(struct udevice *dev)
-{
- struct sh_sdhi_host *host = dev_get_priv(dev);
- struct mmc *mmc = mmc_get_mmc_dev(dev);
-
- return sh_sdhi_set_ios_common(host, mmc);
-}
-
-static const struct dm_mmc_ops sh_sdhi_dm_ops = {
- .send_cmd = sh_sdhi_dm_send_cmd,
- .set_ios = sh_sdhi_dm_set_ios,
-};
-
-static int sh_sdhi_dm_bind(struct udevice *dev)
-{
- struct sh_sdhi_plat *plat = dev_get_plat(dev);
-
- return mmc_bind(dev, &plat->mmc, &plat->cfg);
-}
-
-static int sh_sdhi_dm_probe(struct udevice *dev)
-{
- struct sh_sdhi_plat *plat = dev_get_plat(dev);
- struct sh_sdhi_host *host = dev_get_priv(dev);
- struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
- struct clk sh_sdhi_clk;
- const u32 quirks = dev_get_driver_data(dev);
- fdt_addr_t base;
- int ret;
-
- base = dev_read_addr(dev);
- if (base == FDT_ADDR_T_NONE)
- return -EINVAL;
-
- host->addr = devm_ioremap(dev, base, SZ_2K);
- if (!host->addr)
- return -ENOMEM;
-
- ret = clk_get_by_index(dev, 0, &sh_sdhi_clk);
- if (ret) {
- debug("failed to get clock, ret=%d\n", ret);
- return ret;
- }
-
- ret = clk_enable(&sh_sdhi_clk);
- if (ret) {
- debug("failed to enable clock, ret=%d\n", ret);
- return ret;
- }
-
- host->quirks = quirks;
-
- if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
- host->bus_shift = 2;
- else if (host->quirks & SH_SDHI_QUIRK_16BIT_BUF)
- host->bus_shift = 1;
-
- plat->cfg.name = dev->name;
- plat->cfg.host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS;
-
- switch (fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width",
- 1)) {
- case 8:
- plat->cfg.host_caps |= MMC_MODE_8BIT;
- break;
- case 4:
- plat->cfg.host_caps |= MMC_MODE_4BIT;
- break;
- case 1:
- break;
- default:
- dev_err(dev, "Invalid \"bus-width\" value\n");
- return -EINVAL;
- }
-
- sh_sdhi_initialize_common(host);
-
- plat->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34;
- plat->cfg.f_min = CLKDEV_INIT;
- plat->cfg.f_max = CLKDEV_HS_DATA;
- plat->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
-
- upriv->mmc = &plat->mmc;
-
- return 0;
-}
-
-static const struct udevice_id sh_sdhi_sd_match[] = {
- { .compatible = "renesas,sdhi-r8a7795", .data = SH_SDHI_QUIRK_64BIT_BUF },
- { .compatible = "renesas,sdhi-r8a7796", .data = SH_SDHI_QUIRK_64BIT_BUF },
- { /* sentinel */ }
-};
-
-U_BOOT_DRIVER(sh_sdhi_mmc) = {
- .name = "sh-sdhi-mmc",
- .id = UCLASS_MMC,
- .of_match = sh_sdhi_sd_match,
- .bind = sh_sdhi_dm_bind,
- .probe = sh_sdhi_dm_probe,
- .priv_auto = sizeof(struct sh_sdhi_host),
- .plat_auto = sizeof(struct sh_sdhi_plat),
- .ops = &sh_sdhi_dm_ops,
-};
-#endif
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
index 23bc7da917a..714706d2411 100644
--- a/drivers/mmc/sunxi_mmc.c
+++ b/drivers/mmc/sunxi_mmc.c
@@ -25,8 +25,13 @@
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/cpu.h>
+#if !CONFIG_IS_ENABLED(DM_MMC)
#include <asm/arch/mmc.h>
+#endif
#include <linux/delay.h>
+#include <sunxi_gpio.h>
+
+#include "sunxi_mmc.h"
#ifndef CCM_MMC_CTRL_MODE_SEL_NEW
#define CCM_MMC_CTRL_MODE_SEL_NEW 0
@@ -56,6 +61,7 @@ static bool sunxi_mmc_can_calibrate(void)
return IS_ENABLED(CONFIG_MACH_SUN50I) ||
IS_ENABLED(CONFIG_MACH_SUN50I_H5) ||
IS_ENABLED(CONFIG_SUN50I_GEN_H6) ||
+ IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2) ||
IS_ENABLED(CONFIG_MACH_SUN8I_R40);
}
@@ -190,7 +196,7 @@ static int mmc_config_clock(struct sunxi_mmc_priv *priv, struct mmc *mmc)
rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK;
writel(rval, &priv->reg->clkcr);
-#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6)
+#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) || defined(CONFIG_SUNXI_GEN_NCAT2)
/* A64 supports calibration of delays on MMC controller and we
* have to set delay of zero before starting calibration.
* Allwinner BSP driver sets a delay only in the case of
@@ -543,7 +549,7 @@ struct mmc *sunxi_mmc_init(int sdc_no)
/* config ahb clock */
debug("init mmc %d clock and io\n", sdc_no);
-#if !defined(CONFIG_SUN50I_GEN_H6)
+#if !defined(CONFIG_SUN50I_GEN_H6) && !defined(CONFIG_SUNXI_GEN_NCAT2)
setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no));
#ifdef CONFIG_SUNXI_GEN_SUN6I
@@ -618,7 +624,7 @@ static unsigned get_mclk_offset(void)
if (IS_ENABLED(CONFIG_MACH_SUN9I_A80))
return 0x410;
- if (IS_ENABLED(CONFIG_SUN50I_GEN_H6))
+ if (IS_ENABLED(CONFIG_SUN50I_GEN_H6) || IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2))
return 0x830;
return 0x88;
@@ -699,6 +705,7 @@ static const struct udevice_id sunxi_mmc_ids[] = {
{ .compatible = "allwinner,sun7i-a20-mmc" },
{ .compatible = "allwinner,sun8i-a83t-emmc" },
{ .compatible = "allwinner,sun9i-a80-mmc" },
+ { .compatible = "allwinner,sun20i-d1-mmc" },
{ .compatible = "allwinner,sun50i-a64-mmc" },
{ .compatible = "allwinner,sun50i-a64-emmc" },
{ .compatible = "allwinner,sun50i-h6-mmc" },
diff --git a/drivers/mmc/sunxi_mmc.h b/drivers/mmc/sunxi_mmc.h
new file mode 100644
index 00000000000..f4ae5a790c8
--- /dev/null
+++ b/drivers/mmc/sunxi_mmc.h
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Aaron <leafy.myeh@allwinnertech.com>
+ *
+ * MMC register definition for allwinner sunxi platform.
+ */
+
+#ifndef _SUNXI_MMC_H
+#define _SUNXI_MMC_H
+
+#include <linux/types.h>
+
+struct sunxi_mmc {
+ u32 gctrl; /* 0x00 global control */
+ u32 clkcr; /* 0x04 clock control */
+ u32 timeout; /* 0x08 time out */
+ u32 width; /* 0x0c bus width */
+ u32 blksz; /* 0x10 block size */
+ u32 bytecnt; /* 0x14 byte count */
+ u32 cmd; /* 0x18 command */
+ u32 arg; /* 0x1c argument */
+ u32 resp0; /* 0x20 response 0 */
+ u32 resp1; /* 0x24 response 1 */
+ u32 resp2; /* 0x28 response 2 */
+ u32 resp3; /* 0x2c response 3 */
+ u32 imask; /* 0x30 interrupt mask */
+ u32 mint; /* 0x34 masked interrupt status */
+ u32 rint; /* 0x38 raw interrupt status */
+ u32 status; /* 0x3c status */
+ u32 ftrglevel; /* 0x40 FIFO threshold watermark*/
+ u32 funcsel; /* 0x44 function select */
+ u32 cbcr; /* 0x48 CIU byte count */
+ u32 bbcr; /* 0x4c BIU byte count */
+ u32 dbgc; /* 0x50 debug enable */
+ u32 res0; /* 0x54 reserved */
+ u32 a12a; /* 0x58 Auto command 12 argument */
+ u32 ntsr; /* 0x5c New timing set register */
+ u32 res1[8];
+ u32 dmac; /* 0x80 internal DMA control */
+ u32 dlba; /* 0x84 internal DMA descr list base address */
+ u32 idst; /* 0x88 internal DMA status */
+ u32 idie; /* 0x8c internal DMA interrupt enable */
+ u32 chda; /* 0x90 */
+ u32 cbda; /* 0x94 */
+ u32 res2[26];
+#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) || defined(CONFIG_SUNXI_GEN_NCAT2)
+ u32 res3[17];
+ u32 samp_dl;
+ u32 res4[46];
+#endif
+ u32 fifo; /* 0x100 / 0x200 FIFO access address */
+};
+
+#define SUNXI_MMC_CLK_POWERSAVE (0x1 << 17)
+#define SUNXI_MMC_CLK_ENABLE (0x1 << 16)
+#define SUNXI_MMC_CLK_DIVIDER_MASK (0xff)
+
+#define SUNXI_MMC_GCTRL_SOFT_RESET (0x1 << 0)
+#define SUNXI_MMC_GCTRL_FIFO_RESET (0x1 << 1)
+#define SUNXI_MMC_GCTRL_DMA_RESET (0x1 << 2)
+#define SUNXI_MMC_GCTRL_RESET (SUNXI_MMC_GCTRL_SOFT_RESET|\
+ SUNXI_MMC_GCTRL_FIFO_RESET|\
+ SUNXI_MMC_GCTRL_DMA_RESET)
+#define SUNXI_MMC_GCTRL_DMA_ENABLE (0x1 << 5)
+#define SUNXI_MMC_GCTRL_ACCESS_BY_AHB (0x1 << 31)
+
+#define SUNXI_MMC_CMD_RESP_EXPIRE (0x1 << 6)
+#define SUNXI_MMC_CMD_LONG_RESPONSE (0x1 << 7)
+#define SUNXI_MMC_CMD_CHK_RESPONSE_CRC (0x1 << 8)
+#define SUNXI_MMC_CMD_DATA_EXPIRE (0x1 << 9)
+#define SUNXI_MMC_CMD_WRITE (0x1 << 10)
+#define SUNXI_MMC_CMD_AUTO_STOP (0x1 << 12)
+#define SUNXI_MMC_CMD_WAIT_PRE_OVER (0x1 << 13)
+#define SUNXI_MMC_CMD_SEND_INIT_SEQ (0x1 << 15)
+#define SUNXI_MMC_CMD_UPCLK_ONLY (0x1 << 21)
+#define SUNXI_MMC_CMD_START (0x1 << 31)
+
+#define SUNXI_MMC_RINT_RESP_ERROR (0x1 << 1)
+#define SUNXI_MMC_RINT_COMMAND_DONE (0x1 << 2)
+#define SUNXI_MMC_RINT_DATA_OVER (0x1 << 3)
+#define SUNXI_MMC_RINT_TX_DATA_REQUEST (0x1 << 4)
+#define SUNXI_MMC_RINT_RX_DATA_REQUEST (0x1 << 5)
+#define SUNXI_MMC_RINT_RESP_CRC_ERROR (0x1 << 6)
+#define SUNXI_MMC_RINT_DATA_CRC_ERROR (0x1 << 7)
+#define SUNXI_MMC_RINT_RESP_TIMEOUT (0x1 << 8)
+#define SUNXI_MMC_RINT_DATA_TIMEOUT (0x1 << 9)
+#define SUNXI_MMC_RINT_VOLTAGE_CHANGE_DONE (0x1 << 10)
+#define SUNXI_MMC_RINT_FIFO_RUN_ERROR (0x1 << 11)
+#define SUNXI_MMC_RINT_HARD_WARE_LOCKED (0x1 << 12)
+#define SUNXI_MMC_RINT_START_BIT_ERROR (0x1 << 13)
+#define SUNXI_MMC_RINT_AUTO_COMMAND_DONE (0x1 << 14)
+#define SUNXI_MMC_RINT_END_BIT_ERROR (0x1 << 15)
+#define SUNXI_MMC_RINT_SDIO_INTERRUPT (0x1 << 16)
+#define SUNXI_MMC_RINT_CARD_INSERT (0x1 << 30)
+#define SUNXI_MMC_RINT_CARD_REMOVE (0x1 << 31)
+#define SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT \
+ (SUNXI_MMC_RINT_RESP_ERROR | \
+ SUNXI_MMC_RINT_RESP_CRC_ERROR | \
+ SUNXI_MMC_RINT_DATA_CRC_ERROR | \
+ SUNXI_MMC_RINT_RESP_TIMEOUT | \
+ SUNXI_MMC_RINT_DATA_TIMEOUT | \
+ SUNXI_MMC_RINT_VOLTAGE_CHANGE_DONE | \
+ SUNXI_MMC_RINT_FIFO_RUN_ERROR | \
+ SUNXI_MMC_RINT_HARD_WARE_LOCKED | \
+ SUNXI_MMC_RINT_START_BIT_ERROR | \
+ SUNXI_MMC_RINT_END_BIT_ERROR) /* 0xbfc2 */
+#define SUNXI_MMC_RINT_INTERRUPT_DONE_BIT \
+ (SUNXI_MMC_RINT_AUTO_COMMAND_DONE | \
+ SUNXI_MMC_RINT_DATA_OVER | \
+ SUNXI_MMC_RINT_COMMAND_DONE | \
+ SUNXI_MMC_RINT_VOLTAGE_CHANGE_DONE)
+
+#define SUNXI_MMC_STATUS_RXWL_FLAG (0x1 << 0)
+#define SUNXI_MMC_STATUS_TXWL_FLAG (0x1 << 1)
+#define SUNXI_MMC_STATUS_FIFO_EMPTY (0x1 << 2)
+#define SUNXI_MMC_STATUS_FIFO_FULL (0x1 << 3)
+#define SUNXI_MMC_STATUS_CARD_PRESENT (0x1 << 8)
+#define SUNXI_MMC_STATUS_CARD_DATA_BUSY (0x1 << 9)
+#define SUNXI_MMC_STATUS_DATA_FSM_BUSY (0x1 << 10)
+#define SUNXI_MMC_STATUS_FIFO_LEVEL(reg) (((reg) >> 17) & 0x3fff)
+
+#define SUNXI_MMC_NTSR_MODE_SEL_NEW (0x1 << 31)
+
+#define SUNXI_MMC_IDMAC_RESET (0x1 << 0)
+#define SUNXI_MMC_IDMAC_FIXBURST (0x1 << 1)
+#define SUNXI_MMC_IDMAC_ENABLE (0x1 << 7)
+
+#define SUNXI_MMC_IDIE_TXIRQ (0x1 << 0)
+#define SUNXI_MMC_IDIE_RXIRQ (0x1 << 1)
+
+#define SUNXI_MMC_COMMON_CLK_GATE (1 << 16)
+#define SUNXI_MMC_COMMON_RESET (1 << 18)
+
+#define SUNXI_MMC_CAL_DL_SW_EN (0x1 << 7)
+
+#endif /* _SUNXI_MMC_H */
diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c
index f76fee3ea0f..d507adbb363 100644
--- a/drivers/mmc/tegra_mmc.c
+++ b/drivers/mmc/tegra_mmc.c
@@ -37,6 +37,9 @@ struct tegra_mmc_priv {
unsigned int version; /* SDHCI spec. version */
unsigned int clock; /* Current clock (MHz) */
int mmc_id; /* peripheral id */
+
+ int tap_value;
+ int trim_value;
};
static void tegra_mmc_set_power(struct tegra_mmc_priv *priv,
@@ -526,31 +529,6 @@ static void tegra_mmc_pad_init(struct tegra_mmc_priv *priv)
printf("%s: Warning: Autocal timed out!\n", __func__);
/* TBD: Set CFG2TMC_SDMMC1_PAD_CAL_DRV* regs here */
}
-
-#if defined(CONFIG_TEGRA210)
- u32 tap_value, trim_value;
-
- /* Set tap/trim values for SDMMC1/3 @ <48MHz here */
- val = readl(&priv->reg->venspictl); /* aka VENDOR_SYS_SW_CNTL */
- val &= IO_TRIM_BYPASS_MASK;
- if (id == PERIPH_ID_SDMMC1) {
- tap_value = 4; /* default */
- if (val)
- tap_value = 3;
- trim_value = 2;
- } else { /* SDMMC3 */
- tap_value = 3;
- trim_value = 3;
- }
-
- val = readl(&priv->reg->venclkctl);
- val &= ~TRIM_VAL_MASK;
- val |= (trim_value << TRIM_VAL_SHIFT);
- val &= ~TAP_VAL_MASK;
- val |= (tap_value << TAP_VAL_SHIFT);
- writel(val, &priv->reg->venclkctl);
- debug("%s: VENDOR_CLOCK_CNTRL = 0x%08X\n", __func__, val);
-#endif /* T210 */
#endif /* T30/T210 */
}
@@ -588,6 +566,22 @@ static void tegra_mmc_reset(struct tegra_mmc_priv *priv, struct mmc *mmc)
/* Make sure SDIO pads are set up */
tegra_mmc_pad_init(priv);
+
+ if (!IS_ERR_VALUE(priv->tap_value) ||
+ !IS_ERR_VALUE(priv->trim_value)) {
+ u32 val;
+
+ val = readl(&priv->reg->venclkctl);
+
+ val &= ~TRIM_VAL_MASK;
+ val |= (priv->trim_value << TRIM_VAL_SHIFT);
+
+ val &= ~TAP_VAL_MASK;
+ val |= (priv->tap_value << TAP_VAL_SHIFT);
+
+ writel(val, &priv->reg->venclkctl);
+ debug("%s: VENDOR_CLOCK_CNTRL = 0x%08X\n", __func__, val);
+ }
}
static int tegra_mmc_init(struct udevice *dev)
@@ -742,6 +736,14 @@ static int tegra_mmc_probe(struct udevice *dev)
if (dm_gpio_is_valid(&priv->pwr_gpio))
dm_gpio_set_value(&priv->pwr_gpio, 1);
+ ret = dev_read_u32(dev, "nvidia,default-tap", &priv->tap_value);
+ if (ret)
+ priv->tap_value = ret;
+
+ ret = dev_read_u32(dev, "nvidia,default-trim", &priv->trim_value);
+ if (ret)
+ priv->trim_value = ret;
+
upriv->mmc = &plat->mmc;
return tegra_mmc_init(dev);
diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c
index d1e26815996..890c496b535 100644
--- a/drivers/mmc/tmio-common.c
+++ b/drivers/mmc/tmio-common.c
@@ -122,7 +122,10 @@ static int tmio_sd_wait_for_irq(struct udevice *dev, struct mmc_cmd *cmd,
long wait = 1000000;
int ret;
- while (!(tmio_sd_readl(priv, reg) & flag)) {
+ while (true) {
+ if (tmio_sd_readl(priv, reg) & flag)
+ return tmio_sd_check_error(dev, cmd);
+
if (wait-- < 0) {
dev_err(dev, "timeout\n");
return -ETIMEDOUT;
@@ -756,7 +759,8 @@ int tmio_sd_probe(struct udevice *dev, u32 quirks)
dev_dbg(dev, "version %x\n", priv->version);
if (priv->version >= 0x10) {
priv->caps |= TMIO_SD_CAP_DMA_INTERNAL;
- priv->caps |= TMIO_SD_CAP_DIV1024;
+ if (!(priv->caps & TMIO_SD_CAP_RCAR))
+ priv->caps |= TMIO_SD_CAP_DIV1024;
}
if (fdt_get_property(gd->fdt_blob, dev_of_offset(dev), "non-removable",
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index c638980ea2b..c2fc80b10f0 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -31,7 +31,7 @@ obj-$(CONFIG_NVMXIP) += nvmxip/
else
ifneq ($(mtd-y),)
-obj-$(CONFIG_SPL_MTD_SUPPORT) += mtd.o
+obj-$(CONFIG_SPL_MTD) += mtd.o
endif
obj-$(CONFIG_$(SPL_TPL_)NAND_SUPPORT) += nand/
obj-$(CONFIG_SPL_ONENAND_SUPPORT) += onenand/
diff --git a/drivers/mtd/hbmc-am654.c b/drivers/mtd/hbmc-am654.c
index c86e504da30..8161087b50c 100644
--- a/drivers/mtd/hbmc-am654.c
+++ b/drivers/mtd/hbmc-am654.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
//
-// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+// Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
// Author: Vignesh Raghavendra <vigneshr@ti.com>
#include <common.h>
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index d624589a892..bb9994b8626 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -447,6 +447,22 @@ config NAND_PXA3XX
This enables the driver for the NAND flash device found on
PXA3xx processors (NFCv1) and also on Armada 370/XP (NFCv2).
+config NAND_SANDBOX
+ bool "Support for NAND in sandbox"
+ depends on 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
+ help
+ Enable a dummy NAND driver for sandbox. It simulates any number of
+ arbitrary NAND chips with a RAM buffer. It will also inject errors to
+ test ECC. At the moment, only 8-bit busses and single-chip devices are
+ supported.
+
config NAND_SUNXI
bool "Support for NAND on Allwinner SoCs"
default ARCH_SUNXI
@@ -611,6 +627,14 @@ config ROCKCHIP_NAND
NFC v800: RK3308, RV1108
NFC v900: PX30, RK3326
+config ROCKCHIP_NAND_SKIP_BBTSCAN
+ bool "Skip the automatic BBT scan with Rockchip NAND controllers"
+ depends on ROCKCHIP_NAND
+ help
+ Skip the automatic BBT scan with the NAND_SKIP_BBTSCAN
+ option when data content is not in MTD format or
+ must remain unchanged.
+
config TEGRA_NAND
bool "Support for NAND controller on Tegra SoCs"
depends on ARCH_TEGRA
@@ -651,20 +675,13 @@ config SYS_NAND_ONFI_DETECTION
And fetching device parameters flashed on device, by parsing
ONFI parameter page.
-config SYS_NAND_PAGE_COUNT
- hex "NAND chip page count"
- depends on SPL_NAND_SUPPORT && (NAND_ATMEL || NAND_MXC || \
- SPL_NAND_AM33XX_BCH || SPL_NAND_LOAD || SPL_NAND_SIMPLE || \
- NAND_OMAP_GPMC)
- help
- Number of pages in the NAND chip.
-
config SYS_NAND_PAGE_SIZE
hex "NAND chip page size"
depends on ARCH_SUNXI || NAND_OMAP_GPMC || NAND_LPC32XX_SLC || \
SPL_NAND_SIMPLE || (NAND_MXC && SPL_NAND_SUPPORT) || \
MVEBU_SPL_BOOT_DEVICE_NAND || \
- (NAND_ATMEL && SPL_NAND_SUPPORT) || SPL_GENERATE_ATMEL_PMECC_HEADER
+ (NAND_ATMEL && SPL_NAND_SUPPORT) || \
+ SPL_GENERATE_ATMEL_PMECC_HEADER || NAND_SANDBOX
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
diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
index add2b4cf655..ddbba899e58 100644
--- a/drivers/mtd/nand/raw/Makefile
+++ b/drivers/mtd/nand/raw/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_NAND_PXA3XX) += pxa3xx_nand.o
obj-$(CONFIG_TEGRA_NAND) += tegra_nand.o
obj-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o
obj-$(CONFIG_NAND_OMAP_ELM) += omap_elm.o
+obj-$(CONFIG_NAND_SANDBOX) += sand_nand.o
obj-$(CONFIG_NAND_SUNXI) += sunxi_nand.o
obj-$(CONFIG_NAND_MXIC) += mxic_nand.o
obj-$(CONFIG_NAND_ZYNQ) += zynq_nand.o
diff --git a/drivers/mtd/nand/raw/am335x_spl_bch.c b/drivers/mtd/nand/raw/am335x_spl_bch.c
index 6ab3f1f42c5..6831af98b73 100644
--- a/drivers/mtd/nand/raw/am335x_spl_bch.c
+++ b/drivers/mtd/nand/raw/am335x_spl_bch.c
@@ -11,6 +11,7 @@
#include <common.h>
#include <nand.h>
+#include <system-constants.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/mtd/nand_ecc.h>
@@ -32,7 +33,7 @@ static int nand_command(int block, int page, uint32_t offs,
u8 cmd)
{
struct nand_chip *this = mtd_to_nand(mtd);
- int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
+ int page_addr = page + block * SYS_NAND_BLOCK_PAGES;
void (*hwctrl)(struct mtd_info *mtd, int cmd,
unsigned int ctrl) = this->cmd_ctrl;
@@ -217,6 +218,11 @@ void nand_init(void)
nand_command(0, 0, 0, NAND_CMD_RESET);
}
+unsigned int nand_page_size(void)
+{
+ return nand_to_mtd(&nand_chip)->writesize;
+}
+
/* Unselect after operation */
void nand_deselect(void)
{
diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c
index fa962ba591c..a2151f98491 100644
--- a/drivers/mtd/nand/raw/atmel/nand-controller.c
+++ b/drivers/mtd/nand/raw/atmel/nand-controller.c
@@ -64,6 +64,7 @@
#include <linux/mfd/syscon/atmel-smc.h>
#include <linux/mtd/rawnand.h>
#include <linux/mtd/mtd.h>
+#include <linux/time.h>
#include <mach/at91_sfr.h>
#include <nand.h>
#include <regmap.h>
@@ -71,8 +72,6 @@
#include "pmecc.h"
-#define NSEC_PER_SEC 1000000000L
-
#define ATMEL_HSMC_NFC_CFG 0x0
#define ATMEL_HSMC_NFC_CFG_SPARESIZE(x) (((x) / 4) << 24)
#define ATMEL_HSMC_NFC_CFG_SPARESIZE_MASK GENMASK(30, 24)
@@ -352,40 +351,6 @@ static int atmel_nfc_wait(struct atmel_hsmc_nand_controller *nc, bool poll,
return ret;
}
-static void iowrite8_rep(void *addr, const uint8_t *buf, int len)
-{
- int i;
-
- for (i = 0; i < len; i++)
- writeb(buf[i], addr);
-}
-
-static void ioread8_rep(void *addr, uint8_t *buf, int len)
-{
- int i;
-
- for (i = 0; i < len; i++)
- buf[i] = readb(addr);
-}
-
-static void ioread16_rep(void *addr, void *buf, int len)
-{
- int i;
- u16 *p = (u16 *)buf;
-
- for (i = 0; i < len; i++)
- p[i] = readw(addr);
-}
-
-static void iowrite16_rep(void *addr, const void *buf, int len)
-{
- int i;
- u16 *p = (u16 *)buf;
-
- for (i = 0; i < len; i++)
- writew(p[i], addr);
-}
-
static u8 atmel_nand_read_byte(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd_to_nand(mtd);
diff --git a/drivers/mtd/nand/raw/atmel_nand.c b/drivers/mtd/nand/raw/atmel_nand.c
index 6b17e744a69..6d94e7af38e 100644
--- a/drivers/mtd/nand/raw/atmel_nand.c
+++ b/drivers/mtd/nand/raw/atmel_nand.c
@@ -12,6 +12,7 @@
#include <common.h>
#include <log.h>
+#include <system-constants.h>
#include <asm/gpio.h>
#include <asm/arch/gpio.h>
#include <dm/device_compat.h>
@@ -1258,7 +1259,7 @@ static struct nand_chip nand_chip;
static int nand_command(int block, int page, uint32_t offs, u8 cmd)
{
struct nand_chip *this = mtd_to_nand(mtd);
- int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
+ int page_addr = page + block * SYS_NAND_BLOCK_PAGES;
void (*hwctrl)(struct mtd_info *mtd, int cmd,
unsigned int ctrl) = this->cmd_ctrl;
@@ -1359,7 +1360,7 @@ int spl_nand_erase_one(int block, int page)
if (nand_chip.select_chip)
nand_chip.select_chip(mtd, 0);
- page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
+ page_addr = page + block * SYS_NAND_BLOCK_PAGES;
hwctrl(mtd, NAND_CMD_ERASE1, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
/* Row address */
hwctrl(mtd, (page_addr & 0xff), NAND_CTRL_ALE | NAND_CTRL_CHANGE);
@@ -1451,6 +1452,11 @@ void nand_init(void)
nand_chip.select_chip(mtd, 0);
}
+unsigned int nand_page_size(void)
+{
+ return nand_to_mtd(&nand_chip)->writesize;
+}
+
void nand_deselect(void)
{
if (nand_chip.select_chip)
diff --git a/drivers/mtd/nand/raw/denali_spl.c b/drivers/mtd/nand/raw/denali_spl.c
index 690279c9976..165a23312cb 100644
--- a/drivers/mtd/nand/raw/denali_spl.c
+++ b/drivers/mtd/nand/raw/denali_spl.c
@@ -234,4 +234,9 @@ int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
return 0;
}
+unsigned int nand_page_size(void)
+{
+ return page_size;
+}
+
void nand_deselect(void) {}
diff --git a/drivers/mtd/nand/raw/fsl_ifc_spl.c b/drivers/mtd/nand/raw/fsl_ifc_spl.c
index c67065eaf8c..69d26f1f79a 100644
--- a/drivers/mtd/nand/raw/fsl_ifc_spl.c
+++ b/drivers/mtd/nand/raw/fsl_ifc_spl.c
@@ -106,6 +106,8 @@ static inline int bad_block(uchar *marker, int port_size)
return __raw_readw((u16 *)marker) != 0xffff;
}
+static int saved_page_size;
+
int nand_spl_load_image(uint32_t offs, unsigned int uboot_size, void *vdst)
{
struct fsl_ifc_fcm *gregs = (void *)CFG_SYS_IFC_ADDR;
@@ -150,6 +152,7 @@ int nand_spl_load_image(uint32_t offs, unsigned int uboot_size, void *vdst)
if (port_size == 8)
bad_marker = 5;
}
+ saved_page_size = page_size;
ver = ifc_in32(&gregs->ifc_rev);
if (ver >= FSL_IFC_V2_0_0)
@@ -302,6 +305,11 @@ void nand_init(void)
{
}
+unsigned int nand_page_size(void)
+{
+ return saved_page_size;
+}
+
void nand_deselect(void)
{
}
diff --git a/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c b/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c
index ac2e669d46b..f8ae216d56c 100644
--- a/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c
+++ b/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c
@@ -765,4 +765,9 @@ int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
return 0;
}
+unsigned int nand_page_size(void)
+{
+ return BYTES_PER_PAGE;
+}
+
#endif /* CONFIG_SPL_BUILD */
diff --git a/drivers/mtd/nand/raw/mt7621_nand_spl.c b/drivers/mtd/nand/raw/mt7621_nand_spl.c
index 114fc8b7cea..a2be9ba80e0 100644
--- a/drivers/mtd/nand/raw/mt7621_nand_spl.c
+++ b/drivers/mtd/nand/raw/mt7621_nand_spl.c
@@ -203,6 +203,11 @@ unsigned long nand_size(void)
return SZ_2G;
}
+unsigned int nand_page_size(void)
+{
+ return nfc_dev.nand.mtd.writesize;
+}
+
void nand_deselect(void)
{
}
diff --git a/drivers/mtd/nand/raw/mxc_nand_spl.c b/drivers/mtd/nand/raw/mxc_nand_spl.c
index 309e75d01e5..a855c9987f8 100644
--- a/drivers/mtd/nand/raw/mxc_nand_spl.c
+++ b/drivers/mtd/nand/raw/mxc_nand_spl.c
@@ -13,6 +13,7 @@
#include <common.h>
#include <hang.h>
#include <nand.h>
+#include <system-constants.h>
#include <linux/mtd/rawnand.h>
#include <asm/arch/imx-regs.h>
#include <asm/io.h>
@@ -304,13 +305,13 @@ int nand_spl_load_image(uint32_t from, unsigned int size, void *buf)
* Check if we have crossed a block boundary, and if so
* check for bad block.
*/
- if (!(page % CONFIG_SYS_NAND_PAGE_COUNT)) {
+ if (!(page % SYS_NAND_BLOCK_PAGES)) {
/*
* Yes, new block. See if this block is good. If not,
* loop until we find a good block.
*/
while (is_badblock(page)) {
- page = page + CONFIG_SYS_NAND_PAGE_COUNT;
+ page = page + SYS_NAND_BLOCK_PAGES;
/* Check i we've reached the end of flash. */
if (page >= maxpages)
return -1;
@@ -350,3 +351,8 @@ __used void nand_boot(void)
void nand_init(void) {}
void nand_deselect(void) {}
+
+unsigned int nand_page_size(void)
+{
+ return CONFIG_SYS_NAND_PAGE_SIZE;
+}
diff --git a/drivers/mtd/nand/raw/mxs_nand.c b/drivers/mtd/nand/raw/mxs_nand.c
index 65eab4c8088..fd65772af80 100644
--- a/drivers/mtd/nand/raw/mxs_nand.c
+++ b/drivers/mtd/nand/raw/mxs_nand.c
@@ -31,6 +31,7 @@
#include <linux/errno.h>
#include <linux/mtd/rawnand.h>
#include <linux/sizes.h>
+#include <linux/time.h>
#include <linux/types.h>
#include <linux/math64.h>
@@ -52,8 +53,6 @@
#endif
#define MXS_NAND_BCH_TIMEOUT 10000
-#define USEC_PER_SEC 1000000
-#define NSEC_PER_SEC 1000000000L
#define TO_CYCLES(duration, period) DIV_ROUND_UP_ULL(duration, period)
diff --git a/drivers/mtd/nand/raw/mxs_nand_spl.c b/drivers/mtd/nand/raw/mxs_nand_spl.c
index 300662994cf..f7d3f02f85a 100644
--- a/drivers/mtd/nand/raw/mxs_nand_spl.c
+++ b/drivers/mtd/nand/raw/mxs_nand_spl.c
@@ -295,6 +295,11 @@ int nand_default_bbt(struct mtd_info *mtd)
return 0;
}
+unsigned int nand_page_size(void)
+{
+ return nand_to_mtd(&nand_chip)->writesize;
+}
+
void nand_deselect(void)
{
}
diff --git a/drivers/mtd/nand/raw/nand.c b/drivers/mtd/nand/raw/nand.c
index eacd99c4e27..4c18861aa25 100644
--- a/drivers/mtd/nand/raw/nand.c
+++ b/drivers/mtd/nand/raw/nand.c
@@ -60,13 +60,11 @@ int nand_register(int devnum, struct mtd_info *mtd)
sprintf(dev_name[devnum], "nand%d", devnum);
mtd->name = dev_name[devnum];
-#ifdef CONFIG_MTD
/*
* Add MTD device so that we can reference it later
* via the mtdcore infrastructure (e.g. ubi).
*/
add_mtd_device(mtd);
-#endif
total_nand_size += mtd->size / 1024;
@@ -76,6 +74,23 @@ int nand_register(int devnum, struct mtd_info *mtd)
return 0;
}
+void nand_unregister(struct mtd_info *mtd)
+{
+ int devnum = nand_mtd_to_devnum(mtd);
+
+ if (devnum < 0)
+ return;
+
+ if (nand_curr_device == devnum)
+ nand_curr_device = -1;
+
+ total_nand_size -= mtd->size / 1024;
+
+ del_mtd_device(nand_info[devnum]);
+
+ nand_info[devnum] = NULL;
+}
+
#if !CONFIG_IS_ENABLED(SYS_NAND_SELF_INIT)
static void nand_init_chip(int i)
{
@@ -100,6 +115,8 @@ static void nand_init_chip(int i)
#endif
#ifdef CONFIG_MTD_CONCAT
+struct mtd_info *concat_mtd;
+
static void create_mtd_concat(void)
{
struct mtd_info *nand_info_list[CONFIG_SYS_MAX_NAND_DEVICE];
@@ -114,28 +131,40 @@ static void create_mtd_concat(void)
}
}
if (nand_devices_found > 1) {
- struct mtd_info *mtd;
char c_mtd_name[16];
/*
* We detected multiple devices. Concatenate them together.
*/
sprintf(c_mtd_name, "nand%d", nand_devices_found);
- mtd = mtd_concat_create(nand_info_list, nand_devices_found,
- c_mtd_name);
+ concat_mtd = mtd_concat_create(nand_info_list,
+ nand_devices_found, c_mtd_name);
- if (mtd == NULL)
+ if (!concat_mtd)
return;
- nand_register(nand_devices_found, mtd);
+ nand_register(nand_devices_found, concat_mtd);
}
return;
}
+
+static void destroy_mtd_concat(void)
+{
+ if (!concat_mtd)
+ return;
+
+ mtd_concat_destroy(concat_mtd);
+ concat_mtd = NULL;
+}
#else
static void create_mtd_concat(void)
{
}
+
+static void destroy_mtd_concat(void)
+{
+}
#endif
unsigned long nand_size(void)
@@ -143,10 +172,10 @@ unsigned long nand_size(void)
return total_nand_size;
}
+static int initialized;
+
void nand_init(void)
{
- static int initialized;
-
/*
* Avoid initializing NAND Flash multiple times,
* otherwise it will calculate a wrong total size.
@@ -174,3 +203,22 @@ void nand_init(void)
create_mtd_concat();
}
+
+void nand_reinit(void)
+{
+ int i;
+
+ destroy_mtd_concat();
+ for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
+ assert(!nand_info[i]);
+
+ initialized = 0;
+ nand_init();
+}
+
+unsigned int nand_page_size(void)
+{
+ struct mtd_info *mtd = get_nand_dev_by_index(nand_curr_device);
+
+ return mtd ? mtd->writesize : 1;
+}
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 6b4adcf6bdc..c40a0f23d7b 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -245,39 +245,6 @@ static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
chip->write_buf(mtd, (uint8_t *)&word, 2);
}
-static void iowrite8_rep(void *addr, const uint8_t *buf, int len)
-{
- int i;
-
- for (i = 0; i < len; i++)
- writeb(buf[i], addr);
-}
-static void ioread8_rep(void *addr, uint8_t *buf, int len)
-{
- int i;
-
- for (i = 0; i < len; i++)
- buf[i] = readb(addr);
-}
-
-static void ioread16_rep(void *addr, void *buf, int len)
-{
- int i;
- u16 *p = (u16 *) buf;
-
- for (i = 0; i < len; i++)
- p[i] = readw(addr);
-}
-
-static void iowrite16_rep(void *addr, void *buf, int len)
-{
- int i;
- u16 *p = (u16 *) buf;
-
- for (i = 0; i < len; i++)
- writew(p[i], addr);
-}
-
/**
* nand_write_buf - [DEFAULT] write buffer to chip
* @mtd: MTD device structure
@@ -4462,17 +4429,14 @@ ident_done:
else if (chip->jedec_version)
pr_info("%s %s\n", manufacturer_desc->name,
chip->jedec_params.model);
- else
+ else if (manufacturer_desc)
pr_info("%s %s\n", manufacturer_desc->name, type->name);
#else
if (chip->jedec_version)
pr_info("%s %s\n", manufacturer_desc->name,
chip->jedec_params.model);
- else
+ else if (manufacturer_desc)
pr_info("%s %s\n", manufacturer_desc->name, type->name);
-
- pr_info("%s %s\n", manufacturer_desc->name,
- type->name);
#endif
pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",
diff --git a/drivers/mtd/nand/raw/nand_spl_loaders.c b/drivers/mtd/nand/raw/nand_spl_loaders.c
index 156b44d8358..db4213ea3dc 100644
--- a/drivers/mtd/nand/raw/nand_spl_loaders.c
+++ b/drivers/mtd/nand/raw/nand_spl_loaders.c
@@ -12,8 +12,11 @@ int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
while (block <= lastblock) {
if (!nand_is_bad_block(block)) {
/* Skip bad blocks */
- while (page < CONFIG_SYS_NAND_PAGE_COUNT) {
+ while (size && page < SYS_NAND_BLOCK_PAGES) {
nand_read_page(block, page, dst);
+
+ size -= min(size, CONFIG_SYS_NAND_PAGE_SIZE -
+ page_offset);
/*
* When offs is not aligned to page address the
* extra offset is copied to dst as well. Copy
diff --git a/drivers/mtd/nand/raw/nand_spl_simple.c b/drivers/mtd/nand/raw/nand_spl_simple.c
index 2f3af9edd4c..80d6e0e1e4e 100644
--- a/drivers/mtd/nand/raw/nand_spl_simple.c
+++ b/drivers/mtd/nand/raw/nand_spl_simple.c
@@ -6,6 +6,7 @@
#include <common.h>
#include <nand.h>
+#include <system-constants.h>
#include <asm/io.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/rawnand.h>
@@ -27,7 +28,7 @@ static int nand_command(int block, int page, uint32_t offs,
u8 cmd)
{
struct nand_chip *this = mtd_to_nand(mtd);
- int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
+ int page_addr = page + block * SYS_NAND_BLOCK_PAGES;
while (!this->dev_ready(mtd))
;
@@ -59,7 +60,7 @@ static int nand_command(int block, int page, uint32_t offs,
u8 cmd)
{
struct nand_chip *this = mtd_to_nand(mtd);
- int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
+ int page_addr = page + block * SYS_NAND_BLOCK_PAGES;
void (*hwctrl)(struct mtd_info *mtd, int cmd,
unsigned int ctrl) = this->cmd_ctrl;
@@ -226,6 +227,11 @@ void nand_init(void)
nand_chip.select_chip(mtd, 0);
}
+unsigned int nand_page_size(void)
+{
+ return nand_to_mtd(&nand_chip)->writesize;
+}
+
/* Unselect after operation */
void nand_deselect(void)
{
diff --git a/drivers/mtd/nand/raw/octeontx_nand.c b/drivers/mtd/nand/raw/octeontx_nand.c
index 65a03d22c1d..3b20685fac0 100644
--- a/drivers/mtd/nand/raw/octeontx_nand.c
+++ b/drivers/mtd/nand/raw/octeontx_nand.c
@@ -24,6 +24,7 @@
#include <linux/mtd/nand_bch.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/rawnand.h>
+#include <linux/time.h>
#include <asm/global_data.h>
#include <asm/io.h>
#include <asm/types.h>
@@ -291,7 +292,6 @@ union ndf_cmd {
#define OCTEONTX_NAND_DRIVER_NAME "octeontx_nand"
#define NDF_TIMEOUT 1000 /** Timeout in ms */
-#define USEC_PER_SEC 1000000 /** Linux compatibility */
#ifndef NAND_MAX_CHIPS
# define NAND_MAX_CHIPS 8 /** Linux compatibility */
#endif
diff --git a/drivers/mtd/nand/raw/omap_gpmc.c b/drivers/mtd/nand/raw/omap_gpmc.c
index 1a5ed0de31a..0e25bd5dc28 100644
--- a/drivers/mtd/nand/raw/omap_gpmc.c
+++ b/drivers/mtd/nand/raw/omap_gpmc.c
@@ -6,6 +6,7 @@
#include <common.h>
#include <log.h>
+#include <system-constants.h>
#include <asm/io.h>
#include <dm/uclass.h>
#include <linux/errno.h>
@@ -1298,7 +1299,7 @@ static int nand_is_bad_block(int block)
static int nand_read_page(int block, int page, uchar *dst)
{
- int page_addr = block * CONFIG_SYS_NAND_PAGE_COUNT + page;
+ int page_addr = block * SYS_NAND_BLOCK_PAGES + page;
loff_t ofs = page_addr * CONFIG_SYS_NAND_PAGE_SIZE;
int ret;
size_t len = CONFIG_SYS_NAND_PAGE_SIZE;
diff --git a/drivers/mtd/nand/raw/rockchip_nfc.c b/drivers/mtd/nand/raw/rockchip_nfc.c
index 274489ecbc6..088cc7fead2 100644
--- a/drivers/mtd/nand/raw/rockchip_nfc.c
+++ b/drivers/mtd/nand/raw/rockchip_nfc.c
@@ -955,6 +955,9 @@ static int rk_nfc_nand_chip_init(ofnode node, struct rk_nfc *nfc, int devnum)
chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER;
+ if (IS_ENABLED(CONFIG_ROCKCHIP_NAND_SKIP_BBTSCAN))
+ chip->options |= NAND_SKIP_BBTSCAN;
+
rk_nfc_hw_init(nfc);
ret = nand_scan_ident(mtd, nsels, NULL);
if (ret)
diff --git a/drivers/mtd/nand/raw/sand_nand.c b/drivers/mtd/nand/raw/sand_nand.c
new file mode 100644
index 00000000000..229d7b5b65a
--- /dev/null
+++ b/drivers/mtd/nand/raw/sand_nand.c
@@ -0,0 +1,707 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) Sean Anderson <seanga2@gmail.com>
+ */
+
+#define LOG_CATEGORY UCLASS_MTD
+#include <errno.h>
+#include <hexdump.h>
+#include <log.h>
+#include <nand.h>
+#include <os.h>
+#include <rand.h>
+#include <spl.h>
+#include <system-constants.h>
+#include <dm/device_compat.h>
+#include <dm/read.h>
+#include <dm/uclass.h>
+#include <asm/bitops.h>
+#include <linux/bitmap.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/sizes.h>
+
+enum sand_nand_state {
+ STATE_READY,
+ STATE_IDLE,
+ STATE_READ,
+ STATE_READ_ID,
+ STATE_READ_ONFI,
+ STATE_PARAM_ONFI,
+ STATE_STATUS,
+ STATE_PROG,
+ STATE_ERASE,
+};
+
+static const char *const state_name[] = {
+ [STATE_READY] = "READY",
+ [STATE_IDLE] = "IDLE",
+ [STATE_READ] = "READ",
+ [STATE_READ_ID] = "READ_ID",
+ [STATE_READ_ONFI] = "READ_ONFI",
+ [STATE_PARAM_ONFI] = "PARAM_ONFI",
+ [STATE_STATUS] = "STATUS",
+ [STATE_PROG] = "PROG",
+ [STATE_ERASE] = "ERASE",
+};
+
+/**
+ * struct sand_nand_chip - Per-device private data
+ * @nand: The nand chip
+ * @node: The next device in this controller
+ * @programmed: Bitmap of whether sectors are programmed
+ * @id: ID to report for NAND_CMD_READID
+ * @id_len: Length of @id
+ * @onfi: Three copies of ONFI parameter page
+ * @status: Status to report for NAND_CMD_STATUS
+ * @chunksize: Size of one "chunk" (page + oob) in bytes
+ * @pageize: Size of one page in bytes
+ * @pages: Total number of pages
+ * @pages_per_erase: Number of pages per eraseblock
+ * @err_count: Number of errors to inject per @err_step_bits of data
+ * @err_step_bits: Number of data bits per error "step"
+ * @err_steps: Number of err steps in a page
+ * @cs: Chip select for this device
+ * @state: Current state of the device
+ * @column: Column of the most-recent command
+ * @page_addr: Page address of the most-recent command
+ * @fd: File descriptor for the backing data
+ * @fd_page_addr: Page address that @fd is seek'd to
+ * @selected: Whether this device is selected
+ * @tmp: "Cache" buffer used to store transferred data before committing it
+ * @tmp_dirty: Whether @tmp is dirty (modified) or clean (all ones)
+ *
+ * Data is stored with the OOB area in-line. For example, with 512-byte pages
+ * and and 16-byte OOB areas, the first page would start at offset 0, the second
+ * at offset 528, the third at offset 1056, and so on
+ */
+struct sand_nand_chip {
+ struct nand_chip nand;
+ struct list_head node;
+ long *programmed;
+ const u8 *id;
+ u32 chunksize, pagesize, pages, pages_per_erase;
+ u32 err_count, err_step_bits, err_steps, ecc_bits;
+ unsigned int cs;
+ enum sand_nand_state state;
+ int column, page_addr, fd, fd_page_addr;
+ bool selected, tmp_dirty;
+ u8 status;
+ u8 id_len;
+ u8 tmp[NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE];
+ u8 onfi[sizeof(struct nand_onfi_params) * 3];
+};
+
+#define SAND_DEBUG(chip, fmt, ...) \
+ dev_dbg((chip)->nand.mtd.dev, "%u (%s): " fmt, (chip)->cs, \
+ state_name[(chip)->state], ##__VA_ARGS__)
+
+static inline void to_state(struct sand_nand_chip *chip,
+ enum sand_nand_state new_state)
+{
+ if (new_state != chip->state)
+ SAND_DEBUG(chip, "to state %s\n", state_name[new_state]);
+ chip->state = new_state;
+}
+
+static inline struct sand_nand_chip *to_sand_nand(struct nand_chip *nand)
+{
+ return container_of(nand, struct sand_nand_chip, nand);
+}
+
+struct sand_nand_priv {
+ struct list_head chips;
+};
+
+static int sand_nand_dev_ready(struct mtd_info *mtd)
+{
+ return 1;
+}
+
+static int sand_nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
+{
+ u8 status;
+
+ return nand_status_op(chip, &status) ?: status;
+}
+
+static int sand_nand_seek(struct sand_nand_chip *chip)
+{
+ if (chip->fd_page_addr == chip->page_addr)
+ return 0;
+
+ if (os_lseek(chip->fd, (off_t)chip->page_addr * chip->chunksize,
+ OS_SEEK_SET) < 0) {
+ SAND_DEBUG(chip, "could not seek: %d\n", errno);
+ return -EIO;
+ }
+
+ chip->fd_page_addr = chip->page_addr;
+ return 0;
+}
+
+static void sand_nand_inject_error(struct sand_nand_chip *chip,
+ unsigned int step, unsigned int pos)
+{
+ int byte, index;
+
+ if (pos < chip->err_step_bits) {
+ __change_bit(step * chip->err_step_bits + pos, chip->tmp);
+ return;
+ }
+
+ /*
+ * Only ECC bytes are covered in the OOB area, so
+ * pretend that those are the only bytes which can have
+ * errors.
+ */
+ byte = (pos - chip->err_step_bits + step * chip->ecc_bits) / 8;
+ index = chip->nand.ecc.layout->eccpos[byte];
+ /* Avoid endianness issues by working with bytes */
+ chip->tmp[chip->pagesize + index] ^= BIT(pos & 0x7);
+}
+
+static int sand_nand_read(struct sand_nand_chip *chip)
+{
+ unsigned int i, stop = 0;
+
+ if (chip->column == chip->pagesize)
+ stop = chip->err_step_bits;
+
+ if (test_bit(chip->page_addr, chip->programmed)) {
+ if (sand_nand_seek(chip))
+ return -EIO;
+
+ if (os_read(chip->fd, chip->tmp, chip->chunksize) !=
+ chip->chunksize) {
+ SAND_DEBUG(chip, "could not read: %d\n", errno);
+ return -EIO;
+ }
+ chip->fd_page_addr++;
+ } else if (chip->tmp_dirty) {
+ memset(chip->tmp + chip->column, 0xff,
+ chip->chunksize - chip->column);
+ }
+
+ /*
+ * Inject some errors; this is Method A from "An Efficient Algorithm for
+ * Sequential Random Sampling" (Vitter 87). This is still slow when
+ * generating a lot (dozens) of ECC errors.
+ *
+ * To avoid generating too many errors in any one ECC step, we separate
+ * our error generation by ECC step.
+ */
+ chip->tmp_dirty = true;
+ for (i = 0; i < chip->err_steps; i++) {
+ u32 bit_errors = chip->err_count;
+ unsigned int j = chip->err_step_bits + chip->ecc_bits;
+
+ while (bit_errors) {
+ unsigned int u = rand();
+ float quot = 1ULL << 32;
+
+ do {
+ quot *= j - bit_errors;
+ quot /= j;
+ j--;
+
+ if (j < stop)
+ goto next;
+ } while (u < quot);
+
+ sand_nand_inject_error(chip, i, j);
+ bit_errors--;
+ }
+next:
+ ;
+ }
+
+ return 0;
+}
+
+static void sand_nand_command(struct mtd_info *mtd, unsigned int command,
+ int column, int page_addr)
+{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct sand_nand_chip *chip = to_sand_nand(nand);
+ enum sand_nand_state new_state = chip->state;
+
+ SAND_DEBUG(chip, "command=%02x column=%d page_addr=%d\n", command,
+ column, page_addr);
+
+ if (!chip->selected)
+ return;
+
+ switch (chip->state) {
+ case STATE_READY:
+ if (command == NAND_CMD_RESET)
+ goto reset;
+ break;
+ case STATE_PROG:
+ new_state = STATE_IDLE;
+ if (command != NAND_CMD_PAGEPROG ||
+ test_and_set_bit(chip->page_addr, chip->programmed)) {
+ chip->status |= NAND_STATUS_FAIL;
+ break;
+ }
+
+ if (sand_nand_seek(chip)) {
+ chip->status |= NAND_STATUS_FAIL;
+ break;
+ }
+
+ if (os_write(chip->fd, chip->tmp, chip->chunksize) !=
+ chip->chunksize) {
+ SAND_DEBUG(chip, "could not write: %d\n", errno);
+ chip->status |= NAND_STATUS_FAIL;
+ break;
+ }
+
+ chip->fd_page_addr++;
+ break;
+ case STATE_ERASE:
+ new_state = STATE_IDLE;
+ if (command != NAND_CMD_ERASE2) {
+ chip->status |= NAND_STATUS_FAIL;
+ break;
+ }
+
+ if (chip->page_addr < 0 ||
+ chip->page_addr >= chip->pages ||
+ chip->page_addr % chip->pages_per_erase)
+ chip->status |= NAND_STATUS_FAIL;
+ else
+ bitmap_clear(chip->programmed, chip->page_addr,
+ chip->pages_per_erase);
+ break;
+ default:
+ chip->column = column;
+ chip->page_addr = page_addr;
+ switch (command) {
+ case NAND_CMD_READOOB:
+ if (column >= 0)
+ chip->column += chip->pagesize;
+ fallthrough;
+ case NAND_CMD_READ0:
+ new_state = STATE_IDLE;
+ if (page_addr < 0 || page_addr >= chip->pages)
+ break;
+
+ if (chip->column < 0 || chip->column >= chip->chunksize)
+ break;
+
+ if (sand_nand_read(chip))
+ break;
+
+ chip->page_addr = page_addr;
+ new_state = STATE_READ;
+ break;
+ case NAND_CMD_ERASE1:
+ new_state = STATE_ERASE;
+ chip->status = ~NAND_STATUS_FAIL;
+ break;
+ case NAND_CMD_STATUS:
+ new_state = STATE_STATUS;
+ chip->column = 0;
+ break;
+ case NAND_CMD_SEQIN:
+ new_state = STATE_PROG;
+ chip->status = ~NAND_STATUS_FAIL;
+ if (page_addr < 0 || page_addr >= chip->pages ||
+ chip->column < 0 ||
+ chip->column >= chip->chunksize) {
+ chip->status |= NAND_STATUS_FAIL;
+ } else if (chip->tmp_dirty) {
+ memset(chip->tmp, 0xff, chip->chunksize);
+ chip->tmp_dirty = false;
+ }
+ break;
+ case NAND_CMD_READID:
+ if (chip->onfi[0] && column == 0x20)
+ new_state = STATE_READ_ONFI;
+ else
+ new_state = STATE_READ_ID;
+ chip->column = 0;
+ break;
+ case NAND_CMD_PARAM:
+ if (chip->onfi[0] && !column)
+ new_state = STATE_PARAM_ONFI;
+ else
+ new_state = STATE_IDLE;
+ break;
+ case NAND_CMD_RESET:
+reset:
+ new_state = STATE_IDLE;
+ chip->column = -1;
+ chip->page_addr = -1;
+ chip->status = ~NAND_STATUS_FAIL;
+ break;
+ default:
+ new_state = STATE_IDLE;
+ SAND_DEBUG(chip, "Unsupported command %02x\n", command);
+ }
+ }
+
+ to_state(chip, new_state);
+}
+
+static void sand_nand_select_chip(struct mtd_info *mtd, int n)
+{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct sand_nand_chip *chip = to_sand_nand(nand);
+
+ chip->selected = !n;
+}
+
+static void sand_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct sand_nand_chip *chip = to_sand_nand(nand);
+ unsigned int to_copy;
+ int src_len = 0;
+ const u8 *src = NULL;
+
+ if (!chip->selected)
+ goto copy;
+
+ switch (chip->state) {
+ case STATE_READ:
+ src = chip->tmp;
+ src_len = chip->chunksize;
+ break;
+ case STATE_READ_ID:
+ src = chip->id;
+ src_len = chip->id_len;
+ break;
+ case STATE_READ_ONFI:
+ src = "ONFI";
+ src_len = 4;
+ break;
+ case STATE_PARAM_ONFI:
+ src = chip->onfi;
+ src_len = sizeof(chip->onfi);
+ break;
+ case STATE_STATUS:
+ src = &chip->status;
+ src_len = 1;
+ break;
+ default:
+ break;
+ }
+
+copy:
+ if (chip->column >= 0)
+ to_copy = max(min(len, src_len - chip->column), 0);
+ else
+ to_copy = 0;
+ memcpy(buf, src + chip->column, to_copy);
+ memset(buf + to_copy, 0xff, len - to_copy);
+ chip->column += to_copy;
+
+ if (len == 1) {
+ SAND_DEBUG(chip, "read [ %02x ]\n", buf[0]);
+ } else if (src_len) {
+ SAND_DEBUG(chip, "read %d bytes\n", len);
+#ifdef VERBOSE_DEBUG
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len);
+#endif
+ }
+
+ if (src_len && chip->column == src_len)
+ to_state(chip, STATE_IDLE);
+}
+
+static u8 sand_nand_read_byte(struct mtd_info *mtd)
+{
+ u8 ret;
+
+ sand_nand_read_buf(mtd, &ret, 1);
+ return ret;
+}
+
+static u16 sand_nand_read_word(struct mtd_info *mtd)
+{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct sand_nand_chip *chip = to_sand_nand(nand);
+
+ SAND_DEBUG(chip, "16-bit access unsupported\n");
+ return sand_nand_read_byte(mtd) | 0xff00;
+}
+
+static void sand_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+ struct nand_chip *nand = mtd_to_nand(mtd);
+ struct sand_nand_chip *chip = to_sand_nand(nand);
+
+ SAND_DEBUG(chip, "write %d bytes\n", len);
+#ifdef VERBOSE_DEBUG
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len);
+#endif
+
+ if (chip->state != STATE_PROG || chip->status & NAND_STATUS_FAIL)
+ return;
+
+ chip->tmp_dirty = true;
+ len = min((unsigned int)len, chip->chunksize - chip->column);
+ memcpy(chip->tmp + chip->column, buf, len);
+ chip->column += len;
+}
+
+static struct nand_chip *nand_chip;
+
+int sand_nand_remove(struct udevice *dev)
+{
+ struct sand_nand_priv *priv = dev_get_priv(dev);
+ struct sand_nand_chip *chip;
+
+ list_for_each_entry(chip, &priv->chips, node) {
+ struct nand_chip *nand = &chip->nand;
+
+ if (nand_chip == nand)
+ nand_chip = NULL;
+
+ nand_unregister(nand_to_mtd(nand));
+ free(chip->programmed);
+ os_close(chip->fd);
+ free(chip);
+ }
+
+ return 0;
+}
+
+static int sand_nand_probe(struct udevice *dev)
+{
+ struct sand_nand_priv *priv = dev_get_priv(dev);
+ struct sand_nand_chip *chip;
+ int ret, devnum = 0;
+ ofnode np;
+
+ INIT_LIST_HEAD(&priv->chips);
+
+ dev_for_each_subnode(np, dev) {
+ struct nand_chip *nand;
+ struct mtd_info *mtd;
+ u32 erasesize, oobsize, pagesize, pages;
+ u32 err_count, err_step_size;
+ off_t expected_size;
+ char filename[30];
+ fdt_addr_t cs;
+ const u8 *id, *onfi;
+ int id_len, onfi_len;
+
+ cs = ofnode_get_addr_size_index_notrans(np, 0, NULL);
+ if (cs == FDT_ADDR_T_NONE) {
+ dev_dbg(dev, "Invalid cs for chip %s\n",
+ ofnode_get_name(np));
+ ret = -ENOENT;
+ goto err;
+ }
+
+ id = ofnode_read_prop(np, "sandbox,id", &id_len);
+ if (!id) {
+ dev_dbg(dev, "No sandbox,id property for chip %s\n",
+ ofnode_get_name(np));
+ ret = -EINVAL;
+ goto err;
+ }
+
+ onfi = ofnode_read_prop(np, "sandbox,onfi", &onfi_len);
+ if (onfi && onfi_len != sizeof(struct nand_onfi_params)) {
+ dev_dbg(dev, "Invalid length %d for onfi params\n",
+ onfi_len);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = ofnode_read_u32(np, "sandbox,erasesize", &erasesize);
+ if (ret) {
+ dev_dbg(dev, "No sandbox,erasesize property for chip %s",
+ ofnode_get_name(np));
+ goto err;
+ }
+
+ ret = ofnode_read_u32(np, "sandbox,oobsize", &oobsize);
+ if (ret) {
+ dev_dbg(dev, "No sandbox,oobsize property for chip %s",
+ ofnode_get_name(np));
+ goto err;
+ }
+
+ ret = ofnode_read_u32(np, "sandbox,pagesize", &pagesize);
+ if (ret) {
+ dev_dbg(dev, "No sandbox,pagesize property for chip %s",
+ ofnode_get_name(np));
+ goto err;
+ }
+
+ ret = ofnode_read_u32(np, "sandbox,pages", &pages);
+ if (ret) {
+ dev_dbg(dev, "No sandbox,pages property for chip %s",
+ ofnode_get_name(np));
+ goto err;
+ }
+
+ ret = ofnode_read_u32(np, "sandbox,err-count", &err_count);
+ if (ret) {
+ dev_dbg(dev,
+ "No sandbox,err-count property for chip %s",
+ ofnode_get_name(np));
+ goto err;
+ }
+
+ ret = ofnode_read_u32(np, "sandbox,err-step-size",
+ &err_step_size);
+ if (ret) {
+ dev_dbg(dev,
+ "No sandbox,err-step-size property for chip %s",
+ ofnode_get_name(np));
+ goto err;
+ }
+
+ chip = calloc(sizeof(*chip), 1);
+ if (!chip) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ chip->cs = cs;
+ chip->id = id;
+ chip->id_len = id_len;
+ chip->chunksize = pagesize + oobsize;
+ chip->pagesize = pagesize;
+ chip->pages = pages;
+ chip->pages_per_erase = erasesize / pagesize;
+ memset(chip->tmp, 0xff, chip->chunksize);
+
+ chip->err_count = err_count;
+ chip->err_step_bits = err_step_size * 8;
+ chip->err_steps = pagesize / err_step_size;
+
+ expected_size = (off_t)pages * chip->chunksize;
+ snprintf(filename, sizeof(filename),
+ "/tmp/u-boot.nand%d.XXXXXX", devnum);
+ chip->fd = os_mktemp(filename, expected_size);
+ if (chip->fd < 0) {
+ dev_dbg(dev, "Could not create temp file %s\n",
+ filename);
+ ret = chip->fd;
+ goto err_chip;
+ }
+
+ chip->programmed = calloc(sizeof(long),
+ BITS_TO_LONGS(pages));
+ if (!chip->programmed) {
+ ret = -ENOMEM;
+ goto err_fd;
+ }
+
+ if (onfi) {
+ memcpy(chip->onfi, onfi, onfi_len);
+ memcpy(chip->onfi + onfi_len, onfi, onfi_len);
+ memcpy(chip->onfi + 2 * onfi_len, onfi, onfi_len);
+ }
+
+ nand = &chip->nand;
+ nand->options = spl_in_proper() ? 0 : NAND_SKIP_BBTSCAN;
+ nand->flash_node = np;
+ nand->dev_ready = sand_nand_dev_ready;
+ nand->cmdfunc = sand_nand_command;
+ nand->waitfunc = sand_nand_wait;
+ nand->select_chip = sand_nand_select_chip;
+ nand->read_byte = sand_nand_read_byte;
+ nand->read_word = sand_nand_read_word;
+ nand->read_buf = sand_nand_read_buf;
+ nand->write_buf = sand_nand_write_buf;
+ nand->ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
+
+ mtd = nand_to_mtd(nand);
+ mtd->dev = dev;
+
+ ret = nand_scan(mtd, CONFIG_SYS_NAND_MAX_CHIPS);
+ if (ret) {
+ dev_dbg(dev, "Could not scan chip %s: %d\n",
+ ofnode_get_name(np), ret);
+ goto err_prog;
+ }
+ chip->ecc_bits = nand->ecc.layout->eccbytes * 8 /
+ chip->err_steps;
+
+ ret = nand_register(devnum, mtd);
+ if (ret) {
+ dev_dbg(dev, "Could not register nand %d: %d\n", devnum,
+ ret);
+ goto err_prog;
+ }
+
+ if (!nand_chip)
+ nand_chip = nand;
+
+ list_add_tail(&chip->node, &priv->chips);
+ devnum++;
+ continue;
+
+err_prog:
+ free(chip->programmed);
+err_fd:
+ os_close(chip->fd);
+err_chip:
+ free(chip);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ sand_nand_remove(dev);
+ return ret;
+}
+
+static const struct udevice_id sand_nand_ids[] = {
+ { .compatible = "sandbox,nand" },
+ { }
+};
+
+U_BOOT_DRIVER(sand_nand) = {
+ .name = "sand-nand",
+ .id = UCLASS_MTD,
+ .of_match = sand_nand_ids,
+ .probe = sand_nand_probe,
+ .remove = sand_nand_remove,
+ .priv_auto = sizeof(struct sand_nand_priv),
+};
+
+void board_nand_init(void)
+{
+ struct udevice *dev;
+ int err;
+
+ err = uclass_get_device_by_driver(UCLASS_MTD, DM_DRIVER_REF(sand_nand),
+ &dev);
+ if (err && err != -ENODEV)
+ log_info("Failed to get sandbox NAND: %d\n", err);
+}
+
+#if IS_ENABLED(CONFIG_SPL_BUILD) && IS_ENABLED(CONFIG_SPL_NAND_INIT)
+void nand_deselect(void)
+{
+ nand_chip->select_chip(nand_to_mtd(nand_chip), -1);
+}
+
+static int nand_is_bad_block(int block)
+{
+ struct mtd_info *mtd = nand_to_mtd(nand_chip);
+
+ return mtd_block_isbad(mtd, block << mtd->erasesize_shift);
+}
+
+static int nand_read_page(int block, int page, uchar *dst)
+{
+ struct mtd_info *mtd = nand_to_mtd(nand_chip);
+ loff_t ofs = ((loff_t)block << mtd->erasesize_shift) +
+ ((loff_t)page << mtd->writesize_shift);
+ size_t len = mtd->writesize;
+
+ return nand_read(mtd, ofs, &len, dst);
+}
+
+#include "nand_spl_loaders.c"
+#endif /* CONFIG_SPL_NAND_INIT */
diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c
index 64be6486b4e..3528824575b 100644
--- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c
+++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c
@@ -22,6 +22,7 @@
#include <linux/ioport.h>
#include <linux/mtd/rawnand.h>
#include <linux/printk.h>
+#include <linux/time.h>
/* Bad block marker length */
#define FMC2_BBM_LEN 2
@@ -127,8 +128,6 @@
#define FMC2_BCHDSR4_EBP7 GENMASK(12, 0)
#define FMC2_BCHDSR4_EBP8 GENMASK(28, 16)
-#define FMC2_NSEC_PER_SEC 1000000000L
-
#define FMC2_TIMEOUT_5S 5000000
enum stm32_fmc2_ecc {
@@ -603,7 +602,7 @@ static void stm32_fmc2_nfc_calc_timings(struct nand_chip *chip,
struct stm32_fmc2_nand *nand = to_fmc2_nand(chip);
struct stm32_fmc2_timings *tims = &nand->timings;
unsigned long hclk = clk_get_rate(&nfc->clk);
- unsigned long hclkp = FMC2_NSEC_PER_SEC / (hclk / 1000);
+ unsigned long hclkp = NSEC_PER_SEC / (hclk / 1000);
unsigned long timing, tar, tclr, thiz, twait;
unsigned long tset_mem, tset_att, thold_mem, thold_att;
diff --git a/drivers/mtd/nand/raw/sunxi_nand_spl.c b/drivers/mtd/nand/raw/sunxi_nand_spl.c
index 6de0b0a3554..c9b8c78ed75 100644
--- a/drivers/mtd/nand/raw/sunxi_nand_spl.c
+++ b/drivers/mtd/nand/raw/sunxi_nand_spl.c
@@ -524,9 +524,10 @@ static int nand_read_buffer(struct nfc_config *conf, uint32_t offs,
return 0;
}
+static struct nfc_config conf;
+
int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest)
{
- static struct nfc_config conf = { };
int ret;
ret = nand_detect_config(&conf, offs, dest);
@@ -536,6 +537,11 @@ int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest)
return nand_read_buffer(&conf, offs, size, dest);
}
+unsigned int nand_page_size(void)
+{
+ return conf.page_size;
+}
+
void nand_deselect(void)
{
struct sunxi_ccm_reg *const ccm =
diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
index 6c65b187e86..3051de4f7ef 100644
--- a/drivers/mtd/nand/spi/Makefile
+++ b/drivers/mtd/nand/spi/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
-spinand-objs := core.o gigadevice.o macronix.o micron.o toshiba.o winbond.o
+spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 4ee11e812d8..597b088ca7e 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -17,6 +17,7 @@
#include <linux/mtd/spinand.h>
#include <linux/of.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
#else
@@ -326,6 +327,13 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand,
u16 column = 0;
int ret;
+ /*
+ * Looks like PROGRAM LOAD (AKA write cache) does not necessarily reset
+ * the cache content to 0xFF (depends on vendor implementation), so we
+ * 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.
+ */
memset(spinand->databuf, 0xff,
nanddev_page_size(nand) +
nanddev_per_page_oobsize(nand));
@@ -452,9 +460,11 @@ out:
return status & STATUS_BUSY ? -ETIMEDOUT : 0;
}
-static int spinand_read_id_op(struct spinand_device *spinand, u8 *buf)
+static int spinand_read_id_op(struct spinand_device *spinand, u8 naddr,
+ u8 ndummy, u8 *buf)
{
- struct spi_mem_op op = SPINAND_READID_OP(0, spinand->scratchbuf,
+ struct spi_mem_op op = SPINAND_READID_OP(naddr, ndummy,
+ spinand->scratchbuf,
SPINAND_MAX_ID_LEN);
int ret;
@@ -596,12 +606,12 @@ static int spinand_mtd_read(struct mtd_info *mtd, loff_t from,
if (ret == -EBADMSG) {
ecc_failed = true;
mtd->ecc_stats.failed++;
- ret = 0;
} else {
mtd->ecc_stats.corrected += ret;
max_bitflips = max_t(unsigned int, max_bitflips, ret);
}
+ ret = 0;
ops->retlen += iter.req.datalen;
ops->oobretlen += iter.req.ooblen;
}
@@ -667,16 +677,9 @@ static bool spinand_isbad(struct nand_device *nand, const struct nand_pos *pos)
.oobbuf.in = marker,
.mode = MTD_OPS_RAW,
};
- int ret;
-
- ret = spinand_select_target(spinand, pos->target);
- if (ret)
- return ret;
-
- ret = spinand_read_page(spinand, &req, false);
- if (ret)
- return ret;
+ spinand_select_target(spinand, pos->target);
+ spinand_read_page(spinand, &req, false);
if (marker[0] != 0xff || marker[1] != 0xff)
return true;
@@ -720,6 +723,10 @@ 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;
+
return spinand_write_page(spinand, &req);
}
@@ -808,21 +815,6 @@ static int spinand_mtd_block_isreserved(struct mtd_info *mtd, loff_t offs)
return ret;
}
-const struct spi_mem_op *
-spinand_find_supported_op(struct spinand_device *spinand,
- const struct spi_mem_op *ops,
- unsigned int nops)
-{
- unsigned int i;
-
- for (i = 0; i < nops; i++) {
- if (spi_mem_supports_op(spinand->slave, &ops[i]))
- return &ops[i];
- }
-
- return NULL;
-}
-
static const struct nand_ops spinand_ops = {
.erase = spinand_erase,
.markbad = spinand_markbad,
@@ -833,28 +825,67 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
&gigadevice_spinand_manufacturer,
&macronix_spinand_manufacturer,
&micron_spinand_manufacturer,
+ &paragon_spinand_manufacturer,
&toshiba_spinand_manufacturer,
&winbond_spinand_manufacturer,
};
-static int spinand_manufacturer_detect(struct spinand_device *spinand)
+static int spinand_manufacturer_match(struct spinand_device *spinand,
+ enum spinand_readid_method rdid_method)
{
+ u8 *id = spinand->id.data;
unsigned int i;
int ret;
for (i = 0; i < ARRAY_SIZE(spinand_manufacturers); i++) {
- ret = spinand_manufacturers[i]->ops->detect(spinand);
- if (ret > 0) {
- spinand->manufacturer = spinand_manufacturers[i];
- return 0;
- } else if (ret < 0) {
- return ret;
- }
- }
+ const struct spinand_manufacturer *manufacturer =
+ spinand_manufacturers[i];
+
+ if (id[0] != manufacturer->id)
+ continue;
+
+ ret = spinand_match_and_init(spinand,
+ manufacturer->chips,
+ manufacturer->nchips,
+ rdid_method);
+ if (ret < 0)
+ continue;
+ spinand->manufacturer = manufacturer;
+ return 0;
+ }
return -ENOTSUPP;
}
+static int spinand_id_detect(struct spinand_device *spinand)
+{
+ u8 *id = spinand->id.data;
+ int ret;
+
+ ret = spinand_read_id_op(spinand, 0, 0, id);
+ if (ret)
+ return ret;
+ ret = spinand_manufacturer_match(spinand, SPINAND_READID_METHOD_OPCODE);
+ if (!ret)
+ return 0;
+
+ ret = spinand_read_id_op(spinand, 1, 0, id);
+ if (ret)
+ return ret;
+ ret = spinand_manufacturer_match(spinand,
+ SPINAND_READID_METHOD_OPCODE_ADDR);
+ if (!ret)
+ return 0;
+
+ ret = spinand_read_id_op(spinand, 0, 1, id);
+ if (ret)
+ return ret;
+ ret = spinand_manufacturer_match(spinand,
+ SPINAND_READID_METHOD_OPCODE_DUMMY);
+
+ return ret;
+}
+
static int spinand_manufacturer_init(struct spinand_device *spinand)
{
if (spinand->manufacturer->ops->init)
@@ -910,9 +941,9 @@ spinand_select_op_variant(struct spinand_device *spinand,
* @spinand: SPI NAND object
* @table: SPI NAND device description table
* @table_size: size of the device description table
+ * @rdid_method: read id method to match
*
- * Should be used by SPI NAND manufacturer drivers when they want to find a
- * match between a device ID retrieved through the READ_ID command and an
+ * Match between a device ID retrieved through the READ_ID command and an
* entry in the SPI NAND description table. If a match is found, the spinand
* object will be initialized with information provided by the matching
* spinand_info entry.
@@ -921,8 +952,10 @@ spinand_select_op_variant(struct spinand_device *spinand,
*/
int spinand_match_and_init(struct spinand_device *spinand,
const struct spinand_info *table,
- unsigned int table_size, u8 devid)
+ unsigned int table_size,
+ enum spinand_readid_method rdid_method)
{
+ u8 *id = spinand->id.data;
struct nand_device *nand = spinand_to_nand(spinand);
unsigned int i;
@@ -930,13 +963,17 @@ int spinand_match_and_init(struct spinand_device *spinand,
const struct spinand_info *info = &table[i];
const struct spi_mem_op *op;
- if (devid != info->devid)
+ if (rdid_method != info->devid.method)
+ continue;
+
+ if (memcmp(id + 1, info->devid.id, info->devid.len))
continue;
nand->memorg = table[i].memorg;
nand->eccreq = 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;
op = spinand_select_op_variant(spinand,
@@ -972,13 +1009,7 @@ static int spinand_detect(struct spinand_device *spinand)
if (ret)
return ret;
- ret = spinand_read_id_op(spinand, spinand->id.data);
- if (ret)
- return ret;
-
- spinand->id.len = SPINAND_MAX_ID_LEN;
-
- ret = spinand_manufacturer_detect(spinand);
+ ret = spinand_id_detect(spinand);
if (ret) {
dev_err(spinand->slave->dev, "unknown raw ID %02x %02x %02x %02x\n",
spinand->id.data[0], spinand->id.data[1],
@@ -1083,11 +1114,11 @@ static int spinand_init(struct spinand_device *spinand)
for (i = 0; i < nand->memorg.ntargets; i++) {
ret = spinand_select_target(spinand, i);
if (ret)
- goto err_free_bufs;
+ goto err_manuf_cleanup;
ret = spinand_lock_block(spinand, BL_ALL_UNLOCKED);
if (ret)
- goto err_free_bufs;
+ goto err_manuf_cleanup;
}
ret = nanddev_init(nand, &spinand_ops, THIS_MODULE);
diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c
index a2c93486f49..f2ecf47f8d4 100644
--- a/drivers/mtd/nand/spi/gigadevice.c
+++ b/drivers/mtd/nand/spi/gigadevice.c
@@ -7,13 +7,13 @@
*/
#ifndef __UBOOT__
-#include <malloc.h>
#include <linux/device.h>
#include <linux/kernel.h>
#endif
#include <linux/mtd/spinand.h>
#define SPINAND_MFR_GIGADEVICE 0xC8
+
#define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS (1 << 4)
#define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS (3 << 4)
@@ -22,8 +22,12 @@
#define GD5FXGQXXEXXG_REG_STATUS2 0xf0
-/* Q4 devices, QUADIO: Dummy bytes valid for 1 and 2 GBit variants */
-static SPINAND_OP_VARIANTS(gd5fxgq4_read_cache_variants,
+#define GD5FXGQ4UXFXXG_STATUS_ECC_MASK (7 << 4)
+#define GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS (0 << 4)
+#define GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS (1 << 4)
+#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),
@@ -31,14 +35,13 @@ static SPINAND_OP_VARIANTS(gd5fxgq4_read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
-/* Q5 devices, QUADIO: Dummy bytes only valid for 1 GBit variants */
-static SPINAND_OP_VARIANTS(gd5f1gq5_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),
+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(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_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));
static SPINAND_OP_VARIANTS(write_cache_variants,
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
@@ -48,7 +51,65 @@ static SPINAND_OP_VARIANTS(update_cache_variants,
SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
SPINAND_PROG_LOAD(false, 0, NULL, 0));
-static int gd5fxgqxxexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
+static int gd5fxgq4xa_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 gd5fxgq4xa_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 {
+ /* section 0 has one byte reserved for bad block mark */
+ region->offset = 1;
+ region->length = 7;
+ }
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
+ .ecc = gd5fxgq4xa_ooblayout_ecc,
+ .rfree = gd5fxgq4xa_ooblayout_free,
+};
+
+static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
+ u8 status)
+{
+ switch (status & STATUS_ECC_MASK) {
+ case STATUS_ECC_NO_BITFLIPS:
+ return 0;
+
+ case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS:
+ /* 1-7 bits are flipped. return the maximum. */
+ return 7;
+
+ case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS:
+ return 8;
+
+ case STATUS_ECC_UNCOR_ERROR:
+ return -EBADMSG;
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int gd5fxgqx_variant2_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section)
@@ -60,7 +121,7 @@ static int gd5fxgqxxexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
return 0;
}
-static int gd5fxgqxxexxg_ooblayout_free(struct mtd_info *mtd, int section,
+static int gd5fxgqx_variant2_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section)
@@ -73,7 +134,42 @@ static int gd5fxgqxxexxg_ooblayout_free(struct mtd_info *mtd, int section,
return 0;
}
-static int gd5fxgq4xexxg_ecc_get_status(struct spinand_device *spinand,
+/* Valid for Q4/Q5 and Q6 (untested) devices */
+static const struct mtd_ooblayout_ops gd5fxgqx_variant2_ooblayout = {
+ .ecc = gd5fxgqx_variant2_ooblayout_ecc,
+ .rfree = gd5fxgqx_variant2_ooblayout_free,
+};
+
+static int gd5fxgq4xc_ooblayout_256_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ if (section)
+ return -ERANGE;
+
+ oobregion->offset = 128;
+ oobregion->length = 128;
+
+ return 0;
+}
+
+static int gd5fxgq4xc_ooblayout_256_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ if (section)
+ return -ERANGE;
+
+ oobregion->offset = 1;
+ oobregion->length = 127;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops gd5fxgq4xc_oob_256_ops = {
+ .ecc = gd5fxgq4xc_ooblayout_256_ecc,
+ .rfree = gd5fxgq4xc_ooblayout_256_free,
+};
+
+static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
u8 status)
{
u8 status2;
@@ -152,59 +248,116 @@ static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand,
return -EINVAL;
}
-static const struct mtd_ooblayout_ops gd5fxgqxxexxg_ooblayout = {
- .ecc = gd5fxgqxxexxg_ooblayout_ecc,
- .rfree = gd5fxgqxxexxg_ooblayout_free,
-};
+static int gd5fxgq4ufxxg_ecc_get_status(struct spinand_device *spinand,
+ u8 status)
+{
+ switch (status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) {
+ case GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS:
+ return 0;
+
+ case GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS:
+ return 3;
+
+ case GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR:
+ return -EBADMSG;
+
+ default: /* (2 << 4) through (6 << 4) are 4-8 corrected errors */
+ return ((status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) >> 4) + 2;
+ }
+
+ return -EINVAL;
+}
static const struct spinand_info gigadevice_spinand_table[] = {
- SPINAND_INFO("GD5F1GQ4UExxG", 0xd1,
- NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+ SPINAND_INFO("GD5F1GQ4xA",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf1),
+ NAND_MEMORG(1, 2048, 64, 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(&gd5fxgq4xa_ooblayout,
+ gd5fxgq4xa_ecc_get_status)),
+ SPINAND_INFO("GD5F2GQ4xA",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf2),
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
- SPINAND_INFO_OP_VARIANTS(&gd5fxgq4_read_cache_variants,
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
- 0,
- SPINAND_ECCINFO(&gd5fxgqxxexxg_ooblayout,
- gd5fxgq4xexxg_ecc_get_status)),
- SPINAND_INFO("GD5F1GQ5UExxG", 0x51,
- NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
+ gd5fxgq4xa_ecc_get_status)),
+ SPINAND_INFO("GD5F4GQ4xA",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf4),
+ NAND_MEMORG(1, 2048, 64, 64, 4096, 80, 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(&gd5fxgq4xa_ooblayout,
+ gd5fxgq4xa_ecc_get_status)),
+ SPINAND_INFO("GD5F4GQ4RC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xa4, 0x68),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&gd5fxgq4xc_oob_256_ops,
+ gd5fxgq4ufxxg_ecc_get_status)),
+ SPINAND_INFO("GD5F4GQ4UC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb4, 0x68),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&gd5fxgq4xc_oob_256_ops,
+ gd5fxgq4ufxxg_ecc_get_status)),
+ SPINAND_INFO("GD5F1GQ4UExxG",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd1),
+ 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(&gd5fxgqx_variant2_ooblayout,
+ gd5fxgq4uexxg_ecc_get_status)),
+ SPINAND_INFO("GD5F1GQ4UFxxG",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb1, 0x48),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
+ gd5fxgq4ufxxg_ecc_get_status)),
+ SPINAND_INFO("GD5F1GQ5UExxG",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x51),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(4, 512),
- SPINAND_INFO_OP_VARIANTS(&gd5f1gq5_read_cache_variants,
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
- 0,
- SPINAND_ECCINFO(&gd5fxgqxxexxg_ooblayout,
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
gd5fxgq5xexxg_ecc_get_status)),
};
-static int gigadevice_spinand_detect(struct spinand_device *spinand)
-{
- u8 *id = spinand->id.data;
- int ret;
-
- /*
- * For GD NANDs, There is an address byte needed to shift in before IDs
- * are read out, so the first byte in raw_id is dummy.
- */
- if (id[1] != SPINAND_MFR_GIGADEVICE)
- return 0;
-
- ret = spinand_match_and_init(spinand, gigadevice_spinand_table,
- ARRAY_SIZE(gigadevice_spinand_table),
- id[2]);
- if (ret)
- return ret;
-
- return 1;
-}
-
static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = {
- .detect = gigadevice_spinand_detect,
};
const struct spinand_manufacturer gigadevice_spinand_manufacturer = {
.id = SPINAND_MFR_GIGADEVICE,
.name = "GigaDevice",
+ .chips = gigadevice_spinand_table,
+ .nchips = ARRAY_SIZE(gigadevice_spinand_table),
.ops = &gigadevice_spinand_manuf_ops,
};
diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
index 6d643a8000d..86bffc2800b 100644
--- a/drivers/mtd/nand/spi/macronix.c
+++ b/drivers/mtd/nand/spi/macronix.c
@@ -6,7 +6,6 @@
*/
#ifndef __UBOOT__
-#include <malloc.h>
#include <linux/device.h>
#include <linux/kernel.h>
#endif
@@ -16,7 +15,6 @@
#define SPINAND_MFR_MACRONIX 0xC2
#define MACRONIX_ECCSR_MASK 0x0F
-
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),
@@ -62,7 +60,6 @@ static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
SPI_MEM_OP_DATA_IN(1, eccsr, 1));
int ret = spi_mem_exec_op(spinand->slave, &op);
-
if (ret)
return ret;
@@ -105,8 +102,9 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
}
static const struct spinand_info macronix_spinand_table[] = {
- SPINAND_INFO("MX35LF1GE4AB", 0x12,
- NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+ SPINAND_INFO("MX35LF1GE4AB",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x12),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
@@ -114,16 +112,65 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
- SPINAND_INFO("MX35LF2GE4AB", 0x22,
- NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1),
+ SPINAND_INFO("MX35LF2GE4AB",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x22),
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 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(&mx35lfxge4ab_ooblayout, NULL)),
- SPINAND_INFO("MX35UF4GE4AD", 0xb7,
- NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+ SPINAND_INFO("MX35LF2GE4AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x26),
+ 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,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35LF4GE4AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x37),
+ NAND_MEMORG(1, 4096, 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)),
+ SPINAND_INFO("MX35LF1G24AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
+ 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_INFO("MX35LF2G24AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
+ 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_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+ SPINAND_INFO("MX35LF4G24AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
+ 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_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+ SPINAND_INFO("MX31LF1GE4BC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x1e),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
@@ -131,8 +178,9 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
- SPINAND_INFO("MX35UF2GE4AD", 0xa6,
- NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+ SPINAND_INFO("MX31UF1GE4BC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x9e),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
@@ -140,8 +188,10 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
- SPINAND_INFO("MX35UF2GE4AC", 0xa2,
- NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
+
+ SPINAND_INFO("MX35LF2G14AC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x20),
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
@@ -149,8 +199,9 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
- SPINAND_INFO("MX35UF1GE4AD", 0x96,
- NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+ SPINAND_INFO("MX35UF4G24AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb5),
+ 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,
@@ -158,8 +209,89 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
- SPINAND_INFO("MX35UF1GE4AC", 0x92,
- NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+ SPINAND_INFO("MX35UF4GE4AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb7),
+ 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)),
+ SPINAND_INFO("MX35UF2G14AC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa0),
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 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(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35UF2G24AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa4),
+ 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_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35UF2GE4AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa6),
+ 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)),
+ SPINAND_INFO("MX35UF2GE4AC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa2),
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 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(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35UF1G14AC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x90),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 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(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35UF1G24AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x94),
+ 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,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35UF1GE4AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96),
+ 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,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35UF1GE4AC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
@@ -170,33 +302,13 @@ static const struct spinand_info macronix_spinand_table[] = {
};
-static int macronix_spinand_detect(struct spinand_device *spinand)
-{
- u8 *id = spinand->id.data;
- int ret;
-
- /*
- * Macronix SPI NAND read ID needs a dummy byte, so the first byte in
- * raw_id is garbage.
- */
- if (id[1] != SPINAND_MFR_MACRONIX)
- return 0;
-
- ret = spinand_match_and_init(spinand, macronix_spinand_table,
- ARRAY_SIZE(macronix_spinand_table),
- id[2]);
- if (ret)
- return ret;
-
- return 1;
-}
-
static const struct spinand_manufacturer_ops macronix_spinand_manuf_ops = {
- .detect = macronix_spinand_detect,
};
const struct spinand_manufacturer macronix_spinand_manufacturer = {
.id = SPINAND_MFR_MACRONIX,
.name = "Macronix",
+ .chips = macronix_spinand_table,
+ .nchips = ARRAY_SIZE(macronix_spinand_table),
.ops = &macronix_spinand_manuf_ops,
};
diff --git a/drivers/mtd/nand/spi/micron.c b/drivers/mtd/nand/spi/micron.c
index 6bacf14aafe..b538213ed8e 100644
--- a/drivers/mtd/nand/spi/micron.c
+++ b/drivers/mtd/nand/spi/micron.c
@@ -7,11 +7,9 @@
*/
#ifndef __UBOOT__
-#include <malloc.h>
#include <linux/device.h>
#include <linux/kernel.h>
#endif
-#include <linux/bitops.h>
#include <linux/mtd/spinand.h>
#define SPINAND_MFR_MICRON 0x2c
@@ -32,7 +30,7 @@
#define MICRON_SELECT_DIE(x) ((x) << 6)
-static SPINAND_OP_VARIANTS(read_cache_variants,
+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),
@@ -40,14 +38,27 @@ static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
-static SPINAND_OP_VARIANTS(write_cache_variants,
+static SPINAND_OP_VARIANTS(x4_write_cache_variants,
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
SPINAND_PROG_LOAD(true, 0, NULL, 0));
-static SPINAND_OP_VARIANTS(update_cache_variants,
+static SPINAND_OP_VARIANTS(x4_update_cache_variants,
SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
SPINAND_PROG_LOAD(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));
+
+static SPINAND_OP_VARIANTS(x1_write_cache_variants,
+ SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(x1_update_cache_variants,
+ SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
static int micron_8_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
@@ -78,6 +89,47 @@ static const struct mtd_ooblayout_ops micron_8_ooblayout = {
.rfree = micron_8_ooblayout_free,
};
+static int micron_4_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ struct spinand_device *spinand = mtd_to_spinand(mtd);
+
+ if (section >= spinand->base.memorg.pagesize /
+ mtd->ecc_step_size)
+ return -ERANGE;
+
+ region->offset = (section * 16) + 8;
+ region->length = 8;
+
+ return 0;
+}
+
+static int micron_4_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ struct spinand_device *spinand = mtd_to_spinand(mtd);
+
+ if (section >= spinand->base.memorg.pagesize /
+ mtd->ecc_step_size)
+ return -ERANGE;
+
+ if (section) {
+ region->offset = 16 * section;
+ region->length = 8;
+ } else {
+ /* section 0 has two bytes reserved for the BBM */
+ region->offset = 2;
+ region->length = 6;
+ }
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops micron_4_ooblayout = {
+ .ecc = micron_4_ooblayout_ecc,
+ .rfree = micron_4_ooblayout_free,
+};
+
static int micron_select_target(struct spinand_device *spinand,
unsigned int target)
{
@@ -120,120 +172,119 @@ static int micron_8_ecc_get_status(struct spinand_device *spinand,
static const struct spinand_info micron_spinand_table[] = {
/* M79A 2Gb 3.3V */
- SPINAND_INFO("MT29F2G01ABAGD", 0x24,
- NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
+ SPINAND_INFO("MT29F2G01ABAGD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
+ 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_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+ &x4_write_cache_variants,
+ &x4_update_cache_variants),
0,
SPINAND_ECCINFO(&micron_8_ooblayout,
micron_8_ecc_get_status)),
/* M79A 2Gb 1.8V */
- SPINAND_INFO("MT29F2G01ABBGD", 0x25,
- NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
+ SPINAND_INFO("MT29F2G01ABBGD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
+ 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_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+ &x4_write_cache_variants,
+ &x4_update_cache_variants),
0,
SPINAND_ECCINFO(&micron_8_ooblayout,
micron_8_ecc_get_status)),
/* M78A 1Gb 3.3V */
- SPINAND_INFO("MT29F1G01ABAFD", 0x14,
- NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+ SPINAND_INFO("MT29F1G01ABAFD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
+ 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_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+ &x4_write_cache_variants,
+ &x4_update_cache_variants),
0,
SPINAND_ECCINFO(&micron_8_ooblayout,
micron_8_ecc_get_status)),
/* M78A 1Gb 1.8V */
- SPINAND_INFO("MT29F1G01ABAFD", 0x15,
- NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+ SPINAND_INFO("MT29F1G01ABAFD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),
+ 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_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+ &x4_write_cache_variants,
+ &x4_update_cache_variants),
0,
SPINAND_ECCINFO(&micron_8_ooblayout,
micron_8_ecc_get_status)),
/* M79A 4Gb 3.3V */
- SPINAND_INFO("MT29F4G01ADAGD", 0x36,
- NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 2),
+ SPINAND_INFO("MT29F4G01ADAGD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x36),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 80, 2, 1, 2),
NAND_ECCREQ(8, 512),
- SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
- &write_cache_variants,
- &update_cache_variants),
+ SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+ &x4_write_cache_variants,
+ &x4_update_cache_variants),
0,
SPINAND_ECCINFO(&micron_8_ooblayout,
micron_8_ecc_get_status),
SPINAND_SELECT_TARGET(micron_select_target)),
/* M70A 4Gb 3.3V */
- SPINAND_INFO("MT29F4G01ABAFD", 0x34,
- NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+ SPINAND_INFO("MT29F4G01ABAFD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x34),
+ 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_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+ &x4_write_cache_variants,
+ &x4_update_cache_variants),
SPINAND_HAS_CR_FEAT_BIT,
SPINAND_ECCINFO(&micron_8_ooblayout,
micron_8_ecc_get_status)),
/* M70A 4Gb 1.8V */
- SPINAND_INFO("MT29F4G01ABBFD", 0x35,
- NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+ SPINAND_INFO("MT29F4G01ABBFD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
+ 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_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+ &x4_write_cache_variants,
+ &x4_update_cache_variants),
SPINAND_HAS_CR_FEAT_BIT,
SPINAND_ECCINFO(&micron_8_ooblayout,
micron_8_ecc_get_status)),
/* M70A 8Gb 3.3V */
- SPINAND_INFO("MT29F8G01ADAFD", 0x46,
- NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 2),
+ SPINAND_INFO("MT29F8G01ADAFD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x46),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),
NAND_ECCREQ(8, 512),
- SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
- &write_cache_variants,
- &update_cache_variants),
+ SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+ &x4_write_cache_variants,
+ &x4_update_cache_variants),
SPINAND_HAS_CR_FEAT_BIT,
SPINAND_ECCINFO(&micron_8_ooblayout,
micron_8_ecc_get_status),
SPINAND_SELECT_TARGET(micron_select_target)),
/* M70A 8Gb 1.8V */
- SPINAND_INFO("MT29F8G01ADBFD", 0x47,
- NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 2),
+ SPINAND_INFO("MT29F8G01ADBFD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x47),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),
NAND_ECCREQ(8, 512),
- SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
- &write_cache_variants,
- &update_cache_variants),
+ SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+ &x4_write_cache_variants,
+ &x4_update_cache_variants),
SPINAND_HAS_CR_FEAT_BIT,
SPINAND_ECCINFO(&micron_8_ooblayout,
micron_8_ecc_get_status),
SPINAND_SELECT_TARGET(micron_select_target)),
+ /* M69A 2Gb 3.3V */
+ SPINAND_INFO("MT29F2G01AAAED",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x9F),
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 80, 2, 1, 1),
+ NAND_ECCREQ(4, 512),
+ SPINAND_INFO_OP_VARIANTS(&x4_read_cache_variants,
+ &x1_write_cache_variants,
+ &x1_update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&micron_4_ooblayout, NULL)),
};
-static int micron_spinand_detect(struct spinand_device *spinand)
-{
- u8 *id = spinand->id.data;
- int ret;
-
- /*
- * Micron SPI NAND read ID need a dummy byte,
- * so the first byte in raw_id is dummy.
- */
- if (id[1] != SPINAND_MFR_MICRON)
- return 0;
-
- ret = spinand_match_and_init(spinand, micron_spinand_table,
- ARRAY_SIZE(micron_spinand_table), id[2]);
- if (ret)
- return ret;
-
- return 1;
-}
-
static int micron_spinand_init(struct spinand_device *spinand)
{
/*
@@ -248,12 +299,13 @@ static int micron_spinand_init(struct spinand_device *spinand)
}
static const struct spinand_manufacturer_ops micron_spinand_manuf_ops = {
- .detect = micron_spinand_detect,
.init = micron_spinand_init,
};
const struct spinand_manufacturer micron_spinand_manufacturer = {
.id = SPINAND_MFR_MICRON,
.name = "Micron",
+ .chips = micron_spinand_table,
+ .nchips = ARRAY_SIZE(micron_spinand_table),
.ops = &micron_spinand_manuf_ops,
};
diff --git a/drivers/mtd/nand/spi/paragon.c b/drivers/mtd/nand/spi/paragon.c
new file mode 100644
index 00000000000..0c123930f14
--- /dev/null
+++ b/drivers/mtd/nand/spi/paragon.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Jeff Kletsky
+ *
+ * Author: Jeff Kletsky <git-commits@allycomm.com>
+ */
+
+#ifndef __UBOOT__
+#include <linux/device.h>
+#include <linux/kernel.h>
+#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)
+#define PN26G0XA_STATUS_ECC_1_7_CORRECTED (1 << 4)
+#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));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD(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));
+
+
+static int pn26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 3)
+ return -ERANGE;
+
+ region->offset = 6 + (15 * section); /* 4 BBM + 2 user bytes */
+ region->length = 13;
+
+ return 0;
+}
+
+static int pn26g0xa_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 4)
+ return -ERANGE;
+
+ if (section == 4) {
+ region->offset = 64;
+ region->length = 64;
+ } else {
+ region->offset = 4 + (15 * section);
+ region->length = 2;
+ }
+
+ return 0;
+}
+
+static int pn26g0xa_ecc_get_status(struct spinand_device *spinand,
+ u8 status)
+{
+ switch (status & PN26G0XA_STATUS_ECC_BITMASK) {
+ case PN26G0XA_STATUS_ECC_NONE_DETECTED:
+ return 0;
+
+ case PN26G0XA_STATUS_ECC_1_7_CORRECTED:
+ return 7; /* Return upper limit by convention */
+
+ case PN26G0XA_STATUS_ECC_8_CORRECTED:
+ return 8;
+
+ case PN26G0XA_STATUS_ECC_ERRORED:
+ return -EBADMSG;
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static const struct mtd_ooblayout_ops pn26g0xa_ooblayout = {
+ .ecc = pn26g0xa_ooblayout_ecc,
+ .rfree = pn26g0xa_ooblayout_free,
+};
+
+
+static const struct spinand_info paragon_spinand_table[] = {
+ SPINAND_INFO("PN26G01A",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xe1),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 21, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&pn26g0xa_ooblayout,
+ pn26g0xa_ecc_get_status)),
+ SPINAND_INFO("PN26G02A",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xe2),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 41, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&pn26g0xa_ooblayout,
+ pn26g0xa_ecc_get_status)),
+};
+
+static const struct spinand_manufacturer_ops paragon_spinand_manuf_ops = {
+};
+
+const struct spinand_manufacturer paragon_spinand_manufacturer = {
+ .id = SPINAND_MFR_PARAGON,
+ .name = "Paragon",
+ .chips = paragon_spinand_table,
+ .nchips = ARRAY_SIZE(paragon_spinand_table),
+ .ops = &paragon_spinand_manuf_ops,
+};
diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c
index c2cd3b426b3..b9908e79271 100644
--- a/drivers/mtd/nand/spi/toshiba.c
+++ b/drivers/mtd/nand/spi/toshiba.c
@@ -7,13 +7,13 @@
*/
#ifndef __UBOOT__
-#include <malloc.h>
#include <linux/device.h>
#include <linux/kernel.h>
#endif
#include <linux/bug.h>
#include <linux/mtd/spinand.h>
+/* Kioxia is new name of Toshiba memory. */
#define SPINAND_MFR_TOSHIBA 0x98
#define TOSH_STATUS_ECC_HAS_BITFLIPS_T (3 << 4)
@@ -31,7 +31,7 @@ static SPINAND_OP_VARIANTS(update_cache_x4_variants,
SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
SPINAND_PROG_LOAD(false, 0, NULL, 0));
-/**
+/*
* Backward compatibility for 1st generation Serial NAND devices
* which don't support Quad Program Load operation.
*/
@@ -42,7 +42,7 @@ static SPINAND_OP_VARIANTS(update_cache_variants,
SPINAND_PROG_LOAD(false, 0, NULL, 0));
static int tx58cxgxsxraix_ooblayout_ecc(struct mtd_info *mtd, int section,
- struct mtd_oob_region *region)
+ struct mtd_oob_region *region)
{
if (section > 0)
return -ERANGE;
@@ -54,7 +54,7 @@ static int tx58cxgxsxraix_ooblayout_ecc(struct mtd_info *mtd, int section,
}
static int tx58cxgxsxraix_ooblayout_free(struct mtd_info *mtd, int section,
- struct mtd_oob_region *region)
+ struct mtd_oob_region *region)
{
if (section > 0)
return -ERANGE;
@@ -72,7 +72,7 @@ static const struct mtd_ooblayout_ops tx58cxgxsxraix_ooblayout = {
};
static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand,
- u8 status)
+ u8 status)
{
struct nand_device *nand = spinand_to_nand(spinand);
u8 mbf = 0;
@@ -111,8 +111,9 @@ static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand,
static const struct spinand_info toshiba_spinand_table[] = {
/* 3.3V 1Gb (1st generation) */
- SPINAND_INFO("TC58CVG0S3HRAIG", 0xC2,
- NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+ SPINAND_INFO("TC58CVG0S3HRAIG",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xC2),
+ 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,
@@ -121,8 +122,9 @@ static const struct spinand_info toshiba_spinand_table[] = {
SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
tx58cxgxsxraix_ecc_get_status)),
/* 3.3V 2Gb (1st generation) */
- SPINAND_INFO("TC58CVG1S3HRAIG", 0xCB,
- NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+ SPINAND_INFO("TC58CVG1S3HRAIG",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCB),
+ 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,
@@ -131,8 +133,9 @@ static const struct spinand_info toshiba_spinand_table[] = {
SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
tx58cxgxsxraix_ecc_get_status)),
/* 3.3V 4Gb (1st generation) */
- SPINAND_INFO("TC58CVG2S0HRAIG", 0xCD,
- NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+ SPINAND_INFO("TC58CVG2S0HRAIG",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCD),
+ 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,
@@ -141,8 +144,9 @@ static const struct spinand_info toshiba_spinand_table[] = {
SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
tx58cxgxsxraix_ecc_get_status)),
/* 1.8V 1Gb (1st generation) */
- SPINAND_INFO("TC58CYG0S3HRAIG", 0xB2,
- NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+ SPINAND_INFO("TC58CYG0S3HRAIG",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xB2),
+ 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,
@@ -151,8 +155,9 @@ static const struct spinand_info toshiba_spinand_table[] = {
SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
tx58cxgxsxraix_ecc_get_status)),
/* 1.8V 2Gb (1st generation) */
- SPINAND_INFO("TC58CYG1S3HRAIG", 0xBB,
- NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+ SPINAND_INFO("TC58CYG1S3HRAIG",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBB),
+ 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,
@@ -161,8 +166,9 @@ static const struct spinand_info toshiba_spinand_table[] = {
SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
tx58cxgxsxraix_ecc_get_status)),
/* 1.8V 4Gb (1st generation) */
- SPINAND_INFO("TC58CYG2S0HRAIG", 0xBD,
- NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+ SPINAND_INFO("TC58CYG2S0HRAIG",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBD),
+ 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,
@@ -176,8 +182,9 @@ static const struct spinand_info toshiba_spinand_table[] = {
* QE_BIT.
*/
/* 3.3V 1Gb (2nd generation) */
- SPINAND_INFO("TC58CVG0S3HRAIJ", 0xE2,
- NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+ SPINAND_INFO("TC58CVG0S3HRAIJ",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE2),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_x4_variants,
@@ -186,8 +193,9 @@ static const struct spinand_info toshiba_spinand_table[] = {
SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
tx58cxgxsxraix_ecc_get_status)),
/* 3.3V 2Gb (2nd generation) */
- SPINAND_INFO("TC58CVG1S3HRAIJ", 0xEB,
- NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+ SPINAND_INFO("TC58CVG1S3HRAIJ",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xEB),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_x4_variants,
@@ -196,8 +204,9 @@ static const struct spinand_info toshiba_spinand_table[] = {
SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
tx58cxgxsxraix_ecc_get_status)),
/* 3.3V 4Gb (2nd generation) */
- SPINAND_INFO("TC58CVG2S0HRAIJ", 0xED,
- NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+ SPINAND_INFO("TC58CVG2S0HRAIJ",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xED),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_x4_variants,
@@ -206,8 +215,9 @@ static const struct spinand_info toshiba_spinand_table[] = {
SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
tx58cxgxsxraix_ecc_get_status)),
/* 3.3V 8Gb (2nd generation) */
- SPINAND_INFO("TH58CVG3S0HRAIJ", 0xE4,
- NAND_MEMORG(1, 4096, 256, 64, 4096, 1, 1, 1),
+ SPINAND_INFO("TH58CVG3S0HRAIJ",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4),
+ 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,
@@ -216,8 +226,9 @@ static const struct spinand_info toshiba_spinand_table[] = {
SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
tx58cxgxsxraix_ecc_get_status)),
/* 1.8V 1Gb (2nd generation) */
- SPINAND_INFO("TC58CYG0S3HRAIJ", 0xD2,
- NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+ SPINAND_INFO("TC58CYG0S3HRAIJ",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD2),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_x4_variants,
@@ -226,8 +237,9 @@ static const struct spinand_info toshiba_spinand_table[] = {
SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
tx58cxgxsxraix_ecc_get_status)),
/* 1.8V 2Gb (2nd generation) */
- SPINAND_INFO("TC58CYG1S3HRAIJ", 0xDB,
- NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+ SPINAND_INFO("TC58CYG1S3HRAIJ",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xDB),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_x4_variants,
@@ -236,8 +248,9 @@ static const struct spinand_info toshiba_spinand_table[] = {
SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
tx58cxgxsxraix_ecc_get_status)),
/* 1.8V 4Gb (2nd generation) */
- SPINAND_INFO("TC58CYG2S0HRAIJ", 0xDD,
- NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+ SPINAND_INFO("TC58CYG2S0HRAIJ",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xDD),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_x4_variants,
@@ -246,8 +259,9 @@ static const struct spinand_info toshiba_spinand_table[] = {
SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
tx58cxgxsxraix_ecc_get_status)),
/* 1.8V 8Gb (2nd generation) */
- SPINAND_INFO("TH58CYG3S0HRAIJ", 0xD4,
- NAND_MEMORG(1, 4096, 256, 64, 4096, 1, 1, 1),
+ SPINAND_INFO("TH58CYG3S0HRAIJ",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD4),
+ 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,
@@ -257,33 +271,13 @@ static const struct spinand_info toshiba_spinand_table[] = {
tx58cxgxsxraix_ecc_get_status)),
};
-static int toshiba_spinand_detect(struct spinand_device *spinand)
-{
- u8 *id = spinand->id.data;
- int ret;
-
- /*
- * Toshiba SPI NAND read ID needs a dummy byte,
- * so the first byte in id is garbage.
- */
- if (id[1] != SPINAND_MFR_TOSHIBA)
- return 0;
-
- ret = spinand_match_and_init(spinand, toshiba_spinand_table,
- ARRAY_SIZE(toshiba_spinand_table),
- id[2]);
- if (ret)
- return ret;
-
- return 1;
-}
-
static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = {
- .detect = toshiba_spinand_detect,
};
const struct spinand_manufacturer toshiba_spinand_manufacturer = {
.id = SPINAND_MFR_TOSHIBA,
.name = "Toshiba",
+ .chips = toshiba_spinand_table,
+ .nchips = ARRAY_SIZE(toshiba_spinand_table),
.ops = &toshiba_spinand_manuf_ops,
};
diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index c119486efb7..dd4ed257a83 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -8,11 +8,10 @@
*/
#ifndef __UBOOT__
-#include <malloc.h>
#include <linux/device.h>
#include <linux/kernel.h>
#endif
-#include <linux/bitops.h>
+#include <linux/bug.h>
#include <linux/mtd/spinand.h>
#define SPINAND_MFR_WINBOND 0xEF
@@ -78,9 +77,76 @@ static int w25m02gv_select_target(struct spinand_device *spinand,
return spi_mem_exec_op(spinand->slave, &op);
}
+static int w25n02kv_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 3)
+ return -ERANGE;
+
+ region->offset = 64 + (16 * section);
+ region->length = 13;
+
+ return 0;
+}
+
+static int w25n02kv_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 3)
+ return -ERANGE;
+
+ region->offset = (16 * section) + 2;
+ region->length = 14;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops w25n02kv_ooblayout = {
+ .ecc = w25n02kv_ooblayout_ecc,
+ .rfree = w25n02kv_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);
+
+ switch (status & STATUS_ECC_MASK) {
+ case STATUS_ECC_NO_BITFLIPS:
+ return 0;
+
+ case STATUS_ECC_UNCOR_ERROR:
+ return -EBADMSG;
+
+ case STATUS_ECC_HAS_BITFLIPS:
+ /*
+ * Let's try to retrieve the real maximum number of bitflips
+ * in order to avoid forcing the wear-leveling layer to move
+ * data around if it's not necessary.
+ */
+ if (spi_mem_exec_op(spinand->slave, &op))
+ return nand->eccreq.strength;
+
+ mbf >>= 4;
+
+ if (WARN_ON(mbf > nand->eccreq.strength || !mbf))
+ return nand->eccreq.strength;
+
+ return mbf;
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
static const struct spinand_info winbond_spinand_table[] = {
- SPINAND_INFO("W25M02GV", 0xAB,
- NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 2),
+ SPINAND_INFO("W25M02GV",
+ 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,
@@ -88,41 +154,26 @@ static const struct spinand_info winbond_spinand_table[] = {
0,
SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
SPINAND_SELECT_TARGET(w25m02gv_select_target)),
- SPINAND_INFO("W25N01GV", 0xAA,
- NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+ SPINAND_INFO("W25N01GV",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 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("W25N02KV",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 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)),
};
-/**
- * winbond_spinand_detect - initialize device related part in spinand_device
- * struct if it is a Winbond device.
- * @spinand: SPI NAND device structure
- */
-static int winbond_spinand_detect(struct spinand_device *spinand)
-{
- u8 *id = spinand->id.data;
- int ret;
-
- /*
- * Winbond SPI NAND read ID need a dummy byte,
- * so the first byte in raw_id is dummy.
- */
- if (id[1] != SPINAND_MFR_WINBOND)
- return 0;
-
- ret = spinand_match_and_init(spinand, winbond_spinand_table,
- ARRAY_SIZE(winbond_spinand_table), id[2]);
- if (ret)
- return ret;
-
- return 1;
-}
-
static int winbond_spinand_init(struct spinand_device *spinand)
{
struct nand_device *nand = spinand_to_nand(spinand);
@@ -142,12 +193,13 @@ static int winbond_spinand_init(struct spinand_device *spinand)
}
static const struct spinand_manufacturer_ops winbond_spinand_manuf_ops = {
- .detect = winbond_spinand_detect,
.init = winbond_spinand_init,
};
const struct spinand_manufacturer winbond_spinand_manufacturer = {
.id = SPINAND_MFR_WINBOND,
.name = "Winbond",
+ .chips = winbond_spinand_table,
+ .nchips = ARRAY_SIZE(winbond_spinand_table),
.ops = &winbond_spinand_manuf_ops,
};
diff --git a/drivers/mtd/onenand/onenand_uboot.c b/drivers/mtd/onenand/onenand_uboot.c
index 04791df69bb..ecacabefadc 100644
--- a/drivers/mtd/onenand/onenand_uboot.c
+++ b/drivers/mtd/onenand/onenand_uboot.c
@@ -44,14 +44,12 @@ void onenand_init(void)
puts("Flex-");
puts("OneNAND: ");
-#ifdef CONFIG_MTD
/*
* Add MTD device so that we can reference it later
* via the mtdcore infrastructure (e.g. ubi).
*/
onenand_mtd.name = dev_name;
add_mtd_device(&onenand_mtd);
-#endif
}
print_size(onenand_chip.chipsize, "\n");
}
diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
index a9617c6c58c..732b0760452 100644
--- a/drivers/mtd/spi/Kconfig
+++ b/drivers/mtd/spi/Kconfig
@@ -82,6 +82,7 @@ if SPI_FLASH
config BOOTDEV_SPI_FLASH
bool "SPI Flash bootdev support"
+ depends on BOOTSTD
help
Enable a boot device for SPI flash. This allows reading a script
from SPI flash so that it can be used to boot an Operating System.
@@ -107,7 +108,6 @@ config SPI_FLASH_SMART_HWCAPS
config SPI_NOR_BOOT_SOFT_RESET_EXT_INVERT
bool "Command extension type is INVERT for Software Reset on boot"
- default n
help
Because of SFDP information can not be get before boot.
So define command extension type is INVERT when Software Reset on boot only.
@@ -134,6 +134,13 @@ config SPI_FLASH_BAR
Bank/Extended address registers are used to access the flash
which has size > 16MiB in 3-byte addressing.
+config SPI_FLASH_LOCK
+ bool "Enable the Locking feature"
+ default y
+ help
+ Enable the SPI flash lock support. By default this is set to y.
+ If you intend not to use the lock support you should say n here.
+
config SPI_FLASH_UNLOCK_ALL
bool "Unlock the entire SPI flash on u-boot startup"
default y
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index db20feb4dae..9a1801ba93d 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -1100,6 +1100,7 @@ static int spansion_erase_non_uniform(struct spi_nor *nor, u32 addr,
}
#endif
+#if defined(CONFIG_SPI_FLASH_LOCK)
#if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST)
/* Write status register and ensure bits in mask match written values */
static int write_sr_and_check(struct spi_nor *nor, u8 status_new, u8 mask)
@@ -1387,6 +1388,7 @@ static int stm_is_unlocked(struct spi_nor *nor, loff_t ofs, uint64_t len)
return stm_is_unlocked_sr(nor, ofs, len, status);
}
#endif /* CONFIG_SPI_FLASH_STMICRO */
+#endif
static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
{
@@ -1462,6 +1464,7 @@ read_err:
return ret;
}
+#if defined(CONFIG_SPI_FLASH_LOCK)
#ifdef CONFIG_SPI_FLASH_SST
/*
* sst26 flash series has its own block protection implementation:
@@ -1730,6 +1733,8 @@ sst_write_err:
return ret;
}
#endif
+#endif
+
/*
* Write an address range to the nor chip. Data must be written in
* FLASH_PAGESIZE chunks. The address range may be any size provided
@@ -4104,6 +4109,7 @@ int spi_nor_scan(struct spi_nor *nor)
mtd->_read = spi_nor_read;
mtd->_write = spi_nor_write;
+#if defined(CONFIG_SPI_FLASH_LOCK)
#if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST)
/* NOR protection support for STmicro/Micron chips and similar */
if (JEDEC_MFR(info) == SNOR_MFR_ST ||
@@ -4127,7 +4133,7 @@ int spi_nor_scan(struct spi_nor *nor)
nor->flash_is_unlocked = sst26_is_unlocked;
}
#endif
-
+#endif
if (info->flags & USE_FSR)
nor->flags |= SNOR_F_USE_FSR;
if (info->flags & SPI_NOR_HAS_TB)
diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
index b03dd1cd08e..3cb132dcffc 100644
--- a/drivers/mtd/spi/spi-nor-ids.c
+++ b/drivers/mtd/spi/spi-nor-ids.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc.
* Copyright (C) 2016 Jagan Teki <jagan@openedev.com>
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
*/
#include <common.h>
@@ -532,6 +532,7 @@ const struct flash_info spi_nor_ids[] = {
{ INFO("XM25QH64A", 0x207017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ INFO("XM25QH64C", 0x204017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ INFO("XM25QH128A", 0x207018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { INFO("XM25QU128C", 0x204118, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
#endif
#ifdef CONFIG_SPI_FLASH_XTX
/* XTX Technology Limited */
diff --git a/drivers/mux/mux-uclass.c b/drivers/mux/mux-uclass.c
index 8870305313a..c98576ceb81 100644
--- a/drivers/mux/mux-uclass.c
+++ b/drivers/mux/mux-uclass.c
@@ -7,7 +7,7 @@
* Copyright (C) 2017 Axentia Technologies AB
* Author: Peter Rosin <peda@axentia.se>
*
- * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2017-2018 Texas Instruments Incorporated - https://www.ti.com/
* Jean-Jacques Hiblot <jjhiblot@ti.com>
*/
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 29304fd7775..23ad2c29d0a 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -471,14 +471,6 @@ config SYS_UNIFY_CACHE
depends on MCFFEC
bool "Invalidate icache during ethernet operations"
-config FSLDMAFEC
- bool "ColdFire DMA Ethernet Support"
- select PHYLIB
- select SYS_DISCOVER_PHY
- help
- This driver supports the network interface units in the
- ColdFire family.
-
config KS8851_MLL
bool "Microchip KS8851-MLL controller driver"
help
@@ -903,6 +895,23 @@ config MEDIATEK_ETH
This Driver support MediaTek Ethernet GMAC
Say Y to enable support for the MediaTek Ethernet GMAC.
+config HIFEMAC_ETH
+ bool "HiSilicon Fast Ethernet Controller"
+ select DM_CLK
+ select DM_RESET
+ select PHYLIB
+ help
+ This driver supports HIFEMAC Ethernet controller found on
+ HiSilicon SoCs.
+
+config HIFEMAC_MDIO
+ bool "HiSilicon Fast Ethernet Controller MDIO interface"
+ depends on DM_MDIO
+ select DM_CLK
+ help
+ This driver supports the internal MDIO interface of HIFEMAC
+ Ethernet controller.
+
config HIGMACV300_ETH
bool "HiSilicon Gigabit Ethernet Controller"
select DM_RESET
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 1d444f5b4a6..f9aed1646c9 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -37,7 +37,6 @@ obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o
obj-$(CONFIG_FEC_MXC) += fec_mxc.o
obj-$(CONFIG_FMAN_ENET) += fm/
obj-$(CONFIG_FMAN_ENET) += fsl_mdio.o
-obj-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o
obj-$(CONFIG_FSL_ENETC) += fsl_enetc.o fsl_enetc_mdio.o
obj-$(CONFIG_FSL_LS_MDIO) += fsl_ls_mdio.o
obj-$(CONFIG_FSL_MC_ENET) += fsl-mc/
@@ -47,6 +46,8 @@ obj-$(CONFIG_FSL_PFE) += pfe_eth/
obj-$(CONFIG_FTGMAC100) += ftgmac100.o
obj-$(CONFIG_FTMAC100) += ftmac100.o
obj-$(CONFIG_GMAC_ROCKCHIP) += gmac_rockchip.o
+obj-$(CONFIG_HIFEMAC_ETH) += hifemac.o
+obj-$(CONFIG_HIFEMAC_MDIO) += hifemac_mdio.o
obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o
obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o
obj-$(CONFIG_KSZ9477) += ksz9477.o
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 20b86e74cec..a174344b3ef 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -19,6 +19,7 @@
#include <net.h>
#include <pci.h>
#include <reset.h>
+#include <phys2bus.h>
#include <asm/cache.h>
#include <dm/device_compat.h>
#include <dm/device-internal.h>
@@ -232,8 +233,10 @@ static void tx_descs_init(struct dw_eth_dev *priv)
for (idx = 0; idx < CFG_TX_DESCR_NUM; idx++) {
desc_p = &desc_table_p[idx];
- desc_p->dmamac_addr = (ulong)&txbuffs[idx * CFG_ETH_BUFSIZE];
- desc_p->dmamac_next = (ulong)&desc_table_p[idx + 1];
+ desc_p->dmamac_addr = dev_phys_to_bus(priv->dev,
+ (ulong)&txbuffs[idx * CFG_ETH_BUFSIZE]);
+ desc_p->dmamac_next = dev_phys_to_bus(priv->dev,
+ (ulong)&desc_table_p[idx + 1]);
#if defined(CONFIG_DW_ALTDESCRIPTOR)
desc_p->txrx_status &= ~(DESC_TXSTS_TXINT | DESC_TXSTS_TXLAST |
@@ -251,14 +254,15 @@ static void tx_descs_init(struct dw_eth_dev *priv)
}
/* Correcting the last pointer of the chain */
- desc_p->dmamac_next = (ulong)&desc_table_p[0];
+ desc_p->dmamac_next = dev_phys_to_bus(priv->dev, (ulong)&desc_table_p[0]);
/* Flush all Tx buffer descriptors at once */
flush_dcache_range((ulong)priv->tx_mac_descrtable,
(ulong)priv->tx_mac_descrtable +
sizeof(priv->tx_mac_descrtable));
- writel((ulong)&desc_table_p[0], &dma_p->txdesclistaddr);
+ writel(dev_phys_to_bus(priv->dev, (ulong)&desc_table_p[0]),
+ &dma_p->txdesclistaddr);
priv->tx_currdescnum = 0;
}
@@ -280,8 +284,10 @@ static void rx_descs_init(struct dw_eth_dev *priv)
for (idx = 0; idx < CFG_RX_DESCR_NUM; idx++) {
desc_p = &desc_table_p[idx];
- desc_p->dmamac_addr = (ulong)&rxbuffs[idx * CFG_ETH_BUFSIZE];
- desc_p->dmamac_next = (ulong)&desc_table_p[idx + 1];
+ desc_p->dmamac_addr = dev_phys_to_bus(priv->dev,
+ (ulong)&rxbuffs[idx * CFG_ETH_BUFSIZE]);
+ desc_p->dmamac_next = dev_phys_to_bus(priv->dev,
+ (ulong)&desc_table_p[idx + 1]);
desc_p->dmamac_cntl =
(MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) |
@@ -291,14 +297,15 @@ static void rx_descs_init(struct dw_eth_dev *priv)
}
/* Correcting the last pointer of the chain */
- desc_p->dmamac_next = (ulong)&desc_table_p[0];
+ desc_p->dmamac_next = dev_phys_to_bus(priv->dev, (ulong)&desc_table_p[0]);
/* Flush all Rx buffer descriptors at once */
flush_dcache_range((ulong)priv->rx_mac_descrtable,
(ulong)priv->rx_mac_descrtable +
sizeof(priv->rx_mac_descrtable));
- writel((ulong)&desc_table_p[0], &dma_p->rxdesclistaddr);
+ writel(dev_phys_to_bus(priv->dev, (ulong)&desc_table_p[0]),
+ &dma_p->rxdesclistaddr);
priv->rx_currdescnum = 0;
}
@@ -448,7 +455,7 @@ static int _dw_eth_send(struct dw_eth_dev *priv, void *packet, int length)
ulong desc_start = (ulong)desc_p;
ulong desc_end = desc_start +
roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
- ulong data_start = desc_p->dmamac_addr;
+ ulong data_start = dev_bus_to_phys(priv->dev, desc_p->dmamac_addr);
ulong data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
/*
* Strictly we only need to invalidate the "txrx_status" field
@@ -515,7 +522,7 @@ static int _dw_eth_recv(struct dw_eth_dev *priv, uchar **packetp)
ulong desc_start = (ulong)desc_p;
ulong desc_end = desc_start +
roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
- ulong data_start = desc_p->dmamac_addr;
+ ulong data_start = dev_bus_to_phys(priv->dev, desc_p->dmamac_addr);
ulong data_end;
/* Invalidate entire buffer descriptor */
@@ -532,7 +539,8 @@ static int _dw_eth_recv(struct dw_eth_dev *priv, uchar **packetp)
/* Invalidate received data */
data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
invalidate_dcache_range(data_start, data_end);
- *packetp = (uchar *)(ulong)desc_p->dmamac_addr;
+ *packetp = (uchar *)(ulong)dev_bus_to_phys(priv->dev,
+ desc_p->dmamac_addr);
}
return length;
@@ -757,6 +765,7 @@ int designware_eth_probe(struct udevice *dev)
goto mdio_err;
}
priv->bus = miiphy_get_dev_by_name(dev->name);
+ priv->dev = dev;
ret = dw_phy_init(priv, dev);
debug("%s, ret=%d\n", __func__, ret);
diff --git a/drivers/net/designware.h b/drivers/net/designware.h
index 9da4e902cb0..918a38615ad 100644
--- a/drivers/net/designware.h
+++ b/drivers/net/designware.h
@@ -241,6 +241,7 @@ struct dw_eth_dev {
int clock_count; /* number of clock in clock list */
#endif
+ struct udevice *dev;
struct phy_device *phydev;
struct mii_dev *bus;
};
diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c
index 18466cfe257..a4e3698c600 100644
--- a/drivers/net/dwc_eth_qos.c
+++ b/drivers/net/dwc_eth_qos.c
@@ -746,6 +746,7 @@ static int eqos_start(struct udevice *dev)
u32 val, tx_fifo_sz, rx_fifo_sz, tqs, rqs, pbl;
ulong last_rx_desc;
ulong desc_pad;
+ ulong addr64;
debug("%s(dev=%p):\n", __func__, dev);
@@ -1039,25 +1040,25 @@ static int eqos_start(struct udevice *dev)
for (i = 0; i < EQOS_DESCRIPTORS_RX; i++) {
struct eqos_desc *rx_desc = eqos_get_desc(eqos, i, true);
- rx_desc->des0 = (u32)(ulong)(eqos->rx_dma_buf +
- (i * EQOS_MAX_PACKET_SIZE));
+
+ addr64 = (ulong)(eqos->rx_dma_buf + (i * EQOS_MAX_PACKET_SIZE));
+ rx_desc->des0 = lower_32_bits(addr64);
+ rx_desc->des1 = upper_32_bits(addr64);
rx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_BUF1V;
mb();
eqos->config->ops->eqos_flush_desc(rx_desc);
- eqos->config->ops->eqos_inval_buffer(eqos->rx_dma_buf +
- (i * EQOS_MAX_PACKET_SIZE),
- EQOS_MAX_PACKET_SIZE);
+ eqos->config->ops->eqos_inval_buffer((void *)addr64, EQOS_MAX_PACKET_SIZE);
}
- writel(0, &eqos->dma_regs->ch0_txdesc_list_haddress);
- writel((ulong)eqos_get_desc(eqos, 0, false),
- &eqos->dma_regs->ch0_txdesc_list_address);
+ addr64 = (ulong)eqos_get_desc(eqos, 0, false);
+ writel(upper_32_bits(addr64), &eqos->dma_regs->ch0_txdesc_list_haddress);
+ writel(lower_32_bits(addr64), &eqos->dma_regs->ch0_txdesc_list_address);
writel(EQOS_DESCRIPTORS_TX - 1,
&eqos->dma_regs->ch0_txdesc_ring_length);
- writel(0, &eqos->dma_regs->ch0_rxdesc_list_haddress);
- writel((ulong)eqos_get_desc(eqos, 0, true),
- &eqos->dma_regs->ch0_rxdesc_list_address);
+ addr64 = (ulong)eqos_get_desc(eqos, 0, true);
+ writel(upper_32_bits(addr64), &eqos->dma_regs->ch0_rxdesc_list_haddress);
+ writel(lower_32_bits(addr64), &eqos->dma_regs->ch0_rxdesc_list_address);
writel(EQOS_DESCRIPTORS_RX - 1,
&eqos->dma_regs->ch0_rxdesc_ring_length);
@@ -1162,8 +1163,8 @@ static int eqos_send(struct udevice *dev, void *packet, int length)
eqos->tx_desc_idx++;
eqos->tx_desc_idx %= EQOS_DESCRIPTORS_TX;
- tx_desc->des0 = (ulong)eqos->tx_dma_buf;
- tx_desc->des1 = 0;
+ tx_desc->des0 = lower_32_bits((ulong)eqos->tx_dma_buf);
+ tx_desc->des1 = upper_32_bits((ulong)eqos->tx_dma_buf);
tx_desc->des2 = length;
/*
* Make sure that if HW sees the _OWN write below, it will see all the
@@ -1234,14 +1235,17 @@ static int eqos_free_pkt(struct udevice *dev, uchar *packet, int length)
for (idx = eqos->rx_desc_idx - idx_mask;
idx <= eqos->rx_desc_idx;
idx++) {
+ ulong addr64;
+
rx_desc = eqos_get_desc(eqos, idx, true);
rx_desc->des0 = 0;
+ rx_desc->des1 = 0;
mb();
eqos->config->ops->eqos_flush_desc(rx_desc);
eqos->config->ops->eqos_inval_buffer(packet, length);
- rx_desc->des0 = (u32)(ulong)(eqos->rx_dma_buf +
- (idx * EQOS_MAX_PACKET_SIZE));
- rx_desc->des1 = 0;
+ addr64 = (ulong)(eqos->rx_dma_buf + (idx * EQOS_MAX_PACKET_SIZE));
+ rx_desc->des0 = lower_32_bits(addr64);
+ rx_desc->des1 = upper_32_bits(addr64);
rx_desc->des2 = 0;
/*
* Make sure that if HW sees the _OWN write below,
diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c
index 41e6ba760e2..84a2a7cf904 100644
--- a/drivers/net/e1000.c
+++ b/drivers/net/e1000.c
@@ -5718,15 +5718,9 @@ static const struct eth_ops e1000_eth_ops = {
.write_hwaddr = e1000_write_hwaddr,
};
-static const struct udevice_id e1000_eth_ids[] = {
- { .compatible = "intel,e1000" },
- { }
-};
-
U_BOOT_DRIVER(eth_e1000) = {
.name = "eth_e1000",
.id = UCLASS_ETH,
- .of_match = e1000_eth_ids,
.bind = e1000_eth_bind,
.probe = e1000_eth_probe,
.ops = &e1000_eth_ops,
diff --git a/drivers/net/fm/fm.c b/drivers/net/fm/fm.c
index 7dfa8219094..a8caa0f0927 100644
--- a/drivers/net/fm/fm.c
+++ b/drivers/net/fm/fm.c
@@ -3,7 +3,6 @@
* Copyright 2009-2011 Freescale Semiconductor, Inc.
* Dave Liu <daveliu@freescale.com>
*/
-#include <common.h>
#include <env.h>
#include <fs_loader.h>
#include <image.h>
diff --git a/drivers/net/fsl-mc/mc.c b/drivers/net/fsl-mc/mc.c
index 984616fb65c..f5c5057bec1 100644
--- a/drivers/net/fsl-mc/mc.c
+++ b/drivers/net/fsl-mc/mc.c
@@ -30,6 +30,8 @@
#include <fsl-mc/fsl_qbman_portal.h>
#include <fsl-mc/ldpaa_wriop.h>
#include <net/ldpaa_eth.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch-fsl-layerscape/fsl_icid.h>
#define MC_RAM_BASE_ADDR_ALIGNMENT (512UL * 1024 * 1024)
#define MC_RAM_BASE_ADDR_ALIGNMENT_MASK (~(MC_RAM_BASE_ADDR_ALIGNMENT - 1))
@@ -929,6 +931,114 @@ unsigned long mc_get_dram_block_size(void)
return dram_block_size;
}
+/**
+ * Populate the device tree with MC reserved memory ranges.
+ */
+void fdt_reserve_mc_mem(void *blob, u32 mc_icid)
+{
+ u32 phandle, mc_ph;
+ int noff, ret, i;
+ char mem_name[16];
+ struct fdt_memory mc_mem_ranges[] = {
+ {
+ .start = 0,
+ .end = 0
+ },
+ {
+ .start = CFG_SYS_FSL_MC_BASE,
+ .end = CFG_SYS_FSL_MC_BASE + CFG_SYS_FSL_MC_SIZE - 1
+ },
+ {
+ .start = CFG_SYS_FSL_NI_BASE,
+ .end = CFG_SYS_FSL_NI_BASE + CFG_SYS_FSL_NI_SIZE - 1
+ },
+ {
+ .start = CFG_SYS_FSL_QBMAN_BASE,
+ .end = CFG_SYS_FSL_QBMAN_BASE +
+ CFG_SYS_FSL_QBMAN_SIZE - 1
+ },
+ {
+ .start = CFG_SYS_FSL_PEBUF_BASE,
+ .end = CFG_SYS_FSL_PEBUF_BASE +
+ CFG_SYS_FSL_PEBUF_SIZE - 1
+ },
+ {
+ .start = CFG_SYS_FSL_CCSR_BASE,
+ .end = CFG_SYS_FSL_CCSR_BASE + CFG_SYS_FSL_CCSR_SIZE - 1
+ }
+ };
+
+ mc_mem_ranges[0].start = gd->arch.resv_ram;
+ mc_mem_ranges[0].end = mc_mem_ranges[0].start +
+ mc_get_dram_block_size() - 1;
+
+ for (i = 0; i < ARRAY_SIZE(mc_mem_ranges); i++) {
+ noff = fdt_node_offset_by_compatible(blob, -1, "fsl,qoriq-mc");
+ if (noff < 0) {
+ printf("WARN: failed to get MC node: %d\n", noff);
+ return;
+ }
+ mc_ph = fdt_get_phandle(blob, noff);
+ if (!mc_ph) {
+ mc_ph = fdt_create_phandle(blob, noff);
+ if (!mc_ph) {
+ printf("WARN: failed to get MC node phandle\n");
+ return;
+ }
+ }
+
+ sprintf(mem_name, "mc-mem%d", i);
+ ret = fdtdec_add_reserved_memory(blob, mem_name,
+ &mc_mem_ranges[i], NULL, 0,
+ &phandle, 0);
+ if (ret < 0) {
+ printf("ERROR: failed to reserve MC memory: %d\n", ret);
+ return;
+ }
+
+ noff = fdt_node_offset_by_phandle(blob, phandle);
+ if (noff < 0) {
+ printf("ERROR: failed get resvmem node offset: %d\n",
+ noff);
+ return;
+ }
+ ret = fdt_setprop_u32(blob, noff, "iommu-addresses", mc_ph);
+ if (ret < 0) {
+ printf("ERROR: failed to set 'iommu-addresses': %d\n",
+ ret);
+ return;
+ }
+ ret = fdt_appendprop_u64(blob, noff, "iommu-addresses",
+ mc_mem_ranges[i].start);
+ if (ret < 0) {
+ printf("ERROR: failed to set 'iommu-addresses': %d\n",
+ ret);
+ return;
+ }
+ ret = fdt_appendprop_u64(blob, noff, "iommu-addresses",
+ mc_mem_ranges[i].end -
+ mc_mem_ranges[i].start + 1);
+ if (ret < 0) {
+ printf("ERROR: failed to set 'iommu-addresses': %d\n",
+ ret);
+ return;
+ }
+
+ noff = fdt_node_offset_by_phandle(blob, mc_ph);
+ if (noff < 0) {
+ printf("ERROR: failed get MC node offset: %d\n", noff);
+ return;
+ }
+ ret = fdt_appendprop_u32(blob, noff, "memory-region", phandle);
+ if (ret < 0) {
+ printf("ERROR: failed to set 'memory-region': %d\n",
+ ret);
+ }
+ }
+
+ fdt_set_iommu_prop(blob, noff, fdt_get_smmu_phandle(blob), &mc_icid, 1);
+}
+
int fsl_mc_ldpaa_init(struct bd_info *bis)
{
int i;
diff --git a/drivers/net/fsl_mcdmafec.c b/drivers/net/fsl_mcdmafec.c
deleted file mode 100644
index cc61a107403..00000000000
--- a/drivers/net/fsl_mcdmafec.c
+++ /dev/null
@@ -1,592 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * (C) Copyright 2000-2004
- * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
- *
- * (C) Copyright 2007 Freescale Semiconductor, Inc.
- * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
- *
- * Conversion to DM
- * (C) 2019 Angelo Dureghello <angelo.dureghello@timesys.com>
- */
-
-#include <common.h>
-#include <env.h>
-#include <hang.h>
-#include <malloc.h>
-#include <command.h>
-#include <config.h>
-#include <net.h>
-#include <miiphy.h>
-#include <asm/global_data.h>
-#include <linux/delay.h>
-#include <linux/mii.h>
-#include <asm/immap.h>
-#include <asm/fsl_mcdmafec.h>
-
-#include "MCD_dma.h"
-
-#undef ET_DEBUG
-#undef MII_DEBUG
-
-/* Ethernet Transmit and Receive Buffers */
-#define DBUF_LENGTH 1520
-#define PKT_MAXBUF_SIZE 1518
-#define FIFO_ERRSTAT (FIFO_STAT_RXW | FIFO_STAT_UF | FIFO_STAT_OF)
-
-/* RxBD bits definitions */
-#define BD_ENET_RX_ERR (BD_ENET_RX_LG | BD_ENET_RX_NO | BD_ENET_RX_CR | \
- BD_ENET_RX_OV | BD_ENET_RX_TR)
-
-DECLARE_GLOBAL_DATA_PTR;
-
-static void init_eth_info(struct fec_info_dma *info)
-{
- /* setup Receive and Transmit buffer descriptor */
-#ifdef CFG_SYS_FEC_BUF_USE_SRAM
- static u32 tmp;
-
- if (info->index == 0)
- tmp = CFG_SYS_INIT_RAM_ADDR + 0x1000;
- else
- info->rxbd = (cbd_t *)DBUF_LENGTH;
-
- info->rxbd = (cbd_t *)((u32)info->rxbd + tmp);
- tmp = (u32)info->rxbd;
- info->txbd =
- (cbd_t *)((u32)info->txbd + tmp +
- (PKTBUFSRX * sizeof(cbd_t)));
- tmp = (u32)info->txbd;
- info->txbuf =
- (char *)((u32)info->txbuf + tmp +
- (CFG_SYS_TX_ETH_BUFFER * sizeof(cbd_t)));
- tmp = (u32)info->txbuf;
-#else
- info->rxbd =
- (cbd_t *)memalign(CONFIG_SYS_CACHELINE_SIZE,
- (PKTBUFSRX * sizeof(cbd_t)));
- info->txbd =
- (cbd_t *)memalign(CONFIG_SYS_CACHELINE_SIZE,
- (CFG_SYS_TX_ETH_BUFFER * sizeof(cbd_t)));
- info->txbuf =
- (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, DBUF_LENGTH);
-#endif
-
-#ifdef ET_DEBUG
- printf("rxbd %x txbd %x\n", (int)info->rxbd, (int)info->txbd);
-#endif
- info->phy_name = (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, 32);
-}
-
-static void fec_halt(struct udevice *dev)
-{
- struct fec_info_dma *info = dev_get_priv(dev);
- volatile fecdma_t *fecp = (fecdma_t *)info->iobase;
- int counter = 0xffff;
-
- /* issue graceful stop command to the FEC transmitter if necessary */
- fecp->tcr |= FEC_TCR_GTS;
-
- /* wait for graceful stop to register */
- while ((counter--) && (!(fecp->eir & FEC_EIR_GRA)))
- ;
-
- /* Disable DMA tasks */
- MCD_killDma(info->tx_task);
- MCD_killDma(info->rx_task);
-
- /* Disable the Ethernet Controller */
- fecp->ecr &= ~FEC_ECR_ETHER_EN;
-
- /* Clear FIFO status registers */
- fecp->rfsr &= FIFO_ERRSTAT;
- fecp->tfsr &= FIFO_ERRSTAT;
-
- fecp->frst = 0x01000000;
-
- /* Issue a reset command to the FEC chip */
- fecp->ecr |= FEC_ECR_RESET;
-
- /* wait at least 20 clock cycles */
- mdelay(10);
-
-#ifdef ET_DEBUG
- printf("Ethernet task stopped\n");
-#endif
-}
-
-#ifdef ET_DEBUG
-static void dbg_fec_regs(struct eth_device *dev)
-{
- struct fec_info_dma *info = dev->priv;
- volatile fecdma_t *fecp = (fecdma_t *)info->iobase;
-
- printf("=====\n");
- printf("ievent %x - %x\n", (int)&fecp->eir, fecp->eir);
- printf("imask %x - %x\n", (int)&fecp->eimr, fecp->eimr);
- printf("ecntrl %x - %x\n", (int)&fecp->ecr, fecp->ecr);
- printf("mii_mframe %x - %x\n", (int)&fecp->mmfr, fecp->mmfr);
- printf("mii_speed %x - %x\n", (int)&fecp->mscr, fecp->mscr);
- printf("mii_ctrlstat %x - %x\n", (int)&fecp->mibc, fecp->mibc);
- printf("r_cntrl %x - %x\n", (int)&fecp->rcr, fecp->rcr);
- printf("r hash %x - %x\n", (int)&fecp->rhr, fecp->rhr);
- printf("x_cntrl %x - %x\n", (int)&fecp->tcr, fecp->tcr);
- printf("padr_l %x - %x\n", (int)&fecp->palr, fecp->palr);
- printf("padr_u %x - %x\n", (int)&fecp->paur, fecp->paur);
- printf("op_pause %x - %x\n", (int)&fecp->opd, fecp->opd);
- printf("iadr_u %x - %x\n", (int)&fecp->iaur, fecp->iaur);
- printf("iadr_l %x - %x\n", (int)&fecp->ialr, fecp->ialr);
- printf("gadr_u %x - %x\n", (int)&fecp->gaur, fecp->gaur);
- printf("gadr_l %x - %x\n", (int)&fecp->galr, fecp->galr);
- printf("x_wmrk %x - %x\n", (int)&fecp->tfwr, fecp->tfwr);
- printf("r_fdata %x - %x\n", (int)&fecp->rfdr, fecp->rfdr);
- printf("r_fstat %x - %x\n", (int)&fecp->rfsr, fecp->rfsr);
- printf("r_fctrl %x - %x\n", (int)&fecp->rfcr, fecp->rfcr);
- printf("r_flrfp %x - %x\n", (int)&fecp->rlrfp, fecp->rlrfp);
- printf("r_flwfp %x - %x\n", (int)&fecp->rlwfp, fecp->rlwfp);
- printf("r_frfar %x - %x\n", (int)&fecp->rfar, fecp->rfar);
- printf("r_frfrp %x - %x\n", (int)&fecp->rfrp, fecp->rfrp);
- printf("r_frfwp %x - %x\n", (int)&fecp->rfwp, fecp->rfwp);
- printf("t_fdata %x - %x\n", (int)&fecp->tfdr, fecp->tfdr);
- printf("t_fstat %x - %x\n", (int)&fecp->tfsr, fecp->tfsr);
- printf("t_fctrl %x - %x\n", (int)&fecp->tfcr, fecp->tfcr);
- printf("t_flrfp %x - %x\n", (int)&fecp->tlrfp, fecp->tlrfp);
- printf("t_flwfp %x - %x\n", (int)&fecp->tlwfp, fecp->tlwfp);
- printf("t_ftfar %x - %x\n", (int)&fecp->tfar, fecp->tfar);
- printf("t_ftfrp %x - %x\n", (int)&fecp->tfrp, fecp->tfrp);
- printf("t_ftfwp %x - %x\n", (int)&fecp->tfwp, fecp->tfwp);
- printf("frst %x - %x\n", (int)&fecp->frst, fecp->frst);
- printf("ctcwr %x - %x\n", (int)&fecp->ctcwr, fecp->ctcwr);
-}
-#endif
-
-static void set_fec_duplex_speed(volatile fecdma_t *fecp, int dup_spd)
-{
- struct bd_info *bd = gd->bd;
-
- if ((dup_spd >> 16) == FULL) {
- /* Set maximum frame length */
- fecp->rcr = FEC_RCR_MAX_FL(PKT_MAXBUF_SIZE) | FEC_RCR_MII_MODE |
- FEC_RCR_PROM | 0x100;
- fecp->tcr = FEC_TCR_FDEN;
- } else {
- /* Half duplex mode */
- fecp->rcr = FEC_RCR_MAX_FL(PKT_MAXBUF_SIZE) |
- FEC_RCR_MII_MODE | FEC_RCR_DRT;
- fecp->tcr &= ~FEC_TCR_FDEN;
- }
-
- if ((dup_spd & 0xFFFF) == _100BASET) {
-#ifdef MII_DEBUG
- printf("100Mbps\n");
-#endif
- bd->bi_ethspeed = 100;
- } else {
-#ifdef MII_DEBUG
- printf("10Mbps\n");
-#endif
- bd->bi_ethspeed = 10;
- }
-}
-
-static void fec_set_hwaddr(volatile fecdma_t *fecp, u8 *mac)
-{
- u8 curr_byte; /* byte for which to compute the CRC */
- int byte; /* loop - counter */
- int bit; /* loop - counter */
- u32 crc = 0xffffffff; /* initial value */
-
- for (byte = 0; byte < 6; byte++) {
- curr_byte = mac[byte];
- for (bit = 0; bit < 8; bit++) {
- if ((curr_byte & 0x01) ^ (crc & 0x01)) {
- crc >>= 1;
- crc = crc ^ 0xedb88320;
- } else {
- crc >>= 1;
- }
- curr_byte >>= 1;
- }
- }
-
- crc = crc >> 26;
-
- /* Set individual hash table register */
- if (crc >= 32) {
- fecp->ialr = (1 << (crc - 32));
- fecp->iaur = 0;
- } else {
- fecp->ialr = 0;
- fecp->iaur = (1 << crc);
- }
-
- /* Set physical address */
- fecp->palr = (mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3];
- fecp->paur = (mac[4] << 24) + (mac[5] << 16) + 0x8808;
-
- /* Clear multicast address hash table */
- fecp->gaur = 0;
- fecp->galr = 0;
-}
-
-static int fec_init(struct udevice *dev)
-{
- struct fec_info_dma *info = dev_get_priv(dev);
- volatile fecdma_t *fecp = (fecdma_t *)info->iobase;
- int rval, i;
- uchar enetaddr[6];
-
-#ifdef ET_DEBUG
- printf("fec_init: iobase 0x%08x ...\n", info->iobase);
-#endif
-
- fecpin_setclear(info, 1);
- fec_halt(dev);
-
- mii_init();
- set_fec_duplex_speed(fecp, info->dup_spd);
-
- /* We use strictly polling mode only */
- fecp->eimr = 0;
-
- /* Clear any pending interrupt */
- fecp->eir = 0xffffffff;
-
- /* Set station address */
- if (info->index == 0)
- rval = eth_env_get_enetaddr("ethaddr", enetaddr);
- else
- rval = eth_env_get_enetaddr("eth1addr", enetaddr);
-
- if (!rval) {
- puts("Please set a valid MAC address\n");
- return -EINVAL;
- }
-
- fec_set_hwaddr(fecp, enetaddr);
-
- /* Set Opcode/Pause Duration Register */
- fecp->opd = 0x00010020;
-
- /* Setup Buffers and Buffer Descriptors */
- info->rx_idx = 0;
- info->tx_idx = 0;
-
- /* Setup Receiver Buffer Descriptors (13.14.24.18)
- * Settings: Empty, Wrap */
- for (i = 0; i < PKTBUFSRX; i++) {
- info->rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
- info->rxbd[i].cbd_datlen = PKTSIZE_ALIGN;
- info->rxbd[i].cbd_bufaddr = (uint) net_rx_packets[i];
- }
- info->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
-
- /* Setup Ethernet Transmitter Buffer Descriptors (13.14.24.19)
- * Settings: Last, Tx CRC */
- for (i = 0; i < CFG_SYS_TX_ETH_BUFFER; i++) {
- info->txbd[i].cbd_sc = 0;
- info->txbd[i].cbd_datlen = 0;
- info->txbd[i].cbd_bufaddr = (uint) (&info->txbuf[0]);
- }
- info->txbd[CFG_SYS_TX_ETH_BUFFER - 1].cbd_sc |= BD_ENET_TX_WRAP;
-
- info->used_tbd_idx = 0;
- info->clean_tbd_num = CFG_SYS_TX_ETH_BUFFER;
-
- /* Set Rx FIFO alarm and granularity value */
- fecp->rfcr = 0x0c000000;
- fecp->rfar = 0x0000030c;
-
- /* Set Tx FIFO granularity value */
- fecp->tfcr = FIFO_CTRL_FRAME | FIFO_CTRL_GR(6) | 0x00040000;
- fecp->tfar = 0x00000080;
-
- fecp->tfwr = 0x2;
- fecp->ctcwr = 0x03000000;
-
- /* Enable DMA receive task */
- MCD_startDma(info->rx_task,
- (s8 *)info->rxbd,
- 0,
- (s8 *)&fecp->rfdr,
- 4,
- 0,
- 4,
- info->rx_init,
- info->rx_pri,
- (MCD_FECRX_DMA | MCD_TT_FLAGS_DEF),
- (MCD_NO_CSUM | MCD_NO_BYTE_SWAP)
- );
-
- /* Enable DMA tx task with no ready buffer descriptors */
- MCD_startDma(info->tx_task,
- (s8 *)info->txbd,
- 0,
- (s8 *)&fecp->tfdr,
- 4,
- 0,
- 4,
- info->tx_init,
- info->tx_pri,
- (MCD_FECTX_DMA | MCD_TT_FLAGS_DEF),
- (MCD_NO_CSUM | MCD_NO_BYTE_SWAP)
- );
-
- /* Now enable the transmit and receive processing */
- fecp->ecr |= FEC_ECR_ETHER_EN;
-
- return 0;
-}
-
-static int mcdmafec_init(struct udevice *dev)
-{
- return fec_init(dev);
-}
-
-static int mcdmafec_send(struct udevice *dev, void *packet, int length)
-{
- struct fec_info_dma *info = dev_get_priv(dev);
- cbd_t *p_tbd, *p_used_tbd;
- u16 phy_status;
-
- miiphy_read(dev->name, info->phy_addr, MII_BMSR, &phy_status);
-
- /* process all the consumed TBDs */
- while (info->clean_tbd_num < CFG_SYS_TX_ETH_BUFFER) {
- p_used_tbd = &info->txbd[info->used_tbd_idx];
- if (p_used_tbd->cbd_sc & BD_ENET_TX_READY) {
-#ifdef ET_DEBUG
- printf("Cannot clean TBD %d, in use\n",
- info->clean_tbd_num);
-#endif
- return 0;
- }
-
- /* clean this buffer descriptor */
- if (info->used_tbd_idx == (CFG_SYS_TX_ETH_BUFFER - 1))
- p_used_tbd->cbd_sc = BD_ENET_TX_WRAP;
- else
- p_used_tbd->cbd_sc = 0;
-
- /* update some indeces for a correct handling of TBD ring */
- info->clean_tbd_num++;
- info->used_tbd_idx = (info->used_tbd_idx + 1)
- % CFG_SYS_TX_ETH_BUFFER;
- }
-
- /* Check for valid length of data. */
- if (length > 1500 || length <= 0)
- return -1;
-
- /* Check the number of vacant TxBDs. */
- if (info->clean_tbd_num < 1) {
- printf("No available TxBDs ...\n");
- return -1;
- }
-
- /* Get the first TxBD to send the mac header */
- p_tbd = &info->txbd[info->tx_idx];
- p_tbd->cbd_datlen = length;
- p_tbd->cbd_bufaddr = (u32)packet;
- p_tbd->cbd_sc |= BD_ENET_TX_LAST | BD_ENET_TX_TC | BD_ENET_TX_READY;
- info->tx_idx = (info->tx_idx + 1) % CFG_SYS_TX_ETH_BUFFER;
-
- /* Enable DMA transmit task */
- MCD_continDma(info->tx_task);
-
- info->clean_tbd_num -= 1;
-
- /* wait until frame is sent . */
- while (p_tbd->cbd_sc & BD_ENET_TX_READY)
- udelay(10);
-
- return (int)(info->txbd[info->tx_idx].cbd_sc & BD_ENET_TX_STATS);
-}
-
-static int mcdmafec_recv(struct udevice *dev, int flags, uchar **packetp)
-{
- struct fec_info_dma *info = dev_get_priv(dev);
- volatile fecdma_t *fecp = (fecdma_t *)info->iobase;
-
- cbd_t *prbd = &info->rxbd[info->rx_idx];
- u32 ievent;
- int frame_length, len = 0;
-
- /* Check if any critical events have happened */
- ievent = fecp->eir;
- if (ievent != 0) {
- fecp->eir = ievent;
-
- if (ievent & (FEC_EIR_BABT | FEC_EIR_TXERR | FEC_EIR_RXERR)) {
- printf("fec_recv: error\n");
- fec_halt(dev);
- fec_init(dev);
- return 0;
- }
-
- if (ievent & FEC_EIR_HBERR) {
- /* Heartbeat error */
- fecp->tcr |= FEC_TCR_GTS;
- }
-
- if (ievent & FEC_EIR_GRA) {
- /* Graceful stop complete */
- if (fecp->tcr & FEC_TCR_GTS) {
- printf("fec_recv: tcr_gts\n");
- fec_halt(dev);
- fecp->tcr &= ~FEC_TCR_GTS;
- fec_init(dev);
- }
- }
- }
-
- if (!(prbd->cbd_sc & BD_ENET_RX_EMPTY)) {
- if ((prbd->cbd_sc & BD_ENET_RX_LAST) &&
- !(prbd->cbd_sc & BD_ENET_RX_ERR) &&
- ((prbd->cbd_datlen - 4) > 14)) {
- /* Get buffer address and size */
- frame_length = prbd->cbd_datlen - 4;
-
- /* Fill the buffer and pass it to upper layers */
- net_process_received_packet((uchar *)prbd->cbd_bufaddr,
- frame_length);
- len = frame_length;
- }
-
- /* Reset buffer descriptor as empty */
- if (info->rx_idx == (PKTBUFSRX - 1))
- prbd->cbd_sc = (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY);
- else
- prbd->cbd_sc = BD_ENET_RX_EMPTY;
-
- prbd->cbd_datlen = PKTSIZE_ALIGN;
-
- /* Now, we have an empty RxBD, restart the DMA receive task */
- MCD_continDma(info->rx_task);
-
- /* Increment BD count */
- info->rx_idx = (info->rx_idx + 1) % PKTBUFSRX;
- }
-
- return len;
-}
-
-static void mcdmafec_halt(struct udevice *dev)
-{
- fec_halt(dev);
-}
-
-static const struct eth_ops mcdmafec_ops = {
- .start = mcdmafec_init,
- .send = mcdmafec_send,
- .recv = mcdmafec_recv,
- .stop = mcdmafec_halt,
-};
-
-/*
- * Boot sequence, called just after mcffec_of_to_plat,
- * as DM way, it replaces old mcffec_initialize.
- */
-static int mcdmafec_probe(struct udevice *dev)
-{
- struct fec_info_dma *info = dev_get_priv(dev);
- struct eth_pdata *pdata = dev_get_plat(dev);
- int node = dev_of_offset(dev);
- int retval;
- const u32 *val;
-
- info->index = dev_seq(dev);
- info->iobase = pdata->iobase;
- info->miibase = pdata->iobase;
- info->phy_addr = -1;
-
- val = fdt_getprop(gd->fdt_blob, node, "rx-task", NULL);
- if (val)
- info->rx_task = fdt32_to_cpu(*val);
-
- val = fdt_getprop(gd->fdt_blob, node, "tx-task", NULL);
- if (val)
- info->tx_task = fdt32_to_cpu(*val);
-
- val = fdt_getprop(gd->fdt_blob, node, "rx-prioprity", NULL);
- if (val)
- info->rx_pri = fdt32_to_cpu(*val);
-
- val = fdt_getprop(gd->fdt_blob, node, "tx-prioprity", NULL);
- if (val)
- info->tx_pri = fdt32_to_cpu(*val);
-
- val = fdt_getprop(gd->fdt_blob, node, "rx-init", NULL);
- if (val)
- info->rx_init = fdt32_to_cpu(*val);
-
- val = fdt_getprop(gd->fdt_blob, node, "tx-init", NULL);
- if (val)
- info->tx_init = fdt32_to_cpu(*val);
-
-#ifdef CFG_SYS_FEC_BUF_USE_SRAM
- u32 tmp = CFG_SYS_INIT_RAM_ADDR + 0x1000;
-#endif
- init_eth_info(info);
-
-#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
- info->bus = mdio_alloc();
- if (!info->bus)
- return -ENOMEM;
- strlcpy(info->bus->name, dev->name, MDIO_NAME_LEN);
- info->bus->read = mcffec_miiphy_read;
- info->bus->write = mcffec_miiphy_write;
-
- retval = mdio_register(info->bus);
- if (retval < 0)
- return retval;
-#endif
-
- return 0;
-}
-
-static int mcdmafec_remove(struct udevice *dev)
-{
- struct fec_info_dma *priv = dev_get_priv(dev);
-
- mdio_unregister(priv->bus);
- mdio_free(priv->bus);
-
- return 0;
-}
-
-/*
- * Boot sequence, called 1st
- */
-static int mcdmafec_of_to_plat(struct udevice *dev)
-{
- struct eth_pdata *pdata = dev_get_plat(dev);
- const u32 *val;
-
- pdata->iobase = dev_read_addr(dev);
- /* Default to 10Mbit/s */
- pdata->max_speed = 10;
-
- val = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "max-speed", NULL);
- if (val)
- pdata->max_speed = fdt32_to_cpu(*val);
-
- return 0;
-}
-
-static const struct udevice_id mcdmafec_ids[] = {
- { .compatible = "fsl,mcf-dma-fec" },
- { }
-};
-
-U_BOOT_DRIVER(mcffec) = {
- .name = "mcdmafec",
- .id = UCLASS_ETH,
- .of_match = mcdmafec_ids,
- .of_to_plat = mcdmafec_of_to_plat,
- .probe = mcdmafec_probe,
- .remove = mcdmafec_remove,
- .ops = &mcdmafec_ops,
- .priv_auto = sizeof(struct fec_info_dma),
- .plat_auto = sizeof(struct eth_pdata),
-};
diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c
index 587d3658fa9..9b536fd5ab8 100644
--- a/drivers/net/ftgmac100.c
+++ b/drivers/net/ftgmac100.c
@@ -13,6 +13,7 @@
#include <common.h>
#include <clk.h>
+#include <reset.h>
#include <cpu_func.h>
#include <dm.h>
#include <log.h>
@@ -91,6 +92,7 @@ struct ftgmac100_data {
u32 max_speed;
struct clk_bulk clks;
+ struct reset_ctl *reset_ctl;
/* End of RX/TX ring buffer bits. Depend on model */
u32 rxdes0_edorr_mask;
@@ -569,6 +571,8 @@ static int ftgmac100_of_to_plat(struct udevice *dev)
priv->txdes0_edotr_mask = BIT(15);
}
+ priv->reset_ctl = devm_reset_control_get_optional(dev, NULL);
+
return clk_get_bulk(dev, &priv->clks);
}
@@ -594,6 +598,12 @@ static int ftgmac100_probe(struct udevice *dev)
if (ret)
goto out;
+ if (priv->reset_ctl) {
+ ret = reset_deassert(priv->reset_ctl);
+ if (ret)
+ goto out;
+ }
+
/*
* If DM MDIO is enabled, the MDIO bus will be initialized later in
* dm_eth_phy_connect
@@ -629,6 +639,8 @@ static int ftgmac100_remove(struct udevice *dev)
free(priv->phydev);
mdio_unregister(priv->bus);
mdio_free(priv->bus);
+ if (priv->reset_ctl)
+ reset_assert(priv->reset_ctl);
clk_release_bulk(&priv->clks);
return 0;
diff --git a/drivers/net/hifemac.c b/drivers/net/hifemac.c
new file mode 100644
index 00000000000..b61a29e6360
--- /dev/null
+++ b/drivers/net/hifemac.c
@@ -0,0 +1,481 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Hisilicon Fast Ethernet MAC Driver
+ * Adapted from linux
+ *
+ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
+ * Copyright (c) 2023 Yang Xiwen <forbidden405@outlook.com>
+ */
+
+#include <dm.h>
+#include <clk.h>
+#include <miiphy.h>
+#include <net.h>
+#include <reset.h>
+#include <wait_bit.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+
+/* MAC control register list */
+#define MAC_PORTSEL 0x0200
+#define MAC_PORTSEL_STAT_CPU BIT(0)
+#define MAC_PORTSEL_RMII BIT(1)
+#define MAC_PORTSET 0x0208
+#define MAC_PORTSET_DUPLEX_FULL BIT(0)
+#define MAC_PORTSET_LINKED BIT(1)
+#define MAC_PORTSET_SPEED_100M BIT(2)
+#define MAC_SET 0x0210
+#define MAX_FRAME_SIZE 1600
+#define MAX_FRAME_SIZE_MASK GENMASK(10, 0)
+#define BIT_PAUSE_EN BIT(18)
+#define RX_COALESCE_SET 0x0340
+#define RX_COALESCED_FRAME_OFFSET 24
+#define RX_COALESCED_FRAMES 8
+#define RX_COALESCED_TIMER 0x74
+#define QLEN_SET 0x0344
+#define RX_DEPTH_OFFSET 8
+#define MAX_HW_FIFO_DEPTH 64
+#define HW_TX_FIFO_DEPTH 1
+#define MAX_HW_RX_FIFO_DEPTH (MAX_HW_FIFO_DEPTH - HW_TX_FIFO_DEPTH)
+#define HW_RX_FIFO_DEPTH min(PKTBUFSRX, MAX_HW_RX_FIFO_DEPTH)
+#define IQFRM_DES 0x0354
+#define RX_FRAME_LEN_MASK GENMASK(11, 0)
+#define RX_FRAME_IN_INDEX_MASK GENMASK(17, 12)
+#define IQ_ADDR 0x0358
+#define EQ_ADDR 0x0360
+#define EQFRM_LEN 0x0364
+#define ADDRQ_STAT 0x036C
+#define TX_CNT_INUSE_MASK GENMASK(5, 0)
+#define BIT_TX_READY BIT(24)
+#define BIT_RX_READY BIT(25)
+/* global control register list */
+#define GLB_HOSTMAC_L32 0x0000
+#define GLB_HOSTMAC_H16 0x0004
+#define GLB_SOFT_RESET 0x0008
+#define SOFT_RESET_ALL BIT(0)
+#define GLB_FWCTRL 0x0010
+#define FWCTRL_VLAN_ENABLE BIT(0)
+#define FWCTRL_FW2CPU_ENA BIT(5)
+#define FWCTRL_FWALL2CPU BIT(7)
+#define GLB_MACTCTRL 0x0014
+#define MACTCTRL_UNI2CPU BIT(1)
+#define MACTCTRL_MULTI2CPU BIT(3)
+#define MACTCTRL_BROAD2CPU BIT(5)
+#define MACTCTRL_MACT_ENA BIT(7)
+#define GLB_IRQ_STAT 0x0030
+#define GLB_IRQ_ENA 0x0034
+#define IRQ_ENA_PORT0_MASK GENMASK(7, 0)
+#define IRQ_ENA_PORT0 BIT(18)
+#define IRQ_ENA_ALL BIT(19)
+#define GLB_IRQ_RAW 0x0038
+#define IRQ_INT_RX_RDY BIT(0)
+#define IRQ_INT_TX_PER_PACKET BIT(1)
+#define IRQ_INT_TX_FIFO_EMPTY BIT(6)
+#define IRQ_INT_MULTI_RXRDY BIT(7)
+#define DEF_INT_MASK (IRQ_INT_MULTI_RXRDY | \
+ IRQ_INT_TX_PER_PACKET | \
+ IRQ_INT_TX_FIFO_EMPTY)
+#define GLB_MAC_L32_BASE 0x0100
+#define GLB_MAC_H16_BASE 0x0104
+#define MACFLT_HI16_MASK GENMASK(15, 0)
+#define BIT_MACFLT_ENA BIT(17)
+#define BIT_MACFLT_FW2CPU BIT(21)
+#define GLB_MAC_H16(reg) (GLB_MAC_H16_BASE + ((reg) * 0x8))
+#define GLB_MAC_L32(reg) (GLB_MAC_L32_BASE + ((reg) * 0x8))
+#define MAX_MAC_FILTER_NUM 8
+#define MAX_UNICAST_ADDRESSES 2
+#define MAX_MULTICAST_ADDRESSES (MAX_MAC_FILTER_NUM - \
+ MAX_UNICAST_ADDRESSES)
+/* software tx and rx queue number, should be power of 2 */
+#define TXQ_NUM 64
+#define RXQ_NUM 128
+
+#define PHY_RESET_DELAYS_PROPERTY "hisilicon,phy-reset-delays-us"
+#define MAC_RESET_DELAY_PROPERTY "hisilicon,mac-reset-delay-us"
+#define MAC_RESET_ASSERT_PERIOD 200000
+
+enum phy_reset_delays {
+ PRE_DELAY,
+ PULSE,
+ POST_DELAY,
+ DELAYS_NUM,
+};
+
+enum clk_type {
+ CLK_MAC,
+ CLK_BUS,
+ CLK_PHY,
+ CLK_NUM,
+};
+
+struct hisi_femac_priv {
+ void __iomem *port_base;
+ void __iomem *glb_base;
+ struct clk *clks[CLK_NUM];
+ struct reset_ctl *mac_rst;
+ struct reset_ctl *phy_rst;
+ u32 phy_reset_delays[DELAYS_NUM];
+ u32 mac_reset_delay;
+
+ struct phy_device *phy;
+
+ u32 link_status;
+};
+
+static void hisi_femac_irq_enable(struct hisi_femac_priv *priv, int irqs)
+{
+ u32 val;
+
+ val = readl(priv->glb_base + GLB_IRQ_ENA);
+ writel(val | irqs, priv->glb_base + GLB_IRQ_ENA);
+}
+
+static void hisi_femac_irq_disable(struct hisi_femac_priv *priv, int irqs)
+{
+ u32 val;
+
+ val = readl(priv->glb_base + GLB_IRQ_ENA);
+ writel(val & (~irqs), priv->glb_base + GLB_IRQ_ENA);
+}
+
+static void hisi_femac_port_init(struct hisi_femac_priv *priv)
+{
+ u32 val;
+
+ /* MAC gets link status info and phy mode by software config */
+ val = MAC_PORTSEL_STAT_CPU;
+ if (priv->phy->interface == PHY_INTERFACE_MODE_RMII)
+ val |= MAC_PORTSEL_RMII;
+ writel(val, priv->port_base + MAC_PORTSEL);
+
+ /*clear all interrupt status */
+ writel(IRQ_ENA_PORT0_MASK, priv->glb_base + GLB_IRQ_RAW);
+ hisi_femac_irq_disable(priv, IRQ_ENA_PORT0_MASK | IRQ_ENA_PORT0);
+
+ val = readl(priv->glb_base + GLB_FWCTRL);
+ val &= ~(FWCTRL_VLAN_ENABLE | FWCTRL_FWALL2CPU);
+ val |= FWCTRL_FW2CPU_ENA;
+ writel(val, priv->glb_base + GLB_FWCTRL);
+
+ val = readl(priv->glb_base + GLB_MACTCTRL);
+ val |= (MACTCTRL_BROAD2CPU | MACTCTRL_MACT_ENA);
+ writel(val, priv->glb_base + GLB_MACTCTRL);
+
+ val = readl(priv->port_base + MAC_SET);
+ val &= ~MAX_FRAME_SIZE_MASK;
+ val |= MAX_FRAME_SIZE;
+ writel(val, priv->port_base + MAC_SET);
+
+ val = RX_COALESCED_TIMER |
+ (RX_COALESCED_FRAMES << RX_COALESCED_FRAME_OFFSET);
+ writel(val, priv->port_base + RX_COALESCE_SET);
+
+ val = (HW_RX_FIFO_DEPTH << RX_DEPTH_OFFSET) | HW_TX_FIFO_DEPTH;
+ writel(val, priv->port_base + QLEN_SET);
+}
+
+static void hisi_femac_rx_refill(struct hisi_femac_priv *priv)
+{
+ int i;
+ ulong addr;
+
+ for (i = 0; i < HW_RX_FIFO_DEPTH; i++) {
+ addr = (ulong)net_rx_packets[i];
+ writel(addr, priv->port_base + IQ_ADDR);
+ }
+}
+
+static void hisi_femac_adjust_link(struct udevice *dev)
+{
+ struct hisi_femac_priv *priv = dev_get_priv(dev);
+ struct phy_device *phy = priv->phy;
+ u32 status = 0;
+
+ if (phy->link)
+ status |= MAC_PORTSET_LINKED;
+ if (phy->duplex == DUPLEX_FULL)
+ status |= MAC_PORTSET_DUPLEX_FULL;
+ if (phy->speed == SPEED_100)
+ status |= MAC_PORTSET_SPEED_100M;
+
+ writel(status, priv->port_base + MAC_PORTSET);
+}
+
+static int hisi_femac_port_reset(struct hisi_femac_priv *priv)
+{
+ u32 val;
+
+ val = readl(priv->glb_base + GLB_SOFT_RESET);
+ val |= SOFT_RESET_ALL;
+ writel(val, priv->glb_base + GLB_SOFT_RESET);
+
+ udelay(800);
+
+ val &= ~SOFT_RESET_ALL;
+ writel(val, priv->glb_base + GLB_SOFT_RESET);
+
+ return 0;
+}
+
+static int hisi_femac_set_hw_mac_addr(struct udevice *dev)
+{
+ struct hisi_femac_priv *priv = dev_get_priv(dev);
+ struct eth_pdata *plat = dev_get_plat(dev);
+ unsigned char *mac = plat->enetaddr;
+ u32 reg;
+
+ reg = mac[1] | (mac[0] << 8);
+ writel(reg, priv->glb_base + GLB_HOSTMAC_H16);
+
+ reg = mac[5] | (mac[4] << 8) | (mac[3] << 16) | (mac[2] << 24);
+ writel(reg, priv->glb_base + GLB_HOSTMAC_L32);
+
+ return 0;
+}
+
+static int hisi_femac_start(struct udevice *dev)
+{
+ int ret;
+ struct hisi_femac_priv *priv = dev_get_priv(dev);
+
+ hisi_femac_port_reset(priv);
+ hisi_femac_set_hw_mac_addr(dev);
+ hisi_femac_rx_refill(priv);
+
+ ret = phy_startup(priv->phy);
+ if (ret)
+ return log_msg_ret("Failed to startup phy", ret);
+
+ if (!priv->phy->link) {
+ debug("%s: link down\n", __func__);
+ return -ENODEV;
+ }
+
+ hisi_femac_adjust_link(dev);
+
+ writel(IRQ_ENA_PORT0_MASK, priv->glb_base + GLB_IRQ_RAW);
+ hisi_femac_irq_enable(priv, IRQ_ENA_ALL | IRQ_ENA_PORT0 | DEF_INT_MASK);
+
+ return 0;
+}
+
+static int hisi_femac_send(struct udevice *dev, void *packet, int length)
+{
+ struct hisi_femac_priv *priv = dev_get_priv(dev);
+ ulong addr = (ulong)packet;
+ int ret;
+
+ // clear previous irq
+ writel(IRQ_INT_TX_PER_PACKET, priv->glb_base + GLB_IRQ_RAW);
+
+ // flush cache
+ flush_cache(addr, length + ETH_FCS_LEN);
+
+ // write packet address
+ writel(addr, priv->port_base + EQ_ADDR);
+
+ // write packet length (and send it)
+ writel(length + ETH_FCS_LEN, priv->port_base + EQFRM_LEN);
+
+ // wait until FIFO is empty
+ ret = wait_for_bit_le32(priv->glb_base + GLB_IRQ_RAW, IRQ_INT_TX_PER_PACKET, true, 50, false);
+ if (ret == -ETIMEDOUT)
+ return log_msg_ret("FIFO timeout", ret);
+
+ return 0;
+}
+
+static int hisi_femac_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct hisi_femac_priv *priv = dev_get_priv(dev);
+ int val, index, length;
+
+ val = readl(priv->glb_base + GLB_IRQ_RAW);
+ if (!(val & IRQ_INT_RX_RDY))
+ return -EAGAIN;
+
+ val = readl(priv->port_base + IQFRM_DES);
+ index = (val & RX_FRAME_IN_INDEX_MASK) >> 12;
+ length = val & RX_FRAME_LEN_MASK;
+
+ // invalidate cache
+ invalidate_dcache_range((ulong)net_rx_packets[index], (ulong)net_rx_packets[index] + length);
+ *packetp = net_rx_packets[index];
+
+ // Tell hardware we will process the packet
+ writel(IRQ_INT_RX_RDY, priv->glb_base + GLB_IRQ_RAW);
+
+ return length;
+}
+
+static int hisi_femac_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+ struct hisi_femac_priv *priv = dev_get_priv(dev);
+ ulong addr = (ulong)packet;
+
+ // Tell hardware the packet can be reused
+ writel(addr, priv->port_base + IQ_ADDR);
+
+ return 0;
+}
+
+static void hisi_femac_stop(struct udevice *dev)
+{
+ struct hisi_femac_priv *priv = dev_get_priv(dev);
+
+ // assert internal reset
+ writel(SOFT_RESET_ALL, priv->glb_base + GLB_SOFT_RESET);
+}
+
+int hisi_femac_of_to_plat(struct udevice *dev)
+{
+ int ret, i;
+ struct hisi_femac_priv *priv = dev_get_priv(dev);
+ static const char * const clk_strs[] = {
+ [CLK_MAC] = "mac",
+ [CLK_BUS] = "bus",
+ [CLK_PHY] = "phy",
+ };
+
+ priv->port_base = dev_remap_addr_name(dev, "port");
+ if (IS_ERR(priv->port_base))
+ return log_msg_ret("Failed to remap port address space", PTR_ERR(priv->port_base));
+
+ priv->glb_base = dev_remap_addr_name(dev, "glb");
+ if (IS_ERR(priv->glb_base))
+ return log_msg_ret("Failed to remap global address space", PTR_ERR(priv->glb_base));
+
+ for (i = 0; i < ARRAY_SIZE(clk_strs); i++) {
+ priv->clks[i] = devm_clk_get(dev, clk_strs[i]);
+ if (IS_ERR(priv->clks[i])) {
+ dev_err(dev, "Error getting clock %s\n", clk_strs[i]);
+ return log_msg_ret("Failed to get clocks", PTR_ERR(priv->clks[i]));
+ }
+ }
+
+ priv->mac_rst = devm_reset_control_get(dev, "mac");
+ if (IS_ERR(priv->mac_rst))
+ return log_msg_ret("Failed to get MAC reset", PTR_ERR(priv->mac_rst));
+
+ priv->phy_rst = devm_reset_control_get(dev, "phy");
+ if (IS_ERR(priv->phy_rst))
+ return log_msg_ret("Failed to get PHY reset", PTR_ERR(priv->phy_rst));
+
+ ret = dev_read_u32_array(dev,
+ PHY_RESET_DELAYS_PROPERTY,
+ priv->phy_reset_delays,
+ DELAYS_NUM);
+ if (ret < 0)
+ return log_msg_ret("Failed to get PHY reset delays", ret);
+
+ priv->mac_reset_delay = dev_read_u32_default(dev,
+ MAC_RESET_DELAY_PROPERTY,
+ MAC_RESET_ASSERT_PERIOD);
+
+ return 0;
+}
+
+static int hisi_femac_phy_reset(struct hisi_femac_priv *priv)
+{
+ struct reset_ctl *rst = priv->phy_rst;
+ u32 *delays = priv->phy_reset_delays;
+ int ret;
+
+ // Disable MAC clk before phy reset
+ ret = clk_disable(priv->clks[CLK_MAC]);
+ if (ret < 0)
+ return log_msg_ret("Failed to disable MAC clock", ret);
+ ret = clk_disable(priv->clks[CLK_BUS]);
+ if (ret < 0)
+ return log_msg_ret("Failed to disable bus clock", ret);
+
+ udelay(delays[PRE_DELAY]);
+
+ ret = reset_assert(rst);
+ if (ret < 0)
+ return log_msg_ret("Failed to assert reset", ret);
+
+ udelay(delays[PULSE]);
+
+ ret = reset_deassert(rst);
+ if (ret < 0)
+ return log_msg_ret("Failed to deassert reset", ret);
+
+ udelay(delays[POST_DELAY]);
+
+ ret = clk_enable(priv->clks[CLK_MAC]);
+ if (ret < 0)
+ return log_msg_ret("Failed to enable MAC clock", ret);
+ ret = clk_enable(priv->clks[CLK_BUS]);
+ if (ret < 0)
+ return log_msg_ret("Failed to enable MAC bus clock", ret);
+
+ return 0;
+}
+
+int hisi_femac_probe(struct udevice *dev)
+{
+ struct hisi_femac_priv *priv = dev_get_priv(dev);
+ int ret, i;
+
+ // Enable clocks
+ for (i = 0; i < CLK_NUM; i++) {
+ ret = clk_prepare_enable(priv->clks[i]);
+ if (ret < 0)
+ return log_msg_ret("Failed to enable clks", ret);
+ }
+
+ // Reset MAC
+ ret = reset_assert(priv->mac_rst);
+ if (ret < 0)
+ return log_msg_ret("Failed to assert MAC reset", ret);
+
+ udelay(priv->mac_reset_delay);
+
+ ret = reset_deassert(priv->mac_rst);
+ if (ret < 0)
+ return log_msg_ret("Failed to deassert MAC reset", ret);
+
+ // Reset PHY
+ ret = hisi_femac_phy_reset(priv);
+ if (ret < 0)
+ return log_msg_ret("Failed to reset phy", ret);
+
+ // Connect to PHY
+ priv->phy = dm_eth_phy_connect(dev);
+ if (!priv->phy)
+ return log_msg_ret("Failed to connect to phy", -EINVAL);
+
+ hisi_femac_port_init(priv);
+ return 0;
+}
+
+static const struct eth_ops hisi_femac_ops = {
+ .start = hisi_femac_start,
+ .send = hisi_femac_send,
+ .recv = hisi_femac_recv,
+ .free_pkt = hisi_femac_free_pkt,
+ .stop = hisi_femac_stop,
+ .write_hwaddr = hisi_femac_set_hw_mac_addr,
+};
+
+static const struct udevice_id hisi_femac_ids[] = {
+ {.compatible = "hisilicon,hisi-femac-v1",},
+ {.compatible = "hisilicon,hisi-femac-v2",},
+ {.compatible = "hisilicon,hi3516cv300-femac",},
+ {.compatible = "hisilicon,hi3798mv200-femac",},
+ {},
+};
+
+U_BOOT_DRIVER(hisi_femac_driver) = {
+ .name = "eth_hisi_femac",
+ .id = UCLASS_ETH,
+ .of_match = of_match_ptr(hisi_femac_ids),
+ .of_to_plat = hisi_femac_of_to_plat,
+ .ops = &hisi_femac_ops,
+ .probe = hisi_femac_probe,
+ .plat_auto = sizeof(struct eth_pdata),
+ .priv_auto = sizeof(struct hisi_femac_priv),
+};
diff --git a/drivers/net/hifemac_mdio.c b/drivers/net/hifemac_mdio.c
new file mode 100644
index 00000000000..343c5f3a38a
--- /dev/null
+++ b/drivers/net/hifemac_mdio.c
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Hisilicon Fast Ethernet MDIO Bus Driver
+ *
+ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
+ */
+
+#include <dm.h>
+#include <clk.h>
+#include <miiphy.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+
+#define MDIO_RWCTRL 0x00
+#define MDIO_RO_DATA 0x04
+#define MDIO_WRITE BIT(13)
+#define MDIO_RW_FINISH BIT(15)
+#define BIT_PHY_ADDR_OFFSET 8
+#define BIT_WR_DATA_OFFSET 16
+
+struct hisi_femac_mdio_data {
+ struct clk *clk;
+ void __iomem *membase;
+};
+
+static int hisi_femac_mdio_wait_ready(struct hisi_femac_mdio_data *data)
+{
+ u32 val;
+
+ return readl_poll_timeout(data->membase + MDIO_RWCTRL,
+ val, val & MDIO_RW_FINISH, 10000);
+}
+
+static int hisi_femac_mdio_read(struct udevice *dev, int addr, int devad, int reg)
+{
+ struct hisi_femac_mdio_data *data = dev_get_priv(dev);
+ int ret;
+
+ ret = hisi_femac_mdio_wait_ready(data);
+ if (ret)
+ return ret;
+
+ writel((addr << BIT_PHY_ADDR_OFFSET) | reg,
+ data->membase + MDIO_RWCTRL);
+
+ ret = hisi_femac_mdio_wait_ready(data);
+ if (ret)
+ return ret;
+
+ return readl(data->membase + MDIO_RO_DATA) & 0xFFFF;
+}
+
+static int hisi_femac_mdio_write(struct udevice *dev, int addr, int devad, int reg, u16 val)
+{
+ struct hisi_femac_mdio_data *data = dev_get_priv(dev);
+ int ret;
+
+ ret = hisi_femac_mdio_wait_ready(data);
+ if (ret)
+ return ret;
+
+ writel(MDIO_WRITE | (val << BIT_WR_DATA_OFFSET) |
+ (addr << BIT_PHY_ADDR_OFFSET) | reg,
+ data->membase + MDIO_RWCTRL);
+
+ return hisi_femac_mdio_wait_ready(data);
+}
+
+static int hisi_femac_mdio_of_to_plat(struct udevice *dev)
+{
+ struct hisi_femac_mdio_data *data = dev_get_priv(dev);
+ int ret;
+
+ data->membase = dev_remap_addr(dev);
+ if (IS_ERR(data->membase)) {
+ ret = PTR_ERR(data->membase);
+ return log_msg_ret("Failed to remap base addr", ret);
+ }
+
+ // clk is optional
+ data->clk = devm_clk_get_optional(dev, NULL);
+
+ return 0;
+}
+
+static int hisi_femac_mdio_probe(struct udevice *dev)
+{
+ struct hisi_femac_mdio_data *data = dev_get_priv(dev);
+ int ret;
+
+ ret = clk_prepare_enable(data->clk);
+ if (ret)
+ return log_msg_ret("Failed to enable clk", ret);
+
+ return 0;
+}
+
+static const struct mdio_ops hisi_femac_mdio_ops = {
+ .read = hisi_femac_mdio_read,
+ .write = hisi_femac_mdio_write,
+};
+
+static const struct udevice_id hisi_femac_mdio_dt_ids[] = {
+ { .compatible = "hisilicon,hisi-femac-mdio" },
+ { }
+};
+
+U_BOOT_DRIVER(hisi_femac_mdio_driver) = {
+ .name = "hisi-femac-mdio",
+ .id = UCLASS_MDIO,
+ .of_match = hisi_femac_mdio_dt_ids,
+ .of_to_plat = hisi_femac_mdio_of_to_plat,
+ .probe = hisi_femac_mdio_probe,
+ .ops = &hisi_femac_mdio_ops,
+ .priv_auto = sizeof(struct hisi_femac_mdio_data),
+};
diff --git a/drivers/net/mv88e6xxx.c b/drivers/net/mv88e6xxx.c
index 64e860e324d..c073f81e72d 100644
--- a/drivers/net/mv88e6xxx.c
+++ b/drivers/net/mv88e6xxx.c
@@ -29,6 +29,7 @@
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/of_extra.h>
+#include <linux/bitfield.h>
#include <linux/delay.h>
#include <miiphy.h>
#include <net/dsa.h>
@@ -110,20 +111,35 @@
*/
#define SMI_BUSY BIT(15)
#define SMI_CMD_CLAUSE_22 BIT(12)
-#define SMI_CMD_CLAUSE_22_OP_READ (2 << 10)
-#define SMI_CMD_CLAUSE_22_OP_WRITE (1 << 10)
-#define SMI_CMD_ADDR_SHIFT 5
-#define SMI_CMD_ADDR_MASK 0x1f
-#define SMI_CMD_REG_SHIFT 0
-#define SMI_CMD_REG_MASK 0x1f
+#define SMI_CMD_OP_MASK GENMASK(11, 10)
+#define SMI_CMD_CLAUSE_22_OP_WRITE 0x1
+#define SMI_CMD_CLAUSE_22_OP_READ 0x2
+#define SMI_CMD_CLAUSE_45_OP_WRITE_ADDR 0x0
+#define SMI_CMD_CLAUSE_45_OP_WRITE 0x1
+#define SMI_CMD_CLAUSE_45_OP_READ 0x3
+
+#define SMI_CMD_ADDR_MASK GENMASK(9, 5)
+#define SMI_CMD_REG_MASK GENMASK(4, 0)
#define SMI_CMD_READ(addr, reg) \
- (SMI_BUSY | SMI_CMD_CLAUSE_22 | SMI_CMD_CLAUSE_22_OP_READ) | \
- (((addr) & SMI_CMD_ADDR_MASK) << SMI_CMD_ADDR_SHIFT) | \
- (((reg) & SMI_CMD_REG_MASK) << SMI_CMD_REG_SHIFT)
+ (SMI_BUSY | SMI_CMD_CLAUSE_22 | FIELD_PREP(SMI_CMD_OP_MASK, SMI_CMD_CLAUSE_22_OP_READ)) | \
+ (FIELD_PREP(SMI_CMD_ADDR_MASK, addr)) | \
+ (FIELD_PREP(SMI_CMD_REG_MASK, reg))
#define SMI_CMD_WRITE(addr, reg) \
- (SMI_BUSY | SMI_CMD_CLAUSE_22 | SMI_CMD_CLAUSE_22_OP_WRITE) | \
- (((addr) & SMI_CMD_ADDR_MASK) << SMI_CMD_ADDR_SHIFT) | \
- (((reg) & SMI_CMD_REG_MASK) << SMI_CMD_REG_SHIFT)
+ (SMI_BUSY | SMI_CMD_CLAUSE_22 | FIELD_PREP(SMI_CMD_OP_MASK, SMI_CMD_CLAUSE_22_OP_WRITE)) | \
+ (FIELD_PREP(SMI_CMD_ADDR_MASK, addr)) | \
+ (FIELD_PREP(SMI_CMD_REG_MASK, reg))
+#define SMI_CMD_SET_C45_ADDR(phyad, devad) \
+ (SMI_BUSY | FIELD_PREP(SMI_CMD_OP_MASK, SMI_CMD_CLAUSE_45_OP_WRITE_ADDR)) | \
+ (FIELD_PREP(SMI_CMD_ADDR_MASK, phyad)) | \
+ (FIELD_PREP(SMI_CMD_REG_MASK, devad))
+#define SMI_CMD_READ_C45(phyad, devad) \
+ (SMI_BUSY | FIELD_PREP(SMI_CMD_OP_MASK, SMI_CMD_CLAUSE_45_OP_READ)) | \
+ (FIELD_PREP(SMI_CMD_ADDR_MASK, phyad)) | \
+ (FIELD_PREP(SMI_CMD_REG_MASK, devad))
+#define SMI_CMD_WRITE_C45(phyad, devad) \
+ (SMI_BUSY | FIELD_PREP(SMI_CMD_OP_MASK, SMI_CMD_CLAUSE_45_OP_WRITE)) | \
+ (FIELD_PREP(SMI_CMD_ADDR_MASK, phyad)) | \
+ (FIELD_PREP(SMI_CMD_REG_MASK, devad))
/* ID register values for different switch models */
#define PORT_SWITCH_ID_6020 0x0200
@@ -272,12 +288,37 @@ static int mv88e6xxx_phy_wait(struct udevice *dev)
static int mv88e6xxx_phy_read_indirect(struct udevice *dev, int phyad, int devad, int reg)
{
struct mv88e6xxx_priv *priv = dev_get_priv(dev);
+ u16 smi_cmd;
int res;
+ if (devad >= 0) {
+ /*
+ * For C45 we need to write the register address into the
+ * PHY Data register first and then call the Write Address
+ * Register OP in the PHY command register.
+ */
+ res = mv88e6xxx_reg_write(dev, priv->global2,
+ GLOBAL2_REG_PHY_DATA,
+ reg);
+
+ res = mv88e6xxx_reg_write(dev, priv->global2,
+ GLOBAL2_REG_PHY_CMD,
+ SMI_CMD_SET_C45_ADDR(phyad, devad));
+
+ /* Wait for busy bit to clear */
+ res = mv88e6xxx_phy_wait(dev);
+ if (res < 0)
+ return res;
+
+ /* Set the actual C45 or C22 OP-s */
+ smi_cmd = SMI_CMD_READ_C45(phyad, devad);
+ } else
+ smi_cmd = SMI_CMD_READ(phyad, reg);
+
/* Issue command to read */
res = mv88e6xxx_reg_write(dev, priv->global2,
GLOBAL2_REG_PHY_CMD,
- SMI_CMD_READ(phyad, reg));
+ smi_cmd);
/* Wait for data to be read */
res = mv88e6xxx_phy_wait(dev);
@@ -293,8 +334,33 @@ static int mv88e6xxx_phy_write_indirect(struct udevice *dev, int phyad,
int devad, int reg, u16 data)
{
struct mv88e6xxx_priv *priv = dev_get_priv(dev);
+ u16 smi_cmd;
int res;
+ if (devad >= 0) {
+ /*
+ * For C45 we need to write the register address into the
+ * PHY Data register first and then call the Write Address
+ * Register OP in the PHY command register.
+ */
+ res = mv88e6xxx_reg_write(dev, priv->global2,
+ GLOBAL2_REG_PHY_DATA,
+ reg);
+
+ res = mv88e6xxx_reg_write(dev, priv->global2,
+ GLOBAL2_REG_PHY_CMD,
+ SMI_CMD_SET_C45_ADDR(phyad, devad));
+
+ /* Wait for busy bit to clear */
+ res = mv88e6xxx_phy_wait(dev);
+ if (res < 0)
+ return res;
+
+ /* Set the actual C45 or C22 OP-s */
+ smi_cmd = SMI_CMD_WRITE_C45(phyad, devad);
+ } else
+ smi_cmd = SMI_CMD_WRITE(phyad, reg);
+
/* Set the data to write */
res = mv88e6xxx_reg_write(dev, priv->global2,
GLOBAL2_REG_PHY_DATA, data);
@@ -303,7 +369,7 @@ static int mv88e6xxx_phy_write_indirect(struct udevice *dev, int phyad,
/* Issue the write command */
res = mv88e6xxx_reg_write(dev, priv->global2,
GLOBAL2_REG_PHY_CMD,
- SMI_CMD_WRITE(phyad, reg));
+ smi_cmd);
if (res < 0)
return res;
diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c
index 8d32d73b07f..f9d4782580e 100644
--- a/drivers/net/phy/dp83869.c
+++ b/drivers/net/phy/dp83869.c
@@ -81,7 +81,10 @@
/* RGMIIDCTL bits */
#define DP83869_RGMII_TX_CLK_DELAY_SHIFT 4
-#define DP83869_CLK_DELAY_DEF 7
+#define DP83869_CLK_DELAY_STEP 250
+#define DP83869_CLK_DELAY_MIN 250
+#define DP83869_CLK_DELAY_MAX 4000
+#define DP83869_CLK_DELAY_DEFAULT 2000
/* CFG2 bits */
#define MII_DP83869_CFG2_SPEEDOPT_10EN 0x0040
@@ -157,10 +160,6 @@ static int dp83869_config_port_mirroring(struct phy_device *phydev)
return 0;
}
-static const int dp83869_internal_delay[] = {250, 500, 750, 1000, 1250, 1500,
- 1750, 2000, 2250, 2500, 2750, 3000,
- 3250, 3500, 3750, 4000};
-
static int dp83869_set_strapped_mode(struct phy_device *phydev)
{
struct dp83869_private *dp83869 = phydev->priv;
@@ -183,7 +182,6 @@ static int dp83869_set_strapped_mode(struct phy_device *phydev)
static int dp83869_of_init(struct phy_device *phydev)
{
struct dp83869_private * const dp83869 = phydev->priv;
- const int delay_entries = ARRAY_SIZE(dp83869_internal_delay);
int ret;
ofnode node;
@@ -238,32 +236,45 @@ static int dp83869_of_init(struct phy_device *phydev)
dp83869->tx_fifo_depth = ofnode_read_s32_default(node, "tx-fifo-depth",
DP83869_PHYCR_FIFO_DEPTH_4_B_NIB);
+ /* Internal clock delay values can be configured in steps of
+ * 250ps (0.25ns). The register field for clock delay is 4-bits wide,
+ * the values range from 0b0000 for 0.25ns to 0b1111 for 4ns.
+ */
+
/* RX delay *must* be specified if internal delay of RX is used. */
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
- dp83869->rx_int_delay = ofnode_read_u32_default(node, "rx-internal-delay-ps",
- DP83869_CLK_DELAY_DEF);
- if (dp83869->rx_int_delay > delay_entries) {
- dp83869->rx_int_delay = DP83869_CLK_DELAY_DEF;
- pr_debug("rx-internal-delay-ps not set/invalid, default to %ups\n",
- dp83869_internal_delay[dp83869->rx_int_delay]);
+ dp83869->rx_int_delay = ofnode_read_u32_default(node,
+ "rx-internal-delay-ps", DP83869_CLK_DELAY_DEFAULT);
+ if (dp83869->rx_int_delay > DP83869_CLK_DELAY_MAX ||
+ dp83869->rx_int_delay < DP83869_CLK_DELAY_MIN ||
+ dp83869->rx_int_delay % DP83869_CLK_DELAY_STEP) {
+ dp83869->rx_int_delay = DP83869_CLK_DELAY_DEFAULT;
+ pr_warn("rx-internal-delay-ps not set/invalid, default"
+ " to %ups\n", DP83869_CLK_DELAY_DEFAULT);
}
- dp83869->rx_int_delay = dp83869_internal_delay[dp83869->rx_int_delay];
+ dp83869->rx_int_delay =
+ (dp83869->rx_int_delay - DP83869_CLK_DELAY_STEP)
+ / DP83869_CLK_DELAY_STEP;
}
- /* TX delay *must* be specified if internal delay of RX is used. */
+ /* TX delay *must* be specified if internal delay of TX is used. */
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
- dp83869->tx_int_delay = ofnode_read_u32_default(node, "tx-internal-delay-ps",
- DP83869_CLK_DELAY_DEF);
- if (dp83869->tx_int_delay > delay_entries) {
- dp83869->tx_int_delay = DP83869_CLK_DELAY_DEF;
- pr_debug("tx-internal-delay-ps not set/invalid, default to %ups\n",
- dp83869_internal_delay[dp83869->tx_int_delay]);
+ dp83869->tx_int_delay = ofnode_read_u32_default(node,
+ "tx-internal-delay-ps", DP83869_CLK_DELAY_DEFAULT);
+ if (dp83869->tx_int_delay > DP83869_CLK_DELAY_MAX ||
+ dp83869->tx_int_delay < DP83869_CLK_DELAY_MIN ||
+ dp83869->tx_int_delay % DP83869_CLK_DELAY_STEP) {
+ dp83869->tx_int_delay = DP83869_CLK_DELAY_DEFAULT;
+ pr_warn("tx-internal-delay-ps not set/invalid, default"
+ " to %ups\n", DP83869_CLK_DELAY_DEFAULT);
}
- dp83869->tx_int_delay = dp83869_internal_delay[dp83869->tx_int_delay];
+ dp83869->tx_int_delay =
+ (dp83869->tx_int_delay - DP83869_CLK_DELAY_STEP)
+ / DP83869_CLK_DELAY_STEP;
}
return 0;
diff --git a/drivers/net/phy/et1011c.c b/drivers/net/phy/et1011c.c
index fa4831427d5..db879bc73f2 100644
--- a/drivers/net/phy/et1011c.c
+++ b/drivers/net/phy/et1011c.c
@@ -3,7 +3,7 @@
* ET1011C PHY driver
*
* Derived from Linux kernel driver by Chaithrika U S
- * Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.com/
+ * Copyright (C) 2013, Texas Instruments, Incorporated - https://www.ti.com/
*/
#include <config.h>
#include <phy.h>
diff --git a/drivers/net/phy/xilinx_phy.c b/drivers/net/phy/xilinx_phy.c
index 1df639d6f44..c07c780193f 100644
--- a/drivers/net/phy/xilinx_phy.c
+++ b/drivers/net/phy/xilinx_phy.c
@@ -99,7 +99,6 @@ static int xilinxphy_startup(struct phy_device *phydev)
static int xilinxphy_of_init(struct phy_device *phydev)
{
- u32 phytype;
ofnode node;
debug("%s\n", __func__);
@@ -107,10 +106,6 @@ static int xilinxphy_of_init(struct phy_device *phydev)
if (!ofnode_valid(node))
return -EINVAL;
- phytype = ofnode_read_u32_default(node, "xlnx,phy-type", -1);
- if (phytype == XAE_PHY_TYPE_1000BASE_X)
- phydev->flags |= XAE_PHY_TYPE_1000BASE_X;
-
return 0;
}
diff --git a/drivers/net/qe/uccf.c b/drivers/net/qe/uccf.c
index 306f1ea1db6..00848a1a37d 100644
--- a/drivers/net/qe/uccf.c
+++ b/drivers/net/qe/uccf.c
@@ -6,7 +6,6 @@
* based on source code of Shlomi Gridish
*/
-#include <common.h>
#include <malloc.h>
#include <linux/errno.h>
#include <asm/io.h>
diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
index 04c3274fbe1..a12f7e32e8f 100644
--- a/drivers/net/sun8i_emac.c
+++ b/drivers/net/sun8i_emac.c
@@ -29,6 +29,7 @@
#include <net.h>
#include <reset.h>
#include <wait_bit.h>
+#include <power/regulator.h>
#define MDIO_CMD_MII_BUSY BIT(0)
#define MDIO_CMD_MII_WRITE BIT(1)
@@ -167,9 +168,8 @@ struct emac_eth_dev {
struct clk ephy_clk;
struct reset_ctl tx_rst;
struct reset_ctl ephy_rst;
-#if CONFIG_IS_ENABLED(DM_GPIO)
struct gpio_desc reset_gpio;
-#endif
+ struct udevice *phy_reg;
};
@@ -615,7 +615,6 @@ err_tx_clk:
return ret;
}
-#if CONFIG_IS_ENABLED(DM_GPIO)
static int sun8i_mdio_reset(struct mii_dev *bus)
{
struct udevice *dev = bus->priv;
@@ -647,7 +646,6 @@ static int sun8i_mdio_reset(struct mii_dev *bus)
return 0;
}
-#endif
static int sun8i_mdio_init(const char *name, struct udevice *priv)
{
@@ -662,9 +660,7 @@ static int sun8i_mdio_init(const char *name, struct udevice *priv)
bus->write = sun8i_mdio_write;
snprintf(bus->name, sizeof(bus->name), name);
bus->priv = (void *)priv;
-#if CONFIG_IS_ENABLED(DM_GPIO)
bus->reset = sun8i_mdio_reset;
-#endif
return mdio_register(bus);
}
@@ -720,6 +716,9 @@ static int sun8i_emac_eth_probe(struct udevice *dev)
sun8i_emac_set_syscon(sun8i_pdata, priv);
+ if (priv->phy_reg)
+ regulator_set_enable(priv->phy_reg, true);
+
sun8i_mdio_init(dev->name, dev);
priv->bus = miiphy_get_dev_by_name(dev->name);
@@ -778,9 +777,7 @@ static int sun8i_emac_eth_of_to_plat(struct udevice *dev)
const fdt32_t *reg;
int node = dev_of_offset(dev);
int offset = 0;
-#if CONFIG_IS_ENABLED(DM_GPIO)
int reset_flags = GPIOD_IS_OUT;
-#endif
int ret;
pdata->iobase = dev_read_addr(dev);
@@ -829,6 +826,8 @@ static int sun8i_emac_eth_of_to_plat(struct udevice *dev)
priv->sysctl_reg = (void *)syscon_base + priv->variant->syscon_offset;
+ device_get_supply_regulator(dev, "phy-supply", &priv->phy_reg);
+
pdata->phy_interface = -1;
priv->phyaddr = -1;
priv->use_internal_phy = false;
@@ -865,7 +864,6 @@ 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);
-#if CONFIG_IS_ENABLED(DM_GPIO)
if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
"snps,reset-active-low"))
reset_flags |= GPIOD_ACTIVE_LOW;
@@ -880,7 +878,6 @@ static int sun8i_emac_eth_of_to_plat(struct udevice *dev)
} else if (ret == -ENOENT) {
ret = 0;
}
-#endif
return 0;
}
diff --git a/drivers/net/sunxi_emac.c b/drivers/net/sunxi_emac.c
index 4c90d4b4981..f546ad1fe8d 100644
--- a/drivers/net/sunxi_emac.c
+++ b/drivers/net/sunxi_emac.c
@@ -17,6 +17,7 @@
#include <net.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
+#include <power/regulator.h>
/* EMAC register */
struct emac_regs {
@@ -165,6 +166,7 @@ struct emac_eth_dev {
struct phy_device *phydev;
int link_printed;
uchar rx_buf[EMAC_RX_BUFSIZE];
+ struct udevice *phy_reg;
};
struct emac_rxhdr {
@@ -572,6 +574,9 @@ static int sunxi_emac_eth_probe(struct udevice *dev)
if (ret)
return ret;
+ if (priv->phy_reg)
+ regulator_set_enable(priv->phy_reg, true);
+
return sunxi_emac_init_phy(priv, dev);
}
@@ -585,9 +590,42 @@ static const struct eth_ops sunxi_emac_eth_ops = {
static int sunxi_emac_eth_of_to_plat(struct udevice *dev)
{
struct eth_pdata *pdata = dev_get_plat(dev);
+ struct emac_eth_dev *priv = dev_get_priv(dev);
+ struct ofnode_phandle_args args;
+ ofnode phy_node, mdio_node;
+ int ret;
pdata->iobase = dev_read_addr(dev);
+ phy_node = dev_get_phy_node(dev);
+ if (!ofnode_valid(phy_node)) {
+ dev_err(dev, "failed to get PHY node\n");
+ return -ENOENT;
+ }
+ /*
+ * The PHY regulator is in the MDIO node, not the EMAC or PHY node.
+ * U-Boot does not have (and does not need) a device driver for the
+ * MDIO device, so just "pass through" that DT node to get to the
+ * regulator phandle.
+ * The PHY regulator is optional, though: ignore if we cannot find
+ * a phy-supply property.
+ */
+ mdio_node = ofnode_get_parent(phy_node);
+ ret= ofnode_parse_phandle_with_args(mdio_node, "phy-supply", NULL, 0, 0,
+ &args);
+ if (ret && ret != -ENOENT) {
+ dev_err(dev, "failed to get PHY supply node\n");
+ return ret;
+ }
+ if (!ret) {
+ ret = uclass_get_device_by_ofnode(UCLASS_REGULATOR, args.node,
+ &priv->phy_reg);
+ if (ret) {
+ dev_err(dev, "failed to get PHY regulator node\n");
+ return ret;
+ }
+ }
+
return 0;
}
diff --git a/drivers/net/ti/Kconfig b/drivers/net/ti/Kconfig
index 02660e4fbb4..c75f4186285 100644
--- a/drivers/net/ti/Kconfig
+++ b/drivers/net/ti/Kconfig
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0+
#
-# Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+# Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
config DRIVER_TI_CPSW
bool "TI Common Platform Ethernet Switch"
diff --git a/drivers/net/ti/Makefile b/drivers/net/ti/Makefile
index 8d3808bb4b6..0ce0cf2828a 100644
--- a/drivers/net/ti/Makefile
+++ b/drivers/net/ti/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0+
#
-# Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+# Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
obj-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o cpsw-common.o cpsw_mdio.o
obj-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o
diff --git a/drivers/net/ti/cpsw.c b/drivers/net/ti/cpsw.c
index 877be7fca52..9a5e9642df1 100644
--- a/drivers/net/ti/cpsw.c
+++ b/drivers/net/ti/cpsw.c
@@ -2,7 +2,7 @@
/*
* CPSW Ethernet Switch Driver
*
- * Copyright (C) 2010-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2010-2018 Texas Instruments Incorporated - https://www.ti.com/
*/
#include <common.h>
diff --git a/drivers/net/ti/cpsw_mdio.c b/drivers/net/ti/cpsw_mdio.c
index ac791faa813..74cc956785f 100644
--- a/drivers/net/ti/cpsw_mdio.c
+++ b/drivers/net/ti/cpsw_mdio.c
@@ -2,7 +2,7 @@
/*
* CPSW MDIO generic driver for TI AMxx/K2x/EMAC devices.
*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
*/
#include <common.h>
diff --git a/drivers/net/ti/cpsw_mdio.h b/drivers/net/ti/cpsw_mdio.h
index 9b98763656f..ddf65a4686d 100644
--- a/drivers/net/ti/cpsw_mdio.h
+++ b/drivers/net/ti/cpsw_mdio.h
@@ -2,7 +2,7 @@
/*
* CPSW MDIO generic driver API for TI AMxx/K2x/EMAC devices.
*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
*/
#ifndef CPSW_MDIO_H_
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c
index 3377e669f2f..7c57d32614f 100644
--- a/drivers/net/zynq_gem.c
+++ b/drivers/net/zynq_gem.c
@@ -321,11 +321,38 @@ static int zynq_gem_setup_mac(struct udevice *dev)
return 0;
}
+static u32 gem_mdc_clk_div(struct zynq_gem_priv *priv)
+{
+ u32 config;
+ unsigned long pclk_hz;
+
+ pclk_hz = clk_get_rate(&priv->pclk);
+ if (pclk_hz <= 20000000)
+ config = GEM_MDC_SET(GEM_CLK_DIV8);
+ else if (pclk_hz <= 40000000)
+ config = GEM_MDC_SET(GEM_CLK_DIV16);
+ else if (pclk_hz <= 80000000)
+ config = GEM_MDC_SET(GEM_CLK_DIV32);
+ else if (pclk_hz <= 120000000)
+ config = GEM_MDC_SET(GEM_CLK_DIV48);
+ else if (pclk_hz <= 160000000)
+ config = GEM_MDC_SET(GEM_CLK_DIV64);
+ else if (pclk_hz <= 240000000)
+ config = GEM_MDC_SET(GEM_CLK_DIV96);
+ else if (pclk_hz <= 320000000)
+ config = GEM_MDC_SET(GEM_CLK_DIV128);
+ else
+ config = GEM_MDC_SET(GEM_CLK_DIV224);
+
+ return config;
+}
+
static int zynq_phy_init(struct udevice *dev)
{
- int ret;
+ int ret, val;
struct zynq_gem_priv *priv = dev_get_priv(dev);
struct zynq_gem_regs *regs_mdio = priv->mdiobase;
+ struct zynq_gem_regs *regs = priv->iobase;
const u32 supported = SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
@@ -333,6 +360,10 @@ static int zynq_phy_init(struct udevice *dev)
SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full;
+ val = gem_mdc_clk_div(priv);
+ if (val)
+ writel(val, &regs->nwcfg);
+
/* Enable only MDIO bus */
writel(ZYNQ_GEM_NWCTRL_MDEN_MASK, &regs_mdio->nwctrl);
@@ -360,35 +391,10 @@ static int zynq_phy_init(struct udevice *dev)
return phy_config(priv->phydev);
}
-static u32 gem_mdc_clk_div(struct zynq_gem_priv *priv)
-{
- u32 config;
- unsigned long pclk_hz;
-
- pclk_hz = clk_get_rate(&priv->pclk);
- if (pclk_hz <= 20000000)
- config = GEM_MDC_SET(GEM_CLK_DIV8);
- else if (pclk_hz <= 40000000)
- config = GEM_MDC_SET(GEM_CLK_DIV16);
- else if (pclk_hz <= 80000000)
- config = GEM_MDC_SET(GEM_CLK_DIV32);
- else if (pclk_hz <= 120000000)
- config = GEM_MDC_SET(GEM_CLK_DIV48);
- else if (pclk_hz <= 160000000)
- config = GEM_MDC_SET(GEM_CLK_DIV64);
- else if (pclk_hz <= 240000000)
- config = GEM_MDC_SET(GEM_CLK_DIV96);
- else if (pclk_hz <= 320000000)
- config = GEM_MDC_SET(GEM_CLK_DIV128);
- else
- config = GEM_MDC_SET(GEM_CLK_DIV224);
-
- return config;
-}
static int zynq_gem_init(struct udevice *dev)
{
- u32 i, nwconfig;
+ u32 i, nwconfig, nwcfg;
int ret;
unsigned long clk_rate = 0;
struct zynq_gem_priv *priv = dev_get_priv(dev);
@@ -494,8 +500,7 @@ static int zynq_gem_init(struct udevice *dev)
return -1;
}
- nwconfig = gem_mdc_clk_div(priv);
- nwconfig |= ZYNQ_GEM_NWCFG_INIT;
+ nwconfig = ZYNQ_GEM_NWCFG_INIT;
/*
* Set SGMII enable PCS selection only if internal PCS/PMA
@@ -509,19 +514,21 @@ static int zynq_gem_init(struct udevice *dev)
switch (priv->phydev->speed) {
case SPEED_1000:
- writel(nwconfig | ZYNQ_GEM_NWCFG_SPEED1000,
- &regs->nwcfg);
+ nwconfig |= ZYNQ_GEM_NWCFG_SPEED1000;
clk_rate = ZYNQ_GEM_FREQUENCY_1000;
break;
case SPEED_100:
- writel(nwconfig | ZYNQ_GEM_NWCFG_SPEED100,
- &regs->nwcfg);
+ nwconfig |= ZYNQ_GEM_NWCFG_SPEED100;
clk_rate = ZYNQ_GEM_FREQUENCY_100;
break;
case SPEED_10:
clk_rate = ZYNQ_GEM_FREQUENCY_10;
break;
}
+ nwcfg = readl(&regs->nwcfg);
+ nwcfg |= nwconfig;
+ if (nwcfg)
+ writel(nwcfg, &regs->nwcfg);
#ifdef CONFIG_ARM64
if (priv->interface == PHY_INTERFACE_MODE_SGMII &&
diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c
index 20dc910d8a3..c39cd41aa38 100644
--- a/drivers/nvme/nvme.c
+++ b/drivers/nvme/nvme.c
@@ -906,7 +906,7 @@ int nvme_init(struct udevice *udev)
/* The real blksz and size will be set by nvme_blk_probe() */
ret = blk_create_devicef(udev, "nvme-blk", name, UCLASS_NVME,
- -1, 512, 0, &ns_udev);
+ -1, DEFAULT_BLKSZ, 0, &ns_udev);
if (ret)
goto free_id;
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index ae7350aaff9..e0d01f6a85d 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -123,7 +123,7 @@ static void pci_dev_find_ofnode(struct udevice *bus, phys_addr_t bdf,
dev_for_each_subnode(node, bus) {
ret = ofnode_read_pci_addr(node, FDT_PCI_SPACE_CONFIG, "reg",
- &addr);
+ &addr, NULL);
if (ret)
continue;
diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c
index 3697cd8d652..83559550e6f 100644
--- a/drivers/pci/pci_mvebu.c
+++ b/drivers/pci/pci_mvebu.c
@@ -641,7 +641,8 @@ static int mvebu_pcie_port_parse_dt(ofnode node, ofnode parent, struct mvebu_pci
pcie->is_x4 = true;
/* devfn is in bits [15:8], see PCI_DEV usage */
- ret = ofnode_read_pci_addr(node, FDT_PCI_SPACE_CONFIG, "reg", &pci_addr);
+ ret = ofnode_read_pci_addr(node, FDT_PCI_SPACE_CONFIG, "reg", &pci_addr,
+ NULL);
if (ret < 0) {
printf("%s: property \"reg\" is invalid\n", pcie->name);
goto err;
diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c
index 131c21b7684..d6374a58e33 100644
--- a/drivers/pci/pci_tegra.c
+++ b/drivers/pci/pci_tegra.c
@@ -462,7 +462,7 @@ static int tegra_pcie_parse_port_info(ofnode node, uint *index, uint *lanes)
*lanes = err;
- err = ofnode_read_pci_addr(node, 0, "reg", &addr);
+ err = ofnode_read_pci_addr(node, 0, "reg", &addr, NULL);
if (err < 0) {
pr_err("failed to parse \"reg\" property\n");
return err;
diff --git a/drivers/pci/pcie_mediatek.c b/drivers/pci/pcie_mediatek.c
index ed25a10bcf0..f0f34b5d119 100644
--- a/drivers/pci/pcie_mediatek.c
+++ b/drivers/pci/pcie_mediatek.c
@@ -661,7 +661,7 @@ static int mtk_pcie_probe(struct udevice *dev)
if (!ofnode_is_enabled(subnode))
continue;
- err = ofnode_read_pci_addr(subnode, 0, "reg", &addr);
+ err = ofnode_read_pci_addr(subnode, 0, "reg", &addr, NULL);
if (err)
return err;
@@ -700,7 +700,7 @@ static int mtk_pcie_probe_v2(struct udevice *dev)
if (!ofnode_is_enabled(subnode))
continue;
- err = ofnode_read_pci_addr(subnode, 0, "reg", &addr);
+ err = ofnode_read_pci_addr(subnode, 0, "reg", &addr, NULL);
if (err)
return err;
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 8ac5769ed9a..60138beca49 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -200,7 +200,7 @@ config MESON_GXL_USB_PHY
config MESON_G12A_USB_PHY
bool "Amlogic Meson G12A USB PHYs"
- depends on PHY && ARCH_MESON && MESON_G12A
+ depends on PHY && ARCH_MESON && (MESON_G12A || MESON_A1)
imply REGMAP
help
This is the generic phy driver for the Amlogic Meson G12A
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 5d4de86e71a..2e8723186c0 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0+
#
-# Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+# Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/
# Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
obj-y += allwinner/
diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
index 77dffcad884..6624e9134f4 100644
--- a/drivers/phy/allwinner/phy-sun4i-usb.c
+++ b/drivers/phy/allwinner/phy-sun4i-usb.c
@@ -472,9 +472,9 @@ static int sun4i_usb_phy_probe(struct udevice *dev)
if (!data->cfg)
return -EINVAL;
- data->base = (void __iomem *)devfdt_get_addr_name(dev, "phy_ctrl");
- if (IS_ERR(data->base))
- return PTR_ERR(data->base);
+ data->base = (void __iomem *)dev_read_addr_name_ptr(dev, "phy_ctrl");
+ if (!data->base)
+ return -EINVAL;
device_get_supply_regulator(dev, "usb0_vbus_power-supply",
&data->vbus_power_supply);
@@ -555,9 +555,9 @@ static int sun4i_usb_phy_probe(struct udevice *dev)
if (i || data->cfg->phy0_dual_route) {
snprintf(name, sizeof(name), "pmu%d", i);
- phy->pmu = (void __iomem *)devfdt_get_addr_name(dev, name);
- if (IS_ERR(phy->pmu))
- return PTR_ERR(phy->pmu);
+ phy->pmu = (void __iomem *)dev_read_addr_name_ptr(dev, name);
+ if (!phy->pmu)
+ return -EINVAL;
}
phy->id = i;
diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c
index fc5044fd5d3..4bb8a0ca7f3 100644
--- a/drivers/phy/cadence/phy-cadence-sierra.c
+++ b/drivers/phy/cadence/phy-cadence-sierra.c
@@ -7,7 +7,7 @@
* Copyright (c) 2018 Cadence Design Systems
* Author: Alan Douglas <adouglas@cadence.com>
*
- * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
* Jean-Jacques Hiblot <jjhiblot@ti.com>
*
*/
diff --git a/drivers/phy/keystone-usb-phy.c b/drivers/phy/keystone-usb-phy.c
index 6799e232370..3bb9c0814c1 100644
--- a/drivers/phy/keystone-usb-phy.c
+++ b/drivers/phy/keystone-usb-phy.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/
* Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
*/
diff --git a/drivers/phy/meson-axg-mipi-dphy.c b/drivers/phy/meson-axg-mipi-dphy.c
index cf2a1cd14c7..a69b6c97594 100644
--- a/drivers/phy/meson-axg-mipi-dphy.c
+++ b/drivers/phy/meson-axg-mipi-dphy.c
@@ -25,6 +25,7 @@
#include <linux/bitops.h>
#include <linux/compat.h>
#include <linux/bitfield.h>
+#include <linux/time.h>
/* [31] soft reset for the phy.
* 1: reset. 0: dessert the reset.
@@ -170,8 +171,6 @@
#define MIPI_DSI_TEST_CTRL0 0x3c
#define MIPI_DSI_TEST_CTRL1 0x40
-#define NSEC_PER_MSEC 1000000L
-
struct phy_meson_axg_mipi_dphy_priv {
struct regmap *regmap;
#if CONFIG_IS_ENABLED(CLK)
diff --git a/drivers/phy/meson-g12a-usb2.c b/drivers/phy/meson-g12a-usb2.c
index 8b243225156..3958d2404b8 100644
--- a/drivers/phy/meson-g12a-usb2.c
+++ b/drivers/phy/meson-g12a-usb2.c
@@ -19,17 +19,34 @@
#include <linux/delay.h>
#include <linux/printk.h>
#include <power/regulator.h>
+#include <power-domain.h>
#include <reset.h>
#include <clk.h>
#include <linux/bitops.h>
#include <linux/compat.h>
+#include <linux/bitfield.h>
#define PHY_CTRL_R0 0x0
#define PHY_CTRL_R1 0x4
#define PHY_CTRL_R2 0x8
+
#define PHY_CTRL_R3 0xc
+ #define PHY_CTRL_R3_SQUELCH_REF GENMASK(1, 0)
+ #define PHY_CTRL_R3_HSDIC_REF GENMASK(3, 2)
+ #define PHY_CTRL_R3_DISC_THRESH GENMASK(7, 4)
+
#define PHY_CTRL_R4 0x10
+ #define PHY_CTRL_R4_CALIB_CODE_7_0 GENMASK(7, 0)
+ #define PHY_CTRL_R4_CALIB_CODE_15_8 GENMASK(15, 8)
+ #define PHY_CTRL_R4_CALIB_CODE_23_16 GENMASK(23, 16)
+ #define PHY_CTRL_R4_I_C2L_CAL_EN BIT(24)
+ #define PHY_CTRL_R4_I_C2L_CAL_RESET_N BIT(25)
+ #define PHY_CTRL_R4_I_C2L_CAL_DONE BIT(26)
+ #define PHY_CTRL_R4_TEST_BYPASS_MODE_EN BIT(27)
+ #define PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0 GENMASK(29, 28)
+ #define PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2 GENMASK(31, 30)
+
#define PHY_CTRL_R5 0x14
#define PHY_CTRL_R6 0x18
#define PHY_CTRL_R7 0x1c
@@ -38,35 +55,131 @@
#define PHY_CTRL_R10 0x28
#define PHY_CTRL_R11 0x2c
#define PHY_CTRL_R12 0x30
+
#define PHY_CTRL_R13 0x34
+ #define PHY_CTRL_R13_CUSTOM_PATTERN_19 GENMASK(7, 0)
+ #define PHY_CTRL_R13_LOAD_STAT BIT(14)
+ #define PHY_CTRL_R13_UPDATE_PMA_SIGNALS BIT(15)
+ #define PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET GENMASK(20, 16)
+ #define PHY_CTRL_R13_CLEAR_HOLD_HS_DISCONNECT BIT(21)
+ #define PHY_CTRL_R13_BYPASS_HOST_DISCONNECT_VAL BIT(22)
+ #define PHY_CTRL_R13_BYPASS_HOST_DISCONNECT_EN BIT(23)
+ #define PHY_CTRL_R13_I_C2L_HS_EN BIT(24)
+ #define PHY_CTRL_R13_I_C2L_FS_EN BIT(25)
+ #define PHY_CTRL_R13_I_C2L_LS_EN BIT(26)
+ #define PHY_CTRL_R13_I_C2L_HS_OE BIT(27)
+ #define PHY_CTRL_R13_I_C2L_FS_OE BIT(28)
+ #define PHY_CTRL_R13_I_C2L_HS_RX_EN BIT(29)
+ #define PHY_CTRL_R13_I_C2L_FSLS_RX_EN BIT(30)
+
#define PHY_CTRL_R14 0x38
#define PHY_CTRL_R15 0x3c
+
#define PHY_CTRL_R16 0x40
+ #define PHY_CTRL_R16_MPLL_M GENMASK(8, 0)
+ #define PHY_CTRL_R16_MPLL_N GENMASK(14, 10)
+ #define PHY_CTRL_R16_MPLL_TDC_MODE BIT(20)
+ #define PHY_CTRL_R16_MPLL_SDM_EN BIT(21)
+ #define PHY_CTRL_R16_MPLL_LOAD BIT(22)
+ #define PHY_CTRL_R16_MPLL_DCO_SDM_EN BIT(23)
+ #define PHY_CTRL_R16_MPLL_LOCK_LONG GENMASK(25, 24)
+ #define PHY_CTRL_R16_MPLL_LOCK_F BIT(26)
+ #define PHY_CTRL_R16_MPLL_FAST_LOCK BIT(27)
+ #define PHY_CTRL_R16_MPLL_EN BIT(28)
+ #define PHY_CTRL_R16_MPLL_RESET BIT(29)
+ #define PHY_CTRL_R16_MPLL_LOCK BIT(30)
+ #define PHY_CTRL_R16_MPLL_LOCK_DIG BIT(31)
+
#define PHY_CTRL_R17 0x44
+ #define PHY_CTRL_R17_MPLL_FRAC_IN GENMASK(13, 0)
+ #define PHY_CTRL_R17_MPLL_FIX_EN BIT(16)
+ #define PHY_CTRL_R17_MPLL_LAMBDA1 GENMASK(19, 17)
+ #define PHY_CTRL_R17_MPLL_LAMBDA0 GENMASK(22, 20)
+ #define PHY_CTRL_R17_MPLL_FILTER_MODE BIT(23)
+ #define PHY_CTRL_R17_MPLL_FILTER_PVT2 GENMASK(27, 24)
+ #define PHY_CTRL_R17_MPLL_FILTER_PVT1 GENMASK(31, 28)
+
#define PHY_CTRL_R18 0x48
+ #define PHY_CTRL_R18_MPLL_LKW_SEL GENMASK(1, 0)
+ #define PHY_CTRL_R18_MPLL_LK_W GENMASK(5, 2)
+ #define PHY_CTRL_R18_MPLL_LK_S GENMASK(11, 6)
+ #define PHY_CTRL_R18_MPLL_DCO_M_EN BIT(12)
+ #define PHY_CTRL_R18_MPLL_DCO_CLK_SEL BIT(13)
+ #define PHY_CTRL_R18_MPLL_PFD_GAIN GENMASK(15, 14)
+ #define PHY_CTRL_R18_MPLL_ROU GENMASK(18, 16)
+ #define PHY_CTRL_R18_MPLL_DATA_SEL GENMASK(21, 19)
+ #define PHY_CTRL_R18_MPLL_BIAS_ADJ GENMASK(23, 22)
+ #define PHY_CTRL_R18_MPLL_BB_MODE GENMASK(25, 24)
+ #define PHY_CTRL_R18_MPLL_ALPHA GENMASK(28, 26)
+ #define PHY_CTRL_R18_MPLL_ADJ_LDO GENMASK(30, 29)
+ #define PHY_CTRL_R18_MPLL_ACG_RANGE BIT(31)
+
#define PHY_CTRL_R19 0x4c
+
#define PHY_CTRL_R20 0x50
+ #define PHY_CTRL_R20_USB2_IDDET_EN BIT(0)
+ #define PHY_CTRL_R20_USB2_OTG_VBUS_TRIM_2_0 GENMASK(3, 1)
+ #define PHY_CTRL_R20_USB2_OTG_VBUSDET_EN BIT(4)
+ #define PHY_CTRL_R20_USB2_AMON_EN BIT(5)
+ #define PHY_CTRL_R20_USB2_CAL_CODE_R5 BIT(6)
+ #define PHY_CTRL_R20_BYPASS_OTG_DET BIT(7)
+ #define PHY_CTRL_R20_USB2_DMON_EN BIT(8)
+ #define PHY_CTRL_R20_USB2_DMON_SEL_3_0 GENMASK(12, 9)
+ #define PHY_CTRL_R20_USB2_EDGE_DRV_EN BIT(13)
+ #define PHY_CTRL_R20_USB2_EDGE_DRV_TRIM_1_0 GENMASK(15, 14)
+ #define PHY_CTRL_R20_USB2_BGR_ADJ_4_0 GENMASK(20, 16)
+ #define PHY_CTRL_R20_USB2_BGR_START BIT(21)
+ #define PHY_CTRL_R20_USB2_BGR_VREF_4_0 GENMASK(28, 24)
+ #define PHY_CTRL_R20_USB2_BGR_DBG_1_0 GENMASK(30, 29)
+ #define PHY_CTRL_R20_BYPASS_CAL_DONE_R5 BIT(31)
+
#define PHY_CTRL_R21 0x54
+ #define PHY_CTRL_R21_USB2_BGR_FORCE BIT(0)
+ #define PHY_CTRL_R21_USB2_CAL_ACK_EN BIT(1)
+ #define PHY_CTRL_R21_USB2_OTG_ACA_EN BIT(2)
+ #define PHY_CTRL_R21_USB2_TX_STRG_PD BIT(3)
+ #define PHY_CTRL_R21_USB2_OTG_ACA_TRIM_1_0 GENMASK(5, 4)
+ #define PHY_CTRL_R21_BYPASS_UTMI_CNTR GENMASK(15, 6)
+ #define PHY_CTRL_R21_BYPASS_UTMI_REG GENMASK(25, 20)
+
#define PHY_CTRL_R22 0x58
#define PHY_CTRL_R23 0x5c
#define RESET_COMPLETE_TIME 1000
#define PLL_RESET_COMPLETE_TIME 100
+enum meson_soc_id {
+ MESON_SOC_A1,
+ MESON_SOC_G12A,
+};
+
struct phy_meson_g12a_usb2_priv {
struct regmap *regmap;
#if CONFIG_IS_ENABLED(CLK)
struct clk clk;
#endif
struct reset_ctl reset;
+#if CONFIG_IS_ENABLED(POWER_DOMAIN)
+ struct power_domain pwrdm;
+#endif
+ int soc_id;
};
static int phy_meson_g12a_usb2_init(struct phy *phy)
{
struct udevice *dev = phy->dev;
struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev);
+ u32 value;
int ret;
+#if CONFIG_IS_ENABLED(CLK)
+ ret = clk_enable(&priv->clk);
+ if (ret && ret != -ENOSYS && ret != -ENOTSUPP) {
+ pr_err("failed to enable PHY clock\n");
+ return ret;
+ }
+#endif
+
ret = reset_assert(&priv->reset);
udelay(1);
ret |= reset_deassert(&priv->reset);
@@ -79,25 +192,91 @@ static int phy_meson_g12a_usb2_init(struct phy *phy)
regmap_update_bits(priv->regmap, PHY_CTRL_R21, BIT(2), 0);
/* PLL Setup : 24MHz * 20 / 1 = 480MHz */
- regmap_write(priv->regmap, PHY_CTRL_R16, 0x39400414);
- regmap_write(priv->regmap, PHY_CTRL_R17, 0x927e0000);
- regmap_write(priv->regmap, PHY_CTRL_R18, 0xac5f49e5);
+ regmap_write(priv->regmap, PHY_CTRL_R16,
+ FIELD_PREP(PHY_CTRL_R16_MPLL_M, 20) |
+ FIELD_PREP(PHY_CTRL_R16_MPLL_N, 1) |
+ PHY_CTRL_R16_MPLL_LOAD |
+ FIELD_PREP(PHY_CTRL_R16_MPLL_LOCK_LONG, 1) |
+ PHY_CTRL_R16_MPLL_FAST_LOCK |
+ PHY_CTRL_R16_MPLL_EN |
+ PHY_CTRL_R16_MPLL_RESET);
+
+ regmap_write(priv->regmap, PHY_CTRL_R17,
+ FIELD_PREP(PHY_CTRL_R17_MPLL_FRAC_IN, 0) |
+ FIELD_PREP(PHY_CTRL_R17_MPLL_LAMBDA1, 7) |
+ FIELD_PREP(PHY_CTRL_R17_MPLL_LAMBDA0, 7) |
+ FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT2, 2) |
+ FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT1, 9));
+
+ value = FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) |
+ FIELD_PREP(PHY_CTRL_R18_MPLL_LK_W, 9) |
+ FIELD_PREP(PHY_CTRL_R18_MPLL_LK_S, 0x27) |
+ FIELD_PREP(PHY_CTRL_R18_MPLL_PFD_GAIN, 1) |
+ FIELD_PREP(PHY_CTRL_R18_MPLL_ROU, 7) |
+ FIELD_PREP(PHY_CTRL_R18_MPLL_DATA_SEL, 3) |
+ FIELD_PREP(PHY_CTRL_R18_MPLL_BIAS_ADJ, 1) |
+ FIELD_PREP(PHY_CTRL_R18_MPLL_BB_MODE, 0) |
+ FIELD_PREP(PHY_CTRL_R18_MPLL_ALPHA, 3) |
+ FIELD_PREP(PHY_CTRL_R18_MPLL_ADJ_LDO, 1) |
+ PHY_CTRL_R18_MPLL_ACG_RANGE;
+
+ if (priv->soc_id == MESON_SOC_A1)
+ value |= PHY_CTRL_R18_MPLL_DCO_CLK_SEL;
+
+ regmap_write(priv->regmap, PHY_CTRL_R18, value);
udelay(PLL_RESET_COMPLETE_TIME);
/* UnReset PLL */
- regmap_write(priv->regmap, PHY_CTRL_R16, 0x19400414);
+ regmap_write(priv->regmap, PHY_CTRL_R16,
+ FIELD_PREP(PHY_CTRL_R16_MPLL_M, 20) |
+ FIELD_PREP(PHY_CTRL_R16_MPLL_N, 1) |
+ PHY_CTRL_R16_MPLL_LOAD |
+ FIELD_PREP(PHY_CTRL_R16_MPLL_LOCK_LONG, 1) |
+ PHY_CTRL_R16_MPLL_FAST_LOCK |
+ PHY_CTRL_R16_MPLL_EN);
/* PHY Tuning */
- regmap_write(priv->regmap, PHY_CTRL_R20, 0xfe18);
- regmap_write(priv->regmap, PHY_CTRL_R4, 0x8000fff);
+ regmap_write(priv->regmap, PHY_CTRL_R20,
+ FIELD_PREP(PHY_CTRL_R20_USB2_OTG_VBUS_TRIM_2_0, 4) |
+ PHY_CTRL_R20_USB2_OTG_VBUSDET_EN |
+ FIELD_PREP(PHY_CTRL_R20_USB2_DMON_SEL_3_0, 15) |
+ PHY_CTRL_R20_USB2_EDGE_DRV_EN |
+ FIELD_PREP(PHY_CTRL_R20_USB2_EDGE_DRV_TRIM_1_0, 3) |
+ FIELD_PREP(PHY_CTRL_R20_USB2_BGR_ADJ_4_0, 0) |
+ FIELD_PREP(PHY_CTRL_R20_USB2_BGR_VREF_4_0, 0) |
+ FIELD_PREP(PHY_CTRL_R20_USB2_BGR_DBG_1_0, 0));
+
+ if (priv->soc_id == MESON_SOC_G12A)
+ regmap_write(priv->regmap, PHY_CTRL_R4,
+ FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) |
+ FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) |
+ FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) |
+ PHY_CTRL_R4_TEST_BYPASS_MODE_EN |
+ FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) |
+ FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0));
+ else if (priv->soc_id == MESON_SOC_A1)
+ regmap_write(priv->regmap, PHY_CTRL_R21,
+ PHY_CTRL_R21_USB2_CAL_ACK_EN |
+ PHY_CTRL_R21_USB2_TX_STRG_PD |
+ FIELD_PREP(PHY_CTRL_R21_USB2_OTG_ACA_TRIM_1_0, 2));
/* Tuning Disconnect Threshold */
- regmap_write(priv->regmap, PHY_CTRL_R3, 0x34);
+ regmap_write(priv->regmap, PHY_CTRL_R3,
+ FIELD_PREP(PHY_CTRL_R3_SQUELCH_REF, 0) |
+ FIELD_PREP(PHY_CTRL_R3_HSDIC_REF, 1) |
+ FIELD_PREP(PHY_CTRL_R3_DISC_THRESH, 3));
/* Analog Settings */
- regmap_write(priv->regmap, PHY_CTRL_R14, 0);
- regmap_write(priv->regmap, PHY_CTRL_R13, 0x78000);
+ if (priv->soc_id == MESON_SOC_G12A) {
+ regmap_write(priv->regmap, PHY_CTRL_R14, 0);
+ regmap_write(priv->regmap, PHY_CTRL_R13,
+ PHY_CTRL_R13_UPDATE_PMA_SIGNALS |
+ FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7));
+ } else if (priv->soc_id == MESON_SOC_A1) {
+ regmap_write(priv->regmap, PHY_CTRL_R13,
+ FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7));
+ }
return 0;
}
@@ -108,6 +287,10 @@ static int phy_meson_g12a_usb2_exit(struct phy *phy)
struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev);
int ret;
+#if CONFIG_IS_ENABLED(CLK)
+ clk_disable(&priv->clk);
+#endif
+
ret = reset_assert(&priv->reset);
if (ret)
return ret;
@@ -125,6 +308,8 @@ int meson_g12a_usb2_phy_probe(struct udevice *dev)
struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev);
int ret;
+ priv->soc_id = (enum meson_soc_id)dev_get_driver_data(dev);
+
ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
if (ret)
return ret;
@@ -141,24 +326,40 @@ int meson_g12a_usb2_phy_probe(struct udevice *dev)
return ret;
}
+#if CONFIG_IS_ENABLED(POWER_DOMAIN)
+ ret = power_domain_get(dev, &priv->pwrdm);
+ if (ret < 0 && ret != -ENODEV && ret != -ENOENT) {
+ pr_err("failed to get power domain : %d\n", ret);
+ return ret;
+ }
+
+ if (ret != -ENODEV && ret != -ENOENT) {
+ ret = power_domain_on(&priv->pwrdm);
+ if (ret < 0) {
+ pr_err("failed to enable power domain\n");
+ return ret;
+ }
+ }
+#endif
+
#if CONFIG_IS_ENABLED(CLK)
ret = clk_get_by_index(dev, 0, &priv->clk);
if (ret < 0)
return ret;
-
- ret = clk_enable(&priv->clk);
- if (ret && ret != -ENOSYS && ret != -ENOTSUPP) {
- pr_err("failed to enable PHY clock\n");
- clk_free(&priv->clk);
- return ret;
- }
#endif
return 0;
}
static const struct udevice_id meson_g12a_usb2_phy_ids[] = {
- { .compatible = "amlogic,g12a-usb2-phy" },
+ {
+ .compatible = "amlogic,g12a-usb2-phy",
+ .data = (ulong)MESON_SOC_G12A,
+ },
+ {
+ .compatible = "amlogic,a1-usb2-phy",
+ .data = (ulong)MESON_SOC_A1,
+ },
{ }
};
diff --git a/drivers/phy/nop-phy.c b/drivers/phy/nop-phy.c
index d0904f4f075..c53e3216d0f 100644
--- a/drivers/phy/nop-phy.c
+++ b/drivers/phy/nop-phy.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/
* Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
*/
diff --git a/drivers/phy/omap-usb2-phy.c b/drivers/phy/omap-usb2-phy.c
index 2a9604cdcc4..d3d38062ecf 100644
--- a/drivers/phy/omap-usb2-phy.c
+++ b/drivers/phy/omap-usb2-phy.c
@@ -2,7 +2,7 @@
/*
* OMAP USB2 PHY LAYER
*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com
* Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
*/
diff --git a/drivers/phy/phy-bcm-sr-pcie.c b/drivers/phy/phy-bcm-sr-pcie.c
index f0e795333b9..cf33bab3707 100644
--- a/drivers/phy/phy-bcm-sr-pcie.c
+++ b/drivers/phy/phy-bcm-sr-pcie.c
@@ -143,8 +143,8 @@ static int sr_pcie_phy_probe(struct udevice *dev)
core->dev = dev;
- core->base = (void __iomem *)devfdt_get_addr_name(dev, "reg_base");
- core->cdru = (void __iomem *)devfdt_get_addr_name(dev, "cdru_base");
+ core->base = (void __iomem *)dev_read_addr_name_ptr(dev, "reg_base");
+ core->cdru = (void __iomem *)dev_read_addr_name_ptr(dev, "cdru_base");
debug("ip base %p\n", core->base);
debug("cdru base %p\n", core->cdru);
diff --git a/drivers/phy/phy-core-mipi-dphy.c b/drivers/phy/phy-core-mipi-dphy.c
index ba5f6486126..bb61816add2 100644
--- a/drivers/phy/phy-core-mipi-dphy.c
+++ b/drivers/phy/phy-core-mipi-dphy.c
@@ -6,11 +6,10 @@
#include <common.h>
#include <div64.h>
+#include <linux/time.h>
#include <phy-mipi-dphy.h>
-#define PSEC_PER_SEC 1000000000000LL
-
/*
* Minimum D-PHY timings based on MIPI D-PHY specification. Derived
* from the valid ranges specified in Section 6.9, Table 14, Page 41
diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c
index 22f2fe91487..0dcfe258bc4 100644
--- a/drivers/phy/phy-uclass.c
+++ b/drivers/phy/phy-uclass.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/
* Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
*/
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c
index 9ed7af0d6ef..5be76e05339 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c
@@ -15,6 +15,7 @@
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/math64.h>
+#include <linux/time.h>
#include <phy-mipi-dphy.h>
#include <reset.h>
@@ -186,8 +187,6 @@
#define DSI_PHY_STATUS 0xb0
#define PHY_LOCK BIT(0)
-#define PSEC_PER_SEC 1000000000000LL
-
#define msleep(a) udelay(a * 1000)
enum phy_max_rate {
diff --git a/drivers/phy/sandbox-phy.c b/drivers/phy/sandbox-phy.c
index 7b3d988613b..7e123da25fb 100644
--- a/drivers/phy/sandbox-phy.c
+++ b/drivers/phy/sandbox-phy.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/
* Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
*/
diff --git a/drivers/phy/ti-pipe3-phy.c b/drivers/phy/ti-pipe3-phy.c
index 313735844ab..29a35ae5ffb 100644
--- a/drivers/phy/ti-pipe3-phy.c
+++ b/drivers/phy/ti-pipe3-phy.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/
* Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
*/
diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c
index 72613399073..daf62f5deda 100644
--- a/drivers/phy/ti/phy-j721e-wiz.c
+++ b/drivers/phy/ti/phy-j721e-wiz.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2017-2018 Texas Instruments Incorporated - https://www.ti.com/
* Jean-Jacques Hiblot <jjhiblot@ti.com>
*/
diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c
index 7976e3b3ed5..ff49819b58d 100644
--- a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c
+++ b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c
@@ -329,6 +329,7 @@ struct group_info {
static const struct group_info npcm8xx_groups[] = {
FUNC_LIST
+ {FN_gpio, "GPIO", NULL, 0, 0, 0}
};
/* Pin flags */
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index d80281fd3dd..d1db377c137 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -5,6 +5,7 @@
*/
#include <common.h>
+#include <mapmem.h>
#include <dm.h>
#include <dm/device_compat.h>
#include <dm/devres.h>
@@ -24,7 +25,7 @@
* @bits_per_mux: true if one register controls more than one pin
*/
struct single_pdata {
- fdt_addr_t base;
+ void *base;
int offset;
u32 mask;
u32 width;
@@ -97,7 +98,7 @@ struct single_fdt_bits_cfg {
#if (!IS_ENABLED(CONFIG_SANDBOX))
-static unsigned int single_read(struct udevice *dev, fdt_addr_t reg)
+static unsigned int single_read(struct udevice *dev, void *reg)
{
struct single_pdata *pdata = dev_get_plat(dev);
@@ -113,7 +114,7 @@ static unsigned int single_read(struct udevice *dev, fdt_addr_t reg)
return readb(reg);
}
-static void single_write(struct udevice *dev, unsigned int val, fdt_addr_t reg)
+static void single_write(struct udevice *dev, unsigned int val, void *reg)
{
struct single_pdata *pdata = dev_get_plat(dev);
@@ -131,18 +132,18 @@ static void single_write(struct udevice *dev, unsigned int val, fdt_addr_t reg)
#else /* CONFIG_SANDBOX */
-static unsigned int single_read(struct udevice *dev, fdt_addr_t reg)
+static unsigned int single_read(struct udevice *dev, void *reg)
{
struct single_priv *priv = dev_get_priv(dev);
- return priv->sandbox_regs[reg];
+ return priv->sandbox_regs[map_to_sysmem(reg)];
}
-static void single_write(struct udevice *dev, unsigned int val, fdt_addr_t reg)
+static void single_write(struct udevice *dev, unsigned int val, void *reg)
{
struct single_priv *priv = dev_get_priv(dev);
- priv->sandbox_regs[reg] = val;
+ priv->sandbox_regs[map_to_sysmem(reg)] = val;
}
#endif /* CONFIG_SANDBOX */
@@ -214,7 +215,8 @@ static int single_get_pin_muxing(struct udevice *dev, unsigned int pin,
{
struct single_pdata *pdata = dev_get_plat(dev);
struct single_priv *priv = dev_get_priv(dev);
- fdt_addr_t reg;
+ phys_addr_t phys_reg;
+ void *reg;
const char *fname;
unsigned int val;
int offset, pin_shift = 0;
@@ -226,13 +228,15 @@ static int single_get_pin_muxing(struct udevice *dev, unsigned int pin,
reg = pdata->base + offset;
val = single_read(dev, reg);
+ phys_reg = map_to_sysmem(reg);
+
if (pdata->bits_per_mux)
pin_shift = pin % (pdata->width / priv->bits_per_pin) *
priv->bits_per_pin;
val &= (pdata->mask << pin_shift);
fname = single_get_pin_function(dev, pin);
- snprintf(buf, size, "%pa 0x%08x %s", &reg, val,
+ snprintf(buf, size, "%pa 0x%08x %s", &phys_reg, val,
fname ? fname : "UNCLAIMED");
return 0;
}
@@ -243,7 +247,7 @@ static int single_request(struct udevice *dev, int pin, int flags)
struct single_pdata *pdata = dev_get_plat(dev);
struct single_gpiofunc_range *frange = NULL;
struct list_head *pos, *tmp;
- phys_addr_t reg;
+ void *reg;
int mux_bytes = 0;
u32 data;
@@ -321,7 +325,7 @@ static int single_configure_pins(struct udevice *dev,
int stride = pdata->args_count + 1;
int n, pin, count = size / sizeof(u32);
struct single_func *func;
- phys_addr_t reg;
+ void *reg;
u32 offset, val, mux;
/* If function mask is null, needn't enable it. */
@@ -379,7 +383,7 @@ static int single_configure_bits(struct udevice *dev,
int n, pin, count = size / sizeof(struct single_fdt_bits_cfg);
int npins_in_reg, pin_num_from_lsb;
struct single_func *func;
- phys_addr_t reg;
+ void *reg;
u32 offset, val, mask, bit_pos, val_pos, mask_pos, submask;
/* If function mask is null, needn't enable it. */
@@ -570,7 +574,7 @@ static int single_probe(struct udevice *dev)
static int single_of_to_plat(struct udevice *dev)
{
- fdt_addr_t addr;
+ void *addr;
fdt_size_t size;
struct single_pdata *pdata = dev_get_plat(dev);
int ret;
@@ -591,8 +595,8 @@ static int single_of_to_plat(struct udevice *dev)
return -EINVAL;
}
- addr = dev_read_addr_size_index(dev, 0, &size);
- if (addr == FDT_ADDR_T_NONE) {
+ addr = dev_read_addr_size_index_ptr(dev, 0, &size);
+ if (!addr) {
dev_err(dev, "failed to get base register address\n");
return -EINVAL;
}
diff --git a/drivers/pinctrl/pinctrl-zynqmp.c b/drivers/pinctrl/pinctrl-zynqmp.c
index 517035961da..eb17a4290b7 100644
--- a/drivers/pinctrl/pinctrl-zynqmp.c
+++ b/drivers/pinctrl/pinctrl-zynqmp.c
@@ -548,6 +548,8 @@ static int zynqmp_pinctrl_get_pin_muxing(struct udevice *dev,
&pinmux.drive_strength);
zynqmp_pm_pinctrl_get_config(selector, PM_PINCTRL_CONFIG_VOLTAGE_STATUS,
&pinmux.volt_sts);
+ zynqmp_pm_pinctrl_get_config(selector, PM_PINCTRL_CONFIG_TRI_STATE,
+ &pinmux.tri_state);
switch (pinmux.drive_strength) {
case PM_PINCTRL_DRIVE_STRENGTH_2MA:
@@ -568,13 +570,15 @@ static int zynqmp_pinctrl_get_pin_muxing(struct udevice *dev,
return -EINVAL;
}
- snprintf(buf, size, "slew:%s\tbias:%s\tpull:%s\tinput:%s\tdrive:%dmA\tvolt:%s",
+ snprintf(buf, size,
+ "slew:%s\tbias:%s\tpull:%s\tinput:%s\tdrive:%dmA\tvolt:%s\ttri_state:%s",
pinmux.slew ? "slow" : "fast",
pinmux.bias ? "enabled" : "disabled",
pinmux.pull_ctrl ? "up" : "down",
pinmux.input_type ? "schmitt" : "cmos",
pinmux.drive_strength,
- pinmux.volt_sts ? "1.8" : "3.3");
+ pinmux.volt_sts ? "1.8" : "3.3",
+ pinmux.tri_state ? "enabled" : "disabled");
return 0;
}
diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c
index 8bb7588714a..7120b8edba0 100644
--- a/drivers/pinctrl/pinctrl_stm32.c
+++ b/drivers/pinctrl/pinctrl_stm32.c
@@ -505,6 +505,8 @@ static const struct udevice_id stm32_pinctrl_ids[] = {
{ .compatible = "st,stm32mp157-pinctrl" },
{ .compatible = "st,stm32mp157-z-pinctrl" },
{ .compatible = "st,stm32mp135-pinctrl" },
+ { .compatible = "st,stm32mp257-pinctrl" },
+ { .compatible = "st,stm32mp257-z-pinctrl" },
{ }
};
diff --git a/drivers/pinctrl/renesas/Kconfig b/drivers/pinctrl/renesas/Kconfig
index 32f44e5bbd7..4c8ec9fcf18 100644
--- a/drivers/pinctrl/renesas/Kconfig
+++ b/drivers/pinctrl/renesas/Kconfig
@@ -138,6 +138,15 @@ config PINCTRL_RZA1
help
Support pin multiplexing control on Renesas RZ/A1 R7S72100 SoCs.
+config PINCTRL_RZG2L
+ bool "Renesas RZ/G2L family pin control driver"
+ depends on PINCTRL
+ depends on PINCTRL_GENERIC
+ depends on PINCONF
+ help
+ Support the pinctrl functionality of the pin function controller (PFC)
+ on the Renesas RZ/G2L SoC family.
+
endif
config PINCTRL_RZN1
diff --git a/drivers/pinctrl/renesas/Makefile b/drivers/pinctrl/renesas/Makefile
index f9a68794eb9..cf7ec109681 100644
--- a/drivers/pinctrl/renesas/Makefile
+++ b/drivers/pinctrl/renesas/Makefile
@@ -21,3 +21,4 @@ obj-$(CONFIG_PINCTRL_PFC_R8A779F0) += pfc-r8a779f0.o
obj-$(CONFIG_PINCTRL_PFC_R8A779G0) += pfc-r8a779g0.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/rzg2l-pfc.c b/drivers/pinctrl/renesas/rzg2l-pfc.c
new file mode 100644
index 00000000000..e88ec1c1837
--- /dev/null
+++ b/drivers/pinctrl/renesas/rzg2l-pfc.c
@@ -0,0 +1,624 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/G2L Pin Function Controller
+ *
+ * Copyright (C) 2021-2023 Renesas Electronics Corp.
+ */
+
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <dm/lists.h>
+#include <dm/pinctrl.h>
+#include <renesas/rzg2l-pfc.h>
+#include <reset.h>
+
+struct rzg2l_pfc_driver_data {
+ uint num_dedicated_pins;
+ uint num_ports;
+ const u32 *gpio_configs;
+};
+
+struct rzg2l_dedicated_configs {
+ const char *name;
+ u32 config;
+};
+
+/*
+ * We need to ensure that the module clock is enabled and all resets are
+ * de-asserted before using either the gpio or pinctrl functionality. Error
+ * handling can be quite simple here as if the PFC cannot be enabled then we
+ * will not be able to progress with the boot anyway.
+ */
+int rzg2l_pfc_enable(struct udevice *dev)
+{
+ struct reset_ctl_bulk rsts;
+ struct clk clk;
+ int ret;
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret < 0) {
+ dev_err(dev, "failed to get gpio module clock\n");
+ return ret;
+ }
+
+ ret = clk_enable(&clk);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable gpio module clock\n");
+ return ret;
+ }
+
+ ret = reset_get_bulk(dev, &rsts);
+ if (ret < 0) {
+ dev_err(dev, "failed to get reset lines\n");
+ return ret;
+ }
+
+ ret = reset_deassert_bulk(&rsts);
+ if (ret < 0) {
+ dev_err(dev, "failed to de-assert reset lines\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+bool rzg2l_port_validate(const struct rzg2l_pfc_data *data, u32 port, u8 pin)
+{
+ return (port < data->num_ports) &&
+ (pin < RZG2L_GPIO_PORT_GET_PINCNT(data->gpio_configs[port]));
+}
+
+/* Decode a pin selector, returning the port index and setting *pin to the pin
+ * index. Returns -1 on error, which can be checked directly or by calling
+ * rzg2l_port_validate().
+ */
+static int rzg2l_selector_decode(const struct rzg2l_pfc_data *data,
+ unsigned int selector,
+ u8 *pin)
+{
+ int port;
+
+ selector -= data->num_dedicated_pins;
+ for (port = 0; port < data->num_ports; port++) {
+ u8 num_pins = RZG2L_GPIO_PORT_GET_PINCNT(data->gpio_configs[port]);
+ if (selector < num_pins) {
+ *pin = (u8)selector;
+ return port;
+ }
+ selector -= num_pins;
+ }
+ return -EINVAL;
+}
+
+static unsigned int rzg2l_selector_encode(const struct rzg2l_pfc_data *data,
+ u32 port, u8 pin)
+{
+ unsigned int selector = data->num_dedicated_pins + pin;
+ u32 i;
+
+ for (i = 0; i < port; i++)
+ selector += RZG2L_GPIO_PORT_GET_PINCNT(data->gpio_configs[i]);
+
+ return selector;
+}
+
+static const char * const rzg2l_gpio_names[] = {
+ "P0_0", "P0_1", "P0_2", "P0_3", "P0_4", "P0_5", "P0_6", "P0_7",
+ "P1_0", "P1_1", "P1_2", "P1_3", "P1_4", "P1_5", "P1_6", "P1_7",
+ "P2_0", "P2_1", "P2_2", "P2_3", "P2_4", "P2_5", "P2_6", "P2_7",
+ "P3_0", "P3_1", "P3_2", "P3_3", "P3_4", "P3_5", "P3_6", "P3_7",
+ "P4_0", "P4_1", "P4_2", "P4_3", "P4_4", "P4_5", "P4_6", "P4_7",
+ "P5_0", "P5_1", "P5_2", "P5_3", "P5_4", "P5_5", "P5_6", "P5_7",
+ "P6_0", "P6_1", "P6_2", "P6_3", "P6_4", "P6_5", "P6_6", "P6_7",
+ "P7_0", "P7_1", "P7_2", "P7_3", "P7_4", "P7_5", "P7_6", "P7_7",
+ "P8_0", "P8_1", "P8_2", "P8_3", "P8_4", "P8_5", "P8_6", "P8_7",
+ "P9_0", "P9_1", "P9_2", "P9_3", "P9_4", "P9_5", "P9_6", "P9_7",
+ "P10_0", "P10_1", "P10_2", "P10_3", "P10_4", "P10_5", "P10_6", "P10_7",
+ "P11_0", "P11_1", "P11_2", "P11_3", "P11_4", "P11_5", "P11_6", "P11_7",
+ "P12_0", "P12_1", "P12_2", "P12_3", "P12_4", "P12_5", "P12_6", "P12_7",
+ "P13_0", "P13_1", "P13_2", "P13_3", "P13_4", "P13_5", "P13_6", "P13_7",
+ "P14_0", "P14_1", "P14_2", "P14_3", "P14_4", "P14_5", "P14_6", "P14_7",
+ "P15_0", "P15_1", "P15_2", "P15_3", "P15_4", "P15_5", "P15_6", "P15_7",
+ "P16_0", "P16_1", "P16_2", "P16_3", "P16_4", "P16_5", "P16_6", "P16_7",
+ "P17_0", "P17_1", "P17_2", "P17_3", "P17_4", "P17_5", "P17_6", "P17_7",
+ "P18_0", "P18_1", "P18_2", "P18_3", "P18_4", "P18_5", "P18_6", "P18_7",
+ "P19_0", "P19_1", "P19_2", "P19_3", "P19_4", "P19_5", "P19_6", "P19_7",
+ "P20_0", "P20_1", "P20_2", "P20_3", "P20_4", "P20_5", "P20_6", "P20_7",
+ "P21_0", "P21_1", "P21_2", "P21_3", "P21_4", "P21_5", "P21_6", "P21_7",
+ "P22_0", "P22_1", "P22_2", "P22_3", "P22_4", "P22_5", "P22_6", "P22_7",
+ "P23_0", "P23_1", "P23_2", "P23_3", "P23_4", "P23_5", "P23_6", "P23_7",
+ "P24_0", "P24_1", "P24_2", "P24_3", "P24_4", "P24_5", "P24_6", "P24_7",
+ "P25_0", "P25_1", "P25_2", "P25_3", "P25_4", "P25_5", "P25_6", "P25_7",
+ "P26_0", "P26_1", "P26_2", "P26_3", "P26_4", "P26_5", "P26_6", "P26_7",
+ "P27_0", "P27_1", "P27_2", "P27_3", "P27_4", "P27_5", "P27_6", "P27_7",
+ "P28_0", "P28_1", "P28_2", "P28_3", "P28_4", "P28_5", "P28_6", "P28_7",
+ "P29_0", "P29_1", "P29_2", "P29_3", "P29_4", "P29_5", "P29_6", "P29_7",
+ "P30_0", "P30_1", "P30_2", "P30_3", "P30_4", "P30_5", "P30_6", "P30_7",
+ "P31_0", "P31_1", "P31_2", "P31_3", "P31_4", "P31_5", "P31_6", "P31_7",
+ "P32_0", "P32_1", "P32_2", "P32_3", "P32_4", "P32_5", "P32_6", "P32_7",
+ "P33_0", "P33_1", "P33_2", "P33_3", "P33_4", "P33_5", "P33_6", "P33_7",
+ "P34_0", "P34_1", "P34_2", "P34_3", "P34_4", "P34_5", "P34_6", "P34_7",
+ "P35_0", "P35_1", "P35_2", "P35_3", "P35_4", "P35_5", "P35_6", "P35_7",
+ "P36_0", "P36_1", "P36_2", "P36_3", "P36_4", "P36_5", "P36_6", "P36_7",
+ "P37_0", "P37_1", "P37_2", "P37_3", "P37_4", "P37_5", "P37_6", "P37_7",
+ "P38_0", "P38_1", "P38_2", "P38_3", "P38_4", "P38_5", "P38_6", "P38_7",
+ "P39_0", "P39_1", "P39_2", "P39_3", "P39_4", "P39_5", "P39_6", "P39_7",
+ "P40_0", "P40_1", "P40_2", "P40_3", "P40_4", "P40_5", "P40_6", "P40_7",
+ "P41_0", "P41_1", "P41_2", "P41_3", "P41_4", "P41_5", "P41_6", "P41_7",
+ "P42_0", "P42_1", "P42_2", "P42_3", "P42_4", "P42_5", "P42_6", "P42_7",
+ "P43_0", "P43_1", "P43_2", "P43_3", "P43_4", "P43_5", "P43_6", "P43_7",
+ "P44_0", "P44_1", "P44_2", "P44_3", "P44_4", "P44_5", "P44_6", "P44_7",
+ "P45_0", "P45_1", "P45_2", "P45_3", "P45_4", "P45_5", "P45_6", "P45_7",
+ "P46_0", "P46_1", "P46_2", "P46_3", "P46_4", "P46_5", "P46_6", "P46_7",
+ "P47_0", "P47_1", "P47_2", "P47_3", "P47_4", "P47_5", "P47_6", "P47_7",
+ "P48_0", "P48_1", "P48_2", "P48_3", "P48_4", "P48_5", "P48_6", "P48_7",
+};
+
+static const u32 r9a07g044_gpio_configs[] = {
+ RZG2L_GPIO_PORT_PACK(2, 0x10, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(2, 0x11, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(2, 0x12, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(2, 0x13, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(2, 0x14, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(3, 0x15, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(2, 0x16, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(3, 0x17, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(3, 0x18, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(2, 0x19, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(2, 0x1a, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(2, 0x1b, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(2, 0x1c, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(3, 0x1d, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(2, 0x1e, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(2, 0x1f, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(2, 0x20, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(3, 0x21, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(2, 0x22, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(2, 0x23, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(3, 0x24, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)),
+ RZG2L_GPIO_PORT_PACK(2, 0x25, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)),
+ RZG2L_GPIO_PORT_PACK(2, 0x26, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)),
+ RZG2L_GPIO_PORT_PACK(2, 0x27, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)),
+ RZG2L_GPIO_PORT_PACK(2, 0x28, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)),
+ RZG2L_GPIO_PORT_PACK(2, 0x29, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)),
+ RZG2L_GPIO_PORT_PACK(2, 0x2a, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)),
+ RZG2L_GPIO_PORT_PACK(2, 0x2b, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)),
+ RZG2L_GPIO_PORT_PACK(2, 0x2c, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)),
+ RZG2L_GPIO_PORT_PACK(2, 0x2d, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1)),
+ RZG2L_GPIO_PORT_PACK(2, 0x2e, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1)),
+ RZG2L_GPIO_PORT_PACK(2, 0x2f, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1)),
+ RZG2L_GPIO_PORT_PACK(2, 0x30, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1)),
+ RZG2L_GPIO_PORT_PACK(2, 0x31, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1)),
+ RZG2L_GPIO_PORT_PACK(2, 0x32, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1)),
+ RZG2L_GPIO_PORT_PACK(2, 0x33, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1)),
+ RZG2L_GPIO_PORT_PACK(2, 0x34, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1)),
+ RZG2L_GPIO_PORT_PACK(3, 0x35, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1)),
+ RZG2L_GPIO_PORT_PACK(2, 0x36, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(3, 0x37, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(3, 0x38, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(2, 0x39, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(5, 0x3a, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(4, 0x3b, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(4, 0x3c, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(4, 0x3d, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(4, 0x3e, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(4, 0x3f, RZG2L_MPXED_PIN_FUNCS),
+ RZG2L_GPIO_PORT_PACK(5, 0x40, RZG2L_MPXED_PIN_FUNCS),
+};
+
+static const struct {
+ struct rzg2l_dedicated_configs common[35];
+ struct rzg2l_dedicated_configs rzg2l_pins[7];
+} rzg2l_dedicated_pins = {
+ .common = {
+ { "NMI", RZG2L_SINGLE_PIN_PACK(0x1, 0,
+ (PIN_CFG_FILONOFF | PIN_CFG_FILNUM | PIN_CFG_FILCLKSEL)) },
+ { "TMS/SWDIO", RZG2L_SINGLE_PIN_PACK(0x2, 0,
+ (PIN_CFG_IOLH_A | PIN_CFG_SR | PIN_CFG_IEN)) },
+ { "TDO", RZG2L_SINGLE_PIN_PACK(0x3, 0,
+ (PIN_CFG_IOLH_A | PIN_CFG_SR | PIN_CFG_IEN)) },
+ { "AUDIO_CLK1", RZG2L_SINGLE_PIN_PACK(0x4, 0, PIN_CFG_IEN) },
+ { "AUDIO_CLK2", RZG2L_SINGLE_PIN_PACK(0x4, 1, PIN_CFG_IEN) },
+ { "SD0_CLK", RZG2L_SINGLE_PIN_PACK(0x6, 0,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IO_VMC_SD0)) },
+ { "SD0_CMD", RZG2L_SINGLE_PIN_PACK(0x6, 1,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IEN | PIN_CFG_IO_VMC_SD0)) },
+ { "SD0_RST#", RZG2L_SINGLE_PIN_PACK(0x6, 2,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IO_VMC_SD0)) },
+ { "SD0_DATA0", RZG2L_SINGLE_PIN_PACK(0x7, 0,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IEN | PIN_CFG_IO_VMC_SD0)) },
+ { "SD0_DATA1", RZG2L_SINGLE_PIN_PACK(0x7, 1,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IEN | PIN_CFG_IO_VMC_SD0)) },
+ { "SD0_DATA2", RZG2L_SINGLE_PIN_PACK(0x7, 2,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IEN | PIN_CFG_IO_VMC_SD0)) },
+ { "SD0_DATA3", RZG2L_SINGLE_PIN_PACK(0x7, 3,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IEN | PIN_CFG_IO_VMC_SD0)) },
+ { "SD0_DATA4", RZG2L_SINGLE_PIN_PACK(0x7, 4,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IEN | PIN_CFG_IO_VMC_SD0)) },
+ { "SD0_DATA5", RZG2L_SINGLE_PIN_PACK(0x7, 5,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IEN | PIN_CFG_IO_VMC_SD0)) },
+ { "SD0_DATA6", RZG2L_SINGLE_PIN_PACK(0x7, 6,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IEN | PIN_CFG_IO_VMC_SD0)) },
+ { "SD0_DATA7", RZG2L_SINGLE_PIN_PACK(0x7, 7,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IEN | PIN_CFG_IO_VMC_SD0)) },
+ { "SD1_CLK", RZG2L_SINGLE_PIN_PACK(0x8, 0,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IO_VMC_SD1)) },
+ { "SD1_CMD", RZG2L_SINGLE_PIN_PACK(0x8, 1,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IEN | PIN_CFG_IO_VMC_SD1)) },
+ { "SD1_DATA0", RZG2L_SINGLE_PIN_PACK(0x9, 0,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IEN | PIN_CFG_IO_VMC_SD1)) },
+ { "SD1_DATA1", RZG2L_SINGLE_PIN_PACK(0x9, 1,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IEN | PIN_CFG_IO_VMC_SD1)) },
+ { "SD1_DATA2", RZG2L_SINGLE_PIN_PACK(0x9, 2,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IEN | PIN_CFG_IO_VMC_SD1)) },
+ { "SD1_DATA3", RZG2L_SINGLE_PIN_PACK(0x9, 3,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IEN | PIN_CFG_IO_VMC_SD1)) },
+ { "QSPI0_SPCLK", RZG2L_SINGLE_PIN_PACK(0xa, 0,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IO_VMC_QSPI)) },
+ { "QSPI0_IO0", RZG2L_SINGLE_PIN_PACK(0xa, 1,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IO_VMC_QSPI)) },
+ { "QSPI0_IO1", RZG2L_SINGLE_PIN_PACK(0xa, 2,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IO_VMC_QSPI)) },
+ { "QSPI0_IO2", RZG2L_SINGLE_PIN_PACK(0xa, 3,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IO_VMC_QSPI)) },
+ { "QSPI0_IO3", RZG2L_SINGLE_PIN_PACK(0xa, 4,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IO_VMC_QSPI)) },
+ { "QSPI0_SSL", RZG2L_SINGLE_PIN_PACK(0xa, 5,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IO_VMC_QSPI)) },
+ { "QSPI_RESET#", RZG2L_SINGLE_PIN_PACK(0xc, 0,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IO_VMC_QSPI)) },
+ { "QSPI_WP#", RZG2L_SINGLE_PIN_PACK(0xc, 1,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IO_VMC_QSPI)) },
+ { "WDTOVF_PERROUT#", RZG2L_SINGLE_PIN_PACK(0xd, 0, (PIN_CFG_IOLH_A | PIN_CFG_SR)) },
+ { "RIIC0_SDA", RZG2L_SINGLE_PIN_PACK(0xe, 0, PIN_CFG_IEN) },
+ { "RIIC0_SCL", RZG2L_SINGLE_PIN_PACK(0xe, 1, PIN_CFG_IEN) },
+ { "RIIC1_SDA", RZG2L_SINGLE_PIN_PACK(0xe, 2, PIN_CFG_IEN) },
+ { "RIIC1_SCL", RZG2L_SINGLE_PIN_PACK(0xe, 3, PIN_CFG_IEN) },
+ },
+ .rzg2l_pins = {
+ { "QSPI_INT#", RZG2L_SINGLE_PIN_PACK(0xc, 2, (PIN_CFG_SR | PIN_CFG_IO_VMC_QSPI)) },
+ { "QSPI1_SPCLK", RZG2L_SINGLE_PIN_PACK(0xb, 0,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IO_VMC_QSPI)) },
+ { "QSPI1_IO0", RZG2L_SINGLE_PIN_PACK(0xb, 1,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IO_VMC_QSPI)) },
+ { "QSPI1_IO1", RZG2L_SINGLE_PIN_PACK(0xb, 2,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IO_VMC_QSPI)) },
+ { "QSPI1_IO2", RZG2L_SINGLE_PIN_PACK(0xb, 3,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IO_VMC_QSPI)) },
+ { "QSPI1_IO3", RZG2L_SINGLE_PIN_PACK(0xb, 4,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IO_VMC_QSPI)) },
+ { "QSPI1_SSL", RZG2L_SINGLE_PIN_PACK(0xb, 5,
+ (PIN_CFG_IOLH_B | PIN_CFG_SR | PIN_CFG_IO_VMC_QSPI)) },
+ }
+};
+
+static void rzg2l_rmw_pin_config(const struct rzg2l_pfc_data *data, u32 offset,
+ u8 pin, u32 mask, u32 val)
+{
+ void __iomem *addr = data->base + offset;
+
+ /* handle _L/_H for 32-bit register read/write */
+ if (pin >= 4) {
+ pin -= 4;
+ addr += 4;
+ }
+
+ clrsetbits_le32(addr, mask << (pin * 8), val << (pin * 8));
+}
+
+static int rzg2l_get_pins_count(struct udevice *dev)
+{
+ const struct rzg2l_pfc_data *data =
+ (const struct rzg2l_pfc_data *)dev_get_driver_data(dev);
+
+ return data->num_dedicated_pins + data->num_pins;
+}
+
+static const char *rzg2l_get_pin_name(struct udevice *dev, unsigned int selector)
+{
+ const struct rzg2l_pfc_data *data =
+ (const struct rzg2l_pfc_data *)dev_get_driver_data(dev);
+ int port;
+ u8 pin;
+
+ if (selector < data->num_dedicated_pins) {
+ if (selector >= ARRAY_SIZE(rzg2l_dedicated_pins.common)) {
+ unsigned int u = selector - ARRAY_SIZE(rzg2l_dedicated_pins.common);
+ return rzg2l_dedicated_pins.rzg2l_pins[u].name;
+ } else {
+ return rzg2l_dedicated_pins.common[selector].name;
+ }
+ }
+
+ port = rzg2l_selector_decode(data, selector, &pin);
+ if (port < 0)
+ return "(invalid pin)";
+ return rzg2l_gpio_names[pin + 8 * port];
+}
+
+static int rzg2l_pinconf_set(struct udevice *dev, unsigned int pin_selector,
+ unsigned int param, unsigned int argument)
+{
+ const struct rzg2l_pfc_data *data =
+ (const struct rzg2l_pfc_data *)dev_get_driver_data(dev);
+ u32 cfg, port_offset;
+ u8 pin;
+
+ if (pin_selector >= data->num_dedicated_pins) {
+ /* The pin selector refers to a multiplexed pin */
+ int port = rzg2l_selector_decode(data, pin_selector, &pin);
+ if (port < 0) {
+ dev_err(dev, "Invalid pin selector %u:%u\n", port, pin);
+ return port;
+ }
+
+ cfg = data->gpio_configs[port];
+ port_offset = P(port);
+ } else {
+ /* The pin selector refers to a dedicated function pin */
+ const struct rzg2l_dedicated_configs *dedicated_config;
+
+ if (pin_selector >= data->num_dedicated_pins) {
+ dev_err(dev, "Invalid dedicated pin %u\n", pin_selector);
+ return -EINVAL;
+ }
+
+ if (pin_selector >= ARRAY_SIZE(rzg2l_dedicated_pins.common)) {
+ pin_selector -= ARRAY_SIZE(rzg2l_dedicated_pins.common);
+ dedicated_config = &rzg2l_dedicated_pins.rzg2l_pins[pin_selector];
+ } else {
+ dedicated_config = &rzg2l_dedicated_pins.common[pin_selector];
+ }
+
+ port_offset = RZG2L_SINGLE_PIN_GET_PORT_OFFSET(dedicated_config->config);
+ pin = RZG2L_SINGLE_PIN_GET_BIT(dedicated_config->config);
+ cfg = RZG2L_SINGLE_PIN_GET_CFGS(dedicated_config->config);
+ }
+
+ switch (param) {
+ case PIN_CONFIG_INPUT_ENABLE: {
+ if (!(cfg & PIN_CFG_IEN)) {
+ dev_err(dev, "pin does not support IEN\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(dev, "port off %u:%u set IEN=%u\n",
+ port_offset, pin, argument);
+ rzg2l_rmw_pin_config(data, IEN(port_offset), pin, IEN_MASK, !!argument);
+ break;
+ }
+
+ case PIN_CONFIG_POWER_SOURCE: {
+ u32 pwr_reg = 0x0;
+
+ /* argument is in mV */
+ if (argument != 1800 && argument != 3300) {
+ dev_err(dev, "Invalid mV %u\n", argument);
+ return -EINVAL;
+ }
+
+ /*
+ * TODO: PIN_CFG_IO_VMC_ETH0 & PIN_CFG_IO_VMC_ETH1 will be
+ * handled when the RZ/G2L Ethernet driver is added.
+ */
+ if (cfg & PIN_CFG_IO_VMC_SD0) {
+ dev_dbg(dev, "port off %u:%u set SD_CH 0 PVDD=%u\n",
+ port_offset, pin, argument);
+ pwr_reg = SD_CH(0);
+ } else if (cfg & PIN_CFG_IO_VMC_SD1) {
+ dev_dbg(dev, "port off %u:%u set SD_CH 1 PVDD=%u\n",
+ port_offset, pin, argument);
+ pwr_reg = SD_CH(1);
+ } else if (cfg & PIN_CFG_IO_VMC_QSPI) {
+ dev_dbg(dev, "port off %u:%u set QSPI PVDD=%u\n",
+ port_offset, pin, argument);
+ pwr_reg = QSPI;
+ } else {
+ dev_dbg(dev, "pin power source is not selectable\n");
+ return -EINVAL;
+ }
+
+ writel((argument == 1800) ? PVDD_1800 : PVDD_3300,
+ data->base + pwr_reg);
+ break;
+ }
+
+ default:
+ dev_err(dev, "Invalid pinconf parameter\n");
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int rzg2l_pinmux_property_set(struct udevice *dev, u32 pinmux_group)
+{
+ const struct rzg2l_pfc_data *data =
+ (const struct rzg2l_pfc_data *)dev_get_driver_data(dev);
+ u32 port, pin, func, pfc_state;
+ u8 pmc_state;
+
+ func = RZG2L_PINMUX_TO_FUNC(pinmux_group);
+ if (func > 5) {
+ dev_err(dev, "Invalid pin function %u\n", func);
+ return -EINVAL;
+ }
+
+ port = RZG2L_PINMUX_TO_PORT(pinmux_group);
+ pin = RZG2L_PINMUX_TO_PIN(pinmux_group);
+ if (!rzg2l_port_validate(data, port, pin)) {
+ dev_err(dev, "Invalid pin selector %u:%u\n", port, pin);
+ return -EINVAL;
+ }
+
+ /* Check current PMC & PFC to decide if we need to change anything. */
+ pmc_state = readb(data->base + PMC(port)) & BIT(pin);
+ pfc_state = (readl(data->base + PFC(port)) >> (pin * 4)) & PFC_MASK;
+ if (pmc_state && pfc_state == func)
+ return 0;
+
+ dev_dbg(dev, "pinmux port %u pin %u func %u\n", port, pin, func);
+
+ /* Set pin to 'Non-use (Hi-Z input protection)' */
+ clrbits_le16(data->base + PM(port), PM_MASK << (pin * 2));
+
+ /* Temporarily switch to GPIO mode with PMC register */
+ clrbits_8(data->base + PMC(port), BIT(pin));
+
+ /* Set the PWPR register to allow PFC register to write */
+ writel(0x0, data->base + PWPR); /* B0WI=0, PFCWE=0 */
+ writel(PWPR_PFCWE, data->base + PWPR); /* B0WI=0, PFCWE=1 */
+
+ /* Select Pin function mode with PFC register */
+ clrsetbits_le32(data->base + PFC(port), PFC_MASK << (pin * 4),
+ func << (pin * 4));
+
+ /* Set the PWPR register to be write-protected */
+ writel(0x0, data->base + PWPR); /* B0WI=0, PFCWE=0 */
+ writel(PWPR_B0WI, data->base + PWPR); /* B0WI=1, PFCWE=0 */
+
+ /* Switch to Peripheral pin function with PMC register */
+ setbits_8(data->base + PMC(port), BIT(pin));
+
+ return rzg2l_selector_encode(data, port, pin);
+}
+
+static int rzg2l_get_pin_muxing(struct udevice *dev, unsigned int selector,
+ char *buf, int size)
+{
+ const struct rzg2l_pfc_data *data =
+ (const struct rzg2l_pfc_data *)dev_get_driver_data(dev);
+ u32 pmc_state;
+ int port;
+ u8 pin;
+
+ if (selector < data->num_dedicated_pins) {
+ snprintf(buf, size, rzg2l_get_pin_name(dev, selector));
+ return 0;
+ }
+
+ port = rzg2l_selector_decode(data, selector, &pin);
+ if (port < 0) {
+ dev_err(dev, "Invalid pin selector %u:%u\n", port, pin);
+ return port;
+ }
+
+ pmc_state = readb(data->base + PMC(port)) & BIT(pin);
+ if (pmc_state) {
+ u32 pfc_state = (readl(data->base + PFC(port)) >> (pin * 4)) & PFC_MASK;
+ snprintf(buf, size, "Function %d", pfc_state);
+ return 0;
+ }
+
+ snprintf(buf, size, "GPIO");
+ return 0;
+}
+
+static const struct pinconf_param rzg2l_pinconf_params[] = {
+ { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
+ { "power-source", PIN_CONFIG_POWER_SOURCE, 3300 /* mV */ },
+};
+
+static const struct pinctrl_ops rzg2l_pinctrl_ops = {
+ .get_pins_count = rzg2l_get_pins_count,
+ .get_pin_name = rzg2l_get_pin_name,
+
+ .pinconf_num_params = ARRAY_SIZE(rzg2l_pinconf_params),
+ .pinconf_params = rzg2l_pinconf_params,
+ .pinconf_set = rzg2l_pinconf_set,
+
+ .pinmux_property_set = rzg2l_pinmux_property_set,
+ .set_state = pinctrl_generic_set_state,
+ .get_pin_muxing = rzg2l_get_pin_muxing,
+};
+
+static int rzg2l_pinctrl_probe(struct udevice *dev)
+{
+ return rzg2l_pfc_enable(dev);
+}
+
+U_BOOT_DRIVER(rzg2l_pfc_pinctrl) = {
+ .name = "rzg2l-pfc-pinctrl",
+ .id = UCLASS_PINCTRL,
+ .ops = &rzg2l_pinctrl_ops,
+ .probe = rzg2l_pinctrl_probe,
+};
+
+static const struct rzg2l_pfc_driver_data r9a07g044_driver_data = {
+ .num_dedicated_pins = ARRAY_SIZE(rzg2l_dedicated_pins.common) +
+ ARRAY_SIZE(rzg2l_dedicated_pins.rzg2l_pins),
+ .num_ports = ARRAY_SIZE(r9a07g044_gpio_configs),
+ .gpio_configs = r9a07g044_gpio_configs,
+};
+
+static const struct udevice_id rzg2l_pfc_ids[] = {
+ { .compatible = "renesas,r9a07g044-pinctrl", .data = (ulong)&r9a07g044_driver_data },
+ { /* sentinel */ }
+};
+
+static int rzg2l_pfc_bind(struct udevice *parent)
+{
+ struct rzg2l_pfc_driver_data *driver_data;
+ struct rzg2l_pfc_data *data;
+ struct udevice *pinctrl_dev;
+ struct driver *drv;
+ unsigned int i;
+ int ret;
+
+ driver_data =
+ (struct rzg2l_pfc_driver_data *)dev_get_driver_data(parent);
+ if (!driver_data)
+ return -EINVAL;
+ data = devm_kmalloc(parent, sizeof(*data), 0);
+ if (!data)
+ return -ENOMEM;
+
+ data->base = dev_read_addr_ptr(parent);
+ if (!data->base)
+ return -EINVAL;
+ data->num_dedicated_pins = driver_data->num_dedicated_pins;
+ data->num_ports = driver_data->num_ports;
+ data->gpio_configs = driver_data->gpio_configs;
+
+ data->num_pins = 0;
+ for (i = 0; i < data->num_ports; i++)
+ data->num_pins += RZG2L_GPIO_PORT_GET_PINCNT(data->gpio_configs[i]);
+ dev_dbg(parent, "%u dedicated pins, %u muxed ports, %u muxed pins\n",
+ data->num_dedicated_pins, data->num_ports, data->num_pins);
+
+ drv = lists_driver_lookup_name("rzg2l-pfc-pinctrl");
+ if (!drv)
+ return -ENOENT;
+
+ ret = device_bind_with_driver_data(parent, drv, parent->name,
+ (ulong)data, dev_ofnode(parent),
+ &pinctrl_dev);
+
+ if (!ret && IS_ENABLED(CONFIG_RZG2L_GPIO)) {
+ drv = lists_driver_lookup_name("rzg2l-pfc-gpio");
+ if (!drv) {
+ device_unbind(pinctrl_dev);
+ return -ENOENT;
+ }
+
+ ret = device_bind_with_driver_data(parent, drv, parent->name,
+ (ulong)data,
+ dev_ofnode(parent), NULL);
+ if (ret)
+ device_unbind(pinctrl_dev);
+ }
+
+ return ret;
+}
+
+U_BOOT_DRIVER(rzg2l_pfc) = {
+ .name = "rzg2l-pfc",
+ .id = UCLASS_NOP,
+ .of_match = rzg2l_pfc_ids,
+ .bind = rzg2l_pfc_bind,
+};
diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig
index 77da90836b6..cbd61795986 100644
--- a/drivers/pinctrl/sunxi/Kconfig
+++ b/drivers/pinctrl/sunxi/Kconfig
@@ -124,4 +124,9 @@ config PINCTRL_SUN50I_H616_R
default MACH_SUN50I_H616
select PINCTRL_SUNXI
+config PINCTRL_SUN20I_D1
+ bool "Support for the Allwinner D1/R528 PIO"
+ default MACH_SUN8I_R528
+ select PINCTRL_SUNXI
+
endif
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index e5102180902..37ea93715d1 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -7,6 +7,7 @@
#include <dm/pinctrl.h>
#include <errno.h>
#include <malloc.h>
+#include <sunxi_gpio.h>
#include <asm/gpio.h>
@@ -35,7 +36,7 @@ struct sunxi_pinctrl_desc {
};
struct sunxi_pinctrl_plat {
- struct sunxi_gpio __iomem *base;
+ void __iomem *base;
};
static int sunxi_pinctrl_get_pins_count(struct udevice *dev)
@@ -49,7 +50,7 @@ static const char *sunxi_pinctrl_get_pin_name(struct udevice *dev,
uint pin_selector)
{
const struct sunxi_pinctrl_desc *desc = dev_get_priv(dev);
- static char pin_name[sizeof("PN31")];
+ static char pin_name[sizeof("PN31")] __section(".data");
snprintf(pin_name, sizeof(pin_name), "P%c%d",
pin_selector / SUNXI_GPIOS_PER_BANK + desc->first_bank + 'A',
@@ -86,8 +87,8 @@ static int sunxi_pinctrl_pinmux_set(struct udevice *dev, uint pin_selector,
sunxi_pinctrl_get_function_name(dev, func_selector),
desc->functions[func_selector].mux);
- sunxi_gpio_set_cfgbank(plat->base + bank, pin,
- desc->functions[func_selector].mux);
+ sunxi_gpio_set_cfgbank(plat->base + bank * SUNXI_PINCTRL_BANK_SIZE,
+ pin, desc->functions[func_selector].mux);
return 0;
}
@@ -102,7 +103,7 @@ static const struct pinconf_param sunxi_pinctrl_pinconf_params[] = {
static int sunxi_pinctrl_pinconf_set_pull(struct sunxi_pinctrl_plat *plat,
uint bank, uint pin, uint bias)
{
- struct sunxi_gpio *regs = &plat->base[bank];
+ void *regs = plat->base + bank * SUNXI_PINCTRL_BANK_SIZE;
sunxi_gpio_set_pull_bank(regs, pin, bias);
@@ -112,7 +113,7 @@ static int sunxi_pinctrl_pinconf_set_pull(struct sunxi_pinctrl_plat *plat,
static int sunxi_pinctrl_pinconf_set_drive(struct sunxi_pinctrl_plat *plat,
uint bank, uint pin, uint drive)
{
- struct sunxi_gpio *regs = &plat->base[bank];
+ void *regs = plat->base + bank * SUNXI_PINCTRL_BANK_SIZE;
if (drive < 10 || drive > 40)
return -EINVAL;
@@ -148,7 +149,7 @@ static int sunxi_pinctrl_get_pin_muxing(struct udevice *dev, uint pin_selector,
struct sunxi_pinctrl_plat *plat = dev_get_plat(dev);
int bank = pin_selector / SUNXI_GPIOS_PER_BANK;
int pin = pin_selector % SUNXI_GPIOS_PER_BANK;
- int mux = sunxi_gpio_get_cfgbank(plat->base + bank, pin);
+ int mux = sunxi_gpio_get_cfgbank(plat->base + bank * SUNXI_PINCTRL_BANK_SIZE, pin);
switch (mux) {
case SUNXI_GPIO_INPUT:
@@ -206,7 +207,7 @@ static int sunxi_pinctrl_bind(struct udevice *dev)
if (!gpio_plat)
return -ENOMEM;
- gpio_plat->regs = plat->base + i;
+ gpio_plat->regs = plat->base + i * SUNXI_PINCTRL_BANK_SIZE;
gpio_plat->bank_name[0] = 'P';
gpio_plat->bank_name[1] = 'A' + desc->first_bank + i;
gpio_plat->bank_name[2] = '\0';
@@ -597,6 +598,32 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun9i_a80_r_pinctrl_desc =
.num_banks = 3,
};
+static const struct sunxi_pinctrl_function sun20i_d1_pinctrl_functions[] = {
+ { "emac", 8 }, /* PE0-PE15 */
+ { "gpio_in", 0 },
+ { "gpio_out", 1 },
+ { "i2c0", 4 }, /* PB10-PB11 */
+ { "mmc0", 2 }, /* PF0-PF5 */
+ { "mmc1", 2 }, /* PG0-PG5 */
+ { "mmc2", 3 }, /* PC2-PC7 */
+ { "spi0", 2 }, /* PC2-PC7 */
+#if IS_ENABLED(CONFIG_UART0_PORT_F)
+ { "uart0", 3 }, /* PF2,PF4 */
+#else
+ { "uart0", 6 }, /* PB0-PB1, PB8-PB9, PE2-PE3 */
+#endif
+ { "uart1", 2 }, /* PG6-PG7 */
+ { "uart2", 7 }, /* PB0-PB1 */
+ { "uart3", 7 }, /* PB6-PB7 */
+};
+
+static const struct sunxi_pinctrl_desc __maybe_unused sun20i_d1_pinctrl_desc = {
+ .functions = sun20i_d1_pinctrl_functions,
+ .num_functions = ARRAY_SIZE(sun20i_d1_pinctrl_functions),
+ .first_bank = SUNXI_GPIO_A,
+ .num_banks = 7,
+};
+
static const struct sunxi_pinctrl_function sun50i_a64_pinctrl_functions[] = {
{ "emac", 4 }, /* PD8-PD23 */
{ "gpio_in", 0 },
@@ -862,6 +889,12 @@ static const struct udevice_id sunxi_pinctrl_ids[] = {
.data = (ulong)&sun9i_a80_r_pinctrl_desc,
},
#endif
+#ifdef CONFIG_PINCTRL_SUN20I_D1
+ {
+ .compatible = "allwinner,sun20i-d1-pinctrl",
+ .data = (ulong)&sun20i_d1_pinctrl_desc,
+ },
+#endif
#ifdef CONFIG_PINCTRL_SUN50I_A64
{
.compatible = "allwinner,sun50i-a64-pinctrl",
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 7f3b990d231..2395720c99c 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -101,6 +101,15 @@ config AXP305_POWER
Select this to enable support for the axp305 pmic found on most
H616 boards.
+config AXP313_POWER
+ bool "axp313 pmic support"
+ depends on MACH_SUN50I_H616
+ select AXP_PMIC_BUS
+ select CMD_POWEROFF
+ ---help---
+ Select this to enable support for the AXP313 PMIC found on some
+ H616 boards.
+
config AXP809_POWER
bool "axp809 pmic support"
depends on MACH_SUN9I
@@ -143,9 +152,10 @@ config AXP_DCDC1_VOLT
config AXP_DCDC2_VOLT
int "axp pmic dcdc2 voltage"
- depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
+ depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP313_POWER
default 900 if AXP818_POWER
default 1400 if AXP152_POWER || AXP209_POWER
+ default 1000 if AXP313_POWER
default 1200 if MACH_SUN6I
default 1100 if MACH_SUN8I
default 0 if MACH_SUN9I
@@ -158,13 +168,15 @@ config AXP_DCDC2_VOLT
On A80 boards dcdc2 powers the GPU and can be left off.
On A83T boards dcdc2 is used for VDD-CPUA(cluster 0) and should be 0.9V.
On R40 boards dcdc2 is VDD-CPU and should be 1.1V
+ On boards using the AXP313 it's often VDD-CPU.
config AXP_DCDC3_VOLT
int "axp pmic dcdc3 voltage"
- depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
+ depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP313_POWER
default 900 if AXP809_POWER || AXP818_POWER
default 1500 if AXP152_POWER
default 1250 if AXP209_POWER
+ default 1100 if AXP313_POWER
default 1100 if MACH_SUN8I_R40
default 1200 if MACH_SUN6I || MACH_SUN8I
---help---
@@ -177,10 +189,11 @@ config AXP_DCDC3_VOLT
On A80 boards dcdc3 is used for VDD-CPUA(cluster 0) and should be 0.9V.
On A83T boards dcdc3 is used for VDD-CPUB(cluster 1) and should be 0.9V.
On R40 boards dcdc3 is VDD-SYS and VDD-GPU and should be 1.1V.
+ On boards using the AXP313 it's often VDD-DRAM and should be 1.1V for LPDDR4.
config AXP_DCDC4_VOLT
int "axp pmic dcdc4 voltage"
- depends on AXP152_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP305_POWER
+ depends on AXP152_POWER || AXP221_POWER || AXP809_POWER || AXP305_POWER
default 1250 if AXP152_POWER
default 1200 if MACH_SUN6I
default 0 if MACH_SUN8I
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index ba64b2c5938..c7ee4595fc8 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_AXP152_POWER) += axp152.o
obj-$(CONFIG_AXP209_POWER) += axp209.o
obj-$(CONFIG_AXP221_POWER) += axp221.o
obj-$(CONFIG_AXP305_POWER) += axp305.o
+obj-$(CONFIG_AXP313_POWER) += axp313.o
obj-$(CONFIG_AXP809_POWER) += axp809.o
obj-$(CONFIG_AXP818_POWER) += axp818.o
obj-$(CONFIG_EXYNOS_TMU) += exynos-tmu.o
diff --git a/drivers/power/axp313.c b/drivers/power/axp313.c
new file mode 100644
index 00000000000..bbc9e911115
--- /dev/null
+++ b/drivers/power/axp313.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * AXP313(a) driver
+ *
+ * (C) Copyright 2023 Arm Ltd.
+ *
+ * Based on axp305.c
+ * (C) Copyright 2020 Jernej Skrabec <jernej.skrabec@siol.net>
+ * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <errno.h>
+#include <asm/arch/pmic_bus.h>
+#include <axp_pmic.h>
+
+enum axp313_reg {
+ AXP313_CHIP_VERSION = 0x03,
+ AXP313_OUTPUT_CTRL = 0x10,
+ AXP313_DCDC1_CTRL = 0x13,
+ AXP313_SHUTDOWN = 0x1a,
+};
+
+#define AXP313_CHIP_VERSION_MASK 0xcf
+#define AXP313_CHIP_VERSION_AXP1530 0x48
+#define AXP313_CHIP_VERSION_AXP313A 0x4b
+#define AXP313_CHIP_VERSION_AXP313B 0x4c
+
+#define AXP313_DCDC_SPLIT_OFFSET 71
+#define AXP313_DCDC_SPLIT_MVOLT 1200
+
+#define AXP313_POWEROFF BIT(7)
+
+static u8 mvolt_to_cfg(int mvolt, int min, int max, int div)
+{
+ if (mvolt < min)
+ mvolt = min;
+ else if (mvolt > max)
+ mvolt = max;
+
+ return (mvolt - min) / div;
+}
+
+static int axp_set_dcdc(int dcdc_num, unsigned int mvolt)
+{
+ int ret;
+ u8 cfg, enable_mask = 1U << (dcdc_num - 1);
+ int volt_reg = AXP313_DCDC1_CTRL + dcdc_num - 1;
+ int max_mV;
+
+ switch (dcdc_num) {
+ case 1:
+ case 2:
+ max_mV = 1540;
+ break;
+ case 3:
+ /*
+ * The manual defines a different split point, but tests
+ * show that it's the same 1200mV as for DCDC1/2.
+ */
+ max_mV = 1840;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (mvolt > AXP313_DCDC_SPLIT_MVOLT)
+ cfg = AXP313_DCDC_SPLIT_OFFSET + mvolt_to_cfg(mvolt,
+ AXP313_DCDC_SPLIT_MVOLT + 20, max_mV, 20);
+ else
+ cfg = mvolt_to_cfg(mvolt, 500, AXP313_DCDC_SPLIT_MVOLT, 10);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP313_OUTPUT_CTRL, enable_mask);
+
+ debug("DCDC%d: writing 0x%x to reg 0x%x\n", dcdc_num, cfg, volt_reg);
+ ret = pmic_bus_write(volt_reg, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP313_OUTPUT_CTRL, enable_mask);
+}
+
+int axp_set_dcdc2(unsigned int mvolt)
+{
+ return axp_set_dcdc(2, mvolt);
+}
+
+int axp_set_dcdc3(unsigned int mvolt)
+{
+ return axp_set_dcdc(3, mvolt);
+}
+
+int axp_init(void)
+{
+ u8 axp_chip_id;
+ int ret;
+
+ ret = pmic_bus_init();
+ if (ret)
+ return ret;
+
+ ret = pmic_bus_read(AXP313_CHIP_VERSION, &axp_chip_id);
+ if (ret)
+ return ret;
+
+ axp_chip_id &= AXP313_CHIP_VERSION_MASK;
+ switch (axp_chip_id) {
+ case AXP313_CHIP_VERSION_AXP1530:
+ case AXP313_CHIP_VERSION_AXP313A:
+ case AXP313_CHIP_VERSION_AXP313B:
+ break;
+ default:
+ debug("unknown PMIC: 0x%x\n", axp_chip_id);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+#if !CONFIG_IS_ENABLED(ARM_PSCI_FW) && !IS_ENABLED(CONFIG_SYSRESET_CMD_POWEROFF)
+int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ pmic_bus_write(AXP313_SHUTDOWN, AXP313_POWEROFF);
+
+ /* infinite loop during shutdown */
+ while (1) {}
+
+ /* not reached */
+ return 0;
+}
+#endif
diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig
index 411c210756a..bd82d2f7044 100644
--- a/drivers/power/domain/Kconfig
+++ b/drivers/power/domain/Kconfig
@@ -83,6 +83,13 @@ config SANDBOX_POWER_DOMAIN
simply accepts requests to power on/off various HW modules without
actually doing anything beyond a little error checking.
+config SCMI_POWER_DOMAIN
+ bool "Enable SCMI power domain driver"
+ depends on POWER_DOMAIN && SCMI_FIRMWARE
+ help
+ Enable power domain implementation based on SCMI power domain
+ management protocol.
+
config TEGRA186_POWER_DOMAIN
bool "Enable Tegra186 BPMP-based power domain driver"
depends on TEGRA186_BPMP
diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile
index aa5a4ba57cd..2daab73eb75 100644
--- a/drivers/power/domain/Makefile
+++ b/drivers/power/domain/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_MESON_EE_POWER_DOMAIN) += meson-ee-pwrc.o
obj-$(CONFIG_MESON_SECURE_POWER_DOMAIN) += meson-secure-pwrc.o
obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain.o
obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain-test.o
+obj-$(CONFIG_SCMI_POWER_DOMAIN) += scmi-power-domain.o
obj-$(CONFIG_TEGRA186_POWER_DOMAIN) += tegra186-power-domain.o
obj-$(CONFIG_TI_SCI_POWER_DOMAIN) += ti-sci-power-domain.o
obj-$(CONFIG_TI_POWER_DOMAIN) += ti-power-domain.o
diff --git a/drivers/power/domain/scmi-power-domain.c b/drivers/power/domain/scmi-power-domain.c
new file mode 100644
index 00000000000..3cd0f075d95
--- /dev/null
+++ b/drivers/power/domain/scmi-power-domain.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * SCMI Power domain driver
+ *
+ * Copyright (C) 2023 Linaro Limited
+ * author: AKASHI Takahiro <takahiro.akashi@linaro.org>
+ */
+
+#include <dm.h>
+#include <malloc.h>
+#include <power-domain.h>
+#include <power-domain-uclass.h>
+#include <scmi_agent.h>
+#include <scmi_protocols.h>
+#include <dm/device_compat.h>
+
+/**
+ * struct scmi_pwd_properties
+ * @attributes: Power domain attributes
+ * @name: Name of the domain
+ */
+struct scmi_pwd_properties {
+ u32 attributes;
+ u8 *name; /* not used now */
+};
+
+/**
+ * struct scmi_power_domain_priv
+ * @num_pwdoms: Number of power domains
+ * @prop: Pointer to domain's properties
+ * @stats_addr: Address of statistics memory region
+ * @stats_len: Length of statistics memory region
+ */
+struct scmi_power_domain_priv {
+ int num_pwdoms;
+ struct scmi_pwd_properties *prop;
+ u64 stats_addr;
+ size_t stats_len;
+};
+
+/**
+ * async_is_supported - check asynchronous transition
+ * @attributes: Power domain attributes
+ *
+ * Determine if the power transition can be done asynchronously.
+ *
+ * Return: true if supported, false if not
+ */
+static bool async_is_supported(u32 attributes)
+{
+ if (attributes & SCMI_PWD_ATTR_PSTATE_ASYNC)
+ return true;
+
+ /* TODO: check attributes && SCMI_PWD_ATTR_PSTATE_SYNC */
+ return false;
+}
+
+/**
+ * scmi_power_domain_on - Enable the power domain
+ * @power_domain: Power domain
+ *
+ * Turn on the power domain.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_power_domain_on(struct power_domain *power_domain)
+{
+ struct scmi_power_domain_priv *priv = dev_get_priv(power_domain->dev);
+ u32 flags, pstate;
+ int ret;
+
+ if (power_domain->id > priv->num_pwdoms)
+ return -EINVAL;
+
+ if (async_is_supported(priv->prop[power_domain->id].attributes))
+ flags = SCMI_PWD_SET_FLAGS_ASYNC;
+ else
+ flags = 0;
+
+ /* ON */
+ pstate = 0;
+
+ ret = scmi_pwd_state_set(power_domain->dev, flags, power_domain->id,
+ pstate);
+ if (ret) {
+ dev_err(power_domain->dev, "failed to set the state on (%d)\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * scmi_power_domain_off - Disable the power domain
+ * @power_domain: Power domain
+ *
+ * Turn off the power domain.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_power_domain_off(struct power_domain *power_domain)
+{
+ struct scmi_power_domain_priv *priv = dev_get_priv(power_domain->dev);
+ u32 flags, pstate;
+ int ret;
+
+ if (power_domain->id > priv->num_pwdoms)
+ return -EINVAL;
+
+ if (async_is_supported(priv->prop[power_domain->id].attributes))
+ flags = SCMI_PWD_SET_FLAGS_ASYNC;
+ else
+ flags = 0;
+
+ /* OFF */
+ pstate = SCMI_PWD_PSTATE_TYPE_LOST;
+
+ ret = scmi_pwd_state_set(power_domain->dev, flags, power_domain->id,
+ pstate);
+ if (ret) {
+ dev_err(power_domain->dev, "failed to set the state off (%d)\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * scmi_power_domain_probe - Probe the power domain
+ * @dev: Power domain device
+ *
+ * Probe the power domain and initialize the properties.
+ *
+ * Return: 0 on success, error code on failure
+ */
+static int scmi_power_domain_probe(struct udevice *dev)
+{
+ struct scmi_power_domain_priv *priv = dev_get_priv(dev);
+ u32 version;
+ int i, ret;
+
+ ret = devm_scmi_of_get_channel(dev);
+ if (ret) {
+ dev_err(dev, "failed to get channel (%d)\n", ret);
+ return ret;
+ }
+
+ ret = scmi_generic_protocol_version(dev, SCMI_PROTOCOL_ID_POWER_DOMAIN,
+ &version);
+
+ ret = scmi_pwd_protocol_attrs(dev, &priv->num_pwdoms, &priv->stats_addr,
+ &priv->stats_len);
+ if (ret) {
+ dev_err(dev, "failed to get protocol attributes (%d)\n", ret);
+ return ret;
+ }
+
+ priv->prop = calloc(sizeof(*priv->prop), priv->num_pwdoms);
+ if (!priv->prop)
+ return -ENOMEM;
+
+ for (i = 0; i < priv->num_pwdoms; i++) {
+ ret = scmi_pwd_attrs(dev, i, &priv->prop[i].attributes,
+ &priv->prop[i].name);
+ if (ret) {
+ dev_err(dev, "failed to get attributes pwd:%d (%d)\n",
+ i, ret);
+ for (i--; i >= 0; i--)
+ free(priv->prop[i].name);
+ free(priv->prop);
+
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+struct power_domain_ops scmi_power_domain_ops = {
+ .on = scmi_power_domain_on,
+ .off = scmi_power_domain_off,
+};
+
+U_BOOT_DRIVER(scmi_power_domain) = {
+ .name = "scmi_power_domain",
+ .id = UCLASS_POWER_DOMAIN,
+ .ops = &scmi_power_domain_ops,
+ .probe = scmi_power_domain_probe,
+ .priv_auto = sizeof(struct scmi_power_domain_priv),
+};
diff --git a/drivers/power/domain/ti-power-domain.c b/drivers/power/domain/ti-power-domain.c
index 9e7151307c8..b34c982f4f5 100644
--- a/drivers/power/domain/ti-power-domain.c
+++ b/drivers/power/domain/ti-power-domain.c
@@ -2,7 +2,7 @@
/*
* Texas Instruments power domain driver
*
- * Copyright (C) 2020-2021 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/
* Tero Kristo <t-kristo@ti.com>
*/
diff --git a/drivers/power/domain/ti-sci-power-domain.c b/drivers/power/domain/ti-sci-power-domain.c
index 0140e5e5217..8d6abe13dbc 100644
--- a/drivers/power/domain/ti-sci-power-domain.c
+++ b/drivers/power/domain/ti-sci-power-domain.c
@@ -2,7 +2,7 @@
/*
* Texas Instruments System Control Interface (TI SCI) power domain driver
*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
* Andreas Dannenberg <dannenberg@ti.com>
*
* Loosely based on Linux kernel ti_sci_pm_domains.c...
diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig
index 4a6f0ce093a..454a6e0cf87 100644
--- a/drivers/power/pmic/Kconfig
+++ b/drivers/power/pmic/Kconfig
@@ -184,6 +184,15 @@ config SPL_DM_PMIC_PFUZE100
This config enables implementation of driver-model pmic uclass features
for PMIC PFUZE100 in SPL. The driver implements read/write operations.
+config DM_PMIC_MAX77663
+ bool "Enable Driver Model for PMIC MAX77663"
+ ---help---
+ This config enables implementation of driver-model pmic uclass features
+ for PMIC MAX77663. The driver implements read/write operations.
+ This is a Power Management IC with a decent set of peripherals from which
+ 4 DC-to-DC Step-Down (SD) Regulators, 9 Low-Dropout Linear (LDO) Regulators,
+ 8 GPIOs, Real-Time Clock (RTC) and more with I2C Compatible Interface.
+
config DM_PMIC_MAX77686
bool "Enable Driver Model for PMIC MAX77686"
---help---
@@ -342,6 +351,17 @@ config DM_PMIC_TPS65910
DC-DC converter, 8 LDOs and a RTC. This driver binds the SMPS and LDO
pmic children.
+config DM_PMIC_TPS80031
+ bool "Enable driver for Texas Instruments TPS80031/TPS80032 PMIC"
+ ---help---
+ This config enables implementation of driver-model pmic uclass features
+ for TPS80031/TPS80032 PMICs. The driver implements read/write operations.
+ This is a Power Management IC with a decent set of peripherals from which
+ 5 Buck Converters refered as Switched-mode power supply (SMPS), 11 General-
+ Purpose Low-Dropout Voltage Regulators (LDO), USB OTG Module, Real-Time
+ Clock (RTC) with Timer and Alarm Wake-Up, Two Digital PWM Outputs and more
+ with I2C Compatible Interface. PMIC occupies 4 I2C addresses.
+
config PMIC_STPMIC1
bool "Enable support for STMicroelectronics STPMIC1 PMIC"
depends on DM_I2C
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
index 0b3b3d62d0e..55ee614364b 100644
--- a/drivers/power/pmic/Makefile
+++ b/drivers/power/pmic/Makefile
@@ -6,6 +6,7 @@
obj-$(CONFIG_$(SPL_TPL_)DM_PMIC) += pmic-uclass.o
obj-$(CONFIG_$(SPL_)DM_PMIC_FAN53555) += fan53555.o
obj-$(CONFIG_$(SPL_)DM_PMIC_DA9063) += da9063.o
+obj-$(CONFIG_$(SPL_)DM_PMIC_MAX77663) += max77663.o
obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o
obj-$(CONFIG_DM_PMIC_MAX8998) += max8998.o
obj-$(CONFIG_DM_PMIC_MC34708) += mc34708.o
@@ -26,6 +27,7 @@ obj-$(CONFIG_$(SPL_)PMIC_RN5T567) += rn5t567.o
obj-$(CONFIG_PMIC_TPS65090) += tps65090.o
obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o
obj-$(CONFIG_DM_PMIC_TPS65910) += pmic_tps65910_dm.o
+obj-$(CONFIG_$(SPL_)DM_PMIC_TPS80031) += tps80031.o
obj-$(CONFIG_$(SPL_)PMIC_PALMAS) += palmas.o
obj-$(CONFIG_$(SPL_)PMIC_LP873X) += lp873x.o
obj-$(CONFIG_$(SPL_)PMIC_LP87565) += lp87565.o
diff --git a/drivers/power/pmic/axp.c b/drivers/power/pmic/axp.c
index 025dac24f28..0e1e45fba74 100644
--- a/drivers/power/pmic/axp.c
+++ b/drivers/power/pmic/axp.c
@@ -87,6 +87,7 @@ static const struct udevice_id axp_pmic_ids[] = {
{ .compatible = "x-powers,axp209", .data = AXP209_ID },
{ .compatible = "x-powers,axp221", .data = AXP221_ID },
{ .compatible = "x-powers,axp223", .data = AXP223_ID },
+ { .compatible = "x-powers,axp313a", .data = AXP313_ID },
{ .compatible = "x-powers,axp803", .data = AXP803_ID },
{ .compatible = "x-powers,axp806", .data = AXP806_ID },
{ .compatible = "x-powers,axp809", .data = AXP809_ID },
diff --git a/drivers/power/pmic/max77663.c b/drivers/power/pmic/max77663.c
new file mode 100644
index 00000000000..68c3cbbc646
--- /dev/null
+++ b/drivers/power/pmic/max77663.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <dm/lists.h>
+#include <power/pmic.h>
+#include <power/max77663.h>
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "ldo", .driver = MAX77663_LDO_DRIVER },
+ { .prefix = "sd", .driver = MAX77663_SD_DRIVER },
+ { },
+};
+
+static int max77663_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ int ret;
+
+ ret = dm_i2c_write(dev, reg, buff, len);
+ if (ret) {
+ log_debug("write error to device: %p register: %#x!\n", dev, reg);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int max77663_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ int ret;
+
+ ret = dm_i2c_read(dev, reg, buff, len);
+ if (ret) {
+ log_debug("read error from device: %p register: %#x!\n", dev, reg);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int max77663_bind(struct udevice *dev)
+{
+ ofnode regulators_node;
+ int children, ret;
+
+ if (IS_ENABLED(CONFIG_SYSRESET_MAX77663)) {
+ ret = device_bind_driver(dev, MAX77663_RST_DRIVER,
+ "sysreset", NULL);
+ if (ret) {
+ log_err("cannot bind SYSRESET (ret = %d)\n", ret);
+ return ret;
+ }
+ }
+
+ regulators_node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(regulators_node)) {
+ log_err("%s regulators subnode not found!\n", dev->name);
+ return -ENXIO;
+ }
+
+ debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+
+ children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+ if (!children)
+ log_err("%s - no child found\n", dev->name);
+
+ /* Always return success for this device */
+ return 0;
+}
+
+static struct dm_pmic_ops max77663_ops = {
+ .read = max77663_read,
+ .write = max77663_write,
+};
+
+static const struct udevice_id max77663_ids[] = {
+ { .compatible = "maxim,max77663" },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_max77663) = {
+ .name = "max77663_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = max77663_ids,
+ .bind = max77663_bind,
+ .ops = &max77663_ops,
+};
diff --git a/drivers/power/pmic/palmas.c b/drivers/power/pmic/palmas.c
index eb83c88d564..32f2a938b28 100644
--- a/drivers/power/pmic/palmas.c
+++ b/drivers/power/pmic/palmas.c
@@ -8,13 +8,13 @@
#include <fdtdec.h>
#include <errno.h>
#include <dm.h>
+#include <dm/lists.h>
#include <i2c.h>
#include <log.h>
#include <linux/printk.h>
#include <power/pmic.h>
#include <power/regulator.h>
#include <power/palmas.h>
-#include <dm/device.h>
static const struct pmic_child_info pmic_children_info[] = {
{ .prefix = "ldo", .driver = PALMAS_LDO_DRIVER },
@@ -47,7 +47,16 @@ static int palmas_bind(struct udevice *dev)
{
ofnode pmic_node = ofnode_null(), regulators_node;
ofnode subnode;
- int children;
+ int children, ret;
+
+ if (IS_ENABLED(CONFIG_SYSRESET_PALMAS)) {
+ ret = device_bind_driver(dev, PALMAS_RST_DRIVER,
+ "sysreset", NULL);
+ if (ret) {
+ log_err("cannot bind SYSRESET (ret = %d)\n", ret);
+ return ret;
+ }
+ }
dev_for_each_subnode(subnode, dev) {
const char *name;
@@ -81,6 +90,24 @@ static int palmas_bind(struct udevice *dev)
return 0;
}
+static int palmas_probe(struct udevice *dev)
+{
+ struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
+ struct palmas_priv *priv = dev_get_priv(dev);
+ struct udevice *bus = dev_get_parent(dev);
+ u32 chip2_addr = chip->chip_addr + 1;
+ int ret;
+
+ /* Palmas PMIC is multi chip and chips are located in a row */
+ ret = i2c_get_chip(bus, chip2_addr, 1, &priv->chip2);
+ if (ret) {
+ log_err("cannot get second PMIC I2C chip (err %d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static struct dm_pmic_ops palmas_ops = {
.read = palmas_read,
.write = palmas_write,
@@ -88,6 +115,7 @@ static struct dm_pmic_ops palmas_ops = {
static const struct udevice_id palmas_ids[] = {
{ .compatible = "ti,tps659038", .data = TPS659038 },
+ { .compatible = "ti,tps65913" , .data = TPS659038 },
{ .compatible = "ti,tps65917" , .data = TPS65917 },
{ }
};
@@ -97,5 +125,7 @@ U_BOOT_DRIVER(pmic_palmas) = {
.id = UCLASS_PMIC,
.of_match = palmas_ids,
.bind = palmas_bind,
+ .probe = palmas_probe,
.ops = &palmas_ops,
+ .priv_auto = sizeof(struct palmas_priv),
};
diff --git a/drivers/power/pmic/pmic_tps62362.c b/drivers/power/pmic/pmic_tps62362.c
index 59190d6f672..6426d1488a5 100644
--- a/drivers/power/pmic/pmic_tps62362.c
+++ b/drivers/power/pmic/pmic_tps62362.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * (C) Copyright 2014 Texas Instruments Incorporated - http://www.ti.com
+ * (C) Copyright 2014 Texas Instruments Incorporated - https://www.ti.com
* Author: Felipe Balbi <balbi@ti.com>
*/
diff --git a/drivers/power/pmic/pmic_tps65910_dm.c b/drivers/power/pmic/pmic_tps65910_dm.c
index 8ead1db802a..ecf836eb0e6 100644
--- a/drivers/power/pmic/pmic_tps65910_dm.c
+++ b/drivers/power/pmic/pmic_tps65910_dm.c
@@ -5,6 +5,7 @@
#include <common.h>
#include <dm.h>
+#include <dm/lists.h>
#include <i2c.h>
#include <log.h>
#include <linux/printk.h>
@@ -12,13 +13,19 @@
#include <power/regulator.h>
#include <power/tps65910_pmic.h>
-static const struct pmic_child_info pmic_children_info[] = {
+static const struct pmic_child_info tps65910_children_info[] = {
{ .prefix = "ldo_", .driver = TPS65910_LDO_DRIVER },
{ .prefix = "buck_", .driver = TPS65910_BUCK_DRIVER },
{ .prefix = "boost_", .driver = TPS65910_BOOST_DRIVER },
{ },
};
+static const struct pmic_child_info tps65911_children_info[] = {
+ { .prefix = "ldo", .driver = TPS65911_LDO_DRIVER },
+ { .prefix = "vdd", .driver = TPS65911_VDD_DRIVER },
+ { },
+};
+
static int pmic_tps65910_reg_count(struct udevice *dev)
{
return TPS65910_NUM_REGS;
@@ -50,8 +57,19 @@ static int pmic_tps65910_read(struct udevice *dev, uint reg, u8 *buffer,
static int pmic_tps65910_bind(struct udevice *dev)
{
+ const struct pmic_child_info *tps6591x_children_info =
+ (struct pmic_child_info *)dev_get_driver_data(dev);
ofnode regulators_node;
- int children;
+ int children, ret;
+
+ if (IS_ENABLED(CONFIG_SYSRESET_TPS65910)) {
+ ret = device_bind_driver(dev, TPS65910_RST_DRIVER,
+ "sysreset", NULL);
+ if (ret) {
+ log_err("cannot bind SYSRESET (ret = %d)\n", ret);
+ return ret;
+ }
+ }
regulators_node = dev_read_subnode(dev, "regulators");
if (!ofnode_valid(regulators_node)) {
@@ -59,7 +77,7 @@ static int pmic_tps65910_bind(struct udevice *dev)
return -EINVAL;
}
- children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+ children = pmic_bind_children(dev, regulators_node, tps6591x_children_info);
if (!children)
debug("%s has no children (regulators)\n", dev->name);
@@ -83,7 +101,8 @@ static struct dm_pmic_ops pmic_tps65910_ops = {
};
static const struct udevice_id pmic_tps65910_match[] = {
- { .compatible = "ti,tps65910" },
+ { .compatible = "ti,tps65910", .data = (ulong)&tps65910_children_info },
+ { .compatible = "ti,tps65911", .data = (ulong)&tps65911_children_info },
{ /* sentinel */ }
};
diff --git a/drivers/power/pmic/tps80031.c b/drivers/power/pmic/tps80031.c
new file mode 100644
index 00000000000..a2f935b0c6d
--- /dev/null
+++ b/drivers/power/pmic/tps80031.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <dm/lists.h>
+#include <power/pmic.h>
+#include <power/tps80031.h>
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "ldo", .driver = TPS80031_LDO_DRIVER },
+ { .prefix = "smps", .driver = TPS80031_SMPS_DRIVER },
+ { },
+};
+
+static int tps80031_write(struct udevice *dev, uint reg, const uint8_t *buff,
+ int len)
+{
+ int ret;
+
+ ret = dm_i2c_write(dev, reg, buff, len);
+ if (ret) {
+ log_debug("write error to device: %p register: %#x!\n", dev, reg);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tps80031_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ int ret;
+
+ ret = dm_i2c_read(dev, reg, buff, len);
+ if (ret) {
+ log_debug("read error from device: %p register: %#x!\n", dev, reg);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tps80031_bind(struct udevice *dev)
+{
+ ofnode regulators_node;
+ int children, ret;
+
+ if (IS_ENABLED(CONFIG_SYSRESET_TPS80031)) {
+ ret = device_bind_driver(dev, TPS80031_RST_DRIVER,
+ "sysreset", NULL);
+ if (ret) {
+ log_err("cannot bind SYSRESET (ret = %d)\n", ret);
+ return ret;
+ }
+ }
+
+ regulators_node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(regulators_node)) {
+ log_err("%s regulators subnode not found!\n", dev->name);
+ return -ENXIO;
+ }
+
+ debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+
+ children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+ if (!children)
+ log_err("%s - no child found\n", dev->name);
+
+ /* Always return success for this device */
+ return 0;
+}
+
+static struct dm_pmic_ops tps80031_ops = {
+ .read = tps80031_read,
+ .write = tps80031_write,
+};
+
+static const struct udevice_id tps80031_ids[] = {
+ { .compatible = "ti,tps80031" },
+ { .compatible = "ti,tps80032" },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_tps80031) = {
+ .name = "tps80031_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = tps80031_ids,
+ .bind = tps80031_bind,
+ .ops = &tps80031_ops,
+};
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
index eb5aa38c1cc..102ec7bc5f8 100644
--- a/drivers/power/regulator/Kconfig
+++ b/drivers/power/regulator/Kconfig
@@ -141,6 +141,15 @@ config SPL_REGULATOR_PWM
This config enables implementation of driver-model regulator uclass
features for PWM regulators in SPL.
+config DM_REGULATOR_MAX77663
+ bool "Enable Driver Model for REGULATOR MAX77663"
+ depends on DM_REGULATOR && DM_PMIC_MAX77663
+ ---help---
+ This config enables implementation of driver-model regulator uclass
+ features for REGULATOR MAX77663. The driver supports both DC-to-DC
+ Step-Down (SD) Regulators and Low-Dropout Linear (LDO) Regulators
+ found in MAX77663 PMIC and implements get/set api for value and enable.
+
config DM_REGULATOR_MAX77686
bool "Enable Driver Model for REGULATOR MAX77686"
depends on DM_REGULATOR && DM_PMIC_MAX77686
@@ -337,6 +346,17 @@ config DM_REGULATOR_TPS65910
regulator types of the TPS65910 (BUCK, BOOST and LDO). It implements
the get/set api for value and enable.
+config DM_REGULATOR_TPS65911
+ bool "Enable driver for TPS65911 PMIC regulators"
+ depends on DM_PMIC_TPS65910
+ ---help---
+ This config enables implementation of driver-model regulator
+ uclass features for the TPS65911 PMIC. The driver supports Step-Down
+ DC-DC Converters for Processor Cores (VDD1 and VDD2), Step-Down DC-DC
+ Converter for I/O Power (VIO), Controller for External FETs (VDDCtrl)
+ and LDO Voltage Regulators found in TPS65911 PMIC and implements
+ get/set api for value and enable.
+
config DM_REGULATOR_TPS62360
bool "Enable driver for TPS6236x Power Regulator"
depends on DM_REGULATOR
@@ -347,6 +367,14 @@ config DM_REGULATOR_TPS62360
implements the get/set api for value only, as the power line is
always on.
+config DM_REGULATOR_TPS80031
+ bool "Enable driver for TPS80031/TPS80032 PMIC regulators"
+ depends on DM_PMIC_TPS80031
+ ---help---
+ This enables implementation of driver-model regulator uclass
+ features for TPS80031/TPS80032 PMICs. The driver implements
+ get/set api for: value and enable.
+
config DM_REGULATOR_STPMIC1
bool "Enable driver for STPMIC1 regulators"
depends on DM_REGULATOR && PMIC_STPMIC1
diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile
index d9e0cd5949c..f79932d8330 100644
--- a/drivers/power/regulator/Makefile
+++ b/drivers/power/regulator/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_REGULATOR_AS3722) += as3722_regulator.o
obj-$(CONFIG_$(SPL_)REGULATOR_AXP) += axp_regulator.o
obj-$(CONFIG_$(SPL_)REGULATOR_AXP_USB_POWER) += axp_usb_power.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_DA9063) += da9063.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_MAX77663) += max77663_regulator.o
obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o
obj-$(CONFIG_DM_REGULATOR_NPCM8XX) += npcm8xx_regulator.o
obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o
@@ -31,7 +32,9 @@ obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP873X) += lp873x_regulator.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP87565) += lp87565_regulator.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
obj-$(CONFIG_DM_REGULATOR_TPS65910) += tps65910_regulator.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_TPS65911) += tps65911_regulator.o
obj-$(CONFIG_DM_REGULATOR_TPS62360) += tps62360_regulator.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_TPS80031) += tps80031_regulator.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_STPMIC1) += stpmic1.o
obj-$(CONFIG_DM_REGULATOR_TPS65941) += tps65941_regulator.o
obj-$(CONFIG_DM_REGULATOR_SCMI) += scmi_regulator.o
diff --git a/drivers/power/regulator/axp_regulator.c b/drivers/power/regulator/axp_regulator.c
index 02f320eac1e..d27e09538e0 100644
--- a/drivers/power/regulator/axp_regulator.c
+++ b/drivers/power/regulator/axp_regulator.c
@@ -173,6 +173,22 @@ static const struct axp_regulator_plat axp22x_regulators[] = {
{ }
};
+/*
+ * The "dcdc1" regulator has another range, beyond 1.54V up to 3.4V, in
+ * steps of 100mV. We cannot model this easily, but also don't need that,
+ * since it's typically only used for ~1.1V anyway, so just ignore it.
+ * Also the DCDC3 regulator is described wrongly in the (available) manual,
+ * experiments show that the split point is at 1200mV, as for DCDC1/2.
+ */
+static const struct axp_regulator_plat axp313_regulators[] = {
+ { "dcdc1", 0x10, BIT(0), 0x13, 0x7f, 500, 1540, 10, 70 },
+ { "dcdc2", 0x10, BIT(1), 0x14, 0x7f, 500, 1540, 10, 70 },
+ { "dcdc3", 0x10, BIT(2), 0x15, 0x7f, 500, 1840, 10, 70 },
+ { "aldo1", 0x10, BIT(3), 0x16, 0x1f, 500, 3500, 100, NA },
+ { "dldo1", 0x10, BIT(4), 0x17, 0x1f, 500, 3500, 100, NA },
+ { }
+};
+
static const struct axp_regulator_plat axp803_regulators[] = {
{ "dcdc1", 0x10, BIT(0), 0x20, 0x1f, 1600, 3400, 100, NA },
{ "dcdc2", 0x10, BIT(1), 0x21, 0x7f, 500, 1300, 10, 70 },
@@ -274,6 +290,7 @@ static const struct axp_regulator_plat *const axp_regulators[] = {
[AXP209_ID] = axp20x_regulators,
[AXP221_ID] = axp22x_regulators,
[AXP223_ID] = axp22x_regulators,
+ [AXP313_ID] = axp313_regulators,
[AXP803_ID] = axp803_regulators,
[AXP806_ID] = axp806_regulators,
[AXP809_ID] = axp809_regulators,
diff --git a/drivers/power/regulator/max77663_regulator.c b/drivers/power/regulator/max77663_regulator.c
new file mode 100644
index 00000000000..ea4b7c63e5a
--- /dev/null
+++ b/drivers/power/regulator/max77663_regulator.c
@@ -0,0 +1,375 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/max77663.h>
+
+/* fist row is control registers, second is voltage registers */
+static const char max77663_sd_reg[][MAX77663_SD_NUM] = {
+ { 0x1d, 0x1e, 0x1f, 0x20, 0x21 },
+ { 0x16, 0x17, 0x18, 0x19, 0x2a },
+};
+
+static const char max77663_ldo_reg[MAX77663_LDO_NUM] = {
+ 0x23, 0x25, 0x27, 0x29, 0x2b, 0x2d, 0x2f, 0x31, 0x33
+};
+
+static int max77663_sd_enable(struct udevice *dev, int op, bool *enable)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u32 adr = uc_pdata->ctrl_reg;
+ int val, ret;
+
+ val = pmic_reg_read(dev->parent, adr);
+ if (val < 0)
+ return val;
+
+ if (op == PMIC_OP_GET) {
+ if (val & SD_STATUS_MASK)
+ *enable = true;
+ else
+ *enable = false;
+
+ return 0;
+ } else if (op == PMIC_OP_SET) {
+ val &= ~SD_STATUS_MASK;
+
+ if (*enable)
+ val |= SD_STATUS_MASK;
+
+ ret = pmic_reg_write(dev->parent, adr, val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * max77663_*_volt2hex() - convert voltage in uV into
+ * applicable to register hex value
+ *
+ * @idx: regulator index
+ * @uV: voltage in uV
+ *
+ * Return: voltage in hex on success, -ve on failure
+ */
+static int max77663_sd_volt2hex(int idx, int uV)
+{
+ switch (idx) {
+ case 0:
+ /* SD0 has max voltage 1.4V */
+ if (uV > SD0_VOLT_MAX)
+ return -EINVAL;
+ break;
+ case 1:
+ /* SD1 has max voltage 1.55V */
+ if (uV > SD1_VOLT_MAX)
+ return -EINVAL;
+ break;
+ default:
+ /* SD2 and SD3 have max voltage 3.79V */
+ if (uV > SD_VOLT_MAX)
+ return -EINVAL;
+ break;
+ };
+
+ if (uV < SD_VOLT_MIN)
+ uV = SD_VOLT_MIN;
+
+ return (uV - SD_VOLT_BASE) / 12500;
+}
+
+/**
+ * max77663_*_hex2volt() - convert register hex value into
+ * actual voltage in uV
+ *
+ * @idx: regulator index
+ * @hex: hex value of register
+ *
+ * Return: voltage in uV on success, -ve on failure
+ */
+static int max77663_sd_hex2volt(int idx, int hex)
+{
+ switch (idx) {
+ case 0:
+ /* SD0 has max voltage 1.4V */
+ if (hex > SD0_VOLT_MAX_HEX)
+ return -EINVAL;
+ break;
+ case 1:
+ /* SD1 has max voltage 1.55V */
+ if (hex > SD1_VOLT_MAX_HEX)
+ return -EINVAL;
+ break;
+ default:
+ /* SD2 and SD3 have max voltage 3.79V */
+ if (hex > SD_VOLT_MAX_HEX)
+ return -EINVAL;
+ break;
+ };
+
+ if (hex < SD_VOLT_MIN_HEX)
+ hex = SD_VOLT_MIN_HEX;
+
+ return SD_VOLT_BASE + hex * 12500;
+}
+
+static int max77663_sd_val(struct udevice *dev, int op, int *uV)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u32 adr = uc_pdata->volt_reg;
+ int idx = dev->driver_data;
+ int hex, ret;
+
+ if (op == PMIC_OP_GET) {
+ hex = pmic_reg_read(dev->parent, adr);
+ if (hex < 0)
+ return hex;
+
+ *uV = 0;
+
+ ret = max77663_sd_hex2volt(idx, hex);
+ if (ret < 0)
+ return ret;
+ *uV = ret;
+
+ return 0;
+ }
+
+ /* SD regulators use entire register for voltage */
+ hex = max77663_sd_volt2hex(idx, *uV);
+ if (hex < 0)
+ return hex;
+
+ return pmic_reg_write(dev->parent, adr, hex);
+}
+
+static int max77663_sd_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ int idx = dev->driver_data;
+
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+ uc_pdata->ctrl_reg = max77663_sd_reg[0][idx];
+ uc_pdata->volt_reg = max77663_sd_reg[1][idx];
+
+ return 0;
+}
+
+static int sd_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = max77663_sd_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int sd_set_value(struct udevice *dev, int uV)
+{
+ return max77663_sd_val(dev, PMIC_OP_SET, &uV);
+}
+
+static int sd_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+ ret = max77663_sd_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+
+ return enable;
+}
+
+static int sd_set_enable(struct udevice *dev, bool enable)
+{
+ return max77663_sd_enable(dev, PMIC_OP_SET, &enable);
+}
+
+static const struct dm_regulator_ops max77663_sd_ops = {
+ .get_value = sd_get_value,
+ .set_value = sd_set_value,
+ .get_enable = sd_get_enable,
+ .set_enable = sd_set_enable,
+};
+
+U_BOOT_DRIVER(max77663_sd) = {
+ .name = MAX77663_SD_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &max77663_sd_ops,
+ .probe = max77663_sd_probe,
+};
+
+static int max77663_ldo_enable(struct udevice *dev, int op, bool *enable)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u32 adr = uc_pdata->ctrl_reg;
+ int val, ret;
+
+ val = pmic_reg_read(dev->parent, adr);
+ if (val < 0)
+ return val;
+
+ if (op == PMIC_OP_GET) {
+ if (val & LDO_STATUS_MASK)
+ *enable = true;
+ else
+ *enable = false;
+
+ return 0;
+ } else if (op == PMIC_OP_SET) {
+ val &= ~LDO_STATUS_MASK;
+
+ if (*enable)
+ val |= LDO_STATUS_MASK;
+
+ ret = pmic_reg_write(dev->parent, adr, val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int max77663_ldo_volt2hex(int idx, int uV)
+{
+ switch (idx) {
+ case 0:
+ case 1:
+ if (uV > LDO01_VOLT_MAX)
+ return -EINVAL;
+
+ return (uV - LDO_VOLT_BASE) / 25000;
+ case 4:
+ if (uV > LDO4_VOLT_MAX)
+ return -EINVAL;
+
+ return (uV - LDO_VOLT_BASE) / 12500;
+ default:
+ if (uV > LDO_VOLT_MAX)
+ return -EINVAL;
+
+ return (uV - LDO_VOLT_BASE) / 50000;
+ };
+}
+
+static int max77663_ldo_hex2volt(int idx, int hex)
+{
+ if (hex > LDO_VOLT_MAX_HEX)
+ return -EINVAL;
+
+ switch (idx) {
+ case 0:
+ case 1:
+ return (hex * 25000) + LDO_VOLT_BASE;
+ case 4:
+ return (hex * 12500) + LDO_VOLT_BASE;
+ default:
+ return (hex * 50000) + LDO_VOLT_BASE;
+ };
+}
+
+static int max77663_ldo_val(struct udevice *dev, int op, int *uV)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u32 adr = uc_pdata->ctrl_reg;
+ int idx = dev->driver_data;
+ int hex, val, ret;
+
+ val = pmic_reg_read(dev->parent, adr);
+ if (val < 0)
+ return val;
+
+ if (op == PMIC_OP_GET) {
+ *uV = 0;
+
+ ret = max77663_ldo_hex2volt(idx, val & LDO_VOLT_MASK);
+ if (ret < 0)
+ return ret;
+
+ *uV = ret;
+ return 0;
+ }
+
+ hex = max77663_ldo_volt2hex(idx, *uV);
+ if (hex < 0)
+ return hex;
+
+ val &= ~LDO_VOLT_MASK;
+
+ return pmic_reg_write(dev->parent, adr, val | hex);
+}
+
+static int max77663_ldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ int idx = dev->driver_data;
+
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+ uc_pdata->ctrl_reg = max77663_ldo_reg[idx];
+
+ return 0;
+}
+
+static int ldo_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = max77663_ldo_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int ldo_set_value(struct udevice *dev, int uV)
+{
+ return max77663_ldo_val(dev, PMIC_OP_SET, &uV);
+}
+
+static int ldo_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+ ret = max77663_ldo_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+
+ return enable;
+}
+
+static int ldo_set_enable(struct udevice *dev, bool enable)
+{
+ return max77663_ldo_enable(dev, PMIC_OP_SET, &enable);
+}
+
+static const struct dm_regulator_ops max77663_ldo_ops = {
+ .get_value = ldo_get_value,
+ .set_value = ldo_set_value,
+ .get_enable = ldo_get_enable,
+ .set_enable = ldo_set_enable,
+};
+
+U_BOOT_DRIVER(max77663_ldo) = {
+ .name = MAX77663_LDO_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &max77663_ldo_ops,
+ .probe = max77663_ldo_probe,
+};
diff --git a/drivers/power/regulator/palmas_regulator.c b/drivers/power/regulator/palmas_regulator.c
index 3c4eb83be77..d615e947340 100644
--- a/drivers/power/regulator/palmas_regulator.c
+++ b/drivers/power/regulator/palmas_regulator.c
@@ -301,19 +301,23 @@ static int palmas_ldo_probe(struct udevice *dev)
uc_pdata->type = REGULATOR_TYPE_LDO;
- if (dev->driver_data) {
+ /* check for ldoln and ldousb cases */
+ if (!strcmp("ldoln", dev->name)) {
+ uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][9];
+ uc_pdata->volt_reg = palmas_ldo_volt[type][9];
+ return 0;
+ }
+
+ if (!strcmp("ldousb", dev->name)) {
+ uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][10];
+ uc_pdata->volt_reg = palmas_ldo_volt[type][10];
+ return 0;
+ }
+
+ if (dev->driver_data > 0) {
u8 idx = dev->driver_data - 1;
uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][idx];
uc_pdata->volt_reg = palmas_ldo_volt[type][idx];
- } else {
- /* check for ldoln and ldousb cases */
- if (!strcmp("ldoln", dev->name)) {
- uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][9];
- uc_pdata->volt_reg = palmas_ldo_volt[type][9];
- } else if (!strcmp("ldousb", dev->name)) {
- uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][10];
- uc_pdata->volt_reg = palmas_ldo_volt[type][10];
- }
}
return 0;
diff --git a/drivers/power/regulator/scmi_regulator.c b/drivers/power/regulator/scmi_regulator.c
index 801148036ff..9c72c35d039 100644
--- a/drivers/power/regulator/scmi_regulator.c
+++ b/drivers/power/regulator/scmi_regulator.c
@@ -25,18 +25,9 @@ struct scmi_regulator_platdata {
u32 domain_id;
};
-/**
- * struct scmi_regulator_priv - Private data for SCMI voltage regulator
- * @channel: Reference to the SCMI channel to use
- */
-struct scmi_regulator_priv {
- struct scmi_channel *channel;
-};
-
static int scmi_voltd_set_enable(struct udevice *dev, bool enable)
{
struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
- struct scmi_regulator_priv *priv = dev_get_priv(dev);
struct scmi_voltd_config_set_in in = {
.domain_id = pdata->domain_id,
.config = enable ? SCMI_VOLTD_CONFIG_ON : SCMI_VOLTD_CONFIG_OFF,
@@ -47,7 +38,7 @@ static int scmi_voltd_set_enable(struct udevice *dev, bool enable)
in, out);
int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
+ ret = devm_scmi_process_msg(dev, &msg);
if (ret)
return ret;
@@ -57,7 +48,6 @@ static int scmi_voltd_set_enable(struct udevice *dev, bool enable)
static int scmi_voltd_get_enable(struct udevice *dev)
{
struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
- struct scmi_regulator_priv *priv = dev_get_priv(dev);
struct scmi_voltd_config_get_in in = {
.domain_id = pdata->domain_id,
};
@@ -67,7 +57,7 @@ static int scmi_voltd_get_enable(struct udevice *dev)
in, out);
int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
+ ret = devm_scmi_process_msg(dev, &msg);
if (ret < 0)
return ret;
@@ -80,7 +70,6 @@ static int scmi_voltd_get_enable(struct udevice *dev)
static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV)
{
- struct scmi_regulator_priv *priv = dev_get_priv(dev);
struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
struct scmi_voltd_level_set_in in = {
.domain_id = pdata->domain_id,
@@ -92,7 +81,7 @@ static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV)
in, out);
int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
+ ret = devm_scmi_process_msg(dev, &msg);
if (ret < 0)
return ret;
@@ -101,7 +90,6 @@ static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV)
static int scmi_voltd_get_voltage_level(struct udevice *dev)
{
- struct scmi_regulator_priv *priv = dev_get_priv(dev);
struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
struct scmi_voltd_level_get_in in = {
.domain_id = pdata->domain_id,
@@ -112,7 +100,7 @@ static int scmi_voltd_get_voltage_level(struct udevice *dev)
in, out);
int ret;
- ret = devm_scmi_process_msg(dev, priv->channel, &msg);
+ ret = devm_scmi_process_msg(dev, &msg);
if (ret < 0)
return ret;
@@ -140,7 +128,6 @@ static int scmi_regulator_of_to_plat(struct udevice *dev)
static int scmi_regulator_probe(struct udevice *dev)
{
struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
- struct scmi_regulator_priv *priv = dev_get_priv(dev);
struct scmi_voltd_attr_in in = { 0 };
struct scmi_voltd_attr_out out = { 0 };
struct scmi_msg scmi_msg = {
@@ -153,14 +140,14 @@ static int scmi_regulator_probe(struct udevice *dev)
};
int ret;
- ret = devm_scmi_of_get_channel(dev->parent, &priv->channel);
+ ret = devm_scmi_of_get_channel(dev);
if (ret)
return ret;
/* Check voltage domain is known from SCMI server */
in.domain_id = pdata->domain_id;
- ret = devm_scmi_process_msg(dev, priv->channel, &scmi_msg);
+ ret = devm_scmi_process_msg(dev, &scmi_msg);
if (ret) {
dev_err(dev, "Failed to query voltage domain %u: %d\n",
pdata->domain_id, ret);
@@ -184,7 +171,6 @@ U_BOOT_DRIVER(scmi_regulator) = {
.probe = scmi_regulator_probe,
.of_to_plat = scmi_regulator_of_to_plat,
.plat_auto = sizeof(struct scmi_regulator_platdata),
- .priv_auto = sizeof(struct scmi_regulator_priv *),
};
static int scmi_regulator_bind(struct udevice *dev)
diff --git a/drivers/power/regulator/tps62360_regulator.c b/drivers/power/regulator/tps62360_regulator.c
index b9f4504539e..7014b1982d0 100644
--- a/drivers/power/regulator/tps62360_regulator.c
+++ b/drivers/power/regulator/tps62360_regulator.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
* Tero Kristo <t-kristo@ti.com>
*/
diff --git a/drivers/power/regulator/tps65911_regulator.c b/drivers/power/regulator/tps65911_regulator.c
new file mode 100644
index 00000000000..2b5acdfcbb0
--- /dev/null
+++ b/drivers/power/regulator/tps65911_regulator.c
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/tps65910_pmic.h>
+
+/* fist row is control registers, second is voltage registers */
+static const char tps65911_vdd_reg[][TPS65911_VDD_NUM] = {
+ { TPS65911_REG_VDD1, TPS65911_REG_VDD2,
+ TPS65911_REG_VDDCTRL, TPS65911_REG_VIO },
+ { TPS65911_REG_VDD1_OP, TPS65911_REG_VDD2_OP,
+ TPS65911_REG_VDDCTRL_OP, 0x00 },
+};
+
+static const char tps65911_ldo_reg[TPS65911_LDO_NUM] = {
+ TPS65911_REG_LDO1, TPS65911_REG_LDO2, TPS65911_REG_LDO3,
+ TPS65911_REG_LDO4, TPS65911_REG_LDO5, TPS65911_REG_LDO6,
+ TPS65911_REG_LDO7, TPS65911_REG_LDO8
+};
+
+static int tps65911_regulator_enable(struct udevice *dev, int op, bool *enable)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u32 adr = uc_pdata->ctrl_reg;
+ int val, ret;
+
+ val = pmic_reg_read(dev->parent, adr);
+ if (val < 0)
+ return val;
+
+ if (op == PMIC_OP_GET) {
+ if (val & TPS65910_SUPPLY_STATE_ON)
+ *enable = true;
+ else
+ *enable = false;
+
+ return 0;
+ } else if (op == PMIC_OP_SET) {
+ val &= ~TPS65910_SUPPLY_STATE_MASK;
+
+ if (*enable)
+ val |= TPS65910_SUPPLY_STATE_ON;
+
+ ret = pmic_reg_write(dev->parent, adr, val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tps65911_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+ ret = tps65911_regulator_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+
+ return enable;
+}
+
+static int tps65911_set_enable(struct udevice *dev, bool enable)
+{
+ return tps65911_regulator_enable(dev, PMIC_OP_SET, &enable);
+}
+
+/**
+ * tps65911_vdd_volt2hex() - convert voltage in uV into
+ * applicable to register hex value
+ *
+ * @uV: voltage in uV
+ *
+ * Return: voltage in hex on success, -ve on failure
+ */
+static int tps65911_vdd_volt2hex(int uV)
+{
+ if (uV > TPS65911_VDD_VOLT_MAX)
+ return -EINVAL;
+
+ if (uV < TPS65911_VDD_VOLT_MIN)
+ uV = TPS65911_VDD_VOLT_MIN;
+
+ return (uV - TPS65911_VDD_VOLT_BASE) / 12500;
+}
+
+/**
+ * tps65911_vdd_hex2volt() - convert register hex value into
+ * actual voltage in uV
+ *
+ * @hex: hex value of register
+ *
+ * Return: voltage in uV on success, -ve on failure
+ */
+static int tps65911_vdd_hex2volt(int hex)
+{
+ if (hex > TPS65910_VDD_SEL_MAX)
+ return -EINVAL;
+
+ if (hex < TPS65910_VDD_SEL_MIN)
+ hex = TPS65910_VDD_SEL_MIN;
+
+ return TPS65911_VDD_VOLT_BASE + hex * 12500;
+}
+
+static int tps65911_vio_range[4] = {
+ 1500000, 1800000, 2500000, 3300000
+};
+
+static int tps65911_vio_val(struct udevice *dev, int op, int *uV)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u32 adr = uc_pdata->volt_reg;
+ int i, val;
+
+ val = pmic_reg_read(dev->parent, adr);
+ if (val < 0)
+ return val;
+
+ if (op == PMIC_OP_GET) {
+ *uV = 0;
+
+ val &= TPS65910_SEL_MASK;
+
+ *uV = tps65911_vio_range[val >> 2];
+
+ return 0;
+ }
+
+ val &= ~TPS65910_SEL_MASK;
+
+ for (i = 0; i < ARRAY_SIZE(tps65911_vio_range); i++)
+ if (*uV <= tps65911_vio_range[i])
+ break;
+
+ return pmic_reg_write(dev->parent, adr, val | i << 2);
+}
+
+static int tps65911_vdd_val(struct udevice *dev, int op, int *uV)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u32 adr = uc_pdata->volt_reg;
+ int val, ret;
+
+ /* in case vdd is vio */
+ if (!adr)
+ return tps65911_vio_val(dev, op, uV);
+
+ val = pmic_reg_read(dev->parent, adr);
+ if (val < 0)
+ return val;
+
+ if (op == PMIC_OP_GET) {
+ *uV = 0;
+
+ ret = tps65911_vdd_hex2volt(val);
+ if (ret < 0)
+ return ret;
+
+ *uV = ret;
+ return 0;
+ }
+
+ val = tps65911_vdd_volt2hex(*uV);
+ if (val < 0)
+ return val;
+
+ return pmic_reg_write(dev->parent, adr, val);
+}
+
+static int tps65911_vdd_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+
+ /* check for vddctrl and vddio cases */
+ if (!strcmp("vddctrl", dev->name)) {
+ uc_pdata->ctrl_reg = tps65911_vdd_reg[0][2];
+ uc_pdata->volt_reg = tps65911_vdd_reg[1][2];
+ return 0;
+ }
+
+ if (!strcmp("vddio", dev->name)) {
+ uc_pdata->ctrl_reg = tps65911_vdd_reg[0][3];
+ uc_pdata->volt_reg = tps65911_vdd_reg[1][3];
+ return 0;
+ }
+
+ if (dev->driver_data > 0) {
+ u8 idx = dev->driver_data - 1;
+
+ uc_pdata->ctrl_reg = tps65911_vdd_reg[0][idx];
+ uc_pdata->volt_reg = tps65911_vdd_reg[1][idx];
+ }
+
+ return 0;
+}
+
+static int vdd_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = tps65911_vdd_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int vdd_set_value(struct udevice *dev, int uV)
+{
+ return tps65911_vdd_val(dev, PMIC_OP_SET, &uV);
+}
+
+static const struct dm_regulator_ops tps65911_vdd_ops = {
+ .get_value = vdd_get_value,
+ .set_value = vdd_set_value,
+ .get_enable = tps65911_get_enable,
+ .set_enable = tps65911_set_enable,
+};
+
+U_BOOT_DRIVER(tps65911_vdd) = {
+ .name = TPS65911_VDD_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &tps65911_vdd_ops,
+ .probe = tps65911_vdd_probe,
+};
+
+/**
+ * tps65911_ldo_volt2hex() - convert voltage in uV into
+ * applicable to register hex value
+ *
+ * @idx: regulator index
+ * @uV: voltage in uV
+ *
+ * Return: voltage in hex on success, -ve on failure
+ */
+static int tps65911_ldo_volt2hex(int idx, int uV)
+{
+ int step;
+
+ if (uV > TPS65911_LDO_VOLT_MAX)
+ return -EINVAL;
+
+ if (uV < TPS65911_LDO_VOLT_BASE)
+ uV = TPS65911_LDO_VOLT_BASE;
+
+ switch (idx) {
+ case 1:
+ case 2:
+ case 4:
+ step = TPS65911_LDO124_VOLT_STEP;
+ break;
+ case 3:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ step = TPS65911_LDO358_VOLT_STEP;
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ return ((uV - TPS65911_LDO_VOLT_BASE) / step) << 2;
+}
+
+/**
+ * tps65911_ldo_hex2volt() - convert register hex value into
+ * actual voltage in uV
+ *
+ * @idx: regulator index
+ * @hex: hex value of register
+ *
+ * Return: voltage in uV on success, -ve on failure
+ */
+static int tps65911_ldo_hex2volt(int idx, int hex)
+{
+ int step;
+
+ switch (idx) {
+ case 1:
+ case 2:
+ case 4:
+ if (hex > TPS65911_LDO124_VOLT_MAX_HEX)
+ return -EINVAL;
+
+ step = TPS65911_LDO124_VOLT_STEP;
+ break;
+ case 3:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ if (hex > TPS65911_LDO358_VOLT_MAX_HEX)
+ return -EINVAL;
+
+ if (hex < TPS65911_LDO358_VOLT_MIN_HEX)
+ hex = TPS65911_LDO358_VOLT_MIN_HEX;
+
+ step = TPS65911_LDO358_VOLT_STEP;
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ return TPS65911_LDO_VOLT_BASE + hex * step;
+}
+
+static int tps65911_ldo_val(struct udevice *dev, int op, int *uV)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u32 adr = uc_pdata->ctrl_reg;
+ int idx = dev->driver_data;
+ int val, hex, ret;
+
+ val = pmic_reg_read(dev->parent, adr);
+ if (val < 0)
+ return val;
+
+ if (op == PMIC_OP_GET) {
+ *uV = 0;
+ val &= TPS65911_LDO_SEL_MASK;
+
+ ret = tps65911_ldo_hex2volt(idx, val >> 2);
+ if (ret < 0)
+ return ret;
+
+ *uV = ret;
+ return 0;
+ }
+
+ hex = tps65911_ldo_volt2hex(idx, *uV);
+ if (hex < 0)
+ return hex;
+
+ val &= ~TPS65911_LDO_SEL_MASK;
+
+ return pmic_reg_write(dev->parent, adr, val | hex);
+}
+
+static int tps65911_ldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u8 idx = dev->driver_data - 1;
+
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+ uc_pdata->ctrl_reg = tps65911_ldo_reg[idx];
+
+ return 0;
+}
+
+static int ldo_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = tps65911_ldo_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int ldo_set_value(struct udevice *dev, int uV)
+{
+ return tps65911_ldo_val(dev, PMIC_OP_SET, &uV);
+}
+
+static const struct dm_regulator_ops tps65911_ldo_ops = {
+ .get_value = ldo_get_value,
+ .set_value = ldo_set_value,
+ .get_enable = tps65911_get_enable,
+ .set_enable = tps65911_set_enable,
+};
+
+U_BOOT_DRIVER(tps65911_ldo) = {
+ .name = TPS65911_LDO_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &tps65911_ldo_ops,
+ .probe = tps65911_ldo_probe,
+};
diff --git a/drivers/power/regulator/tps80031_regulator.c b/drivers/power/regulator/tps80031_regulator.c
new file mode 100644
index 00000000000..87696662e11
--- /dev/null
+++ b/drivers/power/regulator/tps80031_regulator.c
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/tps80031.h>
+
+static const char tps80031_smps_reg[][TPS80031_SMPS_NUM] = {
+ { 0x54, 0x5a, 0x66, 0x42, 0x48 },
+ { 0x56, 0x5c, 0x68, 0x44, 0x4a },
+ { BIT(3), BIT(4), BIT(6), BIT(0), BIT(1) },
+};
+
+static const char tps80031_ldo_reg[][TPS80031_LDO_NUM] = {
+ { 0x9e, 0x86, 0x8e, 0x8a, 0x9a, 0x92, 0xa6, 0x96, 0xa2 },
+ { 0x9f, 0x87, 0x8f, 0x8b, 0x9b, 0x93, 0xa7, 0x97, 0xa3 },
+};
+
+static int tps80031_regulator_enable(struct udevice *dev, int op, bool *enable)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u32 adr = uc_pdata->ctrl_reg;
+ int val, ret;
+
+ val = pmic_reg_read(dev->parent, adr);
+ if (val < 0)
+ return val;
+
+ if (op == PMIC_OP_GET) {
+ if (val & REGULATOR_MODE_ON)
+ *enable = true;
+ else
+ *enable = false;
+
+ return 0;
+ } else if (op == PMIC_OP_SET) {
+ val &= ~REGULATOR_STATUS_MASK;
+
+ if (*enable)
+ val |= REGULATOR_MODE_ON;
+
+ ret = pmic_reg_write(dev->parent, adr, val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tps80031_get_enable(struct udevice *dev)
+{
+ bool enable = false;
+ int ret;
+
+ ret = tps80031_regulator_enable(dev, PMIC_OP_GET, &enable);
+ if (ret)
+ return ret;
+
+ return enable;
+}
+
+static int tps80031_set_enable(struct udevice *dev, bool enable)
+{
+ return tps80031_regulator_enable(dev, PMIC_OP_SET, &enable);
+}
+
+/**
+ * tps80031_ldo_volt2hex() - convert voltage in uV into
+ * applicable to register hex value
+ *
+ * @uV: voltage in uV
+ *
+ * Return: voltage in hex on success, -ve on failure
+ */
+static int tps80031_ldo_volt2hex(int uV)
+{
+ if (uV > LDO_VOLT_MAX)
+ return -EINVAL;
+
+ if (uV < LDO_VOLT_MIN)
+ uV = LDO_VOLT_MIN;
+
+ return DIV_ROUND_UP(uV - LDO_VOLT_BASE, 102000);
+}
+
+/**
+ * tps80031_ldo_hex2volt() - convert register hex value into
+ * actual voltage in uV
+ *
+ * @hex: hex value of register
+ *
+ * Return: voltage in uV on success, -ve on failure
+ */
+static int tps80031_ldo_hex2volt(int hex)
+{
+ if (hex > LDO_VOLT_MAX_HEX)
+ return -EINVAL;
+
+ if (hex < LDO_VOLT_MIN_HEX)
+ hex = LDO_VOLT_MIN_HEX;
+
+ return LDO_VOLT_BASE + hex * 102000;
+}
+
+static int tps80031_ldo_val(struct udevice *dev, int op, int *uV)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ u32 adr = uc_pdata->volt_reg;
+ int val, hex, ret;
+
+ val = pmic_reg_read(dev->parent, adr);
+ if (val < 0)
+ return val;
+
+ if (op == PMIC_OP_GET) {
+ *uV = 0;
+
+ ret = tps80031_ldo_hex2volt(val & LDO_VOLT_MASK);
+ if (ret < 0)
+ return ret;
+
+ *uV = ret;
+ return 0;
+ }
+
+ hex = tps80031_ldo_volt2hex(*uV);
+ if (hex < 0)
+ return hex;
+
+ val &= ~LDO_VOLT_MASK;
+
+ return pmic_reg_write(dev->parent, adr, val | hex);
+}
+
+static int tps80031_ldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+
+ /* check for ldoln and ldousb cases */
+ if (!strcmp("ldoln", dev->name)) {
+ uc_pdata->ctrl_reg = tps80031_ldo_reg[CTRL][7];
+ uc_pdata->volt_reg = tps80031_ldo_reg[VOLT][7];
+ return 0;
+ }
+
+ if (!strcmp("ldousb", dev->name)) {
+ uc_pdata->ctrl_reg = tps80031_ldo_reg[CTRL][8];
+ uc_pdata->volt_reg = tps80031_ldo_reg[VOLT][8];
+ return 0;
+ }
+
+ if (dev->driver_data > 0) {
+ u8 idx = dev->driver_data - 1;
+
+ uc_pdata->ctrl_reg = tps80031_ldo_reg[CTRL][idx];
+ uc_pdata->volt_reg = tps80031_ldo_reg[VOLT][idx];
+ }
+
+ return 0;
+}
+
+static int ldo_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = tps80031_ldo_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int ldo_set_value(struct udevice *dev, int uV)
+{
+ return tps80031_ldo_val(dev, PMIC_OP_SET, &uV);
+}
+
+static const struct dm_regulator_ops tps80031_ldo_ops = {
+ .get_value = ldo_get_value,
+ .set_value = ldo_set_value,
+ .get_enable = tps80031_get_enable,
+ .set_enable = tps80031_set_enable,
+};
+
+U_BOOT_DRIVER(tps80031_ldo) = {
+ .name = TPS80031_LDO_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &tps80031_ldo_ops,
+ .probe = tps80031_ldo_probe,
+};
+
+struct tps80031_smps_priv {
+ int flags;
+};
+
+/* DCDC voltages for the selector of 0x39 to 0x3F */
+static int tps80031_dcdc_voltages[5] = {
+ 1350000, 1500000, 1800000, 1900000, 2100000
+};
+
+/**
+ * tps80031_smps_volt2hex() - convert voltage in uV into
+ * applicable to register hex value
+ *
+ * @base: base voltage in uV
+ * @uV: voltage in uV
+ *
+ * Return: voltage in hex on success, -ve on failure
+ */
+static int tps80031_smps_volt2hex(u32 base, int uV)
+{
+ int i;
+
+ if (uV < base)
+ return 1;
+
+ if (uV > SMPS_VOLT_LINEAR) {
+ for (i = 0; i < ARRAY_SIZE(tps80031_dcdc_voltages); i++)
+ if (uV <= tps80031_dcdc_voltages[i])
+ break;
+
+ return SMPS_VOLT_NLINEAR_HEX + i;
+ }
+
+ return DIV_ROUND_UP(uV - base, 12500);
+}
+
+/**
+ * tps80031_smps_hex2volt() - convert register hex value into
+ * actual voltage in uV
+ *
+ * @base: base voltage in uV
+ * @hex: hex value of register
+ *
+ * Return: voltage in uV on success, -ve on failure
+ */
+static int tps80031_smps_hex2volt(u32 base, int hex)
+{
+ if (!hex)
+ return 0;
+
+ /* if reg value exceeds linear scale use table */
+ if (hex > SMPS_VOLT_LINEAR_HEX)
+ return tps80031_dcdc_voltages[hex - SMPS_VOLT_LINEAR_HEX];
+ else
+ return base + hex * 12500;
+}
+
+static int tps80031_smps_val(struct udevice *dev, int op, int *uV)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ struct tps80031_smps_priv *priv = dev_get_priv(dev);
+ u32 adr = uc_pdata->volt_reg;
+ int base, val, hex, ret;
+
+ /* If offset flag was set then base voltage is higher */
+ if (priv->flags & TPS80031_OFFSET_FLAG)
+ base = SMPS_VOLT_BASE_OFFSET;
+ else
+ base = SMPS_VOLT_BASE;
+
+ val = pmic_reg_read(dev->parent, adr);
+ if (val < 0)
+ return val;
+
+ if (op == PMIC_OP_GET) {
+ *uV = 0;
+
+ ret = tps80031_smps_hex2volt(base, val & SMPS_VOLT_MASK);
+ if (ret < 0)
+ return ret;
+
+ *uV = ret;
+ return 0;
+ }
+
+ hex = tps80031_smps_volt2hex(base, *uV);
+ if (hex < 0)
+ return hex;
+
+ val &= ~SMPS_VOLT_MASK;
+
+ return pmic_reg_write(dev->parent, adr, val | hex);
+}
+
+static int tps80031_smps_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata =
+ dev_get_uclass_plat(dev);
+ struct tps80031_smps_priv *priv = dev_get_priv(dev);
+ int idx = dev->driver_data - 1;
+ int val;
+
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+
+ uc_pdata->ctrl_reg = tps80031_smps_reg[CTRL][idx];
+ uc_pdata->volt_reg = tps80031_smps_reg[VOLT][idx];
+
+ /* Determine if smps regulator uses higher voltage */
+ val = pmic_reg_read(dev->parent, TPS80031_SMPS_OFFSET);
+ if (val & tps80031_smps_reg[OFFSET][idx])
+ priv->flags |= TPS80031_OFFSET_FLAG;
+
+ return 0;
+}
+
+static int smps_get_value(struct udevice *dev)
+{
+ int uV;
+ int ret;
+
+ ret = tps80031_smps_val(dev, PMIC_OP_GET, &uV);
+ if (ret)
+ return ret;
+
+ return uV;
+}
+
+static int smps_set_value(struct udevice *dev, int uV)
+{
+ return tps80031_smps_val(dev, PMIC_OP_SET, &uV);
+}
+
+static const struct dm_regulator_ops tps80031_smps_ops = {
+ .get_value = smps_get_value,
+ .set_value = smps_set_value,
+ .get_enable = tps80031_get_enable,
+ .set_enable = tps80031_set_enable,
+};
+
+U_BOOT_DRIVER(tps80031_smps) = {
+ .name = TPS80031_SMPS_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &tps80031_smps_ops,
+ .probe = tps80031_smps_probe,
+ .priv_auto = sizeof(struct tps80031_smps_priv),
+};
diff --git a/drivers/pwm/pwm-aspeed.c b/drivers/pwm/pwm-aspeed.c
index ba98641c866..b03472d2345 100644
--- a/drivers/pwm/pwm-aspeed.c
+++ b/drivers/pwm/pwm-aspeed.c
@@ -49,6 +49,7 @@
#include <dm/device_compat.h>
#include <linux/math64.h>
#include <linux/bitfield.h>
+#include <linux/time.h>
#include <asm/io.h>
/* The channel number of Aspeed pwm controller */
@@ -77,8 +78,6 @@
/* PWM fixed value */
#define PWM_ASPEED_FIXED_PERIOD 0xff
-#define NSEC_PER_SEC 1000000000L
-
struct aspeed_pwm_priv {
struct clk clk;
struct regmap *regmap;
diff --git a/drivers/pwm/pwm-at91.c b/drivers/pwm/pwm-at91.c
index 95597aee557..3ff1fb6d5c3 100644
--- a/drivers/pwm/pwm-at91.c
+++ b/drivers/pwm/pwm-at91.c
@@ -14,11 +14,11 @@
#include <dm.h>
#include <linux/bitops.h>
#include <linux/io.h>
+#include <linux/time.h>
#include <pwm.h>
#define PERIOD_BITS 16
#define PWM_MAX_PRES 10
-#define NSEC_PER_SEC 1000000000L
#define PWM_ENA 0x04
#define PWM_CHANNEL_OFFSET 0x20
diff --git a/drivers/pwm/pwm-cadence-ttc.c b/drivers/pwm/pwm-cadence-ttc.c
index dc3b314b0cc..d9f6736a7ae 100644
--- a/drivers/pwm/pwm-cadence-ttc.c
+++ b/drivers/pwm/pwm-cadence-ttc.c
@@ -17,6 +17,7 @@
#include <linux/bitfield.h>
#include <linux/math64.h>
#include <linux/log2.h>
+#include <linux/time.h>
#include <dm/device_compat.h>
#define CLOCK_CONTROL 0
@@ -37,8 +38,6 @@
#define COUNTER_INTERVAL_ENABLE BIT(1)
#define COUNTER_COUNTING_DISABLE BIT(0)
-#define NSEC_PER_SEC 1000000000L
-
#define TTC_REG(reg, channel) ((reg) + (channel) * sizeof(u32))
#define TTC_CLOCK_CONTROL(reg, channel) \
TTC_REG((reg) + CLOCK_CONTROL, (channel))
diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c
index 2311910a636..60959720dac 100644
--- a/drivers/pwm/pwm-meson.c
+++ b/drivers/pwm/pwm-meson.c
@@ -26,8 +26,7 @@
#include <linux/math64.h>
#include <linux/bitfield.h>
#include <linux/clk-provider.h>
-
-#define NSEC_PER_SEC 1000000000L
+#include <linux/time.h>
#define REG_PWM_A 0x0
#define REG_PWM_B 0x4
diff --git a/drivers/pwm/pwm-mtk.c b/drivers/pwm/pwm-mtk.c
index 11e74440197..ad845ed9662 100644
--- a/drivers/pwm/pwm-mtk.c
+++ b/drivers/pwm/pwm-mtk.c
@@ -12,6 +12,7 @@
#include <div64.h>
#include <linux/bitops.h>
#include <linux/io.h>
+#include <linux/time.h>
/* PWM registers and bits definitions */
#define PWMCON 0x00
@@ -27,8 +28,6 @@
#define PWM_CLK_DIV_MAX 7
#define MAX_PWM_NUM 8
-#define NSEC_PER_SEC 1000000000L
-
enum mtk_pwm_reg_ver {
PWM_REG_V1,
PWM_REG_V2,
diff --git a/drivers/pwm/pwm-ti-ehrpwm.c b/drivers/pwm/pwm-ti-ehrpwm.c
index f09914519bd..fefa3c65ec4 100644
--- a/drivers/pwm/pwm-ti-ehrpwm.c
+++ b/drivers/pwm/pwm-ti-ehrpwm.c
@@ -14,8 +14,7 @@
#include <dm/device_compat.h>
#include <pwm.h>
#include <asm/io.h>
-
-#define NSEC_PER_SEC 1000000000L
+#include <linux/time.h>
/* Time base module registers */
#define TI_EHRPWM_TBCTL 0x00
diff --git a/drivers/qe/fdt.c b/drivers/qe/fdt.c
index 6195c7c4442..fa9e4065560 100644
--- a/drivers/qe/fdt.c
+++ b/drivers/qe/fdt.c
@@ -6,7 +6,6 @@
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*/
-#include <common.h>
#include <asm/global_data.h>
#include <linux/libfdt.h>
#include <fdt_support.h>
diff --git a/drivers/qe/qe.c b/drivers/qe/qe.c
index 2825dc6f9aa..9631337b8d9 100644
--- a/drivers/qe/qe.c
+++ b/drivers/qe/qe.c
@@ -6,7 +6,6 @@
* based on source code of Shlomi Gridish
*/
-#include <common.h>
#include <malloc.h>
#include <command.h>
#include <asm/global_data.h>
@@ -24,6 +23,9 @@
#include <asm/armv8/mmu.h>
#include <asm/arch/cpu.h>
#endif
+#ifdef CONFIG_PPC
+#include <asm/ppc.h>
+#endif
#define MPC85xx_DEVDISR_QE_DISABLE 0x1
diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig
index bf999645774..5b07e920301 100644
--- a/drivers/ram/Kconfig
+++ b/drivers/ram/Kconfig
@@ -109,8 +109,9 @@ config IMXRT_SDRAM
source "drivers/ram/aspeed/Kconfig"
source "drivers/ram/cadence/Kconfig"
+source "drivers/ram/octeon/Kconfig"
source "drivers/ram/rockchip/Kconfig"
source "drivers/ram/sifive/Kconfig"
source "drivers/ram/stm32mp1/Kconfig"
-source "drivers/ram/octeon/Kconfig"
source "drivers/ram/starfive/Kconfig"
+source "drivers/ram/sunxi/Kconfig"
diff --git a/drivers/ram/Makefile b/drivers/ram/Makefile
index 6eb1a241359..985990ab5ac 100644
--- a/drivers/ram/Makefile
+++ b/drivers/ram/Makefile
@@ -23,6 +23,9 @@ obj-$(CONFIG_RAM_SIFIVE) += sifive/
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_SPL_STARFIVE_DDR) += starfive/
endif
+
+obj-$(CONFIG_DRAM_SUN20I_D1) += sunxi/
+
obj-$(CONFIG_ARCH_OCTEON) += octeon/
obj-$(CONFIG_ARCH_RMOBILE) += renesas/
diff --git a/drivers/ram/k3-am654-ddrss.c b/drivers/ram/k3-am654-ddrss.c
index b8338f84a3d..cff8ffc8929 100644
--- a/drivers/ram/k3-am654-ddrss.c
+++ b/drivers/ram/k3-am654-ddrss.c
@@ -2,7 +2,7 @@
/*
* Texas Instruments' AM654 DDRSS driver
*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com>
*/
@@ -903,7 +903,7 @@ static int am654_ddrss_power_on(struct am654_ddrss_desc *ddrss)
static int am654_ddrss_ofdata_to_priv(struct udevice *dev)
{
struct am654_ddrss_desc *ddrss = dev_get_priv(dev);
- phys_addr_t reg;
+ void *reg;
int ret;
debug("%s(dev=%p)\n", __func__, dev);
@@ -926,26 +926,26 @@ static int am654_ddrss_ofdata_to_priv(struct udevice *dev)
return ret;
}
- reg = devfdt_get_addr_name(dev, "ss");
- if (reg == FDT_ADDR_T_NONE) {
+ reg = dev_read_addr_name_ptr(dev, "ss");
+ if (!reg) {
dev_err(dev, "No reg property for DDRSS wrapper logic\n");
return -EINVAL;
}
- ddrss->ddrss_ss_cfg = (void *)reg;
+ ddrss->ddrss_ss_cfg = reg;
- reg = devfdt_get_addr_name(dev, "ctl");
- if (reg == FDT_ADDR_T_NONE) {
+ reg = dev_read_addr_name_ptr(dev, "ctl");
+ if (!reg) {
dev_err(dev, "No reg property for Controller region\n");
return -EINVAL;
}
- ddrss->ddrss_ctl_cfg = (void *)reg;
+ ddrss->ddrss_ctl_cfg = reg;
- reg = devfdt_get_addr_name(dev, "phy");
- if (reg == FDT_ADDR_T_NONE) {
+ reg = dev_read_addr_name_ptr(dev, "phy");
+ if (!reg) {
dev_err(dev, "No reg property for PHY region\n");
return -EINVAL;
}
- ddrss->ddrss_phy_cfg = (void *)reg;
+ ddrss->ddrss_phy_cfg = reg;
ret = dev_read_u32_array(dev, "ti,ss-reg",
(u32 *)&ddrss->params.ss_reg,
diff --git a/drivers/ram/k3-am654-ddrss.h b/drivers/ram/k3-am654-ddrss.h
index c87f186291e..9d03ae10750 100644
--- a/drivers/ram/k3-am654-ddrss.h
+++ b/drivers/ram/k3-am654-ddrss.h
@@ -2,7 +2,7 @@
/*
* AM654: DDRSS Register definitions and structures.
*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com>
*
*/
diff --git a/drivers/ram/k3-ddrss/Makefile b/drivers/ram/k3-ddrss/Makefile
index ba5d9a2f4d3..823d1887178 100644
--- a/drivers/ram/k3-ddrss/Makefile
+++ b/drivers/ram/k3-ddrss/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0+
#
-# Copyright (C) 2019-2022 Texas Instruments Incorporated - http://www.ti.com/
+# Copyright (C) 2019-2022 Texas Instruments Incorporated - https://www.ti.com/
#
obj-$(CONFIG_K3_DDRSS) += k3-ddrss.o
diff --git a/drivers/ram/k3-ddrss/k3-ddrss.c b/drivers/ram/k3-ddrss/k3-ddrss.c
index b54557f02cc..a5c9b82cf1d 100644
--- a/drivers/ram/k3-ddrss/k3-ddrss.c
+++ b/drivers/ram/k3-ddrss/k3-ddrss.c
@@ -2,7 +2,7 @@
/*
* Texas Instruments' K3 DDRSS driver
*
- * Copyright (C) 2020-2021 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/
*/
#include <common.h>
@@ -331,32 +331,29 @@ static int k3_ddrss_ofdata_to_priv(struct udevice *dev)
{
struct k3_ddrss_desc *ddrss = dev_get_priv(dev);
struct k3_ddrss_data *ddrss_data = (struct k3_ddrss_data *)dev_get_driver_data(dev);
- phys_addr_t reg;
+ void *reg;
int ret;
debug("%s(dev=%p)\n", __func__, dev);
- reg = dev_read_addr_name(dev, "cfg");
- if (reg == FDT_ADDR_T_NONE) {
+ reg = dev_read_addr_name_ptr(dev, "cfg");
+ if (!reg) {
dev_err(dev, "No reg property for DDRSS wrapper logic\n");
return -EINVAL;
}
- ddrss->ddrss_ctl_cfg = (void *)reg;
+ ddrss->ddrss_ctl_cfg = reg;
- reg = dev_read_addr_name(dev, "ctrl_mmr_lp4");
- if (reg == FDT_ADDR_T_NONE) {
+ reg = dev_read_addr_name_ptr(dev, "ctrl_mmr_lp4");
+ if (!reg) {
dev_err(dev, "No reg property for CTRL MMR\n");
return -EINVAL;
}
- ddrss->ddrss_ctrl_mmr = (void *)reg;
+ ddrss->ddrss_ctrl_mmr = reg;
- reg = dev_read_addr_name(dev, "ss_cfg");
- if (reg == FDT_ADDR_T_NONE) {
+ reg = dev_read_addr_name_ptr(dev, "ss_cfg");
+ if (!reg)
dev_dbg(dev, "No reg property for SS Config region, but this is optional so continuing.\n");
- ddrss->ddrss_ss_cfg = NULL;
- } else {
- ddrss->ddrss_ss_cfg = (void *)reg;
- }
+ ddrss->ddrss_ss_cfg = reg;
ret = power_domain_get_by_index(dev, &ddrss->ddrcfg_pwrdmn, 0);
if (ret) {
diff --git a/drivers/ram/sunxi/Kconfig b/drivers/ram/sunxi/Kconfig
new file mode 100644
index 00000000000..1775cb0d780
--- /dev/null
+++ b/drivers/ram/sunxi/Kconfig
@@ -0,0 +1,60 @@
+config DRAM_SUN20I_D1
+ bool
+ depends on ARCH_SUNXI
+ help
+ This enables support for the DRAM controller driver covering
+ the Allwinner D1/R528/T113s SoCs.
+
+if DRAM_SUN20I_D1
+
+config DRAM_SUNXI_ODT_EN
+ hex "DRAM ODT EN parameter"
+ help
+ ODT EN value from vendor DRAM settings.
+
+config DRAM_SUNXI_TPR0
+ hex "DRAM TPR0 parameter"
+ help
+ TPR0 value from vendor DRAM settings.
+
+config DRAM_SUNXI_TPR11
+ hex "DRAM TPR11 parameter"
+ help
+ TPR11 value from vendor DRAM settings.
+
+config DRAM_SUNXI_TPR12
+ hex "DRAM TPR12 parameter"
+ help
+ TPR12 value from vendor DRAM settings.
+
+config DRAM_SUNXI_TPR13
+ hex "DRAM TPR13 parameter"
+ help
+ TPR13 value from vendor DRAM settings. It tells which features
+ should be configured.
+
+choice
+ prompt "DRAM chip type"
+ default SUNXI_DRAM_TYPE_DDR3 if DRAM_SUN20I_D1
+
+config SUNXI_DRAM_TYPE_DDR2
+ bool "DDR2 chips"
+
+config SUNXI_DRAM_TYPE_DDR3
+ bool "DDR3 chips"
+
+config SUNXI_DRAM_TYPE_LPDDR2
+ bool "LPDDR2 chips"
+
+config SUNXI_DRAM_TYPE_LPDDR3
+ bool "LPDDR3 chips"
+endchoice
+
+config SUNXI_DRAM_TYPE
+ int
+ default 2 if SUNXI_DRAM_TYPE_DDR2
+ default 3 if SUNXI_DRAM_TYPE_DDR3
+ default 6 if SUNXI_DRAM_TYPE_LPDDR2
+ default 7 if SUNXI_DRAM_TYPE_LPDDR3
+
+endif
diff --git a/drivers/ram/sunxi/Makefile b/drivers/ram/sunxi/Makefile
new file mode 100644
index 00000000000..86ea0b9ae98
--- /dev/null
+++ b/drivers/ram/sunxi/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-$(CONFIG_DRAM_SUN20I_D1) += dram_sun20i_d1.o
diff --git a/drivers/ram/sunxi/dram_sun20i_d1.c b/drivers/ram/sunxi/dram_sun20i_d1.c
new file mode 100644
index 00000000000..38379281d73
--- /dev/null
+++ b/drivers/ram/sunxi/dram_sun20i_d1.c
@@ -0,0 +1,1441 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Allwinner D1/D1s/R528/T113-sx DRAM initialisation
+ *
+ * As usual there is no documentation for the memory controller or PHY IP
+ * used here. The baseline of this code was lifted from awboot[1], which
+ * seems to be based on some form of de-compilation of some original Allwinner
+ * code bits (with a GPL2 license tag from the very beginning).
+ * This version here is a reworked version, to match the U-Boot coding style
+ * and style of the other Allwinner DRAM drivers.
+ *
+ * [1] https://github.com/szemzoa/awboot.git
+ */
+
+#include <asm/io.h>
+#include <common.h>
+#ifdef CONFIG_RAM
+ #include <dm.h>
+ #include <ram.h>
+#endif
+#include <linux/delay.h>
+
+#include "dram_sun20i_d1.h"
+
+#ifndef SUNXI_SID_BASE
+#define SUNXI_SID_BASE 0x3006200
+#endif
+
+#ifndef SUNXI_CCM_BASE
+#define SUNXI_CCM_BASE 0x2001000
+#endif
+
+static void sid_read_ldoB_cal(const dram_para_t *para)
+{
+ uint32_t reg;
+
+ reg = (readl(SUNXI_SID_BASE + 0x1c) & 0xff00) >> 8;
+
+ if (reg == 0)
+ return;
+
+ switch (para->dram_type) {
+ case SUNXI_DRAM_TYPE_DDR2:
+ break;
+ case SUNXI_DRAM_TYPE_DDR3:
+ if (reg > 0x20)
+ reg -= 0x16;
+ break;
+ default:
+ reg = 0;
+ break;
+ }
+
+ clrsetbits_le32(0x3000150, 0xff00, reg << 8);
+}
+
+static void dram_voltage_set(const dram_para_t *para)
+{
+ int vol;
+
+ switch (para->dram_type) {
+ case SUNXI_DRAM_TYPE_DDR2:
+ vol = 47;
+ break;
+ case SUNXI_DRAM_TYPE_DDR3:
+ vol = 25;
+ break;
+ default:
+ vol = 0;
+ break;
+ }
+
+ clrsetbits_le32(0x3000150, 0x20ff00, vol << 8);
+
+ udelay(1);
+
+ sid_read_ldoB_cal(para);
+}
+
+static void dram_enable_all_master(void)
+{
+ writel(~0, 0x3102020);
+ writel(0xff, 0x3102024);
+ writel(0xffff, 0x3102028);
+ udelay(10);
+}
+
+static void dram_disable_all_master(void)
+{
+ writel(1, 0x3102020);
+ writel(0, 0x3102024);
+ writel(0, 0x3102028);
+ udelay(10);
+}
+
+static void eye_delay_compensation(const dram_para_t *para)
+{
+ uint32_t delay;
+ unsigned long ptr;
+
+ // DATn0IOCR, n = 0...7
+ delay = (para->dram_tpr11 & 0xf) << 9;
+ delay |= (para->dram_tpr12 & 0xf) << 1;
+ for (ptr = 0x3103310; ptr < 0x3103334; ptr += 4)
+ setbits_le32(ptr, delay);
+
+ // DATn1IOCR, n = 0...7
+ delay = (para->dram_tpr11 & 0xf0) << 5;
+ delay |= (para->dram_tpr12 & 0xf0) >> 3;
+ for (ptr = 0x3103390; ptr != 0x31033b4; ptr += 4)
+ setbits_le32(ptr, delay);
+
+ // PGCR0: assert AC loopback FIFO reset
+ clrbits_le32(0x3103100, 0x04000000);
+
+ // ??
+
+ delay = (para->dram_tpr11 & 0xf0000) >> 7;
+ delay |= (para->dram_tpr12 & 0xf0000) >> 15;
+ setbits_le32(0x3103334, delay);
+ setbits_le32(0x3103338, delay);
+
+ delay = (para->dram_tpr11 & 0xf00000) >> 11;
+ delay |= (para->dram_tpr12 & 0xf00000) >> 19;
+ setbits_le32(0x31033b4, delay);
+ setbits_le32(0x31033b8, delay);
+
+ setbits_le32(0x310333c, (para->dram_tpr11 & 0xf0000) << 9);
+ setbits_le32(0x31033bc, (para->dram_tpr11 & 0xf00000) << 5);
+
+ // PGCR0: release AC loopback FIFO reset
+ setbits_le32(0x3103100, BIT(26));
+
+ udelay(1);
+
+ delay = (para->dram_tpr10 & 0xf0) << 4;
+ for (ptr = 0x3103240; ptr != 0x310327c; ptr += 4)
+ setbits_le32(ptr, delay);
+ for (ptr = 0x3103228; ptr != 0x3103240; ptr += 4)
+ setbits_le32(ptr, delay);
+
+ setbits_le32(0x3103218, (para->dram_tpr10 & 0x0f) << 8);
+ setbits_le32(0x310321c, (para->dram_tpr10 & 0x0f) << 8);
+
+ setbits_le32(0x3103280, (para->dram_tpr10 & 0xf00) >> 4);
+}
+
+/*
+ * Main purpose of the auto_set_timing routine seems to be to calculate all
+ * timing settings for the specific type of sdram used. Read together with
+ * an sdram datasheet for context on the various variables.
+ */
+static void mctl_set_timing_params(const dram_para_t *para,
+ const dram_config_t *config)
+{
+ /* DRAM_TPR0 */
+ u8 tccd = 2;
+ u8 tfaw;
+ u8 trrd;
+ u8 trcd;
+ u8 trc;
+
+ /* DRAM_TPR1 */
+ u8 txp;
+ u8 twtr;
+ u8 trtp = 4;
+ u8 twr;
+ u8 trp;
+ u8 tras;
+
+ /* DRAM_TPR2 */
+ u16 trefi;
+ u16 trfc;
+
+ u8 tcksrx;
+ u8 tckesr;
+ u8 trd2wr;
+ u8 twr2rd;
+ u8 trasmax;
+ u8 twtp;
+ u8 tcke;
+ u8 tmod;
+ u8 tmrd;
+ u8 tmrw;
+
+ u8 tcl;
+ u8 tcwl;
+ u8 t_rdata_en;
+ u8 wr_latency;
+
+ u32 mr0;
+ u32 mr1;
+ u32 mr2;
+ u32 mr3;
+
+ u32 tdinit0;
+ u32 tdinit1;
+ u32 tdinit2;
+ u32 tdinit3;
+
+ switch (para->dram_type) {
+ case SUNXI_DRAM_TYPE_DDR2:
+ /* DRAM_TPR0 */
+ tfaw = ns_to_t(50);
+ trrd = ns_to_t(10);
+ trcd = ns_to_t(20);
+ trc = ns_to_t(65);
+
+ /* DRAM_TPR1 */
+ txp = 2;
+ twtr = ns_to_t(8);
+ twr = ns_to_t(15);
+ trp = ns_to_t(15);
+ tras = ns_to_t(45);
+
+ /* DRAM_TRP2 */
+ trfc = ns_to_t(328);
+ trefi = ns_to_t(7800) / 32;
+
+ trasmax = CONFIG_DRAM_CLK / 30;
+ if (CONFIG_DRAM_CLK < 409) {
+ t_rdata_en = 1;
+ tcl = 3;
+ mr0 = 0x06a3;
+ } else {
+ t_rdata_en = 2;
+ tcl = 4;
+ mr0 = 0x0e73;
+ }
+ tmrd = 2;
+ twtp = twr + 5;
+ tcksrx = 5;
+ tckesr = 4;
+ trd2wr = 4;
+ tcke = 3;
+ tmod = 12;
+ wr_latency = 1;
+ tmrw = 0;
+ twr2rd = twtr + 5;
+ tcwl = 0;
+
+ mr1 = para->dram_mr1;
+ mr2 = 0;
+ mr3 = 0;
+
+ tdinit0 = 200 * CONFIG_DRAM_CLK + 1;
+ tdinit1 = 100 * CONFIG_DRAM_CLK / 1000 + 1;
+ tdinit2 = 200 * CONFIG_DRAM_CLK + 1;
+ tdinit3 = 1 * CONFIG_DRAM_CLK + 1;
+
+ break;
+ case SUNXI_DRAM_TYPE_DDR3:
+ trfc = ns_to_t(350);
+ trefi = ns_to_t(7800) / 32 + 1; // XXX
+
+ twtr = ns_to_t(8) + 2; // + 2 ? XXX
+ /* Only used by trd2wr calculation, which gets discard below */
+// twr = max(ns_to_t(15), 2);
+ trrd = max(ns_to_t(10), 2);
+ txp = max(ns_to_t(10), 2);
+
+ if (CONFIG_DRAM_CLK <= 800) {
+ tfaw = ns_to_t(50);
+ trcd = ns_to_t(15);
+ trp = ns_to_t(15);
+ trc = ns_to_t(53);
+ tras = ns_to_t(38);
+
+ mr0 = 0x1c70;
+ mr2 = 0x18;
+ tcl = 6;
+ wr_latency = 2;
+ tcwl = 4;
+ t_rdata_en = 4;
+ } else {
+ tfaw = ns_to_t(35);
+ trcd = ns_to_t(14);
+ trp = ns_to_t(14);
+ trc = ns_to_t(48);
+ tras = ns_to_t(34);
+
+ mr0 = 0x1e14;
+ mr2 = 0x20;
+ tcl = 7;
+ wr_latency = 3;
+ tcwl = 5;
+ t_rdata_en = 5;
+ }
+
+ trasmax = CONFIG_DRAM_CLK / 30;
+ twtp = tcwl + 2 + twtr; // WL+BL/2+tWTR
+ /* Gets overwritten below */
+// trd2wr = tcwl + 2 + twr; // WL+BL/2+tWR
+ twr2rd = tcwl + twtr; // WL+tWTR
+
+ tdinit0 = 500 * CONFIG_DRAM_CLK + 1; // 500 us
+ tdinit1 = 360 * CONFIG_DRAM_CLK / 1000 + 1; // 360 ns
+ tdinit2 = 200 * CONFIG_DRAM_CLK + 1; // 200 us
+ tdinit3 = 1 * CONFIG_DRAM_CLK + 1; // 1 us
+
+ mr1 = para->dram_mr1;
+ mr3 = 0;
+ tcke = 3;
+ tcksrx = 5;
+ tckesr = 4;
+ if (((config->dram_tpr13 & 0xc) == 0x04) || CONFIG_DRAM_CLK < 912)
+ trd2wr = 5;
+ else
+ trd2wr = 6;
+
+ tmod = 12;
+ tmrd = 4;
+ tmrw = 0;
+
+ break;
+ case SUNXI_DRAM_TYPE_LPDDR2:
+ tfaw = max(ns_to_t(50), 4);
+ trrd = max(ns_to_t(10), 1);
+ trcd = max(ns_to_t(24), 2);
+ trc = ns_to_t(70);
+ txp = ns_to_t(8);
+ if (txp < 2) {
+ txp++;
+ twtr = 2;
+ } else {
+ twtr = txp;
+ }
+ twr = max(ns_to_t(15), 2);
+ trp = ns_to_t(17);
+ tras = ns_to_t(42);
+ trefi = ns_to_t(3900) / 32;
+ trfc = ns_to_t(210);
+
+ trasmax = CONFIG_DRAM_CLK / 60;
+ mr3 = para->dram_mr3;
+ twtp = twr + 5;
+ mr2 = 6;
+ mr1 = 5;
+ tcksrx = 5;
+ tckesr = 5;
+ trd2wr = 10;
+ tcke = 2;
+ tmod = 5;
+ tmrd = 5;
+ tmrw = 3;
+ tcl = 4;
+ wr_latency = 1;
+ t_rdata_en = 1;
+
+ tdinit0 = 200 * CONFIG_DRAM_CLK + 1;
+ tdinit1 = 100 * CONFIG_DRAM_CLK / 1000 + 1;
+ tdinit2 = 11 * CONFIG_DRAM_CLK + 1;
+ tdinit3 = 1 * CONFIG_DRAM_CLK + 1;
+ twr2rd = twtr + 5;
+ tcwl = 2;
+ mr1 = 195;
+ mr0 = 0;
+
+ break;
+ case SUNXI_DRAM_TYPE_LPDDR3:
+ tfaw = max(ns_to_t(50), 4);
+ trrd = max(ns_to_t(10), 1);
+ trcd = max(ns_to_t(24), 2);
+ trc = ns_to_t(70);
+ twtr = max(ns_to_t(8), 2);
+ twr = max(ns_to_t(15), 2);
+ trp = ns_to_t(17);
+ tras = ns_to_t(42);
+ trefi = ns_to_t(3900) / 32;
+ trfc = ns_to_t(210);
+ txp = twtr;
+
+ trasmax = CONFIG_DRAM_CLK / 60;
+ if (CONFIG_DRAM_CLK < 800) {
+ tcwl = 4;
+ wr_latency = 3;
+ t_rdata_en = 6;
+ mr2 = 12;
+ } else {
+ tcwl = 3;
+ tcke = 6;
+ wr_latency = 2;
+ t_rdata_en = 5;
+ mr2 = 10;
+ }
+ twtp = tcwl + 5;
+ tcl = 7;
+ mr3 = para->dram_mr3;
+ tcksrx = 5;
+ tckesr = 5;
+ trd2wr = 13;
+ tcke = 3;
+ tmod = 12;
+ tdinit0 = 400 * CONFIG_DRAM_CLK + 1;
+ tdinit1 = 500 * CONFIG_DRAM_CLK / 1000 + 1;
+ tdinit2 = 11 * CONFIG_DRAM_CLK + 1;
+ tdinit3 = 1 * CONFIG_DRAM_CLK + 1;
+ tmrd = 5;
+ tmrw = 5;
+ twr2rd = tcwl + twtr + 5;
+ mr1 = 195;
+ mr0 = 0;
+
+ break;
+ default:
+ trfc = 128;
+ trp = 6;
+ trefi = 98;
+ txp = 10;
+ twr = 8;
+ twtr = 3;
+ tras = 14;
+ tfaw = 16;
+ trc = 20;
+ trcd = 6;
+ trrd = 3;
+
+ twr2rd = 8;
+ tcksrx = 4;
+ tckesr = 3;
+ trd2wr = 4;
+ trasmax = 27;
+ twtp = 12;
+ tcke = 2;
+ tmod = 6;
+ tmrd = 2;
+ tmrw = 0;
+ tcwl = 3;
+ tcl = 3;
+ wr_latency = 1;
+ t_rdata_en = 1;
+ mr3 = 0;
+ mr2 = 0;
+ mr1 = 0;
+ mr0 = 0;
+ tdinit3 = 0;
+ tdinit2 = 0;
+ tdinit1 = 0;
+ tdinit0 = 0;
+
+ break;
+ }
+
+ /* Set mode registers */
+ writel(mr0, 0x3103030);
+ writel(mr1, 0x3103034);
+ writel(mr2, 0x3103038);
+ writel(mr3, 0x310303c);
+ /* TODO: dram_odt_en is either 0x0 or 0x1, so right shift looks weird */
+ writel((para->dram_odt_en >> 4) & 0x3, 0x310302c);
+
+ /* Set dram timing DRAMTMG0 - DRAMTMG5 */
+ writel((twtp << 24) | (tfaw << 16) | (trasmax << 8) | (tras << 0),
+ 0x3103058);
+ writel((txp << 16) | (trtp << 8) | (trc << 0),
+ 0x310305c);
+ writel((tcwl << 24) | (tcl << 16) | (trd2wr << 8) | (twr2rd << 0),
+ 0x3103060);
+ writel((tmrw << 16) | (tmrd << 12) | (tmod << 0),
+ 0x3103064);
+ writel((trcd << 24) | (tccd << 16) | (trrd << 8) | (trp << 0),
+ 0x3103068);
+ writel((tcksrx << 24) | (tcksrx << 16) | (tckesr << 8) | (tcke << 0),
+ 0x310306c);
+
+ /* Set dual rank timing */
+ clrsetbits_le32(0x3103078, 0xf000ffff,
+ (CONFIG_DRAM_CLK < 800) ? 0xf0006610 : 0xf0007610);
+
+ /* Set phy interface time PITMG0, PTR3, PTR4 */
+ writel((0x2 << 24) | (t_rdata_en << 16) | BIT(8) | (wr_latency << 0),
+ 0x3103080);
+ writel(((tdinit0 << 0) | (tdinit1 << 20)), 0x3103050);
+ writel(((tdinit2 << 0) | (tdinit3 << 20)), 0x3103054);
+
+ /* Set refresh timing and mode */
+ writel((trefi << 16) | (trfc << 0), 0x3103090);
+ writel((trefi << 15) & 0x0fff0000, 0x3103094);
+}
+
+// Purpose of this routine seems to be to initialize the PLL driving
+// the MBUS and sdram.
+//
+static int ccu_set_pll_ddr_clk(int index, const dram_para_t *para,
+ const dram_config_t *config)
+{
+ unsigned int val, clk, n;
+
+ if (config->dram_tpr13 & BIT(6))
+ clk = para->dram_tpr9;
+ else
+ clk = para->dram_clk;
+
+ // set VCO clock divider
+ n = (clk * 2) / 24;
+
+ val = readl(SUNXI_CCM_BASE + 0x10);
+ val &= ~0x0007ff03; // clear dividers
+ val |= (n - 1) << 8; // set PLL division
+ val |= BIT(31) | BIT(30); // enable PLL and LDO
+ writel(val | BIT(29), SUNXI_CCM_BASE + 0x10);
+
+ // wait for PLL to lock
+ while ((readl(SUNXI_CCM_BASE + 0x10) & BIT(28)) == 0)
+ ;
+
+ udelay(20);
+
+ // enable PLL output
+ setbits_le32(SUNXI_CCM_BASE + 0x0, BIT(27));
+
+ // turn clock gate on
+ val = readl(SUNXI_CCM_BASE + 0x800);
+ val &= ~0x03000303; // select DDR clk source, n=1, m=1
+ val |= BIT(31); // turn clock on
+ writel(val, SUNXI_CCM_BASE + 0x800);
+
+ return n * 24;
+}
+
+/* Set up the PLL and clock gates for the DRAM controller and MBUS clocks. */
+static void mctl_sys_init(const dram_para_t *para, const dram_config_t *config)
+{
+ // assert MBUS reset
+ clrbits_le32(SUNXI_CCM_BASE + 0x540, BIT(30));
+
+ // turn off sdram clock gate, assert sdram reset
+ clrbits_le32(SUNXI_CCM_BASE + 0x80c, 0x10001);
+ clrsetbits_le32(SUNXI_CCM_BASE + 0x800, BIT(31) | BIT(30), BIT(27));
+ udelay(10);
+
+ // set ddr pll clock
+ ccu_set_pll_ddr_clk(0, para, config);
+ udelay(100);
+ dram_disable_all_master();
+
+ // release sdram reset
+ setbits_le32(SUNXI_CCM_BASE + 0x80c, BIT(16));
+
+ // release MBUS reset
+ setbits_le32(SUNXI_CCM_BASE + 0x540, BIT(30));
+ setbits_le32(SUNXI_CCM_BASE + 0x800, BIT(30));
+
+ udelay(5);
+
+ // turn on sdram clock gate
+ setbits_le32(SUNXI_CCM_BASE + 0x80c, BIT(0));
+
+ // turn dram clock gate on, trigger sdr clock update
+ setbits_le32(SUNXI_CCM_BASE + 0x800, BIT(31) | BIT(27));
+ udelay(5);
+
+ // mCTL clock enable
+ writel(0x8000, 0x310300c);
+ udelay(10);
+}
+
+// The main purpose of this routine seems to be to copy an address configuration
+// from the dram_para1 and dram_para2 fields to the PHY configuration registers
+// (0x3102000, 0x3102004).
+//
+static void mctl_com_init(const dram_para_t *para, const dram_config_t *config)
+{
+ uint32_t val, width;
+ unsigned long ptr;
+ int i;
+
+ // purpose ??
+ clrsetbits_le32(0x3102008, 0x3f00, 0x2000);
+
+ // set SDRAM type and word width
+ val = readl(0x3102000) & ~0x00fff000;
+ val |= (para->dram_type & 0x7) << 16; // DRAM type
+ val |= (~config->dram_para2 & 0x1) << 12; // DQ width
+ val |= BIT(22); // ??
+ if (para->dram_type == SUNXI_DRAM_TYPE_LPDDR2 ||
+ para->dram_type == SUNXI_DRAM_TYPE_LPDDR3) {
+ val |= BIT(19); // type 6 and 7 must use 1T
+ } else {
+ if (config->dram_tpr13 & BIT(5))
+ val |= BIT(19);
+ }
+ writel(val, 0x3102000);
+
+ // init rank / bank / row for single/dual or two different ranks
+ if ((config->dram_para2 & BIT(8)) &&
+ ((config->dram_para2 & 0xf000) != 0x1000))
+ width = 32;
+ else
+ width = 16;
+
+ ptr = 0x3102000;
+ for (i = 0; i < width; i += 16) {
+ val = readl(ptr) & 0xfffff000;
+
+ val |= (config->dram_para2 >> 12) & 0x3; // rank
+ val |= ((config->dram_para1 >> (i + 12)) << 2) & 0x4; // bank - 2
+ val |= (((config->dram_para1 >> (i + 4)) - 1) << 4) & 0xff; // row - 1
+
+ // convert from page size to column addr width - 3
+ switch ((config->dram_para1 >> i) & 0xf) {
+ case 8: val |= 0xa00; break;
+ case 4: val |= 0x900; break;
+ case 2: val |= 0x800; break;
+ case 1: val |= 0x700; break;
+ default: val |= 0x600; break;
+ }
+ writel(val, ptr);
+ ptr += 4;
+ }
+
+ // set ODTMAP based on number of ranks in use
+ val = (readl(0x3102000) & 0x1) ? 0x303 : 0x201;
+ writel(val, 0x3103120);
+
+ // set mctl reg 3c4 to zero when using half DQ
+ if (config->dram_para2 & BIT(0))
+ writel(0, 0x31033c4);
+
+ // purpose ??
+ if (para->dram_tpr4) {
+ setbits_le32(0x3102000, (para->dram_tpr4 & 0x3) << 25);
+ setbits_le32(0x3102004, (para->dram_tpr4 & 0x7fc) << 10);
+ }
+}
+
+static const uint8_t ac_remapping_tables[][22] = {
+ [0] = { 0 },
+ [1] = { 1, 9, 3, 7, 8, 18, 4, 13, 5, 6, 10,
+ 2, 14, 12, 0, 0, 21, 17, 20, 19, 11, 22 },
+ [2] = { 4, 9, 3, 7, 8, 18, 1, 13, 2, 6, 10,
+ 5, 14, 12, 0, 0, 21, 17, 20, 19, 11, 22 },
+ [3] = { 1, 7, 8, 12, 10, 18, 4, 13, 5, 6, 3,
+ 2, 9, 0, 0, 0, 21, 17, 20, 19, 11, 22 },
+ [4] = { 4, 12, 10, 7, 8, 18, 1, 13, 2, 6, 3,
+ 5, 9, 0, 0, 0, 21, 17, 20, 19, 11, 22 },
+ [5] = { 13, 2, 7, 9, 12, 19, 5, 1, 6, 3, 4,
+ 8, 10, 0, 0, 0, 21, 22, 18, 17, 11, 20 },
+ [6] = { 3, 10, 7, 13, 9, 11, 1, 2, 4, 6, 8,
+ 5, 12, 0, 0, 0, 20, 1, 0, 21, 22, 17 },
+ [7] = { 3, 2, 4, 7, 9, 1, 17, 12, 18, 14, 13,
+ 8, 15, 6, 10, 5, 19, 22, 16, 21, 20, 11 },
+};
+
+/*
+ * This routine chooses one of several remapping tables for 22 lines.
+ * It is unclear which lines are being remapped. It seems to pick
+ * table cfg7 for the Nezha board.
+ */
+static void mctl_phy_ac_remapping(const dram_para_t *para,
+ const dram_config_t *config)
+{
+ const uint8_t *cfg;
+ uint32_t fuse, val;
+
+ /*
+ * It is unclear whether the LPDDRx types don't need any remapping,
+ * or whether the original code just didn't provide tables.
+ */
+ if (para->dram_type != SUNXI_DRAM_TYPE_DDR2 &&
+ para->dram_type != SUNXI_DRAM_TYPE_DDR3)
+ return;
+
+ fuse = (readl(SUNXI_SID_BASE + 0x28) & 0xf00) >> 8;
+ debug("DDR efuse: 0x%x\n", fuse);
+
+ if (para->dram_type == SUNXI_DRAM_TYPE_DDR2) {
+ if (fuse == 15)
+ return;
+ cfg = ac_remapping_tables[6];
+ } else {
+ if (config->dram_tpr13 & 0xc0000) {
+ cfg = ac_remapping_tables[7];
+ } else {
+ switch (fuse) {
+ case 8: cfg = ac_remapping_tables[2]; break;
+ case 9: cfg = ac_remapping_tables[3]; break;
+ case 10: cfg = ac_remapping_tables[5]; break;
+ case 11: cfg = ac_remapping_tables[4]; break;
+ default:
+ case 12: cfg = ac_remapping_tables[1]; break;
+ case 13:
+ case 14: cfg = ac_remapping_tables[0]; break;
+ }
+ }
+ }
+
+ val = (cfg[4] << 25) | (cfg[3] << 20) | (cfg[2] << 15) |
+ (cfg[1] << 10) | (cfg[0] << 5);
+ writel(val, 0x3102500);
+
+ val = (cfg[10] << 25) | (cfg[9] << 20) | (cfg[8] << 15) |
+ (cfg[ 7] << 10) | (cfg[6] << 5) | cfg[5];
+ writel(val, 0x3102504);
+
+ val = (cfg[15] << 20) | (cfg[14] << 15) | (cfg[13] << 10) |
+ (cfg[12] << 5) | cfg[11];
+ writel(val, 0x3102508);
+
+ val = (cfg[21] << 25) | (cfg[20] << 20) | (cfg[19] << 15) |
+ (cfg[18] << 10) | (cfg[17] << 5) | cfg[16];
+ writel(val, 0x310250c);
+
+ val = (cfg[4] << 25) | (cfg[3] << 20) | (cfg[2] << 15) |
+ (cfg[1] << 10) | (cfg[0] << 5) | 1;
+ writel(val, 0x3102500);
+}
+
+// Init the controller channel. The key part is placing commands in the main
+// command register (PIR, 0x3103000) and checking command status (PGSR0, 0x3103010).
+//
+static unsigned int mctl_channel_init(unsigned int ch_index,
+ const dram_para_t *para,
+ const dram_config_t *config)
+{
+ unsigned int val, dqs_gating_mode;
+
+ dqs_gating_mode = (config->dram_tpr13 & 0xc) >> 2;
+
+ // set DDR clock to half of CPU clock
+ clrsetbits_le32(0x310200c, 0xfff, (para->dram_clk / 2) - 1);
+
+ // MRCTRL0 nibble 3 undocumented
+ clrsetbits_le32(0x3103108, 0xf00, 0x300);
+
+ if (para->dram_odt_en)
+ val = 0;
+ else
+ val = BIT(5);
+
+ // DX0GCR0
+ if (para->dram_clk > 672)
+ clrsetbits_le32(0x3103344, 0xf63e, val);
+ else
+ clrsetbits_le32(0x3103344, 0xf03e, val);
+
+ // DX1GCR0
+ if (para->dram_clk > 672) {
+ setbits_le32(0x3103344, 0x400);
+ clrsetbits_le32(0x31033c4, 0xf63e, val);
+ } else {
+ clrsetbits_le32(0x31033c4, 0xf03e, val);
+ }
+
+ // 0x3103208 undocumented
+ setbits_le32(0x3103208, BIT(1));
+
+ eye_delay_compensation(para);
+
+ // set PLL SSCG ?
+ val = readl(0x3103108);
+ if (dqs_gating_mode == 1) {
+ clrsetbits_le32(0x3103108, 0xc0, 0);
+ clrbits_le32(0x31030bc, 0x107);
+ } else if (dqs_gating_mode == 2) {
+ clrsetbits_le32(0x3103108, 0xc0, 0x80);
+
+ clrsetbits_le32(0x31030bc, 0x107,
+ (((config->dram_tpr13 >> 16) & 0x1f) - 2) | 0x100);
+ clrsetbits_le32(0x310311c, BIT(31), BIT(27));
+ } else {
+ clrbits_le32(0x3103108, 0x40);
+ udelay(10);
+ setbits_le32(0x3103108, 0xc0);
+ }
+
+ if (para->dram_type == SUNXI_DRAM_TYPE_LPDDR2 ||
+ para->dram_type == SUNXI_DRAM_TYPE_LPDDR3) {
+ if (dqs_gating_mode == 1)
+ clrsetbits_le32(0x310311c, 0x080000c0, 0x80000000);
+ else
+ clrsetbits_le32(0x310311c, 0x77000000, 0x22000000);
+ }
+
+ clrsetbits_le32(0x31030c0, 0x0fffffff,
+ (config->dram_para2 & BIT(12)) ? 0x03000001 : 0x01000007);
+
+ if (readl(0x70005d4) & BIT(16)) {
+ clrbits_le32(0x7010250, 0x2);
+ udelay(10);
+ }
+
+ // Set ZQ config
+ clrsetbits_le32(0x3103140, 0x3ffffff,
+ (para->dram_zq & 0x00ffffff) | BIT(25));
+
+ // Initialise DRAM controller
+ if (dqs_gating_mode == 1) {
+ //writel(0x52, 0x3103000); // prep PHY reset + PLL init + z-cal
+ writel(0x53, 0x3103000); // Go
+
+ while ((readl(0x3103010) & 0x1) == 0) {
+ } // wait for IDONE
+ udelay(10);
+
+ // 0x520 = prep DQS gating + DRAM init + d-cal
+ if (para->dram_type == SUNXI_DRAM_TYPE_DDR3)
+ writel(0x5a0, 0x3103000); // + DRAM reset
+ else
+ writel(0x520, 0x3103000);
+ } else {
+ if ((readl(0x70005d4) & (1 << 16)) == 0) {
+ // prep DRAM init + PHY reset + d-cal + PLL init + z-cal
+ if (para->dram_type == SUNXI_DRAM_TYPE_DDR3)
+ writel(0x1f2, 0x3103000); // + DRAM reset
+ else
+ writel(0x172, 0x3103000);
+ } else {
+ // prep PHY reset + d-cal + z-cal
+ writel(0x62, 0x3103000);
+ }
+ }
+
+ setbits_le32(0x3103000, 0x1); // GO
+
+ udelay(10);
+ while ((readl(0x3103010) & 0x1) == 0) {
+ } // wait for IDONE
+
+ if (readl(0x70005d4) & BIT(16)) {
+ clrsetbits_le32(0x310310c, 0x06000000, 0x04000000);
+ udelay(10);
+
+ setbits_le32(0x3103004, 0x1);
+
+ while ((readl(0x3103018) & 0x7) != 0x3) {
+ }
+
+ clrbits_le32(0x7010250, 0x1);
+ udelay(10);
+
+ clrbits_le32(0x3103004, 0x1);
+
+ while ((readl(0x3103018) & 0x7) != 0x1) {
+ }
+
+ udelay(15);
+
+ if (dqs_gating_mode == 1) {
+ clrbits_le32(0x3103108, 0xc0);
+ clrsetbits_le32(0x310310c, 0x06000000, 0x02000000);
+ udelay(1);
+ writel(0x401, 0x3103000);
+
+ while ((readl(0x3103010) & 0x1) == 0) {
+ }
+ }
+ }
+
+ // Check for training error
+ if (readl(0x3103010) & BIT(20)) {
+ printf("ZQ calibration error, check external 240 ohm resistor\n");
+ return 0;
+ }
+
+ // STATR = Zynq STAT? Wait for status 'normal'?
+ while ((readl(0x3103018) & 0x1) == 0) {
+ }
+
+ setbits_le32(0x310308c, BIT(31));
+ udelay(10);
+ clrbits_le32(0x310308c, BIT(31));
+ udelay(10);
+ setbits_le32(0x3102014, BIT(31));
+ udelay(10);
+
+ clrbits_le32(0x310310c, 0x06000000);
+
+ if (dqs_gating_mode == 1)
+ clrsetbits_le32(0x310311c, 0xc0, 0x40);
+
+ return 1;
+}
+
+static unsigned int calculate_rank_size(uint32_t regval)
+{
+ unsigned int bits;
+
+ bits = (regval >> 8) & 0xf; /* page size - 3 */
+ bits += (regval >> 4) & 0xf; /* row width - 1 */
+ bits += (regval >> 2) & 0x3; /* bank count - 2 */
+ bits -= 14; /* 1MB = 20 bits, minus above 6 = 14 */
+
+ return 1U << bits;
+}
+
+/*
+ * The below routine reads the dram config registers and extracts
+ * the number of address bits in each rank available. It then calculates
+ * total memory size in MB.
+ */
+static unsigned int DRAMC_get_dram_size(void)
+{
+ uint32_t val;
+ unsigned int size;
+
+ val = readl(0x3102000); /* MC_WORK_MODE0 */
+ size = calculate_rank_size(val);
+ if ((val & 0x3) == 0) /* single rank? */
+ return size;
+
+ val = readl(0x3102004); /* MC_WORK_MODE1 */
+ if ((val & 0x3) == 0) /* two identical ranks? */
+ return size * 2;
+
+ /* add sizes of both ranks */
+ return size + calculate_rank_size(val);
+}
+
+/*
+ * The below routine reads the command status register to extract
+ * DQ width and rank count. This follows the DQS training command in
+ * channel_init. If error bit 22 is reset, we have two ranks and full DQ.
+ * If there was an error, figure out whether it was half DQ, single rank,
+ * or both. Set bit 12 and 0 in dram_para2 with the results.
+ */
+static int dqs_gate_detect(dram_config_t *config)
+{
+ uint32_t dx0, dx1;
+
+ if ((readl(0x3103010) & BIT(22)) == 0) {
+ config->dram_para2 = (config->dram_para2 & ~0xf) | BIT(12);
+ debug("dual rank and full DQ\n");
+
+ return 1;
+ }
+
+ dx0 = (readl(0x3103348) & 0x3000000) >> 24;
+ if (dx0 == 0) {
+ config->dram_para2 = (config->dram_para2 & ~0xf) | 0x1001;
+ debug("dual rank and half DQ\n");
+
+ return 1;
+ }
+
+ if (dx0 == 2) {
+ dx1 = (readl(0x31033c8) & 0x3000000) >> 24;
+ if (dx1 == 2) {
+ config->dram_para2 = config->dram_para2 & ~0xf00f;
+ debug("single rank and full DQ\n");
+ } else {
+ config->dram_para2 = (config->dram_para2 & ~0xf00f) | BIT(0);
+ debug("single rank and half DQ\n");
+ }
+
+ return 1;
+ }
+
+ if ((config->dram_tpr13 & BIT(29)) == 0)
+ return 0;
+
+ debug("DX0 state: %d\n", dx0);
+ debug("DX1 state: %d\n", dx1);
+
+ return 0;
+}
+
+static int dramc_simple_wr_test(unsigned int mem_mb, int len)
+{
+ unsigned int offs = (mem_mb / 2) << 18; // half of memory size
+ unsigned int patt1 = 0x01234567;
+ unsigned int patt2 = 0xfedcba98;
+ unsigned int *addr, v1, v2, i;
+
+ addr = (unsigned int *)CFG_SYS_SDRAM_BASE;
+ for (i = 0; i != len; i++, addr++) {
+ writel(patt1 + i, (unsigned long)addr);
+ writel(patt2 + i, (unsigned long)(addr + offs));
+ }
+
+ addr = (unsigned int *)CFG_SYS_SDRAM_BASE;
+ for (i = 0; i != len; i++) {
+ v1 = readl((unsigned long)(addr + i));
+ v2 = patt1 + i;
+ if (v1 != v2) {
+ printf("DRAM: simple test FAIL\n");
+ printf("%x != %x at address %p\n", v1, v2, addr + i);
+ return 1;
+ }
+ v1 = readl((unsigned long)(addr + offs + i));
+ v2 = patt2 + i;
+ if (v1 != v2) {
+ printf("DRAM: simple test FAIL\n");
+ printf("%x != %x at address %p\n", v1, v2, addr + offs + i);
+ return 1;
+ }
+ }
+
+ debug("DRAM: simple test OK\n");
+ return 0;
+}
+
+// Set the Vref mode for the controller
+//
+static void mctl_vrefzq_init(const dram_para_t *para, const dram_config_t *config)
+{
+ if (config->dram_tpr13 & BIT(17))
+ return;
+
+ clrsetbits_le32(0x3103110, 0x7f7f7f7f, para->dram_tpr5);
+
+ // IOCVR1
+ if ((config->dram_tpr13 & BIT(16)) == 0)
+ clrsetbits_le32(0x3103114, 0x7f, para->dram_tpr6 & 0x7f);
+}
+
+// Perform an init of the controller. This is actually done 3 times. The first
+// time to establish the number of ranks and DQ width. The second time to
+// establish the actual ram size. The third time is final one, with the final
+// settings.
+//
+static int mctl_core_init(const dram_para_t *para, const dram_config_t *config)
+{
+ mctl_sys_init(para, config);
+
+ mctl_vrefzq_init(para, config);
+
+ mctl_com_init(para, config);
+
+ mctl_phy_ac_remapping(para, config);
+
+ mctl_set_timing_params(para, config);
+
+ return mctl_channel_init(0, para, config);
+}
+
+/*
+ * This routine sizes a DRAM device by cycling through address lines and
+ * figuring out if they are connected to a real address line, or if the
+ * address is a mirror.
+ * First the column and bank bit allocations are set to low values (2 and 9
+ * address lines). Then a maximum allocation (16 lines) is set for rows and
+ * this is tested.
+ * Next the BA2 line is checked. This seems to be placed above the column,
+ * BA0-1 and row addresses. Finally, the column address is allocated 13 lines
+ * and these are tested. The results are placed in dram_para1 and dram_para2.
+ */
+
+static uint32_t get_payload(bool odd, unsigned long int ptr)
+{
+ if (odd)
+ return (uint32_t)ptr;
+ else
+ return ~((uint32_t)ptr);
+}
+
+static int auto_scan_dram_size(const dram_para_t *para, dram_config_t *config)
+{
+ unsigned int rval, i, j, rank, maxrank, offs;
+ unsigned int shft;
+ unsigned long ptr, mc_work_mode, chk;
+
+ if (mctl_core_init(para, config) == 0) {
+ printf("DRAM initialisation error : 0\n");
+ return 0;
+ }
+
+ maxrank = (config->dram_para2 & 0xf000) ? 2 : 1;
+ mc_work_mode = 0x3102000;
+ offs = 0;
+
+ /* write test pattern */
+ for (i = 0, ptr = CFG_SYS_SDRAM_BASE; i < 64; i++, ptr += 4)
+ writel(get_payload(i & 0x1, ptr), ptr);
+
+ for (rank = 0; rank < maxrank;) {
+ /* set row mode */
+ clrsetbits_le32(mc_work_mode, 0xf0c, 0x6f0);
+ udelay(1);
+
+ // Scan per address line, until address wraps (i.e. see shadow)
+ for (i = 11; i < 17; i++) {
+ chk = CFG_SYS_SDRAM_BASE + (1U << (i + 11));
+ ptr = CFG_SYS_SDRAM_BASE;
+ for (j = 0; j < 64; j++) {
+ if (readl(chk) != get_payload(j & 0x1, ptr))
+ break;
+ ptr += 4;
+ chk += 4;
+ }
+ if (j == 64)
+ break;
+ }
+ if (i > 16)
+ i = 16;
+ debug("rank %d row = %d\n", rank, i);
+
+ /* Store rows in para 1 */
+ shft = offs + 4;
+ rval = config->dram_para1;
+ rval &= ~(0xff << shft);
+ rval |= i << shft;
+ config->dram_para1 = rval;
+
+ if (rank == 1) /* Set bank mode for rank0 */
+ clrsetbits_le32(0x3102000, 0xffc, 0x6a4);
+
+ /* Set bank mode for current rank */
+ clrsetbits_le32(mc_work_mode, 0xffc, 0x6a4);
+ udelay(1);
+
+ // Test if bit A23 is BA2 or mirror XXX A22?
+ chk = CFG_SYS_SDRAM_BASE + (1U << 22);
+ ptr = CFG_SYS_SDRAM_BASE;
+ for (i = 0, j = 0; i < 64; i++) {
+ if (readl(chk) != get_payload(i & 1, ptr)) {
+ j = 1;
+ break;
+ }
+ ptr += 4;
+ chk += 4;
+ }
+
+ debug("rank %d bank = %d\n", rank, (j + 1) << 2); /* 4 or 8 */
+
+ /* Store banks in para 1 */
+ shft = 12 + offs;
+ rval = config->dram_para1;
+ rval &= ~(0xf << shft);
+ rval |= j << shft;
+ config->dram_para1 = rval;
+
+ if (rank == 1) /* Set page mode for rank0 */
+ clrsetbits_le32(0x3102000, 0xffc, 0xaa0);
+
+ /* Set page mode for current rank */
+ clrsetbits_le32(mc_work_mode, 0xffc, 0xaa0);
+ udelay(1);
+
+ // Scan per address line, until address wraps (i.e. see shadow)
+ for (i = 9; i < 14; i++) {
+ chk = CFG_SYS_SDRAM_BASE + (1U << i);
+ ptr = CFG_SYS_SDRAM_BASE;
+ for (j = 0; j < 64; j++) {
+ if (readl(chk) != get_payload(j & 1, ptr))
+ break;
+ ptr += 4;
+ chk += 4;
+ }
+ if (j == 64)
+ break;
+ }
+ if (i > 13)
+ i = 13;
+
+ unsigned int pgsize = (i == 9) ? 0 : (1 << (i - 10));
+ debug("rank %d page size = %d KB\n", rank, pgsize);
+
+ /* Store page size */
+ shft = offs;
+ rval = config->dram_para1;
+ rval &= ~(0xf << shft);
+ rval |= pgsize << shft;
+ config->dram_para1 = rval;
+
+ // Move to next rank
+ rank++;
+ if (rank != maxrank) {
+ if (rank == 1) {
+ /* MC_WORK_MODE */
+ clrsetbits_le32(0x3202000, 0xffc, 0x6f0);
+
+ /* MC_WORK_MODE2 */
+ clrsetbits_le32(0x3202004, 0xffc, 0x6f0);
+ }
+ /* store rank1 config in upper half of para1 */
+ offs += 16;
+ mc_work_mode += 4; /* move to MC_WORK_MODE2 */
+ }
+ }
+ if (maxrank == 2) {
+ config->dram_para2 &= 0xfffff0ff;
+ /* note: rval is equal to para->dram_para1 here */
+ if ((rval & 0xffff) == (rval >> 16)) {
+ debug("rank1 config same as rank0\n");
+ } else {
+ config->dram_para2 |= BIT(8);
+ debug("rank1 config different from rank0\n");
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * This routine sets up parameters with dqs_gating_mode equal to 1 and two
+ * ranks enabled. It then configures the core and tests for 1 or 2 ranks and
+ * full or half DQ width. It then resets the parameters to the original values.
+ * dram_para2 is updated with the rank and width findings.
+ */
+static int auto_scan_dram_rank_width(const dram_para_t *para,
+ dram_config_t *config)
+{
+ unsigned int s1 = config->dram_tpr13;
+ unsigned int s2 = config->dram_para1;
+
+ config->dram_para1 = 0x00b000b0;
+ config->dram_para2 = (config->dram_para2 & ~0xf) | BIT(12);
+
+ /* set DQS probe mode */
+ config->dram_tpr13 = (config->dram_tpr13 & ~0x8) | BIT(2) | BIT(0);
+
+ mctl_core_init(para, config);
+
+ if (readl(0x3103010) & BIT(20))
+ return 0;
+
+ if (dqs_gate_detect(config) == 0)
+ return 0;
+
+ config->dram_tpr13 = s1;
+ config->dram_para1 = s2;
+
+ return 1;
+}
+
+/*
+ * This routine determines the SDRAM topology. It first establishes the number
+ * of ranks and the DQ width. Then it scans the SDRAM address lines to establish
+ * the size of each rank. It then updates dram_tpr13 to reflect that the sizes
+ * are now known: a re-init will not repeat the autoscan.
+ */
+static int auto_scan_dram_config(const dram_para_t *para,
+ dram_config_t *config)
+{
+ if (((config->dram_tpr13 & BIT(14)) == 0) &&
+ (auto_scan_dram_rank_width(para, config) == 0)) {
+ printf("ERROR: auto scan dram rank & width failed\n");
+ return 0;
+ }
+
+ if (((config->dram_tpr13 & BIT(0)) == 0) &&
+ (auto_scan_dram_size(para, config) == 0)) {
+ printf("ERROR: auto scan dram size failed\n");
+ return 0;
+ }
+
+ if ((config->dram_tpr13 & BIT(15)) == 0)
+ config->dram_tpr13 |= BIT(14) | BIT(13) | BIT(1) | BIT(0);
+
+ return 1;
+}
+
+static int init_DRAM(int type, const dram_para_t *para)
+{
+ dram_config_t config = {
+ .dram_para1 = 0x000010d2,
+ .dram_para2 = 0,
+ .dram_tpr13 = CONFIG_DRAM_SUNXI_TPR13,
+ };
+ u32 rc, mem_size_mb;
+
+ debug("DRAM BOOT DRIVE INFO: %s\n", "V0.24");
+ debug("DRAM CLK = %d MHz\n", para->dram_clk);
+ debug("DRAM Type = %d (2:DDR2,3:DDR3)\n", para->dram_type);
+ if ((para->dram_odt_en & 0x1) == 0)
+ debug("DRAMC read ODT off\n");
+ else
+ debug("DRAMC ZQ value: 0x%x\n", para->dram_zq);
+
+ /* Test ZQ status */
+ if (config.dram_tpr13 & BIT(16)) {
+ debug("DRAM only have internal ZQ\n");
+ setbits_le32(0x3000160, BIT(8));
+ writel(0, 0x3000168);
+ udelay(10);
+ } else {
+ clrbits_le32(0x3000160, 0x3);
+ writel(config.dram_tpr13 & BIT(16), 0x7010254);
+ udelay(10);
+ clrsetbits_le32(0x3000160, 0x108, BIT(1));
+ udelay(10);
+ setbits_le32(0x3000160, BIT(0));
+ udelay(20);
+ debug("ZQ value = 0x%x\n", readl(0x300016c));
+ }
+
+ dram_voltage_set(para);
+
+ /* Set SDRAM controller auto config */
+ if ((config.dram_tpr13 & BIT(0)) == 0) {
+ if (auto_scan_dram_config(para, &config) == 0) {
+ printf("auto_scan_dram_config() FAILED\n");
+ return 0;
+ }
+ }
+
+ /* report ODT */
+ rc = para->dram_mr1;
+ if ((rc & 0x44) == 0)
+ debug("DRAM ODT off\n");
+ else
+ debug("DRAM ODT value: 0x%x\n", rc);
+
+ /* Init core, final run */
+ if (mctl_core_init(para, &config) == 0) {
+ printf("DRAM initialisation error: 1\n");
+ return 0;
+ }
+
+ /* Get SDRAM size */
+ /* TODO: who ever puts a negative number in the top half? */
+ rc = config.dram_para2;
+ if (rc & BIT(31)) {
+ rc = (rc >> 16) & ~BIT(15);
+ } else {
+ rc = DRAMC_get_dram_size();
+ debug("DRAM: size = %dMB\n", rc);
+ config.dram_para2 = (config.dram_para2 & 0xffffU) | rc << 16;
+ }
+ mem_size_mb = rc;
+
+ /* Purpose ?? */
+ if (config.dram_tpr13 & BIT(30)) {
+ rc = para->dram_tpr8;
+ if (rc == 0)
+ rc = 0x10000200;
+ writel(rc, 0x31030a0);
+ writel(0x40a, 0x310309c);
+ setbits_le32(0x3103004, BIT(0));
+ debug("Enable Auto SR\n");
+ } else {
+ clrbits_le32(0x31030a0, 0xffff);
+ clrbits_le32(0x3103004, 0x1);
+ }
+
+ /* Purpose ?? */
+ if (config.dram_tpr13 & BIT(9)) {
+ clrsetbits_le32(0x3103100, 0xf000, 0x5000);
+ } else {
+ if (para->dram_type != SUNXI_DRAM_TYPE_LPDDR2)
+ clrbits_le32(0x3103100, 0xf000);
+ }
+
+ setbits_le32(0x3103140, BIT(31));
+
+ /* CHECK: is that really writing to a different register? */
+ if (config.dram_tpr13 & BIT(8))
+ writel(readl(0x3103140) | 0x300, 0x31030b8);
+
+ if (config.dram_tpr13 & BIT(16))
+ clrbits_le32(0x3103108, BIT(13));
+ else
+ setbits_le32(0x3103108, BIT(13));
+
+ /* Purpose ?? */
+ if (para->dram_type == SUNXI_DRAM_TYPE_LPDDR3)
+ clrsetbits_le32(0x310307c, 0xf0000, 0x1000);
+
+ dram_enable_all_master();
+ if (config.dram_tpr13 & BIT(28)) {
+ if ((readl(0x70005d4) & BIT(16)) ||
+ dramc_simple_wr_test(mem_size_mb, 4096))
+ return 0;
+ }
+
+ return mem_size_mb;
+}
+
+static const dram_para_t para = {
+ .dram_clk = CONFIG_DRAM_CLK,
+ .dram_type = CONFIG_SUNXI_DRAM_TYPE,
+ .dram_zq = CONFIG_DRAM_ZQ,
+ .dram_odt_en = CONFIG_DRAM_SUNXI_ODT_EN,
+ .dram_mr0 = 0x1c70,
+ .dram_mr1 = 0x42,
+ .dram_mr2 = 0x18,
+ .dram_mr3 = 0,
+ .dram_tpr0 = 0x004a2195,
+ .dram_tpr1 = 0x02423190,
+ .dram_tpr2 = 0x0008b061,
+ .dram_tpr3 = 0xb4787896, // unused
+ .dram_tpr4 = 0,
+ .dram_tpr5 = 0x48484848,
+ .dram_tpr6 = 0x00000048,
+ .dram_tpr7 = 0x1620121e, // unused
+ .dram_tpr8 = 0,
+ .dram_tpr9 = 0, // clock?
+ .dram_tpr10 = 0,
+ .dram_tpr11 = CONFIG_DRAM_SUNXI_TPR11,
+ .dram_tpr12 = CONFIG_DRAM_SUNXI_TPR12,
+};
+
+unsigned long sunxi_dram_init(void)
+{
+ return init_DRAM(0, &para) * 1024UL * 1024;
+};
+
+#ifdef CONFIG_RAM /* using the driver model */
+struct sunxi_ram_priv {
+ size_t size;
+};
+
+static int sunxi_ram_probe(struct udevice *dev)
+{
+ struct sunxi_ram_priv *priv = dev_get_priv(dev);
+ unsigned long dram_size;
+
+ debug("%s: %s: probing\n", __func__, dev->name);
+
+ dram_size = sunxi_dram_init();
+ if (!dram_size) {
+ printf("DRAM init failed\n");
+ return -ENODEV;
+ }
+
+ priv->size = dram_size;
+
+ return 0;
+}
+
+static int sunxi_ram_get_info(struct udevice *dev, struct ram_info *info)
+{
+ struct sunxi_ram_priv *priv = dev_get_priv(dev);
+
+ debug("%s: %s: getting info\n", __func__, dev->name);
+
+ info->base = CFG_SYS_SDRAM_BASE;
+ info->size = priv->size;
+
+ return 0;
+}
+
+static struct ram_ops sunxi_ram_ops = {
+ .get_info = sunxi_ram_get_info,
+};
+
+static const struct udevice_id sunxi_ram_ids[] = {
+ { .compatible = "allwinner,sun20i-d1-mbus" },
+ { }
+};
+
+U_BOOT_DRIVER(sunxi_ram) = {
+ .name = "sunxi_ram",
+ .id = UCLASS_RAM,
+ .of_match = sunxi_ram_ids,
+ .ops = &sunxi_ram_ops,
+ .probe = sunxi_ram_probe,
+ .priv_auto = sizeof(struct sunxi_ram_priv),
+};
+#endif /* CONFIG_RAM (using driver model) */
diff --git a/drivers/ram/sunxi/dram_sun20i_d1.h b/drivers/ram/sunxi/dram_sun20i_d1.h
new file mode 100644
index 00000000000..91383f6cf10
--- /dev/null
+++ b/drivers/ram/sunxi/dram_sun20i_d1.h
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * D1/R528/T113 DRAM controller register and constant defines
+ *
+ * (C) Copyright 2022 Arm Ltd.
+ * Based on H6 and H616 header, which are:
+ * (C) Copyright 2017 Icenowy Zheng <icenowy@aosc.io>
+ * (C) Copyright 2020 Jernej Skrabec <jernej.skrabec@siol.net>
+ *
+ */
+
+#ifndef _SUNXI_DRAM_SUN20I_D1_H
+#define _SUNXI_DRAM_SUN20I_D1_H
+
+enum sunxi_dram_type {
+ SUNXI_DRAM_TYPE_DDR2 = 2,
+ SUNXI_DRAM_TYPE_DDR3 = 3,
+ SUNXI_DRAM_TYPE_LPDDR2 = 6,
+ SUNXI_DRAM_TYPE_LPDDR3 = 7,
+};
+
+/*
+ * This structure contains a mixture of fixed configuration settings,
+ * variables that are used at runtime to communicate settings between
+ * different stages and functions, and unused values.
+ * This is copied from Allwinner's boot0 data structure, which can be
+ * found at offset 0x38 in any boot0 binary. To allow matching up some
+ * board specific settings, this struct is kept compatible, even though
+ * we don't need all members in our code.
+ */
+typedef struct dram_para {
+ /* normal configuration */
+ const u32 dram_clk;
+ const u32 dram_type;
+ const u32 dram_zq;
+ const u32 dram_odt_en;
+
+ /* timing configuration */
+ const u32 dram_mr0;
+ const u32 dram_mr1;
+ const u32 dram_mr2;
+ const u32 dram_mr3;
+ const u32 dram_tpr0; //DRAMTMG0
+ const u32 dram_tpr1; //DRAMTMG1
+ const u32 dram_tpr2; //DRAMTMG2
+ const u32 dram_tpr3; //DRAMTMG3
+ const u32 dram_tpr4; //DRAMTMG4
+ const u32 dram_tpr5; //DRAMTMG5
+ const u32 dram_tpr6; //DRAMTMG8
+ const u32 dram_tpr7;
+ const u32 dram_tpr8;
+ const u32 dram_tpr9;
+ const u32 dram_tpr10;
+ const u32 dram_tpr11;
+ const u32 dram_tpr12;
+} dram_para_t;
+
+typedef struct dram_config {
+ /* control configuration */
+ u32 dram_para1;
+ u32 dram_para2;
+ /* contains a bitfield of DRAM setup settings */
+ u32 dram_tpr13;
+} dram_config_t;
+
+static inline int ns_to_t(int nanoseconds)
+{
+ const unsigned int ctrl_freq = CONFIG_DRAM_CLK / 2;
+
+ return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000);
+}
+
+#endif /* _SUNXI_DRAM_SUN20I_D1_H */
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 27e4a60ff5b..781de530aff 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2015
-# Texas Instruments Incorporated - http://www.ti.com/
+# Texas Instruments Incorporated - https://www.ti.com/
#
menu "Remote Processor drivers"
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index fbe9c172bc0..e09ed1aa4d4 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2015
-# Texas Instruments Incorporated - http://www.ti.com/
+# Texas Instruments Incorporated - https://www.ti.com/
#
obj-$(CONFIG_$(SPL_)REMOTEPROC) += rproc-uclass.o rproc-elf-loader.o
diff --git a/drivers/remoteproc/ipu_rproc.c b/drivers/remoteproc/ipu_rproc.c
index b4a06bc955a..996e658e871 100644
--- a/drivers/remoteproc/ipu_rproc.c
+++ b/drivers/remoteproc/ipu_rproc.c
@@ -2,7 +2,7 @@
/*
* IPU remoteproc driver for various SoCs
*
- * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
* Angela Stegmaier <angelabaker@ti.com>
* Venkateswara Rao Mandela <venkat.mandela@ti.com>
* Keerthy <j-keerthy@ti.com>
diff --git a/drivers/remoteproc/k3_system_controller.c b/drivers/remoteproc/k3_system_controller.c
index e2affe69c67..071de40fbd6 100644
--- a/drivers/remoteproc/k3_system_controller.c
+++ b/drivers/remoteproc/k3_system_controller.c
@@ -2,7 +2,7 @@
/*
* Texas Instruments' K3 System Controller Driver
*
- * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2017-2018 Texas Instruments Incorporated - https://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com>
*/
diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
index 924070a76b5..6ec55e27d9d 100644
--- a/drivers/remoteproc/pru_rproc.c
+++ b/drivers/remoteproc/pru_rproc.c
@@ -2,7 +2,7 @@
/*
* PRU-RTU remoteproc driver for various SoCs
*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
* Keerthy <j-keerthy@ti.com>
*/
diff --git a/drivers/remoteproc/rproc-uclass.c b/drivers/remoteproc/rproc-uclass.c
index ece534c3c0e..28b362c887a 100644
--- a/drivers/remoteproc/rproc-uclass.c
+++ b/drivers/remoteproc/rproc-uclass.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2015
- * Texas Instruments Incorporated - http://www.ti.com/
+ * Texas Instruments Incorporated - https://www.ti.com/
*/
#define LOG_CATEGORY UCLASS_REMOTEPROC
diff --git a/drivers/remoteproc/sandbox_testproc.c b/drivers/remoteproc/sandbox_testproc.c
index d360cf3169f..f76f68ebeb4 100644
--- a/drivers/remoteproc/sandbox_testproc.c
+++ b/drivers/remoteproc/sandbox_testproc.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2015
- * Texas Instruments Incorporated - http://www.ti.com/
+ * Texas Instruments Incorporated - https://www.ti.com/
*/
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <common.h>
diff --git a/drivers/remoteproc/ti_k3_arm64_rproc.c b/drivers/remoteproc/ti_k3_arm64_rproc.c
index 99f11000dfb..767493c1383 100644
--- a/drivers/remoteproc/ti_k3_arm64_rproc.c
+++ b/drivers/remoteproc/ti_k3_arm64_rproc.c
@@ -2,7 +2,7 @@
/*
* Texas Instruments' K3 ARM64 Remoteproc driver
*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com>
*
*/
diff --git a/drivers/remoteproc/ti_k3_dsp_rproc.c b/drivers/remoteproc/ti_k3_dsp_rproc.c
index 1a2e9dd1f58..576de4bb26e 100644
--- a/drivers/remoteproc/ti_k3_dsp_rproc.c
+++ b/drivers/remoteproc/ti_k3_dsp_rproc.c
@@ -2,7 +2,7 @@
/*
* Texas Instruments' K3 DSP Remoteproc driver
*
- * Copyright (C) 2018-2020 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018-2020 Texas Instruments Incorporated - https://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com>
* Suman Anna <s-anna@ti.com>
*/
diff --git a/drivers/remoteproc/ti_power_proc.c b/drivers/remoteproc/ti_power_proc.c
index 6887a3c8541..f55df4a9119 100644
--- a/drivers/remoteproc/ti_power_proc.c
+++ b/drivers/remoteproc/ti_power_proc.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2015-2016
- * Texas Instruments Incorporated - http://www.ti.com/
+ * Texas Instruments Incorporated - https://www.ti.com/
*/
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <common.h>
diff --git a/drivers/remoteproc/ti_sci_proc.h b/drivers/remoteproc/ti_sci_proc.h
index 36351da63fc..167a7143e83 100644
--- a/drivers/remoteproc/ti_sci_proc.h
+++ b/drivers/remoteproc/ti_sci_proc.h
@@ -2,7 +2,7 @@
/*
* Texas Instruments TI-SCI Processor Controller Helper Functions
*
- * Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018-2019 Texas Instruments Incorporated - https://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com>
* Suman Anna <s-anna@ti.com>
*/
diff --git a/drivers/reset/reset-dra7.c b/drivers/reset/reset-dra7.c
index a9589d448dc..05101a94f9b 100644
--- a/drivers/reset/reset-dra7.c
+++ b/drivers/reset/reset-dra7.c
@@ -2,7 +2,7 @@
/*
* Texas Instruments DRA7 reset driver
*
- * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
* Author: Keerthy <j-keerthy@ti.com>
*/
diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c
index 64bc696f137..9d0c8b354f4 100644
--- a/drivers/reset/reset-meson.c
+++ b/drivers/reset/reset-meson.c
@@ -13,18 +13,26 @@
#include <reset-uclass.h>
#include <regmap.h>
#include <linux/bitops.h>
+#include <linux/delay.h>
-#define REG_COUNT 8
#define BITS_PER_REG 32
-#define LEVEL_OFFSET 0x7c
+
+struct meson_reset_drvdata {
+ unsigned int reg_count;
+ unsigned int level_offset;
+};
struct meson_reset_priv {
struct regmap *regmap;
+ struct meson_reset_drvdata *drvdata;
};
static int meson_reset_request(struct reset_ctl *reset_ctl)
{
- if (reset_ctl->id > (REG_COUNT * BITS_PER_REG))
+ struct meson_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+ struct meson_reset_drvdata *data = priv->drvdata;
+
+ if (reset_ctl->id > (data->reg_count * BITS_PER_REG))
return -EINVAL;
return 0;
@@ -33,9 +41,10 @@ static int meson_reset_request(struct reset_ctl *reset_ctl)
static int meson_reset_level(struct reset_ctl *reset_ctl, bool assert)
{
struct meson_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+ struct meson_reset_drvdata *data = priv->drvdata;
uint bank = reset_ctl->id / BITS_PER_REG;
uint offset = reset_ctl->id % BITS_PER_REG;
- uint reg_offset = LEVEL_OFFSET + (bank << 2);
+ uint reg_offset = data->level_offset + (bank << 2);
uint val;
regmap_read(priv->regmap, reg_offset, &val);
@@ -64,15 +73,36 @@ struct reset_ops meson_reset_ops = {
.rst_deassert = meson_reset_deassert,
};
+static const struct meson_reset_drvdata meson_gxbb_data = {
+ .reg_count = 8,
+ .level_offset = 0x7c,
+};
+
+static const struct meson_reset_drvdata meson_a1_data = {
+ .reg_count = 3,
+ .level_offset = 0x40,
+};
+
static const struct udevice_id meson_reset_ids[] = {
- { .compatible = "amlogic,meson-gxbb-reset" },
- { .compatible = "amlogic,meson-axg-reset" },
+ {
+ .compatible = "amlogic,meson-gxbb-reset",
+ .data = (ulong)&meson_gxbb_data,
+ },
+ {
+ .compatible = "amlogic,meson-axg-reset",
+ .data = (ulong)&meson_gxbb_data,
+ },
+ {
+ .compatible = "amlogic,meson-a1-reset",
+ .data = (ulong)&meson_a1_data,
+ },
{ }
};
static int meson_reset_probe(struct udevice *dev)
{
struct meson_reset_priv *priv = dev_get_priv(dev);
+ priv->drvdata = (struct meson_reset_drvdata *)dev_get_driver_data(dev);
return regmap_init_mem(dev_ofnode(dev), &priv->regmap);
}
diff --git a/drivers/reset/reset-scmi.c b/drivers/reset/reset-scmi.c
index 122556162ec..b76711f0a8f 100644
--- a/drivers/reset/reset-scmi.c
+++ b/drivers/reset/reset-scmi.c
@@ -13,17 +13,8 @@
#include <scmi_protocols.h>
#include <asm/types.h>
-/**
- * struct scmi_reset_priv - Private data for SCMI reset controller
- * @channel: Reference to the SCMI channel to use
- */
-struct scmi_reset_priv {
- struct scmi_channel *channel;
-};
-
static int scmi_reset_set_level(struct reset_ctl *rst, bool assert_not_deassert)
{
- struct scmi_reset_priv *priv = dev_get_priv(rst->dev);
struct scmi_rd_reset_in in = {
.domain_id = rst->id,
.flags = assert_not_deassert ? SCMI_RD_RESET_FLAG_ASSERT : 0,
@@ -35,7 +26,7 @@ static int scmi_reset_set_level(struct reset_ctl *rst, bool assert_not_deassert)
in, out);
int ret;
- ret = devm_scmi_process_msg(rst->dev, priv->channel, &msg);
+ ret = devm_scmi_process_msg(rst->dev, &msg);
if (ret)
return ret;
@@ -54,7 +45,6 @@ static int scmi_reset_deassert(struct reset_ctl *rst)
static int scmi_reset_request(struct reset_ctl *rst)
{
- struct scmi_reset_priv *priv = dev_get_priv(rst->dev);
struct scmi_rd_attr_in in = {
.domain_id = rst->id,
};
@@ -68,7 +58,7 @@ static int scmi_reset_request(struct reset_ctl *rst)
* We don't really care about the attribute, just check
* the reset domain exists.
*/
- ret = devm_scmi_process_msg(rst->dev, priv->channel, &msg);
+ ret = devm_scmi_process_msg(rst->dev, &msg);
if (ret)
return ret;
@@ -83,9 +73,7 @@ static const struct reset_ops scmi_reset_domain_ops = {
static int scmi_reset_probe(struct udevice *dev)
{
- struct scmi_reset_priv *priv = dev_get_priv(dev);
-
- return devm_scmi_of_get_channel(dev, &priv->channel);
+ return devm_scmi_of_get_channel(dev);
}
U_BOOT_DRIVER(scmi_reset_domain) = {
@@ -93,5 +81,4 @@ U_BOOT_DRIVER(scmi_reset_domain) = {
.id = UCLASS_RESET,
.ops = &scmi_reset_domain_ops,
.probe = scmi_reset_probe,
- .priv_auto = sizeof(struct scmi_reset_priv *),
};
diff --git a/drivers/reset/reset-ti-sci.c b/drivers/reset/reset-ti-sci.c
index f35332767b2..fd654a08f13 100644
--- a/drivers/reset/reset-ti-sci.c
+++ b/drivers/reset/reset-ti-sci.c
@@ -2,7 +2,7 @@
/*
* Texas Instruments System Control Interface (TI SCI) reset driver
*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
* Andreas Dannenberg <dannenberg@ti.com>
*
* Loosely based on Linux kernel reset-ti-sci.c...
diff --git a/drivers/rng/Kconfig b/drivers/rng/Kconfig
index 24666bff987..a89c8995682 100644
--- a/drivers/rng/Kconfig
+++ b/drivers/rng/Kconfig
@@ -48,6 +48,14 @@ config RNG_OPTEE
accessible to normal world but reserved and used by the OP-TEE
to avoid the weakness of a software PRNG.
+config RNG_RISCV_ZKR
+ bool "RISC-V Zkr random number generator"
+ depends on RISCV_SMODE
+ help
+ This driver provides a Random Number Generator based on the
+ Zkr RISC-V ISA extension which provides an interface to an
+ NIST SP 800-90B or BSI AIS-31 compliant physical entropy source.
+
config RNG_STM32
bool "Enable random number generator for STM32"
depends on ARCH_STM32 || ARCH_STM32MP
@@ -76,6 +84,12 @@ config RNG_SMCCC_TRNG
Enable random number generator for platforms that support Arm
SMCCC TRNG interface.
+config RNG_ARM_RNDR
+ bool "Generic ARMv8.5 RNDR register"
+ depends on DM_RNG && ARM64
+ help
+ Use the ARMv8.5 RNDR register to provide random numbers.
+
config TPM_RNG
bool "Enable random number generator on TPM device"
depends on TPM
@@ -85,4 +99,10 @@ config TPM_RNG
functionality. Enable random number generator on TPM
devices.
+config RNG_JH7110
+ bool "StarFive JH7110 Random Number Generator support"
+ depends on DM_RNG && STARFIVE_JH7110
+ help
+ Enable True Random Number Generator in StarFive JH7110 SoCs.
+
endif
diff --git a/drivers/rng/Makefile b/drivers/rng/Makefile
index 192f911e155..7e64c4cdfc3 100644
--- a/drivers/rng/Makefile
+++ b/drivers/rng/Makefile
@@ -10,7 +10,10 @@ obj-$(CONFIG_RNG_MSM) += msm_rng.o
obj-$(CONFIG_RNG_NPCM) += npcm_rng.o
obj-$(CONFIG_RNG_OPTEE) += optee_rng.o
obj-$(CONFIG_RNG_STM32) += stm32_rng.o
+obj-$(CONFIG_RNG_RISCV_ZKR) += riscv_zkr_rng.o
obj-$(CONFIG_RNG_ROCKCHIP) += rockchip_rng.o
obj-$(CONFIG_RNG_IPROC200) += iproc_rng200.o
obj-$(CONFIG_RNG_SMCCC_TRNG) += smccc_trng.o
+obj-$(CONFIG_RNG_ARM_RNDR) += arm_rndr.o
obj-$(CONFIG_TPM_RNG) += tpm_rng.o
+obj-$(CONFIG_RNG_JH7110) += jh7110_rng.o
diff --git a/drivers/rng/arm_rndr.c b/drivers/rng/arm_rndr.c
new file mode 100644
index 00000000000..55989743eae
--- /dev/null
+++ b/drivers/rng/arm_rndr.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023, Arm Ltd.
+ *
+ * Use the (optional) ARMv8.5 RNDR register to provide random numbers to
+ * U-Boot's UCLASS_RNG users.
+ * Detection is done at runtime using the CPU ID registers.
+ */
+
+#define LOG_CATEGORY UCLASS_RNG
+
+#include <common.h>
+#include <dm.h>
+#include <linux/kernel.h>
+#include <rng.h>
+#include <asm/system.h>
+
+#define DRIVER_NAME "arm-rndr"
+
+static bool cpu_has_rndr(void)
+{
+ uint64_t reg;
+
+ __asm__ volatile("mrs %0, ID_AA64ISAR0_EL1\n" : "=r" (reg));
+ return !!(reg & ID_AA64ISAR0_EL1_RNDR);
+}
+
+/*
+ * The system register name is RNDR, but this isn't widely known among older
+ * toolchains, and also triggers errors because of it being an architecture
+ * extension. Since we check the availability of the register before, it's
+ * fine to use here, though.
+ */
+#define RNDR "S3_3_C2_C4_0"
+
+static uint64_t read_rndr(void)
+{
+ uint64_t reg;
+
+ __asm__ volatile("mrs %0, " RNDR "\n" : "=r" (reg));
+
+ return reg;
+}
+
+static int arm_rndr_read(struct udevice *dev, void *data, size_t len)
+{
+ uint64_t random;
+
+ while (len) {
+ int tocopy = min(sizeof(uint64_t), len);
+
+ random = read_rndr();
+ memcpy(data, &random, tocopy);
+ len -= tocopy;
+ data += tocopy;
+ }
+
+ return 0;
+}
+
+static const struct dm_rng_ops arm_rndr_ops = {
+ .read = arm_rndr_read,
+};
+
+static int arm_rndr_probe(struct udevice *dev)
+{
+ if (!cpu_has_rndr())
+ return -ENODEV;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(arm_rndr) = {
+ .name = DRIVER_NAME,
+ .id = UCLASS_RNG,
+ .ops = &arm_rndr_ops,
+ .probe = arm_rndr_probe,
+};
+
+U_BOOT_DRVINFO(cpu_arm_rndr) = {
+ .name = DRIVER_NAME,
+};
diff --git a/drivers/rng/jh7110_rng.c b/drivers/rng/jh7110_rng.c
new file mode 100644
index 00000000000..eb21afe4e7c
--- /dev/null
+++ b/drivers/rng/jh7110_rng.c
@@ -0,0 +1,274 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * TRNG driver for the StarFive JH7110 SoC
+ *
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <reset.h>
+#include <rng.h>
+#include <asm/io.h>
+#include <linux/iopoll.h>
+
+/* trng register offset */
+#define STARFIVE_CTRL 0x00
+#define STARFIVE_STAT 0x04
+#define STARFIVE_MODE 0x08
+#define STARFIVE_SMODE 0x0C
+#define STARFIVE_IE 0x10
+#define STARFIVE_ISTAT 0x14
+#define STARFIVE_RAND0 0x20
+#define STARFIVE_RAND1 0x24
+#define STARFIVE_RAND2 0x28
+#define STARFIVE_RAND3 0x2C
+#define STARFIVE_RAND4 0x30
+#define STARFIVE_RAND5 0x34
+#define STARFIVE_RAND6 0x38
+#define STARFIVE_RAND7 0x3C
+#define STARFIVE_AUTO_RQSTS 0x60
+#define STARFIVE_AUTO_AGE 0x64
+
+/* CTRL CMD */
+#define STARFIVE_CTRL_EXEC_NOP 0x0
+#define STARFIVE_CTRL_GENE_RANDNUM 0x1
+#define STARFIVE_CTRL_EXEC_RANDRESEED 0x2
+
+/* STAT */
+#define STARFIVE_STAT_NONCE_MODE BIT(2)
+#define STARFIVE_STAT_R256 BIT(3)
+#define STARFIVE_STAT_MISSION_MODE BIT(8)
+#define STARFIVE_STAT_SEEDED BIT(9)
+#define STARFIVE_STAT_LAST_RESEED(x) ((x) << 16)
+#define STARFIVE_STAT_SRVC_RQST BIT(27)
+#define STARFIVE_STAT_RAND_GENERATING BIT(30)
+#define STARFIVE_STAT_RAND_SEEDING BIT(31)
+#define STARFIVE_STAT_RUNNING (STARFIVE_STAT_RAND_GENERATING | \
+ STARFIVE_STAT_RAND_SEEDING)
+
+/* MODE */
+#define STARFIVE_MODE_R256 BIT(3)
+
+/* SMODE */
+#define STARFIVE_SMODE_NONCE_MODE BIT(2)
+#define STARFIVE_SMODE_MISSION_MODE BIT(8)
+#define STARFIVE_SMODE_MAX_REJECTS(x) ((x) << 16)
+
+/* IE */
+#define STARFIVE_IE_RAND_RDY_EN BIT(0)
+#define STARFIVE_IE_SEED_DONE_EN BIT(1)
+#define STARFIVE_IE_LFSR_LOCKUP_EN BIT(4)
+#define STARFIVE_IE_GLBL_EN BIT(31)
+
+#define STARFIVE_IE_ALL (STARFIVE_IE_GLBL_EN | \
+ STARFIVE_IE_RAND_RDY_EN | \
+ STARFIVE_IE_SEED_DONE_EN | \
+ STARFIVE_IE_LFSR_LOCKUP_EN)
+
+/* ISTAT */
+#define STARFIVE_ISTAT_RAND_RDY BIT(0)
+#define STARFIVE_ISTAT_SEED_DONE BIT(1)
+#define STARFIVE_ISTAT_LFSR_LOCKUP BIT(4)
+
+#define STARFIVE_RAND_LEN sizeof(u32)
+
+enum mode {
+ PRNG_128BIT,
+ PRNG_256BIT,
+};
+
+struct starfive_trng_plat {
+ void *base;
+ struct clk *hclk;
+ struct clk *ahb;
+ struct reset_ctl *rst;
+ u32 mode;
+};
+
+static inline int starfive_trng_wait_idle(struct starfive_trng_plat *trng)
+{
+ u32 stat;
+
+ return readl_relaxed_poll_timeout(trng->base + STARFIVE_STAT, stat,
+ !(stat & STARFIVE_STAT_RUNNING),
+ 100000);
+}
+
+static inline void starfive_trng_irq_mask_clear(struct starfive_trng_plat *trng)
+{
+ /* clear register: ISTAT */
+ u32 data = readl(trng->base + STARFIVE_ISTAT);
+
+ writel(data, trng->base + STARFIVE_ISTAT);
+}
+
+static int starfive_trng_cmd(struct starfive_trng_plat *trng, u32 cmd)
+{
+ u32 stat, flg;
+ int ret;
+
+ switch (cmd) {
+ case STARFIVE_CTRL_GENE_RANDNUM:
+ writel(cmd, trng->base + STARFIVE_CTRL);
+ flg = STARFIVE_ISTAT_RAND_RDY;
+ break;
+ case STARFIVE_CTRL_EXEC_RANDRESEED:
+ writel(cmd, trng->base + STARFIVE_CTRL);
+ flg = STARFIVE_ISTAT_SEED_DONE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = readl_relaxed_poll_timeout(trng->base + STARFIVE_ISTAT, stat,
+ (stat & flg), 1000);
+ writel(flg, trng->base + STARFIVE_ISTAT);
+
+ return ret;
+}
+
+static int starfive_trng_read(struct udevice *dev, void *data, size_t len)
+{
+ struct starfive_trng_plat *trng = dev_get_plat(dev);
+ u8 *buffer = data;
+ int iter_mask;
+
+ if (trng->mode == PRNG_256BIT)
+ iter_mask = 7;
+ else
+ iter_mask = 3;
+
+ for (int i = 0; len; ++i, i &= iter_mask) {
+ u32 val;
+ size_t step;
+ int ret;
+
+ if (!i) {
+ ret = starfive_trng_cmd(trng,
+ STARFIVE_CTRL_GENE_RANDNUM);
+ if (ret)
+ return ret;
+ }
+
+ val = readl(trng->base + STARFIVE_RAND0 +
+ (i * STARFIVE_RAND_LEN));
+ step = min_t(size_t, len, STARFIVE_RAND_LEN);
+ memcpy(buffer, &val, step);
+ buffer += step;
+ len -= step;
+ }
+
+ return 0;
+}
+
+static int starfive_trng_init(struct starfive_trng_plat *trng)
+{
+ u32 mode, intr = 0;
+
+ /* setup Auto Request/Age register */
+ writel(0, trng->base + STARFIVE_AUTO_AGE);
+ writel(0, trng->base + STARFIVE_AUTO_RQSTS);
+
+ /* clear register: ISTAT */
+ starfive_trng_irq_mask_clear(trng);
+
+ intr |= STARFIVE_IE_ALL;
+ writel(intr, trng->base + STARFIVE_IE);
+
+ mode = readl(trng->base + STARFIVE_MODE);
+
+ switch (trng->mode) {
+ case PRNG_128BIT:
+ mode &= ~STARFIVE_MODE_R256;
+ break;
+ case PRNG_256BIT:
+ mode |= STARFIVE_MODE_R256;
+ break;
+ default:
+ mode |= STARFIVE_MODE_R256;
+ break;
+ }
+
+ writel(mode, trng->base + STARFIVE_MODE);
+
+ return starfive_trng_cmd(trng, STARFIVE_CTRL_EXEC_RANDRESEED);
+}
+
+static int starfive_trng_probe(struct udevice *dev)
+{
+ struct starfive_trng_plat *pdata = dev_get_plat(dev);
+ int err;
+
+ err = clk_enable(pdata->hclk);
+ if (err)
+ return err;
+
+ err = clk_enable(pdata->ahb);
+ if (err)
+ goto err_ahb;
+
+ err = reset_deassert(pdata->rst);
+ if (err)
+ goto err_reset;
+
+ pdata->mode = PRNG_256BIT;
+
+ err = starfive_trng_init(pdata);
+ if (err)
+ goto err_trng_init;
+
+ return 0;
+
+err_trng_init:
+ reset_assert(pdata->rst);
+err_reset:
+ clk_disable(pdata->ahb);
+err_ahb:
+ clk_disable(pdata->hclk);
+
+ return err;
+}
+
+static int starfive_trng_of_to_plat(struct udevice *dev)
+{
+ struct starfive_trng_plat *pdata = dev_get_plat(dev);
+
+ pdata->base = (void *)dev_read_addr(dev);
+ if (!pdata->base)
+ return -ENODEV;
+
+ pdata->hclk = devm_clk_get(dev, "hclk");
+ if (IS_ERR(pdata->hclk))
+ return -ENODEV;
+
+ pdata->ahb = devm_clk_get(dev, "ahb");
+ if (IS_ERR(pdata->ahb))
+ return -ENODEV;
+
+ pdata->rst = devm_reset_control_get(dev, NULL);
+ if (IS_ERR(pdata->rst))
+ return -ENODEV;
+
+ return 0;
+}
+
+static const struct dm_rng_ops starfive_trng_ops = {
+ .read = starfive_trng_read,
+};
+
+static const struct udevice_id starfive_trng_match[] = {
+ {
+ .compatible = "starfive,jh7110-trng",
+ },
+ {},
+};
+
+U_BOOT_DRIVER(starfive_trng) = {
+ .name = "jh7110-trng",
+ .id = UCLASS_RNG,
+ .of_match = starfive_trng_match,
+ .probe = starfive_trng_probe,
+ .ops = &starfive_trng_ops,
+ .plat_auto = sizeof(struct starfive_trng_plat),
+ .of_to_plat = starfive_trng_of_to_plat,
+};
diff --git a/drivers/rng/meson-rng.c b/drivers/rng/meson-rng.c
index e0a1e8c7e04..fd2988e91b5 100644
--- a/drivers/rng/meson-rng.c
+++ b/drivers/rng/meson-rng.c
@@ -10,10 +10,23 @@
#include <dm.h>
#include <rng.h>
#include <asm/io.h>
+#include <linux/iopoll.h>
+
+#define RNG_DATA 0x00
+#define RNG_S4_DATA 0x08
+#define RNG_S4_CFG 0x00
+
+#define RUN_BIT BIT(0)
+#define SEED_READY_STS_BIT BIT(31)
+
+struct meson_rng_priv {
+ u32 (*read)(fdt_addr_t base);
+};
struct meson_rng_plat {
fdt_addr_t base;
struct clk clk;
+ struct meson_rng_priv *priv;
};
/**
@@ -27,10 +40,11 @@ struct meson_rng_plat {
static int meson_rng_read(struct udevice *dev, void *data, size_t len)
{
struct meson_rng_plat *pdata = dev_get_plat(dev);
+ struct meson_rng_priv *priv = pdata->priv;
char *buffer = (char *)data;
while (len) {
- u32 rand = readl(pdata->base);
+ u32 rand = priv->read(pdata->base);
size_t step;
if (len >= 4)
@@ -44,6 +58,47 @@ static int meson_rng_read(struct udevice *dev, void *data, size_t len)
return 0;
}
+static int meson_rng_wait_status(void __iomem *cfg_addr, int bit)
+{
+ u32 status = 0;
+ int ret;
+
+ ret = readl_relaxed_poll_timeout(cfg_addr,
+ status, !(status & bit),
+ 10000);
+ if (ret)
+ return -EBUSY;
+
+ return 0;
+}
+
+static u32 meson_common_rng_read(fdt_addr_t base)
+{
+ return readl(base);
+}
+
+static u32 meson_s4_rng_read(fdt_addr_t base)
+{
+ void __iomem *cfg_addr = (void *)base + RNG_S4_CFG;
+ int err;
+
+ writel_relaxed(readl_relaxed(cfg_addr) | SEED_READY_STS_BIT, cfg_addr);
+
+ err = meson_rng_wait_status(cfg_addr, SEED_READY_STS_BIT);
+ if (err) {
+ pr_err("Seed isn't ready, try again\n");
+ return err;
+ }
+
+ err = meson_rng_wait_status(cfg_addr, RUN_BIT);
+ if (err) {
+ pr_err("Can't get random number, try again\n");
+ return err;
+ }
+
+ return readl_relaxed(base + RNG_S4_DATA);
+}
+
/**
* meson_rng_probe() - probe rng device
*
@@ -59,6 +114,8 @@ static int meson_rng_probe(struct udevice *dev)
if (err)
return err;
+ pdata->priv = (struct meson_rng_priv *)dev_get_driver_data(dev);
+
return 0;
}
@@ -102,9 +159,22 @@ static const struct dm_rng_ops meson_rng_ops = {
.read = meson_rng_read,
};
+static const struct meson_rng_priv meson_rng_priv = {
+ .read = meson_common_rng_read,
+};
+
+static const struct meson_rng_priv meson_rng_priv_s4 = {
+ .read = meson_s4_rng_read,
+};
+
static const struct udevice_id meson_rng_match[] = {
{
.compatible = "amlogic,meson-rng",
+ .data = (ulong)&meson_rng_priv,
+ },
+ {
+ .compatible = "amlogic,meson-s4-rng",
+ .data = (ulong)&meson_rng_priv_s4,
},
{},
};
diff --git a/drivers/rng/riscv_zkr_rng.c b/drivers/rng/riscv_zkr_rng.c
new file mode 100644
index 00000000000..8c9e111e2e0
--- /dev/null
+++ b/drivers/rng/riscv_zkr_rng.c
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * The RISC-V Zkr extension provides CSR seed which provides access to a
+ * random number generator.
+ */
+
+#define LOG_CATEGORY UCLASS_RNG
+
+#include <dm.h>
+#include <interrupt.h>
+#include <log.h>
+#include <rng.h>
+
+#define DRIVER_NAME "riscv_zkr"
+
+enum opst {
+ /** @BIST: built in self test running */
+ BIST = 0b00,
+ /** @WAIT: sufficient amount of entropy is not yet available */
+ WAIT = 0b01,
+ /** @ES16: 16bits of entropy available */
+ ES16 = 0b10,
+ /** @DEAD: unrecoverable self-test error */
+ DEAD = 0b11,
+};
+
+static unsigned long read_seed(void)
+{
+ unsigned long ret;
+
+ __asm__ __volatile__("csrrw %0, seed, x0" : "=r" (ret) : : "memory");
+
+ return ret;
+}
+
+static int riscv_zkr_read(struct udevice *dev, void *data, size_t len)
+{
+ u8 *ptr = data;
+
+ while (len) {
+ u32 val;
+
+ val = read_seed();
+
+ switch (val >> 30) {
+ case BIST:
+ continue;
+ case WAIT:
+ continue;
+ case ES16:
+ *ptr++ = val & 0xff;
+ if (--len) {
+ *ptr++ = val >> 8;
+ --len;
+ }
+ break;
+ case DEAD:
+ return -ENODEV;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * riscv_zkr_probe() - check if the seed register is available
+ *
+ * If the SBI software has not set mseccfg.sseed=1 or the Zkr
+ * extension is not available this probe function will result
+ * in an exception. Currently we cannot recover from this.
+ *
+ * @dev: RNG device
+ * Return: 0 if successfully probed
+ */
+static int riscv_zkr_probe(struct udevice *dev)
+{
+ struct resume_data resume;
+ int ret;
+ u32 val;
+
+ /* Check if reading seed leads to interrupt */
+ set_resume(&resume);
+ ret = setjmp(resume.jump);
+ if (ret)
+ log_debug("Exception %ld reading seed CSR\n", resume.code);
+ else
+ val = read_seed();
+ set_resume(NULL);
+ if (ret)
+ return -ENODEV;
+
+ do {
+ val = read_seed();
+ val >>= 30;
+ } while (val == BIST || val == WAIT);
+
+ if (val == DEAD)
+ return -ENODEV;
+
+ return 0;
+}
+
+static const struct dm_rng_ops riscv_zkr_ops = {
+ .read = riscv_zkr_read,
+};
+
+U_BOOT_DRIVER(riscv_zkr) = {
+ .name = DRIVER_NAME,
+ .id = UCLASS_RNG,
+ .ops = &riscv_zkr_ops,
+ .probe = riscv_zkr_probe,
+};
+
+U_BOOT_DRVINFO(cpu_riscv_zkr) = {
+ .name = DRIVER_NAME,
+};
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index a8014129d33..7e21c4ae2bb 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1,46 +1,9 @@
config SCSI
- bool "Support SCSI controllers"
+ bool "Support SCSI controllers with driver model"
help
This enables support for SCSI (Small Computer System Interface),
a parallel interface widely used with storage peripherals such as
hard drives and optical drives. The SCSI standards define physical
interfaces as well as protocols for controlling devices and
- tranferring data.
-
-config DM_SCSI
- bool "Support SCSI controllers with driver model"
- help
- This option enables the SCSI (Small Computer System Interface) uclass
- which supports SCSI and SATA HDDs. For every device configuration
- (IDs/LUNs) a block device is created with RAW read/write and
- filesystem support.
-
-if SCSI && !DM_SCSI
-
-config SCSI_AHCI_PLAT
- bool "Platform-specific init of AHCI"
- help
- This enables a way for boards to set up an AHCI device manually, by
- called ahci_init() and providing an ahci_reset() mechanism.
-
- This is deprecated. An AHCI driver should be provided instead.
-
-config SYS_SCSI_MAX_SCSI_ID
- int "Maximum supported SCSI ID"
- default 1
- help
- Sets the maximum number of SCSI IDs to scan when looking for devices.
- IDs from 0 to (this value - 1) are scanned.
-
- This is deprecated and is not needed when BLK is enabled.
-
-config SYS_SCSI_MAX_LUN
- int "Maximum support SCSI LUN"
- default 1
- help
- Sets the maximum number of SCSI Logical Unit Numbers (LUNs) to scan on
- devices. LUNs from 0 to (this value - 1) are scanned.
-
- This is deprecated and is not needed when CONFIG_DM_SCSI is enabled.
-
-endif
+ tranferring data. For every device configuration (IDs/LUNs) a block
+ device is created with RAW read/write and filesystem support.
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index d8d6de59090..628be4c89fb 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -4,25 +4,16 @@
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
ifndef CONFIG_SPL_BUILD
-obj-$(CONFIG_DM_SCSI) += scsi-uclass.o
-obj-$(CONFIG_SCSI) += scsi.o
-
+obj-$(CONFIG_SCSI) += scsi.o scsi-uclass.o
ifdef CONFIG_SCSI
-ifdef CONFIG_DM_SCSI
obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += scsi_bootdev.o
+obj-$(CONFIG_SANDBOX) += sandbox_scsi.o
+obj-$(CONFIG_SANDBOX) += scsi_emul.o
endif
endif
-endif
-
ifdef CONFIG_SPL_BUILD
ifdef CONFIG_SPL_SATA
-obj-$(CONFIG_DM_SCSI) += scsi-uclass.o
-obj-$(CONFIG_SCSI) += scsi.o
+obj-$(CONFIG_SCSI) += scsi.o scsi-uclass.o
endif
endif
-
-ifdef CONFIG_SCSI
-obj-$(CONFIG_SANDBOX) += sandbox_scsi.o
-obj-$(CONFIG_SANDBOX) += scsi_emul.o
-endif
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 7411660d465..79ee400d12f 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -21,38 +21,10 @@
#include <dm/device-internal.h>
#include <dm/uclass-internal.h>
-#if !defined(CONFIG_DM_SCSI)
-# ifdef CFG_SCSI_DEV_LIST
-# define SCSI_DEV_LIST CFG_SCSI_DEV_LIST
-# else
-# ifdef CONFIG_SATA_ULI5288
-
-# define SCSI_VEND_ID 0x10b9
-# define SCSI_DEV_ID 0x5288
-
-# elif !defined(CONFIG_SCSI_AHCI_PLAT)
-# error no scsi device defined
-# endif
-# define SCSI_DEV_LIST {SCSI_VEND_ID, SCSI_DEV_ID}
-# endif
-#endif
-
-#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) && \
- !defined(CONFIG_DM_SCSI)
-const struct pci_device_id scsi_device_list[] = { SCSI_DEV_LIST };
-#endif
static struct scsi_cmd tempccb; /* temporary scsi command buffer */
DEFINE_CACHE_ALIGN_BUFFER(u8, tempbuff, 512); /* temporary data buffer */
-#if !defined(CONFIG_DM_SCSI)
-static int scsi_max_devs; /* number of highest available scsi device */
-
-static int scsi_curr_dev; /* current device */
-
-static struct blk_desc scsi_dev_desc[SCSI_MAX_DEVICE];
-#endif
-
/* almost the maximum amount of the scsi_ext command.. */
#define SCSI_MAX_BLK 0xFFFF
#define SCSI_LBA48_READ 0xFFFFFFF
@@ -107,7 +79,6 @@ static void scsi_setup_inquiry(struct scsi_cmd *pccb)
pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
}
-#ifdef CONFIG_BLK
static void scsi_setup_read_ext(struct scsi_cmd *pccb, lbaint_t start,
unsigned short blocks)
{
@@ -286,59 +257,6 @@ static int scsi_buffer_aligned(struct udevice *dev, struct bounce_buffer *state)
return 1;
}
#endif /* CONFIG_BOUNCE_BUFFER */
-#endif
-
-#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) && \
- !defined(CONFIG_DM_SCSI)
-void scsi_init(void)
-{
- int busdevfunc = -1;
- int i;
- /*
- * Find a device from the list, this driver will support a single
- * controller.
- */
- for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) {
- /* get PCI Device ID */
- struct udevice *dev;
- int ret;
-
- ret = dm_pci_find_device(scsi_device_list[i].vendor,
- scsi_device_list[i].device, 0, &dev);
- if (!ret) {
- busdevfunc = dm_pci_get_bdf(dev);
- break;
- }
- if (busdevfunc != -1)
- break;
- }
-
- if (busdevfunc == -1) {
- printf("Error: SCSI Controller(s) ");
- for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) {
- printf("%04X:%04X ",
- scsi_device_list[i].vendor,
- scsi_device_list[i].device);
- }
- printf("not found\n");
- return;
- }
-#ifdef DEBUG
- else {
- printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n",
- scsi_device_list[i].vendor,
- scsi_device_list[i].device,
- (busdevfunc >> 16) & 0xFF,
- (busdevfunc >> 11) & 0x1F,
- (busdevfunc >> 8) & 0x7);
- }
-#endif
- bootstage_start(BOOTSTAGE_ID_ACCUM_SCSI, "ahci");
- scsi_low_level_init(busdevfunc);
- scsi_scan(true);
- bootstage_accum(BOOTSTAGE_ID_ACCUM_SCSI);
-}
-#endif
/* copy src to dest, skipping leading and trailing blanks
* and null terminate the string
@@ -374,6 +292,7 @@ static int scsi_read_capacity(struct udevice *dev, struct scsi_cmd *pccb,
pccb->cmd[0] = SCSI_RD_CAPAC10;
pccb->cmd[1] = pccb->lun << 5;
pccb->cmdlen = 10;
+ pccb->dma_dir = DMA_FROM_DEVICE;
pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
pccb->datalen = 8;
@@ -450,35 +369,16 @@ static void scsi_setup_test_unit_ready(struct scsi_cmd *pccb)
*/
static void scsi_init_dev_desc_priv(struct blk_desc *dev_desc)
{
+ memset(dev_desc, 0, sizeof(struct blk_desc));
dev_desc->target = 0xff;
dev_desc->lun = 0xff;
dev_desc->log2blksz =
LOG2_INVALID(typeof(dev_desc->log2blksz));
dev_desc->type = DEV_TYPE_UNKNOWN;
- dev_desc->vendor[0] = 0;
- dev_desc->product[0] = 0;
- dev_desc->revision[0] = 0;
- dev_desc->removable = false;
-}
-
-#if !defined(CONFIG_DM_SCSI)
-/**
- * scsi_init_dev_desc - initialize all SCSI specific blk_desc properties
- *
- * @dev_desc: Block device description pointer
- * @devnum: Device number
- */
-static void scsi_init_dev_desc(struct blk_desc *dev_desc, int devnum)
-{
- dev_desc->lba = 0;
- dev_desc->blksz = 0;
- dev_desc->uclass_id = UCLASS_SCSI;
- dev_desc->devnum = devnum;
- dev_desc->part_type = PART_TYPE_UNKNOWN;
-
- scsi_init_dev_desc_priv(dev_desc);
+#if IS_ENABLED(CONFIG_BOUNCE_BUFFER)
+ dev_desc->bb = true;
+#endif /* CONFIG_BOUNCE_BUFFER */
}
-#endif
/**
* scsi_detect_dev - Detect scsi device
@@ -538,6 +438,7 @@ static int scsi_detect_dev(struct udevice *dev, int target, int lun,
for (count = 0; count < 3; count++) {
pccb->datalen = 0;
+ pccb->dma_dir = DMA_NONE;
scsi_setup_test_unit_ready(pccb);
err = scsi_exec(dev, pccb);
if (!err)
@@ -567,7 +468,6 @@ removable:
* (re)-scan the scsi bus and reports scsi device info
* to the user if mode = 1
*/
-#if defined(CONFIG_DM_SCSI)
static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose)
{
int ret;
@@ -606,6 +506,7 @@ static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose)
bdesc->lun = lun;
bdesc->removable = bd.removable;
bdesc->type = bd.type;
+ bdesc->bb = bd.bb;
memcpy(&bdesc->vendor, &bd.vendor, sizeof(bd.vendor));
memcpy(&bdesc->product, &bd.product, sizeof(bd.product));
memcpy(&bdesc->revision, &bd.revision, sizeof(bd.revision));
@@ -687,48 +588,7 @@ int scsi_scan(bool verbose)
return 0;
}
-#else
-int scsi_scan(bool verbose)
-{
- unsigned char i, lun;
- int ret;
- if (verbose)
- printf("scanning bus for devices...\n");
- for (i = 0; i < SCSI_MAX_DEVICE; i++)
- scsi_init_dev_desc(&scsi_dev_desc[i], i);
-
- scsi_max_devs = 0;
- for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) {
- for (lun = 0; lun < CONFIG_SYS_SCSI_MAX_LUN; lun++) {
- struct blk_desc *bdesc = &scsi_dev_desc[scsi_max_devs];
-
- ret = scsi_detect_dev(NULL, i, lun, bdesc);
- if (ret)
- continue;
- part_init(bdesc);
-
- if (verbose) {
- printf(" Device %d: ", bdesc->devnum);
- dev_print(bdesc);
- }
- scsi_max_devs++;
- } /* next LUN */
- }
- if (scsi_max_devs > 0)
- scsi_curr_dev = 0;
- else
- scsi_curr_dev = -1;
-
- printf("Found %d device(s).\n", scsi_max_devs);
-#ifndef CONFIG_SPL_BUILD
- env_set_ulong("scsidevs", scsi_max_devs);
-#endif
- return 0;
-}
-#endif
-
-#ifdef CONFIG_BLK
static const struct blk_ops scsi_blk_ops = {
.read = scsi_read,
.write = scsi_write,
@@ -742,11 +602,3 @@ U_BOOT_DRIVER(scsi_blk) = {
.id = UCLASS_BLK,
.ops = &scsi_blk_ops,
};
-#else
-U_BOOT_LEGACY_BLK(scsi) = {
- .uclass_idname = "scsi",
- .uclass_id = UCLASS_SCSI,
- .max_devs = SCSI_MAX_DEVICE,
- .desc = scsi_dev_desc,
-};
-#endif
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 6cb6598f3d2..6628a887de7 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -24,6 +24,21 @@ config BAUDRATE
in the SPL stage (most drivers) or for choosing a default baudrate
in the absence of an environment setting (serial_mxc.c).
+config OF_SERIAL_BAUD
+ bool "Fetch serial baudrate from device tree"
+ depends on DM_SERIAL && SPL_ENV_SUPPORT
+ select DEFAULT_ENV_IS_RW
+ help
+ Select this to enable fetching and setting of the baudrate
+ configured in the DT. Replace the default baudrate with the DT
+ baudrate and also set it to the environment.
+
+config DEFAULT_ENV_IS_RW
+ bool "Make default environment as writable"
+ help
+ Select this to enable to make default environment writable. This
+ allows modifying the default environment.
+
config REQUIRE_SERIAL_CONSOLE
bool "Require a serial port for console"
# Running without a serial console is not supported by the
@@ -160,7 +175,6 @@ config SERIAL_PROBE_ALL
config SPL_DM_SERIAL
bool "Enable Driver Model for serial drivers in SPL"
depends on DM_SERIAL && SPL_DM
- select SYS_SPL_MALLOC_F
default y
help
Enable driver model for serial in SPL. This replaces
@@ -171,7 +185,6 @@ config SPL_DM_SERIAL
config TPL_DM_SERIAL
bool "Enable Driver Model for serial drivers in TPL"
depends on DM_SERIAL && TPL_DM
- select SYS_TPL_MALLOC_F
default y if TPL && DM_SERIAL
help
Enable driver model for serial in TPL. This replaces
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index eab9537fbae..6deb1d8ddc5 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -13,6 +13,7 @@
#include <ns16550.h>
#include <reset.h>
#include <serial.h>
+#include <spl.h>
#include <watchdog.h>
#include <asm/global_data.h>
#include <linux/err.h>
@@ -472,6 +473,10 @@ static int ns16550_serial_getinfo(struct udevice *dev,
struct ns16550 *const com_port = dev_get_priv(dev);
struct ns16550_plat *plat = com_port->plat;
+ /* save code size */
+ if (!spl_in_proper())
+ return -ENOSYS;
+
info->type = SERIAL_CHIP_16550_COMPATIBLE;
#ifdef CONFIG_SYS_NS16550_PORT_MAPPED
info->addr_space = SERIAL_ADDRESS_SPACE_IO;
@@ -479,6 +484,7 @@ static int ns16550_serial_getinfo(struct udevice *dev,
info->addr_space = SERIAL_ADDRESS_SPACE_MEMORY;
#endif
info->addr = plat->base;
+ info->size = plat->size;
info->reg_width = plat->reg_width;
info->reg_shift = plat->reg_shift;
info->reg_offset = plat->reg_offset;
@@ -487,7 +493,8 @@ static int ns16550_serial_getinfo(struct udevice *dev,
return 0;
}
-static int ns16550_serial_assign_base(struct ns16550_plat *plat, fdt_addr_t base)
+static int ns16550_serial_assign_base(struct ns16550_plat *plat,
+ fdt_addr_t base, fdt_size_t size)
{
if (base == FDT_ADDR_T_NONE)
return -EINVAL;
@@ -497,6 +504,7 @@ static int ns16550_serial_assign_base(struct ns16550_plat *plat, fdt_addr_t base
#else
plat->base = (unsigned long)map_physmem(base, 0, MAP_NOCACHE);
#endif
+ plat->size = size;
return 0;
}
@@ -507,6 +515,7 @@ int ns16550_serial_probe(struct udevice *dev)
struct ns16550 *const com_port = dev_get_priv(dev);
struct reset_ctl_bulk reset_bulk;
fdt_addr_t addr;
+ fdt_addr_t size;
int ret;
/*
@@ -514,8 +523,8 @@ int ns16550_serial_probe(struct udevice *dev)
* or via a PCI bridge, assign plat->base before probing hardware.
*/
if (device_is_on_pci_bus(dev)) {
- addr = devfdt_get_addr_pci(dev);
- ret = ns16550_serial_assign_base(plat, addr);
+ addr = devfdt_get_addr_pci(dev, &size);
+ ret = ns16550_serial_assign_base(plat, addr, size);
if (ret)
return ret;
}
@@ -542,12 +551,14 @@ int ns16550_serial_of_to_plat(struct udevice *dev)
{
struct ns16550_plat *plat = dev_get_plat(dev);
const u32 port_type = dev_get_driver_data(dev);
+ fdt_size_t size = 0;
fdt_addr_t addr;
struct clk clk;
int err;
- addr = dev_read_addr(dev);
- err = ns16550_serial_assign_base(plat, addr);
+ addr = spl_in_proper() ? dev_read_addr_size(dev, &size) :
+ dev_read_addr(dev);
+ err = ns16550_serial_assign_base(plat, addr, size);
if (err && !device_is_on_pci_bus(dev))
return err;
diff --git a/drivers/serial/sandbox.c b/drivers/serial/sandbox.c
index f4003811ee7..f6ac3d22852 100644
--- a/drivers/serial/sandbox.c
+++ b/drivers/serial/sandbox.c
@@ -280,7 +280,7 @@ U_BOOT_DRIVER(sandbox_serial) = {
.flags = DM_FLAG_PRE_RELOC,
};
-#if CONFIG_IS_ENABLED(OF_REAL)
+#if CONFIG_IS_ENABLED(OF_REAL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
static const struct sandbox_serial_plat platdata_non_fdt = {
.colour = -1,
};
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index 5e2e7dfbcb3..e4fa3933bc8 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -155,12 +155,61 @@ static void serial_find_console_or_panic(void)
}
#endif /* CONFIG_SERIAL_PRESENT */
+/**
+ * check_valid_baudrate() - Check whether baudrate is valid or not
+ *
+ * @baud: baud rate to check
+ * Return: 0 if OK, -ve on error
+ */
+static int check_valid_baudrate(int baud)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(baudrate_table); ++i) {
+ if (baud == baudrate_table[i])
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+int fetch_baud_from_dtb(void)
+{
+ int baud_value, ret;
+
+ baud_value = ofnode_read_baud();
+ ret = check_valid_baudrate(baud_value);
+ if (ret)
+ return ret;
+
+ return baud_value;
+}
+
/* Called prior to relocation */
int serial_init(void)
{
#if CONFIG_IS_ENABLED(SERIAL_PRESENT)
serial_find_console_or_panic();
gd->flags |= GD_FLG_SERIAL_READY;
+
+ if (IS_ENABLED(CONFIG_OF_SERIAL_BAUD)) {
+ int ret = 0;
+ char *ptr = (char*)&default_environment[0];
+
+ /*
+ * Fetch the baudrate from the dtb and update the value in the
+ * default environment.
+ */
+ ret = fetch_baud_from_dtb();
+ if (ret != -EINVAL && ret != -EFAULT) {
+ gd->baudrate = ret;
+
+ while (*ptr != '\0' && *(ptr + 1) != '\0')
+ ptr++;
+ ptr += 2;
+ sprintf(ptr, "baudrate=%d", gd->baudrate);
+ }
+ }
serial_setbrg();
#endif
@@ -182,6 +231,16 @@ int serial_initialize(void)
return serial_init();
}
+static void _serial_flush(struct udevice *dev)
+{
+ struct dm_serial_ops *ops = serial_get_ops(dev);
+
+ if (!ops->pending)
+ return;
+ while (ops->pending(dev, false) > 0)
+ ;
+}
+
static void _serial_putc(struct udevice *dev, char ch)
{
struct dm_serial_ops *ops = serial_get_ops(dev);
@@ -193,6 +252,9 @@ static void _serial_putc(struct udevice *dev, char ch)
do {
err = ops->putc(dev, ch);
} while (err == -EAGAIN);
+
+ if (IS_ENABLED(CONFIG_CONSOLE_FLUSH_ON_NEWLINE) && ch == '\n')
+ _serial_flush(dev);
}
static int __serial_puts(struct udevice *dev, const char *str, size_t len)
@@ -231,22 +293,13 @@ static void _serial_puts(struct udevice *dev, const char *str)
if (*newline && __serial_puts(dev, "\r\n", 2))
return;
+ if (IS_ENABLED(CONFIG_CONSOLE_FLUSH_ON_NEWLINE) && *newline)
+ _serial_flush(dev);
+
str += len + !!*newline;
} while (*str);
}
-#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
-static void _serial_flush(struct udevice *dev)
-{
- struct dm_serial_ops *ops = serial_get_ops(dev);
-
- if (!ops->pending)
- return;
- while (ops->pending(dev, false) > 0)
- ;
-}
-#endif
-
static int __serial_getc(struct udevice *dev)
{
struct dm_serial_ops *ops = serial_get_ops(dev);
@@ -520,7 +573,7 @@ static int serial_post_probe(struct udevice *dev)
return 0;
memset(&sdev, '\0', sizeof(sdev));
- strncpy(sdev.name, dev->name, sizeof(sdev.name));
+ strlcpy(sdev.name, dev->name, sizeof(sdev.name));
sdev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_DM;
sdev.priv = dev;
sdev.putc = serial_stub_putc;
diff --git a/drivers/serial/serial_lpuart.c b/drivers/serial/serial_lpuart.c
index 51e66abdbc1..ce08a6b4486 100644
--- a/drivers/serial/serial_lpuart.c
+++ b/drivers/serial/serial_lpuart.c
@@ -480,18 +480,30 @@ static int lpuart_serial_probe(struct udevice *dev)
{
#if CONFIG_IS_ENABLED(CLK)
struct clk per_clk;
+ struct clk ipg_clk;
int ret;
ret = clk_get_by_name(dev, "per", &per_clk);
if (!ret) {
ret = clk_enable(&per_clk);
if (ret) {
- dev_err(dev, "Failed to get per clk: %d\n", ret);
+ dev_err(dev, "Failed to enable per clk: %d\n", ret);
return ret;
}
} else {
debug("%s: Failed to get per clk: %d\n", __func__, ret);
}
+
+ ret = clk_get_by_name(dev, "ipg", &ipg_clk);
+ if (!ret) {
+ ret = clk_enable(&ipg_clk);
+ if (ret) {
+ dev_err(dev, "Failed to enable ipg clk: %d\n", ret);
+ return ret;
+ }
+ } else {
+ debug("%s: Failed to get ipg clk: %d\n", __func__, ret);
+ }
#endif
if (is_lpuart32(dev))
diff --git a/drivers/serial/serial_meson.c b/drivers/serial/serial_meson.c
index 934de2ab235..be5f380f850 100644
--- a/drivers/serial/serial_meson.c
+++ b/drivers/serial/serial_meson.c
@@ -232,6 +232,7 @@ static const struct dm_serial_ops meson_serial_ops = {
static const struct udevice_id meson_serial_ids[] = {
{ .compatible = "amlogic,meson-uart" },
{ .compatible = "amlogic,meson-gx-uart" },
+ { .compatible = "amlogic,meson-a1-uart" },
{ }
};
diff --git a/drivers/serial/serial_msm_geni.c b/drivers/serial/serial_msm_geni.c
index 78fd9389c03..b8bc61451a0 100644
--- a/drivers/serial/serial_msm_geni.c
+++ b/drivers/serial/serial_msm_geni.c
@@ -13,14 +13,13 @@
#include <dm.h>
#include <errno.h>
#include <linux/delay.h>
+#include <linux/time.h>
#include <misc.h>
#include <serial.h>
#define UART_OVERSAMPLING 32
#define STALE_TIMEOUT 160
-#define USEC_PER_SEC 1000000L
-
/* Registers*/
#define GENI_FORCE_DEFAULT_REG 0x20
#define GENI_SER_M_CLK_CFG 0x48
diff --git a/drivers/serial/serial_npcm.c b/drivers/serial/serial_npcm.c
index 76ac7cb80db..6bf3a943a2f 100644
--- a/drivers/serial/serial_npcm.c
+++ b/drivers/serial/serial_npcm.c
@@ -83,8 +83,11 @@ static int npcm_serial_setbrg(struct udevice *dev, int baudrate)
struct npcm_uart *uart = plat->reg;
u16 divisor;
+ if (IS_ENABLED(CONFIG_SYS_SKIP_UART_INIT))
+ return 0;
+
/* BaudOut = UART Clock / (16 * [Divisor + 2]) */
- divisor = DIV_ROUND_CLOSEST(plat->uart_clk, 16 * baudrate + 2) - 2;
+ divisor = DIV_ROUND_CLOSEST(plat->uart_clk, 16 * baudrate) - 2;
setbits_8(&uart->lcr, LCR_DLAB);
writeb(divisor & 0xff, &uart->dll);
@@ -97,29 +100,35 @@ static int npcm_serial_setbrg(struct udevice *dev, int baudrate)
static int npcm_serial_probe(struct udevice *dev)
{
struct npcm_serial_plat *plat = dev_get_plat(dev);
- struct npcm_uart *uart = plat->reg;
+ struct npcm_uart *uart;
struct clk clk, parent;
u32 freq;
int ret;
plat->reg = dev_read_addr_ptr(dev);
- freq = dev_read_u32_default(dev, "clock-frequency", 0);
+ uart = plat->reg;
- ret = clk_get_by_index(dev, 0, &clk);
- if (ret < 0)
- return ret;
+ if (!IS_ENABLED(CONFIG_SYS_SKIP_UART_INIT)) {
+ freq = dev_read_u32_default(dev, "clock-frequency", 24000000);
- ret = clk_get_by_index(dev, 1, &parent);
- if (!ret) {
- ret = clk_set_parent(&clk, &parent);
- if (ret)
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret < 0)
return ret;
- }
- ret = clk_set_rate(&clk, freq);
- if (ret < 0)
- return ret;
- plat->uart_clk = ret;
+ ret = clk_get_by_index(dev, 1, &parent);
+ if (!ret) {
+ ret = clk_set_parent(&clk, &parent);
+ if (ret)
+ return ret;
+ }
+
+ if (freq) {
+ ret = clk_set_rate(&clk, freq);
+ if (ret < 0)
+ return ret;
+ }
+ plat->uart_clk = clk_get_rate(&clk);
+ }
/* Disable all interrupt */
writeb(0, &uart->ier);
diff --git a/drivers/serial/serial_omap.c b/drivers/serial/serial_omap.c
index 26310b0b746..49ced8f9fae 100644
--- a/drivers/serial/serial_omap.c
+++ b/drivers/serial/serial_omap.c
@@ -2,7 +2,7 @@
/*
* Texas Instruments' OMAP serial driver
*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com>
*/
diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c
index 7aeb8c0f8cb..7d04dcff54f 100644
--- a/drivers/serial/serial_s5p.c
+++ b/drivers/serial/serial_s5p.c
@@ -7,7 +7,6 @@
* based on drivers/serial/s3c64xx.c
*/
-#include <common.h>
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
@@ -21,32 +20,39 @@
#include <serial.h>
#include <clk.h>
-DECLARE_GLOBAL_DATA_PTR;
-
enum {
PORT_S5P = 0,
PORT_S5L
};
+#define UFCON_FIFO_EN BIT(0)
+#define UFCON_RX_FIFO_RESET BIT(1)
+#define UMCON_RESET_VAL 0x0
+#define ULCON_WORD_8_BIT 0x3
+#define UCON_RX_IRQ_OR_POLLING BIT(0)
+#define UCON_TX_IRQ_OR_POLLING BIT(2)
+#define UCON_RX_ERR_IRQ_EN BIT(6)
+#define UCON_TX_IRQ_LEVEL BIT(9)
+
#define S5L_RX_FIFO_COUNT_SHIFT 0
#define S5L_RX_FIFO_COUNT_MASK (0xf << S5L_RX_FIFO_COUNT_SHIFT)
-#define S5L_RX_FIFO_FULL (1 << 8)
+#define S5L_RX_FIFO_FULL BIT(8)
#define S5L_TX_FIFO_COUNT_SHIFT 4
#define S5L_TX_FIFO_COUNT_MASK (0xf << S5L_TX_FIFO_COUNT_SHIFT)
-#define S5L_TX_FIFO_FULL (1 << 9)
+#define S5L_TX_FIFO_FULL BIT(9)
#define S5P_RX_FIFO_COUNT_SHIFT 0
#define S5P_RX_FIFO_COUNT_MASK (0xff << S5P_RX_FIFO_COUNT_SHIFT)
-#define S5P_RX_FIFO_FULL (1 << 8)
+#define S5P_RX_FIFO_FULL BIT(8)
#define S5P_TX_FIFO_COUNT_SHIFT 16
#define S5P_TX_FIFO_COUNT_MASK (0xff << S5P_TX_FIFO_COUNT_SHIFT)
-#define S5P_TX_FIFO_FULL (1 << 24)
+#define S5P_TX_FIFO_FULL BIT(24)
/* Information about a serial port */
struct s5p_serial_plat {
- struct s5p_uart *reg; /* address of registers in physical memory */
- u8 reg_width; /* register width */
- u8 port_id; /* uart port number */
+ struct s5p_uart *reg; /* address of registers in physical memory */
+ u8 reg_width; /* register width */
+ u8 port_id; /* uart port number */
u8 rx_fifo_count_shift;
u8 tx_fifo_count_shift;
u32 rx_fifo_count_mask;
@@ -59,7 +65,7 @@ struct s5p_serial_plat {
* The coefficient, used to calculate the baudrate on S5P UARTs is
* calculated as
* C = UBRDIV * 16 + number_of_set_bits_in_UDIVSLOT
- * however, section 31.6.11 of the datasheet doesn't recomment using 1 for 1,
+ * however, section 31.6.11 of the datasheet doesn't recommend using 1 for 1,
* 3 for 2, ... (2^n - 1) for n, instead, they suggest using these constants:
*/
static const int udivslot[] = {
@@ -83,13 +89,15 @@ static const int udivslot[] = {
static void __maybe_unused s5p_serial_init(struct s5p_uart *uart)
{
- /* enable FIFOs, auto clear Rx FIFO */
- writel(0x3, &uart->ufcon);
- writel(0, &uart->umcon);
- /* 8N1 */
- writel(0x3, &uart->ulcon);
+ /* Enable FIFOs, auto clear Rx FIFO */
+ writel(UFCON_FIFO_EN | UFCON_RX_FIFO_RESET, &uart->ufcon);
+ /* No auto flow control, disable nRTS signal */
+ writel(UMCON_RESET_VAL, &uart->umcon);
+ /* 8N1, no parity bit */
+ writel(ULCON_WORD_8_BIT, &uart->ulcon);
/* No interrupts, no DMA, pure polling */
- writel(0x245, &uart->ucon);
+ writel(UCON_RX_IRQ_OR_POLLING | UCON_TX_IRQ_OR_POLLING |
+ UCON_RX_ERR_IRQ_EN | UCON_TX_IRQ_LEVEL, &uart->ucon);
}
static void __maybe_unused s5p_serial_baud(struct s5p_uart *uart, u8 reg_width,
@@ -118,7 +126,7 @@ int s5p_serial_setbrg(struct udevice *dev, int baudrate)
#if IS_ENABLED(CONFIG_CLK_EXYNOS) || IS_ENABLED(CONFIG_ARCH_APPLE)
struct clk clk;
- u32 ret;
+ int ret;
ret = clk_get_by_index(dev, 1, &clk);
if (ret < 0)
@@ -213,16 +221,13 @@ static int s5p_serial_of_to_plat(struct udevice *dev)
{
struct s5p_serial_plat *plat = dev_get_plat(dev);
const ulong port_type = dev_get_driver_data(dev);
- fdt_addr_t addr;
- addr = dev_read_addr(dev);
- if (addr == FDT_ADDR_T_NONE)
+ plat->reg = dev_read_addr_ptr(dev);
+ if (!plat->reg)
return -EINVAL;
- plat->reg = (struct s5p_uart *)addr;
plat->reg_width = dev_read_u32_default(dev, "reg-io-width", 1);
- plat->port_id = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
- "id", dev_seq(dev));
+ plat->port_id = dev_read_u8_default(dev, "id", dev_seq(dev));
if (port_type == PORT_S5L) {
plat->rx_fifo_count_shift = S5L_RX_FIFO_COUNT_SHIFT;
@@ -244,10 +249,10 @@ static int s5p_serial_of_to_plat(struct udevice *dev)
}
static const struct dm_serial_ops s5p_serial_ops = {
- .putc = s5p_serial_putc,
- .pending = s5p_serial_pending,
- .getc = s5p_serial_getc,
- .setbrg = s5p_serial_setbrg,
+ .putc = s5p_serial_putc,
+ .pending = s5p_serial_pending,
+ .getc = s5p_serial_getc,
+ .setbrg = s5p_serial_setbrg,
};
static const struct udevice_id s5p_serial_ids[] = {
@@ -257,13 +262,13 @@ static const struct udevice_id s5p_serial_ids[] = {
};
U_BOOT_DRIVER(serial_s5p) = {
- .name = "serial_s5p",
- .id = UCLASS_SERIAL,
- .of_match = s5p_serial_ids,
- .of_to_plat = s5p_serial_of_to_plat,
+ .name = "serial_s5p",
+ .id = UCLASS_SERIAL,
+ .of_match = s5p_serial_ids,
+ .of_to_plat = s5p_serial_of_to_plat,
.plat_auto = sizeof(struct s5p_serial_plat),
- .probe = s5p_serial_probe,
- .ops = &s5p_serial_ops,
+ .probe = s5p_serial_probe,
+ .ops = &s5p_serial_ops,
};
#endif
@@ -291,10 +296,12 @@ static inline void _debug_uart_putc(int ch)
struct s5p_uart *uart = (struct s5p_uart *)CONFIG_VAL(DEBUG_UART_BASE);
#if IS_ENABLED(CONFIG_ARCH_APPLE)
- while (readl(&uart->ufstat) & S5L_TX_FIFO_FULL);
+ while (readl(&uart->ufstat) & S5L_TX_FIFO_FULL)
+ ;
writel(ch, &uart->utxh);
#else
- while (readl(&uart->ufstat) & S5P_TX_FIFO_FULL);
+ while (readl(&uart->ufstat) & S5P_TX_FIFO_FULL)
+ ;
writeb(ch, &uart->utxh);
#endif
}
diff --git a/drivers/serial/serial_sh.c b/drivers/serial/serial_sh.c
index 20cda5dbe27..e4cc4ee4260 100644
--- a/drivers/serial/serial_sh.c
+++ b/drivers/serial/serial_sh.c
@@ -6,17 +6,18 @@
* Copyright (C) 2002 - 2008 Paul Mundt
*/
-#include <common.h>
-#include <errno.h>
-#include <clk.h>
-#include <dm.h>
#include <asm/global_data.h>
#include <asm/io.h>
#include <asm/processor.h>
-#include <serial.h>
-#include <linux/compiler.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
#include <dm/platform_data/serial_sh.h>
+#include <errno.h>
+#include <linux/compiler.h>
#include <linux/delay.h>
+#include <reset.h>
+#include <serial.h>
#include "serial_sh.h"
DECLARE_GLOBAL_DATA_PTR;
@@ -58,8 +59,10 @@ static void sh_serial_init_generic(struct uart_port *port)
sci_out(port, SCSPTR, 0x0003);
#endif
+#if IS_ENABLED(CONFIG_RCAR_GEN2) || IS_ENABLED(CONFIG_RCAR_GEN3) || IS_ENABLED(CONFIG_RCAR_GEN4)
if (port->type == PORT_HSCIF)
sci_out(port, HSSRR, HSSRR_SRE | HSSRR_SRCYC8);
+#endif
}
static void
@@ -77,10 +80,22 @@ sh_serial_setbrg_generic(struct uart_port *port, int clk, int baudrate)
static void handle_error(struct uart_port *port)
{
- sci_in(port, SCxSR);
- sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
+ /*
+ * Most errors are cleared by resetting the relevant error bits to zero
+ * in the FSR & LSR registers. For each register, a read followed by a
+ * write is needed according to the relevant datasheets.
+ */
+ unsigned short status = sci_in(port, SCxSR);
+ sci_out(port, SCxSR, status & ~SCxSR_ERRORS(port));
sci_in(port, SCLSR);
sci_out(port, SCLSR, 0x00);
+
+ /*
+ * To clear framing errors, we also need to read and discard a
+ * character.
+ */
+ if ((port->type != PORT_SCI) && (status & SCIF_FER))
+ sci_in(port, SCxRDR);
}
static int serial_raw_putc(struct uart_port *port, const char c)
@@ -185,12 +200,24 @@ static int sh_serial_probe(struct udevice *dev)
{
struct sh_serial_plat *plat = dev_get_plat(dev);
struct uart_port *priv = dev_get_priv(dev);
+ struct reset_ctl rst;
+ int ret;
priv->membase = (unsigned char *)plat->base;
priv->mapbase = plat->base;
priv->type = plat->type;
priv->clk_mode = plat->clk_mode;
+ /* De-assert the module reset if it is defined. */
+ ret = reset_get_by_index(dev, 0, &rst);
+ if (!ret) {
+ ret = reset_deassert(&rst);
+ if (ret < 0) {
+ dev_err(dev, "failed to de-assert reset line\n");
+ return ret;
+ }
+ }
+
sh_serial_init_generic(priv);
return 0;
@@ -207,6 +234,7 @@ static const struct dm_serial_ops sh_serial_ops = {
static const struct udevice_id sh_serial_id[] ={
{.compatible = "renesas,sci", .data = PORT_SCI},
{.compatible = "renesas,scif", .data = PORT_SCIF},
+ {.compatible = "renesas,scif-r9a07g044", .data = PORT_SCIFA},
{.compatible = "renesas,scifa", .data = PORT_SCIFA},
{.compatible = "renesas,hscif", .data = PORT_HSCIF},
{}
diff --git a/drivers/serial/serial_sh.h b/drivers/serial/serial_sh.h
index 149ec1fe739..58c2d22bc75 100644
--- a/drivers/serial/serial_sh.h
+++ b/drivers/serial/serial_sh.h
@@ -90,7 +90,7 @@ struct uart_port {
# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
# define SCIF_ORER 0x0001 /* overrun error bit */
#elif defined(CONFIG_RCAR_GEN2) || defined(CONFIG_RCAR_64) || \
- defined(CONFIG_R7S72100)
+ defined(CONFIG_R7S72100) || defined(CONFIG_RZG2L)
# if defined(CFG_SCIF_A)
# define SCIF_ORER 0x0200
# else
@@ -312,6 +312,9 @@ static inline void sci_##name##_out(struct uart_port *port,\
sh4_scif_offset, sh4_scif_size)
#define SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) \
CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
+#elif defined(CONFIG_RZG2L)
+#define SCIF_FNS(reg_name, reg_offset, reg_size) \
+ CPU_SCIF_FNS(reg_name, reg_offset, reg_size)
#else
#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size,\
sh4_sci_offset, sh4_sci_size, \
@@ -387,6 +390,20 @@ SCIF_FNS(SCLSR, 0, 0, 0x14, 16)
#else
SCIF_FNS(SCLSR, 0, 0, 0x24, 16)
#endif
+#elif defined(CONFIG_RZG2L)
+SCIF_FNS(SCSMR, 0x00, 16)
+SCIF_FNS(SCBRR, 0x02, 8)
+SCIF_FNS(SCSCR, 0x04, 16)
+SCIF_FNS(SCxTDR, 0x06, 8)
+SCIF_FNS(SCxSR, 0x08, 16)
+SCIF_FNS(SCxRDR, 0x0A, 8)
+SCIF_FNS(SCFCR, 0x0C, 16)
+SCIF_FNS(SCFDR, 0x0E, 16)
+SCIF_FNS(SCSPTR, 0x10, 16)
+SCIF_FNS(SCLSR, 0x12, 16)
+SCIF_FNS(SCSEMR, 0x14, 8)
+SCIF_FNS(SCxTCR, 0x16, 16)
+SCIF_FNS(DL, 0x00, 0)
#else
/* reg SCI/SH3 SCI/SH4 SCIF/SH3 SCIF/SH4 SCI/H8*/
/* name off sz off sz off sz off sz off sz*/
diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c
index 23d476fba28..fb039546a41 100644
--- a/drivers/serial/serial_stm32.c
+++ b/drivers/serial/serial_stm32.c
@@ -30,7 +30,7 @@
*/
#define ONE_BYTE_B115200_US 87
-static void _stm32_serial_setbrg(fdt_addr_t base,
+static void _stm32_serial_setbrg(void __iomem *base,
struct stm32_uart_info *uart_info,
u32 clock_rate,
int baudrate)
@@ -75,7 +75,7 @@ static int stm32_serial_setconfig(struct udevice *dev, uint serial_config)
struct stm32x7_serial_plat *plat = dev_get_plat(dev);
bool stm32f4 = plat->uart_info->stm32f4;
u8 uart_enable_bit = plat->uart_info->uart_enable_bit;
- u32 cr1 = plat->base + CR1_OFFSET(stm32f4);
+ void __iomem *cr1 = plat->base + CR1_OFFSET(stm32f4);
u32 config = 0;
uint parity = SERIAL_GET_PARITY(serial_config);
uint bits = SERIAL_GET_BITS(serial_config);
@@ -122,7 +122,7 @@ static int stm32_serial_getc(struct udevice *dev)
{
struct stm32x7_serial_plat *plat = dev_get_plat(dev);
bool stm32f4 = plat->uart_info->stm32f4;
- fdt_addr_t base = plat->base;
+ void __iomem *base = plat->base;
u32 isr = readl(base + ISR_OFFSET(stm32f4));
if ((isr & USART_ISR_RXNE) == 0)
@@ -141,7 +141,7 @@ static int stm32_serial_getc(struct udevice *dev)
return readl(base + RDR_OFFSET(stm32f4));
}
-static int _stm32_serial_putc(fdt_addr_t base,
+static int _stm32_serial_putc(void __iomem *base,
struct stm32_uart_info *uart_info,
const char c)
{
@@ -166,7 +166,7 @@ static int stm32_serial_pending(struct udevice *dev, bool input)
{
struct stm32x7_serial_plat *plat = dev_get_plat(dev);
bool stm32f4 = plat->uart_info->stm32f4;
- fdt_addr_t base = plat->base;
+ void __iomem *base = plat->base;
if (input)
return readl(base + ISR_OFFSET(stm32f4)) &
@@ -176,7 +176,7 @@ static int stm32_serial_pending(struct udevice *dev, bool input)
USART_ISR_TXE ? 0 : 1;
}
-static void _stm32_serial_init(fdt_addr_t base,
+static void _stm32_serial_init(void __iomem *base,
struct stm32_uart_info *uart_info)
{
bool stm32f4 = uart_info->stm32f4;
@@ -250,11 +250,14 @@ static const struct udevice_id stm32_serial_id[] = {
static int stm32_serial_of_to_plat(struct udevice *dev)
{
struct stm32x7_serial_plat *plat = dev_get_plat(dev);
+ fdt_addr_t addr;
- plat->base = dev_read_addr(dev);
- if (plat->base == FDT_ADDR_T_NONE)
+ addr = dev_read_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
+ plat->base = (void __iomem *)addr;
+
return 0;
}
@@ -297,7 +300,7 @@ static inline struct stm32_uart_info *_debug_uart_info(void)
static inline void _debug_uart_init(void)
{
- fdt_addr_t base = CONFIG_VAL(DEBUG_UART_BASE);
+ void __iomem *base = (void __iomem *)CONFIG_VAL(DEBUG_UART_BASE);
struct stm32_uart_info *uart_info = _debug_uart_info();
_stm32_serial_init(base, uart_info);
@@ -308,7 +311,7 @@ static inline void _debug_uart_init(void)
static inline void _debug_uart_putc(int c)
{
- fdt_addr_t base = CONFIG_VAL(DEBUG_UART_BASE);
+ void __iomem *base = (void __iomem *)CONFIG_VAL(DEBUG_UART_BASE);
struct stm32_uart_info *uart_info = _debug_uart_info();
while (_stm32_serial_putc(base, uart_info, c) == -EAGAIN)
diff --git a/drivers/serial/serial_stm32.h b/drivers/serial/serial_stm32.h
index b7e7a90b931..d2c92ba48ea 100644
--- a/drivers/serial/serial_stm32.h
+++ b/drivers/serial/serial_stm32.h
@@ -49,7 +49,7 @@ struct stm32_uart_info stm32h7_info = {
/* Information about a serial port */
struct stm32x7_serial_plat {
- fdt_addr_t base; /* address of registers in physical memory */
+ void __iomem *base; /* address of registers in physical memory */
struct stm32_uart_info *uart_info;
unsigned long int clock_rate;
};
diff --git a/drivers/sm/Kconfig b/drivers/sm/Kconfig
new file mode 100644
index 00000000000..926af286330
--- /dev/null
+++ b/drivers/sm/Kconfig
@@ -0,0 +1,8 @@
+config SM
+ bool "Enable Secure Monitor driver support"
+
+config MESON_SM
+ bool "Amlogic Secure Monitor driver"
+ select SM
+ help
+ Say y here to enable the Amlogic secure monitor driver.
diff --git a/drivers/sm/Makefile b/drivers/sm/Makefile
new file mode 100644
index 00000000000..da81ee898ab
--- /dev/null
+++ b/drivers/sm/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-y += sm-uclass.o
+obj-$(CONFIG_SANDBOX) += sandbox-sm.o
+obj-$(CONFIG_MESON_SM) += meson-sm.o
diff --git a/drivers/sm/meson-sm.c b/drivers/sm/meson-sm.c
new file mode 100644
index 00000000000..15b3b0e2672
--- /dev/null
+++ b/drivers/sm/meson-sm.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 SberDevices, Inc.
+ *
+ * Author: Alexey Romanov <avromanov@salutedevices.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <regmap.h>
+#include <sm.h>
+#include <sm-uclass.h>
+#include <stdlib.h>
+#include <syscon.h>
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <meson/sm.h>
+#include <linux/bitfield.h>
+#include <linux/err.h>
+#include <linux/sizes.h>
+
+struct meson_sm_cmd {
+ u32 smc_id;
+};
+
+#define SET_CMD(index, id) \
+ [index] = { \
+ .smc_id = (id), \
+ }
+
+struct meson_sm_data {
+ u32 cmd_get_shmem_in;
+ u32 cmd_get_shmem_out;
+ unsigned int shmem_size;
+ struct meson_sm_cmd cmd[];
+};
+
+struct meson_sm_priv {
+ void *sm_shmem_in;
+ void *sm_shmem_out;
+ const struct meson_sm_data *data;
+};
+
+static unsigned long __meson_sm_call(u32 cmd, const struct pt_regs *args)
+{
+ struct pt_regs r = *args;
+
+ r.regs[0] = cmd;
+ smc_call(&r);
+
+ return r.regs[0];
+};
+
+static u32 meson_sm_get_cmd(const struct meson_sm_data *data,
+ u32 cmd_index)
+{
+ struct meson_sm_cmd cmd;
+
+ if (cmd_index >= MESON_SMC_CMD_COUNT)
+ return 0;
+
+ cmd = data->cmd[cmd_index];
+ return cmd.smc_id;
+}
+
+static int meson_sm_call(struct udevice *dev, u32 cmd_index, s32 *retval,
+ struct pt_regs *args)
+{
+ struct meson_sm_priv *priv = dev_get_priv(dev);
+ u32 cmd, ret;
+
+ cmd = meson_sm_get_cmd(priv->data, cmd_index);
+ if (!cmd)
+ return -ENOENT;
+
+ ret = __meson_sm_call(cmd, args);
+ if (retval)
+ *retval = ret;
+
+ return 0;
+}
+
+static int meson_sm_call_read(struct udevice *dev, void *buffer, size_t size,
+ u32 cmd_index, struct pt_regs *args)
+{
+ struct meson_sm_priv *priv = dev_get_priv(dev);
+ s32 nbytes;
+ int ret;
+
+ if (!buffer || size > priv->data->shmem_size)
+ return -EINVAL;
+
+ ret = meson_sm_call(dev, cmd_index, &nbytes, args);
+ if (ret)
+ return ret;
+
+ if (nbytes < 0 || nbytes > size)
+ return -ENOBUFS;
+
+ /* In some cases (for example GET_CHIP_ID command),
+ * SMC doesn't return the number of bytes read, even
+ * though the bytes were actually read into sm_shmem_out.
+ * So this check is needed.
+ */
+ ret = nbytes;
+ if (!nbytes)
+ nbytes = size;
+
+ memcpy(buffer, priv->sm_shmem_out, nbytes);
+
+ return ret;
+}
+
+static int meson_sm_call_write(struct udevice *dev, void *buffer, size_t size,
+ u32 cmd_index, struct pt_regs *args)
+{
+ struct meson_sm_priv *priv = dev_get_priv(dev);
+ s32 nbytes;
+ int ret;
+
+ if (!buffer || size > priv->data->shmem_size)
+ return -EINVAL;
+
+ memcpy(priv->sm_shmem_in, buffer, size);
+
+ ret = meson_sm_call(dev, cmd_index, &nbytes, args);
+ if (ret)
+ return ret;
+
+ if (nbytes <= 0 || nbytes > size)
+ return -EIO;
+
+ return nbytes;
+}
+
+static int meson_sm_probe(struct udevice *dev)
+{
+ struct meson_sm_priv *priv = dev_get_priv(dev);
+ struct pt_regs regs = { 0 };
+
+ priv->data = (struct meson_sm_data *)dev_get_driver_data(dev);
+ if (!priv->data)
+ return -EINVAL;
+
+ priv->sm_shmem_in =
+ (void *)__meson_sm_call(priv->data->cmd_get_shmem_in, &regs);
+
+ if (!priv->sm_shmem_in)
+ return -ENOMEM;
+
+ priv->sm_shmem_out =
+ (void *)__meson_sm_call(priv->data->cmd_get_shmem_out, &regs);
+
+ if (!priv->sm_shmem_out)
+ return -ENOMEM;
+
+ pr_debug("meson sm driver probed\n"
+ "shmem_in addr: 0x%p, shmem_out addr: 0x%p\n",
+ priv->sm_shmem_in,
+ priv->sm_shmem_out);
+
+ return 0;
+}
+
+static const struct meson_sm_data meson_sm_gxbb_data = {
+ .cmd_get_shmem_in = 0x82000020,
+ .cmd_get_shmem_out = 0x82000021,
+ .shmem_size = SZ_4K,
+ .cmd = {
+ SET_CMD(MESON_SMC_CMD_EFUSE_READ, 0x82000030),
+ SET_CMD(MESON_SMC_CMD_EFUSE_WRITE, 0x82000031),
+ SET_CMD(MESON_SMC_CMD_CHIP_ID_GET, 0x82000044),
+ SET_CMD(MESON_SMC_CMD_PWRDM_SET, 0x82000093),
+ },
+};
+
+static const struct udevice_id meson_sm_ids[] = {
+ {
+ .compatible = "amlogic,meson-gxbb-sm",
+ .data = (ulong)&meson_sm_gxbb_data,
+ },
+ { }
+};
+
+static const struct sm_ops sm_ops = {
+ .sm_call = meson_sm_call,
+ .sm_call_read = meson_sm_call_read,
+ .sm_call_write = meson_sm_call_write,
+};
+
+U_BOOT_DRIVER(meson_sm) = {
+ .name = "meson_sm",
+ .id = UCLASS_SM,
+ .of_match = meson_sm_ids,
+ .probe = meson_sm_probe,
+ .bind = dm_scan_fdt_dev,
+ .priv_auto = sizeof(struct meson_sm_priv),
+ .ops = &sm_ops,
+};
diff --git a/drivers/sm/sandbox-sm.c b/drivers/sm/sandbox-sm.c
new file mode 100644
index 00000000000..109ddb2af55
--- /dev/null
+++ b/drivers/sm/sandbox-sm.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 SberDevices, Inc.
+ *
+ * Author: Alexey Romanov <avromanov@salutedevices.com>
+ */
+
+#include <common.h>
+#include <sm.h>
+#include <sm-uclass.h>
+#include <sandbox-sm.h>
+#include <asm/ptrace.h>
+#include <dm/device.h>
+#include <linux/sizes.h>
+
+static u8 test_buffer[SZ_4K];
+
+static int sandbox_sm_call(struct udevice *dev, u32 cmd_index, s32 *smc_ret,
+ struct pt_regs *args)
+{
+ if (cmd_index >= SANDBOX_SMC_CMD_COUNT)
+ return -EINVAL;
+
+ if (smc_ret)
+ *smc_ret = 0;
+
+ return 0;
+}
+
+static int sandbox_sm_call_read(struct udevice *dev, void *buffer, size_t size,
+ u32 cmd_index, struct pt_regs *args)
+{
+ if (cmd_index >= SANDBOX_SMC_CMD_COUNT || !buffer)
+ return -EINVAL;
+
+ if (size > sizeof(test_buffer))
+ return -EINVAL;
+
+ memcpy(buffer, test_buffer, size);
+
+ return size;
+}
+
+static int sandbox_sm_call_write(struct udevice *dev, void *buffer, size_t size,
+ u32 cmd_index, struct pt_regs *args)
+{
+ if (cmd_index >= SANDBOX_SMC_CMD_COUNT || !buffer)
+ return -EINVAL;
+
+ if (size > sizeof(test_buffer))
+ return -EINVAL;
+
+ memcpy(test_buffer, buffer, size);
+
+ return size;
+}
+
+static const struct udevice_id sandbox_sm_ids[] = {
+ {
+ .compatible = "sandbox,sm",
+ },
+ {},
+};
+
+static const struct sm_ops sandbox_sm_ops = {
+ .sm_call = sandbox_sm_call,
+ .sm_call_read = sandbox_sm_call_read,
+ .sm_call_write = sandbox_sm_call_write,
+};
+
+U_BOOT_DRIVER(sm) = {
+ .name = "sm",
+ .id = UCLASS_SM,
+ .of_match = sandbox_sm_ids,
+ .ops = &sandbox_sm_ops,
+};
diff --git a/drivers/sm/sm-uclass.c b/drivers/sm/sm-uclass.c
new file mode 100644
index 00000000000..6a8b7026293
--- /dev/null
+++ b/drivers/sm/sm-uclass.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 SberDevices, Inc.
+ *
+ * Author: Alexey Romanov <avromanov@salutedevices.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <sm-uclass.h>
+
+static const struct sm_ops *get_sm_ops(struct udevice *dev)
+{
+ return (const struct sm_ops *)dev->driver->ops;
+}
+
+int sm_call(struct udevice *dev, u32 cmd, s32 *ret, struct pt_regs *args)
+{
+ const struct sm_ops *ops = get_sm_ops(dev);
+
+ if (ops->sm_call)
+ return ops->sm_call(dev, cmd, ret, args);
+
+ return -ENOSYS;
+}
+
+int sm_call_read(struct udevice *dev, void *buffer, size_t size,
+ u32 cmd, struct pt_regs *args)
+{
+ const struct sm_ops *ops = get_sm_ops(dev);
+
+ if (ops->sm_call_read)
+ return ops->sm_call_read(dev, buffer, size, cmd,
+ args);
+
+ return -ENOSYS;
+}
+
+int sm_call_write(struct udevice *dev, void *buffer, size_t size,
+ u32 cmd, struct pt_regs *args)
+{
+ const struct sm_ops *ops = get_sm_ops(dev);
+
+ if (ops->sm_call_write)
+ return ops->sm_call_write(dev, buffer, size, cmd,
+ args);
+
+ return -ENOSYS;
+}
+
+UCLASS_DRIVER(sm) = {
+ .name = "sm",
+ .id = UCLASS_SM,
+};
diff --git a/drivers/soc/soc-uclass.c b/drivers/soc/soc-uclass.c
index dfad32d80db..8b3044fed8d 100644
--- a/drivers/soc/soc-uclass.c
+++ b/drivers/soc/soc-uclass.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * (C) Copyright 2020 - Texas Instruments Incorporated - http://www.ti.com/
+ * (C) Copyright 2020 - Texas Instruments Incorporated - https://www.ti.com/
* Dave Gerlach <d-gerlach@ti.com>
*/
diff --git a/drivers/soc/soc_sandbox.c b/drivers/soc/soc_sandbox.c
index 5c82ad84fc2..15fdd9930cb 100644
--- a/drivers/soc/soc_sandbox.c
+++ b/drivers/soc/soc_sandbox.c
@@ -2,7 +2,7 @@
/*
* Sandbox driver for the SOC uclass
*
- * (C) Copyright 2020 - Texas Instruments Incorporated - http://www.ti.com/
+ * (C) Copyright 2020 - Texas Instruments Incorporated - https://www.ti.com/
* Dave Gerlach <d-gerlach@ti.com>
*/
diff --git a/drivers/soc/soc_ti_k3.c b/drivers/soc/soc_ti_k3.c
index b720131ae5d..355a5368dd4 100644
--- a/drivers/soc/soc_ti_k3.c
+++ b/drivers/soc/soc_ti_k3.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2020 Texas Instruments Incorporated - https://www.ti.com/
* Dave Gerlach <d-gerlach@ti.com>
*/
diff --git a/drivers/soc/ti/k3-navss-ringacc.c b/drivers/soc/ti/k3-navss-ringacc.c
index 9881bffc8e1..7a2fbb0db6e 100644
--- a/drivers/soc/ti/k3-navss-ringacc.c
+++ b/drivers/soc/ti/k3-navss-ringacc.c
@@ -2,7 +2,7 @@
/*
* TI K3 AM65x NAVSS Ring accelerator Manager (RA) subsystem driver
*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com
*/
#include <common.h>
@@ -987,10 +987,10 @@ static int k3_nav_ringacc_init(struct udevice *dev, struct k3_nav_ringacc *ringa
if (!base_cfg)
return -EINVAL;
- base_rt = (uint32_t *)devfdt_get_addr_name(dev, "rt");
+ base_rt = dev_read_addr_name_ptr(dev, "rt");
pr_debug("rt %p\n", base_rt);
- if (IS_ERR(base_rt))
- return PTR_ERR(base_rt);
+ if (!base_rt)
+ return -EINVAL;
ringacc->rings = devm_kzalloc(dev,
sizeof(*ringacc->rings) *
@@ -1045,9 +1045,9 @@ struct k3_nav_ringacc *k3_ringacc_dmarings_init(struct udevice *dev,
ringacc->tisci = data->tisci;
ringacc->tisci_dev_id = data->tisci_dev_id;
- base_rt = (uint32_t *)devfdt_get_addr_name(dev, "ringrt");
- if (IS_ERR(base_rt))
- return base_rt;
+ base_rt = dev_read_addr_name_ptr(dev, "ringrt");
+ if (!base_rt)
+ return ERR_PTR(-EINVAL);
ringacc->rings = devm_kzalloc(dev,
sizeof(*ringacc->rings) *
diff --git a/drivers/soc/ti/keystone_serdes.c b/drivers/soc/ti/keystone_serdes.c
index 2ece1a8f647..0e1bf8ff39d 100644
--- a/drivers/soc/ti/keystone_serdes.c
+++ b/drivers/soc/ti/keystone_serdes.c
@@ -8,6 +8,7 @@
#include <errno.h>
#include <common.h>
+#include <asm/io.h>
#include <asm/ti-common/keystone_serdes.h>
#include <linux/bitops.h>
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 854b8b88daf..69b184b0d9e 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -251,6 +251,15 @@ config MICROCHIP_COREQSPI
Enable the QSPI driver for Microchip FPGA QSPI controllers.
This driver can be used on Polarfire SoC.
+config MESON_SPIFC_A1
+ bool "Amlogic Meson A1 SPI Flash Controller driver"
+ depends on ARCH_MESON
+ help
+ Enable the Amlogic A1 SPI Flash Controller (SPIFC) driver.
+ This driver can be used to access the SPI NOR/NAND flash chips
+ with STR mode frequency up to 98MHz. Dual and quad modes are
+ supported by controller.
+
config MPC8XX_SPI
bool "MPC8XX SPI Driver"
depends on MPC8xx
@@ -451,7 +460,6 @@ config SANDBOX_SPI_MAX_CS
config SPI_ASPEED_SMC
bool "ASPEED SPI flash controller driver"
depends on DM_SPI && SPI_MEM
- default n
help
Enable ASPEED SPI flash controller driver for AST2500
and AST2600 SoCs.
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index c27b3327c33..14bdb97f189 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_ICH_SPI) += ich.o
obj-$(CONFIG_IPROC_QSPI) += iproc_qspi.o
obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
obj-$(CONFIG_MESON_SPIFC) += meson_spifc.o
+obj-$(CONFIG_MESON_SPIFC_A1) += meson_spifc_a1.o
obj-$(CONFIG_MICROCHIP_COREQSPI) += microchip_coreqspi.o
obj-$(CONFIG_MPC8XX_SPI) += mpc8xx_spi.o
obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
diff --git a/drivers/spi/cadence_ospi_versal.c b/drivers/spi/cadence_ospi_versal.c
index a7685a2f512..e02a3b3de37 100644
--- a/drivers/spi/cadence_ospi_versal.c
+++ b/drivers/spi/cadence_ospi_versal.c
@@ -44,8 +44,10 @@ int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv,
priv->regbase + CQSPI_REG_INDIR_TRIG_ADDR_RANGE);
writel(CQSPI_DFLT_DMA_PERIPH_CFG,
priv->regbase + CQSPI_REG_DMA_PERIPH_CFG);
- writel((unsigned long)rxbuf, priv->regbase +
+ writel(lower_32_bits((unsigned long)rxbuf), priv->regbase +
CQSPI_DMA_DST_ADDR_REG);
+ writel(upper_32_bits((unsigned long)rxbuf), priv->regbase +
+ CQSPI_DMA_DST_ADDR_MSB_REG);
writel(priv->trigger_address, priv->regbase +
CQSPI_DMA_SRC_RD_ADDR_REG);
writel(bytes_to_dma, priv->regbase +
diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index cc3a54f2958..2efd626852e 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -7,7 +7,6 @@
#include <common.h>
#include <clk.h>
#include <log.h>
-#include <asm-generic/io.h>
#include <dm.h>
#include <fdtdec.h>
#include <malloc.h>
@@ -17,13 +16,13 @@
#include <dm/device_compat.h>
#include <linux/err.h>
#include <linux/errno.h>
+#include <linux/io.h>
#include <linux/sizes.h>
+#include <linux/time.h>
#include <zynqmp_firmware.h>
#include "cadence_qspi.h"
#include <dt-bindings/power/xlnx-versal-power.h>
-#define NSEC_PER_SEC 1000000000L
-
#define CQSPI_STIG_READ 0
#define CQSPI_STIG_WRITE 1
#define CQSPI_READ 2
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c
index 9ebc4ed48f0..25f5e9fdebd 100644
--- a/drivers/spi/davinci_spi.c
+++ b/drivers/spi/davinci_spi.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2009 Texas Instruments Incorporated - https://www.ti.com/
*
* Driver for SPI controller on DaVinci. Based on atmel_spi.c
* by Atmel Corporation
diff --git a/drivers/spi/fsl_dspi.c b/drivers/spi/fsl_dspi.c
index f8ec268812c..89907cbbb02 100644
--- a/drivers/spi/fsl_dspi.c
+++ b/drivers/spi/fsl_dspi.c
@@ -27,9 +27,7 @@
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/printk.h>
-
-/* linux/include/time.h */
-#define NSEC_PER_SEC 1000000000L
+#include <linux/time.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/drivers/spi/meson_spifc_a1.c b/drivers/spi/meson_spifc_a1.c
new file mode 100644
index 00000000000..cca4debb412
--- /dev/null
+++ b/drivers/spi/meson_spifc_a1.c
@@ -0,0 +1,384 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Amlogic A1 SPI flash controller (SPIFC)
+ *
+ * Copyright (c) 2023, SberDevices. All Rights Reserved.
+ *
+ * Author: Martin Kurbanov <mmkurbanov@sberdevices.ru>
+ *
+ * Ported to u-boot:
+ * Author: Igor Prusov <ivprusov@sberdevices.ru>
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <spi.h>
+#include <spi-mem.h>
+#include <asm/io.h>
+#include <linux/log2.h>
+#include <linux/time.h>
+#include <linux/iopoll.h>
+#include <linux/bitfield.h>
+
+#define SPIFC_A1_AHB_CTRL_REG 0x0
+#define SPIFC_A1_AHB_BUS_EN BIT(31)
+
+#define SPIFC_A1_USER_CTRL0_REG 0x200
+#define SPIFC_A1_USER_REQUEST_ENABLE BIT(31)
+#define SPIFC_A1_USER_REQUEST_FINISH BIT(30)
+#define SPIFC_A1_USER_DATA_UPDATED BIT(0)
+
+#define SPIFC_A1_USER_CTRL1_REG 0x204
+#define SPIFC_A1_USER_CMD_ENABLE BIT(30)
+#define SPIFC_A1_USER_CMD_MODE GENMASK(29, 28)
+#define SPIFC_A1_USER_CMD_CODE GENMASK(27, 20)
+#define SPIFC_A1_USER_ADDR_ENABLE BIT(19)
+#define SPIFC_A1_USER_ADDR_MODE GENMASK(18, 17)
+#define SPIFC_A1_USER_ADDR_BYTES GENMASK(16, 15)
+#define SPIFC_A1_USER_DOUT_ENABLE BIT(14)
+#define SPIFC_A1_USER_DOUT_MODE GENMASK(11, 10)
+#define SPIFC_A1_USER_DOUT_BYTES GENMASK(9, 0)
+
+#define SPIFC_A1_USER_CTRL2_REG 0x208
+#define SPIFC_A1_USER_DUMMY_ENABLE BIT(31)
+#define SPIFC_A1_USER_DUMMY_MODE GENMASK(30, 29)
+#define SPIFC_A1_USER_DUMMY_CLK_SYCLES GENMASK(28, 23)
+
+#define SPIFC_A1_USER_CTRL3_REG 0x20c
+#define SPIFC_A1_USER_DIN_ENABLE BIT(31)
+#define SPIFC_A1_USER_DIN_MODE GENMASK(28, 27)
+#define SPIFC_A1_USER_DIN_BYTES GENMASK(25, 16)
+
+#define SPIFC_A1_USER_ADDR_REG 0x210
+
+#define SPIFC_A1_AHB_REQ_CTRL_REG 0x214
+#define SPIFC_A1_AHB_REQ_ENABLE BIT(31)
+
+#define SPIFC_A1_ACTIMING0_REG (0x0088 << 2)
+#define SPIFC_A1_TSLCH GENMASK(31, 30)
+#define SPIFC_A1_TCLSH GENMASK(29, 28)
+#define SPIFC_A1_TSHWL GENMASK(20, 16)
+#define SPIFC_A1_TSHSL2 GENMASK(15, 12)
+#define SPIFC_A1_TSHSL1 GENMASK(11, 8)
+#define SPIFC_A1_TWHSL GENMASK(7, 0)
+
+#define SPIFC_A1_DBUF_CTRL_REG 0x240
+#define SPIFC_A1_DBUF_DIR BIT(31)
+#define SPIFC_A1_DBUF_AUTO_UPDATE_ADDR BIT(30)
+#define SPIFC_A1_DBUF_ADDR GENMASK(7, 0)
+
+#define SPIFC_A1_DBUF_DATA_REG 0x244
+
+#define SPIFC_A1_USER_DBUF_ADDR_REG 0x248
+
+#define SPIFC_A1_BUFFER_SIZE 512U
+
+#define SPIFC_A1_MAX_HZ 200000000
+#define SPIFC_A1_MIN_HZ 1000000
+
+#define SPIFC_A1_USER_CMD(op) ( \
+ SPIFC_A1_USER_CMD_ENABLE | \
+ FIELD_PREP(SPIFC_A1_USER_CMD_CODE, (op)->cmd.opcode) | \
+ FIELD_PREP(SPIFC_A1_USER_CMD_MODE, ilog2((op)->cmd.buswidth)))
+
+#define SPIFC_A1_USER_ADDR(op) ( \
+ SPIFC_A1_USER_ADDR_ENABLE | \
+ FIELD_PREP(SPIFC_A1_USER_ADDR_MODE, ilog2((op)->addr.buswidth)) | \
+ FIELD_PREP(SPIFC_A1_USER_ADDR_BYTES, (op)->addr.nbytes - 1))
+
+#define SPIFC_A1_USER_DUMMY(op) ( \
+ SPIFC_A1_USER_DUMMY_ENABLE | \
+ FIELD_PREP(SPIFC_A1_USER_DUMMY_MODE, ilog2((op)->dummy.buswidth)) | \
+ FIELD_PREP(SPIFC_A1_USER_DUMMY_CLK_SYCLES, (op)->dummy.nbytes << 3))
+
+#define SPIFC_A1_TSLCH_VAL FIELD_PREP(SPIFC_A1_TSLCH, 1)
+#define SPIFC_A1_TCLSH_VAL FIELD_PREP(SPIFC_A1_TCLSH, 1)
+#define SPIFC_A1_TSHWL_VAL FIELD_PREP(SPIFC_A1_TSHWL, 7)
+#define SPIFC_A1_TSHSL2_VAL FIELD_PREP(SPIFC_A1_TSHSL2, 7)
+#define SPIFC_A1_TSHSL1_VAL FIELD_PREP(SPIFC_A1_TSHSL1, 7)
+#define SPIFC_A1_TWHSL_VAL FIELD_PREP(SPIFC_A1_TWHSL, 2)
+#define SPIFC_A1_ACTIMING0_VAL (SPIFC_A1_TSLCH_VAL | SPIFC_A1_TCLSH_VAL | \
+ SPIFC_A1_TSHWL_VAL | SPIFC_A1_TSHSL2_VAL | \
+ SPIFC_A1_TSHSL1_VAL | SPIFC_A1_TWHSL_VAL)
+
+struct amlogic_spifc_a1 {
+ struct clk clk;
+ void __iomem *base;
+ u32 curr_speed_hz;
+};
+
+static int amlogic_spifc_a1_request(struct amlogic_spifc_a1 *spifc, bool read)
+{
+ u32 mask = SPIFC_A1_USER_REQUEST_FINISH |
+ (read ? SPIFC_A1_USER_DATA_UPDATED : 0);
+ u32 val;
+
+ writel(SPIFC_A1_USER_REQUEST_ENABLE,
+ spifc->base + SPIFC_A1_USER_CTRL0_REG);
+
+ return readl_poll_timeout(spifc->base + SPIFC_A1_USER_CTRL0_REG,
+ val, (val & mask) == mask,
+ 200 * USEC_PER_MSEC);
+}
+
+static void amlogic_spifc_a1_drain_buffer(struct amlogic_spifc_a1 *spifc,
+ char *buf, u32 len)
+{
+ u32 data;
+ const u32 count = len / sizeof(data);
+ const u32 pad = len % sizeof(data);
+
+ writel(SPIFC_A1_DBUF_AUTO_UPDATE_ADDR,
+ spifc->base + SPIFC_A1_DBUF_CTRL_REG);
+ ioread32_rep(spifc->base + SPIFC_A1_DBUF_DATA_REG, buf, count);
+
+ if (pad) {
+ data = readl(spifc->base + SPIFC_A1_DBUF_DATA_REG);
+ memcpy(buf + len - pad, &data, pad);
+ }
+}
+
+static void amlogic_spifc_a1_fill_buffer(struct amlogic_spifc_a1 *spifc,
+ const char *buf, u32 len)
+{
+ u32 data;
+ const u32 count = len / sizeof(data);
+ const u32 pad = len % sizeof(data);
+
+ writel(SPIFC_A1_DBUF_DIR | SPIFC_A1_DBUF_AUTO_UPDATE_ADDR,
+ spifc->base + SPIFC_A1_DBUF_CTRL_REG);
+ iowrite32_rep(spifc->base + SPIFC_A1_DBUF_DATA_REG, buf, count);
+
+ if (pad) {
+ memcpy(&data, buf + len - pad, pad);
+ writel(data, spifc->base + SPIFC_A1_DBUF_DATA_REG);
+ }
+}
+
+static void amlogic_spifc_a1_user_init(struct amlogic_spifc_a1 *spifc)
+{
+ writel(0, spifc->base + SPIFC_A1_USER_CTRL0_REG);
+ writel(0, spifc->base + SPIFC_A1_USER_CTRL1_REG);
+ writel(0, spifc->base + SPIFC_A1_USER_CTRL2_REG);
+ writel(0, spifc->base + SPIFC_A1_USER_CTRL3_REG);
+}
+
+static void amlogic_spifc_a1_set_cmd(struct amlogic_spifc_a1 *spifc,
+ u32 cmd_cfg)
+{
+ u32 val;
+
+ val = readl(spifc->base + SPIFC_A1_USER_CTRL1_REG);
+ val &= ~(SPIFC_A1_USER_CMD_MODE | SPIFC_A1_USER_CMD_CODE);
+ val |= cmd_cfg;
+ writel(val, spifc->base + SPIFC_A1_USER_CTRL1_REG);
+}
+
+static void amlogic_spifc_a1_set_addr(struct amlogic_spifc_a1 *spifc, u32 addr,
+ u32 addr_cfg)
+{
+ u32 val;
+
+ writel(addr, spifc->base + SPIFC_A1_USER_ADDR_REG);
+
+ val = readl(spifc->base + SPIFC_A1_USER_CTRL1_REG);
+ val &= ~(SPIFC_A1_USER_ADDR_MODE | SPIFC_A1_USER_ADDR_BYTES);
+ val |= addr_cfg;
+ writel(val, spifc->base + SPIFC_A1_USER_CTRL1_REG);
+}
+
+static void amlogic_spifc_a1_set_dummy(struct amlogic_spifc_a1 *spifc,
+ u32 dummy_cfg)
+{
+ u32 val = readl(spifc->base + SPIFC_A1_USER_CTRL2_REG);
+
+ val &= ~(SPIFC_A1_USER_DUMMY_MODE | SPIFC_A1_USER_DUMMY_CLK_SYCLES);
+ val |= dummy_cfg;
+ writel(val, spifc->base + SPIFC_A1_USER_CTRL2_REG);
+}
+
+static int amlogic_spifc_a1_read(struct amlogic_spifc_a1 *spifc, void *buf,
+ u32 size, u32 mode)
+{
+ u32 val = readl(spifc->base + SPIFC_A1_USER_CTRL3_REG);
+ int ret;
+
+ val &= ~(SPIFC_A1_USER_DIN_MODE | SPIFC_A1_USER_DIN_BYTES);
+ val |= SPIFC_A1_USER_DIN_ENABLE;
+ val |= FIELD_PREP(SPIFC_A1_USER_DIN_MODE, mode);
+ val |= FIELD_PREP(SPIFC_A1_USER_DIN_BYTES, size);
+ writel(val, spifc->base + SPIFC_A1_USER_CTRL3_REG);
+
+ ret = amlogic_spifc_a1_request(spifc, true);
+ if (!ret)
+ amlogic_spifc_a1_drain_buffer(spifc, buf, size);
+
+ return ret;
+}
+
+static int amlogic_spifc_a1_write(struct amlogic_spifc_a1 *spifc,
+ const void *buf, u32 size, u32 mode)
+{
+ u32 val;
+
+ amlogic_spifc_a1_fill_buffer(spifc, buf, size);
+
+ val = readl(spifc->base + SPIFC_A1_USER_CTRL1_REG);
+ val &= ~(SPIFC_A1_USER_DOUT_MODE | SPIFC_A1_USER_DOUT_BYTES);
+ val |= FIELD_PREP(SPIFC_A1_USER_DOUT_MODE, mode);
+ val |= FIELD_PREP(SPIFC_A1_USER_DOUT_BYTES, size);
+ val |= SPIFC_A1_USER_DOUT_ENABLE;
+ writel(val, spifc->base + SPIFC_A1_USER_CTRL1_REG);
+
+ return amlogic_spifc_a1_request(spifc, false);
+}
+
+static int amlogic_spifc_a1_set_freq(struct amlogic_spifc_a1 *spifc, u32 freq)
+{
+ int ret;
+
+ if (freq == spifc->curr_speed_hz)
+ return 0;
+
+ ret = clk_set_rate(&spifc->clk, freq);
+ if (ret)
+ return ret;
+
+ spifc->curr_speed_hz = freq;
+ return 0;
+}
+
+static int amlogic_spifc_a1_exec_op(struct spi_slave *slave,
+ const struct spi_mem_op *op)
+{
+ struct amlogic_spifc_a1 *spifc = dev_get_priv(slave->dev->parent);
+ size_t data_size = op->data.nbytes;
+ int ret;
+
+ ret = amlogic_spifc_a1_set_freq(spifc, slave->max_hz);
+ if (ret)
+ return ret;
+
+ amlogic_spifc_a1_user_init(spifc);
+ amlogic_spifc_a1_set_cmd(spifc, SPIFC_A1_USER_CMD(op));
+
+ if (op->addr.nbytes)
+ amlogic_spifc_a1_set_addr(spifc, op->addr.val,
+ SPIFC_A1_USER_ADDR(op));
+
+ if (op->dummy.nbytes)
+ amlogic_spifc_a1_set_dummy(spifc, SPIFC_A1_USER_DUMMY(op));
+
+ if (data_size) {
+ u32 mode = ilog2(op->data.buswidth);
+
+ writel(0, spifc->base + SPIFC_A1_USER_DBUF_ADDR_REG);
+
+ if (op->data.dir == SPI_MEM_DATA_IN)
+ ret = amlogic_spifc_a1_read(spifc, op->data.buf.in,
+ data_size, mode);
+ else
+ ret = amlogic_spifc_a1_write(spifc, op->data.buf.out,
+ data_size, mode);
+ } else {
+ ret = amlogic_spifc_a1_request(spifc, false);
+ }
+
+ return ret;
+}
+
+static int amlogic_spifc_a1_adjust_op_size(struct spi_slave *slave,
+ struct spi_mem_op *op)
+{
+ op->data.nbytes = min(op->data.nbytes, SPIFC_A1_BUFFER_SIZE);
+ return 0;
+}
+
+static void amlogic_spifc_a1_hw_init(struct amlogic_spifc_a1 *spifc)
+{
+ u32 regv;
+
+ regv = readl(spifc->base + SPIFC_A1_AHB_REQ_CTRL_REG);
+ regv &= ~(SPIFC_A1_AHB_REQ_ENABLE);
+ writel(regv, spifc->base + SPIFC_A1_AHB_REQ_CTRL_REG);
+
+ regv = readl(spifc->base + SPIFC_A1_AHB_CTRL_REG);
+ regv &= ~(SPIFC_A1_AHB_BUS_EN);
+ writel(regv, spifc->base + SPIFC_A1_AHB_CTRL_REG);
+
+ writel(SPIFC_A1_ACTIMING0_VAL, spifc->base + SPIFC_A1_ACTIMING0_REG);
+
+ writel(0, spifc->base + SPIFC_A1_USER_DBUF_ADDR_REG);
+}
+
+static const struct spi_controller_mem_ops amlogic_spifc_a1_mem_ops = {
+ .exec_op = amlogic_spifc_a1_exec_op,
+ .adjust_op_size = amlogic_spifc_a1_adjust_op_size,
+};
+
+static int amlogic_spifc_a1_probe(struct udevice *dev)
+{
+ struct amlogic_spifc_a1 *spifc = dev_get_priv(dev);
+ int ret;
+ struct udevice *bus = dev;
+
+ spifc->base = dev_read_addr_ptr(dev);
+ if (!spifc->base)
+ return -EINVAL;
+
+ ret = clk_get_by_index(bus, 0, &spifc->clk);
+ if (ret) {
+ pr_err("can't get clk spifc_gate!\n");
+ return ret;
+ }
+
+ ret = clk_enable(&spifc->clk);
+ if (ret) {
+ pr_err("enable clk fail\n");
+ return ret;
+ }
+
+ amlogic_spifc_a1_hw_init(spifc);
+
+ return 0;
+}
+
+static int amlogic_spifc_a1_remove(struct udevice *dev)
+{
+ struct amlogic_spifc_a1 *spifc = dev_get_priv(dev);
+
+ clk_free(&spifc->clk);
+
+ return 0;
+}
+
+static const struct udevice_id meson_spifc_ids[] = {
+ { .compatible = "amlogic,a1-spifc", },
+ { }
+};
+
+int amlogic_spifc_a1_set_speed(struct udevice *bus, uint hz)
+{
+ return 0;
+}
+
+int amlogic_spifc_a1_set_mode(struct udevice *bus, uint mode)
+{
+ return 0;
+}
+
+static const struct dm_spi_ops amlogic_spifc_a1_ops = {
+ .mem_ops = &amlogic_spifc_a1_mem_ops,
+ .set_speed = amlogic_spifc_a1_set_speed,
+ .set_mode = amlogic_spifc_a1_set_mode,
+};
+
+U_BOOT_DRIVER(meson_spifc_a1) = {
+ .name = "meson_spifc_a1",
+ .id = UCLASS_SPI,
+ .of_match = meson_spifc_ids,
+ .ops = &amlogic_spifc_a1_ops,
+ .probe = amlogic_spifc_a1_probe,
+ .remove = amlogic_spifc_a1_remove,
+ .priv_auto = sizeof(struct amlogic_spifc_a1),
+};
diff --git a/drivers/spi/mtk_spim.c b/drivers/spi/mtk_spim.c
index 418e586b91d..90f4c3cecb9 100644
--- a/drivers/spi/mtk_spim.c
+++ b/drivers/spi/mtk_spim.c
@@ -409,7 +409,7 @@ static int mtk_spim_transfer_wait(struct spi_slave *slave,
{
struct udevice *bus = dev_get_parent(slave->dev);
struct mtk_spim_priv *priv = dev_get_priv(bus);
- u32 sck_l, sck_h, clk_count, reg;
+ u32 pll_clk, sck_l, sck_h, clk_count, reg;
ulong us = 1;
int ret = 0;
@@ -418,11 +418,12 @@ static int mtk_spim_transfer_wait(struct spi_slave *slave,
else
clk_count = op->data.nbytes;
+ pll_clk = priv->pll_clk_rate;
sck_l = readl(priv->base + SPI_CFG2_REG) >> SPI_CFG2_SCK_LOW_OFFSET;
sck_h = readl(priv->base + SPI_CFG2_REG) & SPI_CFG2_SCK_HIGH_MASK;
- do_div(priv->pll_clk_rate, sck_l + sck_h + 2);
+ do_div(pll_clk, sck_l + sck_h + 2);
- us = CLK_TO_US(priv->pll_clk_rate, clk_count * 8);
+ us = CLK_TO_US(pll_clk, clk_count * 8);
us += 1000 * 1000; /* 1s tolerance */
if (us > UINT_MAX)
diff --git a/drivers/spi/nxp_fspi.c b/drivers/spi/nxp_fspi.c
index 579d6bac9b1..5db27f9ae2c 100644
--- a/drivers/spi/nxp_fspi.c
+++ b/drivers/spi/nxp_fspi.c
@@ -927,6 +927,13 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f)
fspi_writel(f, FSPI_AHBCR_PREF_EN | FSPI_AHBCR_RDADDROPT,
base + FSPI_AHBCR);
+ /* Reset the flashx control1 registers */
+ reg = FSPI_FLSHXCR1_TCSH(0x3) | FSPI_FLSHXCR1_TCSS(0x3);
+ fspi_writel(f, reg, base + FSPI_FLSHA1CR1);
+ fspi_writel(f, reg, base + FSPI_FLSHA2CR1);
+ fspi_writel(f, reg, base + FSPI_FLSHB1CR1);
+ fspi_writel(f, reg, base + FSPI_FLSHB2CR1);
+
/* 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);
diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c
index ff7b55f8707..5cce6baa621 100644
--- a/drivers/spi/omap3_spi.c
+++ b/drivers/spi/omap3_spi.c
@@ -6,7 +6,7 @@
* Copyright (C) 2010 Dirk Behme <dirk.behme@googlemail.com>
*
* Driver for McSPI controller on OMAP3. Based on davinci_spi.c
- * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2009 Texas Instruments Incorporated - https://www.ti.com/
*
* Copyright (C) 2007 Atmel Corporation
*
diff --git a/drivers/spi/spi-mem-nodm.c b/drivers/spi/spi-mem-nodm.c
index 77ddb19a9f3..6d9ab61769a 100644
--- a/drivers/spi/spi-mem-nodm.c
+++ b/drivers/spi/spi-mem-nodm.c
@@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
*/
+#include <errno.h>
#include <log.h>
#include <malloc.h>
#include <spi.h>
diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c
index ec59ef58044..a323994fb2d 100644
--- a/drivers/spi/zynqmp_gqspi.c
+++ b/drivers/spi/zynqmp_gqspi.c
@@ -5,6 +5,8 @@
* Xilinx ZynqMP Generic Quad-SPI(QSPI) controller driver(master mode only)
*/
+#define LOG_CATEGORY UCLASS_SPI
+
#include <common.h>
#include <cpu_func.h>
#include <log.h>
@@ -192,8 +194,6 @@ static int zynqmp_qspi_of_to_plat(struct udevice *bus)
{
struct zynqmp_qspi_plat *plat = dev_get_plat(bus);
- debug("%s\n", __func__);
-
plat->regs = (struct zynqmp_qspi_regs *)(dev_read_addr(bus) +
GQSPI_REG_OFFSET);
plat->dma_regs = (struct zynqmp_qspi_dma_regs *)
@@ -250,7 +250,7 @@ static u32 zynqmp_qspi_genfifo_mode(u8 buswidth)
case 4:
return GQSPI_SPI_MODE_QSPI;
default:
- debug("Unsupported bus width %u\n", buswidth);
+ log_warning("Unsupported bus width %u\n", buswidth);
return GQSPI_SPI_MODE_SPI;
}
}
@@ -262,6 +262,8 @@ static void zynqmp_qspi_fill_gen_fifo(struct zynqmp_qspi_priv *priv,
u32 config_reg, ier;
int ret = 0;
+ log_content("%s, GFIFO_CMD: 0x%X\n", __func__, gqspi_fifo_reg);
+
writel(gqspi_fifo_reg, &regs->genfifo);
config_reg = readl(&regs->confr);
@@ -278,7 +280,7 @@ static void zynqmp_qspi_fill_gen_fifo(struct zynqmp_qspi_priv *priv,
ret = wait_for_bit_le32(&regs->isr, GQSPI_IXR_GFEMTY_MASK, 1,
GQSPI_TIMEOUT, 1);
if (ret)
- printf("%s Timeout\n", __func__);
+ log_warning("%s, Timeout\n", __func__);
}
@@ -286,6 +288,8 @@ static void zynqmp_qspi_chipselect(struct zynqmp_qspi_priv *priv, int is_on)
{
u32 gqspi_fifo_reg = 0;
+ log_debug("%s, assert: %d\r\n", __func__, is_on);
+
if (is_on) {
gqspi_fifo_reg = zynqmp_qspi_bus_select(priv);
gqspi_fifo_reg |= GQSPI_SPI_MODE_SPI |
@@ -295,8 +299,6 @@ static void zynqmp_qspi_chipselect(struct zynqmp_qspi_priv *priv, int is_on)
gqspi_fifo_reg |= GQSPI_IMD_DATA_CS_DEASSERT;
}
- debug("GFIFO_CMD_CS: 0x%x\n", gqspi_fifo_reg);
-
zynqmp_qspi_fill_gen_fifo(priv, gqspi_fifo_reg);
}
@@ -311,8 +313,8 @@ static void zynqmp_qspi_set_tapdelay(struct udevice *bus, u32 baudrateval)
clk_rate = plat->frequency;
reqhz = (clk_rate / (GQSPI_BAUD_DIV_SHIFT << baudrateval));
- debug("%s, req_hz:%d, clk_rate:%d, baudrateval:%d\n",
- __func__, reqhz, clk_rate, baudrateval);
+ log_debug("%s, clk_rate:%d, baudrateval:%d, bus_clk: %d\n",
+ __func__, clk_rate, baudrateval, reqhz);
if (!(IS_ENABLED(CONFIG_ARCH_VERSAL) ||
IS_ENABLED(CONFIG_ARCH_VERSAL_NET))) {
@@ -362,7 +364,8 @@ static int zynqmp_qspi_set_speed(struct udevice *bus, uint speed)
u32 confr;
u8 baud_rate_val = 0;
- debug("%s\n", __func__);
+ log_debug("%s, Speed: %d, Max: %d\n", __func__, speed, plat->frequency);
+
if (speed > plat->frequency)
speed = plat->frequency;
@@ -383,9 +386,8 @@ static int zynqmp_qspi_set_speed(struct udevice *bus, uint speed)
confr &= ~GQSPI_BAUD_DIV_MASK;
confr |= (baud_rate_val << 3);
writel(confr, &regs->confr);
- zynqmp_qspi_set_tapdelay(bus, baud_rate_val);
- debug("regs=%p, speed=%d\n", priv->regs, plat->speed_hz);
+ zynqmp_qspi_set_tapdelay(bus, baud_rate_val);
}
return 0;
@@ -399,8 +401,6 @@ static int zynqmp_qspi_probe(struct udevice *bus)
unsigned long clock;
int ret;
- debug("%s: bus:%p, priv:%p\n", __func__, bus, priv);
-
priv->regs = plat->regs;
priv->dma_regs = plat->dma_regs;
priv->io_mode = plat->io_mode;
@@ -416,7 +416,6 @@ static int zynqmp_qspi_probe(struct udevice *bus)
dev_err(bus, "failed to get rate\n");
return clock;
}
- debug("%s: CLK %ld\n", __func__, clock);
ret = clk_enable(&clk);
if (ret) {
@@ -429,6 +428,8 @@ static int zynqmp_qspi_probe(struct udevice *bus)
/* init the zynq spi hw */
zynqmp_qspi_init_hw(priv);
+ log_debug("%s, Rerence clock frequency: %ld\n", __func__, clock);
+
return 0;
}
@@ -438,7 +439,8 @@ static int zynqmp_qspi_set_mode(struct udevice *bus, uint mode)
struct zynqmp_qspi_regs *regs = priv->regs;
u32 confr;
- debug("%s\n", __func__);
+ log_debug("%s, 0x%X\n", __func__, mode);
+
/* Set the SPI Clock phase and polarities */
confr = readl(&regs->confr);
confr &= ~(GQSPI_CONFIG_CPHA_MASK | GQSPI_CONFIG_CPOL_MASK);
@@ -461,16 +463,11 @@ static int zynqmp_qspi_fill_tx_fifo(struct zynqmp_qspi_priv *priv, u32 size)
u32 *buf = (u32 *)priv->tx_buf;
u32 len = size;
- debug("TxFIFO: 0x%x, size: 0x%x\n", readl(&regs->isr),
- size);
-
while (size) {
ret = wait_for_bit_le32(&regs->isr, GQSPI_IXR_TXNFULL_MASK, 1,
GQSPI_TIMEOUT, 1);
- if (ret) {
- printf("%s: Timeout\n", __func__);
- return ret;
- }
+ if (ret)
+ return log_msg_ret("Timeout\n", ret);
if (size >= 4) {
writel(*buf, &regs->txd0r);
@@ -501,10 +498,8 @@ static int zynqmp_qspi_fill_tx_fifo(struct zynqmp_qspi_priv *priv, u32 size)
ret = wait_for_bit_le32(&regs->isr, GQSPI_IXR_TXFIFOEMPTY_MASK, 1,
GQSPI_TIMEOUT, 1);
- if (ret) {
- printf("%s: Timeout\n", __func__);
- return ret;
- }
+ if (ret)
+ return log_msg_ret("Timeout\n", ret);
priv->tx_buf += len;
return 0;
@@ -516,6 +511,9 @@ static void zynqmp_qspi_genfifo_cmd(struct zynqmp_qspi_priv *priv)
u32 gen_fifo_cmd;
u8 i, dummy_cycles, addr;
+ log_debug("%s, opcode: 0x%0X, addr.nbytes: %d, dummy.mbytes: %d\r\n",
+ __func__, op->cmd.opcode, op->addr.nbytes, op->dummy.nbytes);
+
/* Send opcode */
gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(op->cmd.buswidth);
@@ -532,8 +530,6 @@ static void zynqmp_qspi_genfifo_cmd(struct zynqmp_qspi_priv *priv)
gen_fifo_cmd |= GQSPI_GFIFO_TX;
gen_fifo_cmd |= addr;
- debug("GFIFO_CMD_Cmd = 0x%x\n", gen_fifo_cmd);
-
zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
}
@@ -583,6 +579,8 @@ static int zynqmp_qspi_genfifo_fill_tx(struct zynqmp_qspi_priv *priv)
u32 len;
int ret = 0;
+ log_debug("%s, length: %d\r\n", __func__, priv->len);
+
gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(priv->op->data.buswidth);
gen_fifo_cmd |= GQSPI_GFIFO_TX | GQSPI_GFIFO_DATA_XFR_MASK;
@@ -591,8 +589,6 @@ static int zynqmp_qspi_genfifo_fill_tx(struct zynqmp_qspi_priv *priv)
len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd);
zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
- debug("GFIFO_CMD_TX:0x%x\n", gen_fifo_cmd);
-
if (gen_fifo_cmd & GQSPI_GFIFO_EXP_MASK)
ret = zynqmp_qspi_fill_tx_fifo(priv, 1 << len);
else
@@ -608,7 +604,6 @@ static int zynqmp_qspi_start_io(struct zynqmp_qspi_priv *priv,
u32 gen_fifo_cmd, u32 *buf)
{
u32 len;
- u32 actuallen = priv->len;
u32 config_reg, ier, isr;
u32 timeout = GQSPI_TIMEOUT;
struct zynqmp_qspi_regs *regs = priv->regs;
@@ -623,7 +618,7 @@ static int zynqmp_qspi_start_io(struct zynqmp_qspi_priv *priv,
else
priv->bytes_to_receive = len;
zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
- debug("GFIFO_CMD_RX:0x%x\n", gen_fifo_cmd);
+
/* Manual start */
config_reg = readl(&regs->confr);
config_reg |= GQSPI_STRT_GEN_FIFO;
@@ -652,13 +647,8 @@ static int zynqmp_qspi_start_io(struct zynqmp_qspi_priv *priv,
}
}
- debug("buf:0x%lx, rxbuf:0x%lx, *buf:0x%x len: 0x%x\n",
- (unsigned long)buf, (unsigned long)priv->rx_buf,
- *buf, actuallen);
- if (!timeout) {
- printf("IO timeout: %d\n", readl(&regs->isr));
- return -1;
- }
+ if (!timeout)
+ return log_msg_retz("Timeout\n", timeout);
}
return 0;
@@ -695,26 +685,18 @@ static int zynqmp_qspi_start_dma(struct zynqmp_qspi_priv *priv,
while (priv->len) {
zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd);
zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
-
- debug("GFIFO_CMD_RX:0x%x\n", gen_fifo_cmd);
}
ret = wait_for_bit_le32(&dma_regs->dmaisr,
GQSPI_DMA_DST_I_STS_DONE, 1,
GQSPI_TIMEOUT, 1);
- if (ret) {
- printf("DMA Timeout:0x%x\n", readl(&dma_regs->dmaisr));
- return -ETIMEDOUT;
- }
+ if (ret)
+ return log_msg_ret("Timeout:\n", ret);
invalidate_dcache_range(addr, addr + size);
writel(GQSPI_DMA_DST_I_STS_DONE, &dma_regs->dmaisr);
- debug("buf:0x%lx, rxbuf:0x%lx, *buf:0x%x len: 0x%x\n",
- (unsigned long)buf, (unsigned long)priv->rx_buf, *buf,
- actuallen);
-
if (buf != priv->rx_buf)
memcpy(priv->rx_buf, buf, actuallen);
@@ -731,6 +713,8 @@ static int zynqmp_qspi_genfifo_fill_rx(struct zynqmp_qspi_priv *priv)
u32 *buf;
u32 actuallen = priv->len;
+ log_debug("%s, length: %d\r\n", __func__, priv->len);
+
gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(priv->op->data.buswidth);
gen_fifo_cmd |= GQSPI_GFIFO_RX | GQSPI_GFIFO_DATA_XFR_MASK;
diff --git a/drivers/sysinfo/Kconfig b/drivers/sysinfo/Kconfig
index e35f7cb1791..2030e4babc9 100644
--- a/drivers/sysinfo/Kconfig
+++ b/drivers/sysinfo/Kconfig
@@ -8,6 +8,13 @@ menuconfig SYSINFO
if SYSINFO
+config SYSINFO_EXTRA
+ bool "Show extra information on startup"
+ help
+ Enable this to see extra information on startup. Normally only the
+ model is shown, but with this option the vendor and any prior-stage
+ firmware's version and date are shown as well.
+
config SPL_SYSINFO
depends on SPL_DM
bool "Enable board driver support in SPL"
diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig
index bdbe2a95364..0e52f996283 100644
--- a/drivers/sysreset/Kconfig
+++ b/drivers/sysreset/Kconfig
@@ -74,6 +74,13 @@ config SYSRESET_GPIO
example on Microblaze where reset logic can be controlled via GPIO
pin which triggers cpu reset.
+config SYSRESET_MAX77663
+ bool "Enable support for MAX77663 PMIC System Reset"
+ depends on DM_PMIC_MAX77663
+ select SYSRESET_CMD_POWEROFF if CMD_POWEROFF
+ help
+ Enable system power management functions found in MAX77663 PMIC.
+
config SYSRESET_MICROBLAZE
bool "Enable support for Microblaze soft reset"
depends on MICROBLAZE
@@ -102,6 +109,13 @@ config SYSRESET_SPL_AT91
This enables the system reset driver support for Microchip/Atmel
SoCs in SPL.
+config SYSRESET_PALMAS
+ bool "Enable support for PALMAS System Reset"
+ depends on PMIC_PALMAS
+ select SYSRESET_CMD_POWEROFF if CMD_POWEROFF
+ help
+ Enable system power management functions found in PLAMAS PMIC family.
+
config SYSRESET_PSCI
bool "Enable support for PSCI System Reset"
depends on ARM_PSCI_FW
@@ -137,6 +151,12 @@ config SYSRESET_SOCFPGA_SOC64
This enables the system reset driver support for Intel SOCFPGA
SoC64 SoCs.
+config SYSRESET_TEGRA
+ bool "Tegra PMC system reset driver"
+ depends on ARCH_TEGRA
+ help
+ This enables the system reset ability of PMC used in Tegra SoCs.
+
config SYSRESET_TI_SCI
bool "TI System Control Interface (TI SCI) system reset driver"
depends on TI_SCI_PROTOCOL
@@ -144,6 +164,22 @@ config SYSRESET_TI_SCI
This enables the system reset driver support over TI System Control
Interface available on some new TI's SoCs.
+config SYSRESET_TPS65910
+ bool "Enable support for TPS65910/TPS65911 PMIC System Reset"
+ depends on DM_PMIC_TPS65910
+ select SYSRESET_CMD_POWEROFF if CMD_POWEROFF
+ help
+ Enable system power management functions found in TPS65910/TPS65911
+ PMICs.
+
+config SYSRESET_TPS80031
+ bool "Enable support for TPS80031/TPS80032 PMIC System Reset"
+ depends on DM_PMIC_TPS80031
+ select SYSRESET_CMD_POWEROFF if CMD_POWEROFF
+ help
+ Enable system power management functions found in TPS80031/TPS80032
+ PMICs.
+
config SYSRESET_SYSCON
bool "Enable support for mfd syscon reboot driver"
select REGMAP
diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile
index 40c876764af..c9f1c625aeb 100644
--- a/drivers/sysreset/Makefile
+++ b/drivers/sysreset/Makefile
@@ -9,14 +9,19 @@ obj-$(CONFIG_ARCH_STI) += sysreset_sti.o
obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o
obj-$(CONFIG_POWEROFF_GPIO) += poweroff_gpio.o
obj-$(CONFIG_SYSRESET_GPIO) += sysreset_gpio.o
+obj-$(CONFIG_$(SPL_TPL_)SYSRESET_MAX77663) += sysreset_max77663.o
obj-$(CONFIG_SYSRESET_MPC83XX) += sysreset_mpc83xx.o
obj-$(CONFIG_SYSRESET_MICROBLAZE) += sysreset_microblaze.o
obj-$(CONFIG_SYSRESET_OCTEON) += sysreset_octeon.o
+obj-$(CONFIG_$(SPL_TPL_)SYSRESET_PALMAS) += sysreset_palmas.o
obj-$(CONFIG_SYSRESET_PSCI) += sysreset_psci.o
obj-$(CONFIG_SYSRESET_SBI) += sysreset_sbi.o
obj-$(CONFIG_SYSRESET_SOCFPGA) += sysreset_socfpga.o
obj-$(CONFIG_SYSRESET_SOCFPGA_SOC64) += sysreset_socfpga_soc64.o
+obj-$(CONFIG_SYSRESET_TEGRA) += sysreset_tegra.o
obj-$(CONFIG_SYSRESET_TI_SCI) += sysreset-ti-sci.o
+obj-$(CONFIG_$(SPL_TPL_)SYSRESET_TPS65910) += sysreset_tps65910.o
+obj-$(CONFIG_$(SPL_TPL_)SYSRESET_TPS80031) += sysreset_tps80031.o
obj-$(CONFIG_SYSRESET_SYSCON) += sysreset_syscon.o
obj-$(CONFIG_SYSRESET_WATCHDOG) += sysreset_watchdog.o
obj-$(CONFIG_SYSRESET_RESETCTL) += sysreset_resetctl.o
diff --git a/drivers/sysreset/poweroff_gpio.c b/drivers/sysreset/poweroff_gpio.c
index a5c24fd85bc..ad04e4b1a85 100644
--- a/drivers/sysreset/poweroff_gpio.c
+++ b/drivers/sysreset/poweroff_gpio.c
@@ -33,7 +33,7 @@ static int poweroff_gpio_request(struct udevice *dev, enum sysreset_t type)
int r;
if (type != SYSRESET_POWER_OFF)
- return -ENOSYS;
+ return -EPROTONOSUPPORT;
debug("GPIO poweroff\n");
diff --git a/drivers/sysreset/sysreset-ti-sci.c b/drivers/sysreset/sysreset-ti-sci.c
index 81bfd67ad99..5fc05c46cb0 100644
--- a/drivers/sysreset/sysreset-ti-sci.c
+++ b/drivers/sysreset/sysreset-ti-sci.c
@@ -2,7 +2,7 @@
/*
* Texas Instruments System Control Interface (TI SCI) system reset driver
*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
* Andreas Dannenberg <dannenberg@ti.com>
*/
diff --git a/drivers/sysreset/sysreset_max77663.c b/drivers/sysreset/sysreset_max77663.c
new file mode 100644
index 00000000000..8febcf8de6c
--- /dev/null
+++ b/drivers/sysreset/sysreset_max77663.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <i2c.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <power/pmic.h>
+#include <power/max77663.h>
+
+static int max77663_sysreset_request(struct udevice *dev,
+ enum sysreset_t type)
+{
+ int val;
+
+ val = pmic_reg_read(dev->parent, MAX77663_REG_ONOFF_CFG1);
+ if (val < 0)
+ return val;
+
+ /* clear both bits */
+ val &= ~ONOFF_SFT_RST;
+ val &= ~ONOFF_PWR_OFF;
+
+ switch (type) {
+ case SYSRESET_POWER:
+ /* MAX77663: SFT_RST > ONOFF_CFG1 */
+ pmic_reg_write(dev->parent, MAX77663_REG_ONOFF_CFG1,
+ val | ONOFF_SFT_RST);
+ break;
+ case SYSRESET_POWER_OFF:
+ /* MAX77663: PWR_OFF > ONOFF_CFG1 */
+ pmic_reg_write(dev->parent, MAX77663_REG_ONOFF_CFG1,
+ val | ONOFF_PWR_OFF);
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops max77663_sysreset = {
+ .request = max77663_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_max77663) = {
+ .id = UCLASS_SYSRESET,
+ .name = MAX77663_RST_DRIVER,
+ .ops = &max77663_sysreset,
+};
diff --git a/drivers/sysreset/sysreset_palmas.c b/drivers/sysreset/sysreset_palmas.c
new file mode 100644
index 00000000000..9e3aa403488
--- /dev/null
+++ b/drivers/sysreset/sysreset_palmas.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <i2c.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <power/pmic.h>
+#include <power/palmas.h>
+
+static int palmas_sysreset_request(struct udevice *dev,
+ enum sysreset_t type)
+{
+ struct palmas_priv *priv = dev_get_priv(dev->parent);
+ int ret;
+
+ /*
+ * Mask INT3 on second page which detects vbus
+ * or device will immediately turn on.
+ */
+ ret = dm_i2c_reg_clrset(priv->chip2, PALMAS_INT3_MASK,
+ MASK_VBUS, MASK_VBUS);
+ if (ret < 0)
+ return ret;
+
+ switch (type) {
+ case SYSRESET_POWER:
+ /* PALMAS: SW_RST > DEV_CTRL */
+ pmic_reg_write(dev->parent, PALMAS_DEV_CTRL, SW_RST);
+ break;
+ case SYSRESET_POWER_OFF:
+ /* PALMAS: DEV_OFF > DEV_CTRL */
+ pmic_reg_write(dev->parent, PALMAS_DEV_CTRL, DEV_OFF);
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops palmas_sysreset = {
+ .request = palmas_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_palmas) = {
+ .id = UCLASS_SYSRESET,
+ .name = PALMAS_RST_DRIVER,
+ .ops = &palmas_sysreset,
+};
diff --git a/drivers/sysreset/sysreset_psci.c b/drivers/sysreset/sysreset_psci.c
index a8a41528a84..aa09d0b8827 100644
--- a/drivers/sysreset/sysreset_psci.c
+++ b/drivers/sysreset/sysreset_psci.c
@@ -25,7 +25,7 @@ static int psci_sysreset_request(struct udevice *dev, enum sysreset_t type)
psci_sys_poweroff();
break;
default:
- return -ENOSYS;
+ return -EPROTONOSUPPORT;
}
return -EINPROGRESS;
diff --git a/drivers/sysreset/sysreset_sandbox.c b/drivers/sysreset/sysreset_sandbox.c
index 3750c60b9b9..c12eda81d03 100644
--- a/drivers/sysreset/sysreset_sandbox.c
+++ b/drivers/sysreset/sysreset_sandbox.c
@@ -21,7 +21,7 @@ static int sandbox_warm_sysreset_request(struct udevice *dev,
state->last_sysreset = type;
break;
default:
- return -ENOSYS;
+ return -EPROTONOSUPPORT;
}
if (!state->sysreset_allowed[type])
return -EACCES;
@@ -70,7 +70,7 @@ static int sandbox_sysreset_request(struct udevice *dev, enum sysreset_t type)
return -EACCES;
sandbox_exit();
default:
- return -ENOSYS;
+ return -EPROTONOSUPPORT;
}
if (!state->sysreset_allowed[type])
return -EACCES;
@@ -132,7 +132,7 @@ U_BOOT_DRIVER(warm_sysreset_sandbox) = {
.ops = &sandbox_warm_sysreset_ops,
};
-#if CONFIG_IS_ENABLED(OF_REAL)
+#if CONFIG_IS_ENABLED(OF_REAL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
/* This is here in case we don't have a device tree */
U_BOOT_DRVINFO(sysreset_sandbox_non_fdt) = {
.name = "sysreset_sandbox",
diff --git a/drivers/sysreset/sysreset_tegra.c b/drivers/sysreset/sysreset_tegra.c
new file mode 100644
index 00000000000..10bcd3a1873
--- /dev/null
+++ b/drivers/sysreset/sysreset_tegra.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <linux/err.h>
+#include <asm/arch-tegra/pmc.h>
+
+static int tegra_sysreset_request(struct udevice *dev,
+ enum sysreset_t type)
+{
+ u32 value;
+
+ switch (type) {
+ case SYSRESET_WARM:
+ case SYSRESET_COLD:
+ /* resets everything but scratch 0 and reset status */
+ value = tegra_pmc_readl(PMC_CNTRL);
+ value |= PMC_CNTRL_MAIN_RST;
+ tegra_pmc_writel(value, PMC_CNTRL);
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops tegra_sysreset = {
+ .request = tegra_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_tegra) = {
+ .id = UCLASS_SYSRESET,
+ .name = "sysreset_tegra",
+ .ops = &tegra_sysreset,
+};
+
+/* Link to Tegra PMC once there is a driver */
+U_BOOT_DRVINFO(sysreset_tegra) = {
+ .name = "sysreset_tegra"
+};
diff --git a/drivers/sysreset/sysreset_tps65910.c b/drivers/sysreset/sysreset_tps65910.c
new file mode 100644
index 00000000000..98da56661c0
--- /dev/null
+++ b/drivers/sysreset/sysreset_tps65910.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <i2c.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <power/pmic.h>
+#include <power/tps65910_pmic.h>
+
+static int tps65910_sysreset_request(struct udevice *dev,
+ enum sysreset_t type)
+{
+ int val;
+
+ val = pmic_reg_read(dev->parent, TPS65910_REG_DEVICE_CTRL);
+ if (val < 0)
+ return val;
+
+ /* define power-off to be sequential */
+ val |= PWR_OFF_SEQ;
+ pmic_reg_write(dev->parent, TPS65910_REG_DEVICE_CTRL, val);
+
+ val &= ~DEV_ON;
+
+ switch (type) {
+ case SYSRESET_POWER:
+ /* TPS65910: DEV_OFF_RST > DEVICE_CTRL */
+ pmic_reg_write(dev->parent, TPS65910_REG_DEVICE_CTRL,
+ val | DEV_OFF_RST);
+ break;
+ case SYSRESET_POWER_OFF:
+ /* TPS65910: DEV_OFF > DEVICE_CTRL */
+ pmic_reg_write(dev->parent, TPS65910_REG_DEVICE_CTRL,
+ val | DEV_OFF);
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops tps65910_sysreset = {
+ .request = tps65910_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_tps65910) = {
+ .id = UCLASS_SYSRESET,
+ .name = TPS65910_RST_DRIVER,
+ .ops = &tps65910_sysreset,
+};
diff --git a/drivers/sysreset/sysreset_tps80031.c b/drivers/sysreset/sysreset_tps80031.c
new file mode 100644
index 00000000000..50024fe4e79
--- /dev/null
+++ b/drivers/sysreset/sysreset_tps80031.c
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <i2c.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <power/pmic.h>
+#include <power/tps80031.h>
+
+static int tps80031_sysreset_request(struct udevice *dev,
+ enum sysreset_t type)
+{
+ switch (type) {
+ case SYSRESET_POWER:
+ /* TPS80031: SW_RESET > PHOENIX_DEV_ON */
+ pmic_reg_write(dev->parent, TPS80031_PHOENIX_DEV_ON, SW_RESET);
+ break;
+ case SYSRESET_POWER_OFF:
+ /* TPS80031: DEVOFF > PHOENIX_DEV_ON */
+ pmic_reg_write(dev->parent, TPS80031_PHOENIX_DEV_ON, DEVOFF);
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops tps80031_sysreset = {
+ .request = tps80031_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_tps80031) = {
+ .id = UCLASS_SYSRESET,
+ .name = TPS80031_RST_DRIVER,
+ .ops = &tps80031_sysreset,
+};
diff --git a/drivers/sysreset/sysreset_watchdog.c b/drivers/sysreset/sysreset_watchdog.c
index ceada2e47b5..6db5aa75b54 100644
--- a/drivers/sysreset/sysreset_watchdog.c
+++ b/drivers/sysreset/sysreset_watchdog.c
@@ -29,7 +29,7 @@ static int wdt_reboot_request(struct udevice *dev, enum sysreset_t type)
return ret;
break;
default:
- return -ENOSYS;
+ return -EPROTONOSUPPORT;
}
return -EINPROGRESS;
diff --git a/drivers/sysreset/sysreset_x86.c b/drivers/sysreset/sysreset_x86.c
index 4936fdb76c7..dc772b5ff9e 100644
--- a/drivers/sysreset/sysreset_x86.c
+++ b/drivers/sysreset/sysreset_x86.c
@@ -87,7 +87,7 @@ static int x86_sysreset_request(struct udevice *dev, enum sysreset_t type)
return ret;
return -EINPROGRESS;
default:
- return -ENOSYS;
+ return -EPROTONOSUPPORT;
}
outb(value, IO_PORT_RESET);
diff --git a/drivers/thermal/ti-bandgap.c b/drivers/thermal/ti-bandgap.c
index 0b533d4c420..0ea17a909dd 100644
--- a/drivers/thermal/ti-bandgap.c
+++ b/drivers/thermal/ti-bandgap.c
@@ -1,7 +1,7 @@
/*
* TI Bandgap temperature sensor driver
*
- * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
diff --git a/drivers/timer/timer-uclass.c b/drivers/timer/timer-uclass.c
index 0c2018bfe3b..60ff65529ab 100644
--- a/drivers/timer/timer-uclass.c
+++ b/drivers/timer/timer-uclass.c
@@ -66,13 +66,13 @@ static int timer_pre_probe(struct udevice *dev)
err = clk_get_by_index(dev, 0, &timer_clk);
if (!err) {
ret = clk_get_rate(&timer_clk);
- if (IS_ERR_VALUE(ret))
- return ret;
- uc_priv->clock_rate = ret;
- } else {
- uc_priv->clock_rate =
- dev_read_u32_default(dev, "clock-frequency", 0);
+ if (!IS_ERR_VALUE(ret)) {
+ uc_priv->clock_rate = ret;
+ return 0;
+ }
}
+
+ uc_priv->clock_rate = dev_read_u32_default(dev, "clock-frequency", 0);
}
return 0;
diff --git a/drivers/tpm/tpm2_tis_core.c b/drivers/tpm/tpm2_tis_core.c
index 985a8162198..81b9210056d 100644
--- a/drivers/tpm/tpm2_tis_core.c
+++ b/drivers/tpm/tpm2_tis_core.c
@@ -224,9 +224,6 @@ int tpm_tis_send(struct udevice *dev, const u8 *buf, size_t len)
u8 status;
int ret;
- if (!chip)
- return -ENODEV;
-
ret = tpm_tis_request_locality(dev, 0);
if (ret < 0)
return -EBUSY;
diff --git a/drivers/tpm/tpm2_tis_sandbox.c b/drivers/tpm/tpm2_tis_sandbox.c
index e4004cfcca3..d15a28d9fc8 100644
--- a/drivers/tpm/tpm2_tis_sandbox.c
+++ b/drivers/tpm/tpm2_tis_sandbox.c
@@ -22,11 +22,6 @@ enum tpm2_hierarchy {
TPM2_HIERARCHY_NB,
};
-/* Subset of supported capabilities */
-enum tpm2_capability {
- TPM_CAP_TPM_PROPERTIES = 0x6,
-};
-
/* Subset of supported properties */
#define TPM2_PROPERTIES_OFFSET 0x0000020E
@@ -38,7 +33,8 @@ enum tpm2_cap_tpm_property {
TPM2_PROPERTY_NB,
};
-#define SANDBOX_TPM_PCR_NB 1
+#define SANDBOX_TPM_PCR_NB TPM2_MAX_PCRS
+#define SANDBOX_TPM_PCR_SELECT_MAX ((SANDBOX_TPM_PCR_NB + 7) / 8)
/*
* Information about our TPM emulation. This is preserved in the sandbox
@@ -433,7 +429,7 @@ static int sandbox_tpm2_xfer(struct udevice *dev, const u8 *sendbuf,
int i, j;
/* TPM2_GetProperty */
- u32 capability, property, property_count;
+ u32 capability, property, property_count, val;
/* TPM2_PCR_Read/Extend variables */
int pcr_index = 0;
@@ -542,19 +538,32 @@ static int sandbox_tpm2_xfer(struct udevice *dev, const u8 *sendbuf,
case TPM2_CC_GET_CAPABILITY:
capability = get_unaligned_be32(sent);
sent += sizeof(capability);
- if (capability != TPM_CAP_TPM_PROPERTIES) {
- printf("Sandbox TPM only support TPM_CAPABILITIES\n");
- return TPM2_RC_HANDLE;
- }
-
property = get_unaligned_be32(sent);
sent += sizeof(property);
- property -= TPM2_PROPERTIES_OFFSET;
-
property_count = get_unaligned_be32(sent);
sent += sizeof(property_count);
- if (!property_count ||
- property + property_count > TPM2_PROPERTY_NB) {
+
+ switch (capability) {
+ case TPM2_CAP_PCRS:
+ break;
+ case TPM2_CAP_TPM_PROPERTIES:
+ if (!property_count) {
+ rc = TPM2_RC_HANDLE;
+ return sandbox_tpm2_fill_buf(recv, recv_len,
+ tag, rc);
+ }
+
+ if (property >= TPM2_PROPERTIES_OFFSET &&
+ ((property - TPM2_PROPERTIES_OFFSET) +
+ property_count > TPM2_PROPERTY_NB)) {
+ rc = TPM2_RC_HANDLE;
+ return sandbox_tpm2_fill_buf(recv, recv_len,
+ tag, rc);
+ }
+ break;
+ default:
+ printf("Sandbox TPM2 only supports TPM2_CAP_PCRS or "
+ "TPM2_CAP_TPM_PROPERTIES\n");
rc = TPM2_RC_HANDLE;
return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
}
@@ -578,18 +587,53 @@ static int sandbox_tpm2_xfer(struct udevice *dev, const u8 *sendbuf,
put_unaligned_be32(capability, recv);
recv += sizeof(capability);
- /* Give the number of properties that follow */
- put_unaligned_be32(property_count, recv);
- recv += sizeof(property_count);
-
- /* Fill with the properties */
- for (i = 0; i < property_count; i++) {
- put_unaligned_be32(TPM2_PROPERTIES_OFFSET + property +
- i, recv);
- recv += sizeof(property);
- put_unaligned_be32(tpm->properties[property + i],
- recv);
- recv += sizeof(property);
+ switch (capability) {
+ case TPM2_CAP_PCRS:
+ /* Give the number of algorithms supported - just SHA256 */
+ put_unaligned_be32(1, recv);
+ recv += sizeof(u32);
+
+ /* Give SHA256 algorithm */
+ put_unaligned_be16(TPM2_ALG_SHA256, recv);
+ recv += sizeof(u16);
+
+ /* Select the PCRs supported */
+ *recv = SANDBOX_TPM_PCR_SELECT_MAX;
+ recv++;
+
+ /* Activate all the PCR bits */
+ for (i = 0; i < SANDBOX_TPM_PCR_SELECT_MAX; ++i) {
+ *recv = 0xff;
+ recv++;
+ }
+ break;
+ case TPM2_CAP_TPM_PROPERTIES:
+ /* Give the number of properties that follow */
+ put_unaligned_be32(property_count, recv);
+ recv += sizeof(property_count);
+
+ /* Fill with the properties */
+ for (i = 0; i < property_count; i++) {
+ put_unaligned_be32(property + i, recv);
+ recv += sizeof(property);
+ if (property >= TPM2_PROPERTIES_OFFSET) {
+ val = tpm->properties[(property -
+ TPM2_PROPERTIES_OFFSET) + i];
+ } else {
+ switch (property) {
+ case TPM2_PT_PCR_COUNT:
+ val = SANDBOX_TPM_PCR_NB;
+ break;
+ default:
+ val = 0xffffffff;
+ break;
+ }
+ }
+
+ put_unaligned_be32(val, recv);
+ recv += sizeof(property);
+ }
+ break;
}
/* Add trailing \0 */
diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig
index 0e0cc58e3d6..7da46faed6b 100644
--- a/drivers/ufs/Kconfig
+++ b/drivers/ufs/Kconfig
@@ -2,7 +2,7 @@ menu "UFS Host Controller Support"
config UFS
bool "Support UFS controllers"
- depends on DM_SCSI
+ depends on SCSI
select CHARSET
help
This selects support for Universal Flash Subsystem (UFS).
@@ -15,6 +15,17 @@ 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 TI_J721E_UFS
bool "Glue Layer driver for UFS on TI J721E devices"
help
diff --git a/drivers/ufs/Makefile b/drivers/ufs/Makefile
index 4f3344fd4e4..67c42621aba 100644
--- a/drivers/ufs/Makefile
+++ b/drivers/ufs/Makefile
@@ -1,9 +1,10 @@
# SPDX-License-Identifier: GPL-2.0
#
-# Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
+# Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com
#
obj-$(CONFIG_UFS) += ufs.o ufs-uclass.o
obj-$(CONFIG_CADENCE_UFS) += cdns-platform.o
obj-$(CONFIG_TI_J721E_UFS) += ti-j721e-ufs.o
+obj-$(CONFIG_UFS_PCI) += ufs-pci.o
obj-$(CONFIG_UFS_RENESAS) += ufs-renesas.o
diff --git a/drivers/ufs/cdns-platform.c b/drivers/ufs/cdns-platform.c
index 1e62e252e7a..d1f346937c5 100644
--- a/drivers/ufs/cdns-platform.c
+++ b/drivers/ufs/cdns-platform.c
@@ -2,7 +2,7 @@
/**
* cdns-platform.c - Platform driver for Cadence UFSHCI device
*
- * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com
*/
#include <clk.h>
@@ -13,11 +13,10 @@
#include <dm/device_compat.h>
#include <linux/bitops.h>
#include <linux/err.h>
+#include <linux/time.h>
#include "ufs.h"
-#define USEC_PER_SEC 1000000L
-
#define CDNS_UFS_REG_HCLKDIV 0xFC
#define CDNS_UFS_REG_PHY_XCFGD1 0x113C
diff --git a/drivers/ufs/ti-j721e-ufs.c b/drivers/ufs/ti-j721e-ufs.c
index d875269760c..1860e0dca29 100644
--- a/drivers/ufs/ti-j721e-ufs.c
+++ b/drivers/ufs/ti-j721e-ufs.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
*/
#include <asm/io.h>
diff --git a/drivers/ufs/ufs-pci.c b/drivers/ufs/ufs-pci.c
new file mode 100644
index 00000000000..ad41358727a
--- /dev/null
+++ b/drivers/ufs/ufs-pci.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2023 tinylab.org
+ * Author: Bin Meng <bmeng@tinylab.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <pci.h>
+#include <ufs.h>
+#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;
+
+ err = ufshcd_probe(dev, NULL);
+ if (err)
+ dev_err(dev, "%s failed (ret=%d)\n", __func__, err);
+
+ return err;
+}
+
+U_BOOT_DRIVER(ufs_pci) = {
+ .name = "ufs_pci",
+ .id = UCLASS_UFS,
+ .bind = ufs_pci_bind,
+ .probe = ufs_pci_probe,
+};
+
+static struct pci_device_id ufs_supported[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_UFS) },
+ {},
+};
+
+U_BOOT_PCI_DEVICE(ufs_pci, ufs_supported);
diff --git a/drivers/ufs/ufs-uclass.c b/drivers/ufs/ufs-uclass.c
index ceea30c4a95..92fcdf4e6cb 100644
--- a/drivers/ufs/ufs-uclass.c
+++ b/drivers/ufs/ufs-uclass.c
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/**
- * ufs-uclass.c - Universal Flash Subsystem (UFS) Uclass driver
+ * ufs-uclass.c - Universal Flash Storage (UFS) Uclass driver
*
- * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com
*/
#define LOG_CATEGORY UCLASS_UFS
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c
index 7c48d57f99d..e4400f319a7 100644
--- a/drivers/ufs/ufs.c
+++ b/drivers/ufs/ufs.c
@@ -1,11 +1,11 @@
// SPDX-License-Identifier: GPL-2.0+
/**
- * ufs.c - Universal Flash Subsystem (UFS) 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 - http://www.ti.com
+ * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com
*/
#include <bouncebuf.h>
@@ -320,7 +320,7 @@ static int ufshcd_disable_tx_lcc(struct ufs_hba *hba, bool peer)
UIC_ARG_MPHY_TX_GEN_SEL_INDEX(i)),
0);
if (err) {
- dev_err(hba->dev, "%s: TX LCC Disable failed, peer = %d, lane = %d, err = %d",
+ dev_err(hba->dev, "%s: TX LCC Disable failed, peer = %d, lane = %d, err = %d\n",
__func__, peer, i, err);
break;
}
@@ -441,7 +441,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
ufshcd_enable_run_stop_reg(hba);
} else {
dev_err(hba->dev,
- "Host controller not ready to process requests");
+ "Host controller not ready to process requests\n");
err = -EIO;
goto out;
}
@@ -930,7 +930,7 @@ static int ufshcd_copy_query_response(struct ufs_hba *hba)
memcpy(hba->dev_cmd.query.descriptor, descp, resp_len);
} else {
dev_warn(hba->dev,
- "%s: Response size is bigger than buffer",
+ "%s: Response size is bigger than buffer\n",
__func__);
return -EINVAL;
}
@@ -1179,11 +1179,11 @@ static int ufshcd_read_desc_length(struct ufs_hba *hba, enum desc_idn desc_id,
&header_len);
if (ret) {
- dev_err(hba->dev, "%s: Failed to get descriptor header id %d",
+ 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",
+ 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;
@@ -1302,7 +1302,7 @@ int ufshcd_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id,
/* Sanity checks */
if (ret || !buff_len) {
- dev_err(hba->dev, "%s: Failed to get full descriptor length",
+ dev_err(hba->dev, "%s: Failed to get full descriptor length\n",
__func__);
return ret;
}
@@ -1323,14 +1323,14 @@ int ufshcd_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id,
&buff_len);
if (ret) {
- dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d",
+ 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",
+ 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;
@@ -1914,6 +1914,7 @@ 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);
@@ -1927,7 +1928,14 @@ int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops)
hba->dev = ufs_dev;
hba->ops = hba_ops;
- hba->mmio_base = dev_read_addr_ptr(ufs_dev);
+
+ 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);
@@ -1945,7 +1953,8 @@ int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops)
hba->version != UFSHCI_VERSION_11 &&
hba->version != UFSHCI_VERSION_20 &&
hba->version != UFSHCI_VERSION_21 &&
- hba->version != UFSHCI_VERSION_30)
+ hba->version != UFSHCI_VERSION_30 &&
+ hba->version != UFSHCI_VERSION_31)
dev_err(hba->dev, "invalid UFS version 0x%x\n",
hba->version);
diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h
index 9daaf03d222..816a5ce0caf 100644
--- a/drivers/ufs/ufs.h
+++ b/drivers/ufs/ufs.h
@@ -782,6 +782,7 @@ enum {
UFSHCI_VERSION_20 = 0x00000200, /* 2.0 */
UFSHCI_VERSION_21 = 0x00000210, /* 2.1 */
UFSHCI_VERSION_30 = 0x00000300, /* 3.0 */
+ UFSHCI_VERSION_31 = 0x00000310, /* 3.1 */
};
/* Interrupt disable masks */
diff --git a/drivers/usb/cdns3/cdns3-ti.c b/drivers/usb/cdns3/cdns3-ti.c
index 8958f0166bd..2e44aadea47 100644
--- a/drivers/usb/cdns3/cdns3-ti.c
+++ b/drivers/usb/cdns3/cdns3-ti.c
@@ -2,11 +2,10 @@
/**
* cdns_ti-ti.c - TI specific Glue layer for Cadence USB Controller
*
- * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com
*/
#include <common.h>
-#include <asm-generic/io.h>
#include <clk.h>
#include <dm.h>
#include <dm/device_compat.h>
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 7ca9d09824e..4b4fcd8a22e 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -2,7 +2,7 @@
/**
* core.c - DesignWare USB3 DRD Controller Core file
*
- * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
@@ -31,6 +31,7 @@
#include <linux/usb/gadget.h>
#include <linux/bitfield.h>
#include <linux/math64.h>
+#include <linux/time.h>
#include "core.h"
#include "gadget.h"
@@ -38,8 +39,6 @@
#include "linux-compat.h"
-#define NSEC_PER_SEC 1000000000L
-
static LIST_HEAD(dwc3_list);
/* -------------------------------------------------------------------------- */
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 532746dd88d..4162a682298 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -2,7 +2,7 @@
/**
* core.h - DesignWare USB3 DRD Core Header
*
- * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c
index 744fde80694..6fb2de8a5ac 100644
--- a/drivers/usb/dwc3/dwc3-generic.c
+++ b/drivers/usb/dwc3/dwc3-generic.c
@@ -610,6 +610,7 @@ static const struct udevice_id dwc3_glue_ids[] = {
{ .compatible = "rockchip,rk3328-dwc3", .data = (ulong)&rk_ops },
{ .compatible = "rockchip,rk3399-dwc3" },
{ .compatible = "rockchip,rk3568-dwc3", .data = (ulong)&rk_ops },
+ { .compatible = "rockchip,rk3588-dwc3", .data = (ulong)&rk_ops },
{ .compatible = "qcom,dwc3" },
{ .compatible = "fsl,imx8mp-dwc3", .data = (ulong)&imx8mp_ops },
{ .compatible = "fsl,imx8mq-dwc3" },
diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c
index dc5a976f71a..196035215a6 100644
--- a/drivers/usb/dwc3/dwc3-meson-g12a.c
+++ b/drivers/usb/dwc3/dwc3-meson-g12a.c
@@ -8,13 +8,13 @@
#include <common.h>
#include <log.h>
-#include <asm-generic/io.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dwc3-uboot.h>
#include <generic-phy.h>
#include <linux/delay.h>
+#include <linux/io.h>
#include <linux/printk.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@@ -29,6 +29,7 @@
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/compat.h>
+#include <dt-bindings/clock/amlogic,a1-peripherals-clkc.h>
/* USB2 Ports Control Registers */
@@ -103,10 +104,22 @@ enum {
PHY_COUNT,
};
-static const char *phy_names[PHY_COUNT] = {
+static const char *const dwc3_meson_g12a_phy_names[] = {
"usb2-phy0", "usb2-phy1", "usb3-phy0",
};
+static const char *const dwc3_meson_a1_phy_names[] = {
+ "usb2-phy0", "usb2-phy1"
+};
+
+struct dwc3_meson_g12a;
+
+struct dwc3_meson_g12a_drvdata {
+ const char *const *phy_names;
+ unsigned int phy_cnt;
+ int (*clk_init)(struct dwc3_meson_g12a *priv);
+};
+
struct dwc3_meson_g12a {
struct udevice *dev;
struct regmap *regmap;
@@ -120,6 +133,7 @@ struct dwc3_meson_g12a {
#if CONFIG_IS_ENABLED(DM_REGULATOR)
struct udevice *vbus_supply;
#endif
+ struct dwc3_meson_g12a_drvdata *drvdata;
};
#define U2P_REG_SIZE 0x20
@@ -294,10 +308,11 @@ int dwc3_meson_g12a_force_mode(struct udevice *dev, enum usb_dr_mode mode)
static int dwc3_meson_g12a_get_phys(struct dwc3_meson_g12a *priv)
{
+ struct dwc3_meson_g12a_drvdata *data = priv->drvdata;
int i, ret;
- for (i = 0 ; i < PHY_COUNT ; ++i) {
- ret = generic_phy_get_by_name(priv->dev, phy_names[i],
+ for (i = 0 ; i < data->phy_cnt; ++i) {
+ ret = generic_phy_get_by_name(priv->dev, data->phy_names[i],
&priv->phys[i]);
if (ret == -ENOENT || ret == -ENODATA)
continue;
@@ -355,18 +370,36 @@ static int dwc3_meson_g12a_clk_init(struct dwc3_meson_g12a *priv)
return 0;
}
+static int dwc3_meson_a1_clk_init(struct dwc3_meson_g12a *priv)
+{
+ int ret;
+
+ ret = clk_get_by_name(priv->dev, "usb_bus", &priv->clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&priv->clk);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static int dwc3_meson_g12a_probe(struct udevice *dev)
{
struct dwc3_meson_g12a *priv = dev_get_plat(dev);
+ struct dwc3_meson_g12a_drvdata *data =
+ (struct dwc3_meson_g12a_drvdata *)dev_get_driver_data(dev);
int ret, i;
+ priv->drvdata = data;
priv->dev = dev;
ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
if (ret)
return ret;
- ret = dwc3_meson_g12a_clk_init(priv);
+ ret = data->clk_init(priv);
if (ret)
return ret;
@@ -399,7 +432,7 @@ static int dwc3_meson_g12a_probe(struct udevice *dev)
if (ret)
return ret;
- for (i = 0 ; i < PHY_COUNT ; ++i) {
+ for (i = 0 ; i < data->phy_cnt; ++i) {
if (!priv->phys[i].dev)
continue;
@@ -408,7 +441,7 @@ static int dwc3_meson_g12a_probe(struct udevice *dev)
goto err_phy_init;
}
- for (i = 0; i < PHY_COUNT; ++i) {
+ for (i = 0; i < data->phy_cnt; ++i) {
if (!priv->phys[i].dev)
continue;
@@ -420,7 +453,7 @@ static int dwc3_meson_g12a_probe(struct udevice *dev)
return 0;
err_phy_init:
- for (i = 0 ; i < PHY_COUNT ; ++i) {
+ for (i = 0 ; i < data->phy_cnt ; ++i) {
if (!priv->phys[i].dev)
continue;
@@ -433,20 +466,21 @@ err_phy_init:
static int dwc3_meson_g12a_remove(struct udevice *dev)
{
struct dwc3_meson_g12a *priv = dev_get_plat(dev);
+ struct dwc3_meson_g12a_drvdata *data = priv->drvdata;
int i;
reset_release_all(&priv->reset, 1);
clk_release_all(&priv->clk, 1);
- for (i = 0; i < PHY_COUNT; ++i) {
+ for (i = 0; i < data->phy_cnt; ++i) {
if (!priv->phys[i].dev)
continue;
generic_phy_power_off(&priv->phys[i]);
}
- for (i = 0 ; i < PHY_COUNT ; ++i) {
+ for (i = 0 ; i < data->phy_cnt; ++i) {
if (!priv->phys[i].dev)
continue;
@@ -456,11 +490,26 @@ static int dwc3_meson_g12a_remove(struct udevice *dev)
return dm_scan_fdt_dev(dev);
}
+static const struct dwc3_meson_g12a_drvdata meson_g12a_drvdata = {
+ .phy_names = dwc3_meson_g12a_phy_names,
+ .phy_cnt = ARRAY_SIZE(dwc3_meson_g12a_phy_names),
+ .clk_init = dwc3_meson_g12a_clk_init,
+};
+
+static const struct dwc3_meson_g12a_drvdata meson_a1_drvdata = {
+ .phy_names = dwc3_meson_a1_phy_names,
+ .phy_cnt = ARRAY_SIZE(dwc3_meson_a1_phy_names),
+ .clk_init = dwc3_meson_a1_clk_init,
+};
+
static int dwc3_meson_g12a_child_pre_probe(struct udevice *dev)
{
if (ofnode_device_is_compatible(dev_ofnode(dev), "amlogic,meson-g12a-usb"))
return dwc3_meson_g12a_force_mode(dev->parent, USB_DR_MODE_PERIPHERAL);
+ if (ofnode_device_is_compatible(dev_ofnode(dev), "amlogic,meson-a1-usb"))
+ return dwc3_meson_g12a_force_mode(dev->parent, USB_DR_MODE_PERIPHERAL);
+
return 0;
}
@@ -469,11 +518,21 @@ static int dwc3_meson_g12a_child_post_remove(struct udevice *dev)
if (ofnode_device_is_compatible(dev_ofnode(dev), "amlogic,meson-g12a-usb"))
return dwc3_meson_g12a_force_mode(dev->parent, USB_DR_MODE_HOST);
+ if (ofnode_device_is_compatible(dev_ofnode(dev), "amlogic,meson-a1-usb"))
+ return dwc3_meson_g12a_force_mode(dev->parent, USB_DR_MODE_HOST);
+
return 0;
}
static const struct udevice_id dwc3_meson_g12a_ids[] = {
- { .compatible = "amlogic,meson-g12a-usb-ctrl" },
+ {
+ .compatible = "amlogic,meson-g12a-usb-ctrl",
+ .data = (ulong)&meson_g12a_drvdata,
+ },
+ {
+ .compatible = "amlogic,meson-a1-usb-ctrl",
+ .data = (ulong)&meson_a1_drvdata,
+ },
{ }
};
diff --git a/drivers/usb/dwc3/dwc3-meson-gxl.c b/drivers/usb/dwc3/dwc3-meson-gxl.c
index d56f2747b63..cbe8aaa005b 100644
--- a/drivers/usb/dwc3/dwc3-meson-gxl.c
+++ b/drivers/usb/dwc3/dwc3-meson-gxl.c
@@ -8,12 +8,12 @@
#define DEBUG
#include <common.h>
-#include <asm-generic/io.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dwc3-uboot.h>
#include <generic-phy.h>
+#include <linux/io.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <malloc.h>
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index ff4ebfb4447..4fadb4a3e20 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -2,7 +2,7 @@
/**
* dwc3-omap.c - OMAP Specific Glue layer
*
- * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 75ac993bc64..1133cf82b1a 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -2,7 +2,7 @@
/**
* ep0.c - DesignWare USB3 DRD Controller Endpoint 0 Handling
*
- * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 68cf32cd189..406d36ceafe 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2,7 +2,7 @@
/**
* gadget.c - DesignWare USB3 DRD Controller Gadget Framework Link
*
- * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index 7806ce59a27..f28a9755dcb 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -2,7 +2,7 @@
/**
* gadget.h - DesignWare USB3 DRD Gadget Header
*
- * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
index 2407f826c16..04791d4c9be 100644
--- a/drivers/usb/dwc3/io.h
+++ b/drivers/usb/dwc3/io.h
@@ -2,7 +2,7 @@
/**
* io.h - DesignWare USB3 DRD IO Header
*
- * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
diff --git a/drivers/usb/dwc3/linux-compat.h b/drivers/usb/dwc3/linux-compat.h
index 3bb0bda5a6b..563f8727cdd 100644
--- a/drivers/usb/dwc3/linux-compat.h
+++ b/drivers/usb/dwc3/linux-compat.h
@@ -2,7 +2,7 @@
/**
* linux-compat.h - DesignWare USB3 Linux Compatibiltiy Adapter Header
*
- * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com
*
* Authors: Kishon Vijay Abraham I <kishon@ti.com>
*
diff --git a/drivers/usb/dwc3/ti_usb_phy.c b/drivers/usb/dwc3/ti_usb_phy.c
index f476810763d..8ae130860f7 100644
--- a/drivers/usb/dwc3/ti_usb_phy.c
+++ b/drivers/usb/dwc3/ti_usb_phy.c
@@ -2,7 +2,7 @@
/**
* ti_usb_phy.c - USB3 and USB3 PHY programming for dwc3
*
- * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com
*
* Author: Kishon Vijay Abraham I <kishon@ti.com>
*
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 4eccc5e3370..c72a8047635 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -17,6 +17,7 @@ menuconfig USB_GADGET
bool "USB Gadget Support"
depends on DM
select DM_USB
+ imply CMD_BIND
help
USB is a master/slave protocol, organized with one master
host (such as a PC) controlling up to 127 peripheral devices.
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index f16731c8ebd..4c420747b0b 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -58,13 +58,9 @@ static void submit_request(struct usba_ep *ep, struct usba_request *req)
req->submitted = 1;
next_fifo_transaction(ep, req);
- if (req->last_transaction) {
- usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
- usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
- } else {
+ if (ep_is_control(ep))
usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
- usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
- }
+ usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
}
static void submit_next_request(struct usba_ep *ep)
@@ -890,7 +886,6 @@ restart:
if (req) {
list_del_init(&req->queue);
request_complete(ep, req, 0);
- submit_next_request(ep);
}
usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
ep->state = WAIT_FOR_SETUP;
@@ -1037,7 +1032,6 @@ static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep)
DBG(DBG_BUS, "%s: TX PK ready\n", ep->ep.name);
if (list_empty(&ep->queue)) {
- DBG(DBG_INT, "ep_irq: queue empty\n");
usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
return;
}
@@ -1051,7 +1045,6 @@ static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep)
if (req->last_transaction) {
list_del_init(&req->queue);
- submit_next_request(ep);
request_complete(ep, req, 0);
}
diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c
index 2bfacfe59f9..750d4714879 100644
--- a/drivers/usb/gadget/ci_udc.c
+++ b/drivers/usb/gadget/ci_udc.c
@@ -13,6 +13,7 @@
#include <cpu_func.h>
#include <net.h>
#include <malloc.h>
+#include <wait_bit.h>
#include <asm/byteorder.h>
#include <asm/cache.h>
#include <linux/delay.h>
@@ -354,12 +355,49 @@ static int ci_ep_enable(struct usb_ep *ep,
return 0;
}
+static int ep_disable(int num, int in)
+{
+ struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
+ unsigned int ep_bit, enable_bit;
+ int err;
+
+ if (in) {
+ ep_bit = EPT_TX(num);
+ enable_bit = CTRL_TXE;
+ } else {
+ ep_bit = EPT_RX(num);
+ enable_bit = CTRL_RXE;
+ }
+
+ /* clear primed buffers */
+ do {
+ writel(ep_bit, &udc->epflush);
+ err = wait_for_bit_le32(&udc->epflush, ep_bit, false, 1000, false);
+ if (err)
+ return err;
+ } while (readl(&udc->epstat) & ep_bit);
+
+ /* clear enable bit */
+ clrbits_le32(&udc->epctrl[num], enable_bit);
+
+ return 0;
+}
+
static int ci_ep_disable(struct usb_ep *ep)
{
struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep);
+ int num, in, err;
+
+ num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+ in = (ci_ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
+
+ err = ep_disable(num, in);
+ if (err)
+ return err;
ci_ep->desc = NULL;
ep->desc = NULL;
+ ci_ep->req_primed = false;
return 0;
}
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index 741775a7bcf..9f322c95508 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -520,7 +520,7 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
cmdbuf[req->actual] = '\0';
cmd = fastboot_handle_command(cmdbuf, response);
} else {
- pr_err("buffer overflow");
+ pr_err("buffer overflow\n");
fastboot_fail("buffer overflow", response);
}
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 1d17331cb03..c725aed3f62 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -327,6 +327,7 @@ struct fsg_common {
unsigned int short_packet_received:1;
unsigned int bad_lun_okay:1;
unsigned int running:1;
+ unsigned int eject:1;
int thread_wakeup_needed;
struct completion thread_notifier;
@@ -669,6 +670,10 @@ static int sleep_thread(struct fsg_common *common)
}
if (k == 10) {
+ /* Handle START-STOP UNIT */
+ if (common->eject)
+ return -EPIPE;
+
/* Handle CTRL+C */
if (ctrlc())
return -EPIPE;
@@ -1325,6 +1330,8 @@ static int do_start_stop(struct fsg_common *common)
return -EINVAL;
}
+ common->eject = 1;
+
return 0;
}
diff --git a/drivers/usb/gadget/f_sdp.c b/drivers/usb/gadget/f_sdp.c
index 2b3a9c5fd4c..ca2760c00d0 100644
--- a/drivers/usb/gadget/f_sdp.c
+++ b/drivers/usb/gadget/f_sdp.c
@@ -34,6 +34,7 @@
#include <spl.h>
#include <image.h>
#include <imximage.h>
+#include <imx_container.h>
#include <watchdog.h>
#define HID_REPORT_ID_MASK 0x000000ff
@@ -743,7 +744,7 @@ static ulong sdp_load_read(struct spl_load_info *load, ulong sector,
{
debug("%s: sector %lx, count %lx, buf %lx\n",
__func__, sector, count, (ulong)buf);
- memcpy(buf, (void *)(load->dev + sector), count);
+ memcpy(buf, (void *)(load->priv + sector), count);
return count;
}
@@ -843,8 +844,8 @@ static int sdp_handle_in_ep(struct spl_image_info *spl_image,
struct spl_load_info load;
debug("Found FIT\n");
- load.dev = header;
- load.bl_len = 1;
+ load.priv = header;
+ spl_set_bl_len(&load, 1);
load.read = sdp_load_read;
spl_load_simple_fit(spl_image, &load, 0,
header);
@@ -852,11 +853,12 @@ static int sdp_handle_in_ep(struct spl_image_info *spl_image,
return SDP_EXIT;
}
#endif
- if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) {
+ if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER) &&
+ valid_container_hdr((void *)header)) {
struct spl_load_info load;
- load.dev = header;
- load.bl_len = 1;
+ load.priv = header;
+ spl_set_bl_len(&load, 1);
load.read = sdp_load_read;
spl_load_imx_container(spl_image, &load, 0);
return SDP_EXIT;
diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c
index 7f73926cb3e..ba658d92296 100644
--- a/drivers/usb/gadget/udc/udc-core.c
+++ b/drivers/usb/gadget/udc/udc-core.c
@@ -2,7 +2,7 @@
/**
* udc-core.c - Core UDC Framework
*
- * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com
*
* Author: Felipe Balbi <balbi@ti.com>
*
@@ -323,6 +323,7 @@ err1:
int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
{
struct usb_udc *udc = NULL;
+ unsigned int udc_count = 0;
int ret;
if (!driver || !driver->bind || !driver->setup)
@@ -330,12 +331,22 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
mutex_lock(&udc_lock);
list_for_each_entry(udc, &udc_list, list) {
+ udc_count++;
+
/* For now we take the first one */
if (!udc->driver)
goto found;
}
- printf("couldn't find an available UDC\n");
+ if (!udc_count)
+ printf("No UDC available in the system\n");
+ else
+ /* When this happens, users should 'unbind <class> <index>'
+ * using the output of 'dm tree' and looking at the line right
+ * after the USB peripheral/device controller.
+ */
+ printf("All UDCs in use (%d available), use the unbind command\n",
+ udc_count);
mutex_unlock(&udc_lock);
return -ENODEV;
found:
diff --git a/drivers/usb/gadget/udc/udc-uclass.c b/drivers/usb/gadget/udc/udc-uclass.c
index 3e433129ace..30ee1cab066 100644
--- a/drivers/usb/gadget/udc/udc-uclass.c
+++ b/drivers/usb/gadget/udc/udc-uclass.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com
* Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
*/
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 1a883babf4c..35610ffc2b3 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -90,7 +90,7 @@ config USB_XHCI_OMAP
config USB_XHCI_PCI
bool "Support for PCI-based xHCI USB controller"
- depends on DM_USB
+ depends on DM_USB && PCI
default y if X86
help
Enables support for the PCI-based xHCI controller.
@@ -231,7 +231,6 @@ config USB_EHCI_MXS
config USB_EHCI_NPCM
bool "Support for Nuvoton NPCM on-chip EHCI USB controller"
depends on ARCH_NPCM
- default n
---help---
Enables support for the on-chip EHCI controller on
Nuvoton NPCM chips.
@@ -368,7 +367,6 @@ config USB_OHCI_DA8XX
config USB_OHCI_NPCM
bool "Support for Nuvoton NPCM on-chip OHCI USB controller"
depends on ARCH_NPCM
- default n
---help---
Enables support for the on-chip OHCI controller on
Nuvoton NPCM chips.
diff --git a/drivers/usb/host/dwc3-of-simple.c b/drivers/usb/host/dwc3-of-simple.c
index 66b3e96b007..f9df59d2e5d 100644
--- a/drivers/usb/host/dwc3-of-simple.c
+++ b/drivers/usb/host/dwc3-of-simple.c
@@ -2,7 +2,7 @@
/*
* dwc3-of-simple.c - OF glue layer for simple integrations
*
- * Copyright (c) 2015 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (c) 2015 Texas Instruments Incorporated - https://www.ti.com
*
* Author: Felipe Balbi <balbi@ti.com>
*
diff --git a/drivers/usb/host/ehci-mxs.c b/drivers/usb/host/ehci-mxs.c
index 147b2fa145d..ddf7cc2d00a 100644
--- a/drivers/usb/host/ehci-mxs.c
+++ b/drivers/usb/host/ehci-mxs.c
@@ -136,11 +136,12 @@ static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
struct usb_plat *plat = dev_get_plat(dev);
struct ehci_mxs_port *port = &priv->port;
u32 phandle, phy_reg, clk_reg, clk_id;
+ ofnode np = dev_ofnode(dev);
ofnode phy_node, clk_node;
const char *mode;
int ret;
- mode = ofnode_read_string(dev->node_, "dr_mode");
+ mode = ofnode_read_string(np, "dr_mode");
if (mode) {
if (strcmp(mode, "peripheral") == 0)
plat->init_type = USB_INIT_DEVICE;
@@ -151,12 +152,12 @@ static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
}
/* Read base address of the USB IP block */
- ret = ofnode_read_u32(dev->node_, "reg", &port->usb_regs);
+ ret = ofnode_read_u32(np, "reg", &port->usb_regs);
if (ret)
return ret;
/* Read base address of the USB PHY IP block */
- ret = ofnode_read_u32(dev->node_, "fsl,usbphy", &phandle);
+ ret = ofnode_read_u32(np, "fsl,usbphy", &phandle);
if (ret)
return ret;
@@ -235,9 +236,9 @@ static int ehci_usb_probe(struct udevice *dev)
debug("%s: No vbus supply\n", dev->name);
if (!ret && priv->vbus_supply) {
- ret = regulator_set_enable(priv->vbus_supply,
- (type == USB_INIT_DEVICE) ?
- false : true);
+ ret = regulator_set_enable_if_allowed(priv->vbus_supply,
+ (type == USB_INIT_DEVICE) ?
+ false : true);
if (ret) {
puts("Error enabling VBUS supply\n");
return ret;
@@ -264,7 +265,7 @@ static int ehci_usb_remove(struct udevice *dev)
#if CONFIG_IS_ENABLED(DM_REGULATOR)
if (priv->vbus_supply) {
- ret = regulator_set_enable(priv->vbus_supply, false);
+ ret = regulator_set_enable_if_allowed(priv->vbus_supply, false);
if (ret) {
puts("Error disabling VBUS supply\n");
return ret;
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index c8260cbdf94..b60661fe05e 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -202,6 +202,7 @@ static dma_addr_t queue_trb(struct xhci_ctrl *ctrl, struct xhci_ring *ring,
bool more_trbs_coming, unsigned int *trb_fields)
{
struct xhci_generic_trb *trb;
+ dma_addr_t addr;
int i;
trb = &ring->enqueue->generic;
@@ -211,9 +212,11 @@ static dma_addr_t queue_trb(struct xhci_ctrl *ctrl, struct xhci_ring *ring,
xhci_flush_cache((uintptr_t)trb, sizeof(struct xhci_generic_trb));
+ addr = xhci_trb_virt_to_dma(ring->enq_seg, (union xhci_trb *)trb);
+
inc_enq(ctrl, ring, more_trbs_coming);
- return xhci_trb_virt_to_dma(ring->enq_seg, (union xhci_trb *)trb);
+ return addr;
}
/**
@@ -243,7 +246,8 @@ static int prepare_ring(struct xhci_ctrl *ctrl, struct xhci_ring *ep_ring,
puts("WARN waiting for error on ep to be cleared\n");
return -EINVAL;
case EP_STATE_HALTED:
- puts("WARN halted endpoint, queueing URB anyway.\n");
+ puts("WARN endpoint is halted\n");
+ return -EINVAL;
case EP_STATE_STOPPED:
case EP_STATE_RUNNING:
debug("EP STATE RUNNING.\n");
@@ -466,7 +470,8 @@ union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected)
continue;
type = TRB_FIELD_TO_TYPE(le32_to_cpu(event->event_cmd.flags));
- if (type == expected)
+ if (type == expected ||
+ (expected == TRB_NONE && type != TRB_PORT_STATUS))
return event;
if (type == TRB_PORT_STATUS)
@@ -492,8 +497,9 @@ union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected)
if (expected == TRB_TRANSFER)
return NULL;
- printf("XHCI timeout on event type %d... cannot recover.\n", expected);
- BUG();
+ printf("XHCI timeout on event type %d...\n", expected);
+
+ return NULL;
}
/*
@@ -511,6 +517,9 @@ static void reset_ep(struct usb_device *udev, int ep_index)
printf("Resetting EP %d...\n", ep_index);
xhci_queue_command(ctrl, 0, udev->slot_id, ep_index, TRB_RESET_EP);
event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+ if (!event)
+ return;
+
field = le32_to_cpu(event->trans_event.flags);
BUG_ON(TRB_TO_SLOT_ID(field) != udev->slot_id);
xhci_acknowledge_event(ctrl);
@@ -519,6 +528,9 @@ static void reset_ep(struct usb_device *udev, int ep_index)
(void *)((uintptr_t)ring->enqueue | ring->cycle_state));
xhci_queue_command(ctrl, addr, udev->slot_id, ep_index, TRB_SET_DEQ);
event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+ if (!event)
+ return;
+
BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
!= udev->slot_id || GET_COMP_CODE(le32_to_cpu(
event->event_cmd.status)) != COMP_SUCCESS);
@@ -538,29 +550,49 @@ static void abort_td(struct usb_device *udev, int ep_index)
struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
struct xhci_ring *ring = ctrl->devs[udev->slot_id]->eps[ep_index].ring;
union xhci_trb *event;
+ xhci_comp_code comp;
+ trb_type type;
u64 addr;
u32 field;
xhci_queue_command(ctrl, 0, udev->slot_id, ep_index, TRB_STOP_RING);
- event = xhci_wait_for_event(ctrl, TRB_TRANSFER);
- field = le32_to_cpu(event->trans_event.flags);
- BUG_ON(TRB_TO_SLOT_ID(field) != udev->slot_id);
- BUG_ON(TRB_TO_EP_INDEX(field) != ep_index);
- BUG_ON(GET_COMP_CODE(le32_to_cpu(event->trans_event.transfer_len
- != COMP_STOP)));
- xhci_acknowledge_event(ctrl);
+ event = xhci_wait_for_event(ctrl, TRB_NONE);
+ if (!event)
+ return;
- event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
- BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
- != udev->slot_id || GET_COMP_CODE(le32_to_cpu(
- event->event_cmd.status)) != COMP_SUCCESS);
+ type = TRB_FIELD_TO_TYPE(le32_to_cpu(event->event_cmd.flags));
+ if (type == TRB_TRANSFER) {
+ field = le32_to_cpu(event->trans_event.flags);
+ BUG_ON(TRB_TO_SLOT_ID(field) != udev->slot_id);
+ BUG_ON(TRB_TO_EP_INDEX(field) != ep_index);
+ BUG_ON(GET_COMP_CODE(le32_to_cpu(event->trans_event.transfer_len
+ != COMP_STOP)));
+ xhci_acknowledge_event(ctrl);
+
+ event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+ if (!event)
+ return;
+ type = TRB_FIELD_TO_TYPE(le32_to_cpu(event->event_cmd.flags));
+
+ } else {
+ printf("abort_td: Expected a TRB_TRANSFER TRB first\n");
+ }
+
+ comp = GET_COMP_CODE(le32_to_cpu(event->event_cmd.status));
+ BUG_ON(type != TRB_COMPLETION ||
+ TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
+ != udev->slot_id || (comp != COMP_SUCCESS && comp
+ != COMP_CTX_STATE));
xhci_acknowledge_event(ctrl);
addr = xhci_trb_virt_to_dma(ring->enq_seg,
(void *)((uintptr_t)ring->enqueue | ring->cycle_state));
xhci_queue_command(ctrl, addr, udev->slot_id, ep_index, TRB_SET_DEQ);
event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+ if (!event)
+ return;
+
BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
!= udev->slot_id || GET_COMP_CODE(le32_to_cpu(
event->event_cmd.status)) != COMP_SUCCESS);
@@ -644,6 +676,14 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
ep_ctx = xhci_get_ep_ctx(ctrl, virt_dev->out_ctx, ep_index);
+ /*
+ * If the endpoint was halted due to a prior error, resume it before
+ * the next transfer. It is the responsibility of the upper layer to
+ * have dealt with whatever caused the error.
+ */
+ if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) == EP_STATE_HALTED)
+ reset_ep(udev, ep_index);
+
ring = virt_dev->eps[ep_index].ring;
/*
* How much data is (potentially) left before the 64KB boundary?
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 5cacf0769ec..d13cbff9b37 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -451,6 +451,9 @@ static int xhci_configure_endpoints(struct usb_device *udev, bool ctx_change)
xhci_queue_command(ctrl, in_ctx->dma, udev->slot_id, 0,
ctx_change ? TRB_EVAL_CONTEXT : TRB_CONFIG_EP);
event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+ if (!event)
+ return -ETIMEDOUT;
+
BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
!= udev->slot_id);
@@ -647,6 +650,9 @@ static int xhci_address_device(struct usb_device *udev, int root_portnr)
xhci_queue_command(ctrl, virt_dev->in_ctx->dma,
slot_id, 0, TRB_ADDR_DEV);
event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+ if (!event)
+ return -ETIMEDOUT;
+
BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags)) != slot_id);
switch (GET_COMP_CODE(le32_to_cpu(event->event_cmd.status))) {
@@ -722,6 +728,9 @@ static int _xhci_alloc_device(struct usb_device *udev)
xhci_queue_command(ctrl, 0, 0, 0, TRB_ENABLE_SLOT);
event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+ if (!event)
+ return -ETIMEDOUT;
+
BUG_ON(GET_COMP_CODE(le32_to_cpu(event->event_cmd.status))
!= COMP_SUCCESS);
diff --git a/drivers/usb/musb-new/musb_io.h b/drivers/usb/musb-new/musb_io.h
index 72a53656321..19b12f36a5c 100644
--- a/drivers/usb/musb-new/musb_io.h
+++ b/drivers/usb/musb-new/musb_io.h
@@ -14,31 +14,7 @@
#ifndef __MUSB_LINUX_PLATFORM_ARCH_H__
#define __MUSB_LINUX_PLATFORM_ARCH_H__
-#ifndef __UBOOT__
#include <linux/io.h>
-#else
-#include <asm/io.h>
-#endif
-
-#if !defined(CONFIG_ARM) && !defined(CONFIG_SUPERH) \
- && !defined(CONFIG_PPC32) \
- && !defined(CONFIG_PPC64) && !defined(CONFIG_MIPS) \
- && !defined(CONFIG_M68K)
-static inline void readsl(const void __iomem *addr, void *buf, int len)
- { insl((unsigned long)addr, buf, len); }
-static inline void readsw(const void __iomem *addr, void *buf, int len)
- { insw((unsigned long)addr, buf, len); }
-static inline void readsb(const void __iomem *addr, void *buf, int len)
- { insb((unsigned long)addr, buf, len); }
-
-static inline void writesl(const void __iomem *addr, const void *buf, int len)
- { outsl((unsigned long)addr, buf, len); }
-static inline void writesw(const void __iomem *addr, const void *buf, int len)
- { outsw((unsigned long)addr, buf, len); }
-static inline void writesb(const void __iomem *addr, const void *buf, int len)
- { outsb((unsigned long)addr, buf, len); }
-
-#endif
/* NOTE: these offsets are all in bytes */
diff --git a/drivers/usb/ulpi/omap-ulpi-viewport.c b/drivers/usb/ulpi/omap-ulpi-viewport.c
index 8d71db04a2d..1b01cd4c559 100644
--- a/drivers/usb/ulpi/omap-ulpi-viewport.c
+++ b/drivers/usb/ulpi/omap-ulpi-viewport.c
@@ -3,7 +3,7 @@
* OMAP ulpi viewport support
* Based on drivers/usb/ulpi/ulpi-viewport.c
*
- * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com
* Author: Govindraj R <govindraj.raja@ti.com>
*/
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index ab927641bb7..6f319ba0d54 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -180,7 +180,6 @@ config CONSOLE_ROTATION
config CONSOLE_TRUETYPE
bool "Support a console that uses TrueType fonts"
- select CMD_SELECT_FONT
help
TrueTrype fonts can provide outline-drawing capability rather than
needing to provide a bitmap for each font and size that is needed.
diff --git a/drivers/video/console_core.c b/drivers/video/console_core.c
index b5d0e3dceca..d17764d0b08 100644
--- a/drivers/video/console_core.c
+++ b/drivers/video/console_core.c
@@ -176,6 +176,37 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri
return ret;
}
+int draw_cursor_vertically(void **line, struct video_priv *vid_priv,
+ uint height, bool direction)
+{
+ int step, line_step, pbytes, ret;
+ uint value;
+ void *dst;
+
+ ret = check_bpix_support(vid_priv->bpix);
+ if (ret)
+ return ret;
+
+ pbytes = VNBYTES(vid_priv->bpix);
+ if (direction) {
+ step = -pbytes;
+ line_step = -vid_priv->line_length;
+ } else {
+ step = pbytes;
+ line_step = vid_priv->line_length;
+ }
+
+ value = vid_priv->colour_fg;
+
+ for (int row = 0; row < height; row++) {
+ dst = *line;
+ for (int col = 0; col < VIDCONSOLE_CURSOR_WIDTH; col++)
+ fill_pixel_and_goto_next(&dst, value, pbytes, step);
+ *line += line_step;
+ }
+ return ret;
+}
+
int console_probe(struct udevice *dev)
{
return console_set_font(dev, fonts);
diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c
index 413c7abee9e..a0231293f31 100644
--- a/drivers/video/console_normal.c
+++ b/drivers/video/console_normal.c
@@ -97,6 +97,34 @@ static int console_putc_xy(struct udevice *dev, uint x_frac, uint y, char ch)
return VID_TO_POS(fontdata->width);
}
+static int console_set_cursor_visible(struct udevice *dev, bool visible,
+ uint x, uint y, uint index)
+{
+ struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
+ struct udevice *vid = dev->parent;
+ struct video_priv *vid_priv = dev_get_uclass_priv(vid);
+ struct console_simple_priv *priv = dev_get_priv(dev);
+ struct video_fontdata *fontdata = priv->fontdata;
+ int pbytes = VNBYTES(vid_priv->bpix);
+ void *start, *line;
+
+ /* for now, this is not used outside expo */
+ if (!IS_ENABLED(CONFIG_EXPO))
+ return -ENOSYS;
+
+ x += index * fontdata->width;
+ start = vid_priv->fb + y * vid_priv->line_length + x * pbytes;
+
+ /* place the cursor 1 pixel before the start of the next char */
+ x -= 1;
+
+ line = start;
+ draw_cursor_vertically(&line, vid_priv, vc_priv->y_charsize,
+ NORMAL_DIRECTION);
+
+ return 0;
+}
+
struct vidconsole_ops console_ops = {
.putc_xy = console_putc_xy,
.move_rows = console_move_rows,
@@ -104,6 +132,7 @@ struct vidconsole_ops console_ops = {
.get_font_size = console_simple_get_font_size,
.get_font = console_simple_get_font,
.select_font = console_simple_select_font,
+ .set_cursor_visible = console_set_cursor_visible,
};
U_BOOT_DRIVER(vidconsole_normal) = {
diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c
index 0f9bb49e44f..14fb81e9563 100644
--- a/drivers/video/console_truetype.c
+++ b/drivers/video/console_truetype.c
@@ -4,6 +4,7 @@
*/
#include <common.h>
+#include <abuf.h>
#include <dm.h>
#include <log.h>
#include <malloc.h>
@@ -175,6 +176,17 @@ struct console_tt_priv {
int pos_ptr;
};
+/**
+ * struct console_tt_store - Format used for save/restore of entry information
+ *
+ * @priv: Private data
+ * @cur: Current cursor position
+ */
+struct console_tt_store {
+ struct console_tt_priv priv;
+ struct pos_info cur;
+};
+
static int console_truetype_set_row(struct udevice *dev, uint row, int clr)
{
struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
@@ -706,8 +718,8 @@ static int truetype_select_font(struct udevice *dev, const char *name,
return 0;
}
-int truetype_measure(struct udevice *dev, const char *name, uint size,
- const char *text, struct vidconsole_bbox *bbox)
+static int truetype_measure(struct udevice *dev, const char *name, uint size,
+ const char *text, struct vidconsole_bbox *bbox)
{
struct console_tt_metrics *met;
stbtt_fontinfo *font;
@@ -750,6 +762,177 @@ int truetype_measure(struct udevice *dev, const char *name, uint size,
return 0;
}
+static int truetype_nominal(struct udevice *dev, const char *name, uint size,
+ uint num_chars, struct vidconsole_bbox *bbox)
+{
+ struct console_tt_metrics *met;
+ stbtt_fontinfo *font;
+ int lsb, advance;
+ int width;
+ int ret;
+
+ ret = get_metrics(dev, name, size, &met);
+ if (ret)
+ return log_msg_ret("sel", ret);
+
+ font = &met->font;
+ width = 0;
+
+ /* First get some basic metrics about this character */
+ stbtt_GetCodepointHMetrics(font, 'W', &advance, &lsb);
+
+ width = advance;
+
+ bbox->valid = true;
+ bbox->x0 = 0;
+ bbox->y0 = 0;
+ bbox->x1 = tt_ceil((double)width * num_chars * met->scale);
+ bbox->y1 = met->font_size;
+
+ return 0;
+}
+
+static int truetype_entry_save(struct udevice *dev, struct abuf *buf)
+{
+ struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
+ struct console_tt_priv *priv = dev_get_priv(dev);
+ struct console_tt_store store;
+ const uint size = sizeof(store);
+
+ /*
+ * store the whole priv structure as it is simpler that picking out
+ * what we need
+ */
+ if (!abuf_realloc(buf, size))
+ return log_msg_ret("sav", -ENOMEM);
+
+ store.priv = *priv;
+ store.cur.xpos_frac = vc_priv->xcur_frac;
+ store.cur.ypos = vc_priv->ycur;
+ memcpy(abuf_data(buf), &store, size);
+
+ return 0;
+}
+
+static int truetype_entry_restore(struct udevice *dev, struct abuf *buf)
+{
+ struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
+ struct console_tt_priv *priv = dev_get_priv(dev);
+ struct console_tt_store store;
+
+ memcpy(&store, abuf_data(buf), sizeof(store));
+
+ vc_priv->xcur_frac = store.cur.xpos_frac;
+ vc_priv->ycur = store.cur.ypos;
+ priv->pos_ptr = store.priv.pos_ptr;
+ memcpy(priv->pos, store.priv.pos,
+ store.priv.pos_ptr * sizeof(struct pos_info));
+
+ return 0;
+}
+
+static int truetype_set_cursor_visible(struct udevice *dev, bool visible,
+ uint x, uint y, uint index)
+{
+ struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
+ struct udevice *vid = dev->parent;
+ struct video_priv *vid_priv = dev_get_uclass_priv(vid);
+ struct console_tt_priv *priv = dev_get_priv(dev);
+ struct console_tt_metrics *met = priv->cur_met;
+ uint row, width, height, xoff;
+ void *start, *line;
+ uint out, val;
+ int ret;
+
+ if (!visible)
+ return 0;
+
+ /*
+ * figure out where to place the cursor. This driver ignores the
+ * passed-in values, since an entry_restore() must have been done before
+ * calling this function.
+ */
+ if (index < priv->pos_ptr)
+ x = VID_TO_PIXEL(priv->pos[index].xpos_frac);
+ else
+ x = VID_TO_PIXEL(vc_priv->xcur_frac);
+
+ y = vc_priv->ycur;
+ height = met->font_size;
+ xoff = 0;
+
+ val = vid_priv->colour_bg ? 0 : 255;
+ width = VIDCONSOLE_CURSOR_WIDTH;
+
+ /* Figure out where to write the cursor in the frame buffer */
+ start = vid_priv->fb + y * vid_priv->line_length +
+ x * VNBYTES(vid_priv->bpix);
+ line = start;
+
+ /* draw a vertical bar in the correct position */
+ for (row = 0; row < height; row++) {
+ switch (vid_priv->bpix) {
+ case VIDEO_BPP8:
+ if (IS_ENABLED(CONFIG_VIDEO_BPP8)) {
+ u8 *dst = line + xoff;
+ int i;
+
+ out = val;
+ for (i = 0; i < width; i++) {
+ if (vid_priv->colour_fg)
+ *dst++ |= out;
+ else
+ *dst++ &= out;
+ }
+ }
+ break;
+ case VIDEO_BPP16: {
+ u16 *dst = (u16 *)line + xoff;
+ int i;
+
+ if (IS_ENABLED(CONFIG_VIDEO_BPP16)) {
+ for (i = 0; i < width; i++) {
+ out = val >> 3 |
+ (val >> 2) << 5 |
+ (val >> 3) << 11;
+ if (vid_priv->colour_fg)
+ *dst++ |= out;
+ else
+ *dst++ &= out;
+ }
+ }
+ break;
+ }
+ case VIDEO_BPP32: {
+ u32 *dst = (u32 *)line + xoff;
+ int i;
+
+ if (IS_ENABLED(CONFIG_VIDEO_BPP32)) {
+ for (i = 0; i < width; i++) {
+ int out;
+
+ out = val | val << 8 | val << 16;
+ if (vid_priv->colour_fg)
+ *dst++ |= out;
+ else
+ *dst++ &= out;
+ }
+ }
+ break;
+ }
+ default:
+ return -ENOSYS;
+ }
+
+ line += vid_priv->line_length;
+ }
+ ret = vidconsole_sync_copy(dev, start, line);
+ if (ret)
+ return ret;
+
+ return video_sync(vid, true);
+}
+
const char *console_truetype_get_font_size(struct udevice *dev, uint *sizep)
{
struct console_tt_priv *priv = dev_get_priv(dev);
@@ -802,6 +985,10 @@ struct vidconsole_ops console_truetype_ops = {
.get_font_size = console_truetype_get_font_size,
.select_font = truetype_select_font,
.measure = truetype_measure,
+ .nominal = truetype_nominal,
+ .entry_save = truetype_entry_save,
+ .entry_restore = truetype_entry_restore,
+ .set_cursor_visible = truetype_set_cursor_visible
};
U_BOOT_DRIVER(vidconsole_truetype) = {
diff --git a/drivers/video/dw_mipi_dsi.c b/drivers/video/dw_mipi_dsi.c
index 22fef7e8825..a7e0784596a 100644
--- a/drivers/video/dw_mipi_dsi.c
+++ b/drivers/video/dw_mipi_dsi.c
@@ -22,6 +22,7 @@
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/iopoll.h>
+#include <linux/time.h>
#include <video_bridge.h>
#define HWVER_131 0x31333100 /* IP version 1.31 */
@@ -214,8 +215,6 @@
#define PHY_STATUS_TIMEOUT_US 10000
#define CMD_PKT_STATUS_TIMEOUT_US 20000
-#define MSEC_PER_SEC 1000
-
struct dw_mipi_dsi {
struct mipi_dsi_host dsi_host;
struct mipi_dsi_device *device;
diff --git a/drivers/video/hitachi_tx18d42vm_lcd.c b/drivers/video/hitachi_tx18d42vm_lcd.c
index 87c4d27438a..95984fe3d3d 100644
--- a/drivers/video/hitachi_tx18d42vm_lcd.c
+++ b/drivers/video/hitachi_tx18d42vm_lcd.c
@@ -10,6 +10,7 @@
#include <linux/delay.h>
#include <asm/gpio.h>
+#include <sunxi_gpio.h>
#include <errno.h>
/*
diff --git a/drivers/video/pwm_backlight.c b/drivers/video/pwm_backlight.c
index aa0e2928666..1c747d98d7a 100644
--- a/drivers/video/pwm_backlight.c
+++ b/drivers/video/pwm_backlight.c
@@ -100,8 +100,8 @@ static int enable_sequence(struct udevice *dev, int seq)
plat = dev_get_uclass_plat(priv->reg);
log_debug("Enable '%s', regulator '%s'/'%s'\n",
dev->name, priv->reg->name, plat->name);
- ret = regulator_set_enable(priv->reg, true);
- if (ret) {
+ ret = regulator_set_enable_if_allowed(priv->reg, true);
+ if (ret && ret != -ENOSYS) {
log_debug("Cannot enable regulator for PWM '%s'\n",
dev->name);
return log_ret(ret);
@@ -181,11 +181,10 @@ static int pwm_backlight_set_brightness(struct udevice *dev, int percent)
}
if (disable) {
dm_gpio_set_value(&priv->enable, 0);
- if (priv->reg) {
- ret = regulator_set_enable(priv->reg, false);
- if (ret)
- return log_ret(ret);
- }
+ ret = regulator_set_enable_if_allowed(priv->reg, false);
+ if (ret && ret != -ENOSYS)
+ return log_ret(ret);
+
priv->enabled = false;
}
diff --git a/drivers/video/rockchip/dw_mipi_dsi_rockchip.c b/drivers/video/rockchip/dw_mipi_dsi_rockchip.c
index 1a5ab781e3f..5e75b6ec68c 100644
--- a/drivers/video/rockchip/dw_mipi_dsi_rockchip.c
+++ b/drivers/video/rockchip/dw_mipi_dsi_rockchip.c
@@ -30,12 +30,11 @@
#include <asm/io.h>
#include <dm/device-internal.h>
#include <linux/bitops.h>
+#include <linux/time.h>
#include <asm/arch-rockchip/clock.h>
#include <asm/arch-rockchip/hardware.h>
-#define USEC_PER_SEC 1000000L
-
/*
* DSI wrapper registers & bit definitions
* Note: registers are named as in the Reference Manual
diff --git a/drivers/video/simple_panel.c b/drivers/video/simple_panel.c
index 6a6473eb0e5..efb122b534a 100644
--- a/drivers/video/simple_panel.c
+++ b/drivers/video/simple_panel.c
@@ -114,11 +114,11 @@ static int simple_panel_probe(struct udevice *dev)
const u32 dsi_data = dev_get_driver_data(dev);
int ret;
- if (CONFIG_IS_ENABLED(DM_REGULATOR) && priv->reg) {
- debug("%s: Enable regulator '%s'\n", __func__, priv->reg->name);
- ret = regulator_set_enable(priv->reg, true);
- if (ret)
- return ret;
+ ret = regulator_set_enable_if_allowed(priv->reg, true);
+ if (ret && ret != -ENOSYS) {
+ debug("%s: failed to enable regulator '%s' %d\n",
+ __func__, priv->reg->name, ret);
+ return ret;
}
switch (dsi_data) {
diff --git a/drivers/video/ssd2828.c b/drivers/video/ssd2828.c
index 4cdcbe7755a..948f5e74d0f 100644
--- a/drivers/video/ssd2828.c
+++ b/drivers/video/ssd2828.c
@@ -12,7 +12,6 @@
#include <common.h>
#include <malloc.h>
#include <mipi_display.h>
-#include <asm/arch/gpio.h>
#include <asm/gpio.h>
#include <linux/delay.h>
diff --git a/drivers/video/sunxi/sunxi_display.c b/drivers/video/sunxi/sunxi_display.c
index 9110a484821..8da44a1bb6d 100644
--- a/drivers/video/sunxi/sunxi_display.c
+++ b/drivers/video/sunxi/sunxi_display.c
@@ -31,6 +31,7 @@
#include <malloc.h>
#include <video.h>
#include <dm/uclass-internal.h>
+#include <sunxi_gpio.h>
#include "../videomodes.h"
#include "../anx9804.h"
#include "../hitachi_tx18d42vm_lcd.h"
diff --git a/drivers/video/sunxi/sunxi_lcd.c b/drivers/video/sunxi/sunxi_lcd.c
index 8b9c3b2bfa9..7a01cc343ca 100644
--- a/drivers/video/sunxi/sunxi_lcd.c
+++ b/drivers/video/sunxi/sunxi_lcd.c
@@ -17,6 +17,7 @@
#include <asm/arch/lcdc.h>
#include <asm/global_data.h>
#include <asm/gpio.h>
+#include <sunxi_gpio.h>
struct sunxi_lcd_priv {
struct display_timing timing;
diff --git a/drivers/video/tegra20/tegra-dsi.c b/drivers/video/tegra20/tegra-dsi.c
index 8c3404e085d..a48f9c85d0f 100644
--- a/drivers/video/tegra20/tegra-dsi.c
+++ b/drivers/video/tegra20/tegra-dsi.c
@@ -14,6 +14,7 @@
#include <panel.h>
#include <linux/delay.h>
#include <linux/err.h>
+#include <linux/time.h>
#include <power/regulator.h>
#include <asm/gpio.h>
@@ -24,9 +25,6 @@
#include "mipi-phy.h"
-#define USEC_PER_SEC 1000000L
-#define NSEC_PER_SEC 1000000000L
-
struct tegra_dsi_priv {
struct mipi_dsi_host host;
struct mipi_dsi_device device;
@@ -831,11 +829,9 @@ static int tegra_dsi_bridge_probe(struct udevice *dev)
tegra_dsi_get_format(device->format, &priv->format);
- if (priv->avdd) {
- ret = regulator_set_enable(priv->avdd, true);
- if (ret)
- return ret;
- }
+ ret = regulator_set_enable_if_allowed(priv->avdd, true);
+ if (ret && ret != -ENOSYS)
+ return ret;
tegra_dsi_init_clocks(dev);
diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c
index b5b3b662590..22d55df71f6 100644
--- a/drivers/video/vidconsole-uclass.c
+++ b/drivers/video/vidconsole-uclass.c
@@ -10,6 +10,7 @@
#define LOG_CATEGORY UCLASS_VIDEO_CONSOLE
#include <common.h>
+#include <abuf.h>
#include <command.h>
#include <console.h>
#include <log.h>
@@ -47,7 +48,7 @@ int vidconsole_set_row(struct udevice *dev, uint row, int clr)
return ops->set_row(dev, row, clr);
}
-static int vidconsole_entry_start(struct udevice *dev)
+int vidconsole_entry_start(struct udevice *dev)
{
struct vidconsole_ops *ops = vidconsole_get_ops(dev);
@@ -618,6 +619,74 @@ int vidconsole_measure(struct udevice *dev, const char *name, uint size,
return 0;
}
+int vidconsole_nominal(struct udevice *dev, const char *name, uint size,
+ uint num_chars, struct vidconsole_bbox *bbox)
+{
+ struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+ struct vidconsole_ops *ops = vidconsole_get_ops(dev);
+ int ret;
+
+ if (ops->measure) {
+ ret = ops->nominal(dev, name, size, num_chars, bbox);
+ if (ret != -ENOSYS)
+ return ret;
+ }
+
+ bbox->valid = true;
+ bbox->x0 = 0;
+ bbox->y0 = 0;
+ bbox->x1 = priv->x_charsize * num_chars;
+ bbox->y1 = priv->y_charsize;
+
+ return 0;
+}
+
+int vidconsole_entry_save(struct udevice *dev, struct abuf *buf)
+{
+ struct vidconsole_ops *ops = vidconsole_get_ops(dev);
+ int ret;
+
+ if (ops->measure) {
+ ret = ops->entry_save(dev, buf);
+ if (ret != -ENOSYS)
+ return ret;
+ }
+
+ /* no data so make sure the buffer is empty */
+ abuf_realloc(buf, 0);
+
+ return 0;
+}
+
+int vidconsole_entry_restore(struct udevice *dev, struct abuf *buf)
+{
+ struct vidconsole_ops *ops = vidconsole_get_ops(dev);
+ int ret;
+
+ if (ops->measure) {
+ ret = ops->entry_restore(dev, buf);
+ if (ret != -ENOSYS)
+ return ret;
+ }
+
+ return 0;
+}
+
+int vidconsole_set_cursor_visible(struct udevice *dev, bool visible,
+ uint x, uint y, uint index)
+{
+ struct vidconsole_ops *ops = vidconsole_get_ops(dev);
+ int ret;
+
+ if (ops->set_cursor_visible) {
+ ret = ops->set_cursor_visible(dev, visible, x, y, index);
+ if (ret != -ENOSYS)
+ return ret;
+ }
+
+ return 0;
+}
+
void vidconsole_push_colour(struct udevice *dev, enum colour_idx fg,
enum colour_idx bg, struct vidconsole_colour *old)
{
diff --git a/drivers/video/vidconsole_internal.h b/drivers/video/vidconsole_internal.h
index c41edd45249..0ec581b2663 100644
--- a/drivers/video/vidconsole_internal.h
+++ b/drivers/video/vidconsole_internal.h
@@ -93,6 +93,30 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri
struct video_fontdata *fontdata, bool direction);
/**
+ * draw_cursor_vertically() - Draw a simple vertical cursor
+ *
+ * @line: pointer to framebuffer buffer: upper left cursor corner
+ * @vid_priv: driver private data
+ * @height: height of the cursor in pixels
+ * @param direction controls cursor orientation. Can be normal or flipped.
+ * When normal: When flipped:
+ *|-----------------------------------------------|
+ *| * | line stepping |
+ *| ^ * * * * * | | |
+ *| | * * | v * * |
+ *| | | * * * * * |
+ *| line stepping | * |
+ *| | |
+ *| stepping -> | <<- stepping |
+ *|---!!we're starting from upper left char corner|
+ *|-----------------------------------------------|
+ *
+ * Return: 0, if success, or else error code.
+ */
+int draw_cursor_vertically(void **line, struct video_priv *vid_priv,
+ uint height, bool direction);
+
+/**
* console probe function.
*
* @param dev a pointer to device.
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index 852f6735b60..1de68867d52 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -56,7 +56,7 @@ config VIRTIO_SANDBOX
config VIRTIO_NET
bool "virtio net driver"
- depends on VIRTIO
+ depends on VIRTIO && NETDEVICES
help
This is the virtual net driver for virtio. It can be used with
QEMU based targets.
diff --git a/drivers/virtio/virtio_rng.c b/drivers/virtio/virtio_rng.c
index b85545c2ee5..786359a6e36 100644
--- a/drivers/virtio/virtio_rng.c
+++ b/drivers/virtio/virtio_rng.c
@@ -20,7 +20,7 @@ struct virtio_rng_priv {
static int virtio_rng_read(struct udevice *dev, void *data, size_t len)
{
int ret;
- unsigned int rsize;
+ unsigned int rsize = 1;
unsigned char buf[BUFFER_SIZE] __aligned(4);
unsigned char *ptr = data;
struct virtio_sg sg;
@@ -29,7 +29,12 @@ static int virtio_rng_read(struct udevice *dev, void *data, size_t len)
while (len) {
sg.addr = buf;
- sg.length = min(len, sizeof(buf));
+ /*
+ * Work around implementations which always return 8 bytes
+ * less than requested, down to 0 bytes, which would
+ * cause an endless loop otherwise.
+ */
+ sg.length = min(rsize ? len : len + 8, sizeof(buf));
sgs[0] = &sg;
ret = virtqueue_add(priv->rng_vq, sgs, 0, 1);
diff --git a/drivers/watchdog/npcm_wdt.c b/drivers/watchdog/npcm_wdt.c
index e56aa0ebe1d..57b61215a2a 100644
--- a/drivers/watchdog/npcm_wdt.c
+++ b/drivers/watchdog/npcm_wdt.c
@@ -69,15 +69,21 @@ static int npcm_wdt_stop(struct udevice *dev)
static int npcm_wdt_reset(struct udevice *dev)
{
struct npcm_wdt_priv *priv = dev_get_priv(dev);
+ u32 val;
- writel(NPCM_WTR | NPCM_WTRE | NPCM_WTE, priv->regs);
+ val = readl(priv->regs);
+ writel(val | NPCM_WTR, priv->regs);
return 0;
}
static int npcm_wdt_expire_now(struct udevice *dev, ulong flags)
{
- return npcm_wdt_reset(dev);
+ struct npcm_wdt_priv *priv = dev_get_priv(dev);
+
+ writel(NPCM_WTR | NPCM_WTRE | NPCM_WTE, priv->regs);
+
+ return 0;
}
static int npcm_wdt_of_to_plat(struct udevice *dev)
diff --git a/drivers/watchdog/s5p_wdt.c b/drivers/watchdog/s5p_wdt.c
index 5ad7d2609f0..80524a00101 100644
--- a/drivers/watchdog/s5p_wdt.c
+++ b/drivers/watchdog/s5p_wdt.c
@@ -6,6 +6,7 @@
#include <common.h>
#include <asm/io.h>
+#include <asm/arch/cpu.h>
#include <asm/arch/watchdog.h>
#define PRESCALER_VAL 255
diff --git a/drivers/watchdog/sunxi_wdt.c b/drivers/watchdog/sunxi_wdt.c
index b40a1d29caa..8eeac935760 100644
--- a/drivers/watchdog/sunxi_wdt.c
+++ b/drivers/watchdog/sunxi_wdt.c
@@ -9,8 +9,7 @@
#include <wdt.h>
#include <asm/io.h>
#include <linux/delay.h>
-
-#define MSEC_PER_SEC 1000
+#include <linux/time.h>
#define WDT_MAX_TIMEOUT 16
#define WDT_TIMEOUT_MASK 0xf
diff --git a/drivers/watchdog/wdt-uclass.c b/drivers/watchdog/wdt-uclass.c
index ed329284dec..417e8d7eef9 100644
--- a/drivers/watchdog/wdt-uclass.c
+++ b/drivers/watchdog/wdt-uclass.c
@@ -7,6 +7,7 @@
#include <common.h>
#include <cyclic.h>
+#include <div64.h>
#include <dm.h>
#include <errno.h>
#include <hang.h>
@@ -141,7 +142,7 @@ int wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
printf("WDT: Started %s with%s servicing %s (%ds timeout)\n",
dev->name, IS_ENABLED(CONFIG_WATCHDOG) ? "" : "out",
- str, priv->timeout);
+ str, (u32)lldiv(timeout_ms, 1000));
}
return ret;
diff --git a/drivers/xen/pvblock.c b/drivers/xen/pvblock.c
index 4ad548d599d..1df04e239ad 100644
--- a/drivers/xen/pvblock.c
+++ b/drivers/xen/pvblock.c
@@ -632,7 +632,8 @@ static ulong pvblock_iop(struct udevice *udev, lbaint_t blknr,
memcpy(blk_dev->bounce_buffer, buffer, desc->blksz);
aiocb.aio_nbytes = unaligned ? desc->blksz :
- min((size_t)(BLKIF_MAX_SEGMENTS_PER_REQUEST * PAGE_SIZE),
+ min((size_t)((BLKIF_MAX_SEGMENTS_PER_REQUEST - 1)
+ * PAGE_SIZE),
(size_t)(blocks_todo * desc->blksz));
blkfront_io(&aiocb, write);