summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile14
-rw-r--r--drivers/ata/Makefile2
-rw-r--r--drivers/ata/ahci.c14
-rw-r--r--drivers/block/Makefile2
-rw-r--r--drivers/bus/Makefile2
-rw-r--r--drivers/button/button-qcom-pmic.c8
-rw-r--r--drivers/button/button-uclass.c2
-rw-r--r--drivers/clk/clk-stub.c3
-rw-r--r--drivers/clk/clk-uclass.c19
-rw-r--r--drivers/clk/imx/clk-imx8mp.c69
-rw-r--r--drivers/clk/qcom/clock-apq8096.c5
-rw-r--r--drivers/clk/qcom/clock-sc7280.c11
-rw-r--r--drivers/clk/qcom/clock-sdm845.c3
-rw-r--r--drivers/core/Makefile6
-rw-r--r--drivers/core/ofnode_graph.c2
-rw-r--r--drivers/core/uclass.c19
-rw-r--r--drivers/ddr/altera/Makefile2
-rw-r--r--drivers/dfu/Makefile18
-rw-r--r--drivers/fastboot/Kconfig1
-rw-r--r--drivers/fastboot/fb_common.c4
-rw-r--r--drivers/firmware/Makefile2
-rw-r--r--drivers/firmware/firmware-zynqmp.c74
-rw-r--r--drivers/firmware/scmi/smt.c13
-rw-r--r--drivers/firmware/ti_sci.c23
-rw-r--r--drivers/fpga/altera.c41
-rw-r--r--drivers/fpga/versalpl.c11
-rw-r--r--drivers/gpio/Makefile10
-rw-r--r--drivers/gpio/msm_gpio.c53
-rw-r--r--drivers/i2c/Makefile16
-rw-r--r--drivers/input/Kconfig6
-rw-r--r--drivers/input/Makefile1
-rw-r--r--drivers/input/cpcap_pwrbutton.c134
-rw-r--r--drivers/led/Makefile2
-rw-r--r--drivers/mailbox/Makefile2
-rw-r--r--drivers/misc/Kconfig1
-rw-r--r--drivers/misc/Makefile10
-rw-r--r--drivers/mmc/Kconfig4
-rw-r--r--drivers/mmc/Makefile6
-rw-r--r--drivers/mmc/mmc-uclass.c16
-rw-r--r--drivers/mmc/mmc.c16
-rw-r--r--drivers/mmc/mmc_boot.c173
-rw-r--r--drivers/mmc/mmc_write.c11
-rw-r--r--drivers/mmc/sdhci.c6
-rw-r--r--drivers/mtd/nand/spi/core.c18
-rw-r--r--drivers/mux/Makefile2
-rw-r--r--drivers/net/Kconfig8
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/airoha_eth.c948
-rw-r--r--drivers/net/phy/Kconfig34
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/air_en8811h.c783
-rw-r--r--drivers/nvme/Makefile2
-rw-r--r--drivers/phy/Makefile6
-rw-r--r--drivers/phy/cadence/Makefile4
-rw-r--r--drivers/phy/qcom/phy-qcom-qusb2.c44
-rw-r--r--drivers/phy/ti/Makefile2
-rw-r--r--drivers/pinctrl/Makefile8
-rw-r--r--drivers/pinctrl/qcom/Kconfig15
-rw-r--r--drivers/pinctrl/qcom/Makefile2
-rw-r--r--drivers/pinctrl/qcom/pinctrl-qcom.c67
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sa8775p.c623
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sdm660.c226
-rw-r--r--drivers/pinctrl/tegra/funcmux-tegra20.c9
-rw-r--r--drivers/pinctrl/tegra/pinctrl-tegra.c75
-rw-r--r--drivers/pinctrl/tegra/pinctrl-tegra20.c18
-rw-r--r--drivers/power/domain/Kconfig7
-rw-r--r--drivers/power/domain/Makefile3
-rw-r--r--drivers/power/domain/imx8m-power-domain.c17
-rw-r--r--drivers/power/domain/imx8mp-mediamix.c208
-rw-r--r--drivers/power/pmic/Kconfig10
-rw-r--r--drivers/power/pmic/Makefile31
-rw-r--r--drivers/power/pmic/cpcap.c125
-rw-r--r--drivers/power/regulator/Kconfig16
-rw-r--r--drivers/power/regulator/Makefile48
-rw-r--r--drivers/power/regulator/cpcap_regulator.c275
-rw-r--r--drivers/power/regulator/qcom-rpmh-regulator.c45
-rw-r--r--drivers/power/regulator/qcom_usb_vbus_regulator.c111
-rw-r--r--drivers/remoteproc/Makefile2
-rw-r--r--drivers/scsi/scsi.c117
-rw-r--r--drivers/serial/Kconfig3
-rw-r--r--drivers/serial/Makefile2
-rw-r--r--drivers/spi/Kconfig9
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/airoha_snfi_spi.c718
-rw-r--r--drivers/spi/cadence_ospi_versal.c19
-rw-r--r--drivers/spi/cadence_qspi.c9
-rw-r--r--drivers/spi/cadence_qspi.h3
-rw-r--r--drivers/spi/tegra20_slink.c18
-rw-r--r--drivers/spmi/spmi-msm.c59
-rw-r--r--drivers/sysreset/Kconfig45
-rw-r--r--drivers/sysreset/Makefile4
-rw-r--r--drivers/timer/Makefile8
-rw-r--r--drivers/tpm/cr50_i2c.c4
-rw-r--r--drivers/ufs/ufs-amd-versal2.c66
-rw-r--r--drivers/usb/cdns3/Makefile4
-rw-r--r--drivers/usb/common/Makefile2
-rw-r--r--drivers/usb/dwc3/Makefile4
-rw-r--r--drivers/usb/dwc3/gadget.c2
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c1
-rw-r--r--drivers/usb/gadget/f_mass_storage.c18
-rw-r--r--drivers/usb/gadget/udc/Makefile4
-rw-r--r--drivers/usb/host/Makefile2
-rw-r--r--drivers/video/Kconfig29
-rw-r--r--drivers/video/Makefile9
-rw-r--r--drivers/video/imx/Kconfig9
-rw-r--r--drivers/video/imx/Makefile4
-rw-r--r--drivers/video/imx/lcdif.c314
-rw-r--r--drivers/video/imx/ldb.c251
-rw-r--r--drivers/video/lm3532_backlight.c380
-rw-r--r--drivers/video/mot-panel.c308
-rw-r--r--drivers/video/tegra/Kconfig51
-rw-r--r--drivers/video/tegra/Makefile9
-rw-r--r--drivers/video/tegra/TODO5
-rw-r--r--drivers/video/tegra/dc-pwm-backlight.c (renamed from drivers/video/tegra20/tegra-pwm-backlight.c)2
-rw-r--r--drivers/video/tegra/dc.c (renamed from drivers/video/tegra20/tegra-dc.c)2
-rw-r--r--drivers/video/tegra/dc.h (renamed from drivers/video/tegra20/tegra-dc.h)0
-rw-r--r--drivers/video/tegra/dsi.c (renamed from drivers/video/tegra20/tegra-dsi.c)5
-rw-r--r--drivers/video/tegra/dsi.h (renamed from drivers/video/tegra20/tegra-dsi.h)0
-rw-r--r--drivers/video/tegra/hdmi.c (renamed from drivers/video/tegra20/tegra-hdmi.c)4
-rw-r--r--drivers/video/tegra/hdmi.h (renamed from drivers/video/tegra20/tegra-hdmi.h)0
-rw-r--r--drivers/video/tegra/host1x.c (renamed from drivers/video/tegra20/tegra-host1x.c)0
-rw-r--r--drivers/video/tegra/mipi-phy.c (renamed from drivers/video/tegra20/mipi-phy.c)0
-rw-r--r--drivers/video/tegra/mipi-phy.h (renamed from drivers/video/tegra20/mipi-phy.h)0
-rw-r--r--drivers/video/tegra/mipi.c (renamed from drivers/video/tegra20/tegra-mipi.c)0
-rw-r--r--drivers/video/tegra/tegra124/Makefile (renamed from drivers/video/tegra124/Makefile)0
-rw-r--r--drivers/video/tegra/tegra124/display.c (renamed from drivers/video/tegra124/display.c)0
-rw-r--r--drivers/video/tegra/tegra124/displayport.h (renamed from drivers/video/tegra124/displayport.h)0
-rw-r--r--drivers/video/tegra/tegra124/dp.c (renamed from drivers/video/tegra124/dp.c)0
-rw-r--r--drivers/video/tegra/tegra124/sor.c (renamed from drivers/video/tegra124/sor.c)0
-rw-r--r--drivers/video/tegra/tegra124/sor.h (renamed from drivers/video/tegra124/sor.h)0
-rw-r--r--drivers/video/tegra20/Kconfig38
-rw-r--r--drivers/video/tegra20/Makefile7
-rw-r--r--drivers/video/tidss/Makefile2
133 files changed, 6813 insertions, 369 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index 0e1f58c515b..3c0ad17138f 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -34,15 +34,15 @@ obj-$(CONFIG_$(PHASE_)SERIAL) += serial/
obj-$(CONFIG_$(PHASE_)SPI) += spi/
obj-$(CONFIG_$(PHASE_)TIMER) += timer/
obj-$(CONFIG_$(PHASE_)VIRTIO) += virtio/
-obj-$(CONFIG_$(XPL_)DM_MAILBOX) += mailbox/
-obj-$(CONFIG_$(XPL_)REMOTEPROC) += remoteproc/
-obj-$(CONFIG_$(XPL_)SYSINFO) += sysinfo/
+obj-$(CONFIG_$(PHASE_)DM_MAILBOX) += mailbox/
+obj-$(CONFIG_$(PHASE_)REMOTEPROC) += remoteproc/
+obj-$(CONFIG_$(PHASE_)SYSINFO) += sysinfo/
obj-$(CONFIG_$(PHASE_)SM) += sm/
obj-$(CONFIG_$(PHASE_)TPM) += tpm/
-obj-$(CONFIG_$(XPL_)NVME) += nvme/
+obj-$(CONFIG_$(PHASE_)NVME) += nvme/
obj-$(CONFIG_XEN) += xen/
-obj-$(CONFIG_$(XPL_)FPGA) += fpga/
-obj-$(CONFIG_$(XPL_)VIDEO) += video/
+obj-$(CONFIG_$(PHASE_)FPGA) += fpga/
+obj-$(CONFIG_$(PHASE_)VIDEO) += video/
obj-y += bus/
@@ -55,7 +55,7 @@ obj-$(CONFIG_SPL_CRYPTO) += crypto/
obj-$(CONFIG_SPL_MPC8XXX_INIT_DDR) += ddr/fsl/
obj-$(CONFIG_ARMADA_38X) += ddr/marvell/a38x/
obj-$(CONFIG_ARMADA_XP) += ddr/marvell/axp/
-obj-$(CONFIG_$(XPL_)ALTERA_SDRAM) += ddr/altera/
+obj-$(CONFIG_$(PHASE_)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/
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 69fa9b707e0..20e33f2f27a 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -5,7 +5,7 @@
obj-$(CONFIG_DWC_AHCI) += dwc_ahci.o
obj-$(CONFIG_AHCI) += ahci-uclass.o
-obj-$(CONFIG_$(XPL_)AHCI_PCI) += ahci-pci.o
+obj-$(CONFIG_$(PHASE_)AHCI_PCI) += ahci-pci.o
obj-$(CONFIG_SCSI_AHCI) += ahci.o
obj-$(CONFIG_DWC_AHSATA) += dwc_ahsata.o
obj-$(CONFIG_FSL_SATA) += fsl_sata.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index e593e228685..b532b3b7339 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -735,17 +735,6 @@ static int ata_scsiop_read_write(struct ahci_uc_priv *uc_priv,
is_write ? "WRITE" : "READ");
return -EIO;
}
-
- /* If this transaction is a write, do a following flush.
- * Writes in u-boot are so rare, and the logic to know when is
- * the last write and do a flush only there is sufficiently
- * difficult. Just do a flush after every write. This incurs,
- * usually, one extra flush when the rare writes do happen.
- */
- if (is_write) {
- if (-EIO == ata_io_flush(uc_priv, pccb->target))
- return -EIO;
- }
user_buffer += transfer_size;
user_buffer_size -= transfer_size;
blocks -= now_blocks;
@@ -845,6 +834,9 @@ static int ahci_scsi_exec(struct udevice *dev, struct scsi_cmd *pccb)
case SCSI_INQUIRY:
ret = ata_scsiop_inquiry(uc_priv, pccb);
break;
+ case SCSI_SYNC_CACHE:
+ ret = ata_io_flush(uc_priv, pccb->target);
+ break;
default:
printf("Unsupport SCSI command 0x%02x\n", pccb->cmd[0]);
return -ENOTSUPP;
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index ee290620545..f5a9d8637a3 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -5,7 +5,7 @@
obj-$(CONFIG_$(PHASE_)BLK) += blk-uclass.o
-ifndef CONFIG_$(XPL_)BLK
+ifndef CONFIG_$(PHASE_)BLK
obj-$(CONFIG_SPL_LEGACY_BLOCK) += blk_legacy.o
endif
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index 7daf8247247..2d242bc2886 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -8,4 +8,4 @@ obj-$(CONFIG_TI_PWMSS) += ti-pwmss.o
obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o
endif
-obj-$(CONFIG_$(XPL_)TI_SYSC) += ti-sysc.o
+obj-$(CONFIG_$(PHASE_)TI_SYSC) += ti-sysc.o
diff --git a/drivers/button/button-qcom-pmic.c b/drivers/button/button-qcom-pmic.c
index f9f0948ae09..e3bb9bd758a 100644
--- a/drivers/button/button-qcom-pmic.c
+++ b/drivers/button/button-qcom-pmic.c
@@ -73,25 +73,25 @@ static const struct qcom_pmic_btn_data qcom_pmic_btn_data_table[] = {
.compatible = "qcom,pm8941-pwrkey",
.status_bit = PON_KPDPWR_N_SET,
.code = KEY_ENTER,
- .label = "pwrkey",
+ .label = "Power Button",
},
{
.compatible = "qcom,pm8941-resin",
.status_bit = PON_RESIN_N_SET,
.code = KEY_DOWN,
- .label = "vol_down",
+ .label = "Volume Down",
},
{
.compatible = "qcom,pmk8350-pwrkey",
.status_bit = PON_GEN3_KPDPWR_N_SET,
.code = KEY_ENTER,
- .label = "pwrkey",
+ .label = "Power Button",
},
{
.compatible = "qcom,pmk8350-resin",
.status_bit = PON_GEN3_RESIN_N_SET,
.code = KEY_DOWN,
- .label = "vol_down",
+ .label = "Volume Down",
},
};
diff --git a/drivers/button/button-uclass.c b/drivers/button/button-uclass.c
index 729983d5870..025917887e8 100644
--- a/drivers/button/button-uclass.c
+++ b/drivers/button/button-uclass.c
@@ -21,7 +21,7 @@ int button_get_by_label(const char *label, struct udevice **devp)
struct button_uc_plat *uc_plat = dev_get_uclass_plat(dev);
/* Ignore the top-level button node */
- if (uc_plat->label && !strcmp(label, uc_plat->label))
+ if (uc_plat->label && !strcasecmp(label, uc_plat->label))
return uclass_get_device_tail(dev, 0, devp);
}
diff --git a/drivers/clk/clk-stub.c b/drivers/clk/clk-stub.c
index 343fa5cd3fe..5f5aca41d5b 100644
--- a/drivers/clk/clk-stub.c
+++ b/drivers/clk/clk-stub.c
@@ -14,7 +14,7 @@
static const struct udevice_id nop_parent_ids[] = {
{ .compatible = "qcom,rpm-proc" },
{ .compatible = "qcom,glink-rpm" },
- { .compatible = "qcom,rpm-sm6115" },
+ { .compatible = "qcom,glink-smd-rpm" },
{ }
};
@@ -50,6 +50,7 @@ static struct clk_ops stub_clk_ops = {
static const struct udevice_id stub_clk_ids[] = {
{ .compatible = "qcom,rpmcc" },
+ { .compatible = "qcom,sdm845-rpmh-clk" },
{ .compatible = "qcom,sc7280-rpmh-clk" },
{ .compatible = "qcom,sm8150-rpmh-clk" },
{ .compatible = "qcom,sm8250-rpmh-clk" },
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 90b70529a47..4b3d812f9c6 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -623,14 +623,27 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
if (!ops->set_parent)
return -ENOSYS;
+ ret = clk_enable(parent);
+ if (ret) {
+ printf("Cannot enable parent %s\n", parent->dev->name);
+ return ret;
+ }
+
ret = ops->set_parent(clk, parent);
- if (ret)
+ if (ret) {
+ clk_disable(parent);
return ret;
+ }
- if (CONFIG_IS_ENABLED(CLK_CCF))
+ if (CONFIG_IS_ENABLED(CLK_CCF)) {
ret = device_reparent(clk->dev, parent->dev);
+ if (ret) {
+ clk_disable(parent);
+ return ret;
+ }
+ }
- return ret;
+ return 0;
}
int clk_enable(struct clk *clk)
diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c
index bad579f8d5e..3d8ed21d3b9 100644
--- a/drivers/clk/imx/clk-imx8mp.c
+++ b/drivers/clk/imx/clk-imx8mp.c
@@ -14,7 +14,14 @@
#include "clk.h"
+#if CONFIG_IS_ENABLED(VIDEO)
+static u32 share_count_media;
+#endif
+
static const char * const pll_ref_sels[] = { "osc_24m", "dummy", "dummy", "dummy", };
+#if CONFIG_IS_ENABLED(VIDEO)
+static const char * const video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", };
+#endif
static const char * const dram_pll_bypass_sels[] = {"dram_pll", "dram_pll_ref_sel", };
static const char * const arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", };
static const char * const sys_pll1_bypass_sels[] = {"sys_pll1", "sys_pll1_ref_sel", };
@@ -31,6 +38,12 @@ static const char * const imx8mp_hsio_axi_sels[] = {"osc_24m", "sys_pll2_500m",
"sys_pll2_100m", "sys_pll2_200m", "clk_ext2",
"clk_ext4", "audio_pll2_out", };
+#if CONFIG_IS_ENABLED(VIDEO)
+static const char * const imx8mp_media_isp_sels[] = {"osc_24m", "sys_pll2_1000m", "sys_pll1_800m",
+ "sys_pll3_out", "sys_pll1_400m", "audio_pll2_out",
+ "clk_ext1", "sys_pll2_500m", };
+#endif
+
static const char * const imx8mp_main_axi_sels[] = {"osc_24m", "sys_pll2_333m", "sys_pll1_800m",
"sys_pll2_250m", "sys_pll2_1000m", "audio_pll1_out",
"video_pll1_out", "sys_pll1_100m",};
@@ -43,6 +56,16 @@ static const char * const imx8mp_nand_usdhc_sels[] = {"osc_24m", "sys_pll1_266m"
"sys_pll2_200m", "sys_pll1_133m", "sys_pll3_out",
"sys_pll2_250m", "audio_pll1_out", };
+#if CONFIG_IS_ENABLED(VIDEO)
+static const char * const imx8mp_media_axi_sels[] = {"osc_24m", "sys_pll2_1000m", "sys_pll1_800m",
+ "sys_pll3_out", "sys_pll1_40m", "audio_pll2_out",
+ "clk_ext1", "sys_pll2_500m", };
+
+static const char * const imx8mp_media_apb_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll1_800m",
+ "sys_pll3_out", "sys_pll1_40m", "audio_pll2_out",
+ "clk_ext1", "sys_pll1_133m", };
+#endif
+
static const char * const imx8mp_noc_sels[] = {"osc_24m", "sys_pll1_800m", "sys_pll3_out",
"sys_pll2_1000m", "sys_pll2_500m", "audio_pll1_out",
"video_pll1_out", "audio_pll2_out", };
@@ -175,6 +198,17 @@ static const char * const imx8mp_usdhc3_sels[] = {"osc_24m", "sys_pll1_400m", "s
"sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m",
"audio_pll2_out", "sys_pll1_100m", };
+#if CONFIG_IS_ENABLED(VIDEO)
+static const char * const imx8mp_media_disp_pix_sels[] = {"osc_24m", "video_pll1_out", "audio_pll2_out",
+ "audio_pll1_out", "sys_pll1_800m",
+ "sys_pll2_1000m", "sys_pll3_out", "clk_ext4", };
+
+static const char * const imx8mp_media_ldb_sels[] = {"osc_24m", "sys_pll2_333m", "sys_pll2_100m",
+ "sys_pll1_800m", "sys_pll2_1000m",
+ "clk_ext2", "audio_pll2_out",
+ "video_pll1_out", };
+#endif
+
static const char * const imx8mp_enet_ref_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll2_50m",
"sys_pll2_100m", "sys_pll1_160m", "audio_pll1_out",
"video_pll1_out", "clk_ext4", };
@@ -199,12 +233,19 @@ static int imx8mp_clk_probe(struct udevice *dev)
clk_dm(IMX8MP_CLK_DUMMY, clk_register_fixed_rate(NULL, "dummy", 0));
+#if CONFIG_IS_ENABLED(VIDEO)
+ clk_dm(IMX8MP_VIDEO_PLL1_REF_SEL, imx_clk_mux(dev, "video_pll1_ref_sel", base + 0x28, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
+#endif
clk_dm(IMX8MP_DRAM_PLL_REF_SEL, imx_clk_mux(dev, "dram_pll_ref_sel", base + 0x50, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MP_ARM_PLL_REF_SEL, imx_clk_mux(dev, "arm_pll_ref_sel", base + 0x84, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MP_SYS_PLL1_REF_SEL, imx_clk_mux(dev, "sys_pll1_ref_sel", base + 0x94, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MP_SYS_PLL2_REF_SEL, imx_clk_mux(dev, "sys_pll2_ref_sel", base + 0x104, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MP_SYS_PLL3_REF_SEL, imx_clk_mux(dev, "sys_pll3_ref_sel", base + 0x114, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
+#if CONFIG_IS_ENABLED(VIDEO)
+ clk_dm(IMX8MP_VIDEO_PLL1, imx_clk_pll14xx("video_pll1", "video_pll1_ref_sel", base + 0x28,
+ &imx_1443x_pll));
+#endif
clk_dm(IMX8MP_DRAM_PLL, imx_clk_pll14xx("dram_pll", "dram_pll_ref_sel", base + 0x50,
&imx_1443x_dram_pll));
clk_dm(IMX8MP_ARM_PLL, imx_clk_pll14xx("arm_pll", "arm_pll_ref_sel", base + 0x84,
@@ -216,12 +257,18 @@ static int imx8mp_clk_probe(struct udevice *dev)
clk_dm(IMX8MP_SYS_PLL3, imx_clk_pll14xx("sys_pll3", "sys_pll3_ref_sel", base + 0x114,
&imx_1416x_pll));
+#if CONFIG_IS_ENABLED(VIDEO)
+ clk_dm(IMX8MP_VIDEO_PLL1_BYPASS, imx_clk_mux_flags(dev, "video_pll1_bypass", base + 0x28, 16, 1, video_pll1_bypass_sels, ARRAY_SIZE(video_pll1_bypass_sels), CLK_SET_RATE_PARENT));
+#endif
clk_dm(IMX8MP_DRAM_PLL_BYPASS, imx_clk_mux_flags(dev, "dram_pll_bypass", base + 0x50, 4, 1, dram_pll_bypass_sels, ARRAY_SIZE(dram_pll_bypass_sels), CLK_SET_RATE_PARENT));
clk_dm(IMX8MP_ARM_PLL_BYPASS, imx_clk_mux_flags(dev, "arm_pll_bypass", base + 0x84, 4, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels), CLK_SET_RATE_PARENT));
clk_dm(IMX8MP_SYS_PLL1_BYPASS, imx_clk_mux_flags(dev, "sys_pll1_bypass", base + 0x94, 4, 1, sys_pll1_bypass_sels, ARRAY_SIZE(sys_pll1_bypass_sels), CLK_SET_RATE_PARENT));
clk_dm(IMX8MP_SYS_PLL2_BYPASS, imx_clk_mux_flags(dev, "sys_pll2_bypass", base + 0x104, 4, 1, sys_pll2_bypass_sels, ARRAY_SIZE(sys_pll2_bypass_sels), CLK_SET_RATE_PARENT));
clk_dm(IMX8MP_SYS_PLL3_BYPASS, imx_clk_mux_flags(dev, "sys_pll3_bypass", base + 0x114, 4, 1, sys_pll3_bypass_sels, ARRAY_SIZE(sys_pll3_bypass_sels), CLK_SET_RATE_PARENT));
+#if CONFIG_IS_ENABLED(VIDEO)
+ clk_dm(IMX8MP_VIDEO_PLL1_OUT, imx_clk_gate(dev, "video_pll1_out", "video_pll1_bypass", base + 0x28, 13));
+#endif
clk_dm(IMX8MP_DRAM_PLL_OUT, imx_clk_gate(dev, "dram_pll_out", "dram_pll_bypass", base + 0x50, 13));
clk_dm(IMX8MP_ARM_PLL_OUT, imx_clk_gate(dev, "arm_pll_out", "arm_pll_bypass", base + 0x84, 11));
clk_dm(IMX8MP_SYS_PLL1_OUT, imx_clk_gate(dev, "sys_pll1_out", "sys_pll1_bypass", base + 0x94, 11));
@@ -267,13 +314,23 @@ static int imx8mp_clk_probe(struct udevice *dev)
clk_dm(IMX8MP_CLK_A53_DIV, imx_clk_divider2(dev, "arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3));
clk_dm(IMX8MP_CLK_HSIO_AXI, imx8m_clk_composite(dev, "hsio_axi", imx8mp_hsio_axi_sels, base + 0x8380));
+#if CONFIG_IS_ENABLED(VIDEO)
+ clk_dm(IMX8MP_CLK_MEDIA_ISP, imx8m_clk_composite(dev, "media_isp", imx8mp_media_isp_sels, base + 0x8400));
+#endif
clk_dm(IMX8MP_CLK_MAIN_AXI, imx8m_clk_composite_critical(dev, "main_axi", imx8mp_main_axi_sels, base + 0x8800));
clk_dm(IMX8MP_CLK_ENET_AXI, imx8m_clk_composite_critical(dev, "enet_axi", imx8mp_enet_axi_sels, base + 0x8880));
clk_dm(IMX8MP_CLK_NAND_USDHC_BUS, imx8m_clk_composite_critical(dev, "nand_usdhc_bus", imx8mp_nand_usdhc_sels, base + 0x8900));
+#if CONFIG_IS_ENABLED(VIDEO)
+ clk_dm(IMX8MP_CLK_MEDIA_AXI, imx8m_clk_composite(dev, "media_axi", imx8mp_media_axi_sels, base + 0x8a00));
+ clk_dm(IMX8MP_CLK_MEDIA_APB, imx8m_clk_composite(dev, "media_apb", imx8mp_media_apb_sels, base + 0x8a80));
+#endif
clk_dm(IMX8MP_CLK_NOC, imx8m_clk_composite_critical(dev, "noc", imx8mp_noc_sels, base + 0x8d00));
clk_dm(IMX8MP_CLK_NOC_IO, imx8m_clk_composite_critical(dev, "noc_io", imx8mp_noc_io_sels, base + 0x8d80));
clk_dm(IMX8MP_CLK_AHB, imx8m_clk_composite_critical(dev, "ahb_root", imx8mp_ahb_sels, base + 0x9000));
+#if CONFIG_IS_ENABLED(VIDEO)
+ clk_dm(IMX8MP_CLK_MEDIA_DISP2_PIX, imx8m_clk_composite(dev, "media_disp2_pix", imx8mp_media_disp_pix_sels, base + 0x9300));
+#endif
clk_dm(IMX8MP_CLK_IPG_ROOT, imx_clk_divider2(dev, "ipg_root", "ahb_root", base + 0x9080, 0, 1));
@@ -312,6 +369,10 @@ static int imx8mp_clk_probe(struct udevice *dev)
clk_dm(IMX8MP_CLK_WDOG, imx8m_clk_composite(dev, "wdog", imx8mp_wdog_sels, base + 0xb900));
clk_dm(IMX8MP_CLK_USDHC3, imx8m_clk_composite(dev, "usdhc3", imx8mp_usdhc3_sels, base + 0xbc80));
+#if CONFIG_IS_ENABLED(VIDEO)
+ clk_dm(IMX8MP_CLK_MEDIA_DISP1_PIX, imx8m_clk_composite(dev, "media_disp1_pix", imx8mp_media_disp_pix_sels, base + 0xbe00));
+ clk_dm(IMX8MP_CLK_MEDIA_LDB, imx8m_clk_composite(dev, "media_ldb", imx8mp_media_ldb_sels, base + 0xbf00));
+#endif
clk_dm(IMX8MP_CLK_DRAM_ALT_ROOT, imx_clk_fixed_factor(dev, "dram_alt_root", "dram_alt", 1, 4));
clk_dm(IMX8MP_CLK_DRAM_CORE, imx_clk_mux2_flags(dev, "dram_core_clk", base + 0x9800, 24, 1, imx8mp_dram_core_sels, ARRAY_SIZE(imx8mp_dram_core_sels), CLK_IS_CRITICAL));
@@ -355,6 +416,14 @@ static int imx8mp_clk_probe(struct udevice *dev)
clk_dm(IMX8MP_CLK_WDOG2_ROOT, imx_clk_gate4(dev, "wdog2_root_clk", "wdog", base + 0x4540, 0));
clk_dm(IMX8MP_CLK_WDOG3_ROOT, imx_clk_gate4(dev, "wdog3_root_clk", "wdog", base + 0x4550, 0));
clk_dm(IMX8MP_CLK_HSIO_ROOT, imx_clk_gate4(dev, "hsio_root_clk", "ipg_root", base + 0x45c0, 0));
+#if CONFIG_IS_ENABLED(VIDEO)
+ clk_dm(IMX8MP_CLK_MEDIA_APB_ROOT, imx_clk_gate2_shared2(dev, "media_apb_root_clk", "media_apb", base + 0x45d0, 0, &share_count_media));
+ clk_dm(IMX8MP_CLK_MEDIA_AXI_ROOT, imx_clk_gate2_shared2(dev, "media_axi_root_clk", "media_axi", base + 0x45d0, 0, &share_count_media));
+ clk_dm(IMX8MP_CLK_MEDIA_DISP1_PIX_ROOT, imx_clk_gate2_shared2(dev, "media_disp1_pix_root_clk", "media_disp1_pix", base + 0x45d0, 0, &share_count_media));
+ clk_dm(IMX8MP_CLK_MEDIA_DISP2_PIX_ROOT, imx_clk_gate2_shared2(dev, "media_disp2_pix_root_clk", "media_disp2_pix", base + 0x45d0, 0, &share_count_media));
+ clk_dm(IMX8MP_CLK_MEDIA_LDB_ROOT, imx_clk_gate2_shared2(dev, "media_ldb_root_clk", "media_ldb", base + 0x45d0, 0, &share_count_media));
+ clk_dm(IMX8MP_CLK_MEDIA_ISP_ROOT, imx_clk_gate2_shared2(dev, "media_isp_root_clk", "media_isp", base + 0x45d0, 0, &share_count_media));
+#endif
clk_dm(IMX8MP_CLK_USDHC3_ROOT, imx_clk_gate4(dev, "usdhc3_root_clk", "usdhc3", base + 0x45e0, 0));
diff --git a/drivers/clk/qcom/clock-apq8096.c b/drivers/clk/qcom/clock-apq8096.c
index c77d69128b0..551f52d5197 100644
--- a/drivers/clk/qcom/clock-apq8096.c
+++ b/drivers/clk/qcom/clock-apq8096.c
@@ -83,11 +83,12 @@ static ulong apq8096_clk_set_rate(struct clk *clk, ulong rate)
struct msm_clk_priv *priv = dev_get_priv(clk->dev);
switch (clk->id) {
- case GCC_SDCC1_APPS_CLK: /* SDC1 */
+ case GCC_SDCC2_APPS_CLK: /* SDC2 */
return clk_init_sdc(priv, rate);
break;
case GCC_BLSP2_UART2_APPS_CLK: /*UART2*/
- return clk_init_uart(priv);
+ clk_init_uart(priv);
+ return 7372800;
default:
return 0;
}
diff --git a/drivers/clk/qcom/clock-sc7280.c b/drivers/clk/qcom/clock-sc7280.c
index 8691f08109b..9aff8a847ad 100644
--- a/drivers/clk/qcom/clock-sc7280.c
+++ b/drivers/clk/qcom/clock-sc7280.c
@@ -107,6 +107,17 @@ static const struct gate_clk sc7280_clks[] = {
GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x52008, BIT(10)),
GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x52008, BIT(11)),
GATE_CLK(GCC_QUPV3_WRAP0_S3_CLK, 0x52008, BIT(13)),
+ GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x77010, BIT(0)),
+ GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x770cc, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x77018, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x7705c, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_PHY_AUX_CLK, 0x7709c, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_TX_SYMBOL_0_CLK, 0x7701c, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_0_CLK, 0x77020, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_1_CLK, 0x770b8, BIT(0)),
+ GATE_CLK(GCC_UFS_1_CLKREF_EN, 0x8c000, BIT(0)),
+ GATE_CLK(GCC_SDCC2_AHB_CLK, 0x14008, BIT(0)),
+ GATE_CLK(GCC_SDCC2_APPS_CLK, 0x14004, BIT(0)),
};
static int sc7280_enable(struct clk *clk)
diff --git a/drivers/clk/qcom/clock-sdm845.c b/drivers/clk/qcom/clock-sdm845.c
index 6a0bf16ba2d..5c8702ef2fe 100644
--- a/drivers/clk/qcom/clock-sdm845.c
+++ b/drivers/clk/qcom/clock-sdm845.c
@@ -77,7 +77,9 @@ static ulong sdm845_clk_set_rate(struct clk *clk, ulong rate)
}
static const struct gate_clk sdm845_clks[] = {
+ GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0x8201c, 0x00000001),
GATE_CLK(GCC_AGGRE_USB3_SEC_AXI_CLK, 0x82020, 0x00000001),
+ GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x0502c, 0x00000001),
GATE_CLK(GCC_CFG_NOC_USB3_SEC_AXI_CLK, 0x05030, 0x00000001),
GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x5200c, 0x00000400),
GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x5200c, 0x00000800),
@@ -112,6 +114,7 @@ static const struct gate_clk sdm845_clks[] = {
GATE_CLK(GCC_UFS_CARD_TX_SYMBOL_0_CLK, 0x75014, 0x00000001),
GATE_CLK(GCC_UFS_CARD_UNIPRO_CORE_CLK, 0x75054, 0x00000001),
GATE_CLK(GCC_UFS_MEM_CLKREF_CLK, 0x8c000, 0x00000001),
+ GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x82024, 0x00000001),
GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x77010, 0x00000001),
GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x7700c, 0x00000001),
GATE_CLK(GCC_UFS_PHY_ICE_CORE_CLK, 0x77058, 0x00000001),
diff --git a/drivers/core/Makefile b/drivers/core/Makefile
index 657e589c286..a549890c22b 100644
--- a/drivers/core/Makefile
+++ b/drivers/core/Makefile
@@ -6,16 +6,16 @@ obj-y += device.o fdtaddr.o lists.o root.o uclass.o util.o tag.o
obj-$(CONFIG_$(PHASE_)ACPIGEN) += acpi.o
obj-$(CONFIG_$(PHASE_)DEVRES) += devres.o
obj-$(CONFIG_$(PHASE_)DM_DEVICE_REMOVE) += device-remove.o
-obj-$(CONFIG_$(XPL_)SIMPLE_BUS) += simple-bus.o
+obj-$(CONFIG_$(PHASE_)SIMPLE_BUS) += simple-bus.o
obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
obj-$(CONFIG_DM) += dump.o
obj-$(CONFIG_$(PHASE_)REGMAP) += regmap.o
obj-$(CONFIG_$(PHASE_)SYSCON) += syscon-uclass.o
-obj-$(CONFIG_$(XPL_)OF_LIVE) += of_access.o of_addr.o
+obj-$(CONFIG_$(PHASE_)OF_LIVE) += of_access.o of_addr.o
ifndef CONFIG_DM_DEV_READ_INLINE
obj-$(CONFIG_OF_CONTROL) += read.o
endif
-obj-$(CONFIG_$(XPL_)OF_PLATDATA) += read.o
+obj-$(CONFIG_$(PHASE_)OF_PLATDATA) += read.o
obj-$(CONFIG_OF_CONTROL) += of_extra.o ofnode.o read_extra.o ofnode_graph.o
ccflags-$(CONFIG_DM_DEBUG) += -DDEBUG
diff --git a/drivers/core/ofnode_graph.c b/drivers/core/ofnode_graph.c
index 90c92af3258..175ac768771 100644
--- a/drivers/core/ofnode_graph.c
+++ b/drivers/core/ofnode_graph.c
@@ -98,7 +98,7 @@ ofnode ofnode_graph_get_port_by_id(ofnode parent, u32 id)
* @id: id for the endpoint
*
* Return: ofnode in given endpoint or ofnode_null() if not found.
- * reg and port_reg are ignored when they are -1.
+ * reg_id and id are ignored when they are -1.
*/
ofnode ofnode_graph_get_endpoint_by_regs(ofnode parent, int reg_id, int id)
{
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index f846a35d6b2..ce5e61bbaa6 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -16,6 +16,7 @@
#include <dm/device.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
+#include <dm/ofnode_graph.h>
#include <dm/uclass.h>
#include <dm/uclass-internal.h>
#include <dm/util.h>
@@ -582,6 +583,24 @@ int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
ret = uclass_find_device_by_phandle(id, parent, name, &dev);
return uclass_get_device_tail(dev, ret, devp);
}
+
+int uclass_get_device_by_endpoint(enum uclass_id class_id, struct udevice *dev,
+ int port_idx, int ep_idx, struct udevice **devp)
+{
+ ofnode node_source = dev_ofnode(dev);
+ ofnode node_dest = ofnode_graph_get_remote_node(node_source, port_idx, ep_idx);
+ struct udevice *target = NULL;
+ int ret;
+
+ if (!ofnode_valid(node_dest))
+ return -EINVAL;
+
+ ret = uclass_find_device_by_ofnode(class_id, node_dest, &target);
+ if (ret)
+ return -ENODEV;
+
+ return uclass_get_device_tail(target, 0, devp);
+}
#endif
/*
diff --git a/drivers/ddr/altera/Makefile b/drivers/ddr/altera/Makefile
index b19f3601813..c627f16711e 100644
--- a/drivers/ddr/altera/Makefile
+++ b/drivers/ddr/altera/Makefile
@@ -6,7 +6,7 @@
# (C) Copyright 2010, Thomas Chou <thomas@wytron.com.tw>
# Copyright (C) 2014-2025 Altera Corporation <www.altera.com>
-ifdef CONFIG_$(XPL_)ALTERA_SDRAM
+ifdef CONFIG_$(PHASE_)ALTERA_SDRAM
obj-$(CONFIG_TARGET_SOCFPGA_GEN5) += sdram_gen5.o sequencer.o
obj-$(CONFIG_TARGET_SOCFPGA_ARRIA10) += sdram_arria10.o
obj-$(CONFIG_TARGET_SOCFPGA_STRATIX10) += sdram_soc64.o sdram_s10.o
diff --git a/drivers/dfu/Makefile b/drivers/dfu/Makefile
index 6e1ab1c2ea5..eb4ae5e2074 100644
--- a/drivers/dfu/Makefile
+++ b/drivers/dfu/Makefile
@@ -3,12 +3,12 @@
# Copyright (C) 2012 Samsung Electronics
# Lukasz Majewski <l.majewski@samsung.com>
-obj-$(CONFIG_$(XPL_)DFU) += dfu.o
-obj-$(CONFIG_$(XPL_)DFU_MMC) += dfu_mmc.o
-obj-$(CONFIG_$(XPL_)DFU_MTD) += dfu_mtd.o
-obj-$(CONFIG_$(XPL_)DFU_NAND) += dfu_nand.o
-obj-$(CONFIG_$(XPL_)DFU_RAM) += dfu_ram.o
-obj-$(CONFIG_$(XPL_)DFU_SF) += dfu_sf.o
-obj-$(CONFIG_$(XPL_)DFU_WRITE_ALT) += dfu_alt.o
-obj-$(CONFIG_$(XPL_)DFU_VIRT) += dfu_virt.o
-obj-$(CONFIG_$(XPL_)DFU_SCSI) += dfu_scsi.o
+obj-$(CONFIG_$(PHASE_)DFU) += dfu.o
+obj-$(CONFIG_$(PHASE_)DFU_MMC) += dfu_mmc.o
+obj-$(CONFIG_$(PHASE_)DFU_MTD) += dfu_mtd.o
+obj-$(CONFIG_$(PHASE_)DFU_NAND) += dfu_nand.o
+obj-$(CONFIG_$(PHASE_)DFU_RAM) += dfu_ram.o
+obj-$(CONFIG_$(PHASE_)DFU_SF) += dfu_sf.o
+obj-$(CONFIG_$(PHASE_)DFU_WRITE_ALT) += dfu_alt.o
+obj-$(CONFIG_$(PHASE_)DFU_VIRT) += dfu_virt.o
+obj-$(CONFIG_$(PHASE_)DFU_SCSI) += dfu_scsi.o
diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig
index 1eb460f5a02..70207573de2 100644
--- a/drivers/fastboot/Kconfig
+++ b/drivers/fastboot/Kconfig
@@ -1,6 +1,5 @@
menu "Fastboot support"
depends on CMDLINE
- depends on !NET_LWIP
config FASTBOOT
bool
diff --git a/drivers/fastboot/fb_common.c b/drivers/fastboot/fb_common.c
index 12ffb463deb..68f92c4b887 100644
--- a/drivers/fastboot/fb_common.c
+++ b/drivers/fastboot/fb_common.c
@@ -183,11 +183,15 @@ void fastboot_handle_boot(int command, bool success)
switch (command) {
case FASTBOOT_COMMAND_BOOT:
fastboot_boot();
+#if CONFIG_IS_ENABLED(NET)
net_set_state(NETLOOP_SUCCESS);
+#endif
break;
case FASTBOOT_COMMAND_CONTINUE:
+#if CONFIG_IS_ENABLED(NET)
net_set_state(NETLOOP_SUCCESS);
+#endif
break;
case FASTBOOT_COMMAND_REBOOT:
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 8b979f69ed9..9e7b118b074 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_FIRMWARE) += firmware-uclass.o
-obj-$(CONFIG_$(XPL_)ARM_PSCI_FW) += psci.o
+obj-$(CONFIG_$(PHASE_)ARM_PSCI_FW) += psci.o
obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
obj-$(CONFIG_SANDBOX) += firmware-sandbox.o
obj-$(CONFIG_ZYNQMP_FIRMWARE) += firmware-zynqmp.o
diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c
index 4b1b80d7abe..2940181e83e 100644
--- a/drivers/firmware/firmware-zynqmp.c
+++ b/drivers/firmware/firmware-zynqmp.c
@@ -5,6 +5,8 @@
* Copyright (C) 2018-2019 Xilinx, Inc.
*/
+#include <asm/arch/hardware.h>
+#include <asm/io.h>
#include <cpu_func.h>
#include <dm.h>
#include <dm/device_compat.h>
@@ -169,6 +171,32 @@ unsigned int zynqmp_firmware_version(void)
return pm_api_version;
};
+#if defined(CONFIG_ARCH_VERSAL2)
+int zynqmp_pm_ufs_get_txrx_cfgrdy(u32 *value)
+{
+ *value = readl(PMXC_SLCR_BASE_ADDRESS + PMXC_TX_RX_CFG_RDY);
+ return 0;
+}
+
+int zynqmp_pm_ufs_sram_csr_read(u32 *value)
+{
+ *value = readl(PMXC_SLCR_BASE_ADDRESS + PMXC_SRAM_CSR);
+ return 0;
+}
+
+int zynqmp_pm_ufs_sram_csr_write(u32 *value)
+{
+ writel(*value, PMXC_SLCR_BASE_ADDRESS + PMXC_SRAM_CSR);
+ return 0;
+}
+
+int zynqmp_pm_ufs_cal_reg(u32 *value)
+{
+ *value = readl(PMXC_EFUSE_CACHE_BASE_ADDRESS + PMXC_UFS_CAL_1_OFFSET);
+ return 0;
+}
+#endif
+
int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config, u32 value)
{
int ret;
@@ -195,6 +223,52 @@ int zynqmp_pm_set_sd_config(u32 node, enum pm_sd_config_type config, u32 value)
return ret;
}
+u32 zynqmp_pm_get_bootmode_reg(void)
+{
+ int ret;
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+
+ ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_READ_REG);
+ if (ret) {
+ printf("%s: IOCTL_READ_REG is not supported failed with error code: %d\n"
+ , __func__, ret);
+ return 0;
+ }
+
+ ret = xilinx_pm_request(PM_IOCTL, CRP_BOOT_MODE_REG_NODE, IOCTL_READ_REG,
+ CRP_BOOT_MODE_REG_OFFSET, 0, ret_payload);
+ if (ret) {
+ printf("%s: node 0x%x: get_bootmode 0x%x failed\n",
+ __func__, CRP_BOOT_MODE_REG_NODE, CRP_BOOT_MODE_REG_OFFSET);
+ return 0;
+ }
+
+ return ret_payload[1];
+}
+
+u32 zynqmp_pm_get_pmc_multi_boot_reg(void)
+{
+ int ret;
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+
+ ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_READ_REG);
+ if (ret) {
+ printf("%s: IOCTL_READ_REG is not supported failed with error code: %d\n"
+ , __func__, ret);
+ return 0;
+ }
+
+ ret = xilinx_pm_request(PM_IOCTL, PM_REG_PMC_GLOBAL_NODE, IOCTL_READ_REG,
+ PMC_MULTI_BOOT_MODE_REG_OFFSET, 0, ret_payload);
+ if (ret) {
+ printf("%s: node 0x%x: get_bootmode 0x%x failed\n",
+ __func__, PM_REG_PMC_GLOBAL_NODE, PMC_MULTI_BOOT_MODE_REG_OFFSET);
+ return 0;
+ }
+
+ return ret_payload[1];
+}
+
int zynqmp_pm_feature(const u32 api_id)
{
int ret;
diff --git a/drivers/firmware/scmi/smt.c b/drivers/firmware/scmi/smt.c
index 67d2f450024..3253f4211d6 100644
--- a/drivers/firmware/scmi/smt.c
+++ b/drivers/firmware/scmi/smt.c
@@ -20,6 +20,16 @@
#include "smt.h"
+static void scmi_smt_enable_intr(struct scmi_smt *smt, bool enable)
+{
+ struct scmi_smt_header *hdr = (void *)smt->buf;
+
+ if (enable)
+ hdr->flags |= SCMI_SHMEM_FLAG_INTR_ENABLED;
+ else
+ hdr->flags &= ~SCMI_SHMEM_FLAG_INTR_ENABLED;
+}
+
/**
* Get shared memory configuration defined by the referred DT phandle
* Return with a errno compliant value.
@@ -48,6 +58,9 @@ int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt)
if (!smt->buf)
return -ENOMEM;
+ if (device_is_compatible(dev, "arm,scmi") && ofnode_has_property(dev_ofnode(dev), "mboxes"))
+ scmi_smt_enable_intr(smt, true);
+
#ifdef CONFIG_ARM
if (dcache_status())
mmu_set_region_dcache_behaviour(ALIGN_DOWN((uintptr_t)smt->buf, MMU_SECTION_SIZE),
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 190a1e3f5fc..54d6689ce78 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -696,20 +696,25 @@ static int ti_sci_cmd_put_device(const struct ti_sci_handle *handle, u32 id)
MSG_DEVICE_SW_STATE_AUTO_OFF);
}
-static
-int ti_sci_cmd_release_exclusive_devices(const struct ti_sci_handle *handle)
+static int ti_sci_cmd_release_exclusive_devices(void)
{
struct ti_sci_exclusive_dev *dev, *tmp;
struct ti_sci_info *info;
int i, cnt;
- info = handle_to_ti_sci_info(handle);
-
- list_for_each_entry_safe(dev, tmp, &info->dev_list, list) {
- cnt = dev->count;
- debug("%s: id = %d, cnt = %d\n", __func__, dev->id, cnt);
- for (i = 0; i < cnt; i++)
- ti_sci_cmd_put_device(handle, dev->id);
+ /*
+ * Scan all ti_sci_list registrations, since with FIT images, we could
+ * have started with one device tree registration and switched over
+ * to a final version. This prevents exclusive devices identified
+ * during the first probe to be left orphan.
+ */
+ list_for_each_entry(info, &ti_sci_list, list) {
+ list_for_each_entry_safe(dev, tmp, &info->dev_list, list) {
+ cnt = dev->count;
+ debug("%s: id = %d, cnt = %d\n", __func__, dev->id, cnt);
+ for (i = 0; i < cnt; i++)
+ ti_sci_cmd_put_device(&info->handle, dev->id);
+ }
}
return 0;
diff --git a/drivers/fpga/altera.c b/drivers/fpga/altera.c
index ae06f0123a0..64fda3a307c 100644
--- a/drivers/fpga/altera.c
+++ b/drivers/fpga/altera.c
@@ -12,6 +12,10 @@
/*
* Altera FPGA support
*/
+#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX) || \
+ IS_ENABLED(CONFIG_TARGET_SOCFPGA_STRATIX10)
+#include <asm/arch/misc.h>
+#endif
#include <errno.h>
#include <ACEX1K.h>
#include <log.h>
@@ -47,6 +51,43 @@ static const struct altera_fpga {
#endif
};
+#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX) || \
+ IS_ENABLED(CONFIG_TARGET_SOCFPGA_STRATIX10)
+int fpga_is_partial_data(int devnum, size_t img_len)
+{
+ /*
+ * The FPGA data (full or partial) is checked by
+ * the SDM hardware, for Intel SDM Mailbox based
+ * devices. Hence always return full bitstream.
+ *
+ * For Cyclone V and Arria 10 family, the bitstream
+ * type parameter is not handled by the driver.
+ */
+ return 0;
+}
+
+int fpga_loadbitstream(int devnum, char *fpgadata, size_t size,
+ bitstream_type bstype)
+{
+ int ret_val;
+ int flags = 0;
+
+ ret_val = fpga_load(devnum, (void *)fpgadata, size, bstype, flags);
+
+ /*
+ * Enable the HPS to FPGA bridges when FPGA load is completed
+ * successfully. This is to ensure the FPGA is accessible
+ * by the HPS.
+ */
+ if (!ret_val) {
+ printf("Enable FPGA bridges\n");
+ do_bridge_reset(1, ~0);
+ }
+
+ return ret_val;
+}
+#endif
+
static int altera_validate(Altera_desc *desc, const char *fn)
{
if (!desc) {
diff --git a/drivers/fpga/versalpl.c b/drivers/fpga/versalpl.c
index 1957e8dcaca..d691f135e89 100644
--- a/drivers/fpga/versalpl.c
+++ b/drivers/fpga/versalpl.c
@@ -41,8 +41,15 @@ static int versal_load(xilinx_desc *desc, const void *buf, size_t bsize,
buf_lo = lower_32_bits(bin_buf);
buf_hi = upper_32_bits(bin_buf);
- ret = xilinx_pm_request(VERSAL_PM_LOAD_PDI, VERSAL_PM_PDI_TYPE, buf_lo,
- buf_hi, 0, ret_payload);
+
+ if (desc->family == xilinx_versal2) {
+ ret = xilinx_pm_request(VERSAL_PM_LOAD_PDI, VERSAL_PM_PDI_TYPE, buf_hi,
+ buf_lo, 0, ret_payload);
+ } else {
+ ret = xilinx_pm_request(VERSAL_PM_LOAD_PDI, VERSAL_PM_PDI_TYPE, buf_lo,
+ buf_hi, 0, ret_payload);
+ }
+
if (ret)
printf("PL FPGA LOAD failed with err: 0x%08x\n", ret);
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index d426d3a2d7b..d64c14db5cf 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -10,7 +10,7 @@ obj-$(CONFIG_DM_74X164) += 74x164_gpio.o
endif
obj-$(CONFIG_$(PHASE_)DM_GPIO) += gpio-uclass.o
-obj-$(CONFIG_$(XPL_)DM_PCA953X) += pca953x_gpio.o
+obj-$(CONFIG_$(PHASE_)DM_PCA953X) += pca953x_gpio.o
obj-$(CONFIG_ADI_GPIO) += gpio-adi-adsp.o
obj-$(CONFIG_ASPEED_GPIO) += gpio-aspeed.o
@@ -59,12 +59,12 @@ obj-$(CONFIG_VYBRID_GPIO) += vybrid_gpio.o
obj-$(CONFIG_HIKEY_GPIO) += hi6220_gpio.o
obj-$(CONFIG_HSDK_CREG_GPIO) += hsdk-creg-gpio.o
obj-$(CONFIG_IMX_RGPIO2P) += imx_rgpio2p.o
-obj-$(CONFIG_$(XPL_)PALMAS_GPIO) += palmas_gpio.o
+obj-$(CONFIG_$(PHASE_)PALMAS_GPIO) += palmas_gpio.o
obj-$(CONFIG_PIC32_GPIO) += pic32_gpio.o
obj-$(CONFIG_OCTEON_GPIO) += octeon_gpio.o
obj-$(CONFIG_MVEBU_GPIO) += mvebu_gpio.o
obj-$(CONFIG_MSM_GPIO) += msm_gpio.o
-obj-$(CONFIG_$(XPL_)PCF8575_GPIO) += pcf8575_gpio.o
+obj-$(CONFIG_$(PHASE_)PCF8575_GPIO) += pcf8575_gpio.o
obj-$(CONFIG_$(PHASE_)QCOM_PMIC_GPIO) += qcom_pmic_gpio.o
obj-$(CONFIG_MT7620_GPIO) += mt7620_gpio.o
obj-$(CONFIG_MT7621_GPIO) += mt7621_gpio.o
@@ -73,11 +73,11 @@ obj-$(CONFIG_NX_GPIO) += nx_gpio.o
obj-$(CONFIG_SIFIVE_GPIO) += sifive-gpio.o
obj-$(CONFIG_NOMADIK_GPIO) += nmk_gpio.o
obj-$(CONFIG_MAX7320_GPIO) += max7320_gpio.o
-obj-$(CONFIG_$(XPL_)MAX77663_GPIO) += max77663_gpio.o
+obj-$(CONFIG_$(PHASE_)MAX77663_GPIO) += max77663_gpio.o
obj-$(CONFIG_SL28CPLD_GPIO) += sl28cpld-gpio.o
obj-$(CONFIG_ADP5588_GPIO) += adp5588_gpio.o
obj-$(CONFIG_ZYNQMP_GPIO_MODEPIN) += zynqmp_gpio_modepin.o
obj-$(CONFIG_SLG7XL45106_I2C_GPO) += gpio_slg7xl45106.o
obj-$(CONFIG_FTGPIO010) += ftgpio010.o
-obj-$(CONFIG_$(SPL_)ADP5585_GPIO) += adp5585_gpio.o
+obj-$(CONFIG_$(PHASE_)ADP5585_GPIO) += adp5585_gpio.o
obj-$(CONFIG_RZG2L_GPIO) += rzg2l-gpio.o
diff --git a/drivers/gpio/msm_gpio.c b/drivers/gpio/msm_gpio.c
index cea073b3297..6783fc756f4 100644
--- a/drivers/gpio/msm_gpio.c
+++ b/drivers/gpio/msm_gpio.c
@@ -151,6 +151,9 @@ static int msm_gpio_direction_output(struct udevice *dev, unsigned int gpio,
static int msm_gpio_set_flags(struct udevice *dev, unsigned int gpio, ulong flags)
{
+ if (msm_pinctrl_is_reserved(dev_get_parent(dev), gpio))
+ return -EPERM;
+
if (flags & GPIOD_IS_OUT_ACTIVE) {
return msm_gpio_direction_output(dev, gpio, 1);
} else if (flags & GPIOD_IS_OUT) {
@@ -172,12 +175,19 @@ static int msm_gpio_get_value_special(struct msm_gpio_bank *priv, unsigned int g
const struct msm_special_pin_data *data;
if (!priv->pin_data->special_pins_data)
- return 0;
+ return -EINVAL;
data = &priv->pin_data->special_pins_data[offset];
- if (!data->io_reg || data->in_bit >= 31)
- return 0;
+ if (!data->io_reg)
+ return -EINVAL;
+
+ if (data->in_bit >= 31) {
+ if (data->out_bit >= 31)
+ return -EINVAL;
+
+ return !!(readl(priv->base + data->io_reg) >> data->out_bit);
+ }
return !!(readl(priv->base + data->io_reg) >> data->in_bit);
}
@@ -186,19 +196,54 @@ static int msm_gpio_get_value(struct udevice *dev, unsigned int gpio)
{
struct msm_gpio_bank *priv = dev_get_priv(dev);
+ if (msm_pinctrl_is_reserved(dev_get_parent(dev), gpio))
+ return -EPERM;
+
if (qcom_is_special_pin(priv->pin_data, gpio))
return msm_gpio_get_value_special(priv, gpio);
return !!(readl(priv->base + GPIO_IN_OUT_REG(dev, gpio)) >> GPIO_IN);
}
+static int msm_gpio_get_function_special(struct msm_gpio_bank *priv,
+ unsigned int gpio)
+{
+ unsigned int offset = gpio - priv->pin_data->special_pins_start;
+ const struct msm_special_pin_data *data;
+
+ if (!priv->pin_data->special_pins_data)
+ return GPIOF_UNKNOWN;
+
+ data = &priv->pin_data->special_pins_data[offset];
+
+ /* No I/O fields, cannot control/read the I/O value */
+ if (!data->io_reg || (data->out_bit >= 31 && data->in_bit >= 31))
+ return GPIOF_FUNC;
+
+ /* No Output-Enable register, cannot control I/O direction */
+ if (!data->ctl_reg || data->oe_bit >= 31) {
+ if (data->out_bit >= 31)
+ return GPIOF_INPUT;
+ else
+ return GPIOF_OUTPUT;
+ }
+
+ if (readl(priv->base + data->ctl_reg) & BIT(data->oe_bit))
+ return GPIOF_OUTPUT;
+
+ return GPIOF_INPUT;
+}
+
static int msm_gpio_get_function(struct udevice *dev, unsigned int gpio)
{
struct msm_gpio_bank *priv = dev_get_priv(dev);
+ if (msm_pinctrl_is_reserved(dev_get_parent(dev), gpio))
+ return GPIOF_UNKNOWN;
+
/* Always NOP for special pins, assume they're in the correct state */
if (qcom_is_special_pin(priv->pin_data, gpio))
- return 0;
+ return msm_gpio_get_function_special(priv, gpio);
if (readl(priv->base + GPIO_CONFIG_REG(dev, gpio)) & GPIO_OE_ENABLE)
return GPIOF_OUTPUT;
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 2713289f7db..42326db85f6 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -2,15 +2,15 @@
#
# (C) Copyright 2000-2007
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
-obj-$(CONFIG_$(XPL_)DM_I2C) += i2c-uclass.o
-ifdef CONFIG_$(XPL_)ACPIGEN
-obj-$(CONFIG_$(XPL_)DM_I2C) += acpi_i2c.o
+obj-$(CONFIG_$(PHASE_)DM_I2C) += i2c-uclass.o
+ifdef CONFIG_$(PHASE_)ACPIGEN
+obj-$(CONFIG_$(PHASE_)DM_I2C) += acpi_i2c.o
endif
-obj-$(CONFIG_$(XPL_)DM_I2C_GPIO) += i2c-gpio.o
-obj-$(CONFIG_$(XPL_)I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o
-obj-$(CONFIG_$(XPL_)I2C_CROS_EC_LDO) += cros_ec_ldo.o
+obj-$(CONFIG_$(PHASE_)DM_I2C_GPIO) += i2c-gpio.o
+obj-$(CONFIG_$(PHASE_)I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o
+obj-$(CONFIG_$(PHASE_)I2C_CROS_EC_LDO) += cros_ec_ldo.o
-obj-$(CONFIG_$(XPL_)SYS_I2C_LEGACY) += i2c_core.o
+obj-$(CONFIG_$(PHASE_)SYS_I2C_LEGACY) += i2c_core.o
obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
obj-$(CONFIG_SYS_I2C_ASPEED) += ast_i2c.o
obj-$(CONFIG_SYS_I2C_AST2600) += ast2600_i2c.o
@@ -58,4 +58,4 @@ obj-$(CONFIG_SYS_I2C_VERSATILE) += i2c-versatile.o
obj-$(CONFIG_SYS_I2C_XILINX_XIIC) += xilinx_xiic.o
obj-$(CONFIG_TEGRA186_BPMP_I2C) += tegra186_bpmp_i2c.o
-obj-$(CONFIG_$(XPL_)I2C_MUX) += muxes/
+obj-$(CONFIG_$(PHASE_)I2C_MUX) += muxes/
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index c2b365af11d..c09f0ae795e 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -55,6 +55,12 @@ config BUTTON_KEYBOARD
dt node to define button-event mapping.
For example, an arrows and enter may be implemented to navigate boot menu.
+config CPCAP_POWER_BUTTON
+ bool "Enable power button of CPCAP PMIC support"
+ depends on DM_KEYBOARD && DM_PMIC_CPCAP
+ help
+ Enable support for a dedicated power button of the CPCAP PMIC.
+
config CROS_EC_KEYB
bool "Enable Chrome OS EC keyboard support"
depends on INPUT
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 8d4107b8848..1303fcdb0b7 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_$(PHASE_)CROS_EC_KEYB) += cros_ec_keyb.o
obj-$(CONFIG_$(PHASE_)OF_CONTROL) += key_matrix.o
obj-$(CONFIG_$(PHASE_)DM_KEYBOARD) += input.o keyboard-uclass.o
obj-$(CONFIG_BUTTON_KEYBOARD) += button_kbd.o
+obj-$(CONFIG_CPCAP_POWER_BUTTON) += cpcap_pwrbutton.o
ifndef CONFIG_XPL_BUILD
diff --git a/drivers/input/cpcap_pwrbutton.c b/drivers/input/cpcap_pwrbutton.c
new file mode 100644
index 00000000000..c8ad39d33ca
--- /dev/null
+++ b/drivers/input/cpcap_pwrbutton.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <stdlib.h>
+#include <dm.h>
+#include <input.h>
+#include <keyboard.h>
+#include <power/pmic.h>
+#include <power/cpcap.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/input.h>
+
+static const unsigned int cpcpap_to_reg[] = {
+ CPCAP_REG_INT1,
+ CPCAP_REG_INT2,
+ CPCAP_REG_INT3,
+ CPCAP_REG_INT4,
+};
+
+/**
+ * struct cpcap_pwrbutton_priv
+ *
+ * @bank: id of interrupt bank co-responding to an IRQ register
+ * @id: id of interrupt pin co-responding to the bit in IRQ register
+ * @keycode: linux key code
+ * @old_state: holder of last button state
+ * @skip: holder of keycode skip state. This is required since both pressing
+ * and releasing generate same event and cause key send duplication.
+ */
+struct cpcap_pwrbutton_priv {
+ u32 bank;
+ u32 id;
+
+ u32 keycode;
+
+ bool old_state;
+ bool skip;
+};
+
+static int cpcap_pwrbutton_read_keys(struct input_config *input)
+{
+ struct udevice *dev = input->dev;
+ struct cpcap_pwrbutton_priv *priv = dev_get_priv(dev);
+ u32 value, state_changed;
+ bool state;
+
+ value = pmic_reg_read(dev->parent, cpcpap_to_reg[priv->bank]) &
+ BIT(priv->id);
+
+ /* Interrupt bit is cleared by writing it to interrupt reg */
+ pmic_reg_write(dev->parent, cpcpap_to_reg[priv->bank], BIT(priv->id));
+
+ state = value >> priv->id;
+ state_changed = state != priv->old_state;
+
+ if (state_changed && !priv->skip) {
+ priv->old_state = state;
+ input_add_keycode(input, priv->keycode, state);
+ }
+
+ if (state)
+ priv->skip = !priv->skip;
+
+ return 0;
+}
+
+static int cpcap_pwrbutton_of_to_plat(struct udevice *dev)
+{
+ struct cpcap_pwrbutton_priv *priv = dev_get_priv(dev);
+ ofnode irq_parent;
+ u32 irq_desc;
+ int ret;
+
+ /* Check interrupt parent, driver supports only CPCAP as parent */
+ irq_parent = ofnode_parse_phandle(dev_ofnode(dev), "interrupt-parent", 0);
+ if (!ofnode_device_is_compatible(irq_parent, "motorola,cpcap"))
+ return -EINVAL;
+
+ ret = dev_read_u32(dev, "interrupts", &irq_desc);
+ if (ret)
+ return ret;
+
+ /* IRQ registers are 16 bit wide */
+ priv->bank = irq_desc / 16;
+ priv->id = irq_desc % 16;
+
+ ret = dev_read_u32(dev, "linux,code", &priv->keycode);
+ if (ret)
+ return ret;
+
+ priv->old_state = false;
+ priv->skip = false;
+ return 0;
+}
+
+static int cpcap_pwrbutton_probe(struct udevice *dev)
+{
+ struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct stdio_dev *sdev = &uc_priv->sdev;
+ struct input_config *input = &uc_priv->input;
+ int ret;
+
+ input_init(input, false);
+ input_add_tables(input, false);
+
+ /* Register the device */
+ input->dev = dev;
+ input->read_keys = cpcap_pwrbutton_read_keys;
+ strcpy(sdev->name, "cpcap-pwrbutton");
+ ret = input_stdio_register(sdev);
+ if (ret) {
+ log_debug("%s: input_stdio_register() failed\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id cpcap_pwrbutton_ids[] = {
+ { .compatible = "motorola,cpcap-pwrbutton" },
+ { }
+};
+
+U_BOOT_DRIVER(cpcap_pwrbutton) = {
+ .name = "cpcap_pwrbutton",
+ .id = UCLASS_KEYBOARD,
+ .of_match = cpcap_pwrbutton_ids,
+ .of_to_plat = cpcap_pwrbutton_of_to_plat,
+ .probe = cpcap_pwrbutton_probe,
+ .priv_auto = sizeof(struct cpcap_pwrbutton_priv),
+};
diff --git a/drivers/led/Makefile b/drivers/led/Makefile
index aa64a38b4e1..996753b88ae 100644
--- a/drivers/led/Makefile
+++ b/drivers/led/Makefile
@@ -10,6 +10,6 @@ obj-$(CONFIG_LED_BCM6358) += led_bcm6358.o
obj-$(CONFIG_LED_BCM6753) += led_bcm6753.o
obj-$(CONFIG_LED_BCM6858) += led_bcm6858.o
obj-$(CONFIG_LED_PWM) += led_pwm.o
-obj-$(CONFIG_$(XPL_)LED_GPIO) += led_gpio.o
+obj-$(CONFIG_$(PHASE_)LED_GPIO) += led_gpio.o
obj-$(CONFIG_LED_CORTINA) += led_cortina.o
obj-$(CONFIG_LED_LP5562) += led_lp5562.o
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index 574add60005..e8c745f7d79 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -3,7 +3,7 @@
# Copyright (c) 2016, NVIDIA CORPORATION.
#
-obj-$(CONFIG_$(XPL_)DM_MAILBOX) += mailbox-uclass.o
+obj-$(CONFIG_$(PHASE_)DM_MAILBOX) += mailbox-uclass.o
obj-$(CONFIG_APPLE_MBOX) += apple-mbox.o
obj-$(CONFIG_IMX_MU_MBOX) += imx-mailbox.o
obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox.o
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 834e0285097..0911d2fc0cc 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -576,6 +576,7 @@ config QFW_SMBIOS
bool
default y
depends on QFW && SMBIOS && !SANDBOX && !SYSINFO_SMBIOS
+ select BLOBLIST
help
Hidden option to read SMBIOS tables from QEMU.
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 0b81ba2604f..248068d5b43 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -18,7 +18,7 @@ obj-$(CONFIG_SANDBOX) += p2sb_sandbox.o p2sb_emul.o
obj-$(CONFIG_SANDBOX) += swap_case.o
endif
-ifdef CONFIG_$(XPL_)DM_I2C
+ifdef CONFIG_$(PHASE_)DM_I2C
ifndef CONFIG_XPL_BUILD
obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o
obj-$(CONFIG_USB_HUB_USB251XB) += usb251xb.o
@@ -37,14 +37,14 @@ obj-$(CONFIG_FSL_DEVICE_DISABLE) += fsl_devdis.o
obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
obj-$(CONFIG_FSL_IIM) += fsl_iim.o
obj-$(CONFIG_FSL_SEC_MON) += fsl_sec_mon.o
-obj-$(CONFIG_$(XPL_)FS_LOADER) += fs_loader.o
+obj-$(CONFIG_$(PHASE_)FS_LOADER) += fs_loader.o
obj-$(CONFIG_GATEWORKS_SC) += gsc.o
obj-$(CONFIG_GDSYS_IOEP) += gdsys_ioep.o
obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.o
obj-$(CONFIG_GDSYS_SOC) += gdsys_soc.o
obj-$(CONFIG_IRQ) += irq-uclass.o
obj-$(CONFIG_SANDBOX) += irq_sandbox.o irq_sandbox_test.o
-obj-$(CONFIG_$(XPL_)I2C_EEPROM) += i2c_eeprom.o
+obj-$(CONFIG_$(PHASE_)I2C_EEPROM) += i2c_eeprom.o
obj-$(CONFIG_IHS_FPGA) += ihs_fpga.o
obj-$(CONFIG_IMX8) += imx8/
obj-$(CONFIG_IMX_ELE) += imx_ele/
@@ -53,14 +53,14 @@ obj-$(CONFIG_LED_STATUS) += status_led.o
obj-$(CONFIG_LED_STATUS_GPIO) += gpio_led.o
obj-$(CONFIG_MPC83XX_SERDES) += mpc83xx_serdes.o
obj-$(CONFIG_$(PHASE_)LS2_SFP) += ls2_sfp.o
-obj-$(CONFIG_$(XPL_)MXC_OCOTP) += mxc_ocotp.o
+obj-$(CONFIG_$(PHASE_)MXC_OCOTP) += mxc_ocotp.o
obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
obj-$(CONFIG_NPCM_OTP) += npcm_otp.o
obj-$(CONFIG_NPCM_HOST) += npcm_host_intf.o
obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o
obj-$(CONFIG_P2SB) += p2sb-uclass.o
obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
-obj-$(CONFIG_$(XPL_)PWRSEQ) += pwrseq-uclass.o
+obj-$(CONFIG_$(PHASE_)PWRSEQ) += pwrseq-uclass.o
ifdef CONFIG_QFW
obj-y += qfw.o
obj-$(CONFIG_QFW_ACPI) += qfw_acpi.o
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 6740591a653..38867f30a7e 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -528,6 +528,7 @@ config SPL_MMC_SDHCI_ADMA
config MMC_SDHCI_ADMA_FORCE_32BIT
bool "Force 32 bit mode for ADMA on 64 bit platforms"
+ depends on MMC_SDHCI_ADMA || SPL_MMC_SDHCI_ADMA
help
This forces SDHCI ADMA to be built for 32 bit descriptors, even
on a 64 bit platform where they would otherwise be assumed to
@@ -537,6 +538,7 @@ config MMC_SDHCI_ADMA_FORCE_32BIT
config MMC_SDHCI_ADMA_64BIT
bool "Use SHDCI ADMA with 64 bit descriptors"
+ depends on MMC_SDHCI_ADMA || SPL_MMC_SDHCI_ADMA
depends on !MMC_SDHCI_ADMA_FORCE_32BIT
default y if DMA_ADDR_T_64BIT
help
@@ -869,7 +871,7 @@ config FTSDC010_SDIO
config MMC_MTK
bool "MediaTek SD/MMC Card Interface support"
- depends on ARCH_MEDIATEK || ARCH_MTMIPS
+ depends on ARCH_MEDIATEK || ARCH_MTMIPS || ARCH_AIROHA
depends on OF_CONTROL
help
This selects the MediaTek(R) Secure digital and Multimedia card Interface.
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 94ed28ead71..360706f53d2 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -4,17 +4,17 @@
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-y += mmc.o
-obj-$(CONFIG_$(XPL_)DM_MMC) += mmc-uclass.o
+obj-$(CONFIG_$(PHASE_)DM_MMC) += mmc-uclass.o
ifdef CONFIG_$(PHASE_)DM_MMC
obj-$(CONFIG_$(PHASE_)BOOTSTD) += mmc_bootdev.o
endif
obj-$(CONFIG_$(PHASE_)MMC_WRITE) += mmc_write.o
-obj-$(CONFIG_$(XPL_)MMC_PWRSEQ) += mmc-pwrseq.o
+obj-$(CONFIG_$(PHASE_)MMC_PWRSEQ) += mmc-pwrseq.o
obj-$(CONFIG_MMC_SDHCI_ADMA_HELPERS) += sdhci-adma.o
-ifndef CONFIG_$(XPL_)BLK
+ifndef CONFIG_$(PHASE_)BLK
obj-y += mmc_legacy.o
endif
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
index c8db4f811c2..9af84da1599 100644
--- a/drivers/mmc/mmc-uclass.c
+++ b/drivers/mmc/mmc-uclass.c
@@ -498,22 +498,12 @@ static int mmc_blk_probe(struct udevice *dev)
return ret;
}
- ret = device_probe(dev);
- if (ret) {
- debug("Probing %s failed (err=%d)\n", dev->name, ret);
-
- mmc_deinit(mmc);
-
- return ret;
- }
-
return 0;
}
-static int mmc_blk_remove(struct udevice *dev)
+static int mmc_remove(struct udevice *dev)
{
- struct udevice *mmc_dev = dev_get_parent(dev);
- struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc_dev);
+ struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
struct mmc *mmc = upriv->mmc;
return mmc_deinit(mmc);
@@ -533,7 +523,6 @@ U_BOOT_DRIVER(mmc_blk) = {
.id = UCLASS_BLK,
.ops = &mmc_blk_ops,
.probe = mmc_blk_probe,
- .remove = mmc_blk_remove,
.flags = DM_FLAG_OS_PREPARE,
};
#endif /* CONFIG_BLK */
@@ -543,4 +532,5 @@ UCLASS_DRIVER(mmc) = {
.name = "mmc",
.flags = DM_UC_FLAG_SEQ_ALIAS,
.per_device_auto = sizeof(struct mmc_uclass_priv),
+ .pre_remove = mmc_remove,
};
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 31a72366206..47139e0a911 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -3040,9 +3040,9 @@ static int mmc_complete_init(struct mmc *mmc)
return err;
}
-static void __maybe_unused mmc_cyclic_cd_poll(struct cyclic_info *c)
+static void mmc_cyclic_cd_poll(struct cyclic_info *c)
{
- struct mmc *m = CONFIG_IS_ENABLED(CYCLIC, (container_of(c, struct mmc, cyclic)), (NULL));
+ struct mmc *m = container_of(c, struct mmc, cyclic);
if (!m->has_init)
return;
@@ -3073,15 +3073,15 @@ int mmc_init(struct mmc *mmc)
if (!err)
err = mmc_complete_init(mmc);
- if (err)
+ if (err) {
pr_info("%s: %d, time %lu\n", __func__, err, get_timer(start));
+ return err;
+ }
if (CONFIG_IS_ENABLED(CYCLIC, (!mmc->cyclic.func), (NULL))) {
/* Register cyclic function for card detect polling */
- CONFIG_IS_ENABLED(CYCLIC, (cyclic_register(&mmc->cyclic,
- mmc_cyclic_cd_poll,
- 100 * 1000,
- mmc->cfg->name)));
+ cyclic_register(&mmc->cyclic, mmc_cyclic_cd_poll, 100 * 1000,
+ mmc->cfg->name);
}
return err;
@@ -3092,7 +3092,7 @@ int mmc_deinit(struct mmc *mmc)
u32 caps_filtered;
if (CONFIG_IS_ENABLED(CYCLIC, (mmc->cyclic.func), (NULL)))
- CONFIG_IS_ENABLED(CYCLIC, (cyclic_unregister(&mmc->cyclic)));
+ cyclic_unregister(&mmc->cyclic);
if (!CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) &&
!CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) &&
diff --git a/drivers/mmc/mmc_boot.c b/drivers/mmc/mmc_boot.c
index 367c957b518..986e6c500b1 100644
--- a/drivers/mmc/mmc_boot.c
+++ b/drivers/mmc/mmc_boot.c
@@ -8,20 +8,107 @@
#include <mmc.h>
#include "mmc_private.h"
-/*
- * This function changes the size of boot partition and the size of rpmb
- * partition present on EMMC devices.
- *
- * Input Parameters:
- * struct *mmc: pointer for the mmc device strcuture
- * bootsize: size of boot partition
- * rpmbsize: size of rpmb partition
- *
- * Returns 0 on success.
- */
+static int mmc_resize_boot_micron(struct mmc *mmc, unsigned long bootsize,
+ unsigned long rpmbsize)
+{
+ int err;
-int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
- unsigned long rpmbsize)
+ /* Micron eMMC doesn't support resizing RPMB partition */
+ (void)rpmbsize;
+
+ /* BOOT partition size is multiple of 128KB */
+ bootsize = (bootsize * 1024) / 128;
+
+ if (bootsize > 0xff)
+ bootsize = 0xff;
+
+ /* Set EXT_CSD[175] ERASE_GROUP_DEF to 0x01 */
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_ERASE_GROUP_DEF, 0x01);
+ if (err)
+ goto error;
+
+ /* Set EXT_CSD[127:125] for BOOT partition size, [125] is low byte */
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BOOT_SIZE_MULT_MICRON, bootsize);
+ if (err)
+ goto error;
+
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BOOT_SIZE_MULT_MICRON + 1, 0x00);
+ if (err)
+ goto error;
+
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BOOT_SIZE_MULT_MICRON + 2, 0x00);
+ if (err)
+ goto error;
+
+ /* Set EXT_CSD[155] PARTITION_SETTING_COMPLETE to 0x01 */
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_PARTITION_SETTING, 0x01);
+ if (err)
+ goto error;
+
+ return 0;
+
+error:
+ debug("%s: Error = %d\n", __func__, err);
+ return err;
+}
+
+static int mmc_resize_boot_sandisk(struct mmc *mmc, unsigned long bootsize,
+ unsigned long rpmbsize)
+{
+ int err;
+ struct mmc_cmd cmd;
+
+ /* BOOT/RPMB partition size is multiple of 128KB */
+ bootsize = (bootsize * 1024) / 128;
+ rpmbsize = (rpmbsize * 1024) / 128;
+
+ if (bootsize > 0xff)
+ bootsize = 0xff;
+
+ if (rpmbsize > 0xff)
+ rpmbsize = 0xff;
+
+ /* Send BOOT/RPMB resize op code */
+ cmd.cmdidx = MMC_CMD_RES_MAN;
+ cmd.resp_type = MMC_RSP_R1b;
+ cmd.cmdarg = MMC_CMD62_ARG_SANDISK;
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (err)
+ goto error;
+
+ /* Arg: BOOT partition size */
+ cmd.cmdidx = MMC_CMD_RES_MAN;
+ cmd.resp_type = MMC_RSP_R1b;
+ cmd.cmdarg = bootsize;
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (err)
+ goto error;
+
+ /* Arg: RPMB partition size */
+ cmd.cmdidx = MMC_CMD_RES_MAN;
+ cmd.resp_type = MMC_RSP_R1b;
+ cmd.cmdarg = rpmbsize;
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (err)
+ goto error;
+
+ return 0;
+
+error:
+ debug("%s: Error = %d\n", __func__, err);
+ return err;
+}
+
+static int mmc_resize_boot_samsung(struct mmc *mmc, unsigned long bootsize,
+ unsigned long rpmbsize)
{
int err;
struct mmc_cmd cmd;
@@ -32,10 +119,8 @@ int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
cmd.cmdarg = MMC_CMD62_ARG1;
err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err) {
- debug("mmc_boot_partition_size_change: Error1 = %d\n", err);
- return err;
- }
+ if (err)
+ goto error;
/* Boot partition changing mode */
cmd.cmdidx = MMC_CMD_RES_MAN;
@@ -43,10 +128,9 @@ int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
cmd.cmdarg = MMC_CMD62_ARG2;
err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err) {
- debug("mmc_boot_partition_size_change: Error2 = %d\n", err);
- return err;
- }
+ if (err)
+ goto error;
+
/* boot partition size is multiple of 128KB */
bootsize = (bootsize * 1024) / 128;
@@ -56,10 +140,9 @@ int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
cmd.cmdarg = bootsize;
err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err) {
- debug("mmc_boot_partition_size_change: Error3 = %d\n", err);
- return err;
- }
+ if (err)
+ goto error;
+
/* RPMB partition size is multiple of 128KB */
rpmbsize = (rpmbsize * 1024) / 128;
/* Arg: RPMB partition size */
@@ -68,11 +151,43 @@ int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
cmd.cmdarg = rpmbsize;
err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err) {
- debug("mmc_boot_partition_size_change: Error4 = %d\n", err);
- return err;
- }
+ if (err)
+ goto error;
+
return 0;
+
+error:
+ debug("%s: Error = %d\n", __func__, err);
+ return err;
+}
+
+/*
+ * This function changes the size of BOOT partition and the size of RPMB
+ * partition present on eMMC devices.
+ *
+ * Input Parameters:
+ * struct *mmc: pointer for the mmc device strcuture
+ * bootsize: size of BOOT partition
+ * rpmbsize: size of RPMB partition
+ *
+ * Returns 0 on success.
+ */
+
+int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
+ unsigned long rpmbsize)
+{
+ switch (mmc->cid[0] >> 24) {
+ case CID_MANFID_MICRON:
+ return mmc_resize_boot_micron(mmc, bootsize, rpmbsize);
+ case CID_MANFID_SAMSUNG:
+ return mmc_resize_boot_samsung(mmc, bootsize, rpmbsize);
+ case CID_MANFID_SANDISK:
+ return mmc_resize_boot_sandisk(mmc, bootsize, rpmbsize);
+ default:
+ printf("Unsupported manufacturer id 0x%02x\n",
+ mmc->cid[0] >> 24);
+ return -EPERM;
+ }
}
/*
diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c
index c023d15e52a..90fcf2679bb 100644
--- a/drivers/mmc/mmc_write.c
+++ b/drivers/mmc/mmc_write.c
@@ -80,6 +80,8 @@ ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt)
struct mmc *mmc = find_mmc_device(dev_num);
lbaint_t blk = 0, blk_r = 0;
int timeout_ms = 1000;
+ u32 grpcnt;
+
if (!mmc)
return -1;
@@ -123,6 +125,15 @@ ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt)
} else {
blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ?
mmc->erase_grp_size : (blkcnt - blk);
+
+ grpcnt = (blkcnt - blk) / mmc->erase_grp_size;
+ /* Max 2GB per spec */
+ if ((blkcnt - blk) > 0x400000)
+ blk_r = 0x400000;
+ else if (grpcnt)
+ blk_r = grpcnt * mmc->erase_grp_size;
+ else
+ blk_r = blkcnt - blk;
}
err = mmc_erase_t(mmc, start + blk, blk_r, erase_args);
if (err)
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 4833b5158c7..dc7f0724a7b 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -177,8 +177,10 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data)
} while (!(stat & SDHCI_INT_DATA_END));
#if (CONFIG_IS_ENABLED(MMC_SDHCI_SDMA) || CONFIG_IS_ENABLED(MMC_SDHCI_ADMA))
- dma_unmap_single(host->start_addr, data->blocks * data->blocksize,
- mmc_get_dma_dir(data));
+ if (host->flags & USE_DMA) {
+ dma_unmap_single(host->start_addr, data->blocks * data->blocksize,
+ mmc_get_dma_dir(data));
+ }
#endif
return 0;
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index f5ddfbf4b83..3a1e7e18736 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -941,6 +941,19 @@ spinand_select_op_variant(struct spinand_device *spinand,
return NULL;
}
+static int spinand_setup_slave(struct spinand_device *spinand,
+ const struct spinand_info *spinand_info)
+{
+ struct spi_slave *slave = spinand->slave;
+ struct udevice *bus = slave->dev->parent;
+ struct dm_spi_ops *ops = spi_get_ops(bus);
+
+ if (!ops->setup_for_spinand)
+ return 0;
+
+ return ops->setup_for_spinand(slave, spinand_info);
+}
+
/**
* spinand_match_and_init() - Try to find a match between a device ID and an
* entry in a spinand_info table
@@ -964,6 +977,7 @@ int spinand_match_and_init(struct spinand_device *spinand,
u8 *id = spinand->id.data;
struct nand_device *nand = spinand_to_nand(spinand);
unsigned int i;
+ int ret;
for (i = 0; i < table_size; i++) {
const struct spinand_info *info = &table[i];
@@ -975,6 +989,10 @@ int spinand_match_and_init(struct spinand_device *spinand,
if (memcmp(id + 1, info->devid.id, info->devid.len))
continue;
+ ret = spinand_setup_slave(spinand, info);
+ if (ret)
+ return ret;
+
nand->memorg = table[i].memorg;
nand->eccreq = table[i].eccreq;
spinand->eccinfo = table[i].eccinfo;
diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
index 63770e12bd1..b61f713c301 100644
--- a/drivers/mux/Makefile
+++ b/drivers/mux/Makefile
@@ -4,4 +4,4 @@
# Jean-Jacques Hiblot <jjhiblot@ti.com>
obj-$(CONFIG_MULTIPLEXER) += mux-uclass.o
-obj-$(CONFIG_$(XPL_)MUX_MMIO) += mmio.o
+obj-$(CONFIG_$(PHASE_)MUX_MMIO) += mmio.o
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 3db784faedd..a0a7890bd26 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -122,6 +122,14 @@ config AG7XXX
This driver supports the Atheros AG7xxx Ethernet MAC. This MAC is
present in the Atheros AR7xxx, AR9xxx and QCA9xxx MIPS chips.
+config AIROHA_ETH
+ bool "Airoha Ethernet QDMA Driver"
+ depends on ARCH_AIROHA
+ select PHYLIB
+ select DM_RESET
+ help
+ This Driver support Airoha Ethernet QDMA Driver
+ Say Y to enable support for the Airoha Ethernet QDMA.
config ALTERA_TSE
bool "Altera Triple-Speed Ethernet MAC support"
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index d919d437c08..3244d39036d 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -5,6 +5,7 @@
obj-$(CONFIG_AG7XXX) += ag7xxx.o
+obj-$(CONFIG_AIROHA_ETH) += airoha_eth.o
obj-$(CONFIG_ALTERA_TSE) += altera_tse.o
obj-$(CONFIG_ASPEED_MDIO) += aspeed_mdio.o
obj-$(CONFIG_BCM6348_ETH) += bcm6348-eth.o
diff --git a/drivers/net/airoha_eth.c b/drivers/net/airoha_eth.c
new file mode 100644
index 00000000000..7e35e1fd41d
--- /dev/null
+++ b/drivers/net/airoha_eth.c
@@ -0,0 +1,948 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Based on Linux airoha_eth.c majorly rewritten
+ * and simplified for U-Boot usage for single TX/RX ring.
+ *
+ * Copyright (c) 2024 AIROHA Inc
+ * Author: Lorenzo Bianconi <lorenzo@kernel.org>
+ * Christian Marangi <ansuelsmth@gmail.org>
+ */
+
+#include <dm.h>
+#include <dm/devres.h>
+#include <mapmem.h>
+#include <net.h>
+#include <regmap.h>
+#include <reset.h>
+#include <syscon.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/time.h>
+
+#define AIROHA_MAX_NUM_GDM_PORTS 1
+#define AIROHA_MAX_NUM_QDMA 1
+#define AIROHA_MAX_NUM_RSTS 3
+#define AIROHA_MAX_NUM_XSI_RSTS 4
+
+#define AIROHA_MAX_PACKET_SIZE 2048
+#define AIROHA_NUM_TX_RING 1
+#define AIROHA_NUM_RX_RING 1
+#define AIROHA_NUM_TX_IRQ 1
+#define HW_DSCP_NUM 32
+#define IRQ_QUEUE_LEN 1
+#define TX_DSCP_NUM 16
+#define RX_DSCP_NUM PKTBUFSRX
+
+/* SCU */
+#define SCU_SHARE_FEMEM_SEL 0x958
+
+/* SWITCH */
+#define SWITCH_MFC 0x10
+#define SWITCH_BC_FFP GENMASK(31, 24)
+#define SWITCH_UNM_FFP GENMASK(23, 16)
+#define SWITCH_UNU_FFP GENMASK(15, 8)
+#define SWITCH_PMCR(_n) 0x3000 + ((_n) * 0x100)
+#define SWITCH_IPG_CFG GENMASK(19, 18)
+#define SWITCH_IPG_CFG_NORMAL FIELD_PREP(SWITCH_IPG_CFG, 0x0)
+#define SWITCH_IPG_CFG_SHORT FIELD_PREP(SWITCH_IPG_CFG, 0x1)
+#define SWITCH_IPG_CFG_SHRINK FIELD_PREP(SWITCH_IPG_CFG, 0x2)
+#define SWITCH_MAC_MODE BIT(16)
+#define SWITCH_FORCE_MODE BIT(15)
+#define SWITCH_MAC_TX_EN BIT(14)
+#define SWITCH_MAC_RX_EN BIT(13)
+#define SWITCH_BKOFF_EN BIT(9)
+#define SWITCH_BKPR_EN BIT(8)
+#define SWITCH_FORCE_RX_FC BIT(5)
+#define SWITCH_FORCE_TX_FC BIT(4)
+#define SWITCH_FORCE_SPD GENMASK(3, 2)
+#define SWITCH_FORCE_SPD_10 FIELD_PREP(SWITCH_FORCE_SPD, 0x0)
+#define SWITCH_FORCE_SPD_100 FIELD_PREP(SWITCH_FORCE_SPD, 0x1)
+#define SWITCH_FORCE_SPD_1000 FIELD_PREP(SWITCH_FORCE_SPD, 0x2)
+#define SWITCH_FORCE_DPX BIT(1)
+#define SWITCH_FORCE_LNK BIT(0)
+#define SWITCH_SMACCR0 0x30e4
+#define SMACCR0_MAC2 GENMASK(31, 24)
+#define SMACCR0_MAC3 GENMASK(23, 16)
+#define SMACCR0_MAC4 GENMASK(15, 8)
+#define SMACCR0_MAC5 GENMASK(7, 0)
+#define SWITCH_SMACCR1 0x30e8
+#define SMACCR1_MAC0 GENMASK(15, 8)
+#define SMACCR1_MAC1 GENMASK(7, 0)
+#define SWITCH_PHY_POLL 0x7018
+#define SWITCH_PHY_AP_EN GENMASK(30, 24)
+#define SWITCH_EEE_POLL_EN GENMASK(22, 16)
+#define SWITCH_PHY_PRE_EN BIT(15)
+#define SWITCH_PHY_END_ADDR GENMASK(12, 8)
+#define SWITCH_PHY_ST_ADDR GENMASK(4, 0)
+
+/* FE */
+#define PSE_BASE 0x0100
+#define CSR_IFC_BASE 0x0200
+#define CDM1_BASE 0x0400
+#define GDM1_BASE 0x0500
+#define PPE1_BASE 0x0c00
+
+#define CDM2_BASE 0x1400
+#define GDM2_BASE 0x1500
+
+#define GDM3_BASE 0x1100
+#define GDM4_BASE 0x2500
+
+#define GDM_BASE(_n) \
+ ((_n) == 4 ? GDM4_BASE : \
+ (_n) == 3 ? GDM3_BASE : \
+ (_n) == 2 ? GDM2_BASE : GDM1_BASE)
+
+#define REG_GDM_FWD_CFG(_n) GDM_BASE(_n)
+#define GDM_DROP_CRC_ERR BIT(23)
+#define GDM_IP4_CKSUM BIT(22)
+#define GDM_TCP_CKSUM BIT(21)
+#define GDM_UDP_CKSUM BIT(20)
+#define GDM_UCFQ_MASK GENMASK(15, 12)
+#define GDM_BCFQ_MASK GENMASK(11, 8)
+#define GDM_MCFQ_MASK GENMASK(7, 4)
+#define GDM_OCFQ_MASK GENMASK(3, 0)
+
+/* QDMA */
+#define REG_QDMA_GLOBAL_CFG 0x0004
+#define GLOBAL_CFG_RX_2B_OFFSET_MASK BIT(31)
+#define GLOBAL_CFG_DMA_PREFERENCE_MASK GENMASK(30, 29)
+#define GLOBAL_CFG_CPU_TXR_RR_MASK BIT(28)
+#define GLOBAL_CFG_DSCP_BYTE_SWAP_MASK BIT(27)
+#define GLOBAL_CFG_PAYLOAD_BYTE_SWAP_MASK BIT(26)
+#define GLOBAL_CFG_MULTICAST_MODIFY_FP_MASK BIT(25)
+#define GLOBAL_CFG_OAM_MODIFY_MASK BIT(24)
+#define GLOBAL_CFG_RESET_MASK BIT(23)
+#define GLOBAL_CFG_RESET_DONE_MASK BIT(22)
+#define GLOBAL_CFG_MULTICAST_EN_MASK BIT(21)
+#define GLOBAL_CFG_IRQ1_EN_MASK BIT(20)
+#define GLOBAL_CFG_IRQ0_EN_MASK BIT(19)
+#define GLOBAL_CFG_LOOPCNT_EN_MASK BIT(18)
+#define GLOBAL_CFG_RD_BYPASS_WR_MASK BIT(17)
+#define GLOBAL_CFG_QDMA_LOOPBACK_MASK BIT(16)
+#define GLOBAL_CFG_LPBK_RXQ_SEL_MASK GENMASK(13, 8)
+#define GLOBAL_CFG_CHECK_DONE_MASK BIT(7)
+#define GLOBAL_CFG_TX_WB_DONE_MASK BIT(6)
+#define GLOBAL_CFG_MAX_ISSUE_NUM_MASK GENMASK(5, 4)
+#define GLOBAL_CFG_RX_DMA_BUSY_MASK BIT(3)
+#define GLOBAL_CFG_RX_DMA_EN_MASK BIT(2)
+#define GLOBAL_CFG_TX_DMA_BUSY_MASK BIT(1)
+#define GLOBAL_CFG_TX_DMA_EN_MASK BIT(0)
+
+#define REG_FWD_DSCP_BASE 0x0010
+#define REG_FWD_BUF_BASE 0x0014
+
+#define REG_HW_FWD_DSCP_CFG 0x0018
+#define HW_FWD_DSCP_PAYLOAD_SIZE_MASK GENMASK(29, 28)
+#define HW_FWD_DSCP_SCATTER_LEN_MASK GENMASK(17, 16)
+#define HW_FWD_DSCP_MIN_SCATTER_LEN_MASK GENMASK(15, 0)
+
+#define REG_INT_STATUS(_n) \
+ (((_n) == 4) ? 0x0730 : \
+ ((_n) == 3) ? 0x0724 : \
+ ((_n) == 2) ? 0x0720 : \
+ ((_n) == 1) ? 0x0024 : 0x0020)
+
+#define REG_TX_IRQ_BASE(_n) ((_n) ? 0x0048 : 0x0050)
+
+#define REG_TX_IRQ_CFG(_n) ((_n) ? 0x004c : 0x0054)
+#define TX_IRQ_THR_MASK GENMASK(27, 16)
+#define TX_IRQ_DEPTH_MASK GENMASK(11, 0)
+
+#define REG_IRQ_CLEAR_LEN(_n) ((_n) ? 0x0064 : 0x0058)
+#define IRQ_CLEAR_LEN_MASK GENMASK(7, 0)
+
+#define REG_TX_RING_BASE(_n) \
+ (((_n) < 8) ? 0x0100 + ((_n) << 5) : 0x0b00 + (((_n) - 8) << 5))
+
+#define REG_TX_CPU_IDX(_n) \
+ (((_n) < 8) ? 0x0108 + ((_n) << 5) : 0x0b08 + (((_n) - 8) << 5))
+
+#define TX_RING_CPU_IDX_MASK GENMASK(15, 0)
+
+#define REG_TX_DMA_IDX(_n) \
+ (((_n) < 8) ? 0x010c + ((_n) << 5) : 0x0b0c + (((_n) - 8) << 5))
+
+#define TX_RING_DMA_IDX_MASK GENMASK(15, 0)
+
+#define IRQ_RING_IDX_MASK GENMASK(20, 16)
+#define IRQ_DESC_IDX_MASK GENMASK(15, 0)
+
+#define REG_RX_RING_BASE(_n) \
+ (((_n) < 16) ? 0x0200 + ((_n) << 5) : 0x0e00 + (((_n) - 16) << 5))
+
+#define REG_RX_RING_SIZE(_n) \
+ (((_n) < 16) ? 0x0204 + ((_n) << 5) : 0x0e04 + (((_n) - 16) << 5))
+
+#define RX_RING_THR_MASK GENMASK(31, 16)
+#define RX_RING_SIZE_MASK GENMASK(15, 0)
+
+#define REG_RX_CPU_IDX(_n) \
+ (((_n) < 16) ? 0x0208 + ((_n) << 5) : 0x0e08 + (((_n) - 16) << 5))
+
+#define RX_RING_CPU_IDX_MASK GENMASK(15, 0)
+
+#define REG_RX_DMA_IDX(_n) \
+ (((_n) < 16) ? 0x020c + ((_n) << 5) : 0x0e0c + (((_n) - 16) << 5))
+
+#define REG_RX_DELAY_INT_IDX(_n) \
+ (((_n) < 16) ? 0x0210 + ((_n) << 5) : 0x0e10 + (((_n) - 16) << 5))
+
+#define RX_DELAY_INT_MASK GENMASK(15, 0)
+
+#define RX_RING_DMA_IDX_MASK GENMASK(15, 0)
+
+#define REG_LMGR_INIT_CFG 0x1000
+#define LMGR_INIT_START BIT(31)
+#define LMGR_SRAM_MODE_MASK BIT(30)
+#define HW_FWD_PKTSIZE_OVERHEAD_MASK GENMASK(27, 20)
+#define HW_FWD_DESC_NUM_MASK GENMASK(16, 0)
+
+/* CTRL */
+#define QDMA_DESC_DONE_MASK BIT(31)
+#define QDMA_DESC_DROP_MASK BIT(30) /* tx: drop - rx: overflow */
+#define QDMA_DESC_MORE_MASK BIT(29) /* more SG elements */
+#define QDMA_DESC_DEI_MASK BIT(25)
+#define QDMA_DESC_NO_DROP_MASK BIT(24)
+#define QDMA_DESC_LEN_MASK GENMASK(15, 0)
+/* DATA */
+#define QDMA_DESC_NEXT_ID_MASK GENMASK(15, 0)
+/* TX MSG0 */
+#define QDMA_ETH_TXMSG_MIC_IDX_MASK BIT(30)
+#define QDMA_ETH_TXMSG_SP_TAG_MASK GENMASK(29, 14)
+#define QDMA_ETH_TXMSG_ICO_MASK BIT(13)
+#define QDMA_ETH_TXMSG_UCO_MASK BIT(12)
+#define QDMA_ETH_TXMSG_TCO_MASK BIT(11)
+#define QDMA_ETH_TXMSG_TSO_MASK BIT(10)
+#define QDMA_ETH_TXMSG_FAST_MASK BIT(9)
+#define QDMA_ETH_TXMSG_OAM_MASK BIT(8)
+#define QDMA_ETH_TXMSG_CHAN_MASK GENMASK(7, 3)
+#define QDMA_ETH_TXMSG_QUEUE_MASK GENMASK(2, 0)
+/* TX MSG1 */
+#define QDMA_ETH_TXMSG_NO_DROP BIT(31)
+#define QDMA_ETH_TXMSG_METER_MASK GENMASK(30, 24) /* 0x7f no meters */
+#define QDMA_ETH_TXMSG_FPORT_MASK GENMASK(23, 20)
+#define QDMA_ETH_TXMSG_NBOQ_MASK GENMASK(19, 15)
+#define QDMA_ETH_TXMSG_HWF_MASK BIT(14)
+#define QDMA_ETH_TXMSG_HOP_MASK BIT(13)
+#define QDMA_ETH_TXMSG_PTP_MASK BIT(12)
+#define QDMA_ETH_TXMSG_ACNT_G1_MASK GENMASK(10, 6) /* 0x1f do not count */
+#define QDMA_ETH_TXMSG_ACNT_G0_MASK GENMASK(5, 0) /* 0x3f do not count */
+
+/* RX MSG1 */
+#define QDMA_ETH_RXMSG_DEI_MASK BIT(31)
+#define QDMA_ETH_RXMSG_IP6_MASK BIT(30)
+#define QDMA_ETH_RXMSG_IP4_MASK BIT(29)
+#define QDMA_ETH_RXMSG_IP4F_MASK BIT(28)
+#define QDMA_ETH_RXMSG_L4_VALID_MASK BIT(27)
+#define QDMA_ETH_RXMSG_L4F_MASK BIT(26)
+#define QDMA_ETH_RXMSG_SPORT_MASK GENMASK(25, 21)
+#define QDMA_ETH_RXMSG_CRSN_MASK GENMASK(20, 16)
+#define QDMA_ETH_RXMSG_PPE_ENTRY_MASK GENMASK(15, 0)
+
+struct airoha_qdma_desc {
+ __le32 rsv;
+ __le32 ctrl;
+ __le32 addr;
+ __le32 data;
+ __le32 msg0;
+ __le32 msg1;
+ __le32 msg2;
+ __le32 msg3;
+};
+
+struct airoha_qdma_fwd_desc {
+ __le32 addr;
+ __le32 ctrl0;
+ __le32 ctrl1;
+ __le32 ctrl2;
+ __le32 msg0;
+ __le32 msg1;
+ __le32 rsv0;
+ __le32 rsv1;
+};
+
+struct airoha_queue {
+ struct airoha_qdma_desc *desc;
+ u16 head;
+
+ int ndesc;
+};
+
+struct airoha_tx_irq_queue {
+ struct airoha_qdma *qdma;
+
+ int size;
+ u32 *q;
+};
+
+struct airoha_qdma {
+ struct airoha_eth *eth;
+ void __iomem *regs;
+
+ struct airoha_tx_irq_queue q_tx_irq[AIROHA_NUM_TX_IRQ];
+
+ struct airoha_queue q_tx[AIROHA_NUM_TX_RING];
+ struct airoha_queue q_rx[AIROHA_NUM_RX_RING];
+
+ /* descriptor and packet buffers for qdma hw forward */
+ struct {
+ void *desc;
+ void *q;
+ } hfwd;
+};
+
+struct airoha_gdm_port {
+ struct airoha_qdma *qdma;
+ int id;
+};
+
+struct airoha_eth {
+ void __iomem *fe_regs;
+ void __iomem *switch_regs;
+
+ struct reset_ctl_bulk rsts;
+ struct reset_ctl_bulk xsi_rsts;
+
+ struct airoha_qdma qdma[AIROHA_MAX_NUM_QDMA];
+ struct airoha_gdm_port *ports[AIROHA_MAX_NUM_GDM_PORTS];
+};
+
+static u32 airoha_rr(void __iomem *base, u32 offset)
+{
+ return readl(base + offset);
+}
+
+static void airoha_wr(void __iomem *base, u32 offset, u32 val)
+{
+ writel(val, base + offset);
+}
+
+static u32 airoha_rmw(void __iomem *base, u32 offset, u32 mask, u32 val)
+{
+ val |= (airoha_rr(base, offset) & ~mask);
+ airoha_wr(base, offset, val);
+
+ return val;
+}
+
+#define airoha_fe_rr(eth, offset) \
+ airoha_rr((eth)->fe_regs, (offset))
+#define airoha_fe_wr(eth, offset, val) \
+ airoha_wr((eth)->fe_regs, (offset), (val))
+#define airoha_fe_rmw(eth, offset, mask, val) \
+ airoha_rmw((eth)->fe_regs, (offset), (mask), (val))
+#define airoha_fe_set(eth, offset, val) \
+ airoha_rmw((eth)->fe_regs, (offset), 0, (val))
+#define airoha_fe_clear(eth, offset, val) \
+ airoha_rmw((eth)->fe_regs, (offset), (val), 0)
+
+#define airoha_qdma_rr(qdma, offset) \
+ airoha_rr((qdma)->regs, (offset))
+#define airoha_qdma_wr(qdma, offset, val) \
+ airoha_wr((qdma)->regs, (offset), (val))
+#define airoha_qdma_rmw(qdma, offset, mask, val) \
+ airoha_rmw((qdma)->regs, (offset), (mask), (val))
+#define airoha_qdma_set(qdma, offset, val) \
+ airoha_rmw((qdma)->regs, (offset), 0, (val))
+#define airoha_qdma_clear(qdma, offset, val) \
+ airoha_rmw((qdma)->regs, (offset), (val), 0)
+
+#define airoha_switch_wr(eth, offset, val) \
+ airoha_wr((eth)->switch_regs, (offset), (val))
+
+static void airoha_fe_maccr_init(struct airoha_eth *eth)
+{
+ int p;
+
+ for (p = 1; p <= ARRAY_SIZE(eth->ports); p++) {
+ /* Disable any kind of CRC drop or offload */
+ airoha_fe_wr(eth, REG_GDM_FWD_CFG(p), 0);
+ }
+}
+
+static int airoha_fe_init(struct airoha_eth *eth)
+{
+ airoha_fe_maccr_init(eth);
+
+ return 0;
+}
+
+static void airoha_qdma_reset_rx_desc(struct airoha_queue *q, int index,
+ uchar *rx_packet)
+{
+ struct airoha_qdma_desc *desc;
+ u32 val;
+
+ desc = &q->desc[index];
+ index = (index + 1) % q->ndesc;
+
+ dma_map_single(rx_packet, PKTSIZE_ALIGN, DMA_TO_DEVICE);
+
+ WRITE_ONCE(desc->msg0, cpu_to_le32(0));
+ WRITE_ONCE(desc->msg1, cpu_to_le32(0));
+ WRITE_ONCE(desc->msg2, cpu_to_le32(0));
+ WRITE_ONCE(desc->msg3, cpu_to_le32(0));
+ WRITE_ONCE(desc->addr, cpu_to_le32(virt_to_phys(rx_packet)));
+ WRITE_ONCE(desc->data, cpu_to_le32(index));
+ val = FIELD_PREP(QDMA_DESC_LEN_MASK, PKTSIZE_ALIGN);
+ WRITE_ONCE(desc->ctrl, cpu_to_le32(val));
+
+ dma_map_single(desc, sizeof(*desc), DMA_TO_DEVICE);
+}
+
+static void airoha_qdma_init_rx_desc(struct airoha_queue *q)
+{
+ int i;
+
+ for (i = 0; i < q->ndesc; i++)
+ airoha_qdma_reset_rx_desc(q, i, net_rx_packets[i]);
+}
+
+static int airoha_qdma_init_rx_queue(struct airoha_queue *q,
+ struct airoha_qdma *qdma, int ndesc)
+{
+ int qid = q - &qdma->q_rx[0];
+ unsigned long dma_addr;
+
+ q->ndesc = ndesc;
+ q->head = 0;
+
+ q->desc = dma_alloc_coherent(q->ndesc * sizeof(*q->desc), &dma_addr);
+ if (!q->desc)
+ return -ENOMEM;
+
+ memset(q->desc, 0, q->ndesc * sizeof(*q->desc));
+ dma_map_single(q->desc, q->ndesc * sizeof(*q->desc), DMA_TO_DEVICE);
+
+ airoha_qdma_wr(qdma, REG_RX_RING_BASE(qid), dma_addr);
+ airoha_qdma_rmw(qdma, REG_RX_RING_SIZE(qid),
+ RX_RING_SIZE_MASK,
+ FIELD_PREP(RX_RING_SIZE_MASK, ndesc));
+
+ airoha_qdma_rmw(qdma, REG_RX_RING_SIZE(qid), RX_RING_THR_MASK,
+ FIELD_PREP(RX_RING_THR_MASK, 0));
+ airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK,
+ FIELD_PREP(RX_RING_CPU_IDX_MASK, q->ndesc - 1));
+ airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK,
+ FIELD_PREP(RX_RING_DMA_IDX_MASK, q->head));
+
+ return 0;
+}
+
+static int airoha_qdma_init_rx(struct airoha_qdma *qdma)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) {
+ int err;
+
+ err = airoha_qdma_init_rx_queue(&qdma->q_rx[i], qdma,
+ RX_DSCP_NUM);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int airoha_qdma_init_tx_queue(struct airoha_queue *q,
+ struct airoha_qdma *qdma, int size)
+{
+ int qid = q - &qdma->q_tx[0];
+ unsigned long dma_addr;
+
+ q->ndesc = size;
+ q->head = 0;
+
+ q->desc = dma_alloc_coherent(q->ndesc * sizeof(*q->desc), &dma_addr);
+ if (!q->desc)
+ return -ENOMEM;
+
+ memset(q->desc, 0, q->ndesc * sizeof(*q->desc));
+ dma_map_single(q->desc, q->ndesc * sizeof(*q->desc), DMA_TO_DEVICE);
+
+ airoha_qdma_wr(qdma, REG_TX_RING_BASE(qid), dma_addr);
+ airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), TX_RING_CPU_IDX_MASK,
+ FIELD_PREP(TX_RING_CPU_IDX_MASK, q->head));
+ airoha_qdma_rmw(qdma, REG_TX_DMA_IDX(qid), TX_RING_DMA_IDX_MASK,
+ FIELD_PREP(TX_RING_DMA_IDX_MASK, q->head));
+
+ return 0;
+}
+
+static int airoha_qdma_tx_irq_init(struct airoha_tx_irq_queue *irq_q,
+ struct airoha_qdma *qdma, int size)
+{
+ int id = irq_q - &qdma->q_tx_irq[0];
+ unsigned long dma_addr;
+
+ irq_q->q = dma_alloc_coherent(size * sizeof(u32), &dma_addr);
+ if (!irq_q->q)
+ return -ENOMEM;
+
+ memset(irq_q->q, 0xffffffff, size * sizeof(u32));
+ irq_q->size = size;
+ irq_q->qdma = qdma;
+
+ dma_map_single(irq_q->q, size * sizeof(u32), DMA_TO_DEVICE);
+
+ airoha_qdma_wr(qdma, REG_TX_IRQ_BASE(id), dma_addr);
+ airoha_qdma_rmw(qdma, REG_TX_IRQ_CFG(id), TX_IRQ_DEPTH_MASK,
+ FIELD_PREP(TX_IRQ_DEPTH_MASK, size));
+
+ return 0;
+}
+
+static int airoha_qdma_init_tx(struct airoha_qdma *qdma)
+{
+ int i, err;
+
+ for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) {
+ err = airoha_qdma_tx_irq_init(&qdma->q_tx_irq[i], qdma,
+ IRQ_QUEUE_LEN);
+ if (err)
+ return err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) {
+ err = airoha_qdma_init_tx_queue(&qdma->q_tx[i], qdma,
+ TX_DSCP_NUM);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int airoha_qdma_init_hfwd_queues(struct airoha_qdma *qdma)
+{
+ unsigned long dma_addr;
+ u32 status;
+ int size;
+
+ size = HW_DSCP_NUM * sizeof(struct airoha_qdma_fwd_desc);
+ qdma->hfwd.desc = dma_alloc_coherent(size, &dma_addr);
+ if (!qdma->hfwd.desc)
+ return -ENOMEM;
+
+ memset(qdma->hfwd.desc, 0, size);
+ dma_map_single(qdma->hfwd.desc, size, DMA_TO_DEVICE);
+
+ airoha_qdma_wr(qdma, REG_FWD_DSCP_BASE, dma_addr);
+
+ size = AIROHA_MAX_PACKET_SIZE * HW_DSCP_NUM;
+ qdma->hfwd.q = dma_alloc_coherent(size, &dma_addr);
+ if (!qdma->hfwd.q)
+ return -ENOMEM;
+
+ memset(qdma->hfwd.q, 0, size);
+ dma_map_single(qdma->hfwd.q, size, DMA_TO_DEVICE);
+
+ airoha_qdma_wr(qdma, REG_FWD_BUF_BASE, dma_addr);
+
+ airoha_qdma_rmw(qdma, REG_HW_FWD_DSCP_CFG,
+ HW_FWD_DSCP_PAYLOAD_SIZE_MASK |
+ HW_FWD_DSCP_MIN_SCATTER_LEN_MASK,
+ FIELD_PREP(HW_FWD_DSCP_PAYLOAD_SIZE_MASK, 0) |
+ FIELD_PREP(HW_FWD_DSCP_MIN_SCATTER_LEN_MASK, 1));
+ airoha_qdma_rmw(qdma, REG_LMGR_INIT_CFG,
+ LMGR_INIT_START | LMGR_SRAM_MODE_MASK |
+ HW_FWD_DESC_NUM_MASK,
+ FIELD_PREP(HW_FWD_DESC_NUM_MASK, HW_DSCP_NUM) |
+ LMGR_INIT_START);
+
+ udelay(1000);
+ return read_poll_timeout(airoha_qdma_rr, status,
+ !(status & LMGR_INIT_START), USEC_PER_MSEC,
+ 30 * USEC_PER_MSEC, qdma,
+ REG_LMGR_INIT_CFG);
+}
+
+static int airoha_qdma_hw_init(struct airoha_qdma *qdma)
+{
+ int i;
+
+ /* clear pending irqs */
+ for (i = 0; i < 2; i++)
+ airoha_qdma_wr(qdma, REG_INT_STATUS(i), 0xffffffff);
+
+ airoha_qdma_wr(qdma, REG_QDMA_GLOBAL_CFG,
+ GLOBAL_CFG_CPU_TXR_RR_MASK |
+ GLOBAL_CFG_PAYLOAD_BYTE_SWAP_MASK |
+ GLOBAL_CFG_IRQ0_EN_MASK |
+ GLOBAL_CFG_TX_WB_DONE_MASK |
+ FIELD_PREP(GLOBAL_CFG_MAX_ISSUE_NUM_MASK, 3));
+
+ /* disable qdma rx delay interrupt */
+ for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) {
+ if (!qdma->q_rx[i].ndesc)
+ continue;
+
+ airoha_qdma_clear(qdma, REG_RX_DELAY_INT_IDX(i),
+ RX_DELAY_INT_MASK);
+ }
+
+ return 0;
+}
+
+static int airoha_qdma_init(struct udevice *dev,
+ struct airoha_eth *eth,
+ struct airoha_qdma *qdma)
+{
+ int err;
+
+ qdma->eth = eth;
+ qdma->regs = dev_remap_addr_name(dev, "qdma0");
+ if (IS_ERR(qdma->regs))
+ return PTR_ERR(qdma->regs);
+
+ err = airoha_qdma_init_rx(qdma);
+ if (err)
+ return err;
+
+ err = airoha_qdma_init_tx(qdma);
+ if (err)
+ return err;
+
+ err = airoha_qdma_init_hfwd_queues(qdma);
+ if (err)
+ return err;
+
+ return airoha_qdma_hw_init(qdma);
+}
+
+static int airoha_hw_init(struct udevice *dev,
+ struct airoha_eth *eth)
+{
+ int ret, i;
+
+ /* disable xsi */
+ ret = reset_assert_bulk(&eth->xsi_rsts);
+ if (ret)
+ return ret;
+
+ ret = reset_assert_bulk(&eth->rsts);
+ if (ret)
+ return ret;
+
+ mdelay(20);
+
+ ret = reset_deassert_bulk(&eth->rsts);
+ if (ret)
+ return ret;
+
+ mdelay(20);
+
+ ret = airoha_fe_init(eth);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) {
+ ret = airoha_qdma_init(dev, eth, &eth->qdma[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int airoha_switch_init(struct udevice *dev, struct airoha_eth *eth)
+{
+ ofnode switch_node;
+ fdt_addr_t addr;
+
+ switch_node = ofnode_by_compatible(ofnode_null(), "airoha,en7581-switch");
+ if (!ofnode_valid(switch_node))
+ return -EINVAL;
+
+ addr = ofnode_get_addr(switch_node);
+ if (addr == FDT_ADDR_T_NONE)
+ return -ENOMEM;
+
+ /* Switch doesn't have a DEV, gets address and setup Flood and CPU port */
+ eth->switch_regs = map_sysmem(addr, 0);
+
+ /* Set FLOOD, no CPU switch register */
+ airoha_switch_wr(eth, SWITCH_MFC, SWITCH_BC_FFP | SWITCH_UNM_FFP |
+ SWITCH_UNU_FFP);
+
+ /* Set CPU 6 PMCR */
+ airoha_switch_wr(eth, SWITCH_PMCR(6),
+ SWITCH_IPG_CFG_SHORT | SWITCH_MAC_MODE |
+ SWITCH_FORCE_MODE | SWITCH_MAC_TX_EN |
+ SWITCH_MAC_RX_EN | SWITCH_BKOFF_EN | SWITCH_BKPR_EN |
+ SWITCH_FORCE_RX_FC | SWITCH_FORCE_TX_FC |
+ SWITCH_FORCE_SPD_1000 | SWITCH_FORCE_DPX |
+ SWITCH_FORCE_LNK);
+
+ /* Sideband signal error for Port 3, which need the auto polling */
+ airoha_switch_wr(eth, SWITCH_PHY_POLL,
+ FIELD_PREP(SWITCH_PHY_AP_EN, 0x7f) |
+ FIELD_PREP(SWITCH_EEE_POLL_EN, 0x7f) |
+ SWITCH_PHY_PRE_EN |
+ FIELD_PREP(SWITCH_PHY_END_ADDR, 0xc) |
+ FIELD_PREP(SWITCH_PHY_ST_ADDR, 0x8));
+
+ return 0;
+}
+
+static int airoha_eth_probe(struct udevice *dev)
+{
+ struct airoha_eth *eth = dev_get_priv(dev);
+ struct regmap *scu_regmap;
+ ofnode scu_node;
+ int ret;
+
+ scu_node = ofnode_by_compatible(ofnode_null(), "airoha,en7581-scu");
+ if (!ofnode_valid(scu_node))
+ return -EINVAL;
+
+ scu_regmap = syscon_node_to_regmap(scu_node);
+ if (IS_ERR(scu_regmap))
+ return PTR_ERR(scu_regmap);
+
+ /* It seems by default the FEMEM_SEL is set to Memory (0x1)
+ * preventing any access to any QDMA and FrameEngine register
+ * reporting all 0xdeadbeef (poor cow :( )
+ */
+ regmap_write(scu_regmap, SCU_SHARE_FEMEM_SEL, 0x0);
+
+ eth->fe_regs = dev_remap_addr_name(dev, "fe");
+ if (!eth->fe_regs)
+ return -ENOMEM;
+
+ eth->rsts.resets = devm_kcalloc(dev, AIROHA_MAX_NUM_RSTS,
+ sizeof(struct reset_ctl), GFP_KERNEL);
+ if (!eth->rsts.resets)
+ return -ENOMEM;
+ eth->rsts.count = AIROHA_MAX_NUM_RSTS;
+
+ eth->xsi_rsts.resets = devm_kcalloc(dev, AIROHA_MAX_NUM_XSI_RSTS,
+ sizeof(struct reset_ctl), GFP_KERNEL);
+ if (!eth->xsi_rsts.resets)
+ return -ENOMEM;
+ eth->xsi_rsts.count = AIROHA_MAX_NUM_XSI_RSTS;
+
+ ret = reset_get_by_name(dev, "fe", &eth->rsts.resets[0]);
+ if (ret)
+ return ret;
+
+ ret = reset_get_by_name(dev, "pdma", &eth->rsts.resets[1]);
+ if (ret)
+ return ret;
+
+ ret = reset_get_by_name(dev, "qdma", &eth->rsts.resets[2]);
+ if (ret)
+ return ret;
+
+ ret = reset_get_by_name(dev, "hsi0-mac", &eth->xsi_rsts.resets[0]);
+ if (ret)
+ return ret;
+
+ ret = reset_get_by_name(dev, "hsi1-mac", &eth->xsi_rsts.resets[1]);
+ if (ret)
+ return ret;
+
+ ret = reset_get_by_name(dev, "hsi-mac", &eth->xsi_rsts.resets[2]);
+ if (ret)
+ return ret;
+
+ ret = reset_get_by_name(dev, "xfp-mac", &eth->xsi_rsts.resets[3]);
+ if (ret)
+ return ret;
+
+ ret = airoha_hw_init(dev, eth);
+ if (ret)
+ return ret;
+
+ return airoha_switch_init(dev, eth);
+}
+
+static int airoha_eth_init(struct udevice *dev)
+{
+ struct airoha_eth *eth = dev_get_priv(dev);
+ struct airoha_qdma *qdma = &eth->qdma[0];
+ struct airoha_queue *q;
+ int qid;
+
+ qid = 0;
+ q = &qdma->q_rx[qid];
+
+ airoha_qdma_init_rx_desc(q);
+
+ airoha_qdma_set(qdma, REG_QDMA_GLOBAL_CFG,
+ GLOBAL_CFG_TX_DMA_EN_MASK |
+ GLOBAL_CFG_RX_DMA_EN_MASK);
+
+ return 0;
+}
+
+static void airoha_eth_stop(struct udevice *dev)
+{
+ struct airoha_eth *eth = dev_get_priv(dev);
+ struct airoha_qdma *qdma = &eth->qdma[0];
+
+ airoha_qdma_clear(qdma, REG_QDMA_GLOBAL_CFG,
+ GLOBAL_CFG_TX_DMA_EN_MASK |
+ GLOBAL_CFG_RX_DMA_EN_MASK);
+}
+
+static int airoha_eth_send(struct udevice *dev, void *packet, int length)
+{
+ struct airoha_eth *eth = dev_get_priv(dev);
+ struct airoha_qdma *qdma = &eth->qdma[0];
+ struct airoha_qdma_desc *desc;
+ struct airoha_queue *q;
+ dma_addr_t dma_addr;
+ u32 msg0, msg1;
+ int qid, index;
+ u8 fport;
+ u32 val;
+ int i;
+
+ dma_addr = dma_map_single(packet, length, DMA_TO_DEVICE);
+
+ qid = 0;
+ q = &qdma->q_tx[qid];
+ desc = &q->desc[q->head];
+ index = (q->head + 1) % q->ndesc;
+
+ fport = 1;
+
+ msg0 = 0;
+ msg1 = FIELD_PREP(QDMA_ETH_TXMSG_FPORT_MASK, fport) |
+ FIELD_PREP(QDMA_ETH_TXMSG_METER_MASK, 0x7f);
+
+ val = FIELD_PREP(QDMA_DESC_LEN_MASK, length);
+ WRITE_ONCE(desc->ctrl, cpu_to_le32(val));
+ WRITE_ONCE(desc->addr, cpu_to_le32(dma_addr));
+ val = FIELD_PREP(QDMA_DESC_NEXT_ID_MASK, index);
+ WRITE_ONCE(desc->data, cpu_to_le32(val));
+ WRITE_ONCE(desc->msg0, cpu_to_le32(msg0));
+ WRITE_ONCE(desc->msg1, cpu_to_le32(msg1));
+ WRITE_ONCE(desc->msg2, cpu_to_le32(0xffff));
+
+ dma_map_single(desc, sizeof(*desc), DMA_TO_DEVICE);
+
+ airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), TX_RING_CPU_IDX_MASK,
+ FIELD_PREP(TX_RING_CPU_IDX_MASK, index));
+
+ for (i = 0; i < 100; i++) {
+ dma_unmap_single(virt_to_phys(desc), sizeof(*desc),
+ DMA_FROM_DEVICE);
+ if (desc->ctrl & QDMA_DESC_DONE_MASK)
+ break;
+
+ udelay(1);
+ }
+
+ /* Return error if for some reason the descriptor never ACK */
+ if (!(desc->ctrl & QDMA_DESC_DONE_MASK))
+ return -EAGAIN;
+
+ q->head = index;
+ airoha_qdma_rmw(qdma, REG_IRQ_CLEAR_LEN(0),
+ IRQ_CLEAR_LEN_MASK, 1);
+
+ return 0;
+}
+
+static int airoha_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct airoha_eth *eth = dev_get_priv(dev);
+ struct airoha_qdma *qdma = &eth->qdma[0];
+ struct airoha_qdma_desc *desc;
+ struct airoha_queue *q;
+ u16 length;
+ int qid;
+
+ qid = 0;
+ q = &qdma->q_rx[qid];
+ desc = &q->desc[q->head];
+
+ dma_unmap_single(virt_to_phys(desc), sizeof(*desc),
+ DMA_FROM_DEVICE);
+
+ if (!(desc->ctrl & QDMA_DESC_DONE_MASK))
+ return -EAGAIN;
+
+ length = FIELD_GET(QDMA_DESC_LEN_MASK, desc->ctrl);
+ dma_unmap_single(desc->addr, length,
+ DMA_FROM_DEVICE);
+
+ *packetp = phys_to_virt(desc->addr);
+
+ return length;
+}
+
+static int arht_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+ struct airoha_eth *eth = dev_get_priv(dev);
+ struct airoha_qdma *qdma = &eth->qdma[0];
+ struct airoha_queue *q;
+ int qid;
+
+ if (!packet)
+ return 0;
+
+ qid = 0;
+ q = &qdma->q_rx[qid];
+
+ dma_map_single(packet, length, DMA_TO_DEVICE);
+
+ airoha_qdma_reset_rx_desc(q, q->head, packet);
+
+ airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK,
+ FIELD_PREP(RX_RING_CPU_IDX_MASK, q->head));
+ q->head = (q->head + 1) % q->ndesc;
+
+ return 0;
+}
+
+static int arht_eth_write_hwaddr(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct airoha_eth *eth = dev_get_priv(dev);
+ unsigned char *mac = pdata->enetaddr;
+ u32 macaddr_lsb, macaddr_msb;
+
+ macaddr_lsb = FIELD_PREP(SMACCR0_MAC2, mac[2]) |
+ FIELD_PREP(SMACCR0_MAC3, mac[3]) |
+ FIELD_PREP(SMACCR0_MAC4, mac[4]) |
+ FIELD_PREP(SMACCR0_MAC5, mac[5]);
+ macaddr_msb = FIELD_PREP(SMACCR1_MAC1, mac[1]) |
+ FIELD_PREP(SMACCR1_MAC0, mac[0]);
+
+ /* Set MAC for Switch */
+ airoha_switch_wr(eth, SWITCH_SMACCR0, macaddr_lsb);
+ airoha_switch_wr(eth, SWITCH_SMACCR1, macaddr_msb);
+
+ return 0;
+}
+
+static const struct udevice_id airoha_eth_ids[] = {
+ { .compatible = "airoha,en7581-eth" },
+};
+
+static const struct eth_ops airoha_eth_ops = {
+ .start = airoha_eth_init,
+ .stop = airoha_eth_stop,
+ .send = airoha_eth_send,
+ .recv = airoha_eth_recv,
+ .free_pkt = arht_eth_free_pkt,
+ .write_hwaddr = arht_eth_write_hwaddr,
+};
+
+U_BOOT_DRIVER(airoha_eth) = {
+ .name = "airoha-eth",
+ .id = UCLASS_ETH,
+ .of_match = airoha_eth_ids,
+ .probe = airoha_eth_probe,
+ .ops = &airoha_eth_ops,
+ .priv_auto = sizeof(struct airoha_eth),
+ .plat_auto = sizeof(struct eth_pdata),
+};
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 3132718e4f8..5b4cf30b0a3 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -79,6 +79,40 @@ config PHY_ADIN
help
Add support for configuring RGMII on Analog Devices ADIN PHYs.
+menuconfig PHY_AIROHA
+ bool "Airoha Ethernet PHYs support"
+
+config PHY_AIROHA_EN8811H
+ bool "Airoha Ethernet EN8811H support"
+ depends on PHY_AIROHA
+ help
+ AIROHA EN8811H supported.
+
+choice
+ prompt "Location of the Airoha PHY firmware"
+ default PHY_AIROHA_FW_IN_MMC
+ depends on PHY_AIROHA_EN8811H
+
+config PHY_AIROHA_FW_IN_MMC
+ bool "Airoha firmware in MMC boot1 partition"
+
+endchoice
+
+config AIROHA_FW_ADDR
+ hex "Airoha Firmware Address"
+ depends on PHY_AIROHA_EN8811H
+ default 0x0
+
+config AIROHA_MD32_DM_SIZE
+ hex "Airoha Firmware MD32 DM Size"
+ depends on PHY_AIROHA_EN8811H
+ default 0x4000
+
+config AIROHA_MD32_DSP_SIZE
+ hex "Airoha Firmware MD32 DSP Size"
+ depends on PHY_AIROHA_EN8811H
+ default 0x20000
+
menuconfig PHY_AQUANTIA
bool "Aquantia Ethernet PHYs support"
select PHY_GIGE
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 2487f366e1c..87dee3c15b9 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_MV88E6352_SWITCH) += mv88e6352.o
obj-$(CONFIG_PHYLIB) += phy.o
obj-$(CONFIG_PHYLIB_10G) += generic_10g.o
obj-$(CONFIG_PHY_ADIN) += adin.o
+obj-$(CONFIG_PHY_AIROHA_EN8811H) += air_en8811h.o
obj-$(CONFIG_PHY_AQUANTIA) += aquantia.o
obj-$(CONFIG_PHY_ATHEROS) += atheros.o
obj-$(CONFIG_PHY_BROADCOM) += broadcom.o
diff --git a/drivers/net/phy/air_en8811h.c b/drivers/net/phy/air_en8811h.c
new file mode 100644
index 00000000000..96bb24418a0
--- /dev/null
+++ b/drivers/net/phy/air_en8811h.c
@@ -0,0 +1,783 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for the Airoha EN8811H 2.5 Gigabit PHY.
+ *
+ * Limitations of the EN8811H:
+ * - Only full duplex supported
+ * - Forced speed (AN off) is not supported by hardware (100Mbps)
+ *
+ * Source originated from linux air_en8811h.c
+ *
+ * Copyright (C) 2025 Airoha Technology Corp.
+ */
+#include <phy.h>
+#include <errno.h>
+#include <malloc.h>
+#include <asm/unaligned.h>
+#include <linux/iopoll.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <mmc.h>
+
+#define EN8811H_PHY_ID 0x03a2a411
+
+#define AIR_FW_ADDR_DM 0x00000000
+#define AIR_FW_ADDR_DSP 0x00100000
+
+#define EN8811H_MD32_DM_SIZE 0x4000
+#define EN8811H_MD32_DSP_SIZE 0x20000
+
+ #define EN8811H_FW_CTRL_1 0x0f0018
+ #define EN8811H_FW_CTRL_1_START 0x0
+ #define EN8811H_FW_CTRL_1_FINISH 0x1
+ #define EN8811H_FW_CTRL_2 0x800000
+ #define EN8811H_FW_CTRL_2_LOADING BIT(11)
+
+ /* MII Registers */
+ #define AIR_AUX_CTRL_STATUS 0x1d
+ #define AIR_AUX_CTRL_STATUS_SPEED_MASK GENMASK(4, 2)
+ #define AIR_AUX_CTRL_STATUS_SPEED_100 0x4
+ #define AIR_AUX_CTRL_STATUS_SPEED_1000 0x8
+ #define AIR_AUX_CTRL_STATUS_SPEED_2500 0xc
+
+#define AIR_EXT_PAGE_ACCESS 0x1f
+#define AIR_PHY_PAGE_STANDARD 0x0000
+#define AIR_PHY_PAGE_EXTENDED_4 0x0004
+
+/* MII Registers Page 4*/
+#define AIR_BPBUS_MODE 0x10
+#define AIR_BPBUS_MODE_ADDR_FIXED 0x0000
+#define AIR_BPBUS_MODE_ADDR_INCR BIT(15)
+#define AIR_BPBUS_WR_ADDR_HIGH 0x11
+#define AIR_BPBUS_WR_ADDR_LOW 0x12
+#define AIR_BPBUS_WR_DATA_HIGH 0x13
+#define AIR_BPBUS_WR_DATA_LOW 0x14
+#define AIR_BPBUS_RD_ADDR_HIGH 0x15
+#define AIR_BPBUS_RD_ADDR_LOW 0x16
+#define AIR_BPBUS_RD_DATA_HIGH 0x17
+#define AIR_BPBUS_RD_DATA_LOW 0x18
+
+/* Registers on MDIO_MMD_VEND1 */
+#define EN8811H_PHY_FW_STATUS 0x8009
+#define EN8811H_PHY_READY 0x02
+
+/* Registers on MDIO_MMD_VEND2 */
+#define AIR_PHY_LED_BCR 0x021
+#define AIR_PHY_LED_BCR_MODE_MASK GENMASK(1, 0)
+#define AIR_PHY_LED_BCR_TIME_TEST BIT(2)
+#define AIR_PHY_LED_BCR_CLK_EN BIT(3)
+#define AIR_PHY_LED_BCR_EXT_CTRL BIT(15)
+
+#define AIR_PHY_LED_DUR_ON 0x022
+
+#define AIR_PHY_LED_DUR_BLINK 0x023
+
+#define AIR_PHY_LED_ON(i) (0x024 + ((i) * 2))
+#define AIR_PHY_LED_ON_MASK (GENMASK(6, 0) | BIT(8))
+#define AIR_PHY_LED_ON_LINK1000 BIT(0)
+#define AIR_PHY_LED_ON_LINK100 BIT(1)
+#define AIR_PHY_LED_ON_LINK10 BIT(2)
+#define AIR_PHY_LED_ON_LINKDOWN BIT(3)
+#define AIR_PHY_LED_ON_FDX BIT(4) /* Full duplex */
+#define AIR_PHY_LED_ON_HDX BIT(5) /* Half duplex */
+#define AIR_PHY_LED_ON_FORCE_ON BIT(6)
+#define AIR_PHY_LED_ON_LINK2500 BIT(8)
+#define AIR_PHY_LED_ON_POLARITY BIT(14)
+#define AIR_PHY_LED_ON_ENABLE BIT(15)
+
+#define AIR_PHY_LED_BLINK(i) (0x025 + ((i) * 2))
+#define AIR_PHY_LED_BLINK_1000TX BIT(0)
+#define AIR_PHY_LED_BLINK_1000RX BIT(1)
+#define AIR_PHY_LED_BLINK_100TX BIT(2)
+#define AIR_PHY_LED_BLINK_100RX BIT(3)
+#define AIR_PHY_LED_BLINK_10TX BIT(4)
+#define AIR_PHY_LED_BLINK_10RX BIT(5)
+#define AIR_PHY_LED_BLINK_COLLISION BIT(6)
+#define AIR_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
+#define AIR_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
+#define AIR_PHY_LED_BLINK_FORCE_BLINK BIT(9)
+#define AIR_PHY_LED_BLINK_2500TX BIT(10)
+#define AIR_PHY_LED_BLINK_2500RX BIT(11)
+
+#define EN8811H_FW_VERSION 0x3b3c
+
+#define EN8811H_POLARITY 0xca0f8
+#define EN8811H_POLARITY_TX_NORMAL BIT(0)
+#define EN8811H_POLARITY_RX_REVERSE BIT(1)
+
+#define EN8811H_CLK_CGM 0xcf958
+#define EN8811H_CLK_CGM_CKO BIT(26)
+#define EN8811H_HWTRAP1 0xcf914
+#define EN8811H_HWTRAP1_CKO BIT(12)
+
+#define air_upper_16_bits(n) ((u16)((n) >> 16))
+#define air_lower_16_bits(n) ((u16)((n) & 0xffff))
+
+/* Led definitions */
+#define EN8811H_LED_COUNT 3
+
+/* Default LED setup:
+ * GPIO5 <-> LED0 On: Link detected
+ * GPIO4 <-> LED1 On: Link detected at 2500 and 1000 Mbps
+ * GPIO3 <-> LED2 On: Link detected at 2500 and 100 Mbps
+ */
+#define AIR_DEFAULT_TRIGGER_LED0 (AIR_PHY_LED_ON_LINK2500 | \
+ AIR_PHY_LED_ON_LINK1000 | \
+ AIR_PHY_LED_ON_LINK100)
+#define AIR_DEFAULT_TRIGGER_LED1 (AIR_PHY_LED_ON_LINK2500 | \
+ AIR_PHY_LED_ON_LINK1000 | \
+ AIR_PHY_LED_BLINK_2500TX | \
+ AIR_PHY_LED_BLINK_2500RX | \
+ AIR_PHY_LED_BLINK_1000TX | \
+ AIR_PHY_LED_BLINK_1000RX)
+#define AIR_DEFAULT_TRIGGER_LED2 (AIR_PHY_LED_ON_LINK2500 | \
+ AIR_PHY_LED_ON_LINK100 | \
+ AIR_PHY_LED_BLINK_2500TX | \
+ AIR_PHY_LED_BLINK_2500RX | \
+ AIR_PHY_LED_BLINK_100TX | \
+ AIR_PHY_LED_BLINK_100RX)
+
+struct led {
+ unsigned long rules;
+};
+
+enum {
+ AIR_PHY_LED_DUR_BLINK_32MS,
+ AIR_PHY_LED_DUR_BLINK_64MS,
+ AIR_PHY_LED_DUR_BLINK_128MS,
+ AIR_PHY_LED_DUR_BLINK_256MS,
+ AIR_PHY_LED_DUR_BLINK_512MS,
+ AIR_PHY_LED_DUR_BLINK_1024MS,
+};
+
+enum {
+ AIR_LED_DISABLE,
+ AIR_LED_ENABLE,
+};
+
+enum {
+ AIR_ACTIVE_LOW,
+ AIR_ACTIVE_HIGH,
+};
+
+enum {
+ AIR_LED_MODE_DISABLE,
+ AIR_LED_MODE_USER_DEFINE,
+};
+
+#define AIR_PHY_LED_DUR_UNIT 781
+#define AIR_PHY_LED_DUR (AIR_PHY_LED_DUR_UNIT << AIR_PHY_LED_DUR_BLINK_64MS)
+
+struct en8811h_priv {
+ int firmware_version;
+ bool mcu_needs_restart;
+ struct led led[EN8811H_LED_COUNT];
+};
+
+static int air_phy_read_page(struct phy_device *phydev)
+{
+ return phy_read(phydev, MDIO_DEVAD_NONE, AIR_EXT_PAGE_ACCESS);
+}
+
+static int air_phy_write_page(struct phy_device *phydev, int page)
+{
+ return phy_write(phydev, MDIO_DEVAD_NONE, AIR_EXT_PAGE_ACCESS, page);
+}
+
+int air_phy_select_page(struct phy_device *phydev, int page)
+{
+ int ret, oldpage;
+
+ oldpage = air_phy_read_page(phydev);
+ if (oldpage < 0)
+ return oldpage;
+
+ if (oldpage != page) {
+ ret = air_phy_write_page(phydev, page);
+ if (ret < 0)
+ return ret;
+ }
+
+ return oldpage;
+}
+
+int air_phy_restore_page(struct phy_device *phydev, int oldpage, int ret)
+{
+ int r;
+
+ if (oldpage >= 0) {
+ r = air_phy_write_page(phydev, oldpage);
+
+ if (ret >= 0 && r < 0)
+ ret = r;
+ } else {
+ ret = oldpage;
+ }
+
+ return ret;
+}
+
+static int air_buckpbus_reg_write(struct phy_device *phydev,
+ u32 pbus_address, u32 pbus_data)
+{
+ int ret, saved_page;
+
+ saved_page = air_phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
+
+ if (saved_page >= 0) {
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
+ if (ret < 0)
+ goto restore_page;
+
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_HIGH,
+ air_upper_16_bits(pbus_address));
+ if (ret < 0)
+ goto restore_page;
+
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_LOW,
+ air_lower_16_bits(pbus_address));
+ if (ret < 0)
+ goto restore_page;
+
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_HIGH,
+ air_upper_16_bits(pbus_data));
+ if (ret < 0)
+ goto restore_page;
+
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_LOW,
+ air_lower_16_bits(pbus_data));
+ if (ret < 0)
+ goto restore_page;
+ }
+
+restore_page:
+ if (ret < 0)
+ printf("%s 0x%08x failed: %d\n", __func__,
+ pbus_address, ret);
+
+ return air_phy_restore_page(phydev, saved_page, ret);
+}
+
+static int air_buckpbus_reg_read(struct phy_device *phydev,
+ u32 pbus_address, u32 *pbus_data)
+{
+ int pbus_data_low, pbus_data_high;
+ int ret = 0, saved_page;
+
+ saved_page = air_phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
+
+ if (saved_page >= 0) {
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
+ if (ret < 0)
+ goto restore_page;
+
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_HIGH,
+ air_upper_16_bits(pbus_address));
+ if (ret < 0)
+ goto restore_page;
+
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_LOW,
+ air_lower_16_bits(pbus_address));
+ if (ret < 0)
+ goto restore_page;
+
+ pbus_data_high = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_HIGH);
+ if (pbus_data_high < 0) {
+ ret = pbus_data_high;
+ goto restore_page;
+ }
+
+ pbus_data_low = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_LOW);
+ if (pbus_data_low < 0) {
+ ret = pbus_data_low;
+ goto restore_page;
+ }
+
+ *pbus_data = pbus_data_low | (pbus_data_high << 16);
+ }
+
+restore_page:
+ if (ret < 0)
+ printf("%s 0x%08x failed: %d\n", __func__,
+ pbus_address, ret);
+
+ return air_phy_restore_page(phydev, saved_page, ret);
+}
+
+static int air_buckpbus_reg_modify(struct phy_device *phydev,
+ u32 pbus_address, u32 mask, u32 set)
+{
+ int pbus_data_low, pbus_data_high;
+ u32 pbus_data_old, pbus_data_new;
+ int ret = 0, saved_page;
+
+ saved_page = air_phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
+
+ if (saved_page >= 0) {
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
+ if (ret < 0)
+ goto restore_page;
+
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_HIGH,
+ air_upper_16_bits(pbus_address));
+ if (ret < 0)
+ goto restore_page;
+
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_LOW,
+ air_lower_16_bits(pbus_address));
+ if (ret < 0)
+ goto restore_page;
+
+ pbus_data_high = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_HIGH);
+ if (pbus_data_high < 0)
+ return pbus_data_high;
+
+ pbus_data_low = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_LOW);
+ if (pbus_data_low < 0)
+ return pbus_data_low;
+
+ pbus_data_old = pbus_data_low | (pbus_data_high << 16);
+ pbus_data_new = (pbus_data_old & ~mask) | set;
+ if (pbus_data_new == pbus_data_old)
+ return 0;
+
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_HIGH,
+ air_upper_16_bits(pbus_address));
+ if (ret < 0)
+ goto restore_page;
+
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_LOW,
+ air_lower_16_bits(pbus_address));
+ if (ret < 0)
+ goto restore_page;
+
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_HIGH,
+ air_upper_16_bits(pbus_data_new));
+ if (ret < 0)
+ goto restore_page;
+
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_LOW,
+ air_lower_16_bits(pbus_data_new));
+ if (ret < 0)
+ goto restore_page;
+ }
+
+restore_page:
+ if (ret < 0)
+ printf("%s 0x%08x failed: %d\n", __func__,
+ pbus_address, ret);
+
+ return air_phy_restore_page(phydev, saved_page, ret);
+}
+
+static int air_write_buf(struct phy_device *phydev, unsigned long address,
+ unsigned long array_size, const unsigned char *buffer)
+{
+ unsigned int offset;
+ int ret, saved_page;
+ u16 val;
+
+ saved_page = air_phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
+
+ if (saved_page >= 0) {
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_INCR);
+ if (ret < 0)
+ goto restore_page;
+
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_HIGH,
+ air_upper_16_bits(address));
+ if (ret < 0)
+ goto restore_page;
+
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_LOW,
+ air_lower_16_bits(address));
+ if (ret < 0)
+ goto restore_page;
+
+ for (offset = 0; offset < array_size; offset += 4) {
+ val = get_unaligned_le16(&buffer[offset + 2]);
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_HIGH, val);
+ if (ret < 0)
+ goto restore_page;
+
+ val = get_unaligned_le16(&buffer[offset]);
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_LOW, val);
+ if (ret < 0)
+ goto restore_page;
+ }
+ }
+
+restore_page:
+ if (ret < 0)
+ printf("%s 0x%08lx failed: %d\n", __func__,
+ address, ret);
+
+ return air_phy_restore_page(phydev, saved_page, ret);
+}
+
+__weak ulong *en8811h_get_fw_addr(void)
+{
+ return (ulong *)CONFIG_AIROHA_FW_ADDR;
+}
+
+static int en8811h_wait_mcu_ready(struct phy_device *phydev)
+{
+ int ret, reg_value;
+
+ /* Because of mdio-lock, may have to wait for multiple loads */
+ ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
+ EN8811H_PHY_FW_STATUS, reg_value,
+ reg_value == EN8811H_PHY_READY,
+ 20000, 7500000, true);
+ if (ret) {
+ printf("MCU not ready: 0x%x\n", reg_value);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int en8811h_load_firmware(struct phy_device *phydev)
+{
+ int ret;
+ char *addr = NULL;
+ struct en8811h_priv *priv = phydev->priv;
+ int dev = CONFIG_SYS_MMC_ENV_DEV;
+ u32 cnt = (CONFIG_AIROHA_MD32_DM_SIZE +
+ CONFIG_AIROHA_MD32_DSP_SIZE) / 512;
+ ulong airoha_fw_addr = (ulong)en8811h_get_fw_addr();
+ u32 blk = airoha_fw_addr / 512;
+
+ addr = malloc(CONFIG_AIROHA_MD32_DM_SIZE + CONFIG_AIROHA_MD32_DSP_SIZE);
+ if (!addr) {
+ puts("cannot allocated buffer for firmware.\n");
+ return -ENOMEM;
+ }
+
+ if (IS_ENABLED(CONFIG_PHY_AIROHA_FW_IN_MMC)) {
+ struct mmc *mmc = find_mmc_device(dev);
+
+ if (!mmc) {
+ puts("Failed to find MMC device for Airoha ucode\n");
+ goto en8811h_load_firmware_out;
+ }
+
+ printf("MMC read: dev # %u, block # %u, count %u ...\n",
+ dev, blk, cnt);
+
+ if (mmc_init(mmc)) {
+ puts("initializing MMC device failed.\n");
+ goto en8811h_load_firmware_out;
+ }
+
+ ret = mmc_set_part_conf(mmc, 1, 2, 2);
+ if (ret) {
+ puts("cannot access eMMC boot1 hw partition.\n");
+ goto en8811h_load_firmware_out;
+ }
+
+ (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt, addr);
+
+ mmc_set_part_conf(mmc, 1, 1, 0);
+
+ } else {
+ puts("EN8811H firmware loading not implemented");
+ free(addr);
+ addr = NULL;
+ return -EOPNOTSUPP;
+ }
+
+ ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
+ EN8811H_FW_CTRL_1_START);
+ if (ret < 0)
+ return ret;
+
+ ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2,
+ EN8811H_FW_CTRL_2_LOADING,
+ EN8811H_FW_CTRL_2_LOADING);
+ if (ret < 0)
+ return ret;
+
+ ret = air_write_buf(phydev, AIR_FW_ADDR_DM, CONFIG_AIROHA_MD32_DM_SIZE, addr);
+ if (ret < 0)
+ goto en8811h_load_firmware_out;
+
+ ret = air_write_buf(phydev, AIR_FW_ADDR_DSP, CONFIG_AIROHA_MD32_DSP_SIZE,
+ addr + CONFIG_AIROHA_MD32_DM_SIZE);
+ if (ret < 0)
+ goto en8811h_load_firmware_out;
+
+ ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2,
+ EN8811H_FW_CTRL_2_LOADING, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
+ EN8811H_FW_CTRL_1_FINISH);
+ if (ret < 0)
+ return ret;
+
+ ret = en8811h_wait_mcu_ready(phydev);
+
+ air_buckpbus_reg_read(phydev, EN8811H_FW_VERSION,
+ &priv->firmware_version);
+ printf("MD32 firmware version: %08x\n",
+ priv->firmware_version);
+
+en8811h_load_firmware_out:
+ free(addr);
+ if (ret < 0)
+ printf("Firmware loading failed: %d\n", ret);
+
+ return ret;
+}
+
+static int en8811h_restart_mcu(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = phy_write_mmd(phydev, 0x1e, 0x8009, 0x0);
+ if (ret < 0)
+ return ret;
+
+ ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
+ EN8811H_FW_CTRL_1_START);
+ if (ret < 0)
+ return ret;
+
+ return air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
+ EN8811H_FW_CTRL_1_FINISH);
+}
+
+static int air_led_hw_control_set(struct phy_device *phydev,
+ u8 index, unsigned long rules)
+{
+ struct en8811h_priv *priv = phydev->priv;
+ u16 on = 0, blink = 0;
+ int ret;
+
+ if (index >= EN8811H_LED_COUNT)
+ return -EINVAL;
+
+ on |= rules & (AIR_PHY_LED_ON_LINK100 |
+ AIR_PHY_LED_ON_LINK1000 |
+ AIR_PHY_LED_ON_LINK2500);
+
+ blink |= rules & (AIR_PHY_LED_BLINK_100TX |
+ AIR_PHY_LED_BLINK_100RX |
+ AIR_PHY_LED_BLINK_1000TX |
+ AIR_PHY_LED_BLINK_1000RX |
+ AIR_PHY_LED_BLINK_2500TX |
+ AIR_PHY_LED_BLINK_2500RX);
+
+ if (blink || on) {
+ on &= ~AIR_PHY_LED_ON_FORCE_ON;
+ blink &= ~AIR_PHY_LED_BLINK_FORCE_BLINK;
+ } else {
+ priv->led[index].rules = 0;
+ }
+
+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_ON(index),
+ AIR_PHY_LED_ON_MASK, on);
+ if (ret < 0)
+ return ret;
+
+ return phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BLINK(index),
+ blink);
+}
+
+static int air_led_init(struct phy_device *phydev, u8 index, u8 state, u8 pol)
+{
+ int val = 0;
+ int err;
+
+ if (index >= EN8811H_LED_COUNT)
+ return -EINVAL;
+
+ if (state == AIR_LED_ENABLE)
+ val |= AIR_PHY_LED_ON_ENABLE;
+ else
+ val &= ~AIR_PHY_LED_ON_ENABLE;
+
+ if (pol == AIR_ACTIVE_HIGH)
+ val |= AIR_PHY_LED_ON_POLARITY;
+ else
+ val &= ~AIR_PHY_LED_ON_POLARITY;
+
+ err = phy_write_mmd(phydev, 0x1f, AIR_PHY_LED_ON(index), val);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int air_leds_init(struct phy_device *phydev, int num, int dur, int mode)
+{
+ int ret, i;
+ struct en8811h_priv *priv = phydev->priv;
+
+ ret = phy_write_mmd(phydev, 0x1f, AIR_PHY_LED_DUR_BLINK, dur);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write_mmd(phydev, 0x1f, AIR_PHY_LED_DUR_ON, dur >> 1);
+ if (ret < 0)
+ return ret;
+
+ switch (mode) {
+ case AIR_LED_MODE_DISABLE:
+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR,
+ AIR_PHY_LED_BCR_EXT_CTRL |
+ AIR_PHY_LED_BCR_MODE_MASK, 0);
+ break;
+ case AIR_LED_MODE_USER_DEFINE:
+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR,
+ AIR_PHY_LED_BCR_EXT_CTRL |
+ AIR_PHY_LED_BCR_CLK_EN,
+ AIR_PHY_LED_BCR_EXT_CTRL |
+ AIR_PHY_LED_BCR_CLK_EN);
+ if (ret < 0)
+ return ret;
+ break;
+ default:
+ printf("LED mode %d is not supported\n", mode);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num; ++i) {
+ ret = air_led_init(phydev, i, AIR_LED_ENABLE, AIR_ACTIVE_HIGH);
+ if (ret < 0) {
+ printf("LED%d init failed: %d\n", i, ret);
+ return ret;
+ }
+ air_led_hw_control_set(phydev, i, priv->led[i].rules);
+ }
+
+ return 0;
+}
+
+static int en8811h_config(struct phy_device *phydev)
+{
+ ofnode node = phy_get_ofnode(phydev);
+ struct en8811h_priv *priv = phydev->priv;
+ int ret = 0;
+ u32 pbus_value = 0;
+
+ /* If restart happened in .probe(), no need to restart now */
+ if (priv->mcu_needs_restart) {
+ ret = en8811h_restart_mcu(phydev);
+ if (ret < 0)
+ return ret;
+ } else {
+ ret = en8811h_load_firmware(phydev);
+ if (ret) {
+ printf("Load firmware fail.\n");
+ return ret;
+ }
+ /* Next calls to .config() mcu needs to restart */
+ priv->mcu_needs_restart = true;
+ }
+
+ ret = phy_write_mmd(phydev, 0x1e, 0x800c, 0x0);
+ ret |= phy_write_mmd(phydev, 0x1e, 0x800d, 0x0);
+ ret |= phy_write_mmd(phydev, 0x1e, 0x800e, 0x1101);
+ ret |= phy_write_mmd(phydev, 0x1e, 0x800f, 0x0002);
+ if (ret < 0)
+ return ret;
+
+ /* Serdes polarity */
+ pbus_value = 0;
+ if (ofnode_read_bool(node, "airoha,pnswap-rx"))
+ pbus_value |= EN8811H_POLARITY_RX_REVERSE;
+ else
+ pbus_value &= ~EN8811H_POLARITY_RX_REVERSE;
+ if (ofnode_read_bool(node, "airoha,pnswap-tx"))
+ pbus_value &= ~EN8811H_POLARITY_TX_NORMAL;
+ else
+ pbus_value |= EN8811H_POLARITY_TX_NORMAL;
+ ret = air_buckpbus_reg_modify(phydev, EN8811H_POLARITY,
+ EN8811H_POLARITY_RX_REVERSE |
+ EN8811H_POLARITY_TX_NORMAL, pbus_value);
+ if (ret < 0)
+ return ret;
+
+ ret = air_leds_init(phydev, EN8811H_LED_COUNT, AIR_PHY_LED_DUR,
+ AIR_LED_MODE_USER_DEFINE);
+ if (ret < 0) {
+ printf("Failed to disable leds: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int en8811h_parse_status(struct phy_device *phydev)
+{
+ int ret = 0, reg_value;
+
+ phydev->duplex = DUPLEX_FULL;
+
+ reg_value = phy_read(phydev, MDIO_DEVAD_NONE, AIR_AUX_CTRL_STATUS);
+ if (reg_value < 0)
+ return reg_value;
+
+ switch (reg_value & AIR_AUX_CTRL_STATUS_SPEED_MASK) {
+ case AIR_AUX_CTRL_STATUS_SPEED_2500:
+ phydev->speed = SPEED_2500;
+ break;
+ case AIR_AUX_CTRL_STATUS_SPEED_1000:
+ phydev->speed = SPEED_1000;
+ break;
+ case AIR_AUX_CTRL_STATUS_SPEED_100:
+ phydev->speed = SPEED_100;
+ break;
+ default:
+ printf("Auto-neg error, defaulting to 100M/FD\n");
+ phydev->speed = SPEED_100;
+ break;
+ }
+
+ return ret;
+}
+
+static int en8811h_startup(struct phy_device *phydev)
+{
+ int ret = 0;
+
+ ret = genphy_update_link(phydev);
+ if (ret)
+ return ret;
+
+ return en8811h_parse_status(phydev);
+}
+
+static int en8811h_probe(struct phy_device *phydev)
+{
+ struct en8811h_priv *priv;
+
+ priv = malloc(sizeof(*priv));
+ if (!priv)
+ return -ENOMEM;
+ memset(priv, 0, sizeof(*priv));
+
+ priv->led[0].rules = AIR_DEFAULT_TRIGGER_LED0;
+ priv->led[1].rules = AIR_DEFAULT_TRIGGER_LED1;
+ priv->led[2].rules = AIR_DEFAULT_TRIGGER_LED2;
+
+ /* mcu has just restarted after firmware load */
+ priv->mcu_needs_restart = false;
+
+ phydev->priv = priv;
+
+ return 0;
+}
+
+U_BOOT_PHY_DRIVER(en8811h) = {
+ .name = "Airoha EN8811H",
+ .uid = EN8811H_PHY_ID,
+ .mask = 0x0ffffff0,
+ .config = &en8811h_config,
+ .probe = &en8811h_probe,
+ .startup = &en8811h_startup,
+ .shutdown = &genphy_shutdown,
+};
diff --git a/drivers/nvme/Makefile b/drivers/nvme/Makefile
index 8c32cfbfc0f..5f8ed79077d 100644
--- a/drivers/nvme/Makefile
+++ b/drivers/nvme/Makefile
@@ -4,4 +4,4 @@
obj-y += nvme-uclass.o nvme.o nvme_show.o
obj-$(CONFIG_NVME_APPLE) += nvme_apple.o
-obj-$(CONFIG_$(XPL_)NVME_PCI) += nvme_pci.o
+obj-$(CONFIG_$(PHASE_)NVME_PCI) += nvme_pci.o
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index ce4ea28b299..b4d01fc700d 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -8,8 +8,8 @@ obj-y += marvell/
obj-y += rockchip/
obj-y += socionext/
-obj-$(CONFIG_$(XPL_)PHY) += phy-uclass.o
-obj-$(CONFIG_$(XPL_)NOP_PHY) += nop-phy.o
+obj-$(CONFIG_$(PHASE_)PHY) += phy-uclass.o
+obj-$(CONFIG_$(PHASE_)NOP_PHY) += nop-phy.o
obj-$(CONFIG_MIPI_DPHY_HELPERS) += phy-core-mipi-dphy.o
obj-$(CONFIG_AB8500_USB_PHY) += phy-ab8500-usb.o
obj-$(CONFIG_APPLE_ATCPHY) += phy-apple-atc.o
@@ -19,7 +19,7 @@ obj-$(CONFIG_BCM6358_USBH_PHY) += bcm6358-usbh-phy.o
obj-$(CONFIG_BCM6368_USBH_PHY) += bcm6368-usbh-phy.o
obj-$(CONFIG_BCM_SR_PCIE_PHY) += phy-bcm-sr-pcie.o
obj-$(CONFIG_PHY_SANDBOX) += sandbox-phy.o
-obj-$(CONFIG_$(XPL_)PIPE3_PHY) += ti-pipe3-phy.o
+obj-$(CONFIG_$(PHASE_)PIPE3_PHY) += ti-pipe3-phy.o
obj-$(CONFIG_AM654_PHY) += phy-ti-am654.o
obj-$(CONFIG_STI_USB_PHY) += sti_usb_phy.o
obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o
diff --git a/drivers/phy/cadence/Makefile b/drivers/phy/cadence/Makefile
index e0da41cd7eb..2b1e51768da 100644
--- a/drivers/phy/cadence/Makefile
+++ b/drivers/phy/cadence/Makefile
@@ -1,2 +1,2 @@
-obj-$(CONFIG_$(XPL_)PHY_CADENCE_SIERRA) += phy-cadence-sierra.o
-obj-$(CONFIG_$(XPL_)PHY_CADENCE_TORRENT) += phy-cadence-torrent.o
+obj-$(CONFIG_$(PHASE_)PHY_CADENCE_SIERRA) += phy-cadence-sierra.o
+obj-$(CONFIG_$(PHASE_)PHY_CADENCE_TORRENT) += phy-cadence-torrent.o
diff --git a/drivers/phy/qcom/phy-qcom-qusb2.c b/drivers/phy/qcom/phy-qcom-qusb2.c
index c91ba18c4ab..d98f6108e69 100644
--- a/drivers/phy/qcom/phy-qcom-qusb2.c
+++ b/drivers/phy/qcom/phy-qcom-qusb2.c
@@ -122,6 +122,9 @@ struct qusb2_phy_cfg {
/* true if PHY has PLL_CORE_INPUT_OVERRIDE register to reset PLL */
bool has_pll_override;
+
+ /* true if PHY default clk scheme is single-ended */
+ bool se_clk_scheme_default;
};
/* set of registers with offsets different per-PHY */
@@ -173,6 +176,19 @@ static const unsigned int sm6115_regs_layout[] = {
[QUSB2PHY_PORT_POWERDOWN] = 0xb4, [QUSB2PHY_INTR_CTRL] = 0xbc,
};
+static const struct qusb2_phy_init_tbl msm8996_init_tbl[] = {
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0xf8),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0xb3),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE3, 0x83),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE4, 0xc0),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_TUNE, 0x30),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL1, 0x79),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL2, 0x21),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TEST2, 0x14),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_AUTOPGM_CTL1, 0x9f),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),
+};
+
static const struct qusb2_phy_init_tbl qusb2_v2_init_tbl[] = {
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_ANALOG_CONTROLS_TWO, 0x03),
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CLOCK_INVERTERS, 0x7c),
@@ -214,6 +230,19 @@ static const struct qusb2_phy_cfg sm6115_phy_cfg = {
.regs = sm6115_regs_layout,
.has_pll_test = true,
+ .se_clk_scheme_default = true,
+ .disable_ctrl = (CLAMP_N_EN | FREEZIO_N | POWER_DOWN),
+ .mask_core_ready = PLL_LOCKED,
+ .autoresume_en = BIT(3),
+};
+
+static const struct qusb2_phy_cfg sdm660_phy_cfg = {
+ .tbl = msm8996_init_tbl,
+ .tbl_num = ARRAY_SIZE(msm8996_init_tbl),
+ .regs = sm6115_regs_layout,
+
+ .has_pll_test = true,
+ .se_clk_scheme_default = false,
.disable_ctrl = (CLAMP_N_EN | FREEZIO_N | POWER_DOWN),
.mask_core_ready = PLL_LOCKED,
.autoresume_en = BIT(3),
@@ -228,6 +257,7 @@ static const struct qusb2_phy_cfg qusb2_v2_phy_cfg = {
POWER_DOWN),
.mask_core_ready = CORE_READY_STATUS,
.has_pll_override = true,
+ .se_clk_scheme_default = true,
.autoresume_en = BIT(0),
.update_tune1_with_efuse = true,
};
@@ -316,8 +346,18 @@ static int qusb2phy_power_on(struct phy *phy)
/* Required to get phy pll lock successfully */
udelay(150);
+ /*
+ * Not all the SoCs have got a readable TCSR_PHY_CLK_SCHEME
+ * register in the TCSR so, if there's none, use the default
+ * value hardcoded in the configuration.
+ */
+ qphy->has_se_clk_scheme = cfg->se_clk_scheme_default;
+
if (cfg->has_pll_test) {
- val |= CLK_REF_SEL;
+ if (!qphy->has_se_clk_scheme)
+ val &= ~CLK_REF_SEL;
+ else
+ val |= CLK_REF_SEL;
writel(val, qphy->base + QUSB2PHY_PLL_TEST);
@@ -413,6 +453,8 @@ static const struct udevice_id qusb2phy_ids[] = {
{ .compatible = "qcom,qusb2-phy" },
{ .compatible = "qcom,qcm2290-qusb2-phy",
.data = (ulong)&sm6115_phy_cfg },
+ { .compatible = "qcom,sdm660-qusb2-phy",
+ .data = (ulong)&sdm660_phy_cfg },
{ .compatible = "qcom,sm6115-qusb2-phy",
.data = (ulong)&sm6115_phy_cfg },
{ .compatible = "qcom,qusb2-v2-phy", .data = (ulong)&qusb2_v2_phy_cfg },
diff --git a/drivers/phy/ti/Makefile b/drivers/phy/ti/Makefile
index 699901fd15e..169036a08d7 100644
--- a/drivers/phy/ti/Makefile
+++ b/drivers/phy/ti/Makefile
@@ -1 +1 @@
-obj-$(CONFIG_$(XPL_)PHY_J721E_WIZ) += phy-j721e-wiz.o
+obj-$(CONFIG_$(PHASE_)PHY_J721E_WIZ) += phy-j721e-wiz.o
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 6deb6aaf6eb..a8eba656843 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -1,14 +1,14 @@
# SPDX-License-Identifier: GPL-2.0+
obj-y += pinctrl-uclass.o
-obj-$(CONFIG_$(XPL_)PINCTRL_GENERIC) += pinctrl-generic.o
+obj-$(CONFIG_$(PHASE_)PINCTRL_GENERIC) += pinctrl-generic.o
obj-$(CONFIG_PINCTRL_ADI) += pinctrl-adi-adsp.o
obj-$(CONFIG_PINCTRL_APPLE) += pinctrl-apple.o
obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o
obj-$(CONFIG_PINCTRL_AT91PIO4) += pinctrl-at91-pio4.o
obj-y += nxp/
-obj-$(CONFIG_$(XPL_)PINCTRL_ROCKCHIP) += rockchip/
+obj-$(CONFIG_$(PHASE_)PINCTRL_ROCKCHIP) += rockchip/
obj-$(CONFIG_ARCH_ASPEED) += aspeed/
obj-$(CONFIG_ARCH_ATH79) += ath79/
obj-$(CONFIG_PINCTRL_INTEL) += intel/
@@ -18,7 +18,7 @@ obj-$(CONFIG_PINCTRL_QCOM) += qcom/
obj-$(CONFIG_ARCH_RENESAS) += renesas/
obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o
obj-$(CONFIG_PINCTRL_SUNXI) += sunxi/
-obj-$(CONFIG_$(XPL_)PINCTRL_TEGRA) += tegra/
+obj-$(CONFIG_$(PHASE_)PINCTRL_TEGRA) += tegra/
obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/
obj-$(CONFIG_PINCTRL_PIC32) += pinctrl_pic32.o
obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/
@@ -32,7 +32,7 @@ obj-$(CONFIG_PINCTRL_QE) += pinctrl-qe-io.o
obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
obj-$(CONFIG_PINCTRL_STI) += pinctrl-sti.o
obj-$(CONFIG_PINCTRL_STM32) += pinctrl_stm32.o
-obj-$(CONFIG_$(XPL_)PINCTRL_STMFX) += pinctrl-stmfx.o
+obj-$(CONFIG_$(PHASE_)PINCTRL_STMFX) += pinctrl-stmfx.o
obj-y += broadcom/
obj-$(CONFIG_PINCTRL_ZYNQMP) += pinctrl-zynqmp.o
obj-$(CONFIG_PINCTRL_STARFIVE) += starfive/
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index f4a3942ee2f..e567cb113a3 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -48,12 +48,25 @@ config PINCTRL_QCOM_QCS404
Say Y here to enable support for pinctrl on the Snapdragon QCS404 SoC,
as well as the associated GPIO driver.
+config PINCTRL_QCOM_SA8775P
+ bool "Qualcomm SA8775P Pinctrl"
+ select PINCTRL_QCOM
+ help
+ Say Y here to enable support for pinctrl on the Snapdragon SA8775P SoC,
+ as well as the associated GPIO driver.
+
config PINCTRL_QCOM_SC7280
bool "Qualcomm SC7280/QCM6490 Pinctrl"
select PINCTRL_QCOM
help
Say Y here to enable support for pinctrl on the Snapdragon SC7280 SoC,
- as well as the associated GPIO driver.
+
+config PINCTRL_QCOM_SDM660
+ bool "Qualcomm SDM630/660 Pinctrl"
+ select PINCTRL_QCOM
+ help
+ Say Y here to enable support for pinctrl on the Snapdragon 630/636/660
+ SoCs, as well as the associated GPIO driver.
config PINCTRL_QCOM_SDM845
bool "Qualcomm SDM845 Pinctrl"
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index 94cdc6e4a62..6ffc6d48c15 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -9,7 +9,9 @@ obj-$(CONFIG_PINCTRL_QCOM_IPQ9574) += pinctrl-ipq9574.o
obj-$(CONFIG_PINCTRL_QCOM_APQ8096) += pinctrl-apq8096.o
obj-$(CONFIG_PINCTRL_QCOM_QCM2290) += pinctrl-qcm2290.o
obj-$(CONFIG_PINCTRL_QCOM_QCS404) += pinctrl-qcs404.o
+obj-$(CONFIG_PINCTRL_QCOM_SA8775P) += pinctrl-sa8775p.o
obj-$(CONFIG_PINCTRL_QCOM_SC7280) += pinctrl-sc7280.o
+obj-$(CONFIG_PINCTRL_QCOM_SDM660) += pinctrl-sdm660.o
obj-$(CONFIG_PINCTRL_QCOM_SDM845) += pinctrl-sdm845.o
obj-$(CONFIG_PINCTRL_QCOM_SM6115) += pinctrl-sm6115.o
obj-$(CONFIG_PINCTRL_QCOM_SM8150) += pinctrl-sm8150.o
diff --git a/drivers/pinctrl/qcom/pinctrl-qcom.c b/drivers/pinctrl/qcom/pinctrl-qcom.c
index 24d031947a3..c95db56bc47 100644
--- a/drivers/pinctrl/qcom/pinctrl-qcom.c
+++ b/drivers/pinctrl/qcom/pinctrl-qcom.c
@@ -15,14 +15,18 @@
#include <asm/gpio.h>
#include <dm/pinctrl.h>
#include <linux/bitops.h>
+#include <linux/bitmap.h>
#include <linux/bug.h>
#include <mach/gpio.h>
#include "pinctrl-qcom.h"
+#define MSM_PINCTRL_MAX_PINS 256
+
struct msm_pinctrl_priv {
phys_addr_t base;
struct msm_pinctrl_data *data;
+ DECLARE_BITMAP(reserved_map, MSM_PINCTRL_MAX_PINS);
};
#define GPIO_CONFIG_REG(priv, x) \
@@ -71,13 +75,60 @@ static const char *msm_get_function_name(struct udevice *dev,
return priv->data->get_function_name(dev, selector);
}
+static int msm_pinctrl_parse_ranges(struct udevice *dev)
+{
+ struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+ ofnode node = dev_ofnode(dev);
+ int ret, count, i;
+ u32 *ranges;
+
+ if (ofnode_read_prop(node, "gpio-reserved-ranges", &count)) {
+ if (count % 2 == 1) {
+ dev_err(dev, "gpio-reserved-ranges must be a multiple of 2\n");
+ return -EINVAL;
+ }
+
+ ranges = malloc(count);
+ if (!ranges)
+ return -ENOMEM;
+
+ ret = ofnode_read_u32_array(node, "gpio-reserved-ranges", ranges, count / 4);
+ if (ret) {
+ dev_err(dev, "failed to read gpio-reserved-ranges array (%d)\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < count / 4; i += 2) {
+ if (ranges[i] >= MSM_PINCTRL_MAX_PINS ||
+ (ranges[i] + ranges[i + 1]) >= MSM_PINCTRL_MAX_PINS) {
+ dev_err(dev, "invalid reserved-range (%d;%d)\n",
+ ranges[i], ranges[i + 1]);
+ return -EINVAL;
+ }
+
+ bitmap_set(priv->reserved_map, ranges[i], ranges[i + 1]);
+ }
+
+ free(ranges);
+ }
+
+ return 0;
+}
+
static int msm_pinctrl_probe(struct udevice *dev)
{
struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+ int ret;
priv->base = dev_read_addr(dev);
priv->data = (struct msm_pinctrl_data *)dev_get_driver_data(dev);
+ ret = msm_pinctrl_parse_ranges(dev);
+ if (ret) {
+ printf("Couldn't parse reserved GPIO ranges!\n");
+ return ret;
+ }
+
return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0;
}
@@ -97,6 +148,9 @@ static int msm_pinmux_set(struct udevice *dev, unsigned int pin_selector,
if (func < 0)
return func;
+ if (msm_pinctrl_is_reserved(dev, pin_selector))
+ return -EPERM;
+
/* Always NOP for special pins, assume they're in the correct state */
if (qcom_is_special_pin(&priv->data->pin_data, pin_selector))
return 0;
@@ -145,6 +199,9 @@ static int msm_pinconf_set(struct udevice *dev, unsigned int pin_selector,
{
struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+ if (msm_pinctrl_is_reserved(dev, pin_selector))
+ return -EPERM;
+
if (qcom_is_special_pin(&priv->data->pin_data, pin_selector))
return msm_pinconf_set_special(priv, pin_selector, param, argument);
@@ -241,3 +298,13 @@ U_BOOT_DRIVER(pinctrl_qcom) = {
.ops = &msm_pinctrl_ops,
.probe = msm_pinctrl_probe,
};
+
+bool msm_pinctrl_is_reserved(struct udevice *dev, unsigned int pin)
+{
+ struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+
+ if (pin >= MSM_PINCTRL_MAX_PINS)
+ return false;
+
+ return test_bit(pin, priv->reserved_map);
+}
diff --git a/drivers/pinctrl/qcom/pinctrl-sa8775p.c b/drivers/pinctrl/qcom/pinctrl-sa8775p.c
new file mode 100644
index 00000000000..cb2496ff1fb
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-sa8775p.c
@@ -0,0 +1,623 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#include <dm.h>
+
+#include "pinctrl-qcom.h"
+
+#define MAX_PIN_NAME_LEN 32
+static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
+
+typedef unsigned int msm_pin_function[10];
+#define SA8775_PIN_OFFSET 0x100000
+
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9)\
+ { \
+ msm_mux_gpio, /* gpio mode */ \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9 \
+ }
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = pg_name, \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ }
+
+#define UFS_RESET(pg_name, ctl) \
+ { \
+ .name = pg_name, \
+ .ctl_reg = ctl, \
+ .io_reg = ctl + 0x4, \
+ .pull_bit = 3, \
+ .drv_bit = 0, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = 0, \
+ }
+
+enum sa8775p_functions {
+ msm_mux_gpio,
+ msm_mux_atest_char,
+ msm_mux_atest_usb2,
+ msm_mux_audio_ref,
+ msm_mux_cam_mclk,
+ msm_mux_cci_async,
+ msm_mux_cci_i2c,
+ msm_mux_cci_timer0,
+ msm_mux_cci_timer1,
+ msm_mux_cci_timer2,
+ msm_mux_cci_timer3,
+ msm_mux_cci_timer4,
+ msm_mux_cci_timer5,
+ msm_mux_cci_timer6,
+ msm_mux_cci_timer7,
+ msm_mux_cci_timer8,
+ msm_mux_cci_timer9,
+ msm_mux_cri_trng,
+ msm_mux_cri_trng0,
+ msm_mux_cri_trng1,
+ msm_mux_dbg_out,
+ msm_mux_ddr_bist,
+ msm_mux_ddr_pxi0,
+ msm_mux_ddr_pxi1,
+ msm_mux_ddr_pxi2,
+ msm_mux_ddr_pxi3,
+ msm_mux_ddr_pxi4,
+ msm_mux_ddr_pxi5,
+ msm_mux_edp0_hot,
+ msm_mux_edp0_lcd,
+ msm_mux_edp1_hot,
+ msm_mux_edp1_lcd,
+ msm_mux_edp2_hot,
+ msm_mux_edp2_lcd,
+ msm_mux_edp3_hot,
+ msm_mux_edp3_lcd,
+ msm_mux_emac0_mcg0,
+ msm_mux_emac0_mcg1,
+ msm_mux_emac0_mcg2,
+ msm_mux_emac0_mcg3,
+ msm_mux_emac0_mdc,
+ msm_mux_emac0_mdio,
+ msm_mux_emac0_ptp_aux,
+ msm_mux_emac0_ptp_pps,
+ msm_mux_emac1_mcg0,
+ msm_mux_emac1_mcg1,
+ msm_mux_emac1_mcg2,
+ msm_mux_emac1_mcg3,
+ msm_mux_emac1_mdc,
+ msm_mux_emac1_mdio,
+ msm_mux_emac1_ptp_aux,
+ msm_mux_emac1_ptp_pps,
+ msm_mux_gcc_gp1,
+ msm_mux_gcc_gp2,
+ msm_mux_gcc_gp3,
+ msm_mux_gcc_gp4,
+ msm_mux_gcc_gp5,
+ msm_mux_hs0_mi2s,
+ msm_mux_hs1_mi2s,
+ msm_mux_hs2_mi2s,
+ msm_mux_ibi_i3c,
+ msm_mux_jitter_bist,
+ msm_mux_mdp0_vsync0,
+ msm_mux_mdp0_vsync1,
+ msm_mux_mdp0_vsync2,
+ msm_mux_mdp0_vsync3,
+ msm_mux_mdp0_vsync4,
+ msm_mux_mdp0_vsync5,
+ msm_mux_mdp0_vsync6,
+ msm_mux_mdp0_vsync7,
+ msm_mux_mdp0_vsync8,
+ msm_mux_mdp1_vsync0,
+ msm_mux_mdp1_vsync1,
+ msm_mux_mdp1_vsync2,
+ msm_mux_mdp1_vsync3,
+ msm_mux_mdp1_vsync4,
+ msm_mux_mdp1_vsync5,
+ msm_mux_mdp1_vsync6,
+ msm_mux_mdp1_vsync7,
+ msm_mux_mdp1_vsync8,
+ msm_mux_mdp_vsync,
+ msm_mux_mi2s1_data0,
+ msm_mux_mi2s1_data1,
+ msm_mux_mi2s1_sck,
+ msm_mux_mi2s1_ws,
+ msm_mux_mi2s2_data0,
+ msm_mux_mi2s2_data1,
+ msm_mux_mi2s2_sck,
+ msm_mux_mi2s2_ws,
+ msm_mux_mi2s_mclk0,
+ msm_mux_mi2s_mclk1,
+ msm_mux_pcie0_clkreq,
+ msm_mux_pcie1_clkreq,
+ msm_mux_phase_flag,
+ msm_mux_pll_bist,
+ msm_mux_pll_clk,
+ msm_mux_prng_rosc0,
+ msm_mux_prng_rosc1,
+ msm_mux_prng_rosc2,
+ msm_mux_prng_rosc3,
+ msm_mux_qdss_cti,
+ msm_mux_qdss_gpio,
+ msm_mux_qup0_se0,
+ msm_mux_qup0_se1,
+ msm_mux_qup0_se2,
+ msm_mux_qup0_se3,
+ msm_mux_qup0_se4,
+ msm_mux_qup0_se5,
+ msm_mux_qup1_se0,
+ msm_mux_qup1_se1,
+ msm_mux_qup1_se2,
+ msm_mux_qup1_se3,
+ msm_mux_qup1_se4,
+ msm_mux_qup1_se5,
+ msm_mux_qup1_se6,
+ msm_mux_qup2_se0,
+ msm_mux_qup2_se1,
+ msm_mux_qup2_se2,
+ msm_mux_qup2_se3,
+ msm_mux_qup2_se4,
+ msm_mux_qup2_se5,
+ msm_mux_qup2_se6,
+ msm_mux_qup3_se0,
+ msm_mux_sail_top,
+ msm_mux_sailss_emac0,
+ msm_mux_sailss_ospi,
+ msm_mux_sgmii_phy,
+ msm_mux_tb_trig,
+ msm_mux_tgu_ch0,
+ msm_mux_tgu_ch1,
+ msm_mux_tgu_ch2,
+ msm_mux_tgu_ch3,
+ msm_mux_tgu_ch4,
+ msm_mux_tgu_ch5,
+ msm_mux_tsense_pwm1,
+ msm_mux_tsense_pwm2,
+ msm_mux_tsense_pwm3,
+ msm_mux_tsense_pwm4,
+ msm_mux_usb2phy_ac,
+ msm_mux_vsense_trigger,
+ msm_mux__,
+};
+
+#define MSM_PIN_FUNCTION(fname) \
+ [msm_mux_##fname] = {#fname, msm_mux_##fname}
+
+static const struct pinctrl_function msm_pinctrl_functions[] = {
+ MSM_PIN_FUNCTION(gpio),
+ MSM_PIN_FUNCTION(atest_char),
+ MSM_PIN_FUNCTION(atest_usb2),
+ MSM_PIN_FUNCTION(audio_ref),
+ MSM_PIN_FUNCTION(cam_mclk),
+ MSM_PIN_FUNCTION(cci_async),
+ MSM_PIN_FUNCTION(cci_i2c),
+ MSM_PIN_FUNCTION(cci_timer0),
+ MSM_PIN_FUNCTION(cci_timer1),
+ MSM_PIN_FUNCTION(cci_timer2),
+ MSM_PIN_FUNCTION(cci_timer3),
+ MSM_PIN_FUNCTION(cci_timer4),
+ MSM_PIN_FUNCTION(cci_timer5),
+ MSM_PIN_FUNCTION(cci_timer6),
+ MSM_PIN_FUNCTION(cci_timer7),
+ MSM_PIN_FUNCTION(cci_timer8),
+ MSM_PIN_FUNCTION(cci_timer9),
+ MSM_PIN_FUNCTION(cri_trng),
+ MSM_PIN_FUNCTION(cri_trng0),
+ MSM_PIN_FUNCTION(cri_trng1),
+ MSM_PIN_FUNCTION(dbg_out),
+ MSM_PIN_FUNCTION(ddr_bist),
+ MSM_PIN_FUNCTION(ddr_pxi0),
+ MSM_PIN_FUNCTION(ddr_pxi1),
+ MSM_PIN_FUNCTION(ddr_pxi2),
+ MSM_PIN_FUNCTION(ddr_pxi3),
+ MSM_PIN_FUNCTION(ddr_pxi4),
+ MSM_PIN_FUNCTION(ddr_pxi5),
+ MSM_PIN_FUNCTION(edp0_hot),
+ MSM_PIN_FUNCTION(edp0_lcd),
+ MSM_PIN_FUNCTION(edp1_hot),
+ MSM_PIN_FUNCTION(edp1_lcd),
+ MSM_PIN_FUNCTION(edp2_hot),
+ MSM_PIN_FUNCTION(edp2_lcd),
+ MSM_PIN_FUNCTION(edp3_hot),
+ MSM_PIN_FUNCTION(edp3_lcd),
+ MSM_PIN_FUNCTION(emac0_mcg0),
+ MSM_PIN_FUNCTION(emac0_mcg1),
+ MSM_PIN_FUNCTION(emac0_mcg2),
+ MSM_PIN_FUNCTION(emac0_mcg3),
+ MSM_PIN_FUNCTION(emac0_mdc),
+ MSM_PIN_FUNCTION(emac0_mdio),
+ MSM_PIN_FUNCTION(emac0_ptp_aux),
+ MSM_PIN_FUNCTION(emac0_ptp_pps),
+ MSM_PIN_FUNCTION(emac1_mcg0),
+ MSM_PIN_FUNCTION(emac1_mcg1),
+ MSM_PIN_FUNCTION(emac1_mcg2),
+ MSM_PIN_FUNCTION(emac1_mcg3),
+ MSM_PIN_FUNCTION(emac1_mdc),
+ MSM_PIN_FUNCTION(emac1_mdio),
+ MSM_PIN_FUNCTION(emac1_ptp_aux),
+ MSM_PIN_FUNCTION(emac1_ptp_pps),
+ MSM_PIN_FUNCTION(gcc_gp1),
+ MSM_PIN_FUNCTION(gcc_gp2),
+ MSM_PIN_FUNCTION(gcc_gp3),
+ MSM_PIN_FUNCTION(gcc_gp4),
+ MSM_PIN_FUNCTION(gcc_gp5),
+ MSM_PIN_FUNCTION(hs0_mi2s),
+ MSM_PIN_FUNCTION(hs1_mi2s),
+ MSM_PIN_FUNCTION(hs2_mi2s),
+ MSM_PIN_FUNCTION(ibi_i3c),
+ MSM_PIN_FUNCTION(jitter_bist),
+ MSM_PIN_FUNCTION(mdp0_vsync0),
+ MSM_PIN_FUNCTION(mdp0_vsync1),
+ MSM_PIN_FUNCTION(mdp0_vsync2),
+ MSM_PIN_FUNCTION(mdp0_vsync3),
+ MSM_PIN_FUNCTION(mdp0_vsync4),
+ MSM_PIN_FUNCTION(mdp0_vsync5),
+ MSM_PIN_FUNCTION(mdp0_vsync6),
+ MSM_PIN_FUNCTION(mdp0_vsync7),
+ MSM_PIN_FUNCTION(mdp0_vsync8),
+ MSM_PIN_FUNCTION(mdp1_vsync0),
+ MSM_PIN_FUNCTION(mdp1_vsync1),
+ MSM_PIN_FUNCTION(mdp1_vsync2),
+ MSM_PIN_FUNCTION(mdp1_vsync3),
+ MSM_PIN_FUNCTION(mdp1_vsync4),
+ MSM_PIN_FUNCTION(mdp1_vsync5),
+ MSM_PIN_FUNCTION(mdp1_vsync6),
+ MSM_PIN_FUNCTION(mdp1_vsync7),
+ MSM_PIN_FUNCTION(mdp1_vsync8),
+ MSM_PIN_FUNCTION(mdp_vsync),
+ MSM_PIN_FUNCTION(mi2s1_data0),
+ MSM_PIN_FUNCTION(mi2s1_data1),
+ MSM_PIN_FUNCTION(mi2s1_sck),
+ MSM_PIN_FUNCTION(mi2s1_ws),
+ MSM_PIN_FUNCTION(mi2s2_data0),
+ MSM_PIN_FUNCTION(mi2s2_data1),
+ MSM_PIN_FUNCTION(mi2s2_sck),
+ MSM_PIN_FUNCTION(mi2s2_ws),
+ MSM_PIN_FUNCTION(mi2s_mclk0),
+ MSM_PIN_FUNCTION(mi2s_mclk1),
+ MSM_PIN_FUNCTION(pcie0_clkreq),
+ MSM_PIN_FUNCTION(pcie1_clkreq),
+ MSM_PIN_FUNCTION(phase_flag),
+ MSM_PIN_FUNCTION(pll_bist),
+ MSM_PIN_FUNCTION(pll_clk),
+ MSM_PIN_FUNCTION(prng_rosc0),
+ MSM_PIN_FUNCTION(prng_rosc1),
+ MSM_PIN_FUNCTION(prng_rosc2),
+ MSM_PIN_FUNCTION(prng_rosc3),
+ MSM_PIN_FUNCTION(qdss_cti),
+ MSM_PIN_FUNCTION(qdss_gpio),
+ MSM_PIN_FUNCTION(qup0_se0),
+ MSM_PIN_FUNCTION(qup0_se1),
+ MSM_PIN_FUNCTION(qup0_se2),
+ MSM_PIN_FUNCTION(qup0_se3),
+ MSM_PIN_FUNCTION(qup0_se4),
+ MSM_PIN_FUNCTION(qup0_se5),
+ MSM_PIN_FUNCTION(qup1_se0),
+ MSM_PIN_FUNCTION(qup1_se1),
+ MSM_PIN_FUNCTION(qup1_se2),
+ MSM_PIN_FUNCTION(qup1_se3),
+ MSM_PIN_FUNCTION(qup1_se4),
+ MSM_PIN_FUNCTION(qup1_se5),
+ MSM_PIN_FUNCTION(qup1_se6),
+ MSM_PIN_FUNCTION(qup2_se0),
+ MSM_PIN_FUNCTION(qup2_se1),
+ MSM_PIN_FUNCTION(qup2_se2),
+ MSM_PIN_FUNCTION(qup2_se3),
+ MSM_PIN_FUNCTION(qup2_se4),
+ MSM_PIN_FUNCTION(qup2_se5),
+ MSM_PIN_FUNCTION(qup2_se6),
+ MSM_PIN_FUNCTION(qup3_se0),
+ MSM_PIN_FUNCTION(sail_top),
+ MSM_PIN_FUNCTION(sailss_emac0),
+ MSM_PIN_FUNCTION(sailss_ospi),
+ MSM_PIN_FUNCTION(sgmii_phy),
+ MSM_PIN_FUNCTION(tb_trig),
+ MSM_PIN_FUNCTION(tgu_ch0),
+ MSM_PIN_FUNCTION(tgu_ch1),
+ MSM_PIN_FUNCTION(tgu_ch2),
+ MSM_PIN_FUNCTION(tgu_ch3),
+ MSM_PIN_FUNCTION(tgu_ch4),
+ MSM_PIN_FUNCTION(tgu_ch5),
+ MSM_PIN_FUNCTION(tsense_pwm1),
+ MSM_PIN_FUNCTION(tsense_pwm2),
+ MSM_PIN_FUNCTION(tsense_pwm3),
+ MSM_PIN_FUNCTION(tsense_pwm4),
+ MSM_PIN_FUNCTION(usb2phy_ac),
+ MSM_PIN_FUNCTION(vsense_trigger),
+};
+
+static const msm_pin_function sa8775p_pin_functions[] = {
+ [0] = PINGROUP(0, _, _, _, _, _, _, _, _, _),
+ [1] = PINGROUP(1, pcie0_clkreq, _, _, _, _, _, _, _, _),
+ [2] = PINGROUP(2, _, _, _, _, _, _, _, _, _),
+ [3] = PINGROUP(3, pcie1_clkreq, _, _, _, _, _, _, _, _),
+ [4] = PINGROUP(4, _, _, _, _, _, _, _, _, _),
+ [5] = PINGROUP(5, _, _, _, _, _, _, _, _, _),
+ [6] = PINGROUP(6, emac0_ptp_aux, emac0_ptp_pps, emac1_ptp_aux,
+ emac1_ptp_pps, _, _, _, _, _),
+ [7] = PINGROUP(7, sgmii_phy, _, _, _, _, _, _, _, _),
+ [8] = PINGROUP(8, emac0_mdc, _, _, _, _, _, _, _, _),
+ [9] = PINGROUP(9, emac0_mdio, _, _, _, _, _, _, _, _),
+ [10] = PINGROUP(10, usb2phy_ac, emac0_ptp_aux, emac0_ptp_pps,
+ emac1_ptp_aux, emac1_ptp_pps, _, _, _, _),
+ [11] = PINGROUP(11, usb2phy_ac, emac0_ptp_aux, emac0_ptp_pps,
+ emac1_ptp_aux, emac1_ptp_pps, _, _, _, _),
+ [12] = PINGROUP(12, usb2phy_ac, emac0_ptp_aux, emac0_ptp_pps,
+ emac1_ptp_aux, emac1_ptp_pps, emac0_mcg0, _, _, _),
+ [13] = PINGROUP(13, qup3_se0, emac0_mcg1, _, _, sail_top, _, _, _, _),
+ [14] = PINGROUP(14, qup3_se0, emac0_mcg2, _, _, sail_top, _, _, _, _),
+ [15] = PINGROUP(15, qup3_se0, emac0_mcg3, _, _, sail_top, _, _, _, _),
+ [16] = PINGROUP(16, qup3_se0, emac1_mcg0, _, _, sail_top, _, _, _, _),
+ [17] = PINGROUP(17, qup3_se0, tb_trig, tb_trig, emac1_mcg1, _, _, _, _, _),
+ [18] = PINGROUP(18, qup3_se0, emac1_mcg2, _, _, sailss_ospi, sailss_emac0, _, _, _),
+ [19] = PINGROUP(19, qup3_se0, emac1_mcg3, _, _, sailss_ospi, sailss_emac0, _, _, _),
+ [20] = PINGROUP(20, qup0_se0, emac1_mdc, qdss_gpio, _, _, _, _, _, _),
+ [21] = PINGROUP(21, qup0_se0, emac1_mdio, qdss_gpio, _, _, _, _, _, _),
+ [22] = PINGROUP(22, qup0_se0, qdss_gpio, _, _, _, _, _, _, _),
+ [23] = PINGROUP(23, qup0_se0, qdss_gpio, _, _, _, _, _, _, _),
+ [24] = PINGROUP(24, qup0_se1, qdss_gpio, _, _, _, _, _, _, _),
+ [25] = PINGROUP(25, qup0_se1, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [26] = PINGROUP(26, sgmii_phy, qup0_se1, qdss_cti, phase_flag, _, _, _, _, _),
+ [27] = PINGROUP(27, qup0_se1, qdss_cti, phase_flag, _, atest_char, _, _, _, _),
+ [28] = PINGROUP(28, qup0_se3, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [29] = PINGROUP(29, qup0_se3, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [30] = PINGROUP(30, qup0_se3, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [31] = PINGROUP(31, qup0_se3, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [32] = PINGROUP(32, qup0_se4, phase_flag, _, _, _, _, _, _, _),
+ [33] = PINGROUP(33, qup0_se4, gcc_gp4, _, ddr_pxi0, _, _, _, _, _),
+ [34] = PINGROUP(34, qup0_se4, gcc_gp5, _, ddr_pxi0, _, _, _, _, _),
+ [35] = PINGROUP(35, qup0_se4, phase_flag, _, _, _, _, _, _, _),
+ [36] = PINGROUP(36, qup0_se2, qup0_se5, phase_flag, tgu_ch2, _, _, _, _, _),
+ [37] = PINGROUP(37, qup0_se2, qup0_se5, phase_flag, tgu_ch3, _, _, _, _, _),
+ [38] = PINGROUP(38, qup0_se5, qup0_se2, qdss_cti, phase_flag, tgu_ch4, _, _, _, _),
+ [39] = PINGROUP(39, qup0_se5, qup0_se2, qdss_cti, phase_flag, tgu_ch5, _, _, _, _),
+ [40] = PINGROUP(40, qup1_se0, qup1_se1, ibi_i3c, mdp1_vsync0, _, _, _, _, _),
+ [41] = PINGROUP(41, qup1_se0, qup1_se1, ibi_i3c, mdp1_vsync1, _, _, _, _, _),
+ [42] = PINGROUP(42, qup1_se1, qup1_se0, ibi_i3c, mdp1_vsync2, gcc_gp5, _, _, _, _),
+ [43] = PINGROUP(43, qup1_se1, qup1_se0, ibi_i3c, mdp1_vsync3, _, _, _, _, _),
+ [44] = PINGROUP(44, qup1_se2, qup1_se3, edp0_lcd, _, _, _, _, _, _),
+ [45] = PINGROUP(45, qup1_se2, qup1_se3, edp1_lcd, _, _, _, _, _, _),
+ [46] = PINGROUP(46, qup1_se3, qup1_se2, mdp1_vsync4, tgu_ch0, _, _, _, _, _),
+ [47] = PINGROUP(47, qup1_se3, qup1_se2, mdp1_vsync5, tgu_ch1, _, _, _, _, _),
+ [48] = PINGROUP(48, qup1_se4, qdss_cti, edp2_lcd, _, _, _, _, _, _),
+ [49] = PINGROUP(49, qup1_se4, qdss_cti, edp3_lcd, _, _, _, _, _, _),
+ [50] = PINGROUP(50, qup1_se4, cci_async, qdss_cti, mdp1_vsync8, _, _, _, _, _),
+ [51] = PINGROUP(51, qup1_se4, qdss_cti, mdp1_vsync6, gcc_gp1, _, _, _, _, _),
+ [52] = PINGROUP(52, qup1_se5, cci_timer4, cci_i2c, mdp1_vsync7, gcc_gp2, _, ddr_pxi1, _, _),
+ [53] = PINGROUP(53, qup1_se5, cci_timer5, cci_i2c, gcc_gp3, _, ddr_pxi1, _, _, _),
+ [54] = PINGROUP(54, qup1_se5, cci_timer6, cci_i2c, _, _, _, _, _, _),
+ [55] = PINGROUP(55, qup1_se5, cci_timer7, cci_i2c, gcc_gp4, _, ddr_pxi2, _, _, _),
+ [56] = PINGROUP(56, qup1_se6, qup1_se6, cci_timer8, cci_i2c, phase_flag, ddr_bist, _, _, _),
+ [57] = PINGROUP(57, qup1_se6, qup1_se6, cci_timer9, cci_i2c,
+ mdp0_vsync0, phase_flag, ddr_bist, _, _),
+ [58] = PINGROUP(58, cci_i2c, mdp0_vsync1, ddr_bist, _, atest_usb2, atest_char, _, _, _),
+ [59] = PINGROUP(59, cci_i2c, mdp0_vsync2, ddr_bist, _, atest_usb2, atest_char, _, _, _),
+ [60] = PINGROUP(60, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [61] = PINGROUP(61, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [62] = PINGROUP(62, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [63] = PINGROUP(63, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [64] = PINGROUP(64, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [65] = PINGROUP(65, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [66] = PINGROUP(66, cci_i2c, cci_async, qdss_gpio, _, _, _, _, _, _),
+ [67] = PINGROUP(67, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [68] = PINGROUP(68, cci_timer0, cci_async, _, _, _, _, _, _, _),
+ [69] = PINGROUP(69, cci_timer1, cci_async, _, _, _, _, _, _, _),
+ [70] = PINGROUP(70, cci_timer2, cci_async, _, _, _, _, _, _, _),
+ [71] = PINGROUP(71, cci_timer3, cci_async, _, _, _, _, _, _, _),
+ [72] = PINGROUP(72, cam_mclk, _, _, _, _, _, _, _, _),
+ [73] = PINGROUP(73, cam_mclk, _, _, _, _, _, _, _, _),
+ [74] = PINGROUP(74, cam_mclk, _, _, _, _, _, _, _, _),
+ [75] = PINGROUP(75, cam_mclk, _, _, _, _, _, _, _, _),
+ [76] = PINGROUP(76, _, _, _, _, _, _, _, _, _),
+ [77] = PINGROUP(77, _, _, _, _, _, _, _, _, _),
+ [78] = PINGROUP(78, _, _, _, _, _, _, _, _, _),
+ [79] = PINGROUP(79, _, _, _, _, _, _, _, _, _),
+ [80] = PINGROUP(80, qup2_se0, ibi_i3c, mdp0_vsync3, _, _, _, _, _, _),
+ [81] = PINGROUP(81, qup2_se0, ibi_i3c, mdp0_vsync4, _, _, _, _, _, _),
+ [82] = PINGROUP(82, qup2_se0, mdp_vsync, gcc_gp1, _, _, _, _, _, _),
+ [83] = PINGROUP(83, qup2_se0, mdp_vsync, gcc_gp2, _, _, _, _, _, _),
+ [84] = PINGROUP(84, qup2_se1, qup2_se5, ibi_i3c, mdp_vsync, gcc_gp3, _, _, _, _),
+ [85] = PINGROUP(85, qup2_se1, qup2_se5, ibi_i3c, _, _, _, _, _, _),
+ [86] = PINGROUP(86, qup2_se2, jitter_bist, atest_usb2, ddr_pxi2, _, _, _, _, _),
+ [87] = PINGROUP(87, qup2_se2, pll_clk, atest_usb2, ddr_pxi3, _, _, _, _, _),
+ [88] = PINGROUP(88, qup2_se2, _, atest_usb2, ddr_pxi3, _, _, _, _, _),
+ [89] = PINGROUP(89, qup2_se2, _, atest_usb2, ddr_pxi4, atest_char, _, _, _, _),
+ [90] = PINGROUP(90, qup2_se2, _, atest_usb2, ddr_pxi4, atest_char, _, _, _, _),
+ [91] = PINGROUP(91, qup2_se3, mdp0_vsync5, _, atest_usb2, _, _, _, _, _),
+ [92] = PINGROUP(92, qup2_se3, mdp0_vsync6, _, atest_usb2, _, _, _, _, _),
+ [93] = PINGROUP(93, qup2_se3, mdp0_vsync7, _, atest_usb2, _, _, _, _, _),
+ [94] = PINGROUP(94, qup2_se3, mdp0_vsync8, _, atest_usb2, _, _, _, _, _),
+ [95] = PINGROUP(95, qup2_se4, qup2_se6, _, atest_usb2, _, _, _, _, _),
+ [96] = PINGROUP(96, qup2_se4, qup2_se6, _, atest_usb2, _, _, _, _, _),
+ [97] = PINGROUP(97, qup2_se6, qup2_se4, cri_trng0, _, atest_usb2, _, _, _, _),
+ [98] = PINGROUP(98, qup2_se6, qup2_se4, phase_flag, cri_trng1, _, _, _, _, _),
+ [99] = PINGROUP(99, qup2_se5, qup2_se1, phase_flag, cri_trng, _, _, _, _, _),
+ [100] = PINGROUP(100, qup2_se5, qup2_se1, _, _, _, _, _, _, _),
+ [101] = PINGROUP(101, edp0_hot, prng_rosc0, tsense_pwm4, _, _, _, _, _, _),
+ [102] = PINGROUP(102, edp1_hot, prng_rosc1, tsense_pwm3, _, _, _, _, _, _),
+ [103] = PINGROUP(103, edp3_hot, prng_rosc2, tsense_pwm2, _, _, _, _, _, _),
+ [104] = PINGROUP(104, edp2_hot, prng_rosc3, tsense_pwm1, _, _, _, _, _, _),
+ [105] = PINGROUP(105, mi2s_mclk0, _, qdss_gpio, atest_usb2, _, _, _, _, _),
+ [106] = PINGROUP(106, mi2s1_sck, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [107] = PINGROUP(107, mi2s1_ws, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [108] = PINGROUP(108, mi2s1_data0, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [109] = PINGROUP(109, mi2s1_data1, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [110] = PINGROUP(110, mi2s2_sck, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [111] = PINGROUP(111, mi2s2_ws, phase_flag, _, qdss_gpio, vsense_trigger, _, _, _, _),
+ [112] = PINGROUP(112, mi2s2_data0, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [113] = PINGROUP(113, mi2s2_data1, audio_ref, phase_flag, _, qdss_gpio, _, _, _, _),
+ [114] = PINGROUP(114, hs0_mi2s, pll_bist, phase_flag, _, qdss_gpio, _, _, _, _),
+ [115] = PINGROUP(115, hs0_mi2s, _, qdss_gpio, _, _, _, _, _, _),
+ [116] = PINGROUP(116, hs0_mi2s, _, qdss_gpio, _, _, _, _, _, _),
+ [117] = PINGROUP(117, hs0_mi2s, mi2s_mclk1, _, qdss_gpio, _, _, _, _, _),
+ [118] = PINGROUP(118, hs1_mi2s, _, qdss_gpio, ddr_pxi5, _, _, _, _, _),
+ [119] = PINGROUP(119, hs1_mi2s, _, qdss_gpio, ddr_pxi5, _, _, _, _, _),
+ [120] = PINGROUP(120, hs1_mi2s, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [121] = PINGROUP(121, hs1_mi2s, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [122] = PINGROUP(122, hs2_mi2s, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [123] = PINGROUP(123, hs2_mi2s, phase_flag, _, _, _, _, _, _, _),
+ [124] = PINGROUP(124, hs2_mi2s, phase_flag, _, _, _, _, _, _, _),
+ [125] = PINGROUP(125, hs2_mi2s, phase_flag, _, _, _, _, _, _, _),
+ [126] = PINGROUP(126, _, _, _, _, _, _, _, _, _),
+ [127] = PINGROUP(127, _, _, _, _, _, _, _, _, _),
+ [128] = PINGROUP(128, _, _, _, _, _, _, _, _, _),
+ [129] = PINGROUP(129, _, _, _, _, _, _, _, _, _),
+ [130] = PINGROUP(130, _, _, _, _, _, _, _, _, _),
+ [131] = PINGROUP(131, _, _, _, _, _, _, _, _, _),
+ [132] = PINGROUP(132, _, _, _, _, _, _, _, _, _),
+ [133] = PINGROUP(133, _, _, _, _, _, _, _, _, _),
+ [134] = PINGROUP(134, _, _, _, _, _, _, _, _, _),
+ [135] = PINGROUP(135, _, _, _, _, _, _, _, _, _),
+ [136] = PINGROUP(136, _, _, _, _, _, _, _, _, _),
+ [137] = PINGROUP(137, _, _, _, _, _, _, _, _, _),
+ [138] = PINGROUP(138, _, _, _, _, _, _, _, _, _),
+ [139] = PINGROUP(139, _, _, _, _, _, _, _, _, _),
+ [140] = PINGROUP(140, _, _, _, _, _, _, _, _, _),
+ [141] = PINGROUP(141, _, _, _, _, _, _, _, _, _),
+ [142] = PINGROUP(142, _, _, _, _, _, _, _, _, _),
+ [143] = PINGROUP(143, _, _, _, _, _, _, _, _, _),
+ [144] = PINGROUP(144, dbg_out, _, _, _, _, _, _, _, _),
+ [145] = PINGROUP(145, _, _, _, _, _, _, _, _, _),
+ [146] = PINGROUP(146, _, _, _, _, _, _, _, _, _),
+ [147] = PINGROUP(147, _, _, _, _, _, _, _, _, _),
+ [148] = PINGROUP(148, _, _, _, _, _, _, _, _, _),
+};
+
+static const struct msm_special_pin_data msm_special_pins_data[] = {
+ [0] = UFS_RESET("ufs_reset", 0x1a2000),
+ [1] = SDC_QDSD_PINGROUP("sdc1_rclk", 0x199000, 15, 0),
+ [2] = SDC_QDSD_PINGROUP("sdc1_clk", 0x199000, 13, 6),
+ [3] = SDC_QDSD_PINGROUP("sdc1_cmd", 0x199000, 11, 3),
+ [4] = SDC_QDSD_PINGROUP("sdc1_data", 0x199000, 9, 0),
+};
+
+static const char *sa8775p_get_function_name(struct udevice *dev,
+ unsigned int selector)
+{
+ return msm_pinctrl_functions[selector].name;
+}
+
+static const char *sa8775p_get_pin_name(struct udevice *dev,
+ unsigned int selector)
+{
+ if (selector >= 149 && selector <= 155)
+ snprintf(pin_name, MAX_PIN_NAME_LEN,
+ msm_special_pins_data[selector - 149].name);
+ else
+ snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
+
+ return pin_name;
+}
+
+static int sa8775p_get_function_mux(__maybe_unused unsigned int pin,
+ unsigned int selector)
+{
+ unsigned int i;
+ const msm_pin_function *func = sa8775p_pin_functions + pin;
+
+ for (i = 0; i < 10; i++)
+ if ((*func)[i] == selector)
+ return i;
+
+ pr_err("Can't find requested function for pin %u pin\n", pin);
+
+ return -EINVAL;
+}
+
+static const unsigned int sa8775p_pin_offsets[] = {
+ [0] = SA8775_PIN_OFFSET, [1] = SA8775_PIN_OFFSET, [2] = SA8775_PIN_OFFSET,
+ [3] = SA8775_PIN_OFFSET, [4] = SA8775_PIN_OFFSET, [5] = SA8775_PIN_OFFSET,
+ [6] = SA8775_PIN_OFFSET, [7] = SA8775_PIN_OFFSET, [8] = SA8775_PIN_OFFSET,
+ [9] = SA8775_PIN_OFFSET, [10] = SA8775_PIN_OFFSET, [11] = SA8775_PIN_OFFSET,
+ [12] = SA8775_PIN_OFFSET, [13] = SA8775_PIN_OFFSET, [14] = SA8775_PIN_OFFSET,
+ [15] = SA8775_PIN_OFFSET, [16] = SA8775_PIN_OFFSET, [17] = SA8775_PIN_OFFSET,
+ [18] = SA8775_PIN_OFFSET, [19] = SA8775_PIN_OFFSET, [20] = SA8775_PIN_OFFSET,
+ [21] = SA8775_PIN_OFFSET, [22] = SA8775_PIN_OFFSET, [23] = SA8775_PIN_OFFSET,
+ [24] = SA8775_PIN_OFFSET, [25] = SA8775_PIN_OFFSET, [26] = SA8775_PIN_OFFSET,
+ [27] = SA8775_PIN_OFFSET, [28] = SA8775_PIN_OFFSET, [29] = SA8775_PIN_OFFSET,
+ [30] = SA8775_PIN_OFFSET, [31] = SA8775_PIN_OFFSET, [32] = SA8775_PIN_OFFSET,
+ [33] = SA8775_PIN_OFFSET, [34] = SA8775_PIN_OFFSET, [35] = SA8775_PIN_OFFSET,
+ [36] = SA8775_PIN_OFFSET, [37] = SA8775_PIN_OFFSET, [38] = SA8775_PIN_OFFSET,
+ [39] = SA8775_PIN_OFFSET, [40] = SA8775_PIN_OFFSET, [41] = SA8775_PIN_OFFSET,
+ [42] = SA8775_PIN_OFFSET, [43] = SA8775_PIN_OFFSET, [44] = SA8775_PIN_OFFSET,
+ [45] = SA8775_PIN_OFFSET, [46] = SA8775_PIN_OFFSET, [47] = SA8775_PIN_OFFSET,
+ [48] = SA8775_PIN_OFFSET, [49] = SA8775_PIN_OFFSET, [50] = SA8775_PIN_OFFSET,
+ [51] = SA8775_PIN_OFFSET, [52] = SA8775_PIN_OFFSET, [53] = SA8775_PIN_OFFSET,
+ [54] = SA8775_PIN_OFFSET, [55] = SA8775_PIN_OFFSET, [56] = SA8775_PIN_OFFSET,
+ [57] = SA8775_PIN_OFFSET, [58] = SA8775_PIN_OFFSET, [59] = SA8775_PIN_OFFSET,
+ [60] = SA8775_PIN_OFFSET, [61] = SA8775_PIN_OFFSET, [62] = SA8775_PIN_OFFSET,
+ [63] = SA8775_PIN_OFFSET, [64] = SA8775_PIN_OFFSET, [65] = SA8775_PIN_OFFSET,
+ [66] = SA8775_PIN_OFFSET, [67] = SA8775_PIN_OFFSET, [68] = SA8775_PIN_OFFSET,
+ [69] = SA8775_PIN_OFFSET, [70] = SA8775_PIN_OFFSET, [71] = SA8775_PIN_OFFSET,
+ [72] = SA8775_PIN_OFFSET, [73] = SA8775_PIN_OFFSET, [74] = SA8775_PIN_OFFSET,
+ [75] = SA8775_PIN_OFFSET, [76] = SA8775_PIN_OFFSET, [77] = SA8775_PIN_OFFSET,
+ [78] = SA8775_PIN_OFFSET, [79] = SA8775_PIN_OFFSET, [80] = SA8775_PIN_OFFSET,
+ [81] = SA8775_PIN_OFFSET, [82] = SA8775_PIN_OFFSET, [83] = SA8775_PIN_OFFSET,
+ [84] = SA8775_PIN_OFFSET, [85] = SA8775_PIN_OFFSET, [86] = SA8775_PIN_OFFSET,
+ [87] = SA8775_PIN_OFFSET, [88] = SA8775_PIN_OFFSET, [89] = SA8775_PIN_OFFSET,
+ [90] = SA8775_PIN_OFFSET, [91] = SA8775_PIN_OFFSET, [92] = SA8775_PIN_OFFSET,
+ [93] = SA8775_PIN_OFFSET, [94] = SA8775_PIN_OFFSET, [95] = SA8775_PIN_OFFSET,
+ [96] = SA8775_PIN_OFFSET, [97] = SA8775_PIN_OFFSET, [98] = SA8775_PIN_OFFSET,
+ [99] = SA8775_PIN_OFFSET, [100] = SA8775_PIN_OFFSET, [101] = SA8775_PIN_OFFSET,
+ [102] = SA8775_PIN_OFFSET, [103] = SA8775_PIN_OFFSET, [104] = SA8775_PIN_OFFSET,
+ [105] = SA8775_PIN_OFFSET, [106] = SA8775_PIN_OFFSET, [107] = SA8775_PIN_OFFSET,
+ [108] = SA8775_PIN_OFFSET, [109] = SA8775_PIN_OFFSET, [110] = SA8775_PIN_OFFSET,
+ [111] = SA8775_PIN_OFFSET, [112] = SA8775_PIN_OFFSET, [113] = SA8775_PIN_OFFSET,
+ [114] = SA8775_PIN_OFFSET, [115] = SA8775_PIN_OFFSET, [116] = SA8775_PIN_OFFSET,
+ [117] = SA8775_PIN_OFFSET, [118] = SA8775_PIN_OFFSET, [119] = SA8775_PIN_OFFSET,
+ [120] = SA8775_PIN_OFFSET, [121] = SA8775_PIN_OFFSET, [122] = SA8775_PIN_OFFSET,
+ [123] = SA8775_PIN_OFFSET, [124] = SA8775_PIN_OFFSET, [125] = SA8775_PIN_OFFSET,
+ [126] = SA8775_PIN_OFFSET, [127] = SA8775_PIN_OFFSET, [128] = SA8775_PIN_OFFSET,
+ [129] = SA8775_PIN_OFFSET, [130] = SA8775_PIN_OFFSET, [131] = SA8775_PIN_OFFSET,
+ [132] = SA8775_PIN_OFFSET, [133] = SA8775_PIN_OFFSET, [134] = SA8775_PIN_OFFSET,
+ [135] = SA8775_PIN_OFFSET, [136] = SA8775_PIN_OFFSET, [137] = SA8775_PIN_OFFSET,
+ [138] = SA8775_PIN_OFFSET, [139] = SA8775_PIN_OFFSET, [140] = SA8775_PIN_OFFSET,
+ [141] = SA8775_PIN_OFFSET, [142] = SA8775_PIN_OFFSET, [143] = SA8775_PIN_OFFSET,
+ [144] = SA8775_PIN_OFFSET, [145] = SA8775_PIN_OFFSET, [146] = SA8775_PIN_OFFSET,
+ [147] = SA8775_PIN_OFFSET, [148] = SA8775_PIN_OFFSET, [148] = SA8775_PIN_OFFSET,
+ [149] = SA8775_PIN_OFFSET, [150] = SA8775_PIN_OFFSET, [151] = SA8775_PIN_OFFSET,
+ [152] = SA8775_PIN_OFFSET, [153] = SA8775_PIN_OFFSET, [154] = SA8775_PIN_OFFSET,
+};
+
+static const struct msm_pinctrl_data sa8775p_data = {
+ .pin_data = {
+ .pin_count = 155,
+ .special_pins_start = 149,
+ .special_pins_data = msm_special_pins_data,
+ .pin_offsets = sa8775p_pin_offsets,
+ },
+ .functions_count = ARRAY_SIZE(msm_pinctrl_functions),
+ .get_function_name = sa8775p_get_function_name,
+ .get_function_mux = sa8775p_get_function_mux,
+ .get_pin_name = sa8775p_get_pin_name,
+};
+
+static const struct udevice_id msm_pinctrl_ids[] = {
+ { .compatible = "qcom,sa8775p-tlmm", .data = (ulong)&sa8775p_data },
+ { /* Sentinal */ }
+};
+
+U_BOOT_DRIVER(pinctrl_sa8775p) = {
+ .name = "pinctrl_sa8775p",
+ .id = UCLASS_NOP,
+ .of_match = msm_pinctrl_ids,
+ .ops = &msm_pinctrl_ops,
+ .bind = msm_pinctrl_bind,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm660.c b/drivers/pinctrl/qcom/pinctrl-sdm660.c
new file mode 100644
index 00000000000..646d848ffa4
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-sdm660.c
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm SDM630/660 TLMM pinctrl
+ *
+ */
+
+#include <dm.h>
+#include "pinctrl-qcom.h"
+
+#define TLMM_BASE 0x03100000
+#define SOUTH (0x03100000 - TLMM_BASE) /* 0x0 */
+#define CENTER (0x03500000 - TLMM_BASE) /* 0x400000 */
+#define NORTH (0x03900000 - TLMM_BASE) /* 0x800000 */
+
+#define MAX_PIN_NAME_LEN 32
+static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
+
+static const struct pinctrl_function sdm660_pinctrl_functions[] = {
+ { "gpio", 0 },
+ { "blsp_uart2", 3 }, /* gpio 4 and 5, used for debug uart */
+};
+
+static const unsigned int sdm660_pin_offsets[] = {
+ [0] = SOUTH,
+ [1] = SOUTH,
+ [2] = SOUTH,
+ [3] = SOUTH,
+ [4] = NORTH,
+ [5] = SOUTH,
+ [6] = SOUTH,
+ [7] = SOUTH,
+ [8] = NORTH,
+ [9] = NORTH,
+ [10] = NORTH,
+ [11] = NORTH,
+ [12] = NORTH,
+ [13] = NORTH,
+ [14] = NORTH,
+ [15] = NORTH,
+ [16] = CENTER,
+ [17] = CENTER,
+ [18] = CENTER,
+ [19] = CENTER,
+ [20] = SOUTH,
+ [21] = SOUTH,
+ [22] = CENTER,
+ [23] = CENTER,
+ [24] = NORTH,
+ [25] = NORTH,
+ [26] = NORTH,
+ [27] = NORTH,
+ [28] = CENTER,
+ [29] = CENTER,
+ [30] = CENTER,
+ [31] = CENTER,
+ [32] = SOUTH,
+ [33] = SOUTH,
+ [34] = SOUTH,
+ [35] = SOUTH,
+ [36] = SOUTH,
+ [37] = SOUTH,
+ [38] = SOUTH,
+ [39] = SOUTH,
+ [40] = SOUTH,
+ [41] = SOUTH,
+ [42] = SOUTH,
+ [43] = SOUTH,
+ [44] = SOUTH,
+ [45] = SOUTH,
+ [46] = SOUTH,
+ [47] = SOUTH,
+ [48] = SOUTH,
+ [49] = SOUTH,
+ [50] = SOUTH,
+ [51] = SOUTH,
+ [52] = SOUTH,
+ [53] = NORTH,
+ [54] = NORTH,
+ [55] = SOUTH,
+ [56] = SOUTH,
+ [57] = SOUTH,
+ [58] = SOUTH,
+ [59] = NORTH,
+ [60] = NORTH,
+ [61] = NORTH,
+ [62] = NORTH,
+ [63] = NORTH,
+ [64] = SOUTH,
+ [65] = SOUTH,
+ [66] = NORTH,
+ [67] = NORTH,
+ [68] = NORTH,
+ [69] = NORTH,
+ [70] = NORTH,
+ [71] = NORTH,
+ [72] = NORTH,
+ [73] = NORTH,
+ [74] = NORTH,
+ [75] = NORTH,
+ [76] = NORTH,
+ [77] = NORTH,
+ [78] = NORTH,
+ [79] = SOUTH,
+ [80] = SOUTH,
+ [81] = CENTER,
+ [82] = CENTER,
+ [83] = SOUTH,
+ [84] = SOUTH,
+ [85] = SOUTH,
+ [86] = SOUTH,
+ [87] = SOUTH,
+ [88] = SOUTH,
+ [89] = SOUTH,
+ [90] = SOUTH,
+ [91] = SOUTH,
+ [92] = SOUTH,
+ [93] = SOUTH,
+ [94] = SOUTH,
+ [95] = SOUTH,
+ [96] = SOUTH,
+ [97] = SOUTH,
+ [98] = SOUTH,
+ [99] = SOUTH,
+ [100] = SOUTH,
+ [101] = SOUTH,
+ [102] = SOUTH,
+ [103] = SOUTH,
+ [104] = SOUTH,
+ [105] = SOUTH,
+ [106] = SOUTH,
+ [107] = SOUTH,
+ [108] = SOUTH,
+ [109] = SOUTH,
+ [110] = SOUTH,
+ [111] = SOUTH,
+ [112] = SOUTH,
+ [113] = SOUTH,
+};
+
+/*
+ * Special pins - eMMC/SD related: [114..120], in total 7 special pins
+ */
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = pg_name, \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ }
+
+/* All SDC pins are in the NORTH tile */
+static const struct msm_special_pin_data sdm660_special_pins_data[] = {
+ SDC_QDSD_PINGROUP("sdc1_clk", NORTH + 0x9a000, 13, 6),
+ SDC_QDSD_PINGROUP("sdc1_cmd", NORTH + 0x9a000, 11, 3),
+ SDC_QDSD_PINGROUP("sdc1_data", NORTH + 0x9a000, 9, 0),
+ SDC_QDSD_PINGROUP("sdc2_clk", NORTH + 0x9b000, 14, 6),
+ SDC_QDSD_PINGROUP("sdc2_cmd", NORTH + 0x9b000, 11, 3),
+ SDC_QDSD_PINGROUP("sdc2_data", NORTH + 0x9b000, 9, 0),
+ SDC_QDSD_PINGROUP("sdc1_rclk", NORTH + 0x9a000, 15, 0),
+};
+
+static const char *sdm660_get_function_name(struct udevice *dev, unsigned int selector)
+{
+ return sdm660_pinctrl_functions[selector].name;
+}
+
+static const char *sdm660_get_pin_name(struct udevice *dev, unsigned int selector)
+{
+ static const char * const special_pins_names[] = {
+ "sdc1_clk", "sdc1_cmd", "sdc1_data",
+ "sdc2_clk", "sdc2_cmd", "sdc2_data",
+ "sdc1_rclk"
+ };
+
+ if (selector >= 114 && selector <= 120)
+ snprintf(pin_name, MAX_PIN_NAME_LEN, special_pins_names[selector - 114]);
+ else
+ snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
+
+ return pin_name;
+}
+
+static int sdm660_get_function_mux(__maybe_unused unsigned int pin, unsigned int selector)
+{
+ if (selector >= 0 && selector < ARRAY_SIZE(sdm660_pinctrl_functions))
+ return sdm660_pinctrl_functions[selector].val;
+ return -EINVAL;
+}
+
+struct msm_pinctrl_data sdm660_data = {
+ .pin_data = {
+ .pin_offsets = sdm660_pin_offsets,
+ .pin_count = ARRAY_SIZE(sdm660_pin_offsets) + ARRAY_SIZE(sdm660_special_pins_data),
+ .special_pins_start = 114,
+ .special_pins_data = sdm660_special_pins_data,
+ },
+ .functions_count = ARRAY_SIZE(sdm660_pinctrl_functions),
+ .get_function_name = sdm660_get_function_name,
+ .get_function_mux = sdm660_get_function_mux,
+ .get_pin_name = sdm660_get_pin_name,
+};
+
+static const struct udevice_id msm_pinctrl_ids[] = {
+ {
+ .compatible = "qcom,sdm630-pinctrl",
+ .data = (ulong)&sdm660_data
+ },
+ {
+ .compatible = "qcom,sdm660-pinctrl",
+ .data = (ulong)&sdm660_data
+ },
+ { /* Sentinel */ }
+};
+
+U_BOOT_DRIVER(pinctrl_ssdm660) = {
+ .name = "pinctrl_sdm660",
+ .id = UCLASS_NOP,
+ .of_match = msm_pinctrl_ids,
+ .ops = &msm_pinctrl_ops,
+ .bind = msm_pinctrl_bind,
+};
diff --git a/drivers/pinctrl/tegra/funcmux-tegra20.c b/drivers/pinctrl/tegra/funcmux-tegra20.c
index 951ae196161..f60d5aad3a4 100644
--- a/drivers/pinctrl/tegra/funcmux-tegra20.c
+++ b/drivers/pinctrl/tegra/funcmux-tegra20.c
@@ -62,8 +62,15 @@ int funcmux_select(enum periph_id id, int config)
pinmux_tristate_disable(PMUX_PINGRP_SDIO1);
bad_config = 0;
break;
+ case FUNCMUX_UART1_SDB_SDD:
+ pinmux_set_func(PMUX_PINGRP_SDB, PMUX_FUNC_UARTA);
+ pinmux_set_func(PMUX_PINGRP_SDD, PMUX_FUNC_UARTA);
+ pinmux_tristate_disable(PMUX_PINGRP_SDB);
+ pinmux_tristate_disable(PMUX_PINGRP_SDD);
+ bad_config = 0;
+ break;
}
- if (!bad_config) {
+ if (!bad_config && config != FUNCMUX_UART1_SDB_SDD) {
/*
* Tegra appears to boot with function UARTA pre-
* selected on mux group SDB. If two mux groups are
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
index b04be168bc8..bc02825ee1f 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
@@ -14,7 +14,7 @@
static void tegra_pinctrl_set_drive(struct udevice *config, int drvcnt)
{
struct pmux_drvgrp_config *drive_group;
- int i, ret, pad_id;
+ int i, ret, pad_id, count = 0;
const char **pads;
drive_group = kmalloc_array(drvcnt, sizeof(*drive_group), GFP_KERNEL);
@@ -46,21 +46,32 @@ static void tegra_pinctrl_set_drive(struct udevice *config, int drvcnt)
goto exit;
}
+ /*
+ * i goes through all drive instances defined, while
+ * count is increased only if a valid configuration is found
+ */
for (i = 0; i < drvcnt; i++) {
for (pad_id = 0; pad_id < PMUX_DRVGRP_COUNT; pad_id++)
if (tegra_pinctrl_to_drvgrp[pad_id])
if (!strcmp(pads[i], tegra_pinctrl_to_drvgrp[pad_id])) {
- drive_group[i].drvgrp = pad_id;
+ drive_group[count].drvgrp = pad_id;
break;
}
- debug("%s drvmap: %d, %d, %d, %d, %d\n", pads[i],
- drive_group[i].drvgrp, drive_group[i].slwf,
- drive_group[i].slwr, drive_group[i].drvup,
- drive_group[i].drvdn);
+ if (pad_id == PMUX_DRVGRP_COUNT) {
+ log_debug("%s: drive %s is not valid\n", __func__, pads[i]);
+ continue;
+ }
+
+ log_debug("%s(%d) drvmap: %d, %d, %d, %d, %d\n", pads[count], count,
+ drive_group[count].drvgrp, drive_group[count].slwf,
+ drive_group[count].slwr, drive_group[count].drvup,
+ drive_group[count].drvdn);
+
+ count++;
}
- pinmux_config_drvgrp_table(drive_group, drvcnt);
+ pinmux_config_drvgrp_table(drive_group, count);
free(pads);
exit:
@@ -71,7 +82,7 @@ exit:
static void tegra_pinctrl_set_mipipad(struct udevice *config, int padcnt)
{
struct pmux_mipipadctrlgrp_config *mipipad_group;
- int i, ret, pad_id;
+ int i, ret, pad_id, count = 0;
const char *function;
const char **pads;
@@ -89,6 +100,11 @@ static void tegra_pinctrl_set_mipipad(struct udevice *config, int padcnt)
if (!strcmp(function, tegra_pinctrl_to_func[i]))
break;
+ if (!function || i == PMUX_FUNC_COUNT) {
+ log_debug("%s: pin function is not defined or is not valid\n", __func__);
+ goto exit;
+ }
+
mipipad_group[0].func = i;
for (i = 1; i < padcnt; i++)
@@ -100,16 +116,27 @@ static void tegra_pinctrl_set_mipipad(struct udevice *config, int padcnt)
goto exit;
}
+ /*
+ * i goes through all pin instances defined, while
+ * count is increased only if a valid configuration is found
+ */
for (i = 0; i < padcnt; i++) {
for (pad_id = 0; pad_id < PMUX_MIPIPADCTRLGRP_COUNT; pad_id++)
if (tegra_pinctrl_to_mipipadgrp[pad_id])
if (!strcmp(pads[i], tegra_pinctrl_to_mipipadgrp[pad_id])) {
- mipipad_group[i].grp = pad_id;
+ mipipad_group[count].grp = pad_id;
break;
}
+
+ if (pad_id == PMUX_MIPIPADCTRLGRP_COUNT) {
+ log_debug("%s: drive %s is not valid\n", __func__, pads[i]);
+ continue;
+ }
+
+ count++;
}
- pinmux_config_mipipadctrlgrp_table(mipipad_group, padcnt);
+ pinmux_config_mipipadctrlgrp_table(mipipad_group, count);
free(pads);
exit:
@@ -122,7 +149,7 @@ static void tegra_pinctrl_set_mipipad(struct udevice *config, int padcnt) { }
static void tegra_pinctrl_set_pin(struct udevice *config, int pincnt)
{
struct pmux_pingrp_config *pinmux_group;
- int i, ret, pin_id;
+ int i, ret, pin_id, count = 0;
const char *function;
const char **pins;
@@ -140,6 +167,11 @@ static void tegra_pinctrl_set_pin(struct udevice *config, int pincnt)
if (!strcmp(function, tegra_pinctrl_to_func[i]))
break;
+ if (!function || i == PMUX_FUNC_COUNT) {
+ log_debug("%s: pin function is not defined or is not valid\n", __func__);
+ goto exit;
+ }
+
pinmux_group[0].func = i;
pinmux_group[0].pull = dev_read_u32_default(config, "nvidia,pull", PMUX_PULL_NORMAL);
@@ -178,20 +210,31 @@ static void tegra_pinctrl_set_pin(struct udevice *config, int pincnt)
goto exit;
}
+ /*
+ * i goes through all pin instances defined, while
+ * count is increased only if a valid configuration is found
+ */
for (i = 0; i < pincnt; i++) {
for (pin_id = 0; pin_id < PMUX_PINGRP_COUNT; pin_id++)
if (tegra_pinctrl_to_pingrp[pin_id])
if (!strcmp(pins[i], tegra_pinctrl_to_pingrp[pin_id])) {
- pinmux_group[i].pingrp = pin_id;
+ pinmux_group[count].pingrp = pin_id;
break;
}
- debug("%s pinmap: %d, %d, %d, %d\n", pins[i],
- pinmux_group[i].pingrp, pinmux_group[i].func,
- pinmux_group[i].pull, pinmux_group[i].tristate);
+ if (pin_id == PMUX_PINGRP_COUNT) {
+ log_debug("%s: pin %s is not valid\n", __func__, pins[i]);
+ continue;
+ }
+
+ log_debug("%s(%d) pinmap: %d, %d, %d, %d\n", pins[count], count,
+ pinmux_group[count].pingrp, pinmux_group[count].func,
+ pinmux_group[count].pull, pinmux_group[count].tristate);
+
+ count++;
}
- pinmux_config_pingrp_table(pinmux_group, pincnt);
+ pinmux_config_pingrp_table(pinmux_group, count);
free(pins);
exit:
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra20.c b/drivers/pinctrl/tegra/pinctrl-tegra20.c
index d59b3ec7b5d..c32d590a7e0 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra20.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra20.c
@@ -37,6 +37,11 @@ static void tegra_pinctrl_set_pin(struct udevice *config)
if (!strcmp(pins[i], tegra_pinctrl_to_pingrp[pin_id]))
break;
+ if (pin_id == PMUX_PINGRP_COUNT) {
+ log_debug("%s: %s(%d) is not valid\n", __func__, pins[i], pin_id);
+ continue;
+ }
+
if (pull >= 0)
pinmux_set_pullupdown(pin_id, pull);
@@ -58,13 +63,16 @@ static void tegra_pinctrl_set_func(struct udevice *config)
const char **pins;
function = dev_read_string(config, "nvidia,function");
- if (function)
+ if (function) {
for (i = 0; i < PMUX_FUNC_COUNT; i++)
if (tegra_pinctrl_to_func[i])
if (!strcmp(function, tegra_pinctrl_to_func[i]))
break;
- func_id = i;
+ func_id = i;
+ } else {
+ func_id = PMUX_FUNC_COUNT;
+ }
count = dev_read_string_list(config, "nvidia,pins", &pins);
if (count < 0) {
@@ -78,6 +86,12 @@ static void tegra_pinctrl_set_func(struct udevice *config)
if (!strcmp(pins[i], tegra_pinctrl_to_pingrp[pin_id]))
break;
+ if (func_id == PMUX_FUNC_COUNT || pin_id == PMUX_PINGRP_COUNT) {
+ log_debug("%s: pin %s(%d) or function %s(%d) is not valid\n",
+ __func__, pins[i], pin_id, function, func_id);
+ continue;
+ }
+
debug("%s(%d) muxed to %s(%d)\n", pins[i], pin_id, function, func_id);
pinmux_set_func(pin_id, func_id);
diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig
index bd82d2f7044..5f5218bd8b5 100644
--- a/drivers/power/domain/Kconfig
+++ b/drivers/power/domain/Kconfig
@@ -47,6 +47,13 @@ config IMX8MP_HSIOMIX_BLKCTRL
help
Enable support for manipulating NXP i.MX8MP on-SoC HSIOMIX block controller.
+config IMX8MP_MEDIAMIX_BLKCTRL
+ bool "Enable i.MX8MP MEDIAMIX domain driver"
+ depends on POWER_DOMAIN && IMX8MP
+ select CLK
+ help
+ Enable support for manipulating NXP i.MX8MP on-SoC MEDIAMIX block controller.
+
config MTK_POWER_DOMAIN
bool "Enable the MediaTek power domain driver"
depends on POWER_DOMAIN && ARCH_MEDIATEK
diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile
index 110646c503a..4d20c97d26c 100644
--- a/drivers/power/domain/Makefile
+++ b/drivers/power/domain/Makefile
@@ -3,12 +3,13 @@
# Copyright (c) 2016, NVIDIA CORPORATION.
#
-obj-$(CONFIG_$(XPL_)POWER_DOMAIN) += power-domain-uclass.o
+obj-$(CONFIG_$(PHASE_)POWER_DOMAIN) += power-domain-uclass.o
obj-$(CONFIG_APPLE_PMGR_POWER_DOMAIN) += apple-pmgr.o
obj-$(CONFIG_BCM6328_POWER_DOMAIN) += bcm6328-power-domain.o
obj-$(CONFIG_IMX8_POWER_DOMAIN) += imx8-power-domain-legacy.o imx8-power-domain.o
obj-$(CONFIG_IMX8M_POWER_DOMAIN) += imx8m-power-domain.o
obj-$(CONFIG_IMX8MP_HSIOMIX_BLKCTRL) += imx8mp-hsiomix.o
+obj-$(CONFIG_IMX8MP_MEDIAMIX_BLKCTRL) += imx8mp-mediamix.o
obj-$(CONFIG_MTK_POWER_DOMAIN) += mtk-power-domain.o
obj-$(CONFIG_MESON_GX_VPU_POWER_DOMAIN) += meson-gx-pwrc-vpu.o
obj-$(CONFIG_MESON_EE_POWER_DOMAIN) += meson-ee-pwrc.o
diff --git a/drivers/power/domain/imx8m-power-domain.c b/drivers/power/domain/imx8m-power-domain.c
index c22fbe60675..e54ba5d9a54 100644
--- a/drivers/power/domain/imx8m-power-domain.c
+++ b/drivers/power/domain/imx8m-power-domain.c
@@ -40,6 +40,7 @@ DECLARE_GLOBAL_DATA_PTR;
#define IMX8MN_MIPI_A53_DOMAIN BIT(2)
#define IMX8MP_HSIOMIX_A53_DOMAIN BIT(19)
+#define IMX8MP_MEDIAMIX_A53_DOMAIN BIT(12)
#define IMX8MP_USB2_PHY_A53_DOMAIN BIT(5)
#define IMX8MP_USB1_PHY_A53_DOMAIN BIT(4)
#define IMX8MP_PCIE_PHY_A53_DOMAIN BIT(3)
@@ -63,6 +64,7 @@ DECLARE_GLOBAL_DATA_PTR;
#define IMX8MN_MIPI_SW_Pxx_REQ BIT(0)
#define IMX8MP_HSIOMIX_Pxx_REQ BIT(17)
+#define IMX8MP_MEDIAMIX_Pxx_REQ BIT(10)
#define IMX8MP_USB2_PHY_Pxx_REQ BIT(3)
#define IMX8MP_USB1_PHY_Pxx_REQ BIT(2)
#define IMX8MP_PCIE_PHY_SW_Pxx_REQ BIT(1)
@@ -81,6 +83,9 @@ DECLARE_GLOBAL_DATA_PTR;
#define IMX8MP_HSIOMIX_PWRDNACKN BIT(28)
#define IMX8MP_HSIOMIX_PWRDNREQN BIT(12)
+#define IMX8MP_MEDIAMIX_PWRDNACKN BIT(30)
+#define IMX8MP_MEDIAMIX_PWRDNREQN BIT(14)
+
/*
* The PGC offset values in Reference Manual
* (Rev. 1, 01/2018 and the older ones) GPC chapter's
@@ -101,6 +106,7 @@ DECLARE_GLOBAL_DATA_PTR;
#define IMX8MP_PGC_PCIE 13
#define IMX8MP_PGC_USB1 14
#define IMX8MP_PGC_USB2 15
+#define IMX8MP_PGC_MEDIAMIX 22
#define IMX8MP_PGC_HSIOMIX 29
#define GPC_PGC_CTRL(n) (0x800 + (n) * 0x40)
@@ -303,6 +309,17 @@ static const struct imx_pgc_domain imx8mp_pgc_domains[] = {
.pgc = BIT(IMX8MP_PGC_HSIOMIX),
.keep_clocks = true,
},
+
+ [IMX8MP_POWER_DOMAIN_MEDIAMIX] = {
+ .bits = {
+ .pxx = IMX8MP_MEDIAMIX_Pxx_REQ,
+ .map = IMX8MP_MEDIAMIX_A53_DOMAIN,
+ .hskreq = IMX8MP_MEDIAMIX_PWRDNREQN,
+ .hskack = IMX8MP_MEDIAMIX_PWRDNACKN,
+ },
+ .pgc = BIT(IMX8MP_PGC_MEDIAMIX),
+ .keep_clocks = true,
+ },
};
static const struct imx_pgc_regs imx8mp_pgc_regs = {
diff --git a/drivers/power/domain/imx8mp-mediamix.c b/drivers/power/domain/imx8mp-mediamix.c
new file mode 100644
index 00000000000..78c32ca3d3a
--- /dev/null
+++ b/drivers/power/domain/imx8mp-mediamix.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * i.MX8 MEDIAMIX control block driver
+ * Copyright (C) 2024 Miquel Raynal <miquel.raynal@bootlin.com>
+ * Inspired from Marek Vasut <marex@denx.de> work on the hsiomix driver.
+ */
+
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <power-domain-uclass.h>
+#include <linux/delay.h>
+
+#include <dt-bindings/power/imx8mp-power.h>
+
+#define BLK_SFT_RSTN 0x0
+#define BLK_CLK_EN 0x4
+
+struct imx8mp_mediamix_priv {
+ void __iomem *base;
+ struct clk clk_apb;
+ struct clk clk_axi;
+ struct clk clk_disp2;
+ struct power_domain pd_bus;
+ struct power_domain pd_lcdif2;
+};
+
+static int imx8mp_mediamix_on(struct power_domain *power_domain)
+{
+ struct udevice *dev = power_domain->dev;
+ struct imx8mp_mediamix_priv *priv = dev_get_priv(dev);
+ struct power_domain *domain;
+ struct clk *clk;
+ u32 reset;
+ int ret;
+
+ switch (power_domain->id) {
+ case IMX8MP_MEDIABLK_PD_LCDIF_2:
+ domain = &priv->pd_lcdif2;
+ clk = &priv->clk_disp2;
+ reset = BIT(11) | BIT(12) | BIT(24);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Make sure bus domain is awake */
+ ret = power_domain_on(&priv->pd_bus);
+ if (ret)
+ return ret;
+
+ /* Put devices into reset */
+ clrbits_le32(priv->base + BLK_SFT_RSTN, reset);
+
+ /* Enable upstream clocks */
+ ret = clk_enable(&priv->clk_apb);
+ if (ret)
+ goto dis_bus_pd;
+
+ ret = clk_enable(&priv->clk_axi);
+ if (ret)
+ goto dis_apb_clk;
+
+ /* Enable blk-ctrl clock to allow reset to propagate */
+ ret = clk_enable(clk);
+ if (ret)
+ goto dis_axi_clk;
+ setbits_le32(priv->base + BLK_CLK_EN, reset);
+
+ /* Power up upstream GPC domain */
+ ret = power_domain_on(domain);
+ if (ret)
+ goto dis_lcdif_clk;
+
+ /* Wait for reset to propagate */
+ udelay(5);
+
+ /* Release reset */
+ setbits_le32(priv->base + BLK_SFT_RSTN, reset);
+
+ return 0;
+
+dis_lcdif_clk:
+ clk_disable(clk);
+dis_axi_clk:
+ clk_disable(&priv->clk_axi);
+dis_apb_clk:
+ clk_disable(&priv->clk_apb);
+dis_bus_pd:
+ power_domain_off(&priv->pd_bus);
+
+ return ret;
+}
+
+static int imx8mp_mediamix_off(struct power_domain *power_domain)
+{
+ struct udevice *dev = power_domain->dev;
+ struct imx8mp_mediamix_priv *priv = dev_get_priv(dev);
+ struct power_domain *domain;
+ struct clk *clk;
+ u32 reset;
+
+ switch (power_domain->id) {
+ case IMX8MP_MEDIABLK_PD_LCDIF_2:
+ domain = &priv->pd_lcdif2;
+ clk = &priv->clk_disp2;
+ reset = BIT(11) | BIT(12) | BIT(24);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Put devices into reset and disable clocks */
+ clrbits_le32(priv->base + BLK_SFT_RSTN, reset);
+ clrbits_le32(priv->base + BLK_CLK_EN, reset);
+
+ /* Power down upstream GPC domain */
+ power_domain_off(domain);
+
+ clk_disable(clk);
+ clk_disable(&priv->clk_axi);
+ clk_disable(&priv->clk_apb);
+
+ /* Allow bus domain to suspend */
+ power_domain_off(&priv->pd_bus);
+
+ return 0;
+}
+
+static int imx8mp_mediamix_of_xlate(struct power_domain *power_domain,
+ struct ofnode_phandle_args *args)
+{
+ power_domain->id = args->args[0];
+
+ return 0;
+}
+
+static int imx8mp_mediamix_bind(struct udevice *dev)
+{
+ /* Bind child lcdif */
+ return dm_scan_fdt_dev(dev);
+}
+
+static int imx8mp_mediamix_probe(struct udevice *dev)
+{
+ struct imx8mp_mediamix_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->base = dev_read_addr_ptr(dev);
+
+ ret = clk_get_by_name(dev, "apb", &priv->clk_apb);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_get_by_name(dev, "axi", &priv->clk_axi);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_get_by_name(dev, "disp2", &priv->clk_disp2);
+ if (ret < 0)
+ return ret;
+
+ ret = power_domain_get_by_name(dev, &priv->pd_bus, "bus");
+ if (ret < 0)
+ return ret;
+
+ ret = power_domain_get_by_name(dev, &priv->pd_lcdif2, "lcdif2");
+ if (ret < 0)
+ goto free_bus_pd;
+
+ return 0;
+
+free_bus_pd:
+ power_domain_free(&priv->pd_bus);
+ return ret;
+}
+
+static int imx8mp_mediamix_remove(struct udevice *dev)
+{
+ struct imx8mp_mediamix_priv *priv = dev_get_priv(dev);
+
+ power_domain_free(&priv->pd_lcdif2);
+ power_domain_free(&priv->pd_bus);
+
+ return 0;
+}
+
+static const struct udevice_id imx8mp_mediamix_ids[] = {
+ { .compatible = "fsl,imx8mp-media-blk-ctrl" },
+ { }
+};
+
+struct power_domain_ops imx8mp_mediamix_ops = {
+ .on = imx8mp_mediamix_on,
+ .off = imx8mp_mediamix_off,
+ .of_xlate = imx8mp_mediamix_of_xlate,
+};
+
+U_BOOT_DRIVER(imx8mp_mediamix) = {
+ .name = "imx8mp_mediamix",
+ .id = UCLASS_POWER_DOMAIN,
+ .of_match = imx8mp_mediamix_ids,
+ .bind = imx8mp_mediamix_bind,
+ .probe = imx8mp_mediamix_probe,
+ .remove = imx8mp_mediamix_remove,
+ .priv_auto = sizeof(struct imx8mp_mediamix_priv),
+ .ops = &imx8mp_mediamix_ops,
+};
diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig
index bbcbcee4c35..5a61cd45b8c 100644
--- a/drivers/power/pmic/Kconfig
+++ b/drivers/power/pmic/Kconfig
@@ -295,6 +295,16 @@ config DM_PMIC_SANDBOX
Driver binding info: doc/device-tree-bindings/pmic/sandbox.txt
+config DM_PMIC_CPCAP
+ bool "Enable Driver Model for Motorola CPCAP"
+ help
+ The CPCAP is a Motorola/ST-Ericsson creation, a multifunctional IC
+ whose main purpose is power control. It was used in a wide variety of
+ Motorola products, both Tegra and OMAP based. The most notable devices
+ using this PMIC are the Motorola Droid 4, Atrix 4G, and Droid X2.
+ Unlike most PMICs, this one is not I2C based; it uses the SPI bus. The
+ core driver provides both read and write access to the device registers.
+
config PMIC_S5M8767
bool "Enable Driver Model for the Samsung S5M8767 PMIC"
---help---
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
index bc138f563ff..2210b1a64ae 100644
--- a/drivers/power/pmic/Makefile
+++ b/drivers/power/pmic/Makefile
@@ -4,41 +4,42 @@
# Lukasz Majewski <l.majewski@samsung.com>
obj-$(CONFIG_$(PHASE_)DM_PMIC) += pmic-uclass.o
-obj-$(CONFIG_$(XPL_)DM_PMIC_FAN53555) += fan53555.o
-obj-$(CONFIG_$(XPL_)DM_PMIC_DA9063) += da9063.o
-obj-$(CONFIG_$(XPL_)DM_PMIC_MAX77663) += max77663.o
+obj-$(CONFIG_$(PHASE_)DM_PMIC_FAN53555) += fan53555.o
+obj-$(CONFIG_$(PHASE_)DM_PMIC_DA9063) += da9063.o
+obj-$(CONFIG_$(PHASE_)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
-obj-$(CONFIG_$(XPL_)DM_PMIC_BD71837) += bd71837.o
-obj-$(CONFIG_$(XPL_)DM_PMIC_MP5416) += mp5416.o
-obj-$(CONFIG_$(XPL_)DM_PMIC_PFUZE100) += pfuze100.o
-obj-$(CONFIG_$(XPL_)DM_PMIC_PCA9450) += pca9450.o
+obj-$(CONFIG_$(PHASE_)DM_PMIC_BD71837) += bd71837.o
+obj-$(CONFIG_$(PHASE_)DM_PMIC_MP5416) += mp5416.o
+obj-$(CONFIG_$(PHASE_)DM_PMIC_PFUZE100) += pfuze100.o
+obj-$(CONFIG_$(PHASE_)DM_PMIC_PCA9450) += pca9450.o
obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o
obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o
obj-$(CONFIG_PMIC_AB8500) += ab8500.o
obj-$(CONFIG_PMIC_ACT8846) += act8846.o
obj-$(CONFIG_PMIC_AS3722) += as3722.o as3722_gpio.o
-obj-$(CONFIG_$(XPL_)PMIC_AXP) += axp.o
+obj-$(CONFIG_$(PHASE_)PMIC_AXP) += axp.o
obj-$(CONFIG_PMIC_MAX8997) += max8997.o
obj-$(CONFIG_PMIC_QCOM) += pmic_qcom.o
obj-$(CONFIG_$(PHASE_)PMIC_RK8XX) += rk8xx.o
-obj-$(CONFIG_$(XPL_)PMIC_RN5T567) += rn5t567.o
+obj-$(CONFIG_$(PHASE_)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_$(XPL_)DM_PMIC_TPS80031) += tps80031.o
-obj-$(CONFIG_$(XPL_)PMIC_PALMAS) += palmas.o
-obj-$(CONFIG_$(XPL_)PMIC_LP873X) += lp873x.o
-obj-$(CONFIG_$(XPL_)PMIC_LP87565) += lp87565.o
+obj-$(CONFIG_$(PHASE_)DM_PMIC_TPS80031) += tps80031.o
+obj-$(CONFIG_$(PHASE_)PMIC_PALMAS) += palmas.o
+obj-$(CONFIG_$(PHASE_)PMIC_LP873X) += lp873x.o
+obj-$(CONFIG_$(PHASE_)PMIC_LP87565) += lp87565.o
obj-$(CONFIG_PMIC_STPMIC1) += stpmic1.o
obj-$(CONFIG_PMIC_TPS65217) += pmic_tps65217.o
obj-$(CONFIG_PMIC_TPS65219) += tps65219.o
obj-$(CONFIG_PMIC_TPS65941) += tps65941.o
obj-$(CONFIG_PMIC_RAA215300) += raa215300.o
obj-$(CONFIG_POWER_TPS65218) += pmic_tps65218.o
+obj-$(CONFIG_$(PHASE_)DM_PMIC_CPCAP) += cpcap.o
-ifeq ($(CONFIG_$(XPL_)POWER_LEGACY),y)
+ifeq ($(CONFIG_$(PHASE_)POWER_LEGACY),y)
obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o
obj-$(CONFIG_POWER_PCA9450) += pmic_pca9450.o
obj-$(CONFIG_POWER_PFUZE100) += pmic_pfuze100.o
@@ -47,5 +48,5 @@ obj-$(CONFIG_POWER_HI6553) += pmic_hi6553.o
obj-$(CONFIG_POWER_MC34VR500) += pmic_mc34vr500.o
endif
-obj-$(CONFIG_$(XPL_)POWER_TPS62362) += pmic_tps62362.o
+obj-$(CONFIG_$(PHASE_)POWER_TPS62362) += pmic_tps62362.o
obj-$(CONFIG_SPL_POWER_TPS65910) += pmic_tps65910.o
diff --git a/drivers/power/pmic/cpcap.c b/drivers/power/pmic/cpcap.c
new file mode 100644
index 00000000000..f2076afff43
--- /dev/null
+++ b/drivers/power/pmic/cpcap.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <dm/lists.h>
+#include <log.h>
+#include <power/pmic.h>
+#include <power/cpcap.h>
+#include <spi.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+static const struct pmic_child_info pmic_children_info[] = {
+ { .prefix = "sw", .driver = CPCAP_SW_DRIVER },
+ { .prefix = "v", .driver = CPCAP_LDO_DRIVER },
+ { },
+};
+
+static int cpcap_write(struct udevice *dev, uint reg, const uint8_t *buff, int len)
+{
+ u8 buf[4];
+ u16 data = *(u16 *)buff;
+ int ret;
+
+ buf[0] = ((reg >> 8) & 0xff) | 0x80;
+ buf[1] = reg & 0xff;
+ buf[2] = data >> 8 & 0xff;
+ buf[3] = data & 0xff;
+
+ ret = dm_spi_xfer(dev, 32, buf, NULL, SPI_XFER_ONCE);
+
+ log_debug("%s: reg 0x%x, data 0x%04x, ret %d\n", __func__, reg, data, ret);
+
+ return ret;
+}
+
+static int cpcap_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ u8 buf[4];
+ int ret;
+
+ buf[0] = (reg >> 8) & 0xff;
+ buf[1] = reg & 0xff;
+ buf[2] = 0;
+ buf[3] = 0;
+
+ ret = dm_spi_xfer(dev, 32, buf, buf, SPI_XFER_ONCE);
+ *buff = (buf[2] << 8) | buf[3];
+
+ log_debug("%s: reg 0x%x, data 0x%04x, ret %d\n", __func__, reg, *buff, ret);
+ return ret;
+}
+
+static int cpcap_bind(struct udevice *dev)
+{
+ ofnode regulators_node;
+ int children;
+
+ /* Regulator device node of PMIC */
+ regulators_node = dev_read_subnode(dev, "regulator");
+ if (!ofnode_valid(regulators_node)) {
+ log_err("%s regulator subnode not found!\n", dev->name);
+ return -ENXIO;
+ }
+
+ /* Actual regulators container */
+ regulators_node = ofnode_find_subnode(regulators_node, "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);
+
+ return dm_scan_fdt_dev(dev);
+}
+
+static int cpcap_probe(struct udevice *dev)
+{
+ struct spi_slave *slave = dev_get_parent_priv(dev);
+ int ret;
+
+ ret = spi_claim_bus(slave);
+ if (ret) {
+ log_err("SPI bus allocation failed (%d)\n", ret);
+ return ret;
+ }
+
+ u16 id = pmic_reg_read(dev, CPCAP_REG_VERSC1);
+
+ u16 ven = (id >> 6) & 0x7;
+ u16 rev = ((id >> 3) & 0x7) | ((id << 3) & 0x38);
+
+ log_debug("%s: vendor %s rev: %i.%i (%x)\n", __func__,
+ ven == CPCAP_VENDOR_ST ? "ST" : "TI",
+ CPCAP_REVISION_MAJOR(rev), CPCAP_REVISION_MINOR(rev),
+ rev);
+ return 0;
+}
+
+static struct dm_pmic_ops cpcap_ops = {
+ .read = cpcap_read,
+ .write = cpcap_write,
+};
+
+static const struct udevice_id cpcap_ids[] = {
+ { .compatible = "motorola,cpcap" },
+ { .compatible = "st,6556002" },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_cpcap) = {
+ .name = "cpcap_pmic",
+ .id = UCLASS_PMIC,
+ .of_match = cpcap_ids,
+ .bind = cpcap_bind,
+ .probe = cpcap_probe,
+ .ops = &cpcap_ops,
+};
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
index 8f102a92c23..bec2d2d7d49 100644
--- a/drivers/power/regulator/Kconfig
+++ b/drivers/power/regulator/Kconfig
@@ -224,6 +224,13 @@ config DM_REGULATOR_QCOM_RPMH
implements get/set api for a limited set of regulators used
by u-boot.
+config DM_REGULATOR_QCOM_USB_VBUS
+ bool "Enable driver model for Qualcomm USB vbus regulator"
+ depends on DM_REGULATOR
+ ---help---
+ Enable support for the Qualcomm USB Vbus regulator. The driver
+ implements get/set api for the regulator to be used by u-boot.
+
config SPL_DM_REGULATOR_GPIO
bool "Enable Driver Model for GPIO REGULATOR in SPL"
depends on DM_REGULATOR_GPIO && SPL_GPIO
@@ -486,3 +493,12 @@ config REGULATOR_RZG2L_USBPHY
Enable this option to support controlling the VBUS supply in
the USB PHY peripheral of the Renesas RZ/G2L SoC. This option
is required in order to use the USB OTG port.
+
+config DM_REGULATOR_CPCAP
+ bool "Enable driver for CPCAP PMIC regulators"
+ depends on DM_REGULATOR && DM_PMIC_CPCAP
+ ---help---
+ Enable implementation of driver-model regulator uclass features for
+ REGULATOR CPCAP. The driver supports both DC-to-DC Step-Down Switching
+ (SW) Regulators and Low-Dropout Linear (LDO) Regulators found in CPCAP
+ PMIC and implements get/set api for voltage and state.
diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile
index 4382d4b3ab9..99affa235f3 100644
--- a/drivers/power/regulator/Makefile
+++ b/drivers/power/regulator/Makefile
@@ -4,42 +4,44 @@
# Przemyslaw Marczak <p.marczak@samsung.com>
#
-obj-$(CONFIG_$(XPL_)DM_REGULATOR) += regulator-uclass.o
+obj-$(CONFIG_$(PHASE_)DM_REGULATOR) += regulator-uclass.o
obj-$(CONFIG_REGULATOR_ACT8846) += act8846.o
obj-$(CONFIG_REGULATOR_AS3722) += as3722_regulator.o
-obj-$(CONFIG_$(XPL_)REGULATOR_AXP) += axp_regulator.o
-obj-$(CONFIG_$(XPL_)REGULATOR_AXP_USB_POWER) += axp_usb_power.o
-obj-$(CONFIG_$(XPL_)DM_REGULATOR_DA9063) += da9063.o
-obj-$(CONFIG_$(XPL_)DM_REGULATOR_MAX77663) += max77663_regulator.o
+obj-$(CONFIG_$(PHASE_)REGULATOR_AXP) += axp_regulator.o
+obj-$(CONFIG_$(PHASE_)REGULATOR_AXP_USB_POWER) += axp_usb_power.o
+obj-$(CONFIG_$(PHASE_)DM_REGULATOR_DA9063) += da9063.o
+obj-$(CONFIG_$(PHASE_)DM_REGULATOR_MAX77663) += max77663_regulator.o
obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o
obj-$(CONFIG_DM_REGULATOR_NPCM8XX) += npcm8xx_regulator.o
-obj-$(CONFIG_$(XPL_)DM_PMIC_PFUZE100) += pfuze100.o
-obj-$(CONFIG_$(XPL_)DM_REGULATOR_BD71837) += bd71837.o
-obj-$(CONFIG_$(XPL_)DM_REGULATOR_PCA9450) += pca9450.o
-obj-$(CONFIG_$(XPL_)REGULATOR_PWM) += pwm_regulator.o
-obj-$(CONFIG_$(XPL_)DM_REGULATOR_FAN53555) += fan53555.o
-obj-$(CONFIG_$(XPL_)DM_REGULATOR_COMMON) += regulator_common.o
-obj-$(CONFIG_$(XPL_)DM_REGULATOR_FIXED) += fixed.o
-obj-$(CONFIG_$(XPL_)DM_REGULATOR_GPIO) += gpio-regulator.o
+obj-$(CONFIG_$(PHASE_)DM_PMIC_PFUZE100) += pfuze100.o
+obj-$(CONFIG_$(PHASE_)DM_REGULATOR_BD71837) += bd71837.o
+obj-$(CONFIG_$(PHASE_)DM_REGULATOR_PCA9450) += pca9450.o
+obj-$(CONFIG_$(PHASE_)REGULATOR_PWM) += pwm_regulator.o
+obj-$(CONFIG_$(PHASE_)DM_REGULATOR_FAN53555) += fan53555.o
+obj-$(CONFIG_$(PHASE_)DM_REGULATOR_COMMON) += regulator_common.o
+obj-$(CONFIG_$(PHASE_)DM_REGULATOR_FIXED) += fixed.o
+obj-$(CONFIG_$(PHASE_)DM_REGULATOR_GPIO) += gpio-regulator.o
obj-$(CONFIG_DM_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o
+obj-$(CONFIG_DM_REGULATOR_QCOM_USB_VBUS) += qcom_usb_vbus_regulator.o
obj-$(CONFIG_$(PHASE_)REGULATOR_RK8XX) += rk8xx.o
obj-$(CONFIG_DM_REGULATOR_S2MPS11) += s2mps11_regulator.o
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o
obj-$(CONFIG_REGULATOR_TPS65090) += tps65090_regulator.o
-obj-$(CONFIG_$(XPL_)DM_REGULATOR_PALMAS) += palmas_regulator.o
-obj-$(CONFIG_$(XPL_)DM_REGULATOR_PBIAS) += pbias_regulator.o
-obj-$(CONFIG_$(XPL_)DM_REGULATOR_LP873X) += lp873x_regulator.o
-obj-$(CONFIG_$(XPL_)DM_REGULATOR_LP87565) += lp87565_regulator.o
-obj-$(CONFIG_$(XPL_)DM_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
+obj-$(CONFIG_$(PHASE_)DM_REGULATOR_PALMAS) += palmas_regulator.o
+obj-$(CONFIG_$(PHASE_)DM_REGULATOR_PBIAS) += pbias_regulator.o
+obj-$(CONFIG_$(PHASE_)DM_REGULATOR_LP873X) += lp873x_regulator.o
+obj-$(CONFIG_$(PHASE_)DM_REGULATOR_LP87565) += lp87565_regulator.o
+obj-$(CONFIG_$(PHASE_)DM_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
obj-$(CONFIG_DM_REGULATOR_TPS65910) += tps65910_regulator.o
-obj-$(CONFIG_$(XPL_)DM_REGULATOR_TPS65911) += tps65911_regulator.o
+obj-$(CONFIG_$(PHASE_)DM_REGULATOR_TPS65911) += tps65911_regulator.o
obj-$(CONFIG_DM_REGULATOR_TPS62360) += tps62360_regulator.o
-obj-$(CONFIG_$(XPL_)DM_REGULATOR_TPS6287X) += tps6287x_regulator.o
-obj-$(CONFIG_$(XPL_)DM_REGULATOR_TPS80031) += tps80031_regulator.o
-obj-$(CONFIG_$(XPL_)DM_REGULATOR_STPMIC1) += stpmic1.o
+obj-$(CONFIG_$(PHASE_)DM_REGULATOR_TPS6287X) += tps6287x_regulator.o
+obj-$(CONFIG_$(PHASE_)DM_REGULATOR_TPS80031) += tps80031_regulator.o
+obj-$(CONFIG_$(PHASE_)DM_REGULATOR_STPMIC1) += stpmic1.o
obj-$(CONFIG_DM_REGULATOR_TPS65941) += tps65941_regulator.o
obj-$(CONFIG_DM_REGULATOR_SCMI) += scmi_regulator.o
-obj-$(CONFIG_$(XPL_)DM_REGULATOR_ANATOP) += anatop_regulator.o
+obj-$(CONFIG_$(PHASE_)DM_REGULATOR_ANATOP) += anatop_regulator.o
obj-$(CONFIG_DM_REGULATOR_TPS65219) += tps65219_regulator.o
obj-$(CONFIG_REGULATOR_RZG2L_USBPHY) += rzg2l-usbphy-regulator.o
+obj-$(CONFIG_$(PHASE_)DM_REGULATOR_CPCAP) += cpcap_regulator.o
diff --git a/drivers/power/regulator/cpcap_regulator.c b/drivers/power/regulator/cpcap_regulator.c
new file mode 100644
index 00000000000..04cd6651374
--- /dev/null
+++ b/drivers/power/regulator/cpcap_regulator.c
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright(C) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/cpcap.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+/* CPCAP_REG_ASSIGN2 bits - Resource Assignment 2 */
+#define CPCAP_BIT_VSDIO_SEL BIT(15)
+#define CPCAP_BIT_VDIG_SEL BIT(14)
+#define CPCAP_BIT_VCAM_SEL BIT(13)
+#define CPCAP_BIT_SW6_SEL BIT(12)
+#define CPCAP_BIT_SW5_SEL BIT(11)
+#define CPCAP_BIT_SW4_SEL BIT(10)
+#define CPCAP_BIT_SW3_SEL BIT(9)
+#define CPCAP_BIT_SW2_SEL BIT(8)
+#define CPCAP_BIT_SW1_SEL BIT(7)
+
+/* CPCAP_REG_ASSIGN3 bits - Resource Assignment 3 */
+#define CPCAP_BIT_VUSBINT2_SEL BIT(15)
+#define CPCAP_BIT_VUSBINT1_SEL BIT(14)
+#define CPCAP_BIT_VVIB_SEL BIT(13)
+#define CPCAP_BIT_VWLAN1_SEL BIT(12)
+#define CPCAP_BIT_VRF1_SEL BIT(11)
+#define CPCAP_BIT_VHVIO_SEL BIT(10)
+#define CPCAP_BIT_VDAC_SEL BIT(9)
+#define CPCAP_BIT_VUSB_SEL BIT(8)
+#define CPCAP_BIT_VSIM_SEL BIT(7)
+#define CPCAP_BIT_VRFREF_SEL BIT(6)
+#define CPCAP_BIT_VPLL_SEL BIT(5)
+#define CPCAP_BIT_VFUSE_SEL BIT(4)
+#define CPCAP_BIT_VCSI_SEL BIT(3)
+#define CPCAP_BIT_SPARE_14_2 BIT(2)
+#define CPCAP_BIT_VWLAN2_SEL BIT(1)
+#define CPCAP_BIT_VRF2_SEL BIT(0)
+#define CPCAP_BIT_NONE 0
+
+/* CPCAP_REG_ASSIGN4 bits - Resource Assignment 4 */
+#define CPCAP_BIT_VAUDIO_SEL BIT(0)
+
+/*
+ * Off mode configuration bit. Used currently only by SW5 on omap4. There's
+ * the following comment in Motorola Linux kernel tree for it:
+ *
+ * When set in the regulator mode, the regulator assignment will be changed
+ * to secondary when the regulator is disabled. The mode will be set back to
+ * primary when the regulator is turned on.
+ */
+#define CPCAP_REG_OFF_MODE_SEC BIT(15)
+
+#define CPCAP_REG(_reg, _assignment_reg, _assignment_mask, _mode_mask, \
+ _volt_mask, _volt_shft, _mode_val, _off_mode_val, _val_tbl, \
+ _mode_cntr, _volt_trans_time, _turn_on_time, _bit_offset) { \
+ .reg = CPCAP_REG_##_reg, \
+ .assignment_reg = CPCAP_REG_##_assignment_reg, \
+ .assignment_mask = CPCAP_BIT_##_assignment_mask, \
+ .mode_mask = _mode_mask, \
+ .volt_mask = _volt_mask, \
+ .volt_shft = _volt_shft, \
+ .mode_val = _mode_val, \
+ .off_mode_val = _off_mode_val, \
+ .val_tbl_sz = ARRAY_SIZE(_val_tbl), \
+ .val_tbl = _val_tbl, \
+ .mode_cntr = _mode_cntr, \
+ .volt_trans_time = _volt_trans_time, \
+ .turn_on_time = _turn_on_time, \
+ .bit_offset_from_cpcap_lowest_voltage = _bit_offset, \
+}
+
+static const struct cpcap_regulator_data tegra20_regulators[CPCAP_REGULATORS_COUNT] = {
+ /* BUCK */
+ [CPCAP_SW1] = CPCAP_REG(S1C1, ASSIGN2, SW1_SEL, 0x6f00, 0x007f,
+ 0, 0x6800, 0, sw1_val_tbl, 0, 0, 1500, 0x0c),
+ [CPCAP_SW2] = CPCAP_REG(S2C1, ASSIGN2, SW2_SEL, 0x6f00, 0x007f,
+ 0, 0x4804, 0, sw2_sw4_val_tbl, 0, 0, 1500, 0x18),
+ [CPCAP_SW3] = CPCAP_REG(S3C, ASSIGN2, SW3_SEL, 0x0578, 0x0003,
+ 0, 0x043c, 0, sw3_val_tbl, 0, 0, 0, 0),
+ [CPCAP_SW4] = CPCAP_REG(S4C1, ASSIGN2, SW4_SEL, 0x6f00, 0x007f,
+ 0, 0x4909, 0, sw2_sw4_val_tbl, 0, 0, 1500, 0x18),
+ [CPCAP_SW5] = CPCAP_REG(S5C, ASSIGN2, SW5_SEL, 0x0028, 0x0000,
+ 0, 0x0020, 0, sw5_val_tbl, 0, 0, 1500, 0),
+ [CPCAP_SW6] = CPCAP_REG(S6C, ASSIGN2, SW6_SEL, 0x0000, 0x0000,
+ 0, 0, 0, unknown_val_tbl, 0, 0, 0, 0),
+ /* LDO */
+ [CPCAP_VCAM] = CPCAP_REG(VCAMC, ASSIGN2, VCAM_SEL, 0x0087, 0x0030,
+ 4, 0x7, 0, vcam_val_tbl, 0, 420, 1000, 0),
+ [CPCAP_VCSI] = CPCAP_REG(VCSIC, ASSIGN3, VCSI_SEL, 0x0047, 0x0010,
+ 4, 0x7, 0, vcsi_val_tbl, 0, 350, 1000, 0),
+ [CPCAP_VDAC] = CPCAP_REG(VDACC, ASSIGN3, VDAC_SEL, 0x0087, 0x0030,
+ 4, 0x0, 0, vdac_val_tbl, 0, 420, 1000, 0),
+ [CPCAP_VDIG] = CPCAP_REG(VDIGC, ASSIGN2, VDIG_SEL, 0x0087, 0x0030,
+ 4, 0x0, 0, vdig_val_tbl, 0, 420, 1000, 0),
+ [CPCAP_VFUSE] = CPCAP_REG(VFUSEC, ASSIGN3, VFUSE_SEL, 0x00a0, 0x000f,
+ 0, 0x0, 0, vfuse_val_tbl, 0, 420, 1000, 0),
+ [CPCAP_VHVIO] = CPCAP_REG(VHVIOC, ASSIGN3, VHVIO_SEL, 0x0017, 0x0000,
+ 0, 0x2, 0, vhvio_val_tbl, 0, 0, 1000, 0),
+ [CPCAP_VSDIO] = CPCAP_REG(VSDIOC, ASSIGN2, VSDIO_SEL, 0x0087, 0x0038,
+ 3, 0x2, 0, vsdio_val_tbl, 0, 420, 1000, 0),
+ [CPCAP_VPLL] = CPCAP_REG(VPLLC, ASSIGN3, VPLL_SEL, 0x0047, 0x0018,
+ 3, 0x1, 0, vpll_val_tbl, 0, 420, 100, 0),
+ [CPCAP_VRF1] = CPCAP_REG(VRF1C, ASSIGN3, VRF1_SEL, 0x00ac, 0x0002,
+ 1, 0x0, 0, vrf1_val_tbl, 0, 10, 1000, 0),
+ [CPCAP_VRF2] = CPCAP_REG(VRF2C, ASSIGN3, VRF2_SEL, 0x0023, 0x0008,
+ 3, 0x0, 0, vrf2_val_tbl, 0, 10, 1000, 0),
+ [CPCAP_VRFREF] = CPCAP_REG(VRFREFC, ASSIGN3, VRFREF_SEL, 0x0023, 0x0008,
+ 3, 0x0, 0, vrfref_val_tbl, 0, 420, 100, 0),
+ [CPCAP_VWLAN1] = CPCAP_REG(VWLAN1C, ASSIGN3, VWLAN1_SEL, 0x0047, 0x0010,
+ 4, 0x0, 0, vwlan1_val_tbl, 0, 420, 1000, 0),
+ [CPCAP_VWLAN2] = CPCAP_REG(VWLAN2C, ASSIGN3, VWLAN2_SEL, 0x020c, 0x00c0,
+ 6, 0xd, 0, vwlan2_val_tbl, 0, 420, 1000, 0),
+ [CPCAP_VSIM] = CPCAP_REG(VSIMC, ASSIGN3, NONE, 0x0023, 0x0008,
+ 3, 0x0, 0, vsim_val_tbl, 0, 420, 1000, 0),
+ [CPCAP_VSIMCARD] = CPCAP_REG(VSIMC, ASSIGN3, NONE, 0x1e80, 0x0008,
+ 3, 0x1E00, 0, vsimcard_val_tbl, 0, 420, 1000, 0),
+ [CPCAP_VVIB] = CPCAP_REG(VVIBC, ASSIGN3, VVIB_SEL, 0x0001, 0x000c,
+ 2, 0x1, 0, vvib_val_tbl, 0, 500, 500, 0),
+ [CPCAP_VUSB] = CPCAP_REG(VUSBC, ASSIGN3, VUSB_SEL, 0x011c, 0x0040,
+ 6, 0xc, 0, vusb_val_tbl, 0, 0, 1000, 0),
+ [CPCAP_VAUDIO] = CPCAP_REG(VAUDIOC, ASSIGN4, VAUDIO_SEL, 0x0016, 0x0001,
+ 0, 0x5, 0, vaudio_val_tbl, 0, 0, 1000, 0),
+};
+
+static int cpcap_regulator_get_value(struct udevice *dev)
+{
+ const struct cpcap_regulator_data *regulator =
+ &tegra20_regulators[dev->driver_data];
+ int value, volt_shift = regulator->volt_shft;
+
+ value = pmic_reg_read(dev->parent, regulator->reg);
+ if (value < 0)
+ return value;
+
+ if (!(value & regulator->mode_mask))
+ return 0;
+
+ value &= regulator->volt_mask;
+ value -= regulator->bit_offset_from_cpcap_lowest_voltage;
+
+ return regulator->val_tbl[value >> volt_shift];
+}
+
+static int cpcap_regulator_set_value(struct udevice *dev, int uV)
+{
+ const struct cpcap_regulator_data *regulator =
+ &tegra20_regulators[dev->driver_data];
+ int value, ret, volt_shift = regulator->volt_shft;
+
+ if (dev->driver_data == CPCAP_VRF1) {
+ if (uV > 2500000)
+ value = 0;
+ else
+ value = regulator->volt_mask;
+ } else {
+ for (value = 0; value < regulator->val_tbl_sz; value++)
+ if (regulator->val_tbl[value] >= uV)
+ break;
+
+ if (value >= regulator->val_tbl_sz)
+ value = regulator->val_tbl_sz;
+
+ value <<= volt_shift;
+ value += regulator->bit_offset_from_cpcap_lowest_voltage;
+ }
+
+ ret = pmic_clrsetbits(dev->parent, regulator->reg, regulator->volt_mask,
+ value);
+ if (ret)
+ return ret;
+
+ if (regulator->volt_trans_time)
+ udelay(regulator->volt_trans_time);
+
+ return 0;
+}
+
+static int cpcap_regulator_get_enable(struct udevice *dev)
+{
+ const struct cpcap_regulator_data *regulator =
+ &tegra20_regulators[dev->driver_data];
+ int value;
+
+ value = pmic_reg_read(dev->parent, regulator->reg);
+ if (value < 0)
+ return value;
+
+ return (value & regulator->mode_mask) ? 1 : 0;
+}
+
+static int cpcap_regulator_set_enable(struct udevice *dev, bool enable)
+{
+ const struct cpcap_regulator_data *regulator =
+ &tegra20_regulators[dev->driver_data];
+ int ret;
+
+ if (enable) {
+ ret = pmic_clrsetbits(dev->parent, regulator->reg, regulator->mode_mask,
+ regulator->mode_val);
+ if (ret)
+ return ret;
+ }
+
+ if (regulator->mode_val & CPCAP_REG_OFF_MODE_SEC) {
+ ret = pmic_clrsetbits(dev->parent, regulator->assignment_reg,
+ regulator->assignment_mask,
+ enable ? 0 : regulator->assignment_mask);
+ if (ret)
+ return ret;
+ }
+
+ if (!enable) {
+ ret = pmic_clrsetbits(dev->parent, regulator->reg, regulator->mode_mask,
+ regulator->off_mode_val);
+ if (ret)
+ return ret;
+ }
+
+ if (regulator->turn_on_time)
+ udelay(regulator->turn_on_time);
+
+ return 0;
+}
+
+static int cpcap_regulator_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
+ int id;
+
+ for (id = 0; id < CPCAP_REGULATORS_COUNT; id++)
+ if (cpcap_regulator_to_name[id])
+ if (!strcmp(dev->name, cpcap_regulator_to_name[id]))
+ break;
+
+ switch (id) {
+ case CPCAP_SW1 ... CPCAP_SW6:
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+ break;
+
+ case CPCAP_VCAM ... CPCAP_VAUDIO:
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+ break;
+
+ default:
+ log_err("CPCAP: Invalid regulator ID\n");
+ return -ENODEV;
+ }
+
+ dev->driver_data = id;
+ return 0;
+}
+
+static const struct dm_regulator_ops cpcap_regulator_ops = {
+ .get_value = cpcap_regulator_get_value,
+ .set_value = cpcap_regulator_set_value,
+ .get_enable = cpcap_regulator_get_enable,
+ .set_enable = cpcap_regulator_set_enable,
+};
+
+U_BOOT_DRIVER(cpcap_sw) = {
+ .name = CPCAP_SW_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &cpcap_regulator_ops,
+ .probe = cpcap_regulator_probe,
+};
+
+U_BOOT_DRIVER(cpcap_ldo) = {
+ .name = CPCAP_LDO_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &cpcap_regulator_ops,
+ .probe = cpcap_regulator_probe,
+};
diff --git a/drivers/power/regulator/qcom-rpmh-regulator.c b/drivers/power/regulator/qcom-rpmh-regulator.c
index cd2b1a654c1..954deca5ed7 100644
--- a/drivers/power/regulator/qcom-rpmh-regulator.c
+++ b/drivers/power/regulator/qcom-rpmh-regulator.c
@@ -466,6 +466,25 @@ static const struct rpmh_vreg_hw_data pmic5_nldo515 = {
.n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo),
};
+static const struct rpmh_vreg_hw_data pmic5_ftsmps527 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000),
+ .n_voltages = 215,
+ .pmic_mode_map = pmic_mode_map_pmic5_smps,
+ .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_smps),
+};
+
+static const struct rpmh_vreg_hw_data pmic5_pldo515_mv = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_range = REGULATOR_LINEAR_RANGE(1800000, 0, 187, 8000),
+ .n_voltages = 188,
+ .hpm_min_load_uA = 10000,
+ .pmic_mode_map = pmic_mode_map_pmic5_ldo,
+ .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo),
+};
+
#define RPMH_VREG(_name, _resource_name, _hw_data, _supply_name) \
{ \
.name = _name, \
@@ -558,6 +577,28 @@ static const struct rpmh_vreg_init_data pmc8380_vreg_data[] = {
{}
};
+static const struct rpmh_vreg_init_data pmm8654au_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps527, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps527, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps527, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps527, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps527, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps527, "vdd-s6"),
+ RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps527, "vdd-s7"),
+ RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps527, "vdd-s8"),
+ RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps527, "vdd-s9"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-s9"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2-l3"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l2-l3"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515, "vdd-s9"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo515, "vdd-s9"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo515, "vdd-l6-l7"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo515, "vdd-l6-l7"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo515_mv, "vdd-l8-l9"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l8-l9"),
+ {}
+};
+
/* probe an individual regulator */
static int rpmh_regulator_probe(struct udevice *dev)
{
@@ -688,6 +729,10 @@ static const struct udevice_id rpmh_regulator_ids[] = {
.compatible = "qcom,pmc8380-rpmh-regulators",
.data = (ulong)pmc8380_vreg_data,
},
+ {
+ .compatible = "qcom,pmm8654au-rpmh-regulators",
+ .data = (ulong)pmm8654au_vreg_data,
+ },
{ /* sentinal */ },
};
diff --git a/drivers/power/regulator/qcom_usb_vbus_regulator.c b/drivers/power/regulator/qcom_usb_vbus_regulator.c
new file mode 100644
index 00000000000..2d58ef5e111
--- /dev/null
+++ b/drivers/power/regulator/qcom_usb_vbus_regulator.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2025, Linaro Limited
+ */
+#define pr_fmt(fmt) "qcom_usb_vbus: " fmt
+
+#include <bitfield.h>
+#include <errno.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <asm/gpio.h>
+#include <linux/bitops.h>
+#include <linux/printk.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+
+#define CMD_OTG 0x50
+#define OTG_EN BIT(0)
+// The 0 bit in this register's bit field is undocumented
+#define OTG_CFG 0x56
+#define OTG_EN_SRC_CFG BIT(1)
+
+struct qcom_usb_vbus_priv {
+ phys_addr_t base;
+};
+
+static int qcom_usb_vbus_regulator_of_to_plat(struct udevice *dev)
+{
+ struct qcom_usb_vbus_priv *priv = dev_get_priv(dev);
+
+ priv->base = dev_read_addr(dev);
+ if (priv->base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int qcom_usb_vbus_regulator_get_enable(struct udevice *dev)
+{
+ struct qcom_usb_vbus_priv *priv = dev_get_priv(dev);
+ int otg_en_reg = priv->base + CMD_OTG;
+ int ret;
+
+ ret = pmic_reg_read(dev->parent, otg_en_reg);
+ if (ret < 0)
+ log_err("failed to read usb vbus: %d\n", ret);
+ else
+ ret &= OTG_EN;
+
+ return ret;
+}
+
+static int qcom_usb_vbus_regulator_set_enable(struct udevice *dev, bool enable)
+{
+ struct qcom_usb_vbus_priv *priv = dev_get_priv(dev);
+ int otg_en_reg = priv->base + CMD_OTG;
+ int ret;
+
+ if (enable) {
+ ret = pmic_clrsetbits(dev->parent, otg_en_reg, 0, OTG_EN);
+ if (ret < 0) {
+ log_err("error enabling: %d\n", ret);
+ return ret;
+ }
+ } else {
+ ret = pmic_clrsetbits(dev->parent, otg_en_reg, OTG_EN, 0);
+ if (ret < 0) {
+ log_err("error disabling: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int qcom_usb_vbus_regulator_probe(struct udevice *dev)
+{
+ struct qcom_usb_vbus_priv *priv = dev_get_priv(dev);
+ int otg_cfg_reg = priv->base + OTG_CFG;
+ int ret;
+
+ /* Disable HW logic for VBUS enable */
+ ret = pmic_clrsetbits(dev->parent, otg_cfg_reg, OTG_EN_SRC_CFG, 0);
+ if (ret < 0) {
+ log_err("error setting EN_SRC_CFG: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dm_regulator_ops qcom_usb_vbus_regulator_ops = {
+ .get_enable = qcom_usb_vbus_regulator_get_enable,
+ .set_enable = qcom_usb_vbus_regulator_set_enable,
+};
+
+static const struct udevice_id qcom_usb_vbus_regulator_ids[] = {
+ { .compatible = "qcom,pm8150b-vbus-reg"},
+ { },
+};
+
+U_BOOT_DRIVER(qcom_usb_vbus_regulator) = {
+ .name = "qcom-usb-vbus-regulator",
+ .id = UCLASS_REGULATOR,
+ .of_match = qcom_usb_vbus_regulator_ids,
+ .of_to_plat = qcom_usb_vbus_regulator_of_to_plat,
+ .ops = &qcom_usb_vbus_regulator_ops,
+ .probe = qcom_usb_vbus_regulator_probe,
+ .priv_auto = sizeof(struct qcom_usb_vbus_priv),
+};
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index bd94ea771be..47bd57c7890 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -4,7 +4,7 @@
# Texas Instruments Incorporated - https://www.ti.com/
#
-obj-$(CONFIG_$(XPL_)REMOTEPROC) += rproc-uclass.o rproc-elf-loader.o
+obj-$(CONFIG_$(PHASE_)REMOTEPROC) += rproc-uclass.o rproc-elf-loader.o
# Remote proc drivers - Please keep this list alphabetically sorted.
obj-$(CONFIG_K3_SYSTEM_CONTROLLER) += k3_system_controller.o
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index cd0b84c0622..7d022ce718a 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -28,6 +28,10 @@ DEFINE_CACHE_ALIGN_BUFFER(u8, tempbuff, 512); /* temporary data buffer */
#define SCSI_MAX_BLK 0xFFFF
#define SCSI_LBA48_READ 0xFFFFFFF
+#define SCSI_UNMAP_PARAM_RESERVED 0
+#define SCSI_UNMAP_PARAM_LEN 22
+#define SCSI_UNMAP_PARAM_DATA_LEN 16
+
static void scsi_print_error(struct scsi_cmd *pccb)
{
/* Dummy function that could print an error for debugging */
@@ -78,6 +82,23 @@ static void scsi_setup_inquiry(struct scsi_cmd *pccb)
pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
}
+static void scsi_setup_sync_cache(struct scsi_cmd *pccb, lbaint_t start,
+ unsigned short blocks)
+{
+ pccb->cmd[0] = SCSI_SYNC_CACHE;
+ pccb->cmd[1] = 0;
+ pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff;
+ pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff;
+ pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff;
+ pccb->cmd[5] = (unsigned char)start & 0xff;
+ pccb->cmd[6] = 0;
+ pccb->cmd[7] = (unsigned char)(blocks >> 8) & 0xff;
+ pccb->cmd[8] = (unsigned char)blocks & 0xff;
+ pccb->cmd[9] = 0;
+ pccb->cmdlen = 10;
+ pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
+}
+
static void scsi_setup_read_ext(struct scsi_cmd *pccb, lbaint_t start,
unsigned short blocks)
{
@@ -90,7 +111,7 @@ static void scsi_setup_read_ext(struct scsi_cmd *pccb, lbaint_t start,
pccb->cmd[6] = 0;
pccb->cmd[7] = (unsigned char)(blocks >> 8) & 0xff;
pccb->cmd[8] = (unsigned char)blocks & 0xff;
- pccb->cmd[6] = 0;
+ pccb->cmd[9] = 0;
pccb->cmdlen = 10;
pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
debug("scsi_setup_read_ext: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n",
@@ -121,6 +142,51 @@ static void scsi_setup_write_ext(struct scsi_cmd *pccb, lbaint_t start,
pccb->cmd[7], pccb->cmd[8]);
}
+static void scsi_setup_erase_ext(struct scsi_cmd *pccb, lbaint_t start,
+ unsigned short blocks)
+{
+ u8 *param = tempbuff;
+ const u8 param_size = 24;
+
+ memset(param, 0, param_size);
+ param[0] = SCSI_UNMAP_PARAM_RESERVED;
+ param[1] = SCSI_UNMAP_PARAM_LEN;
+ param[2] = SCSI_UNMAP_PARAM_RESERVED;
+ param[3] = SCSI_UNMAP_PARAM_DATA_LEN;
+
+ param[8] = 0x0;
+ param[9] = 0x0;
+ param[10] = 0x0;
+ param[11] = 0x0;
+ param[12] = (start >> 24) & 0xff;
+ param[13] = (start >> 16) & 0xff;
+ param[14] = (start >> 8) & 0xff;
+ param[15] = (start) & 0xff;
+ param[16] = (blocks >> 24) & 0xff;
+ param[17] = (blocks >> 16) & 0xff;
+ param[18] = (blocks >> 8) & 0xff;
+ param[19] = (blocks) & 0xff;
+
+ memset(pccb->cmd, 0, sizeof(pccb->cmd));
+ pccb->cmd[0] = SCSI_UNMAP;
+ pccb->cmd[1] = 0;
+ pccb->cmd[6] = 0;
+ pccb->cmd[7] = 0;
+ pccb->cmd[8] = param_size;
+ pccb->cmd[9] = 0;
+ pccb->cmdlen = 10;
+
+ pccb->pdata = param;
+ pccb->datalen = param_size;
+ pccb->dma_dir = DMA_TO_DEVICE;
+
+ debug("%s: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n",
+ __func__,
+ pccb->cmd[0], pccb->cmd[1],
+ pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5],
+ pccb->cmd[7], pccb->cmd[8]);
+}
+
static ulong scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
void *buffer)
{
@@ -240,11 +306,59 @@ static ulong scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
}
buf_addr += pccb->datalen;
} while (blks != 0);
+
+ /* Flush the SCSI cache so we don't lose data on board reset. */
+ scsi_setup_sync_cache(pccb, 0, 0);
+ if (scsi_exec(bdev, pccb))
+ scsi_print_error(pccb);
+
debug("%s: end startblk " LBAF ", blccnt %x buffer %lX\n",
__func__, start, smallblks, buf_addr);
return blkcnt;
}
+/*******************************************************************************
+ * scsi_erase
+ */
+static ulong scsi_erase(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt)
+{
+ struct blk_desc *block_dev = dev_get_uclass_plat(dev);
+ struct udevice *bdev = dev->parent;
+ struct scsi_plat *uc_plat = dev_get_uclass_plat(bdev);
+ lbaint_t start, blks, max_blks;
+ struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb;
+
+ /* Setup device */
+ pccb->target = block_dev->target;
+ pccb->lun = block_dev->lun;
+ start = blknr;
+ blks = blkcnt;
+ if (uc_plat->max_bytes_per_req)
+ max_blks = uc_plat->max_bytes_per_req / block_dev->blksz;
+ else
+ max_blks = SCSI_MAX_BLK;
+
+ debug("\n%s: dev %d startblk " LBAF ", blccnt " LBAF "\n",
+ __func__, block_dev->devnum, start, blks);
+ do {
+ if (blks > max_blks) {
+ scsi_setup_erase_ext(pccb, start, max_blks);
+ start += max_blks;
+ blks -= max_blks;
+ } else {
+ scsi_setup_erase_ext(pccb, start, blks);
+ start += blks;
+ blks = 0;
+ }
+ if (scsi_exec(bdev, pccb)) {
+ scsi_print_error(pccb);
+ blkcnt -= blks;
+ break;
+ }
+ } while (blks != 0);
+ return blkcnt;
+}
+
#if IS_ENABLED(CONFIG_BOUNCE_BUFFER)
static int scsi_buffer_aligned(struct udevice *dev, struct bounce_buffer *state)
{
@@ -592,6 +706,7 @@ int scsi_scan(bool verbose)
static const struct blk_ops scsi_blk_ops = {
.read = scsi_read,
.write = scsi_write,
+ .erase = scsi_erase,
#if IS_ENABLED(CONFIG_BOUNCE_BUFFER)
.buffer_aligned = scsi_buffer_aligned,
#endif /* CONFIG_BOUNCE_BUFFER */
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 84130524c2d..589b526381f 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -519,6 +519,8 @@ config DEBUG_UART_BASE
default 0x0 if DEBUG_UART_SANDBOX
default 0xff000000 if DEBUG_UART_ZYNQ && ARCH_ZYNQMP
default 0xe0000000 if DEBUG_UART_ZYNQ && ARCH_ZYNQ
+ default 0xff000000 if DEBUG_UART_PL011 && ARCH_VERSAL
+ default 0xf1920000 if DEBUG_UART_PL011 && (ARCH_VERSAL_NET || ARCH_VERSAL2)
help
This is the base address of your UART for memory-mapped UARTs.
@@ -554,6 +556,7 @@ config DEBUG_UART_CLOCK
default 0 if DEBUG_MVEBU_A3700_UART
default 100000000 if DEBUG_UART_ZYNQ && ARCH_ZYNQMP
default 50000000 if DEBUG_UART_ZYNQ && ARCH_ZYNQ
+ default 100000000 if DEBUG_UART_PL011 && (ARCH_VERSAL || ARCH_VERSAL_NET || ARCH_VERSAL2)
help
The UART input clock determines the speed of the internal UART
circuitry. The baud rate is derived from this by dividing the input
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 2ef8ba20cf5..c32e3fcd439 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -11,7 +11,7 @@ endif
obj-$(CONFIG_PL01X_SERIAL) += serial_pl01x.o
obj-$(CONFIG_PL011_SERIAL) += serial_pl01x.o
-obj-$(CONFIG_$(XPL_)SYS_NS16550_SERIAL) += serial_ns16550.o
+obj-$(CONFIG_$(PHASE_)SYS_NS16550_SERIAL) += serial_ns16550.o
obj-$(CONFIG_ALTERA_UART) += altera_uart.o
obj-$(CONFIG_ALTERA_JTAG_UART) += altera_jtag_uart.o
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index f475f341c9c..a3513f0a3ef 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -59,6 +59,15 @@ config ADI_SPI3
Enable the ADI (Analog Devices) SPI controller driver. This
driver enables the support for SC5XX spi controller.
+config AIROHA_SNFI_SPI
+ bool "Airoha SPI memory controller driver"
+ depends on SPI_MEM
+ help
+ Enable the Airoha SPI memory controller driver. This driver is
+ originally based on the Airoha SNFI IP core. It can only be
+ used to access SPI memory devices like SPI-NOR or SPI-NAND on
+ platforms embedding this IP core, like AN7581.
+
config ALTERA_SPI
bool "Altera SPI driver"
help
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 21895d46429..da91b18b6ed 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_SPI_MEM) += spi-mem-nodm.o
endif
obj-$(CONFIG_ADI_SPI3) += adi_spi3.o
+obj-$(CONFIG_AIROHA_SNFI_SPI) += airoha_snfi_spi.o
obj-$(CONFIG_ALTERA_SPI) += altera_spi.o
obj-$(CONFIG_APPLE_SPI) += apple_spi.o
obj-$(CONFIG_ATH79_SPI) += ath79_spi.o
diff --git a/drivers/spi/airoha_snfi_spi.c b/drivers/spi/airoha_snfi_spi.c
new file mode 100644
index 00000000000..3ea25b293d1
--- /dev/null
+++ b/drivers/spi/airoha_snfi_spi.c
@@ -0,0 +1,718 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2024 AIROHA Inc
+ *
+ * Based on spi-airoha-snfi.c on Linux
+ *
+ * Author: Lorenzo Bianconi <lorenzo@kernel.org>
+ * Author: Ray Liu <ray.liu@airoha.com>
+ */
+
+#include <asm/unaligned.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <linux/bitfield.h>
+#include <linux/dma-mapping.h>
+#include <linux/mtd/spinand.h>
+#include <linux/time.h>
+#include <regmap.h>
+#include <spi.h>
+#include <spi-mem.h>
+
+/* SPI */
+#define REG_SPI_CTRL_READ_MODE 0x0000
+#define REG_SPI_CTRL_READ_IDLE_EN 0x0004
+#define REG_SPI_CTRL_SIDLY 0x0008
+#define REG_SPI_CTRL_CSHEXT 0x000c
+#define REG_SPI_CTRL_CSLEXT 0x0010
+
+#define REG_SPI_CTRL_MTX_MODE_TOG 0x0014
+#define SPI_CTRL_MTX_MODE_TOG GENMASK(3, 0)
+
+#define REG_SPI_CTRL_RDCTL_FSM 0x0018
+#define SPI_CTRL_RDCTL_FSM GENMASK(3, 0)
+
+#define REG_SPI_CTRL_MACMUX_SEL 0x001c
+
+#define REG_SPI_CTRL_MANUAL_EN 0x0020
+#define SPI_CTRL_MANUAL_EN BIT(0)
+
+#define REG_SPI_CTRL_OPFIFO_EMPTY 0x0024
+#define SPI_CTRL_OPFIFO_EMPTY BIT(0)
+
+#define REG_SPI_CTRL_OPFIFO_WDATA 0x0028
+#define SPI_CTRL_OPFIFO_LEN GENMASK(8, 0)
+#define SPI_CTRL_OPFIFO_OP GENMASK(13, 9)
+
+#define REG_SPI_CTRL_OPFIFO_FULL 0x002c
+#define SPI_CTRL_OPFIFO_FULL BIT(0)
+
+#define REG_SPI_CTRL_OPFIFO_WR 0x0030
+#define SPI_CTRL_OPFIFO_WR BIT(0)
+
+#define REG_SPI_CTRL_DFIFO_FULL 0x0034
+#define SPI_CTRL_DFIFO_FULL BIT(0)
+
+#define REG_SPI_CTRL_DFIFO_WDATA 0x0038
+#define SPI_CTRL_DFIFO_WDATA GENMASK(7, 0)
+
+#define REG_SPI_CTRL_DFIFO_EMPTY 0x003c
+#define SPI_CTRL_DFIFO_EMPTY BIT(0)
+
+#define REG_SPI_CTRL_DFIFO_RD 0x0040
+#define SPI_CTRL_DFIFO_RD BIT(0)
+
+#define REG_SPI_CTRL_DFIFO_RDATA 0x0044
+#define SPI_CTRL_DFIFO_RDATA GENMASK(7, 0)
+
+#define REG_SPI_CTRL_DUMMY 0x0080
+#define SPI_CTRL_CTRL_DUMMY GENMASK(3, 0)
+
+#define REG_SPI_CTRL_PROBE_SEL 0x0088
+#define REG_SPI_CTRL_INTERRUPT 0x0090
+#define REG_SPI_CTRL_INTERRUPT_EN 0x0094
+#define REG_SPI_CTRL_SI_CK_SEL 0x009c
+#define REG_SPI_CTRL_SW_CFGNANDADDR_VAL 0x010c
+#define REG_SPI_CTRL_SW_CFGNANDADDR_EN 0x0110
+#define REG_SPI_CTRL_SFC_STRAP 0x0114
+
+#define REG_SPI_CTRL_NFI2SPI_EN 0x0130
+#define SPI_CTRL_NFI2SPI_EN BIT(0)
+
+/* NFI2SPI */
+#define REG_SPI_NFI_CNFG 0x0000
+#define SPI_NFI_DMA_MODE BIT(0)
+#define SPI_NFI_READ_MODE BIT(1)
+#define SPI_NFI_DMA_BURST_EN BIT(2)
+#define SPI_NFI_HW_ECC_EN BIT(8)
+#define SPI_NFI_AUTO_FDM_EN BIT(9)
+#define SPI_NFI_OPMODE GENMASK(14, 12)
+
+#define REG_SPI_NFI_PAGEFMT 0x0004
+#define SPI_NFI_PAGE_SIZE GENMASK(1, 0)
+#define SPI_NFI_SPARE_SIZE GENMASK(5, 4)
+
+#define REG_SPI_NFI_CON 0x0008
+#define SPI_NFI_FIFO_FLUSH BIT(0)
+#define SPI_NFI_RST BIT(1)
+#define SPI_NFI_RD_TRIG BIT(8)
+#define SPI_NFI_WR_TRIG BIT(9)
+#define SPI_NFI_SEC_NUM GENMASK(15, 12)
+
+#define REG_SPI_NFI_INTR_EN 0x0010
+#define SPI_NFI_RD_DONE_EN BIT(0)
+#define SPI_NFI_WR_DONE_EN BIT(1)
+#define SPI_NFI_RST_DONE_EN BIT(2)
+#define SPI_NFI_ERASE_DONE_EN BIT(3)
+#define SPI_NFI_BUSY_RETURN_EN BIT(4)
+#define SPI_NFI_ACCESS_LOCK_EN BIT(5)
+#define SPI_NFI_AHB_DONE_EN BIT(6)
+#define SPI_NFI_ALL_IRQ_EN \
+ (SPI_NFI_RD_DONE_EN | SPI_NFI_WR_DONE_EN | \
+ SPI_NFI_RST_DONE_EN | SPI_NFI_ERASE_DONE_EN | \
+ SPI_NFI_BUSY_RETURN_EN | SPI_NFI_ACCESS_LOCK_EN | \
+ SPI_NFI_AHB_DONE_EN)
+
+#define REG_SPI_NFI_INTR 0x0014
+#define SPI_NFI_AHB_DONE BIT(6)
+
+#define REG_SPI_NFI_CMD 0x0020
+
+#define REG_SPI_NFI_ADDR_NOB 0x0030
+#define SPI_NFI_ROW_ADDR_NOB GENMASK(6, 4)
+
+#define REG_SPI_NFI_STA 0x0060
+#define REG_SPI_NFI_FIFOSTA 0x0064
+#define REG_SPI_NFI_STRADDR 0x0080
+#define REG_SPI_NFI_FDM0L 0x00a0
+#define REG_SPI_NFI_FDM0M 0x00a4
+#define REG_SPI_NFI_FDM7L 0x00d8
+#define REG_SPI_NFI_FDM7M 0x00dc
+#define REG_SPI_NFI_FIFODATA0 0x0190
+#define REG_SPI_NFI_FIFODATA1 0x0194
+#define REG_SPI_NFI_FIFODATA2 0x0198
+#define REG_SPI_NFI_FIFODATA3 0x019c
+#define REG_SPI_NFI_MASTERSTA 0x0224
+
+#define REG_SPI_NFI_SECCUS_SIZE 0x022c
+#define SPI_NFI_CUS_SEC_SIZE GENMASK(12, 0)
+#define SPI_NFI_CUS_SEC_SIZE_EN BIT(16)
+
+#define REG_SPI_NFI_RD_CTL2 0x0510
+#define REG_SPI_NFI_RD_CTL3 0x0514
+
+#define REG_SPI_NFI_PG_CTL1 0x0524
+#define SPI_NFI_PG_LOAD_CMD GENMASK(15, 8)
+
+#define REG_SPI_NFI_PG_CTL2 0x0528
+#define REG_SPI_NFI_NOR_PROG_ADDR 0x052c
+#define REG_SPI_NFI_NOR_RD_ADDR 0x0534
+
+#define REG_SPI_NFI_SNF_MISC_CTL 0x0538
+#define SPI_NFI_DATA_READ_WR_MODE GENMASK(18, 16)
+
+#define REG_SPI_NFI_SNF_MISC_CTL2 0x053c
+#define SPI_NFI_READ_DATA_BYTE_NUM GENMASK(12, 0)
+#define SPI_NFI_PROG_LOAD_BYTE_NUM GENMASK(28, 16)
+
+#define REG_SPI_NFI_SNF_STA_CTL1 0x0550
+#define SPI_NFI_READ_FROM_CACHE_DONE BIT(25)
+#define SPI_NFI_LOAD_TO_CACHE_DONE BIT(26)
+
+#define REG_SPI_NFI_SNF_STA_CTL2 0x0554
+
+#define REG_SPI_NFI_SNF_NFI_CNFG 0x055c
+#define SPI_NFI_SPI_MODE BIT(0)
+
+/* SPI NAND Protocol OP */
+#define SPI_NAND_OP_GET_FEATURE 0x0f
+#define SPI_NAND_OP_SET_FEATURE 0x1f
+#define SPI_NAND_OP_PAGE_READ 0x13
+#define SPI_NAND_OP_READ_FROM_CACHE_SINGLE 0x03
+#define SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST 0x0b
+#define SPI_NAND_OP_READ_FROM_CACHE_DUAL 0x3b
+#define SPI_NAND_OP_READ_FROM_CACHE_QUAD 0x6b
+#define SPI_NAND_OP_WRITE_ENABLE 0x06
+#define SPI_NAND_OP_WRITE_DISABLE 0x04
+#define SPI_NAND_OP_PROGRAM_LOAD_SINGLE 0x02
+#define SPI_NAND_OP_PROGRAM_LOAD_QUAD 0x32
+#define SPI_NAND_OP_PROGRAM_LOAD_RAMDOM_SINGLE 0x84
+#define SPI_NAND_OP_PROGRAM_LOAD_RAMDON_QUAD 0x34
+#define SPI_NAND_OP_PROGRAM_EXECUTE 0x10
+#define SPI_NAND_OP_READ_ID 0x9f
+#define SPI_NAND_OP_BLOCK_ERASE 0xd8
+#define SPI_NAND_OP_RESET 0xff
+#define SPI_NAND_OP_DIE_SELECT 0xc2
+
+#define SPI_NAND_CACHE_SIZE (SZ_4K + SZ_256)
+#define SPI_MAX_TRANSFER_SIZE 511
+
+enum airoha_snand_mode {
+ SPI_MODE_AUTO,
+ SPI_MODE_MANUAL,
+ SPI_MODE_DMA,
+};
+
+enum airoha_snand_cs {
+ SPI_CHIP_SEL_HIGH,
+ SPI_CHIP_SEL_LOW,
+};
+
+struct airoha_snand_priv {
+ struct regmap *regmap_ctrl;
+ struct regmap *regmap_nfi;
+ struct clk *spi_clk;
+
+ struct {
+ size_t page_size;
+ size_t sec_size;
+ u8 sec_num;
+ u8 spare_size;
+ } nfi_cfg;
+};
+
+static int airoha_snand_set_fifo_op(struct airoha_snand_priv *priv,
+ u8 op_cmd, int op_len)
+{
+ int err;
+ u32 val;
+
+ err = regmap_write(priv->regmap_ctrl, REG_SPI_CTRL_OPFIFO_WDATA,
+ FIELD_PREP(SPI_CTRL_OPFIFO_LEN, op_len) |
+ FIELD_PREP(SPI_CTRL_OPFIFO_OP, op_cmd));
+ if (err)
+ return err;
+
+ err = regmap_read_poll_timeout(priv->regmap_ctrl,
+ REG_SPI_CTRL_OPFIFO_FULL,
+ val, !(val & SPI_CTRL_OPFIFO_FULL),
+ 0, 250 * USEC_PER_MSEC);
+ if (err)
+ return err;
+
+ err = regmap_write(priv->regmap_ctrl, REG_SPI_CTRL_OPFIFO_WR,
+ SPI_CTRL_OPFIFO_WR);
+ if (err)
+ return err;
+
+ return regmap_read_poll_timeout(priv->regmap_ctrl,
+ REG_SPI_CTRL_OPFIFO_EMPTY,
+ val, (val & SPI_CTRL_OPFIFO_EMPTY),
+ 0, 250 * USEC_PER_MSEC);
+}
+
+static int airoha_snand_set_cs(struct airoha_snand_priv *priv, u8 cs)
+{
+ return airoha_snand_set_fifo_op(priv, cs, sizeof(cs));
+}
+
+static int airoha_snand_write_data_to_fifo(struct airoha_snand_priv *priv,
+ const u8 *data, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ int err;
+ u32 val;
+
+ /* 1. Wait until dfifo is not full */
+ err = regmap_read_poll_timeout(priv->regmap_ctrl,
+ REG_SPI_CTRL_DFIFO_FULL, val,
+ !(val & SPI_CTRL_DFIFO_FULL),
+ 0, 250 * USEC_PER_MSEC);
+ if (err)
+ return err;
+
+ /* 2. Write data to register DFIFO_WDATA */
+ err = regmap_write(priv->regmap_ctrl,
+ REG_SPI_CTRL_DFIFO_WDATA,
+ FIELD_PREP(SPI_CTRL_DFIFO_WDATA, data[i]));
+ if (err)
+ return err;
+
+ /* 3. Wait until dfifo is not full */
+ err = regmap_read_poll_timeout(priv->regmap_ctrl,
+ REG_SPI_CTRL_DFIFO_FULL, val,
+ !(val & SPI_CTRL_DFIFO_FULL),
+ 0, 250 * USEC_PER_MSEC);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int airoha_snand_read_data_from_fifo(struct airoha_snand_priv *priv,
+ u8 *ptr, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ int err;
+ u32 val;
+
+ /* 1. wait until dfifo is not empty */
+ err = regmap_read_poll_timeout(priv->regmap_ctrl,
+ REG_SPI_CTRL_DFIFO_EMPTY, val,
+ !(val & SPI_CTRL_DFIFO_EMPTY),
+ 0, 250 * USEC_PER_MSEC);
+ if (err)
+ return err;
+
+ /* 2. read from dfifo to register DFIFO_RDATA */
+ err = regmap_read(priv->regmap_ctrl,
+ REG_SPI_CTRL_DFIFO_RDATA, &val);
+ if (err)
+ return err;
+
+ ptr[i] = FIELD_GET(SPI_CTRL_DFIFO_RDATA, val);
+ /* 3. enable register DFIFO_RD to read next byte */
+ err = regmap_write(priv->regmap_ctrl,
+ REG_SPI_CTRL_DFIFO_RD, SPI_CTRL_DFIFO_RD);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int airoha_snand_set_mode(struct airoha_snand_priv *priv,
+ enum airoha_snand_mode mode)
+{
+ int err;
+
+ switch (mode) {
+ case SPI_MODE_MANUAL: {
+ u32 val;
+
+ err = regmap_write(priv->regmap_ctrl,
+ REG_SPI_CTRL_NFI2SPI_EN, 0);
+ if (err)
+ return err;
+
+ err = regmap_write(priv->regmap_ctrl,
+ REG_SPI_CTRL_READ_IDLE_EN, 0);
+ if (err)
+ return err;
+
+ err = regmap_read_poll_timeout(priv->regmap_ctrl,
+ REG_SPI_CTRL_RDCTL_FSM, val,
+ !(val & SPI_CTRL_RDCTL_FSM),
+ 0, 250 * USEC_PER_MSEC);
+ if (err)
+ return err;
+
+ err = regmap_write(priv->regmap_ctrl,
+ REG_SPI_CTRL_MTX_MODE_TOG, 9);
+ if (err)
+ return err;
+
+ err = regmap_write(priv->regmap_ctrl,
+ REG_SPI_CTRL_MANUAL_EN, SPI_CTRL_MANUAL_EN);
+ if (err)
+ return err;
+ break;
+ }
+ case SPI_MODE_DMA:
+ err = regmap_write(priv->regmap_ctrl,
+ REG_SPI_CTRL_NFI2SPI_EN,
+ SPI_CTRL_MANUAL_EN);
+ if (err < 0)
+ return err;
+
+ err = regmap_write(priv->regmap_ctrl,
+ REG_SPI_CTRL_MTX_MODE_TOG, 0x0);
+ if (err < 0)
+ return err;
+
+ err = regmap_write(priv->regmap_ctrl,
+ REG_SPI_CTRL_MANUAL_EN, 0x0);
+ if (err < 0)
+ return err;
+ break;
+ case SPI_MODE_AUTO:
+ default:
+ break;
+ }
+
+ return regmap_write(priv->regmap_ctrl, REG_SPI_CTRL_DUMMY, 0);
+}
+
+static int airoha_snand_write_data(struct airoha_snand_priv *priv, u8 cmd,
+ const u8 *data, int len)
+{
+ int i, data_len;
+
+ for (i = 0; i < len; i += data_len) {
+ int err;
+
+ data_len = min(len - i, SPI_MAX_TRANSFER_SIZE);
+ err = airoha_snand_set_fifo_op(priv, cmd, data_len);
+ if (err)
+ return err;
+
+ err = airoha_snand_write_data_to_fifo(priv, &data[i],
+ data_len);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int airoha_snand_read_data(struct airoha_snand_priv *priv, u8 *data,
+ int len)
+{
+ int i, data_len;
+
+ for (i = 0; i < len; i += data_len) {
+ int err;
+
+ data_len = min(len - i, SPI_MAX_TRANSFER_SIZE);
+ err = airoha_snand_set_fifo_op(priv, 0xc, data_len);
+ if (err)
+ return err;
+
+ err = airoha_snand_read_data_from_fifo(priv, &data[i],
+ data_len);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int airoha_snand_nfi_init(struct airoha_snand_priv *priv)
+{
+ int err;
+
+ /* switch to SNFI mode */
+ err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_SNF_NFI_CNFG,
+ SPI_NFI_SPI_MODE);
+ if (err)
+ return err;
+
+ /* Enable DMA */
+ return regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_INTR_EN,
+ SPI_NFI_ALL_IRQ_EN, SPI_NFI_AHB_DONE_EN);
+}
+
+static int airoha_snand_nfi_config(struct airoha_snand_priv *priv)
+{
+ int err;
+ u32 val;
+
+ err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_CON,
+ SPI_NFI_FIFO_FLUSH | SPI_NFI_RST);
+ if (err)
+ return err;
+
+ /* auto FDM */
+ err = regmap_clear_bits(priv->regmap_nfi, REG_SPI_NFI_CNFG,
+ SPI_NFI_AUTO_FDM_EN);
+ if (err)
+ return err;
+
+ /* HW ECC */
+ err = regmap_clear_bits(priv->regmap_nfi, REG_SPI_NFI_CNFG,
+ SPI_NFI_HW_ECC_EN);
+ if (err)
+ return err;
+
+ /* DMA Burst */
+ err = regmap_set_bits(priv->regmap_nfi, REG_SPI_NFI_CNFG,
+ SPI_NFI_DMA_BURST_EN);
+ if (err)
+ return err;
+
+ /* page format */
+ switch (priv->nfi_cfg.spare_size) {
+ case 26:
+ val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x1);
+ break;
+ case 27:
+ val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x2);
+ break;
+ case 28:
+ val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x3);
+ break;
+ default:
+ val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x0);
+ break;
+ }
+
+ err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_PAGEFMT,
+ SPI_NFI_SPARE_SIZE, val);
+ if (err)
+ return err;
+
+ switch (priv->nfi_cfg.page_size) {
+ case 2048:
+ val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x1);
+ break;
+ case 4096:
+ val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x2);
+ break;
+ default:
+ val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x0);
+ break;
+ }
+
+ err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_PAGEFMT,
+ SPI_NFI_PAGE_SIZE, val);
+ if (err)
+ return err;
+
+ /* sec num */
+ val = FIELD_PREP(SPI_NFI_SEC_NUM, priv->nfi_cfg.sec_num);
+ err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_CON,
+ SPI_NFI_SEC_NUM, val);
+ if (err)
+ return err;
+
+ /* enable cust sec size */
+ err = regmap_set_bits(priv->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE,
+ SPI_NFI_CUS_SEC_SIZE_EN);
+ if (err)
+ return err;
+
+ /* set cust sec size */
+ val = FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, priv->nfi_cfg.sec_size);
+ return regmap_update_bits(priv->regmap_nfi,
+ REG_SPI_NFI_SECCUS_SIZE,
+ SPI_NFI_CUS_SEC_SIZE, val);
+}
+
+static int airoha_snand_adjust_op_size(struct spi_slave *slave,
+ struct spi_mem_op *op)
+{
+ size_t max_len;
+
+ max_len = 1 + op->addr.nbytes + op->dummy.nbytes;
+ if (max_len >= 160)
+ return -EOPNOTSUPP;
+
+ if (op->data.nbytes > 160 - max_len)
+ op->data.nbytes = 160 - max_len;
+
+ return 0;
+}
+
+static bool airoha_snand_supports_op(struct spi_slave *slave,
+ const struct spi_mem_op *op)
+{
+ if (!spi_mem_default_supports_op(slave, op))
+ return false;
+
+ if (op->cmd.buswidth != 1)
+ return false;
+
+ return (!op->addr.nbytes || op->addr.buswidth == 1) &&
+ (!op->dummy.nbytes || op->dummy.buswidth == 1) &&
+ (!op->data.nbytes || op->data.buswidth == 1);
+}
+
+static int airoha_snand_exec_op(struct spi_slave *slave,
+ const struct spi_mem_op *op)
+{
+ u8 data[8], cmd, opcode = op->cmd.opcode;
+ struct udevice *bus = slave->dev->parent;
+ struct airoha_snand_priv *priv;
+ int i, err;
+
+ priv = dev_get_priv(bus);
+
+ /* switch to manual mode */
+ err = airoha_snand_set_mode(priv, SPI_MODE_MANUAL);
+ if (err < 0)
+ return err;
+
+ err = airoha_snand_set_cs(priv, SPI_CHIP_SEL_LOW);
+ if (err < 0)
+ return err;
+
+ /* opcode */
+ err = airoha_snand_write_data(priv, 0x8, &opcode, sizeof(opcode));
+ if (err)
+ return err;
+
+ /* addr part */
+ cmd = opcode == SPI_NAND_OP_GET_FEATURE ? 0x11 : 0x8;
+ put_unaligned_be64(op->addr.val, data);
+
+ for (i = ARRAY_SIZE(data) - op->addr.nbytes;
+ i < ARRAY_SIZE(data); i++) {
+ err = airoha_snand_write_data(priv, cmd, &data[i],
+ sizeof(data[0]));
+ if (err)
+ return err;
+ }
+
+ /* dummy */
+ data[0] = 0xff;
+ for (i = 0; i < op->dummy.nbytes; i++) {
+ err = airoha_snand_write_data(priv, 0x8, &data[0],
+ sizeof(data[0]));
+ if (err)
+ return err;
+ }
+
+ /* data */
+ if (op->data.dir == SPI_MEM_DATA_IN) {
+ err = airoha_snand_read_data(priv, op->data.buf.in,
+ op->data.nbytes);
+ if (err)
+ return err;
+ } else {
+ err = airoha_snand_write_data(priv, 0x8, op->data.buf.out,
+ op->data.nbytes);
+ if (err)
+ return err;
+ }
+
+ return airoha_snand_set_cs(priv, SPI_CHIP_SEL_HIGH);
+}
+
+static int airoha_snand_probe(struct udevice *dev)
+{
+ struct airoha_snand_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = regmap_init_mem_index(dev_ofnode(dev), &priv->regmap_ctrl, 0);
+ if (ret) {
+ dev_err(dev, "failed to init spi ctrl regmap\n");
+ return ret;
+ }
+
+ ret = regmap_init_mem_index(dev_ofnode(dev), &priv->regmap_nfi, 1);
+ if (ret) {
+ dev_err(dev, "failed to init spi nfi regmap\n");
+ return ret;
+ }
+
+ priv->spi_clk = devm_clk_get(dev, "spi");
+ if (IS_ERR(priv->spi_clk)) {
+ dev_err(dev, "unable to get spi clk\n");
+ return PTR_ERR(priv->regmap_ctrl);
+ }
+ clk_enable(priv->spi_clk);
+
+ return airoha_snand_nfi_init(priv);
+}
+
+static int airoha_snand_nfi_set_speed(struct udevice *bus, uint speed)
+{
+ struct airoha_snand_priv *priv = dev_get_priv(bus);
+ int ret;
+
+ ret = clk_set_rate(priv->spi_clk, speed);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int airoha_snand_nfi_set_mode(struct udevice *bus, uint mode)
+{
+ return 0;
+}
+
+static int airoha_snand_nfi_setup(struct spi_slave *slave,
+ const struct spinand_info *spinand_info)
+{
+ struct udevice *bus = slave->dev->parent;
+ struct airoha_snand_priv *priv;
+ u32 sec_size, sec_num;
+ int pagesize, oobsize;
+
+ priv = dev_get_priv(bus);
+
+ pagesize = spinand_info->memorg.pagesize;
+ oobsize = spinand_info->memorg.oobsize;
+
+ if (pagesize == 2 * 1024)
+ sec_num = 4;
+ else if (pagesize == 4 * 1024)
+ sec_num = 8;
+ else
+ sec_num = 1;
+
+ sec_size = (pagesize + oobsize) / sec_num;
+
+ /* init default value */
+ priv->nfi_cfg.sec_size = sec_size;
+ priv->nfi_cfg.sec_num = sec_num;
+ priv->nfi_cfg.page_size = round_down(sec_size * sec_num, 1024);
+ priv->nfi_cfg.spare_size = 16;
+
+ return airoha_snand_nfi_config(priv);
+}
+
+static const struct spi_controller_mem_ops airoha_snand_mem_ops = {
+ .adjust_op_size = airoha_snand_adjust_op_size,
+ .supports_op = airoha_snand_supports_op,
+ .exec_op = airoha_snand_exec_op,
+};
+
+static const struct dm_spi_ops airoha_snfi_spi_ops = {
+ .mem_ops = &airoha_snand_mem_ops,
+ .set_speed = airoha_snand_nfi_set_speed,
+ .set_mode = airoha_snand_nfi_set_mode,
+ .setup_for_spinand = airoha_snand_nfi_setup,
+};
+
+static const struct udevice_id airoha_snand_ids[] = {
+ { .compatible = "airoha,en7581-snand" },
+ { }
+};
+
+U_BOOT_DRIVER(airoha_snfi_spi) = {
+ .name = "airoha-snfi-spi",
+ .id = UCLASS_SPI,
+ .of_match = airoha_snand_ids,
+ .ops = &airoha_snfi_spi_ops,
+ .priv_auto = sizeof(struct airoha_snand_priv),
+ .probe = airoha_snand_probe,
+};
diff --git a/drivers/spi/cadence_ospi_versal.c b/drivers/spi/cadence_ospi_versal.c
index 816916de16d..fbeb0c6a85c 100644
--- a/drivers/spi/cadence_ospi_versal.c
+++ b/drivers/spi/cadence_ospi_versal.c
@@ -204,3 +204,22 @@ void cadence_qspi_apb_enable_linear_mode(bool enable)
~VERSAL_OSPI_LINEAR_MODE, VERSAL_AXI_MUX_SEL);
}
}
+
+int cadence_device_reset(struct udevice *bus)
+{
+ struct cadence_spi_priv *priv = dev_get_priv(bus);
+ u32 reg;
+
+ reg = readl(priv->regbase + CQSPI_REG_CONFIG);
+ reg |= CQSPI_REG_CONFIG_RESET_CFG_FLD_MASK;
+ writel(reg, priv->regbase + CQSPI_REG_CONFIG);
+
+ writel(reg & ~CQSPI_REG_CONFIG_RESET_PIN_FLD_MASK, priv->regbase + CQSPI_REG_CONFIG);
+ udelay(5);
+ writel(reg | CQSPI_REG_CONFIG_RESET_PIN_FLD_MASK, priv->regbase + CQSPI_REG_CONFIG);
+ udelay(150);
+ writel(reg & ~CQSPI_REG_CONFIG_RESET_PIN_FLD_MASK, priv->regbase + CQSPI_REG_CONFIG);
+ udelay(1200);
+
+ return 0;
+}
diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index 623904ecdad..a78c00db4ff 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -33,6 +33,11 @@ __weak int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv,
return 0;
}
+__weak int cadence_device_reset(struct udevice *dev)
+{
+ return 0;
+}
+
__weak int cadence_qspi_flash_reset(struct udevice *dev)
{
return 0;
@@ -251,6 +256,9 @@ static int cadence_spi_probe(struct udevice *bus)
priv->wr_delay = 50 * DIV_ROUND_UP(NSEC_PER_SEC, priv->ref_clk_hz);
+ if (device_is_compatible(bus, "amd,versal2-ospi"))
+ return cadence_device_reset(bus);
+
/* Reset ospi flash device */
return cadence_qspi_flash_reset(bus);
@@ -452,6 +460,7 @@ static const struct dm_spi_ops cadence_spi_ops = {
static const struct udevice_id cadence_spi_ids[] = {
{ .compatible = "cdns,qspi-nor" },
{ .compatible = "ti,am654-ospi" },
+ { .compatible = "amd,versal2-ospi" },
{ }
};
diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h
index 1f9125cd239..731b6527cf3 100644
--- a/drivers/spi/cadence_qspi.h
+++ b/drivers/spi/cadence_qspi.h
@@ -45,6 +45,8 @@
#define CQSPI_REG_CONFIG_CLK_POL BIT(1)
#define CQSPI_REG_CONFIG_CLK_PHA BIT(2)
#define CQSPI_REG_CONFIG_PHY_ENABLE_MASK BIT(3)
+#define CQSPI_REG_CONFIG_RESET_PIN_FLD_MASK BIT(5)
+#define CQSPI_REG_CONFIG_RESET_CFG_FLD_MASK BIT(6)
#define CQSPI_REG_CONFIG_DIRECT BIT(7)
#define CQSPI_REG_CONFIG_DECODE BIT(9)
#define CQSPI_REG_CONFIG_ENBL_DMA BIT(15)
@@ -310,5 +312,6 @@ int cadence_qspi_apb_exec_flash_cmd(void *reg_base, unsigned int reg);
int cadence_qspi_flash_reset(struct udevice *dev);
ofnode cadence_qspi_get_subnode(struct udevice *dev);
void cadence_qspi_apb_enable_linear_mode(bool enable);
+int cadence_device_reset(struct udevice *dev);
#endif /* __CADENCE_QSPI_H__ */
diff --git a/drivers/spi/tegra20_slink.c b/drivers/spi/tegra20_slink.c
index d54a5049205..097d9164175 100644
--- a/drivers/spi/tegra20_slink.c
+++ b/drivers/spi/tegra20_slink.c
@@ -29,7 +29,10 @@ DECLARE_GLOBAL_DATA_PTR;
#define SLINK_CMD_IDLE_SCLK_PULL_LOW (2 << 24)
#define SLINK_CMD_IDLE_SCLK_PULL_HIGH (3 << 24)
#define SLINK_CMD_IDLE_SCLK_MASK (3 << 24)
+#define SLINK_CMD_CS_POL3 BIT(23)
+#define SLINK_CMD_CS_POL2 BIT(22)
#define SLINK_CMD_CK_SDA BIT(21)
+#define SLINK_CMD_CS_POL1 BIT(20)
#define SLINK_CMD_CS_POL BIT(13)
#define SLINK_CMD_CS_VAL BIT(12)
#define SLINK_CMD_CS_SOFT BIT(11)
@@ -64,6 +67,13 @@ DECLARE_GLOBAL_DATA_PTR;
#define SPI_TIMEOUT 1000
#define TEGRA_SPI_MAX_FREQ 52000000
+unsigned int cmd_cs_pol_bit[] = {
+ SLINK_CMD_CS_POL,
+ SLINK_CMD_CS_POL1,
+ SLINK_CMD_CS_POL2,
+ SLINK_CMD_CS_POL3,
+};
+
struct spi_regs {
u32 command; /* SLINK_COMMAND_0 register */
u32 command2; /* SLINK_COMMAND2_0 reg */
@@ -155,6 +165,14 @@ static int tegra30_spi_claim_bus(struct udevice *dev)
writel(reg, &regs->status);
debug("%s: STATUS = %08x\n", __func__, readl(&regs->status));
+ /* Update the polarity bits */
+ if (priv->mode & SPI_CS_HIGH)
+ setbits_le32(&priv->regs->command,
+ cmd_cs_pol_bit[spi_chip_select(dev)]);
+ else
+ clrbits_le32(&priv->regs->command,
+ cmd_cs_pol_bit[spi_chip_select(dev)]);
+
/* Set master mode and sw controlled CS */
reg = readl(&regs->command);
reg |= SLINK_CMD_M_S | SLINK_CMD_CS_SOFT;
diff --git a/drivers/spmi/spmi-msm.c b/drivers/spmi/spmi-msm.c
index 5cc5a9e654c..faae54e9fef 100644
--- a/drivers/spmi/spmi-msm.c
+++ b/drivers/spmi/spmi-msm.c
@@ -24,6 +24,9 @@ DECLARE_GLOBAL_DATA_PTR;
#define PMIC_ARB_VERSION_V5_MIN 0x50000000
#define PMIC_ARB_VERSION_V7_MIN 0x70000000
+#define PMIC_ARB_FEATURES 0x0004
+#define PMIC_ARB_FEATURES_PERIPH_MASK GENMASK(10, 0)
+
#define APID_MAP_OFFSET_V1_V2_V3 (0x800)
#define APID_MAP_OFFSET_V5 (0x900)
#define APID_MAP_OFFSET_V7 (0x2000)
@@ -60,6 +63,7 @@ DECLARE_GLOBAL_DATA_PTR;
#define SPMI_MAX_PERIPH 256
#define SPMI_CHANNEL_READ_ONLY BIT(31)
+#define SPMI_CHANNEL_VALID BIT(30)
#define SPMI_CHANNEL_MASK 0xffff
enum arb_ver {
@@ -114,6 +118,8 @@ static int msm_spmi_write(struct udevice *dev, int usid, int pid, int off,
return -EIO;
if (pid >= SPMI_MAX_PERIPH)
return -EIO;
+ if (!(priv->channel_map[usid][pid] & SPMI_CHANNEL_VALID))
+ return -EINVAL;
if (priv->channel_map[usid][pid] & SPMI_CHANNEL_READ_ONLY)
return -EPERM;
@@ -183,6 +189,8 @@ static int msm_spmi_read(struct udevice *dev, int usid, int pid, int off)
return -EIO;
if (pid >= SPMI_MAX_PERIPH)
return -EIO;
+ if (!(priv->channel_map[usid][pid] & SPMI_CHANNEL_VALID))
+ return -EINVAL;
channel = priv->channel_map[usid][pid] & SPMI_CHANNEL_MASK;
@@ -246,6 +254,32 @@ static struct dm_spmi_ops msm_spmi_ops = {
.write = msm_spmi_write,
};
+/*
+ * In order to allow multiple EEs to write to a single PPID in arbiter
+ * version 5 and 7, there is more than one APID mapped to each PPID.
+ * The owner field for each of these mappings specifies the EE which is
+ * allowed to write to the APID.
+ */
+static void msm_spmi_channel_map_v5(struct msm_spmi_priv *priv, unsigned int i,
+ uint8_t slave_id, uint8_t pid)
+{
+ /* Mark channels read-only when from different owner */
+ uint32_t cnfg = readl(priv->spmi_cnfg + ARB_CHANNEL_OFFSET(i));
+ uint8_t owner = SPMI_OWNERSHIP_PERIPH2OWNER(cnfg);
+ bool prev_valid = priv->channel_map[slave_id][pid] & SPMI_CHANNEL_VALID;
+ uint32_t prev_read_only = priv->channel_map[slave_id][pid] & SPMI_CHANNEL_READ_ONLY;
+
+ if (!prev_valid) {
+ /* First PPID mapping */
+ priv->channel_map[slave_id][pid] = i | SPMI_CHANNEL_VALID;
+ if (owner != priv->owner)
+ priv->channel_map[slave_id][pid] |= SPMI_CHANNEL_READ_ONLY;
+ } else if ((owner == priv->owner) && prev_read_only) {
+ /* Read only and we found one we own, switch */
+ priv->channel_map[slave_id][pid] = i | SPMI_CHANNEL_VALID;
+ }
+}
+
static int msm_spmi_probe(struct udevice *dev)
{
struct msm_spmi_priv *priv = dev_get_priv(dev);
@@ -271,13 +305,17 @@ static int msm_spmi_probe(struct udevice *dev)
} else if (hw_ver < PMIC_ARB_VERSION_V7_MIN) {
priv->arb_ver = V5;
priv->arb_chnl = core_addr + APID_MAP_OFFSET_V5;
- priv->max_channels = SPMI_MAX_CHANNELS_V5;
+ priv->max_channels = min_t(u32, readl(core_addr + PMIC_ARB_FEATURES) &
+ PMIC_ARB_FEATURES_PERIPH_MASK,
+ SPMI_MAX_CHANNELS_V5);
priv->spmi_cnfg = dev_read_addr_name(dev, "cnfg");
} else {
/* TOFIX: handle second bus */
priv->arb_ver = V7;
priv->arb_chnl = core_addr + APID_MAP_OFFSET_V7;
- priv->max_channels = SPMI_MAX_CHANNELS_V7;
+ priv->max_channels = min_t(u32, readl(core_addr + PMIC_ARB_FEATURES) &
+ PMIC_ARB_FEATURES_PERIPH_MASK,
+ SPMI_MAX_CHANNELS_V7);
priv->spmi_cnfg = dev_read_addr_name(dev, "cnfg");
}
@@ -297,15 +335,16 @@ static int msm_spmi_probe(struct udevice *dev)
uint8_t slave_id = (periph & 0xf0000) >> 16;
uint8_t pid = (periph & 0xff00) >> 8;
- priv->channel_map[slave_id][pid] = i;
-
- /* Mark channels read-only when from different owner */
- if (priv->arb_ver == V5 || priv->arb_ver == V7) {
- uint32_t cnfg = readl(priv->spmi_cnfg + ARB_CHANNEL_OFFSET(i));
- uint8_t owner = SPMI_OWNERSHIP_PERIPH2OWNER(cnfg);
+ switch (priv->arb_ver) {
+ case V2:
+ case V3:
+ priv->channel_map[slave_id][pid] = i | SPMI_CHANNEL_VALID;
+ break;
- if (owner != priv->owner)
- priv->channel_map[slave_id][pid] |= SPMI_CHANNEL_READ_ONLY;
+ case V5:
+ case V7:
+ msm_spmi_channel_map_v5(priv, i, slave_id, pid);
+ break;
}
}
return 0;
diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig
index 475540ffac7..4972905482a 100644
--- a/drivers/sysreset/Kconfig
+++ b/drivers/sysreset/Kconfig
@@ -71,6 +71,27 @@ config POWEROFF_GPIO
Support for system poweroff using a GPIO pin. This can be used
for systems having a single GPIO to trigger a system poweroff.
+config SPL_POWEROFF_GPIO
+ bool "Enable support for GPIO poweroff driver in SPL"
+ depends on DM_GPIO && SPL
+ help
+ Support for system poweroff using a GPIO pin in SPL. This can be used
+ for systems having a single GPIO to trigger a system poweroff.
+
+config TPL_POWEROFF_GPIO
+ bool "Enable support for GPIO poweroff driver in TPL"
+ depends on DM_GPIO && TPL
+ help
+ Support for system poweroff using a GPIO pin in TPL. This can be used
+ for systems having a single GPIO to trigger a system poweroff.
+
+config VPL_POWEROFF_GPIO
+ bool "Enable support for GPIO poweroff driver in VPL"
+ depends on DM_GPIO && VPL
+ help
+ Support for system poweroff using a GPIO pin in VPL. This can be used
+ for systems having a single GPIO to trigger a system poweroff.
+
config SYSRESET_GPIO
bool "Enable support for GPIO reset driver"
depends on DM_GPIO
@@ -79,6 +100,30 @@ config SYSRESET_GPIO
example on Microblaze where reset logic can be controlled via GPIO
pin which triggers cpu reset.
+config SPL_SYSRESET_GPIO
+ bool "Enable support for GPIO reset driver in SPL"
+ depends on DM_GPIO && SPL
+ help
+ Reset support via GPIO pin connected reset logic in SPL. This is used
+ for example on Microblaze where reset logic can be controlled via
+ GPIO pin which triggers cpu reset.
+
+config TPL_SYSRESET_GPIO
+ bool "Enable support for GPIO reset driver in TPL"
+ depends on DM_GPIO && TPL
+ help
+ Reset support via GPIO pin connected reset logic in TPL. This is used
+ for example on Microblaze where reset logic can be controlled via
+ GPIO pin which triggers cpu reset.
+
+config VPL_SYSRESET_GPIO
+ bool "Enable support for GPIO reset driver in VPL"
+ depends on DM_GPIO && VPL
+ help
+ Reset support via GPIO pin connected reset logic in VPL. This is used
+ for 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
diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile
index 796fc9effa5..ded91a4d325 100644
--- a/drivers/sysreset/Makefile
+++ b/drivers/sysreset/Makefile
@@ -8,8 +8,8 @@ obj-$(CONFIG_ARCH_ROCKCHIP) += sysreset_rockchip.o
obj-$(CONFIG_ARCH_STI) += sysreset_sti.o
obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o
obj-$(CONFIG_SYSRESET_CV1800B) += sysreset_cv1800b.o
-obj-$(CONFIG_POWEROFF_GPIO) += poweroff_gpio.o
-obj-$(CONFIG_SYSRESET_GPIO) += sysreset_gpio.o
+obj-$(CONFIG_$(PHASE_)POWEROFF_GPIO) += poweroff_gpio.o
+obj-$(CONFIG_$(PHASE_)SYSRESET_GPIO) += sysreset_gpio.o
obj-$(CONFIG_$(PHASE_)SYSRESET_MAX77663) += sysreset_max77663.o
obj-$(CONFIG_SYSRESET_MPC83XX) += sysreset_mpc83xx.o
obj-$(CONFIG_SYSRESET_MICROBLAZE) += sysreset_microblaze.o
diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
index 7a847e8388b..21db0d317fe 100644
--- a/drivers/timer/Makefile
+++ b/drivers/timer/Makefile
@@ -5,14 +5,14 @@
obj-y += timer-uclass.o
obj-$(CONFIG_ADI_SC5XX_TIMER) += adi_sc5xx_timer.o
obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o
-obj-$(CONFIG_$(XPL_)ANDES_PLMT_TIMER) += andes_plmt_timer.o
+obj-$(CONFIG_$(PHASE_)ANDES_PLMT_TIMER) += andes_plmt_timer.o
obj-$(CONFIG_ARC_TIMER) += arc_timer.o
obj-$(CONFIG_ARM_TWD_TIMER) += arm_twd_timer.o
obj-$(CONFIG_AST_TIMER) += ast_timer.o
obj-$(CONFIG_AST_IBEX_TIMER) += ast_ibex_timer.o
obj-$(CONFIG_ATCPIT100_TIMER) += atcpit100_timer.o
-obj-$(CONFIG_$(XPL_)ATMEL_PIT_TIMER) += atmel_pit_timer.o
-obj-$(CONFIG_$(XPL_)ATMEL_TCB_TIMER) += atmel_tcb_timer.o
+obj-$(CONFIG_$(PHASE_)ATMEL_PIT_TIMER) += atmel_pit_timer.o
+obj-$(CONFIG_$(PHASE_)ATMEL_TCB_TIMER) += atmel_tcb_timer.o
obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence-ttc.o
obj-$(CONFIG_DESIGNWARE_APB_TIMER) += dw-apb-timer.o
obj-$(CONFIG_FTTMR010_TIMER) += fttmr010_timer.o
@@ -27,7 +27,7 @@ obj-$(CONFIG_RISCV_TIMER) += riscv_timer.o
obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o
obj-$(CONFIG_SANDBOX_TIMER) += sandbox_timer.o
obj-$(CONFIG_SP804_TIMER) += sp804_timer.o
-obj-$(CONFIG_$(XPL_)RISCV_ACLINT) += riscv_aclint_timer.o
+obj-$(CONFIG_$(PHASE_)RISCV_ACLINT) += riscv_aclint_timer.o
obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o
obj-$(CONFIG_STM32_TIMER) += stm32_timer.o
obj-$(CONFIG_TEGRA_TIMER) += tegra-timer.o
diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c
index 08ec179346e..5b2d5ccb146 100644
--- a/drivers/tpm/cr50_i2c.c
+++ b/drivers/tpm/cr50_i2c.c
@@ -737,9 +737,13 @@ static int cr50_i2c_report_state(struct udevice *dev, char *str, int str_max)
static int cr50_i2c_open(struct udevice *dev)
{
+ struct cr50_priv *priv = dev_get_priv(dev);
char buf[80];
int ret;
+ if (priv->locality != -1)
+ return -EBUSY;
+
ret = process_reset(dev);
if (ret)
return log_msg_ret("reset", ret);
diff --git a/drivers/ufs/ufs-amd-versal2.c b/drivers/ufs/ufs-amd-versal2.c
index bfd844e4193..1c5ed538370 100644
--- a/drivers/ufs/ufs-amd-versal2.c
+++ b/drivers/ufs/ufs-amd-versal2.c
@@ -19,8 +19,6 @@
#include "ufshcd-dwc.h"
#include "ufshci-dwc.h"
-#define VERSAL2_UFS_DEVICE_ID 4
-
#define SRAM_CSR_INIT_DONE_MASK BIT(0)
#define SRAM_CSR_EXT_LD_DONE_MASK BIT(1)
#define SRAM_CSR_BYPASS_MASK BIT(2)
@@ -32,19 +30,12 @@
#define TIMEOUT_MICROSEC 1000000L
-#define IOCTL_UFS_TXRX_CFGRDY_GET 40
-#define IOCTL_UFS_SRAM_CSR_SEL 41
-
-#define PM_UFS_SRAM_CSR_WRITE 0
-#define PM_UFS_SRAM_CSR_READ 1
-
struct ufs_versal2_priv {
struct ufs_hba *hba;
struct reset_ctl *rstc;
struct reset_ctl *rstphy;
u32 phy_mode;
u32 host_clk;
- u32 pd_dev_id;
u8 attcompval0;
u8 attcompval1;
u8 ctlecompval0;
@@ -102,41 +93,6 @@ static int ufs_versal2_phy_reg_read(struct ufs_hba *hba, u32 addr, u32 *val)
return 0;
}
-int versal2_pm_ufs_get_txrx_cfgrdy(u32 node_id, u32 *value)
-{
- u32 ret_payload[PAYLOAD_ARG_CNT];
- int ret;
-
- if (!value)
- return -EINVAL;
-
- ret = xilinx_pm_request(PM_IOCTL, node_id, IOCTL_UFS_TXRX_CFGRDY_GET,
- 0, 0, ret_payload);
- *value = ret_payload[1];
-
- return ret;
-}
-
-int versal2_pm_ufs_sram_csr_sel(u32 node_id, u32 type, u32 *value)
-{
- u32 ret_payload[PAYLOAD_ARG_CNT];
- int ret;
-
- if (!value)
- return -EINVAL;
-
- if (type == PM_UFS_SRAM_CSR_READ) {
- ret = xilinx_pm_request(PM_IOCTL, node_id, IOCTL_UFS_SRAM_CSR_SEL,
- type, 0, ret_payload);
- *value = ret_payload[1];
- } else {
- ret = xilinx_pm_request(PM_IOCTL, node_id, IOCTL_UFS_SRAM_CSR_SEL,
- type, *value, 0);
- }
-
- return ret;
-}
-
static int ufs_versal2_enable_phy(struct ufs_hba *hba)
{
u32 offset, reg;
@@ -281,7 +237,7 @@ static int ufs_versal2_phy_init(struct ufs_hba *hba)
time_left = TIMEOUT_MICROSEC;
do {
time_left--;
- ret = versal2_pm_ufs_get_txrx_cfgrdy(priv->pd_dev_id, &reg);
+ ret = zynqmp_pm_ufs_get_txrx_cfgrdy(&reg);
if (ret)
return ret;
@@ -312,8 +268,7 @@ static int ufs_versal2_phy_init(struct ufs_hba *hba)
time_left = TIMEOUT_MICROSEC;
do {
time_left--;
- ret = versal2_pm_ufs_sram_csr_sel(priv->pd_dev_id,
- PM_UFS_SRAM_CSR_READ, &reg);
+ ret = zynqmp_pm_ufs_sram_csr_read(&reg);
if (ret)
return ret;
@@ -341,10 +296,10 @@ static int ufs_versal2_init(struct ufs_hba *hba)
struct ufs_versal2_priv *priv = dev_get_priv(hba->dev);
struct clk clk;
unsigned long core_clk_rate = 0;
+ u32 cal;
int ret = 0;
priv->phy_mode = UFSHCD_DWC_PHY_MODE_ROM;
- priv->pd_dev_id = VERSAL2_UFS_DEVICE_ID;
ret = clk_get_by_name(hba->dev, "core_clk", &clk);
if (ret) {
@@ -371,6 +326,15 @@ static int ufs_versal2_init(struct ufs_hba *hba)
return PTR_ERR(priv->rstphy);
}
+ ret = zynqmp_pm_ufs_cal_reg(&cal);
+ if (ret)
+ return ret;
+
+ priv->attcompval0 = (u8)cal;
+ priv->attcompval1 = (u8)(cal >> 8);
+ priv->ctlecompval0 = (u8)(cal >> 16);
+ priv->ctlecompval1 = (u8)(cal >> 24);
+
return ret;
}
@@ -397,8 +361,7 @@ static int ufs_versal2_hce_enable_notify(struct ufs_hba *hba,
return ret;
}
- ret = versal2_pm_ufs_sram_csr_sel(priv->pd_dev_id,
- PM_UFS_SRAM_CSR_READ, &sram_csr);
+ ret = zynqmp_pm_ufs_sram_csr_read(&sram_csr);
if (ret)
return ret;
@@ -410,8 +373,7 @@ static int ufs_versal2_hce_enable_notify(struct ufs_hba *hba,
return -EINVAL;
}
- ret = versal2_pm_ufs_sram_csr_sel(priv->pd_dev_id,
- PM_UFS_SRAM_CSR_WRITE, &sram_csr);
+ ret = zynqmp_pm_ufs_sram_csr_write(&sram_csr);
if (ret)
return ret;
diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile
index 1f00f23f704..dea5316599b 100644
--- a/drivers/usb/cdns3/Makefile
+++ b/drivers/usb/cdns3/Makefile
@@ -4,9 +4,9 @@ cdns3-y := core.o drd.o
obj-$(CONFIG_USB_CDNS3) += cdns3.o
-cdns3-$(CONFIG_$(XPL_)USB_CDNS3_GADGET) += gadget.o ep0.o
+cdns3-$(CONFIG_$(PHASE_)USB_CDNS3_GADGET) += gadget.o ep0.o
-cdns3-$(CONFIG_$(XPL_)USB_CDNS3_HOST) += host.o
+cdns3-$(CONFIG_$(PHASE_)USB_CDNS3_HOST) += host.o
obj-$(CONFIG_USB_CDNS3_STARFIVE) += cdns3-starfive.o
obj-$(CONFIG_USB_CDNS3_TI) += cdns3-ti.o
diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile
index 11cc4657a0f..4c597c166c6 100644
--- a/drivers/usb/common/Makefile
+++ b/drivers/usb/common/Makefile
@@ -3,7 +3,7 @@
# (C) Copyright 2016 Freescale Semiconductor, Inc.
#
-obj-$(CONFIG_$(XPL_)DM_USB) += common.o
+obj-$(CONFIG_$(PHASE_)DM_USB) += common.o
obj-$(CONFIG_USB_ISP1760) += usb_urb.o
obj-$(CONFIG_USB_MUSB_HOST) += usb_urb.o
obj-$(CONFIG_USB_MUSB_GADGET) += usb_urb.o
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 985206eafe4..a619cd374fb 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -6,11 +6,11 @@ dwc3-y := core.o
obj-$(CONFIG_USB_DWC3_GADGET) += gadget.o ep0.o
-obj-$(CONFIG_$(XPL_)USB_DWC3_AM62) += dwc3-am62.o
+obj-$(CONFIG_$(PHASE_)USB_DWC3_AM62) += dwc3-am62.o
obj-$(CONFIG_USB_DWC3_OMAP) += dwc3-omap.o
obj-$(CONFIG_USB_DWC3_MESON_G12A) += dwc3-meson-g12a.o
obj-$(CONFIG_USB_DWC3_MESON_GXL) += dwc3-meson-gxl.o
-obj-$(CONFIG_$(XPL_)USB_DWC3_GENERIC) += dwc3-generic.o
+obj-$(CONFIG_$(PHASE_)USB_DWC3_GENERIC) += dwc3-generic.o
obj-$(CONFIG_USB_DWC3_UNIPHIER) += dwc3-uniphier.o
obj-$(CONFIG_USB_DWC3_LAYERSCAPE) += dwc3-layerscape.o
obj-$(CONFIG_USB_DWC3_PHY_OMAP) += ti_usb_phy.o
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 477ecd02098..2b01113d54c 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1635,7 +1635,7 @@ usb_ep *dwc3_gadget_match_ep(struct usb_gadget *gadget,
/*
* Special workaround for NXP UUU tool in SPL.
*
- * The tool excepts the interrupt-in endpoint to be ep1in,
+ * The tool expects the interrupt-in endpoint to be ep1in,
* otherwise it crashes. This is a result of the previous
* hard-coded EP setup in drivers/usb/gadget/epautoconf.c
* which did special-case EP allocation for SPL builds,
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index a77037a7094..f9326f0a7e7 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -1443,6 +1443,7 @@ static const struct udevice_id usba_udc_ids[] = {
{ .compatible = "atmel,at91sam9rl-udc" },
{ .compatible = "atmel,at91sam9g45-udc" },
{ .compatible = "atmel,sama5d3-udc" },
+ { .compatible = "microchip,sam9x60-udc" },
{}
};
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index d3fc4acb401..71dc58da3f0 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -284,7 +284,6 @@ static const char fsg_string_interface[] = "Mass Storage";
#define kthread_create(...) __builtin_return_address(0)
#define wait_for_completion(...) do {} while (0)
-struct kref {int x; };
struct completion {int x; };
struct fsg_dev;
@@ -345,8 +344,6 @@ struct fsg_common {
/* Vendor (8 chars), product (16 chars), release (4
* hexadecimal digits) and NUL byte */
char inquiry_string[8 + 16 + 4 + 1];
-
- struct kref ref;
};
struct fsg_config {
@@ -2436,7 +2433,7 @@ int fsg_main_thread(void *common_)
return 0;
}
-static void fsg_common_release(struct kref *ref);
+static void fsg_common_release(struct fsg_common *common);
static struct fsg_common *fsg_common_init(struct fsg_common *common,
struct usb_composite_dev *cdev)
@@ -2548,16 +2545,12 @@ error_luns:
common->nluns = i + 1;
error_release:
common->state = FSG_STATE_TERMINATED; /* The thread is dead */
- /* Call fsg_common_release() directly, ref might be not
- * initialised */
- fsg_common_release(&common->ref);
+ fsg_common_release(common);
return ERR_PTR(rc);
}
-static void fsg_common_release(struct kref *ref)
+static void fsg_common_release(struct fsg_common *common)
{
- struct fsg_common *common = container_of(ref, struct fsg_common, ref);
-
/* If the thread isn't already dead, tell it to exit now */
if (common->state != FSG_STATE_TERMINATED) {
raise_exception(common, FSG_STATE_EXIT);
@@ -2571,8 +2564,6 @@ static void fsg_common_release(struct kref *ref)
/* In error recovery common->nluns may be zero. */
for (; i; --i, ++lun)
fsg_lun_close(lun);
-
- kfree(common->luns);
}
{
@@ -2648,6 +2639,7 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
}
+ fsg_common_release(fsg->common);
free(fsg->function.descriptors);
free(fsg->function.hs_descriptors);
kfree(fsg);
@@ -2751,6 +2743,8 @@ int fsg_add(struct usb_configuration *c)
struct fsg_common *fsg_common;
fsg_common = fsg_common_init(NULL, c->cdev);
+ if (IS_ERR(fsg_common))
+ return PTR_ERR(fsg_common);
fsg_common->vendor_name = 0;
fsg_common->product_name = 0;
diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile
index 4b6a8fdfeee..56b9b123fa1 100644
--- a/drivers/usb/gadget/udc/Makefile
+++ b/drivers/usb/gadget/udc/Makefile
@@ -2,9 +2,9 @@
#
# USB peripheral controller drivers
-ifndef CONFIG_$(XPL_)DM_USB_GADGET
+ifndef CONFIG_$(PHASE_)DM_USB_GADGET
obj-$(CONFIG_USB_DWC3_GADGET) += udc-core.o
endif
-obj-$(CONFIG_$(XPL_)DM_USB_GADGET) += udc-core.o
+obj-$(CONFIG_$(PHASE_)DM_USB_GADGET) += udc-core.o
obj-y += udc-uclass.o
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 902d68d0378..ef4ce62a680 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -3,7 +3,7 @@
# (C) Copyright 2000-2007
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
-ifdef CONFIG_$(XPL_)DM_USB
+ifdef CONFIG_$(PHASE_)DM_USB
obj-y += usb-uclass.o
obj-$(CONFIG_SANDBOX) += usb-sandbox.o
endif
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index df607303616..73353944971 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -529,6 +529,16 @@ config VIDEO_LCD_HIMAX_HX8394
Say Y here if you want to enable support for Himax HX8394
dsi 4dl panel.
+config VIDEO_LCD_MOT
+ tristate "Atrix 4G and Droid X2 540x960 DSI video mode panel"
+ depends on PANEL && BACKLIGHT
+ select VIDEO_MIPI_DSI
+ help
+ Say Y here if you want to enable support for the LCD panel module for
+ Motorola Atrix 4G or Droid X2. Exact panel vendor and model are
+ unknown. The panel has a 540x960 resolution and uses 24 bit RGB per
+ pixel.
+
config VIDEO_LCD_ORISETECH_OTM8009A
bool "OTM8009A DSI LCD panel support"
select VIDEO_MIPI_DSI
@@ -728,6 +738,15 @@ config ATMEL_HLCD
help
HLCDC supports video output to an attached LCD panel.
+config BACKLIGHT_LM3532
+ bool "Backlight Driver for LM3532"
+ depends on BACKLIGHT
+ select DM_I2C
+ help
+ Say Y to enable the backlight driver for National Semiconductor / TI
+ LM3532 Lighting Power chip. Only backlight functions is supported as
+ for now. Supported backlight level range is from 1 to 255.
+
config BACKLIGHT_LM3533
bool "Backlight Driver for LM3533"
depends on BACKLIGHT
@@ -809,17 +828,9 @@ source "drivers/video/stm32/Kconfig"
source "drivers/video/tidss/Kconfig"
-config VIDEO_TEGRA124
- bool "Enable video support on Tegra124"
- help
- Tegra124 supports many video output options including eDP and
- HDMI. At present only eDP is supported by U-Boot. This option
- enables this support which can be used on devices which
- have an eDP display connected.
-
source "drivers/video/bridge/Kconfig"
-source "drivers/video/tegra20/Kconfig"
+source "drivers/video/tegra/Kconfig"
source "drivers/video/imx/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 6073bc5234a..fbdb058647a 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -29,13 +29,13 @@ obj-$(CONFIG_$(PHASE_)BMP) += bmp.o
endif
+obj-$(CONFIG_BACKLIGHT_LM3532) += lm3532_backlight.o
obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_backlight.o
obj-$(CONFIG_BACKLIGHT_LP855x) += lp855x_backlight.o
obj-${CONFIG_EXYNOS_FB} += exynos/
obj-${CONFIG_VIDEO_ROCKCHIP} += rockchip/
obj-${CONFIG_VIDEO_STM32} += stm32/
-obj-${CONFIG_VIDEO_TEGRA124} += tegra124/
-obj-${CONFIG_$(XPL_)VIDEO_TIDSS} += tidss/
+obj-${CONFIG_$(PHASE_)VIDEO_TIDSS} += tidss/
obj-y += ti/
obj-$(CONFIG_ATMEL_HLCD) += atmel_hlcdfb.o
@@ -53,13 +53,14 @@ obj-$(CONFIG_VIDEO_COREBOOT) += coreboot.o
obj-$(CONFIG_VIDEO_DW_HDMI) += dw_hdmi.o
obj-$(CONFIG_VIDEO_DW_MIPI_DSI) += dw_mipi_dsi.o
obj-$(CONFIG_VIDEO_EFI) += efi.o
-obj-$(CONFIG_VIDEO_IPUV3) += imx/
+obj-y += imx/
obj-$(CONFIG_VIDEO_IVYBRIDGE_IGD) += ivybridge_igd.o
obj-$(CONFIG_VIDEO_LCD_ANX9804) += anx9804.o
obj-$(CONFIG_VIDEO_LCD_ENDEAVORU) += endeavoru-panel.o
obj-$(CONFIG_VIDEO_LCD_HIMAX_HX8394) += himax-hx8394.o
obj-$(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM) += hitachi_tx18d42vm_lcd.o
obj-$(CONFIG_VIDEO_LCD_LG_LD070WX3) += lg-ld070wx3.o
+obj-$(CONFIG_VIDEO_LCD_MOT) += mot-panel.o
obj-$(CONFIG_VIDEO_LCD_ORISETECH_OTM8009A) += orisetech_otm8009a.o
obj-$(CONFIG_VIDEO_LCD_RAYDIUM_RM68200) += raydium-rm68200.o
obj-$(CONFIG_VIDEO_LCD_RENESAS_R61307) += renesas-r61307.o
@@ -85,4 +86,4 @@ obj-$(CONFIG_VIDEO_ZYNQMP_DPSUB) += zynqmp/
obj-y += bridge/
obj-y += sunxi/
-obj-y += tegra20/
+obj-y += tegra/
diff --git a/drivers/video/imx/Kconfig b/drivers/video/imx/Kconfig
index 34e8b640595..12f11c2eea8 100644
--- a/drivers/video/imx/Kconfig
+++ b/drivers/video/imx/Kconfig
@@ -13,3 +13,12 @@ config IMX_VIDEO_SKIP
config IMX_HDMI
bool "Enable HDMI support in IPUv3"
depends on VIDEO_IPUV3
+
+config IMX_LDB
+ bool "Freescale i.MX8MP LDB bridge"
+ depends on VIDEO_BRIDGE
+ help
+ Support for i.MX8MP DPI-to-LVDS on-SoC encoder.
+
+config IMX_LCDIF
+ bool "i.MX LCDIFv3 LCD controller"
diff --git a/drivers/video/imx/Makefile b/drivers/video/imx/Makefile
index 179ea651fe8..1edf5a6bdf0 100644
--- a/drivers/video/imx/Makefile
+++ b/drivers/video/imx/Makefile
@@ -3,4 +3,6 @@
# (C) Copyright 2000-2007
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
-obj-y += mxc_ipuv3_fb.o ipu_common.o ipu_disp.o
+obj-$(CONFIG_VIDEO_IPUV3) += mxc_ipuv3_fb.o ipu_common.o ipu_disp.o
+obj-$(CONFIG_IMX_LDB) += ldb.o
+obj-$(CONFIG_IMX_LCDIF) += lcdif.o
diff --git a/drivers/video/imx/lcdif.c b/drivers/video/imx/lcdif.c
new file mode 100644
index 00000000000..9f4fc7f5152
--- /dev/null
+++ b/drivers/video/imx/lcdif.c
@@ -0,0 +1,314 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * i.MX8 LCD interface driver inspired from the Linux driver
+ * Copyright 2019 NXP
+ * Copyright 2024 Bootlin
+ * Adapted by Miquel Raynal <miquel.raynal@bootlin.com>
+ */
+
+#include <asm/io.h>
+#include <asm/mach-imx/dma.h>
+#include <clk.h>
+#include <dm.h>
+#include <panel.h>
+#include <power-domain.h>
+#include <video.h>
+#include <video_bridge.h>
+#include <linux/delay.h>
+
+#include "../videomodes.h"
+
+#define LCDIFV3_CTRL 0x0
+#define LCDIFV3_CTRL_SET 0x4
+#define LCDIFV3_CTRL_CLR 0x8
+#define CTRL_INV_HS BIT(0)
+#define CTRL_INV_VS BIT(1)
+#define CTRL_INV_DE BIT(2)
+#define CTRL_INV_PXCK BIT(3)
+#define CTRL_CLK_GATE BIT(30)
+#define CTRL_SW_RESET BIT(31)
+
+#define LCDIFV3_DISP_PARA 0x10
+#define DISP_PARA_DISP_MODE_NORMAL 0
+#define DISP_PARA_LINE_PATTERN_RGB_YUV 0
+#define DISP_PARA_DISP_ON BIT(31)
+
+#define LCDIFV3_DISP_SIZE 0x14
+#define DISP_SIZE_DELTA_X(x) ((x) & 0xffff)
+#define DISP_SIZE_DELTA_Y(x) ((x) << 16)
+
+#define LCDIFV3_HSYN_PARA 0x18
+#define HSYN_PARA_FP_H(x) ((x) & 0xffff)
+#define HSYN_PARA_BP_H(x) ((x) << 16)
+
+#define LCDIFV3_VSYN_PARA 0x1C
+#define VSYN_PARA_FP_V(x) ((x) & 0xffff)
+#define VSYN_PARA_BP_V(x) ((x) << 16)
+
+#define LCDIFV3_VSYN_HSYN_WIDTH 0x20
+#define VSYN_HSYN_PW_H(x) ((x) & 0xffff)
+#define VSYN_HSYN_PW_V(x) ((x) << 16)
+
+#define LCDIFV3_CTRLDESCL0_1 0x200
+#define CTRLDESCL0_1_WIDTH(x) ((x) & 0xffff)
+#define CTRLDESCL0_1_HEIGHT(x) ((x) << 16)
+
+#define LCDIFV3_CTRLDESCL0_3 0x208
+#define CTRLDESCL0_3_PITCH(x) ((x) & 0xFFFF)
+
+#define LCDIFV3_CTRLDESCL_LOW0_4 0x20C
+#define LCDIFV3_CTRLDESCL_HIGH0_4 0x210
+
+#define LCDIFV3_CTRLDESCL0_5 0x214
+#define CTRLDESCL0_5_YUV_FORMAT(x) (((x) & 0x3) << 14)
+#define CTRLDESCL0_5_BPP(x) (((x) & 0xf) << 24)
+#define BPP32_ARGB8888 0x9
+#define CTRLDESCL0_5_SHADOW_LOAD_EN BIT(30)
+#define CTRLDESCL0_5_EN BIT(31)
+
+struct lcdifv3_priv {
+ void __iomem *base;
+ struct clk pix_clk;
+ struct power_domain pd;
+ struct udevice *panel;
+ struct udevice *bridge;
+};
+
+static void lcdifv3_set_mode(struct lcdifv3_priv *priv,
+ struct display_timing *timings)
+{
+ u32 reg;
+
+ writel(DISP_SIZE_DELTA_X(timings->hactive.typ) |
+ DISP_SIZE_DELTA_Y(timings->vactive.typ),
+ priv->base + LCDIFV3_DISP_SIZE);
+
+ writel(HSYN_PARA_FP_H(timings->hfront_porch.typ) |
+ HSYN_PARA_BP_H(timings->hback_porch.typ),
+ priv->base + LCDIFV3_HSYN_PARA);
+
+ writel(VSYN_PARA_BP_V(timings->vback_porch.typ) |
+ VSYN_PARA_FP_V(timings->vfront_porch.typ),
+ priv->base + LCDIFV3_VSYN_PARA);
+
+ writel(VSYN_HSYN_PW_H(timings->hsync_len.typ) |
+ VSYN_HSYN_PW_V(timings->vsync_len.typ),
+ priv->base + LCDIFV3_VSYN_HSYN_WIDTH);
+
+ writel(CTRLDESCL0_1_WIDTH(timings->hactive.typ) |
+ CTRLDESCL0_1_HEIGHT(timings->vactive.typ),
+ priv->base + LCDIFV3_CTRLDESCL0_1);
+
+ if (timings->flags & DISPLAY_FLAGS_HSYNC_LOW)
+ writel(CTRL_INV_HS, priv->base + LCDIFV3_CTRL_SET);
+ else
+ writel(CTRL_INV_HS, priv->base + LCDIFV3_CTRL_CLR);
+
+ if (timings->flags & DISPLAY_FLAGS_VSYNC_LOW)
+ writel(CTRL_INV_VS, priv->base + LCDIFV3_CTRL_SET);
+ else
+ writel(CTRL_INV_VS, priv->base + LCDIFV3_CTRL_CLR);
+
+ if (timings->flags & DISPLAY_FLAGS_DE_LOW)
+ writel(CTRL_INV_DE, priv->base + LCDIFV3_CTRL_SET);
+ else
+ writel(CTRL_INV_DE, priv->base + LCDIFV3_CTRL_CLR);
+
+ if (timings->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
+ writel(CTRL_INV_PXCK, priv->base + LCDIFV3_CTRL_SET);
+ else
+ writel(CTRL_INV_PXCK, priv->base + LCDIFV3_CTRL_CLR);
+
+ writel(0, priv->base + LCDIFV3_DISP_PARA);
+
+ reg = readl(priv->base + LCDIFV3_CTRLDESCL0_5);
+ reg &= ~(CTRLDESCL0_5_BPP(0xf) | CTRLDESCL0_5_YUV_FORMAT(0x3));
+ reg |= CTRLDESCL0_5_BPP(BPP32_ARGB8888);
+ writel(reg, priv->base + LCDIFV3_CTRLDESCL0_5);
+}
+
+static void lcdifv3_enable_controller(struct lcdifv3_priv *priv)
+{
+ u32 reg;
+
+ reg = readl(priv->base + LCDIFV3_DISP_PARA);
+ reg |= DISP_PARA_DISP_ON;
+ writel(reg, priv->base + LCDIFV3_DISP_PARA);
+
+ reg = readl(priv->base + LCDIFV3_CTRLDESCL0_5);
+ reg |= CTRLDESCL0_5_EN;
+ writel(reg, priv->base + LCDIFV3_CTRLDESCL0_5);
+}
+
+static int lcdifv3_video_sync(struct udevice *dev)
+{
+ struct lcdifv3_priv *priv = dev_get_priv(dev);
+ u32 reg;
+
+ reg = readl(priv->base + LCDIFV3_CTRLDESCL0_5);
+ reg |= CTRLDESCL0_5_SHADOW_LOAD_EN;
+ writel(reg, priv->base + LCDIFV3_CTRLDESCL0_5);
+
+ return 0;
+}
+
+static void lcdifv3_init(struct udevice *dev, struct display_timing *timings)
+{
+ struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+ struct lcdifv3_priv *priv = dev_get_priv(dev);
+
+ clk_set_rate(&priv->pix_clk, timings->pixelclock.typ);
+
+ writel(CTRL_SW_RESET | CTRL_CLK_GATE, priv->base + LCDIFV3_CTRL_CLR);
+ udelay(10);
+
+ lcdifv3_set_mode(priv, timings);
+
+ writel(plat->base & 0xFFFFFFFF, priv->base + LCDIFV3_CTRLDESCL_LOW0_4);
+ writel(plat->base >> 32, priv->base + LCDIFV3_CTRLDESCL_HIGH0_4);
+
+ writel(CTRLDESCL0_3_PITCH(timings->hactive.typ * 4), /* 32bpp */
+ priv->base + LCDIFV3_CTRLDESCL0_3);
+
+ lcdifv3_enable_controller(priv);
+}
+
+static int lcdifv3_video_probe(struct udevice *dev)
+{
+ struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+ struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct lcdifv3_priv *priv = dev_get_priv(dev);
+ struct clk axi_clk, disp_axi_clk;
+ struct display_timing timings;
+ u32 fb_start, fb_end;
+ int ret;
+
+ ret = power_domain_get(dev, &priv->pd);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_get_by_name(dev, "pix", &priv->pix_clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_get_by_name(dev, "axi", &axi_clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_get_by_name(dev, "disp_axi", &disp_axi_clk);
+ if (ret < 0)
+ return ret;
+
+ ret = power_domain_on(&priv->pd);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&priv->pix_clk);
+ if (ret)
+ goto dis_pd;
+
+ ret = clk_enable(&axi_clk);
+ if (ret)
+ goto dis_pix_clk;
+
+ ret = clk_enable(&disp_axi_clk);
+ if (ret)
+ goto dis_axi_clk;
+
+ priv->base = dev_remap_addr(dev);
+ if (!priv->base) {
+ ret = -EINVAL;
+ goto dis_clks;
+ }
+
+ /* Attach bridge */
+ ret = uclass_get_device_by_endpoint(UCLASS_VIDEO_BRIDGE, dev,
+ -1, -1, &priv->bridge);
+ if (ret)
+ goto dis_clks;
+
+ ret = video_bridge_attach(priv->bridge);
+ if (ret)
+ goto dis_clks;
+
+ ret = video_bridge_set_backlight(priv->bridge, 80);
+ if (ret)
+ goto dis_clks;
+
+ /* Attach panels */
+ ret = uclass_get_device_by_endpoint(UCLASS_PANEL, priv->bridge,
+ 1, -1, &priv->panel);
+ if (ret) {
+ ret = uclass_get_device_by_endpoint(UCLASS_PANEL, priv->bridge,
+ 2, -1, &priv->panel);
+ if (ret)
+ goto dis_clks;
+ }
+
+ ret = panel_get_display_timing(priv->panel, &timings);
+ if (ret) {
+ ret = ofnode_decode_display_timing(dev_ofnode(priv->panel),
+ 0, &timings);
+ if (ret) {
+ printf("Cannot decode panel timings (%d)\n", ret);
+ goto dis_clks;
+ }
+ }
+
+ lcdifv3_init(dev, &timings);
+
+ /* Only support 32bpp for now */
+ uc_priv->bpix = VIDEO_BPP32;
+ uc_priv->xsize = timings.hactive.typ;
+ uc_priv->ysize = timings.vactive.typ;
+
+ /* Enable dcache for the frame buffer */
+ fb_start = plat->base & ~(MMU_SECTION_SIZE - 1);
+ fb_end = ALIGN(plat->base + plat->size, 1 << MMU_SECTION_SHIFT);
+ mmu_set_region_dcache_behaviour(fb_start, fb_end - fb_start,
+ DCACHE_WRITEBACK);
+ video_set_flush_dcache(dev, true);
+
+ return 0;
+
+dis_clks:
+ clk_disable(&disp_axi_clk);
+dis_axi_clk:
+ clk_disable(&axi_clk);
+dis_pix_clk:
+ clk_disable(&priv->pix_clk);
+dis_pd:
+ power_domain_off(&priv->pd);
+
+ return ret;
+}
+
+static int lcdifv3_video_bind(struct udevice *dev)
+{
+ struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+
+ /* Max size supported by LCDIF */
+ plat->size = 1920 * 1080 * VNBYTES(VIDEO_BPP32);
+
+ return 0;
+}
+
+static const struct udevice_id lcdifv3_video_ids[] = {
+ { .compatible = "fsl,imx8mp-lcdif" },
+ { }
+};
+
+static struct video_ops lcdifv3_video_ops = {
+ .video_sync = lcdifv3_video_sync,
+};
+
+U_BOOT_DRIVER(lcdifv3_video) = {
+ .name = "lcdif",
+ .id = UCLASS_VIDEO,
+ .of_match = lcdifv3_video_ids,
+ .bind = lcdifv3_video_bind,
+ .ops = &lcdifv3_video_ops,
+ .probe = lcdifv3_video_probe,
+ .priv_auto = sizeof(struct lcdifv3_priv),
+ .flags = DM_FLAG_PRE_RELOC | DM_FLAG_OS_PREPARE,
+};
diff --git a/drivers/video/imx/ldb.c b/drivers/video/imx/ldb.c
new file mode 100644
index 00000000000..e918341c0a3
--- /dev/null
+++ b/drivers/video/imx/ldb.c
@@ -0,0 +1,251 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Derived work from:
+ * Philippe Cornu <philippe.cornu@st.com>
+ * Yannick Fertre <yannick.fertre@st.com>
+ * Adapted by Miquel Raynal <miquel.raynal@bootlin.com>
+ */
+
+#define LOG_CATEGORY UCLASS_VIDEO_BRIDGE
+
+#include <clk.h>
+#include <dm.h>
+#include <log.h>
+#include <panel.h>
+#include <video_bridge.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+
+#define LDB_CTRL_CH0_ENABLE BIT(0)
+#define LDB_CTRL_CH1_ENABLE BIT(2)
+#define LDB_CTRL_CH0_DATA_WIDTH BIT(5)
+#define LDB_CTRL_CH0_BIT_MAPPING BIT(6)
+#define LDB_CTRL_CH1_DATA_WIDTH BIT(7)
+#define LDB_CTRL_CH1_BIT_MAPPING BIT(8)
+#define LDB_CTRL_DI0_VSYNC_POLARITY BIT(9)
+#define LDB_CTRL_DI1_VSYNC_POLARITY BIT(10)
+
+#define LVDS_CTRL_CH0_EN BIT(0)
+#define LVDS_CTRL_CH1_EN BIT(1)
+#define LVDS_CTRL_VBG_EN BIT(2)
+#define LVDS_CTRL_PRE_EMPH_EN BIT(4)
+#define LVDS_CTRL_PRE_EMPH_ADJ(n) (((n) & 0x7) << 5)
+#define LVDS_CTRL_CC_ADJ(n) (((n) & 0x7) << 11)
+
+struct imx_ldb_priv {
+ struct clk ldb_clk;
+ void __iomem *ldb_ctrl;
+ void __iomem *lvds_ctrl;
+ struct udevice *lvds1;
+ struct udevice *lvds2;
+};
+
+static int imx_ldb_set_backlight(struct udevice *dev, int percent)
+{
+ struct imx_ldb_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ if (priv->lvds1) {
+ ret = panel_enable_backlight(priv->lvds1);
+ if (ret) {
+ debug("ldb: Cannot enable lvds1 backlight\n");
+ return ret;
+ }
+
+ ret = panel_set_backlight(priv->lvds1, percent);
+ if (ret)
+ return ret;
+ }
+
+ if (priv->lvds2) {
+ ret = panel_enable_backlight(priv->lvds2);
+ if (ret) {
+ debug("ldb: Cannot enable lvds2 backlight\n");
+ return ret;
+ }
+
+ ret = panel_set_backlight(priv->lvds2, percent);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int imx_ldb_of_to_plat(struct udevice *dev)
+{
+ struct imx_ldb_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ uclass_get_device_by_endpoint(UCLASS_PANEL, dev, 1, -1, &priv->lvds1);
+ uclass_get_device_by_endpoint(UCLASS_PANEL, dev, 2, -1, &priv->lvds2);
+ if (!priv->lvds1 && !priv->lvds2) {
+ debug("ldb: No remote panel for '%s' (ret=%d)\n",
+ dev_read_name(dev), ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/* The block has a mysterious x7 internal divisor (x3.5 in dual configuration) */
+#define IMX_LDB_INTERNAL_DIVISOR(x) (((x) * 70) / 10)
+#define IMX_LDB_INTERNAL_DIVISOR_DUAL(x) (((x) * 35) / 10)
+
+static ulong imx_ldb_input_rate(struct imx_ldb_priv *priv,
+ struct display_timing *timings)
+{
+ ulong target_rate = timings->pixelclock.typ;
+
+ if (priv->lvds1 && priv->lvds2)
+ return IMX_LDB_INTERNAL_DIVISOR_DUAL(target_rate);
+
+ return IMX_LDB_INTERNAL_DIVISOR(target_rate);
+}
+
+static int imx_ldb_attach(struct udevice *dev)
+{
+ struct imx_ldb_priv *priv = dev_get_priv(dev);
+ struct display_timing timings;
+ bool format_jeida = false;
+ bool format_24bpp = true;
+ u32 ldb_ctrl = 0, lvds_ctrl;
+ ulong ldb_rate;
+ int ret;
+
+ /* TODO: update the 24bpp/jeida booleans with proper checks when they
+ * will be supported.
+ */
+ if (priv->lvds1) {
+ ret = panel_get_display_timing(priv->lvds1, &timings);
+ if (ret) {
+ ret = ofnode_decode_display_timing(dev_ofnode(priv->lvds1),
+ 0, &timings);
+ if (ret) {
+ printf("Cannot decode lvds1 timings (%d)\n", ret);
+ return ret;
+ }
+ }
+
+ ldb_ctrl |= LDB_CTRL_CH0_ENABLE;
+ if (format_24bpp)
+ ldb_ctrl |= LDB_CTRL_CH0_DATA_WIDTH;
+ if (format_jeida)
+ ldb_ctrl |= LDB_CTRL_CH0_BIT_MAPPING;
+ if (timings.flags & DISPLAY_FLAGS_VSYNC_HIGH)
+ ldb_ctrl |= LDB_CTRL_DI0_VSYNC_POLARITY;
+ }
+
+ if (priv->lvds2) {
+ ret = panel_get_display_timing(priv->lvds2, &timings);
+ if (ret) {
+ ret = ofnode_decode_display_timing(dev_ofnode(priv->lvds2),
+ 0, &timings);
+ if (ret) {
+ printf("Cannot decode lvds2 timings (%d)\n", ret);
+ return ret;
+ }
+ }
+
+ ldb_ctrl |= LDB_CTRL_CH1_ENABLE;
+ if (format_24bpp)
+ ldb_ctrl |= LDB_CTRL_CH1_DATA_WIDTH;
+ if (format_jeida)
+ ldb_ctrl |= LDB_CTRL_CH1_BIT_MAPPING;
+ if (timings.flags & DISPLAY_FLAGS_VSYNC_HIGH)
+ ldb_ctrl |= LDB_CTRL_DI1_VSYNC_POLARITY;
+ }
+
+ /*
+ * Not all pixel clocks will work, as the final rate (after internal
+ * integer division) should be identical to the LCDIF clock, otherwise
+ * the rendering will appear resized/shimmering.
+ */
+ ldb_rate = imx_ldb_input_rate(priv, &timings);
+ clk_set_rate(&priv->ldb_clk, ldb_rate);
+
+ writel(ldb_ctrl, priv->ldb_ctrl);
+
+ lvds_ctrl = LVDS_CTRL_CC_ADJ(2) | LVDS_CTRL_PRE_EMPH_EN |
+ LVDS_CTRL_PRE_EMPH_ADJ(3) | LVDS_CTRL_VBG_EN;
+ writel(lvds_ctrl, priv->lvds_ctrl);
+
+ /* Wait for VBG to stabilize. */
+ udelay(15);
+
+ if (priv->lvds1)
+ lvds_ctrl |= LVDS_CTRL_CH0_EN;
+ if (priv->lvds2)
+ lvds_ctrl |= LVDS_CTRL_CH1_EN;
+
+ writel(lvds_ctrl, priv->lvds_ctrl);
+
+ return 0;
+}
+
+static int imx_ldb_probe(struct udevice *dev)
+{
+ struct imx_ldb_priv *priv = dev_get_priv(dev);
+ struct udevice *parent = dev_get_parent(dev);
+ fdt_addr_t parent_addr, child_addr;
+ int ret;
+
+ ret = clk_get_by_name(dev, "ldb", &priv->ldb_clk);
+ if (ret < 0)
+ return ret;
+
+ parent_addr = dev_read_addr(parent);
+ if (parent_addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ child_addr = dev_read_addr_name(dev, "ldb");
+ if (child_addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->ldb_ctrl = map_physmem(parent_addr + child_addr, 0, MAP_NOCACHE);
+ if (!priv->ldb_ctrl)
+ return -EINVAL;
+
+ child_addr = dev_read_addr_name(dev, "lvds");
+ if (child_addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->lvds_ctrl = map_physmem(parent_addr + child_addr, 0, MAP_NOCACHE);
+ if (!priv->lvds_ctrl)
+ return -EINVAL;
+
+ ret = clk_enable(&priv->ldb_clk);
+ if (ret)
+ return ret;
+
+ ret = video_bridge_set_active(dev, true);
+ if (ret)
+ goto dis_clk;
+
+ return 0;
+
+dis_clk:
+ clk_disable(&priv->ldb_clk);
+
+ return ret;
+}
+
+struct video_bridge_ops imx_ldb_ops = {
+ .attach = imx_ldb_attach,
+ .set_backlight = imx_ldb_set_backlight,
+};
+
+static const struct udevice_id imx_ldb_ids[] = {
+ { .compatible = "fsl,imx8mp-ldb"},
+ { }
+};
+
+U_BOOT_DRIVER(imx_ldb) = {
+ .name = "imx-lvds-display-bridge",
+ .id = UCLASS_VIDEO_BRIDGE,
+ .of_match = imx_ldb_ids,
+ .probe = imx_ldb_probe,
+ .of_to_plat = imx_ldb_of_to_plat,
+ .ops = &imx_ldb_ops,
+ .priv_auto = sizeof(struct imx_ldb_priv),
+};
diff --git a/drivers/video/lm3532_backlight.c b/drivers/video/lm3532_backlight.c
new file mode 100644
index 00000000000..81b3b910196
--- /dev/null
+++ b/drivers/video/lm3532_backlight.c
@@ -0,0 +1,380 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * TI LM3532 LED driver
+ *
+ * Copyright (c) 2019 Texas Instruments Incorporated
+ * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#define LOG_CATEGORY UCLASS_PANEL_BACKLIGHT
+
+#include <backlight.h>
+#include <dm.h>
+#include <dm/ofnode.h>
+#include <i2c.h>
+#include <log.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <asm/gpio.h>
+#include <power/regulator.h>
+
+#define LM3532_BL_MODE_MANUAL 0x00
+#define LM3532_BL_MODE_ALS 0x01
+
+#define LM3532_REG_OUTPUT_CFG 0x10
+#define LM3532_REG_STARTSHUT_RAMP 0x11
+#define LM3532_REG_RT_RAMP 0x12
+#define LM3532_REG_PWM_A_CFG 0x13
+#define LM3532_REG_PWM_B_CFG 0x14
+#define LM3532_REG_PWM_C_CFG 0x15
+#define LM3532_REG_ZONE_CFG_A 0x16
+#define LM3532_REG_CTRL_A_FS_CURR 0x17
+#define LM3532_REG_ZONE_CFG_B 0x18
+#define LM3532_REG_CTRL_B_FS_CURR 0x19
+#define LM3532_REG_ZONE_CFG_C 0x1a
+#define LM3532_REG_CTRL_C_FS_CURR 0x1b
+#define LM3532_REG_ENABLE 0x1d
+#define LM3532_ALS_CONFIG 0x23
+#define LM3532_REG_ZN_0_HI 0x60
+#define LM3532_REG_ZN_0_LO 0x61
+#define LM3532_REG_ZN_1_HI 0x62
+#define LM3532_REG_ZN_1_LO 0x63
+#define LM3532_REG_ZN_2_HI 0x64
+#define LM3532_REG_ZN_2_LO 0x65
+#define LM3532_REG_ZN_3_HI 0x66
+#define LM3532_REG_ZN_3_LO 0x67
+#define LM3532_REG_ZONE_TRGT_A 0x70
+#define LM3532_REG_ZONE_TRGT_B 0x75
+#define LM3532_REG_ZONE_TRGT_C 0x7a
+#define LM3532_REG_MAX 0x7e
+
+/* Control Enable */
+#define LM3532_CTRL_A_ENABLE BIT(0)
+#define LM3532_CTRL_B_ENABLE BIT(1)
+#define LM3532_CTRL_C_ENABLE BIT(2)
+
+/* PWM Zone Control */
+#define LM3532_PWM_ZONE_MASK 0x7c
+#define LM3532_PWM_ZONE_0_EN BIT(2)
+#define LM3532_PWM_ZONE_1_EN BIT(3)
+#define LM3532_PWM_ZONE_2_EN BIT(4)
+#define LM3532_PWM_ZONE_3_EN BIT(5)
+#define LM3532_PWM_ZONE_4_EN BIT(6)
+
+/* Brightness Configuration */
+#define LM3532_I2C_CTRL BIT(0)
+#define LM3532_ALS_CTRL 0
+#define LM3532_LINEAR_MAP BIT(1)
+#define LM3532_ZONE_MASK (BIT(2) | BIT(3) | BIT(4))
+#define LM3532_ZONE_0 0
+#define LM3532_ZONE_1 BIT(2)
+#define LM3532_ZONE_2 BIT(3)
+#define LM3532_ZONE_3 (BIT(2) | BIT(3))
+#define LM3532_ZONE_4 BIT(4)
+
+#define LM3532_ENABLE_ALS BIT(3)
+#define LM3532_ALS_SEL_SHIFT 6
+
+/* Zone Boundary Register */
+#define LM3532_ALS_WINDOW_mV 2000
+#define LM3532_ALS_ZB_MAX 4
+#define LM3532_ALS_OFFSET_mV 2
+
+#define LM3532_CONTROL_A 0
+#define LM3532_CONTROL_B 1
+#define LM3532_CONTROL_C 2
+#define LM3532_MAX_CONTROL_BANKS 3
+#define LM3532_MAX_LED_STRINGS 3
+
+#define LM3532_OUTPUT_CFG_MASK 0x3
+#define LM3532_BRT_VAL_ADJUST 8
+#define LM3532_RAMP_DOWN_SHIFT 3
+
+#define LM3532_NUM_RAMP_VALS 8
+#define LM3532_NUM_AVG_VALS 8
+#define LM3532_NUM_IMP_VALS 32
+
+#define LM3532_FS_CURR_MIN 5000
+#define LM3532_FS_CURR_MAX 29800
+#define LM3532_FS_CURR_STEP 800
+
+struct lm3532_bank_data {
+ int control_bank;
+ int mode;
+ int ctrl_brt_pointer;
+ int num_leds;
+ int full_scale_current;
+ u32 present:1;
+ u32 led_strings[LM3532_MAX_CONTROL_BANKS];
+};
+
+struct lm3532_backlight_priv {
+ struct gpio_desc enable_gpio;
+ struct udevice *regulator;
+
+ u32 runtime_ramp_up;
+ u32 runtime_ramp_down;
+
+ struct lm3532_bank_data bank[LM3532_MAX_CONTROL_BANKS];
+};
+
+/* This device does not like i2c md so use this instead */
+static void __maybe_unused dump_i2c(struct udevice *dev)
+{
+ int i, c;
+
+ for (i = 0; i < 0x10; i++) {
+ printf("00%02x: %02x", i * 0x10, dm_i2c_reg_read(dev, i * 0x10));
+ for (c = 1; c < 0xf; c++)
+ printf(" %02x", dm_i2c_reg_read(dev, i * 0x10 + c));
+ printf(" %02x\n", dm_i2c_reg_read(dev, i * 0x10 + 0xf));
+ }
+}
+
+static int lm3532_backlight_enable(struct udevice *dev)
+{
+ struct lm3532_backlight_priv *priv = dev_get_priv(dev);
+ int ret, i;
+
+ for (i = 0; i < LM3532_MAX_CONTROL_BANKS; i++) {
+ if (priv->bank[i].present) {
+ u32 ctrl_en_val = BIT(priv->bank[i].control_bank);
+
+ ret = dm_i2c_reg_clrset(dev, LM3532_REG_ENABLE,
+ ctrl_en_val, ctrl_en_val);
+ if (ret) {
+ log_debug("%s: failed to set ctrl: %d\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+ }
+
+ regulator_set_enable_if_allowed(priv->regulator, 1);
+
+ return 0;
+}
+
+static int lm3532_backlight_set_brightness(struct udevice *dev, int percent)
+{
+ struct lm3532_backlight_priv *priv = dev_get_priv(dev);
+ struct lm3532_bank_data *bank;
+ int ret, i;
+
+ for (i = 0; i < LM3532_MAX_CONTROL_BANKS; i++) {
+ if (priv->bank[i].present) {
+ bank = &priv->bank[i];
+ u32 brightness_reg = LM3532_REG_ZONE_TRGT_A +
+ bank->control_bank * 5 +
+ (bank->ctrl_brt_pointer >> 2);
+
+ ret = dm_i2c_reg_write(dev, brightness_reg, percent);
+ if (ret) {
+ log_debug("%s: failed to set brightness: %d\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static const int ramp_table[LM3532_NUM_RAMP_VALS] = { 8, 1024, 2048, 4096, 8192,
+ 16384, 32768, 65536 };
+static int lm3532_get_ramp_index(int ramp_time)
+{
+ int i;
+
+ if (ramp_time <= ramp_table[0])
+ return 0;
+
+ if (ramp_time > ramp_table[LM3532_NUM_RAMP_VALS - 1])
+ return LM3532_NUM_RAMP_VALS - 1;
+
+ for (i = 1; i < LM3532_NUM_RAMP_VALS; i++) {
+ if (ramp_time == ramp_table[i])
+ return i;
+
+ /* Find an approximate index by looking up the table */
+ if (ramp_time > ramp_table[i - 1] &&
+ ramp_time < ramp_table[i]) {
+ if (ramp_time - ramp_table[i - 1] < ramp_table[i] - ramp_time)
+ return i - 1;
+ else
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+static int lm3532_backlight_of_to_plat(struct udevice *dev)
+{
+ struct lm3532_backlight_priv *priv = dev_get_priv(dev);
+ u32 ramp_time, reg;
+ ofnode child;
+ int ret;
+
+ ret = gpio_request_by_name(dev, "enable-gpios", 0,
+ &priv->enable_gpio, GPIOD_IS_OUT);
+ if (ret) {
+ log_debug("%s: could not decode enable-gpios (%d)\n", __func__, ret);
+ return ret;
+ }
+
+ ret = device_get_supply_regulator(dev, "vin-supply", &priv->regulator);
+ if (ret) {
+ log_debug("%s: vin regulator not defined: %d\n", __func__, ret);
+ if (ret != -ENOENT)
+ return log_ret(ret);
+ }
+
+ ramp_time = dev_read_u32_default(dev, "ramp-up-us", 0);
+ priv->runtime_ramp_up = lm3532_get_ramp_index(ramp_time);
+
+ ramp_time = dev_read_u32_default(dev, "ramp-down-us", 0);
+ priv->runtime_ramp_down = lm3532_get_ramp_index(ramp_time);
+
+ /* Backlight is one of children but has no dedicated driver */
+ ofnode_for_each_subnode(child, dev_ofnode(dev)) {
+ ret = ofnode_read_u32(child, "reg", &reg);
+ if (ret || reg > LM3532_CONTROL_C) {
+ log_debug("%s: control bank invalid %d\n", __func__, reg);
+ continue;
+ }
+
+ struct lm3532_bank_data *bank = &priv->bank[reg];
+
+ bank->control_bank = reg;
+ bank->present = 1;
+ bank->mode = ofnode_read_u32_default(child, "ti,led-mode",
+ LM3532_BL_MODE_MANUAL);
+ bank->mode = LM3532_BL_MODE_ALS ? LM3532_ALS_CTRL : LM3532_I2C_CTRL;
+
+ if (ofnode_read_bool(child, "ti,linear-mapping-mode"))
+ bank->mode |= LM3532_LINEAR_MAP;
+
+ bank->num_leds = ofnode_read_size(child, "led-sources");
+ bank->num_leds /= sizeof(u32);
+ if (bank->num_leds > LM3532_MAX_LED_STRINGS) {
+ log_debug("%s: too many LED string defined %d\n",
+ __func__, bank->num_leds);
+ continue;
+ }
+
+ ret = ofnode_read_u32_array(child, "led-sources",
+ bank->led_strings,
+ bank->num_leds);
+ if (ret) {
+ log_debug("%s: led-sources property missing %d\n",
+ __func__, ret);
+ continue;
+ }
+
+ ret = ofnode_read_u32(child, "led-max-microamp",
+ &bank->full_scale_current);
+ if (ret)
+ log_debug("%s: failed getting led-max-microamp %d\n",
+ __func__, ret);
+ else
+ bank->full_scale_current = min(bank->full_scale_current,
+ LM3532_FS_CURR_MAX);
+ }
+
+ return 0;
+}
+
+static int lm3532_backlight_init_registers(struct udevice *dev,
+ struct lm3532_bank_data *bank)
+{
+ struct lm3532_backlight_priv *priv = dev_get_priv(dev);
+ u32 brightness_config_val, runtime_ramp_val;
+ u32 output_cfg_val = 0, output_cfg_shift = 0, output_cfg_mask = 0;
+ int fs_current_reg, fs_current_val;
+ int ret, i;
+
+ if (!bank->present)
+ return 0;
+
+ u32 brightness_config_reg = LM3532_REG_ZONE_CFG_A + bank->control_bank * 2;
+ /*
+ * This could be hard coded to the default value but the control
+ * brightness register may have changed during boot.
+ */
+ ret = dm_i2c_reg_read(dev, brightness_config_reg);
+ if (ret < 0)
+ return ret;
+
+ bank->ctrl_brt_pointer = ret & ~LM3532_ZONE_MASK;
+ brightness_config_val = bank->ctrl_brt_pointer | bank->mode;
+
+ ret = dm_i2c_reg_write(dev, brightness_config_reg, brightness_config_val);
+ if (ret)
+ return ret;
+
+ if (bank->full_scale_current) {
+ fs_current_reg = LM3532_REG_CTRL_A_FS_CURR + bank->control_bank * 2;
+ fs_current_val = (bank->full_scale_current - LM3532_FS_CURR_MIN) /
+ LM3532_FS_CURR_STEP;
+
+ ret = dm_i2c_reg_write(dev, fs_current_reg, fs_current_val);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < bank->num_leds; i++) {
+ output_cfg_shift = bank->led_strings[i] * 2;
+ output_cfg_val |= (bank->control_bank << output_cfg_shift);
+ output_cfg_mask |= LM3532_OUTPUT_CFG_MASK << output_cfg_shift;
+ }
+
+ ret = dm_i2c_reg_clrset(dev, LM3532_REG_OUTPUT_CFG, output_cfg_mask,
+ output_cfg_val);
+ if (ret)
+ return ret;
+
+ runtime_ramp_val = priv->runtime_ramp_up |
+ (priv->runtime_ramp_down << LM3532_RAMP_DOWN_SHIFT);
+
+ return dm_i2c_reg_write(dev, LM3532_REG_RT_RAMP, runtime_ramp_val);
+}
+
+static int lm3532_backlight_probe(struct udevice *dev)
+{
+ struct lm3532_backlight_priv *priv = dev_get_priv(dev);
+ int ret, i;
+
+ if (device_get_uclass_id(dev->parent) != UCLASS_I2C)
+ return -EPROTONOSUPPORT;
+
+ dm_gpio_set_value(&priv->enable_gpio, 1);
+
+ for (i = 0; i < LM3532_MAX_CONTROL_BANKS; i++) {
+ ret = lm3532_backlight_init_registers(dev, &priv->bank[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct backlight_ops lm3532_backlight_ops = {
+ .enable = lm3532_backlight_enable,
+ .set_brightness = lm3532_backlight_set_brightness,
+};
+
+static const struct udevice_id lm3532_backlight_ids[] = {
+ { .compatible = "ti,lm3532" },
+ { }
+};
+
+U_BOOT_DRIVER(lm3532_backlight) = {
+ .name = "lm3532_backlight",
+ .id = UCLASS_PANEL_BACKLIGHT,
+ .of_match = lm3532_backlight_ids,
+ .of_to_plat = lm3532_backlight_of_to_plat,
+ .probe = lm3532_backlight_probe,
+ .ops = &lm3532_backlight_ops,
+ .priv_auto = sizeof(struct lm3532_backlight_priv),
+};
diff --git a/drivers/video/mot-panel.c b/drivers/video/mot-panel.c
new file mode 100644
index 00000000000..a9114957867
--- /dev/null
+++ b/drivers/video/mot-panel.c
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Motorola ATRIX 4G and DROID X2 DSI panel driver
+ * Exact manufacturer and model unknown
+ *
+ * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <backlight.h>
+#include <dm.h>
+#include <panel.h>
+#include <log.h>
+#include <misc.h>
+#include <mipi_display.h>
+#include <mipi_dsi.h>
+#include <asm/gpio.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <power/regulator.h>
+
+struct mot_panel_priv {
+ struct udevice *vdd;
+ struct udevice *vddio;
+
+ struct udevice *backlight;
+
+ struct gpio_desc reset_gpio;
+};
+
+#define dsi_generic_write_seq(dsi, cmd, seq...) do { \
+ static const u8 b[] = { cmd, seq }; \
+ int ret; \
+ ret = mipi_dsi_dcs_write_buffer(dsi, b, ARRAY_SIZE(b)); \
+ if (ret < 0) \
+ return ret; \
+ } while (0)
+
+static struct display_timing default_timing = {
+ .pixelclock.typ = 38250000,
+ .hactive.typ = 540,
+ .hfront_porch.typ = 32,
+ .hback_porch.typ = 32,
+ .hsync_len.typ = 16,
+ .vactive.typ = 960,
+ .vfront_porch.typ = 12,
+ .vback_porch.typ = 12,
+ .vsync_len.typ = 8,
+};
+
+static int mot_es2(struct mipi_dsi_device *dsi)
+{
+ int ret;
+
+ dsi_generic_write_seq(dsi, 0x55, 0x01);
+
+ ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+ if (ret < 0) {
+ log_debug("%s: failed to exit sleep mode: %d\n", __func__, ret);
+ return ret;
+ }
+ mdelay(120);
+
+ dsi_generic_write_seq(dsi, 0xf4, 0x00, 0xbb, 0x46, 0x53, 0x0c, 0x49,
+ 0x74, 0x29, 0x12, 0x15, 0x2f, 0x2f, 0x04);
+ dsi_generic_write_seq(dsi, 0xf8, 0x4b, 0x04, 0x10, 0x1a, 0x2c, 0x2c,
+ 0x2c, 0x2c, 0x14, 0x12);
+
+ dsi_generic_write_seq(dsi, 0xb5, 0x03, 0x7f, 0x00, 0x80, 0xc7, 0x00);
+ dsi_generic_write_seq(dsi, 0xb7, 0x66, 0xf6, 0x46, 0x9f, 0x90, 0x99,
+ 0xff, 0x80, 0x6d, 0x01);
+
+ /* Gamma R */
+ dsi_generic_write_seq(dsi, 0xf9, 0x04);
+ dsi_generic_write_seq(dsi, 0xfa, 0x00, 0x2f, 0x30, 0x12, 0x0e, 0x0c,
+ 0x22, 0x27, 0x31, 0x2e, 0x07, 0x0f);
+ dsi_generic_write_seq(dsi, 0xfb, 0x00, 0x2f, 0x30, 0x12, 0x0e, 0x0c,
+ 0x22, 0x27, 0x31, 0x2e, 0x07, 0x0f);
+
+ /* Gamma G */
+ dsi_generic_write_seq(dsi, 0xf9, 0x02);
+ dsi_generic_write_seq(dsi, 0xfa, 0x00, 0x2f, 0x37, 0x15, 0x15, 0x11,
+ 0x1f, 0x25, 0x2d, 0x2a, 0x05, 0x0f);
+ dsi_generic_write_seq(dsi, 0xfb, 0x00, 0x2f, 0x37, 0x15, 0x15, 0x11,
+ 0x1f, 0x25, 0x2d, 0x2a, 0x05, 0x0f);
+
+ /* Gamma B */
+ dsi_generic_write_seq(dsi, 0xf9, 0x01);
+ dsi_generic_write_seq(dsi, 0xfa, 0x00, 0x2f, 0x3f, 0x16, 0x1f, 0x15,
+ 0x1f, 0x25, 0x2d, 0x2b, 0x06, 0x0b);
+ dsi_generic_write_seq(dsi, 0xfb, 0x00, 0x2f, 0x3f, 0x16, 0x1f, 0x15,
+ 0x1f, 0x25, 0x2d, 0x2b, 0x06, 0x0b);
+
+ /* Gamma W */
+ dsi_generic_write_seq(dsi, 0xf9, 0x20);
+ dsi_generic_write_seq(dsi, 0xfa, 0x00, 0x2f, 0x34, 0x15, 0x1a, 0x11,
+ 0x1f, 0x23, 0x2d, 0x29, 0x02, 0x08);
+ dsi_generic_write_seq(dsi, 0xfb, 0x00, 0x2f, 0x34, 0x15, 0x1a, 0x11,
+ 0x1f, 0x23, 0x2d, 0x29, 0x02, 0x08);
+
+ dsi_generic_write_seq(dsi, 0x53, 0x2c);
+ dsi_generic_write_seq(dsi, 0x35, 0x00);
+
+ return 0;
+}
+
+static int __maybe_unused mot_es4(struct mipi_dsi_device *dsi)
+{
+ int ret;
+
+ dsi_generic_write_seq(dsi, 0xd2, 0x04, 0x53);
+ dsi_generic_write_seq(dsi, 0xd2, 0x05, 0x53);
+ dsi_generic_write_seq(dsi, 0x55, 0x01);
+
+ ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+ if (ret < 0) {
+ log_debug("%s: failed to exit sleep mode: %d\n", __func__, ret);
+ return ret;
+ }
+ mdelay(120);
+
+ dsi_generic_write_seq(dsi, 0xb5, 0x03, 0x7f, 0x0a, 0x80, 0xff, 0x00);
+ dsi_generic_write_seq(dsi, 0xb7, 0x7a, 0xf7, 0x4d, 0x91, 0x90, 0xb3,
+ 0xff, 0x80, 0x6d, 0x01);
+ dsi_generic_write_seq(dsi, 0xf4, 0x00, 0xbb, 0x46, 0x53, 0x0c, 0x49,
+ 0x74, 0x29, 0x12, 0x15, 0x37, 0x37, 0x04);
+ dsi_generic_write_seq(dsi, 0xf8, 0x0a, 0x04, 0x10, 0x2a, 0x35, 0x35,
+ 0x35, 0x35, 0x21, 0x1a);
+
+ /* Gamma R */
+ dsi_generic_write_seq(dsi, 0xf9, 0x04);
+ dsi_generic_write_seq(dsi, 0xfa, 0x08, 0x1c, 0x1b, 0x0f, 0x0f, 0x0a,
+ 0x1e, 0x22, 0x27, 0x26, 0x07, 0x0d);
+ dsi_generic_write_seq(dsi, 0xfb, 0x08, 0x3c, 0x27, 0x0f, 0x0f, 0x0a,
+ 0x1e, 0x26, 0x31, 0x2f, 0x07, 0x0b);
+
+ /* Gamma G */
+ dsi_generic_write_seq(dsi, 0xf9, 0x02);
+ dsi_generic_write_seq(dsi, 0xfa, 0x30, 0x14, 0x0f, 0x00, 0x06, 0x02,
+ 0x1e, 0x22, 0x27, 0x27, 0x08, 0x10);
+ dsi_generic_write_seq(dsi, 0xfb, 0x30, 0x35, 0x0f, 0x00, 0x0a, 0x02,
+ 0x1c, 0x23, 0x31, 0x2f, 0x08, 0x0e);
+
+ /* Gamma B */
+ dsi_generic_write_seq(dsi, 0xf9, 0x01);
+ dsi_generic_write_seq(dsi, 0xfa, 0x12, 0x1b, 0x26, 0x0e, 0x12, 0x0b,
+ 0x1e, 0x22, 0x27, 0x27, 0x06, 0x0c);
+ dsi_generic_write_seq(dsi, 0xfb, 0x12, 0x3b, 0x2c, 0x12, 0x12, 0x0e,
+ 0x1e, 0x26, 0x31, 0x2f, 0x06, 0x0d);
+
+ /* Gamma W */
+ dsi_generic_write_seq(dsi, 0xf9, 0x20);
+ dsi_generic_write_seq(dsi, 0xfa, 0x37, 0x1b, 0x09, 0x01, 0x06, 0x04,
+ 0x19, 0x19, 0x22, 0x24, 0x04, 0x15);
+ dsi_generic_write_seq(dsi, 0xfb, 0x37, 0x3b, 0x17, 0x01, 0x0a, 0x04,
+ 0x19, 0x1d, 0x2c, 0x2c, 0x04, 0x13);
+
+ dsi_generic_write_seq(dsi, 0x53, 0x2c);
+ dsi_generic_write_seq(dsi, 0x35, 0x00);
+ dsi_generic_write_seq(dsi, 0xc3, 0x01, 0x4e);
+
+ return 0;
+}
+
+static int mot_panel_enable_backlight(struct udevice *dev)
+{
+ struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
+ struct mipi_dsi_device *dsi = plat->device;
+ int ret;
+
+ dsi_generic_write_seq(dsi, 0xf0, 0x5a, 0x5a);
+ dsi_generic_write_seq(dsi, 0xf1, 0x5a, 0x5a);
+ dsi_generic_write_seq(dsi, 0xd0, 0x8e);
+
+ ret = mot_es2(dsi);
+ if (ret)
+ return ret;
+
+ ret = mipi_dsi_dcs_set_display_on(dsi);
+ if (ret < 0) {
+ log_debug("%s: failed to set display on: %d\n", __func__, ret);
+ return ret;
+ }
+ mdelay(20);
+
+ return 0;
+}
+
+static int mot_panel_set_backlight(struct udevice *dev, int percent)
+{
+ struct mot_panel_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = backlight_enable(priv->backlight);
+ if (ret)
+ return ret;
+
+ mdelay(5);
+
+ return backlight_set_brightness(priv->backlight, percent);
+}
+
+static int mot_panel_timings(struct udevice *dev, struct display_timing *timing)
+{
+ memcpy(timing, &default_timing, sizeof(*timing));
+ return 0;
+}
+
+static int mot_panel_of_to_plat(struct udevice *dev)
+{
+ struct mot_panel_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
+ "backlight", &priv->backlight);
+ if (ret) {
+ log_debug("%s: cannot get backlight: ret = %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = device_get_supply_regulator(dev, "vdd-supply", &priv->vdd);
+ if (ret) {
+ log_debug("%s: cannot get vdd-supply: ret = %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = device_get_supply_regulator(dev, "vddio-supply", &priv->vddio);
+ if (ret) {
+ log_debug("%s: cannot get vddio-supply: ret = %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = gpio_request_by_name(dev, "reset-gpios", 0,
+ &priv->reset_gpio, GPIOD_IS_OUT);
+ if (ret) {
+ log_debug("%s: could not decode reser-gpios (%d)\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mot_panel_hw_init(struct udevice *dev)
+{
+ struct mot_panel_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = regulator_set_enable_if_allowed(priv->vddio, 1);
+ if (ret) {
+ log_debug("%s: enabling vddio-supply failed (%d)\n", __func__, ret);
+ return ret;
+ }
+
+ ret = regulator_set_enable_if_allowed(priv->vdd, 1);
+ if (ret) {
+ log_debug("%s: enabling vdd-supply failed (%d)\n", __func__, ret);
+ return ret;
+ }
+
+ ret = dm_gpio_set_value(&priv->reset_gpio, 1);
+ if (ret) {
+ log_debug("%s: error entering reset (%d)\n", __func__, ret);
+ return ret;
+ }
+ mdelay(50);
+
+ ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+ if (ret) {
+ log_debug("%s: error exiting reset (%d)\n", __func__, ret);
+ return ret;
+ }
+ mdelay(10);
+
+ return 0;
+}
+
+static int mot_panel_probe(struct udevice *dev)
+{
+ struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
+
+ /* fill characteristics of DSI data link */
+ plat->lanes = 2;
+ plat->format = MIPI_DSI_FMT_RGB888;
+ plat->mode_flags = MIPI_DSI_MODE_LPM;
+
+ return mot_panel_hw_init(dev);
+}
+
+static const struct panel_ops mot_panel_ops = {
+ .enable_backlight = mot_panel_enable_backlight,
+ .set_backlight = mot_panel_set_backlight,
+ .get_display_timing = mot_panel_timings,
+};
+
+static const struct udevice_id mot_panel_ids[] = {
+ { .compatible = "motorola,mot-panel" },
+ { }
+};
+
+U_BOOT_DRIVER(mot_panel) = {
+ .name = "mot_panel",
+ .id = UCLASS_PANEL,
+ .of_match = mot_panel_ids,
+ .ops = &mot_panel_ops,
+ .of_to_plat = mot_panel_of_to_plat,
+ .probe = mot_panel_probe,
+ .plat_auto = sizeof(struct mipi_dsi_panel_plat),
+ .priv_auto = sizeof(struct mot_panel_priv),
+};
diff --git a/drivers/video/tegra/Kconfig b/drivers/video/tegra/Kconfig
new file mode 100644
index 00000000000..d3b8dbb2826
--- /dev/null
+++ b/drivers/video/tegra/Kconfig
@@ -0,0 +1,51 @@
+config HOST1X_TEGRA
+ bool "NVIDIA Tegra host1x BUS support"
+ depends on SIMPLE_BUS
+
+config VIDEO_TEGRA
+ bool "Enable Display Controller support on Tegra devices"
+ depends on OF_CONTROL
+ select HOST1X_TEGRA
+ help
+ Enable support for Display Controller found in Tegra SoC. The
+ Display Controller Complex integrates two independent display
+ controllers. Each display controller is capable of interfacing
+ to an external display device, which can be a parallel interface
+ or SPI LCD, DVI, an HDMI HDTV, RGB monitor or a MIPI DSI LCD.
+ Direct interface is supported directly to most LCD displays with
+ TFT or TFT-like interface.
+
+config VIDEO_DSI_TEGRA
+ bool "Enable DSI controller support on Tegra devices"
+ depends on VIDEO_BRIDGE && PANEL && DM_GPIO
+ select VIDEO_TEGRA
+ select VIDEO_MIPI_DSI
+ help
+ Enable support for the Display Serial Interface (DSI) found in
+ Tegra SoC. It is a MIPI standard serial bitstream, intended to
+ provide a low pin count interface to a display panel.
+
+config VIDEO_HDMI_TEGRA
+ bool "Enable HDMI support on Tegra devices"
+ depends on VIDEO_BRIDGE && DM_I2C
+ select I2C_EDID
+ select VIDEO_TEGRA
+ help
+ Enable support for the High-Definition Multimedia Interface (HDMI)
+ found in Tegra SoC.
+
+config TEGRA_BACKLIGHT_PWM
+ bool "Enable Tegra DC PWM backlight support"
+ depends on BACKLIGHT
+ select VIDEO_TEGRA
+ help
+ Enable support for the Display Controller dependent PWM backlight
+ found in the Tegra SoC and usually used with DSI panels.
+
+config VIDEO_TEGRA124
+ bool "Enable video support on Tegra124"
+ help
+ Tegra124 supports many video output options including eDP and
+ HDMI. At present only eDP is supported by U-Boot. This option
+ enables this support which can be used on devices which
+ have an eDP display connected.
diff --git a/drivers/video/tegra/Makefile b/drivers/video/tegra/Makefile
new file mode 100644
index 00000000000..3c50a0ba3c3
--- /dev/null
+++ b/drivers/video/tegra/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-$(CONFIG_HOST1X_TEGRA) += host1x.o
+obj-$(CONFIG_VIDEO_TEGRA) += dc.o
+obj-$(CONFIG_VIDEO_DSI_TEGRA) += dsi.o mipi.o mipi-phy.o
+obj-$(CONFIG_VIDEO_HDMI_TEGRA) += hdmi.o
+obj-$(CONFIG_TEGRA_BACKLIGHT_PWM) += dc-pwm-backlight.o
+
+obj-${CONFIG_VIDEO_TEGRA124} += tegra124/
diff --git a/drivers/video/tegra/TODO b/drivers/video/tegra/TODO
new file mode 100644
index 00000000000..1c8c2389a18
--- /dev/null
+++ b/drivers/video/tegra/TODO
@@ -0,0 +1,5 @@
+Existence of separate Tegra124 video implementations is not an ideal solution
+since generic video setup for Tegra already has Tegra124 support of some degree.
+It is not possible at the time of this note is written to integrate T124 SOR
+and DP without possible regressions. Tegra124 setup for SOR and DP should be
+incorporated into existing setup once such opportunity occurs.
diff --git a/drivers/video/tegra20/tegra-pwm-backlight.c b/drivers/video/tegra/dc-pwm-backlight.c
index 998f0df1991..eff10b5563e 100644
--- a/drivers/video/tegra20/tegra-pwm-backlight.c
+++ b/drivers/video/tegra/dc-pwm-backlight.c
@@ -15,7 +15,7 @@
#include <asm/io.h>
#include <asm/gpio.h>
-#include "tegra-dc.h"
+#include "dc.h"
#define TEGRA_PWM_BL_MIN_BRIGHTNESS 0x10
#define TEGRA_PWM_BL_MAX_BRIGHTNESS 0xFF
diff --git a/drivers/video/tegra20/tegra-dc.c b/drivers/video/tegra/dc.c
index 1f43153ff27..f0e3d2c993f 100644
--- a/drivers/video/tegra20/tegra-dc.c
+++ b/drivers/video/tegra/dc.c
@@ -19,7 +19,7 @@
#include <asm/arch/clock.h>
#include <asm/arch/powergate.h>
-#include "tegra-dc.h"
+#include "dc.h"
/* Holder of Tegra per-SOC DC differences */
struct tegra_dc_soc_info {
diff --git a/drivers/video/tegra20/tegra-dc.h b/drivers/video/tegra/dc.h
index 2a4013b3355..2a4013b3355 100644
--- a/drivers/video/tegra20/tegra-dc.h
+++ b/drivers/video/tegra/dc.h
diff --git a/drivers/video/tegra20/tegra-dsi.c b/drivers/video/tegra/dsi.c
index a2a22fa0fe2..bc308869f4e 100644
--- a/drivers/video/tegra20/tegra-dsi.c
+++ b/drivers/video/tegra/dsi.c
@@ -24,8 +24,8 @@
#include <asm/arch/clock.h>
#include <asm/arch-tegra/clk_rst.h>
-#include "tegra-dc.h"
-#include "tegra-dsi.h"
+#include "dc.h"
+#include "dsi.h"
#include "mipi-phy.h"
/* List of supported DSI bridges */
@@ -1129,6 +1129,7 @@ static const struct video_bridge_ops tegra_dsi_bridge_ops = {
};
static const struct udevice_id tegra_dsi_bridge_ids[] = {
+ { .compatible = "nvidia,tegra20-dsi", .data = DSI_V0 },
{ .compatible = "nvidia,tegra30-dsi", .data = DSI_V0 },
{ .compatible = "nvidia,tegra114-dsi", .data = DSI_V1 },
{ .compatible = "nvidia,tegra124-dsi", .data = DSI_V1 },
diff --git a/drivers/video/tegra20/tegra-dsi.h b/drivers/video/tegra/dsi.h
index 683c5e31a34..683c5e31a34 100644
--- a/drivers/video/tegra20/tegra-dsi.h
+++ b/drivers/video/tegra/dsi.h
diff --git a/drivers/video/tegra20/tegra-hdmi.c b/drivers/video/tegra/hdmi.c
index bda69919d92..bfb48b25187 100644
--- a/drivers/video/tegra20/tegra-hdmi.c
+++ b/drivers/video/tegra/hdmi.c
@@ -22,8 +22,8 @@
#include <asm/io.h>
#include <asm/arch/clock.h>
-#include "tegra-dc.h"
-#include "tegra-hdmi.h"
+#include "dc.h"
+#include "hdmi.h"
#define DDCCI_ENTRY_ADDR 0x37
#define DDCCI_SOURSE_ADDR 0x51
diff --git a/drivers/video/tegra20/tegra-hdmi.h b/drivers/video/tegra/hdmi.h
index d17655973e3..d17655973e3 100644
--- a/drivers/video/tegra20/tegra-hdmi.h
+++ b/drivers/video/tegra/hdmi.h
diff --git a/drivers/video/tegra20/tegra-host1x.c b/drivers/video/tegra/host1x.c
index 58ab871a3b4..58ab871a3b4 100644
--- a/drivers/video/tegra20/tegra-host1x.c
+++ b/drivers/video/tegra/host1x.c
diff --git a/drivers/video/tegra20/mipi-phy.c b/drivers/video/tegra/mipi-phy.c
index 576262e405d..576262e405d 100644
--- a/drivers/video/tegra20/mipi-phy.c
+++ b/drivers/video/tegra/mipi-phy.c
diff --git a/drivers/video/tegra20/mipi-phy.h b/drivers/video/tegra/mipi-phy.h
index 41889a75035..41889a75035 100644
--- a/drivers/video/tegra20/mipi-phy.h
+++ b/drivers/video/tegra/mipi-phy.h
diff --git a/drivers/video/tegra20/tegra-mipi.c b/drivers/video/tegra/mipi.c
index a4f4343d008..a4f4343d008 100644
--- a/drivers/video/tegra20/tegra-mipi.c
+++ b/drivers/video/tegra/mipi.c
diff --git a/drivers/video/tegra124/Makefile b/drivers/video/tegra/tegra124/Makefile
index a378382628c..a378382628c 100644
--- a/drivers/video/tegra124/Makefile
+++ b/drivers/video/tegra/tegra124/Makefile
diff --git a/drivers/video/tegra124/display.c b/drivers/video/tegra/tegra124/display.c
index abe31e27d84..abe31e27d84 100644
--- a/drivers/video/tegra124/display.c
+++ b/drivers/video/tegra/tegra124/display.c
diff --git a/drivers/video/tegra124/displayport.h b/drivers/video/tegra/tegra124/displayport.h
index a3044475aeb..a3044475aeb 100644
--- a/drivers/video/tegra124/displayport.h
+++ b/drivers/video/tegra/tegra124/displayport.h
diff --git a/drivers/video/tegra124/dp.c b/drivers/video/tegra/tegra124/dp.c
index b95b14da77d..b95b14da77d 100644
--- a/drivers/video/tegra124/dp.c
+++ b/drivers/video/tegra/tegra124/dp.c
diff --git a/drivers/video/tegra124/sor.c b/drivers/video/tegra/tegra124/sor.c
index 1ce5330c6bc..1ce5330c6bc 100644
--- a/drivers/video/tegra124/sor.c
+++ b/drivers/video/tegra/tegra124/sor.c
diff --git a/drivers/video/tegra124/sor.h b/drivers/video/tegra/tegra124/sor.h
index 2fc9a38267d..2fc9a38267d 100644
--- a/drivers/video/tegra124/sor.h
+++ b/drivers/video/tegra/tegra124/sor.h
diff --git a/drivers/video/tegra20/Kconfig b/drivers/video/tegra20/Kconfig
deleted file mode 100644
index 598f9ea1f21..00000000000
--- a/drivers/video/tegra20/Kconfig
+++ /dev/null
@@ -1,38 +0,0 @@
-config HOST1X_TEGRA
- bool "NVIDIA Tegra host1x BUS support"
- depends on SIMPLE_BUS
-
-config VIDEO_TEGRA20
- bool "Enable Display Controller support on Tegra20 and Tegra 30"
- depends on OF_CONTROL
- select HOST1X_TEGRA
- help
- T20/T30 support video output to an attached LCD panel as well as
- other options such as HDMI. Only the LCD is supported in U-Boot.
- This option enables this support which can be used on devices which
- have an LCD display connected.
-
-config VIDEO_DSI_TEGRA30
- bool "Enable Tegra 30 DSI support"
- depends on VIDEO_BRIDGE && PANEL && DM_GPIO
- select VIDEO_TEGRA20
- select VIDEO_MIPI_DSI
- help
- T30 has native support for DSI panels. This option enables support
- for such panels which can be used on endeavoru and tf600t.
-
-config VIDEO_HDMI_TEGRA
- bool "Enable Tegra HDMI support"
- depends on VIDEO_BRIDGE && DM_I2C
- select I2C_EDID
- select VIDEO_TEGRA20
- help
- Tegra has native support for HDMI. This option enables support
- for such connection and can be used for any supported device.
-
-config TEGRA_BACKLIGHT_PWM
- bool "Enable Tegra DC PWM backlight support"
- depends on BACKLIGHT
- select VIDEO_TEGRA20
- help
- Tegra DC dependent backlight.
diff --git a/drivers/video/tegra20/Makefile b/drivers/video/tegra20/Makefile
deleted file mode 100644
index 78521405749..00000000000
--- a/drivers/video/tegra20/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0+
-
-obj-$(CONFIG_HOST1X_TEGRA) += tegra-host1x.o
-obj-$(CONFIG_VIDEO_TEGRA20) += tegra-dc.o
-obj-$(CONFIG_VIDEO_DSI_TEGRA30) += tegra-dsi.o tegra-mipi.o mipi-phy.o
-obj-$(CONFIG_VIDEO_HDMI_TEGRA) += tegra-hdmi.o
-obj-$(CONFIG_TEGRA_BACKLIGHT_PWM) += tegra-pwm-backlight.o
diff --git a/drivers/video/tidss/Makefile b/drivers/video/tidss/Makefile
index f0cbe1d4ed1..3381a5fec57 100644
--- a/drivers/video/tidss/Makefile
+++ b/drivers/video/tidss/Makefile
@@ -9,4 +9,4 @@
# Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
-obj-${CONFIG_$(XPL_)VIDEO_TIDSS} = tidss_drv.o
+obj-${CONFIG_$(PHASE_)VIDEO_TIDSS} = tidss_drv.o