summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/extcon/Kconfig31
-rw-r--r--drivers/extcon/Makefile7
-rw-r--r--drivers/extcon/extcon-max14526.c151
-rw-r--r--drivers/extcon/extcon-sandbox.c17
-rw-r--r--drivers/extcon/extcon-uclass.c16
-rw-r--r--drivers/fastboot/Kconfig14
-rw-r--r--drivers/fastboot/fb_common.c33
-rw-r--r--drivers/misc/Kconfig7
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/esm_pmic.c9
-rw-r--r--drivers/misc/qcom-geni-se.c41
-rw-r--r--drivers/mmc/hi6220_dw_mmc.c2
-rw-r--r--drivers/mtd/spi/spi-nor-core.c117
-rw-r--r--drivers/net/dwc_eth_qos.c18
-rw-r--r--drivers/net/fsl-mc/mc.c31
-rw-r--r--drivers/net/ksz9477.c33
-rw-r--r--drivers/net/ldpaa_eth/ldpaa_eth.c7
-rw-r--r--drivers/net/phy/broadcom.c14
-rw-r--r--drivers/net/phy/dp83867.c2
-rw-r--r--drivers/net/phy/ethernet_id.c2
-rw-r--r--drivers/net/phy/realtek.c15
-rw-r--r--drivers/net/phy/xilinx_gmii2rgmii.c9
-rw-r--r--drivers/net/rtl8169.c52
-rw-r--r--drivers/pci/pci_auto.c4
-rw-r--r--drivers/pci/pci_mpc85xx.c51
-rw-r--r--drivers/pci/pcie_fsl.c14
-rw-r--r--drivers/pci/pcie_layerscape_rc.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common.c4
-rw-r--r--drivers/serial/Kconfig2
-rw-r--r--drivers/serial/serial_msm_geni.c65
-rw-r--r--drivers/spi/cadence_qspi.c16
-rw-r--r--drivers/spi/cadence_qspi_apb.c56
-rw-r--r--drivers/spi/npcm_fiu_spi.c72
-rw-r--r--drivers/spi/spi-mem.c8
-rw-r--r--drivers/spi/spi-sn-f-ospi.c2
-rw-r--r--drivers/spi/spi-synquacer.c4
-rw-r--r--drivers/usb/host/ehci-mx6.c10
-rw-r--r--drivers/video/Kconfig261
-rw-r--r--drivers/video/Makefile20
-rw-r--r--drivers/video/bridge/Kconfig7
-rw-r--r--drivers/video/bridge/Makefile1
-rw-r--r--drivers/video/bridge/ssd2825.c520
-rw-r--r--drivers/video/console_core.c6
-rw-r--r--drivers/video/endeavoru-panel.c252
-rw-r--r--drivers/video/lm3533_backlight.c134
-rw-r--r--drivers/video/renesas-r61307.c302
-rw-r--r--drivers/video/renesas-r69328.c238
-rw-r--r--drivers/video/tegra20/Kconfig7
-rw-r--r--drivers/video/tegra20/Makefile1
-rw-r--r--drivers/video/tegra20/tegra-pwm-backlight.c156
-rw-r--r--drivers/video/tidss/Kconfig6
-rw-r--r--drivers/video/tidss/Makefile2
-rw-r--r--drivers/video/vidconsole-uclass.c2
-rw-r--r--drivers/video/video-uclass.c14
-rw-r--r--drivers/video/video_bmp.c8
57 files changed, 2687 insertions, 192 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 9101e538b09..75937fbb6d9 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -36,6 +36,8 @@ source "drivers/dfu/Kconfig"
source "drivers/dma/Kconfig"
+source "drivers/extcon/Kconfig"
+
source "drivers/fastboot/Kconfig"
source "drivers/firmware/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 58be410135d..29be78a3f28 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_$(SPL_TPL_)DM) += core/
obj-$(CONFIG_$(SPL_TPL_)DMA) += dma/
obj-$(CONFIG_$(SPL_TPL_)DMA_LEGACY) += dma/
obj-$(CONFIG_$(SPL_TPL_)DFU) += dfu/
+obj-$(CONFIG_$(SPL_TPL_)EXTCON) += extcon/
obj-$(CONFIG_$(SPL_TPL_)GPIO) += gpio/
obj-$(CONFIG_$(SPL_TPL_)DRIVERS_MISC) += misc/
obj-$(CONFIG_$(SPL_TPL_)SYSRESET) += sysreset/
@@ -61,6 +62,7 @@ obj-$(CONFIG_SPL_USB_HOST) += usb/host/
obj-$(CONFIG_SPL_SATA) += ata/ scsi/
obj-$(CONFIG_SPL_LEGACY_BLOCK) += block/
obj-$(CONFIG_SPL_THERMAL) += thermal/
+obj-$(CONFIG_SPL_VIDEO) +=video/
endif
endif
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
new file mode 100644
index 00000000000..fbb73354aa3
--- /dev/null
+++ b/drivers/extcon/Kconfig
@@ -0,0 +1,31 @@
+menu "Extcon Support"
+
+config EXTCON
+ bool "External Connector Class (extcon) support"
+ depends on DM
+ help
+ Say Y here to enable external connector class (extcon) support.
+ This allows monitoring external connectors and supports external
+ connectors with multiple states; i.e., an extcon that may have
+ multiple cables attached. For example, an external connector
+ of a device may be used to connect an HDMI cable and a AC adaptor,
+ and to host USB ports. Many of 30-pin connectors including PDMI
+ are also good examples.
+
+config EXTCON_SANDBOX
+ bool "Sandbox extcon"
+ depends on EXTCON
+ help
+ Enable extcon support for sandbox. This is an emulation of a real
+ extcon. Currectly all configuration is done in the probe.
+
+config EXTCON_MAX14526
+ bool "Maxim MAX14526 EXTCON Support"
+ depends on DM_I2C
+ depends on EXTCON
+ help
+ If you say yes here you get support for the MUIC device of
+ Maxim MAX14526. The MAX14526 MUIC is a USB port accessory
+ detector and switch.
+
+endmenu
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
new file mode 100644
index 00000000000..3309f2aac2e
--- /dev/null
+++ b/drivers/extcon/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+
+obj-$(CONFIG_EXTCON) += extcon-uclass.o
+obj-$(CONFIG_EXTCON_SANDBOX) += extcon-sandbox.o
+obj-$(CONFIG_EXTCON_MAX14526) += extcon-max14526.o
diff --git a/drivers/extcon/extcon-max14526.c b/drivers/extcon/extcon-max14526.c
new file mode 100644
index 00000000000..a33b5ef919c
--- /dev/null
+++ b/drivers/extcon/extcon-max14526.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <log.h>
+#include <extcon.h>
+#include <asm/gpio.h>
+
+#define CONTROL_1 0x01
+#define SW_CONTROL 0x03
+
+#define ID_200 0x10
+#define ADC_EN 0x02
+#define CP_EN 0x01
+
+#define DP_USB 0x00
+#define DP_UART 0x08
+#define DP_AUDIO 0x10
+#define DP_OPEN 0x38
+
+#define DM_USB 0x00
+#define DM_UART 0x01
+#define DM_AUDIO 0x02
+#define DM_OPEN 0x07
+
+#define AP_USB BIT(0)
+#define CP_USB BIT(1)
+#define CP_UART BIT(2)
+
+struct max14526_priv {
+ struct gpio_desc usif_gpio;
+ struct gpio_desc dp2t_gpio;
+ struct gpio_desc ifx_usb_vbus_gpio;
+};
+
+static void max14526_set_mode(struct udevice *dev, int mode)
+{
+ struct max14526_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ if ((mode & AP_USB) || (mode & CP_USB)) {
+ /* Connect CP UART signals to AP */
+ ret = dm_gpio_set_value(&priv->usif_gpio, 0);
+ if (ret)
+ log_debug("cp-uart > ap failed (%d)\n", ret);
+ }
+
+ if (mode & CP_UART) {
+ /* Connect CP UART signals to DP2T */
+ ret = dm_gpio_set_value(&priv->usif_gpio, 1);
+ if (ret)
+ log_debug("cp-uart > dp2t failed (%d)\n", ret);
+ }
+
+ if (mode & CP_USB) {
+ /* Connect CP USB to MUIC UART */
+ ret = dm_gpio_set_value(&priv->ifx_usb_vbus_gpio, 1);
+ if (ret)
+ log_debug("usb-vbus-gpio enable failed (%d)\n", ret);
+
+ ret = dm_gpio_set_value(&priv->dp2t_gpio, 1);
+ if (ret)
+ log_debug("cp-usb > muic-uart failed (%d)\n", ret);
+ }
+
+ if ((mode & AP_USB) || (mode & CP_UART)) {
+ /* Connect CP UART to MUIC UART */
+ ret = dm_gpio_set_value(&priv->dp2t_gpio, 0);
+ if (ret)
+ log_debug("cp-uart > muic-uart failed (%d)\n", ret);
+ }
+
+ if (mode & AP_USB) {
+ /* Enables USB Path */
+ ret = dm_i2c_reg_write(dev, SW_CONTROL, DP_USB | DM_USB);
+ if (ret)
+ log_debug("USB path set failed: %d\n", ret);
+ }
+
+ if ((mode & CP_USB) || (mode & CP_UART)) {
+ /* Enables UART Path */
+ ret = dm_i2c_reg_write(dev, SW_CONTROL, DP_UART | DM_UART);
+ if (ret)
+ log_debug("UART path set failed: %d\n", ret);
+ }
+
+ /* Enables 200K, Charger Pump, and ADC */
+ ret = dm_i2c_reg_write(dev, CONTROL_1, ID_200 | ADC_EN | CP_EN);
+ if (ret)
+ log_debug("200K, Charger Pump, and ADC set failed: %d\n", ret);
+}
+
+static int max14526_probe(struct udevice *dev)
+{
+ struct max14526_priv *priv = dev_get_priv(dev);
+ int ret, mode = 0;
+
+ ret = gpio_request_by_name(dev, "usif-gpios", 0,
+ &priv->usif_gpio, GPIOD_IS_OUT);
+ if (ret) {
+ log_err("could not decode usif-gpios (%d)\n", ret);
+ return ret;
+ }
+
+ ret = gpio_request_by_name(dev, "dp2t-gpios", 0,
+ &priv->dp2t_gpio, GPIOD_IS_OUT);
+ if (ret) {
+ log_err("could not decode dp2t-gpios (%d)\n", ret);
+ return ret;
+ }
+
+ if (dev_read_bool(dev, "maxim,ap-usb"))
+ mode |= AP_USB;
+
+ if (dev_read_bool(dev, "maxim,cp-usb")) {
+ mode |= CP_USB;
+
+ ret = gpio_request_by_name(dev, "usb-vbus-gpios", 0,
+ &priv->ifx_usb_vbus_gpio, GPIOD_IS_OUT);
+ if (ret) {
+ log_err("could not decode usb-vbus-gpios (%d)\n", ret);
+ return ret;
+ }
+ }
+
+ if (dev_read_bool(dev, "maxim,cp-uart"))
+ mode |= CP_UART;
+
+ max14526_set_mode(dev, mode);
+
+ return 0;
+}
+
+static const struct udevice_id max14526_ids[] = {
+ { .compatible = "maxim,max14526-muic" },
+ { }
+};
+
+U_BOOT_DRIVER(extcon_max14526) = {
+ .name = "extcon_max14526",
+ .id = UCLASS_EXTCON,
+ .of_match = max14526_ids,
+ .probe = max14526_probe,
+ .priv_auto = sizeof(struct max14526_priv),
+};
diff --git a/drivers/extcon/extcon-sandbox.c b/drivers/extcon/extcon-sandbox.c
new file mode 100644
index 00000000000..ab6a6c1cfdc
--- /dev/null
+++ b/drivers/extcon/extcon-sandbox.c
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <dm.h>
+
+static const struct udevice_id sandbox_extcon_ids[] = {
+ { .compatible = "sandbox,extcon" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(extcon_sandbox) = {
+ .name = "extcon_sandbox",
+ .id = UCLASS_EXTCON,
+ .of_match = sandbox_extcon_ids,
+};
diff --git a/drivers/extcon/extcon-uclass.c b/drivers/extcon/extcon-uclass.c
new file mode 100644
index 00000000000..9dd22b57626
--- /dev/null
+++ b/drivers/extcon/extcon-uclass.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#define LOG_CATEGORY UCLASS_EXTCON
+
+#include <common.h>
+#include <extcon.h>
+#include <dm.h>
+
+UCLASS_DRIVER(extcon) = {
+ .id = UCLASS_EXTCON,
+ .name = "extcon",
+ .per_device_plat_auto = sizeof(struct extcon_uc_plat),
+};
diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig
index eefa34779c4..a3df9aa3d0f 100644
--- a/drivers/fastboot/Kconfig
+++ b/drivers/fastboot/Kconfig
@@ -4,6 +4,13 @@ config FASTBOOT
bool
imply ANDROID_BOOT_IMAGE
imply CMD_FASTBOOT
+ help
+ Fastboot is a protocol used in Android devices for
+ communicating between the device and a computer during
+ the bootloader stage. It allows the user to flash the
+ device firmware and unlock the bootloader.
+ More information about the protocol and usecases:
+ https://android.googlesource.com/platform/system/core/+/refs/heads/master/fastboot/
config USB_FUNCTION_FASTBOOT
bool "Enable USB fastboot gadget"
@@ -28,6 +35,13 @@ config UDP_FUNCTION_FASTBOOT_PORT
help
The fastboot protocol requires a UDP port number.
+config TCP_FUNCTION_FASTBOOT
+ depends on NET
+ select FASTBOOT
+ bool "Enable fastboot protocol over TCP"
+ help
+ This enables the fastboot protocol over TCP.
+
if FASTBOOT
config FASTBOOT_BUF_ADDR
diff --git a/drivers/fastboot/fb_common.c b/drivers/fastboot/fb_common.c
index 57b6182c46a..621146bc6b0 100644
--- a/drivers/fastboot/fb_common.c
+++ b/drivers/fastboot/fb_common.c
@@ -15,7 +15,7 @@
#include <command.h>
#include <env.h>
#include <fastboot.h>
-#include <net/fastboot.h>
+#include <net.h>
/**
* fastboot_buf_addr - base address of the fastboot download buffer
@@ -157,6 +157,37 @@ void fastboot_boot(void)
}
/**
+ * fastboot_handle_boot() - Shared implementation of system reaction to
+ * fastboot commands
+ *
+ * Making desceisions about device boot state (stay in fastboot, reboot
+ * to bootloader, reboot to OS, etc).
+ */
+void fastboot_handle_boot(int command, bool success)
+{
+ if (!success)
+ return;
+
+ switch (command) {
+ case FASTBOOT_COMMAND_BOOT:
+ fastboot_boot();
+ net_set_state(NETLOOP_SUCCESS);
+ break;
+
+ case FASTBOOT_COMMAND_CONTINUE:
+ net_set_state(NETLOOP_SUCCESS);
+ break;
+
+ case FASTBOOT_COMMAND_REBOOT:
+ case FASTBOOT_COMMAND_REBOOT_BOOTLOADER:
+ case FASTBOOT_COMMAND_REBOOT_FASTBOOTD:
+ case FASTBOOT_COMMAND_REBOOT_RECOVERY:
+ do_reset(NULL, 0, 0, NULL);
+ break;
+ }
+}
+
+/**
* fastboot_set_progress_callback() - set progress callback
*
* @progress: Pointer to progress callback
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 4e1ae03e9fd..04460f1acb2 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -511,6 +511,13 @@ config WINBOND_W83627
legacy UART or other devices in the Winbond Super IO chips
on X86 platforms.
+config QCOM_GENI_SE
+ bool "Qualcomm GENI Serial Engine Driver"
+ depends on ARCH_SNAPDRAGON
+ help
+ The driver manages Generic Interface (GENI) firmware based
+ Qualcomm Technologies, Inc. Universal Peripheral (QUP) Wrapper.
+
config QFW
bool
help
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 3b792f2a14c..52aed096021 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -60,6 +60,7 @@ obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o
obj-$(CONFIG_P2SB) += p2sb-uclass.o
obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o
+obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o
ifdef CONFIG_QFW
obj-y += qfw.o
obj-$(CONFIG_QFW_PIO) += qfw_pio.o
diff --git a/drivers/misc/esm_pmic.c b/drivers/misc/esm_pmic.c
index a195dc5eb1d..b971f32f6a1 100644
--- a/drivers/misc/esm_pmic.c
+++ b/drivers/misc/esm_pmic.c
@@ -26,6 +26,9 @@
#define ESM_MCU_EN BIT(6)
#define ESM_MCU_ENDRV BIT(5)
+#define ESM_MCU_MASK_REG 0x59
+#define ESM_MCU_MASK 0x7
+
/**
* pmic_esm_probe: configures and enables PMIC ESM functionality
*
@@ -48,6 +51,12 @@ static int pmic_esm_probe(struct udevice *dev)
return ret;
}
+ ret = pmic_reg_write(dev->parent, ESM_MCU_MASK_REG, ESM_MCU_MASK);
+ if (ret) {
+ dev_err(dev, "clearing ESM masks failed: %d\n", ret);
+ return ret;
+ }
+
ret = pmic_reg_write(dev->parent, ESM_MCU_START_REG, ESM_MCU_START);
if (ret) {
dev_err(dev, "starting ESM failed: %d\n", ret);
diff --git a/drivers/misc/qcom-geni-se.c b/drivers/misc/qcom-geni-se.c
new file mode 100644
index 00000000000..281a5ec819a
--- /dev/null
+++ b/drivers/misc/qcom-geni-se.c
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm Generic Interface (GENI) Serial Engine (SE) Wrapper
+ *
+ * Copyright (C) 2023 Linaro Ltd. <vladimir.zapolskiy@linaro.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <misc.h>
+#include <asm/io.h>
+
+static int geni_se_qup_read(struct udevice *dev, int offset,
+ void *buf, int size)
+{
+ fdt_addr_t base = dev_read_addr(dev);
+
+ if (size != sizeof(u32))
+ return -EINVAL;
+
+ *(u32 *)buf = readl(base + offset);
+
+ return size;
+}
+
+static struct misc_ops geni_se_qup_ops = {
+ .read = geni_se_qup_read,
+};
+
+static const struct udevice_id geni_se_qup_ids[] = {
+ { .compatible = "qcom,geni-se-qup" },
+ {}
+};
+
+U_BOOT_DRIVER(geni_se_qup) = {
+ .name = "geni_se_qup",
+ .id = UCLASS_MISC,
+ .of_match = geni_se_qup_ids,
+ .ops = &geni_se_qup_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/mmc/hi6220_dw_mmc.c b/drivers/mmc/hi6220_dw_mmc.c
index 2cec5b9ae32..71962cd47e0 100644
--- a/drivers/mmc/hi6220_dw_mmc.c
+++ b/drivers/mmc/hi6220_dw_mmc.c
@@ -100,6 +100,8 @@ static const struct udevice_id hi6220_dwmmc_ids[] = {
.data = (ulong)&hi6220_mmc_data },
{ .compatible = "hisilicon,hi3798cv200-dw-mshc",
.data = (ulong)&hi6220_mmc_data },
+ { .compatible = "hisilicon,hi3798mv200-dw-mshc",
+ .data = (ulong)&hi6220_mmc_data },
{ .compatible = "hisilicon,hi3660-dw-mshc",
.data = (ulong)&hi3660_mmc_data },
{ }
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 2c3116ee530..6093277f171 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -669,6 +669,7 @@ static int set_4byte(struct spi_nor *nor, const struct flash_info *info,
case SNOR_MFR_MICRON:
/* Some Micron need WREN command; all will accept it */
need_wren = true;
+ fallthrough;
case SNOR_MFR_ISSI:
case SNOR_MFR_MACRONIX:
case SNOR_MFR_WINBOND:
@@ -903,6 +904,30 @@ static int read_bar(struct spi_nor *nor, const struct flash_info *info)
}
#endif
+/**
+ * spi_nor_erase_chip() - Erase the entire flash memory.
+ * @nor: pointer to 'struct spi_nor'.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_erase_chip(struct spi_nor *nor)
+{
+ struct spi_mem_op op =
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CHIP_ERASE, 0),
+ SPI_MEM_OP_NO_ADDR,
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_NO_DATA);
+ int ret;
+
+ spi_nor_setup_op(nor, &op, nor->write_proto);
+
+ ret = spi_mem_exec_op(nor->spi, &op);
+ if (ret)
+ return ret;
+
+ return nor->mtd.size;
+}
+
/*
* Initiate the erasure of a single sector. Returns the number of bytes erased
* on success, a negative error code on error.
@@ -974,7 +999,12 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
if (ret < 0)
goto erase_err;
- ret = spi_nor_erase_sector(nor, addr);
+ if (len == mtd->size &&
+ !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) {
+ ret = spi_nor_erase_chip(nor);
+ } else {
+ ret = spi_nor_erase_sector(nor, addr);
+ }
if (ret < 0)
goto erase_err;
@@ -3199,6 +3229,87 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
/* Use ID byte 4 to distinguish S25FS256T and S25Hx-T */
#define S25FS256T_ID4 (0x08)
+/* Number of dummy cycle for Read Any Register (RDAR) op. */
+#define S25FS_S_RDAR_DUMMY 8
+
+static int s25fs_s_quad_enable(struct spi_nor *nor)
+{
+ return spansion_quad_enable_volatile(nor, 0, S25FS_S_RDAR_DUMMY);
+}
+
+static int s25fs_s_erase_non_uniform(struct spi_nor *nor, loff_t addr)
+{
+ /* Support 8 x 4KB sectors at bottom */
+ return spansion_erase_non_uniform(nor, addr, SPINOR_OP_BE_4K_4B, 0, SZ_32K);
+}
+
+static int s25fs_s_setup(struct spi_nor *nor, const struct flash_info *info,
+ const struct spi_nor_flash_parameter *params)
+{
+ int ret;
+ u8 cfr3v;
+
+ /* Bank Address Register is not supported */
+ if (CONFIG_IS_ENABLED(SPI_FLASH_BAR))
+ return -EOPNOTSUPP;
+
+ /*
+ * Read CR3V to check if uniform sector is selected. If not, assign an
+ * erase hook that supports non-uniform erase.
+ */
+ ret = spansion_read_any_reg(nor, SPINOR_REG_ADDR_CFR3V,
+ S25FS_S_RDAR_DUMMY, &cfr3v);
+ if (ret)
+ return ret;
+ if (!(cfr3v & CFR3V_UNHYSA))
+ nor->erase = s25fs_s_erase_non_uniform;
+
+ return spi_nor_default_setup(nor, info, params);
+}
+
+static void s25fs_s_default_init(struct spi_nor *nor)
+{
+ nor->setup = s25fs_s_setup;
+}
+
+static int s25fs_s_post_bfpt_fixup(struct spi_nor *nor,
+ const struct sfdp_parameter_header *header,
+ const struct sfdp_bfpt *bfpt,
+ struct spi_nor_flash_parameter *params)
+{
+ /* The erase size is set to 4K from BFPT, but it's wrong. Fix it. */
+ nor->erase_opcode = SPINOR_OP_SE;
+ nor->mtd.erasesize = nor->info->sector_size;
+
+ /* The S25FS-S chip family reports 512-byte pages in BFPT but
+ * in reality the write buffer still wraps at the safe default
+ * of 256 bytes. Overwrite the page size advertised by BFPT
+ * to get the writes working.
+ */
+ params->page_size = 256;
+
+ return 0;
+}
+
+static void s25fs_s_post_sfdp_fixup(struct spi_nor *nor,
+ struct spi_nor_flash_parameter *params)
+{
+ /* READ_1_1_2 is not supported */
+ params->hwcaps.mask &= ~SNOR_HWCAPS_READ_1_1_2;
+ /* READ_1_1_4 is not supported */
+ params->hwcaps.mask &= ~SNOR_HWCAPS_READ_1_1_4;
+ /* PP_1_1_4 is not supported */
+ params->hwcaps.mask &= ~SNOR_HWCAPS_PP_1_1_4;
+ /* Use volatile register to enable quad */
+ params->quad_enable = s25fs_s_quad_enable;
+}
+
+static struct spi_nor_fixups s25fs_s_fixups = {
+ .default_init = s25fs_s_default_init,
+ .post_bfpt = s25fs_s_post_bfpt_fixup,
+ .post_sfdp = s25fs_s_post_sfdp_fixup,
+};
+
static int s25_mdp_ready(struct spi_nor *nor)
{
u32 addr;
@@ -3897,6 +4008,10 @@ void spi_nor_set_fixups(struct spi_nor *nor)
if (CONFIG_IS_ENABLED(SPI_FLASH_BAR) &&
!strcmp(nor->info->name, "s25fl256l"))
nor->fixups = &s25fl256l_fixups;
+
+ /* For FS-S (family ID = 0x81) */
+ if (JEDEC_MFR(nor->info) == SNOR_MFR_SPANSION && nor->info->id[5] == 0x81)
+ nor->fixups = &s25fs_s_fixups;
#endif
#ifdef CONFIG_SPI_FLASH_MT35XU
diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c
index ec58697b311..9bbba6eed07 100644
--- a/drivers/net/dwc_eth_qos.c
+++ b/drivers/net/dwc_eth_qos.c
@@ -794,9 +794,21 @@ static int eqos_start(struct udevice *dev)
*/
if (!eqos->phy) {
int addr = -1;
- addr = eqos_get_phy_addr(eqos, dev);
- eqos->phy = phy_connect(eqos->mii, addr, dev,
- eqos->config->interface(dev));
+ ofnode fixed_node;
+
+ if (IS_ENABLED(CONFIG_PHY_FIXED)) {
+ fixed_node = ofnode_find_subnode(dev_ofnode(dev),
+ "fixed-link");
+ if (ofnode_valid(fixed_node))
+ eqos->phy = fixed_phy_create(dev_ofnode(dev));
+ }
+
+ if (!eqos->phy) {
+ addr = eqos_get_phy_addr(eqos, dev);
+ eqos->phy = phy_connect(eqos->mii, addr, dev,
+ eqos->config->interface(dev));
+ }
+
if (!eqos->phy) {
pr_err("phy_connect() failed");
goto err_stop_resets;
diff --git a/drivers/net/fsl-mc/mc.c b/drivers/net/fsl-mc/mc.c
index 4f84403d956..78a40f285aa 100644
--- a/drivers/net/fsl-mc/mc.c
+++ b/drivers/net/fsl-mc/mc.c
@@ -29,6 +29,7 @@
#include <fsl-mc/fsl_dpsparser.h>
#include <fsl-mc/fsl_qbman_portal.h>
#include <fsl-mc/ldpaa_wriop.h>
+#include <net/ldpaa_eth.h>
#define MC_RAM_BASE_ADDR_ALIGNMENT (512UL * 1024 * 1024)
#define MC_RAM_BASE_ADDR_ALIGNMENT_MASK (~(MC_RAM_BASE_ADDR_ALIGNMENT - 1))
@@ -383,37 +384,31 @@ static int mc_fixup_dpc_mac_addr(void *blob, int dpmac_id,
static int mc_fixup_mac_addrs(void *blob, enum mc_fixup_type type)
{
- int i, err = 0, ret = 0;
-#define ETH_NAME_LEN 20
struct udevice *eth_dev;
- char ethname[ETH_NAME_LEN];
-
- for (i = WRIOP1_DPMAC1; i < NUM_WRIOP_PORTS; i++) {
- /* port not enabled */
- if (wriop_is_enabled_dpmac(i) != 1)
- continue;
-
- snprintf(ethname, ETH_NAME_LEN, "DPMAC%d@%s", i,
- phy_interface_strings[wriop_get_enet_if(i)]);
-
- eth_dev = eth_get_dev_by_name(ethname);
- if (eth_dev == NULL)
+ int err = 0, ret = 0;
+ struct uclass *uc;
+ uint32_t dpmac_id;
+
+ uclass_get(UCLASS_ETH, &uc);
+ uclass_foreach_dev(eth_dev, uc) {
+ if (!eth_dev->driver || !eth_dev->driver->name ||
+ strcmp(eth_dev->driver->name, LDPAA_ETH_DRIVER_NAME))
continue;
+ dpmac_id = ldpaa_eth_get_dpmac_id(eth_dev);
switch (type) {
case MC_FIXUP_DPL:
- err = mc_fixup_dpl_mac_addr(blob, i, eth_dev);
+ err = mc_fixup_dpl_mac_addr(blob, dpmac_id, eth_dev);
break;
case MC_FIXUP_DPC:
- err = mc_fixup_dpc_mac_addr(blob, i, eth_dev);
+ err = mc_fixup_dpc_mac_addr(blob, dpmac_id, eth_dev);
break;
default:
break;
}
if (err)
- printf("fsl-mc: ERROR fixing mac address for %s\n",
- ethname);
+ printf("fsl-mc: ERROR fixing mac address for %s\n", eth_dev->name);
ret |= err;
}
diff --git a/drivers/net/ksz9477.c b/drivers/net/ksz9477.c
index fb5c76c600b..6b59b5fcd26 100644
--- a/drivers/net/ksz9477.c
+++ b/drivers/net/ksz9477.c
@@ -337,11 +337,21 @@ static int ksz_port_setup(struct udevice *dev, int port,
return 0;
}
+static int ksz_port_probe(struct udevice *dev, int port, struct phy_device *phy)
+{
+ int supported = PHY_GBIT_FEATURES;
+
+ /* configure phy */
+ phy->supported &= supported;
+ phy->advertising &= supported;
+
+ return phy_config(phy);
+}
+
static int ksz_port_enable(struct udevice *dev, int port, struct phy_device *phy)
{
struct dsa_pdata *pdata = dev_get_uclass_plat(dev);
struct ksz_dsa_priv *priv = dev_get_priv(dev);
- int supported = PHY_GBIT_FEATURES;
u8 data8;
int ret;
@@ -365,23 +375,12 @@ static int ksz_port_enable(struct udevice *dev, int port, struct phy_device *phy
if (port == pdata->cpu_port)
return 0;
- /* configure phy */
- phy->supported &= supported;
- phy->advertising &= supported;
- ret = phy_config(phy);
- if (ret)
- return ret;
-
- ret = phy_startup(phy);
- if (ret)
- return ret;
-
/* start switch */
ksz_read8(priv->dev, REG_SW_OPERATION, &data8);
data8 |= SW_START;
ksz_write8(priv->dev, REG_SW_OPERATION, data8);
- return 0;
+ return phy_startup(phy);
}
static void ksz_port_disable(struct udevice *dev, int port, struct phy_device *phy)
@@ -410,6 +409,7 @@ static void ksz_port_disable(struct udevice *dev, int port, struct phy_device *p
}
static const struct dsa_ops ksz_dsa_ops = {
+ .port_probe = ksz_port_probe,
.port_enable = ksz_port_enable,
.port_disable = ksz_port_disable,
};
@@ -443,15 +443,10 @@ static int ksz_i2c_probe(struct udevice *dev)
{
struct dsa_pdata *pdata = dev_get_uclass_plat(dev);
struct ksz_dsa_priv *priv = dev_get_priv(dev);
- struct udevice *master = dsa_get_master(dev);
int i, ret;
u8 data8;
u32 id;
- if (!master)
- return -ENODEV;
-
- dev_dbg(dev, "%s %s master:%s\n", __func__, dev->name, master->name);
dev_set_parent_priv(dev, priv);
ret = i2c_set_chip_offset_len(dev, 2);
@@ -501,8 +496,6 @@ static int ksz_i2c_probe(struct udevice *dev)
ksz_pwrite8(priv->dev, i, REG_PORT_MSTP_STATE, data8);
}
- dsa_set_tagging(dev, 0, 0);
-
return 0;
};
diff --git a/drivers/net/ldpaa_eth/ldpaa_eth.c b/drivers/net/ldpaa_eth/ldpaa_eth.c
index 24850777949..2cb6e9b7d70 100644
--- a/drivers/net/ldpaa_eth/ldpaa_eth.c
+++ b/drivers/net/ldpaa_eth/ldpaa_eth.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2014-2016 Freescale Semiconductor, Inc.
- * Copyright 2017 NXP
+ * Copyright 2017, 2023 NXP
*/
#include <common.h>
@@ -21,6 +21,7 @@
#include <linux/compat.h>
#include <linux/delay.h>
#include <asm/global_data.h>
+#include <net/ldpaa_eth.h>
#include "ldpaa_eth.h"
#ifdef CONFIG_PHYLIB
@@ -995,7 +996,7 @@ static int ldpaa_eth_probe(struct udevice *dev)
return 0;
}
-static uint32_t ldpaa_eth_get_dpmac_id(struct udevice *dev)
+uint32_t ldpaa_eth_get_dpmac_id(struct udevice *dev)
{
int port_node = dev_of_offset(dev);
@@ -1049,7 +1050,7 @@ static const struct udevice_id ldpaa_eth_of_ids[] = {
};
U_BOOT_DRIVER(ldpaa_eth) = {
- .name = "ldpaa_eth",
+ .name = LDPAA_ETH_DRIVER_NAME,
.id = UCLASS_ETH,
.of_match = ldpaa_eth_of_ids,
.of_to_plat = ldpaa_eth_of_to_plat,
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index ea98cfcc1b5..36c70da181a 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -162,18 +162,6 @@ static int bcm5482_config(struct phy_device *phydev)
return 0;
}
-static int bcm_cygnus_startup(struct phy_device *phydev)
-{
- int ret;
-
- /* Read the Status (2x to make sure link is right) */
- ret = genphy_update_link(phydev);
- if (ret)
- return ret;
-
- return genphy_parse_link(phydev);
-}
-
static void bcm_cygnus_afe(struct phy_device *phydev)
{
/* ensures smdspclk is enabled */
@@ -359,6 +347,6 @@ U_BOOT_PHY_DRIVER(bcm_cygnus) = {
.mask = 0xfffff0,
.features = PHY_GBIT_FEATURES,
.config = &bcm_cygnus_config,
- .startup = &bcm_cygnus_startup,
+ .startup = &genphy_startup,
.shutdown = &genphy_shutdown,
};
diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c
index b861bf7cef3..7111e36aa0d 100644
--- a/drivers/net/phy/dp83867.c
+++ b/drivers/net/phy/dp83867.c
@@ -330,7 +330,7 @@ static int dp83867_config(struct phy_device *phydev)
DP83867_RGMIIDCTL, delay);
}
- if (phy_interface_is_sgmii(phydev)) {
+ if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
if (dp83867->sgmii_ref_clk_en)
phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_SGMIICTL,
DP83867_SGMII_TYPE);
diff --git a/drivers/net/phy/ethernet_id.c b/drivers/net/phy/ethernet_id.c
index 8864f99bb32..a715e83db98 100644
--- a/drivers/net/phy/ethernet_id.c
+++ b/drivers/net/phy/ethernet_id.c
@@ -39,7 +39,7 @@ struct phy_device *phy_connect_phy_id(struct mii_dev *bus, struct udevice *dev,
if (!IS_ENABLED(CONFIG_DM_ETH_PHY)) {
ret = gpio_request_by_name_nodev(node, "reset-gpios", 0, &gpio,
- GPIOD_ACTIVE_LOW);
+ GPIOD_IS_OUT | GPIOD_ACTIVE_LOW);
if (!ret) {
assert = ofnode_read_u32_default(node,
"reset-assert-us", 0);
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index 247d9753a88..396cac76d63 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -384,17 +384,6 @@ static int rtl8211x_startup(struct phy_device *phydev)
return rtl8211x_parse_status(phydev);
}
-static int rtl8211e_startup(struct phy_device *phydev)
-{
- int ret;
-
- ret = genphy_update_link(phydev);
- if (ret)
- return ret;
-
- return genphy_parse_link(phydev);
-}
-
static int rtl8211f_startup(struct phy_device *phydev)
{
int ret;
@@ -428,7 +417,7 @@ U_BOOT_PHY_DRIVER(rtl8211e) = {
.features = PHY_GBIT_FEATURES,
.probe = &rtl8211e_probe,
.config = &rtl8211e_config,
- .startup = &rtl8211e_startup,
+ .startup = &genphy_startup,
.shutdown = &genphy_shutdown,
};
@@ -465,6 +454,6 @@ U_BOOT_PHY_DRIVER(rtl8201f) = {
.features = PHY_BASIC_FEATURES,
.probe = &rtl8210f_probe,
.config = &rtl8201f_config,
- .startup = &rtl8211e_startup,
+ .startup = &genphy_startup,
.shutdown = &genphy_shutdown,
};
diff --git a/drivers/net/phy/xilinx_gmii2rgmii.c b/drivers/net/phy/xilinx_gmii2rgmii.c
index 0b7436a7e1e..e2969bc4842 100644
--- a/drivers/net/phy/xilinx_gmii2rgmii.c
+++ b/drivers/net/phy/xilinx_gmii2rgmii.c
@@ -48,7 +48,14 @@ static int xilinxgmiitorgmii_config(struct phy_device *phydev)
return -EINVAL;
}
- ext_phydev->interface = PHY_INTERFACE_MODE_RGMII;
+ ext_phydev->interface = ofnode_read_phy_mode(node);
+ if (ext_phydev->interface == PHY_INTERFACE_MODE_NA) {
+ ext_phydev->interface = PHY_INTERFACE_MODE_RGMII;
+ } else if (!phy_interface_is_rgmii(ext_phydev)) {
+ printf("Incorrect external interface type\n");
+ return -EINVAL;
+ }
+
ext_phydev->node = phandle.node;
phydev->priv = ext_phydev;
diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c
index c9c07a5a8ff..2276a465e78 100644
--- a/drivers/net/rtl8169.c
+++ b/drivers/net/rtl8169.c
@@ -118,9 +118,9 @@ enum RTL8169_registers {
FLASH = 0x30,
ERSR = 0x36,
ChipCmd = 0x37,
- TxPoll = 0x38,
- IntrMask = 0x3C,
- IntrStatus = 0x3E,
+ TxPoll_8169 = 0x38,
+ IntrMask_8169 = 0x3C,
+ IntrStatus_8169 = 0x3E,
TxConfig = 0x40,
RxConfig = 0x44,
RxMissed = 0x4C,
@@ -148,6 +148,12 @@ enum RTL8169_registers {
FuncForceEvent = 0xFC,
};
+enum RTL8125_registers {
+ IntrMask_8125 = 0x38,
+ IntrStatus_8125 = 0x3C,
+ TxPoll_8125 = 0x90,
+};
+
enum RTL8169_register_content {
/*InterruptStatusBits */
SYSErr = 0x8000,
@@ -263,6 +269,7 @@ static struct {
{"RTL-8101e", 0x34, 0xff7e1880,},
{"RTL-8100e", 0x32, 0xff7e1880,},
{"RTL-8168h/8111h", 0x54, 0xff7e1880,},
+ {"RTL-8125B", 0x64, 0xff7e1880,},
};
enum _DescStatusBit {
@@ -347,6 +354,7 @@ static struct pci_device_id supported[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167) },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168) },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169) },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8125) },
{}
};
@@ -517,6 +525,7 @@ static int rtl_recv_common(struct udevice *dev, unsigned long dev_iobase,
/* return true if there's an ethernet packet ready to read */
/* nic->packet should contain data on return */
/* nic->packetlen should contain length of data */
+ struct pci_child_plat *pplat = dev_get_parent_plat(dev);
int cur_rx;
int length = 0;
@@ -558,6 +567,10 @@ static int rtl_recv_common(struct udevice *dev, unsigned long dev_iobase,
return length;
} else {
+ u32 IntrStatus = IntrStatus_8169;
+
+ if (pplat->device == 0x8125)
+ IntrStatus = IntrStatus_8125;
ushort sts = RTL_R8(IntrStatus);
RTL_W8(IntrStatus, sts & ~(TxErr | RxErr | SYSErr));
udelay(100); /* wait */
@@ -582,6 +595,7 @@ static int rtl_send_common(struct udevice *dev, unsigned long dev_iobase,
{
/* send the packet to destination */
+ struct pci_child_plat *pplat = dev_get_parent_plat(dev);
u32 to;
u8 *ptxb;
int entry = tpc->cur_tx % NUM_TX_DESC;
@@ -618,7 +632,10 @@ static int rtl_send_common(struct udevice *dev, unsigned long dev_iobase,
((len > ETH_ZLEN) ? len : ETH_ZLEN));
}
rtl_flush_tx_desc(&tpc->TxDescArray[entry]);
- RTL_W8(TxPoll, 0x40); /* set polling bit */
+ if (pplat->device == 0x8125)
+ RTL_W8(TxPoll_8125, 0x1); /* set polling bit */
+ else
+ RTL_W8(TxPoll_8169, 0x40); /* set polling bit */
tpc->cur_tx++;
to = currticks() + TX_TIMEOUT;
@@ -824,21 +841,26 @@ static int rtl8169_eth_start(struct udevice *dev)
return 0;
}
-static void rtl_halt_common(unsigned long dev_iobase)
+static void rtl_halt_common(struct udevice *dev)
{
+ struct rtl8169_private *priv = dev_get_priv(dev);
+ struct pci_child_plat *pplat = dev_get_parent_plat(dev);
int i;
#ifdef DEBUG_RTL8169
printf ("%s\n", __FUNCTION__);
#endif
- ioaddr = dev_iobase;
+ ioaddr = priv->iobase;
/* Stop the chip's Tx and Rx DMA processes. */
RTL_W8(ChipCmd, 0x00);
/* Disable interrupts by clearing the interrupt mask. */
- RTL_W16(IntrMask, 0x0000);
+ if (pplat->device == 0x8125)
+ RTL_W16(IntrMask_8125, 0x0000);
+ else
+ RTL_W16(IntrMask_8169, 0x0000);
RTL_W32(RxMissed, 0);
@@ -849,9 +871,7 @@ static void rtl_halt_common(unsigned long dev_iobase)
void rtl8169_eth_stop(struct udevice *dev)
{
- struct rtl8169_private *priv = dev_get_priv(dev);
-
- rtl_halt_common(priv->iobase);
+ rtl_halt_common(dev);
}
static int rtl8169_write_hwaddr(struct udevice *dev)
@@ -1025,23 +1045,25 @@ static int rtl8169_eth_probe(struct udevice *dev)
struct pci_child_plat *pplat = dev_get_parent_plat(dev);
struct rtl8169_private *priv = dev_get_priv(dev);
struct eth_pdata *plat = dev_get_plat(dev);
- u32 iobase;
int region;
int ret;
- debug("rtl8169: REALTEK RTL8169 @0x%x\n", iobase);
switch (pplat->device) {
case 0x8168:
+ case 0x8125:
region = 2;
break;
default:
region = 1;
break;
}
- dm_pci_read_config32(dev, PCI_BASE_ADDRESS_0 + region * 4, &iobase);
- iobase &= ~0xf;
- priv->iobase = (int)dm_pci_mem_to_phys(dev, iobase);
+ priv->iobase = (ulong)dm_pci_map_bar(dev,
+ PCI_BASE_ADDRESS_0 + region * 4,
+ 0, 0,
+ PCI_REGION_TYPE, PCI_REGION_MEM);
+
+ debug("rtl8169: REALTEK RTL8169 @0x%lx\n", priv->iobase);
ret = rtl_init(priv->iobase, dev->name, plat->enetaddr);
if (ret < 0) {
printf(pr_fmt("failed to initialize card: %d\n"), ret);
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c
index 14fd3bbf679..01230360bad 100644
--- a/drivers/pci/pci_auto.c
+++ b/drivers/pci/pci_auto.c
@@ -580,10 +580,6 @@ int dm_pciauto_config_device(struct udevice *dev)
break;
#endif
- case PCI_CLASS_PROCESSOR_POWERPC: /* an agent or end-point */
- debug("PCI AutoConfig: Found PowerPC device\n");
- /* fall through */
-
default:
dm_pciauto_setup_device(dev, pci_mem, pci_prefetch, pci_io);
break;
diff --git a/drivers/pci/pci_mpc85xx.c b/drivers/pci/pci_mpc85xx.c
index 8a81a74067e..249cfe66466 100644
--- a/drivers/pci/pci_mpc85xx.c
+++ b/drivers/pci/pci_mpc85xx.c
@@ -22,10 +22,33 @@ static int mpc85xx_pci_dm_read_config(const struct udevice *dev, pci_dev_t bdf,
struct mpc85xx_pci_priv *priv = dev_get_priv(dev);
u32 addr;
- addr = PCI_CONF1_EXT_ADDRESS(PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), offset);
+ if (offset > 0xff) {
+ *value = pci_get_ff(size);
+ return 0;
+ }
+
+ /* Skip mpc85xx PCI controller's ATMU inbound registers */
+ if (PCI_BUS(bdf) == 0 && PCI_DEV(bdf) == 0 && PCI_FUNC(bdf) == 0 &&
+ (offset & ~3) >= PCI_BASE_ADDRESS_0 && (offset & ~3) <= PCI_BASE_ADDRESS_5) {
+ *value = 0;
+ return 0;
+ }
+
+ addr = PCI_CONF1_ADDRESS(PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), offset);
out_be32(priv->cfg_addr, addr);
sync();
- *value = pci_conv_32_to_size(in_le32(priv->cfg_data), offset, size);
+
+ switch (size) {
+ case PCI_SIZE_8:
+ *value = in_8(priv->cfg_data + (offset & 3));
+ break;
+ case PCI_SIZE_16:
+ *value = in_le16(priv->cfg_data + (offset & 2));
+ break;
+ case PCI_SIZE_32:
+ *value = in_le32(priv->cfg_data);
+ break;
+ }
return 0;
}
@@ -37,10 +60,30 @@ static int mpc85xx_pci_dm_write_config(struct udevice *dev, pci_dev_t bdf,
struct mpc85xx_pci_priv *priv = dev_get_priv(dev);
u32 addr;
- addr = PCI_CONF1_EXT_ADDRESS(PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), offset);
+ if (offset > 0xff)
+ return 0;
+
+ /* Skip mpc85xx PCI controller's ATMU inbound registers */
+ if (PCI_BUS(bdf) == 0 && PCI_DEV(bdf) == 0 && PCI_FUNC(bdf) == 0 &&
+ (offset & ~3) >= PCI_BASE_ADDRESS_0 && (offset & ~3) <= PCI_BASE_ADDRESS_5)
+ return 0;
+
+ addr = PCI_CONF1_ADDRESS(PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), offset);
out_be32(priv->cfg_addr, addr);
sync();
- out_le32(priv->cfg_data, pci_conv_size_to_32(0, value, offset, size));
+
+ switch (size) {
+ case PCI_SIZE_8:
+ out_8(priv->cfg_data + (offset & 3), value);
+ break;
+ case PCI_SIZE_16:
+ out_le16(priv->cfg_data + (offset & 2), value);
+ break;
+ case PCI_SIZE_32:
+ out_le32(priv->cfg_data, value);
+ break;
+ }
+ sync();
return 0;
}
diff --git a/drivers/pci/pcie_fsl.c b/drivers/pci/pcie_fsl.c
index 4600652f2b1..8d89a1e5919 100644
--- a/drivers/pci/pcie_fsl.c
+++ b/drivers/pci/pcie_fsl.c
@@ -58,6 +58,14 @@ static int fsl_pcie_read_config(const struct udevice *bus, pci_dev_t bdf,
return 0;
}
+ /* Skip Freescale PCIe controller's PEXCSRBAR register */
+ if (PCI_BUS(bdf) - dev_seq(bus) == 0 &&
+ PCI_DEV(bdf) == 0 && PCI_FUNC(bdf) == 0 &&
+ (offset & ~3) == PCI_BASE_ADDRESS_0) {
+ *valuep = 0;
+ return 0;
+ }
+
val = PCI_CONF1_EXT_ADDRESS(PCI_BUS(bdf) - dev_seq(bus),
PCI_DEV(bdf), PCI_FUNC(bdf),
offset);
@@ -95,6 +103,12 @@ static int fsl_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
if (fsl_pcie_addr_valid(pcie, bdf))
return 0;
+ /* Skip Freescale PCIe controller's PEXCSRBAR register */
+ if (PCI_BUS(bdf) - dev_seq(bus) == 0 &&
+ PCI_DEV(bdf) == 0 && PCI_FUNC(bdf) == 0 &&
+ (offset & ~3) == PCI_BASE_ADDRESS_0)
+ return 0;
+
val = PCI_CONF1_EXT_ADDRESS(PCI_BUS(bdf) - dev_seq(bus),
PCI_DEV(bdf), PCI_FUNC(bdf),
offset);
diff --git a/drivers/pci/pcie_layerscape_rc.c b/drivers/pci/pcie_layerscape_rc.c
index 17969e2f236..6a5bf88da23 100644
--- a/drivers/pci/pcie_layerscape_rc.c
+++ b/drivers/pci/pcie_layerscape_rc.c
@@ -403,6 +403,7 @@ static const struct ls_pcie_drvdata ls1028a_drvdata = {
static const struct udevice_id ls_pcie_ids[] = {
{ .compatible = "fsl,ls-pcie" },
{ .compatible = "fsl,ls1028a-pcie", .data = (ulong)&ls1028a_drvdata },
+ { .compatible = "fsl,ls1088a-pcie", .data = (ulong)&ls1028a_drvdata },
{ }
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index 47e2d67426f..5a4d58b3272 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -349,10 +349,10 @@ int mtk_pinconf_bias_set_v1(struct udevice *dev, u32 pin, bool disable,
{
int err;
- /* try pupd_r1_r0 if pullen_pullsel return error */
+ /* set pupd_r1_r0 if pullen_pullsel succeeded */
err = mtk_pinconf_bias_set_pullen_pullsel(dev, pin, disable, pullup,
val);
- if (err)
+ if (!err)
return mtk_pinconf_bias_set_pupd_r1_r0(dev, pin, disable,
pullup, val);
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 10d07daf277..7faf6784442 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -946,6 +946,8 @@ config MSM_SERIAL
config MSM_GENI_SERIAL
bool "Qualcomm on-chip GENI UART"
+ select MISC
+ imply QCOM_GENI_SE
help
Support UART based on Generic Interface (GENI) Serial Engine (SE),
used on Qualcomm Snapdragon SoCs. Should support all qualcomm SOCs
diff --git a/drivers/serial/serial_msm_geni.c b/drivers/serial/serial_msm_geni.c
index 3943ca43e49..78fd9389c03 100644
--- a/drivers/serial/serial_msm_geni.c
+++ b/drivers/serial/serial_msm_geni.c
@@ -11,15 +11,10 @@
#include <clk.h>
#include <common.h>
#include <dm.h>
-#include <dm/pinctrl.h>
#include <errno.h>
-#include <linux/compiler.h>
-#include <log.h>
#include <linux/delay.h>
-#include <malloc.h>
+#include <misc.h>
#include <serial.h>
-#include <watchdog.h>
-#include <linux/bug.h>
#define UART_OVERSAMPLING 32
#define STALE_TIMEOUT 160
@@ -116,6 +111,10 @@
#define TX_FIFO_DEPTH_MSK (GENMASK(21, 16))
#define TX_FIFO_DEPTH_SHFT 16
+/* GENI SE QUP Registers */
+#define QUP_HW_VER_REG 0x4
+#define QUP_SE_VERSION_2_5 0x20050000
+
/*
* Predefined packing configuration of the serial engine (CFG0, CFG1 regs)
* for uart mode.
@@ -133,11 +132,12 @@ DECLARE_GLOBAL_DATA_PTR;
struct msm_serial_data {
phys_addr_t base;
u32 baud;
+ u32 oversampling;
};
unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200,
- 32000000, 48000000, 64000000, 80000000,
- 96000000, 100000000};
+ 32000000, 48000000, 64000000, 80000000,
+ 96000000, 100000000};
/**
* get_clk_cfg() - Get clock rate to apply on clock supplier.
@@ -166,8 +166,7 @@ static int get_clk_cfg(unsigned long clk_freq)
*
* Return: frequency, supported by clock supplier, multiple of clk_freq.
*/
-static int get_clk_div_rate(u32 baud,
- u64 sampling_rate, u32 *clk_div)
+static int get_clk_div_rate(u32 baud, u64 sampling_rate, u32 *clk_div)
{
unsigned long ser_clk;
unsigned long desired_clk;
@@ -189,7 +188,7 @@ static int geni_serial_set_clock_rate(struct udevice *dev, u64 rate)
struct clk *clk;
int ret;
- clk = devm_clk_get(dev, "se-clk");
+ clk = devm_clk_get(dev, NULL);
if (!clk)
return -EINVAL;
@@ -234,7 +233,7 @@ static inline u32 geni_se_get_tx_fifo_width(long base)
}
static inline void geni_serial_baud(phys_addr_t base_address, u32 clk_div,
- int baud)
+ int baud)
{
u32 s_clk_cfg = 0;
@@ -245,15 +244,15 @@ static inline void geni_serial_baud(phys_addr_t base_address, u32 clk_div,
writel(s_clk_cfg, base_address + GENI_SER_S_CLK_CFG);
}
-int msm_serial_setbrg(struct udevice *dev, int baud)
+static int msm_serial_setbrg(struct udevice *dev, int baud)
{
struct msm_serial_data *priv = dev_get_priv(dev);
+ u64 clk_rate;
+ u32 clk_div;
priv->baud = baud;
- u32 clk_div;
- u64 clk_rate;
- clk_rate = get_clk_div_rate(baud, UART_OVERSAMPLING, &clk_div);
+ clk_rate = get_clk_div_rate(baud, priv->oversampling, &clk_div);
geni_serial_set_clock_rate(dev, clk_rate);
geni_serial_baud(priv->base, clk_div, baud);
@@ -274,7 +273,7 @@ int msm_serial_setbrg(struct udevice *dev, int baud)
* reached.
*/
static bool qcom_geni_serial_poll_bit(const struct udevice *dev, int offset,
- int field, bool set)
+ int field, bool set)
{
u32 reg;
struct msm_serial_data *priv = dev_get_priv(dev);
@@ -487,6 +486,31 @@ static const struct dm_serial_ops msm_serial_ops = {
.setbrg = msm_serial_setbrg,
};
+static void geni_set_oversampling(struct udevice *dev)
+{
+ struct msm_serial_data *priv = dev_get_priv(dev);
+ struct udevice *parent_dev = dev_get_parent(dev);
+ u32 geni_se_version;
+ int ret;
+
+ priv->oversampling = UART_OVERSAMPLING;
+
+ /*
+ * It could happen that GENI SE IP is missing in the board's device
+ * tree or GENI UART node is a direct child of SoC device tree node.
+ */
+ if (device_get_uclass_id(parent_dev) != UCLASS_MISC)
+ return;
+
+ ret = misc_read(parent_dev, QUP_HW_VER_REG,
+ &geni_se_version, sizeof(geni_se_version));
+ if (ret != sizeof(geni_se_version))
+ return;
+
+ if (geni_se_version >= QUP_SE_VERSION_2_5)
+ priv->oversampling /= 2;
+}
+
static inline void geni_serial_init(struct udevice *dev)
{
struct msm_serial_data *priv = dev_get_priv(dev);
@@ -530,6 +554,8 @@ static int msm_serial_probe(struct udevice *dev)
{
struct msm_serial_data *priv = dev_get_priv(dev);
+ geni_set_oversampling(dev);
+
/* No need to reinitialize the UART after relocation */
if (gd->flags & GD_FLG_RELOC)
return 0;
@@ -554,7 +580,9 @@ static int msm_serial_ofdata_to_platdata(struct udevice *dev)
}
static const struct udevice_id msm_serial_ids[] = {
- {.compatible = "qcom,msm-geni-uart"}, {}};
+ { .compatible = "qcom,geni-debug-uart" },
+ { }
+};
U_BOOT_DRIVER(serial_msm_geni) = {
.name = "serial_msm_geni",
@@ -564,6 +592,7 @@ U_BOOT_DRIVER(serial_msm_geni) = {
.priv_auto = sizeof(struct msm_serial_data),
.probe = msm_serial_probe,
.ops = &msm_serial_ops,
+ .flags = DM_FLAG_PRE_RELOC,
};
#ifdef CONFIG_DEBUG_UART_MSM_GENI
diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index c7f10c50132..f931e4cf3e2 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -312,13 +312,12 @@ static int cadence_spi_mem_exec_op(struct spi_slave *spi,
* which is unsupported on some flash devices during register
* reads, prefer STIG mode for such small reads.
*/
- if (!op->addr.nbytes ||
- op->data.nbytes <= CQSPI_STIG_DATA_LEN_MAX)
+ if (op->data.nbytes <= CQSPI_STIG_DATA_LEN_MAX)
mode = CQSPI_STIG_READ;
else
mode = CQSPI_READ;
} else {
- if (!op->addr.nbytes || !op->data.buf.out)
+ if (op->data.nbytes <= CQSPI_STIG_DATA_LEN_MAX)
mode = CQSPI_STIG_WRITE;
else
mode = CQSPI_WRITE;
@@ -362,8 +361,15 @@ static bool cadence_spi_mem_supports_op(struct spi_slave *slave,
{
bool all_true, all_false;
- all_true = op->cmd.dtr && op->addr.dtr && op->dummy.dtr &&
- op->data.dtr;
+ /*
+ * op->dummy.dtr is required for converting nbytes into ncycles.
+ * Also, don't check the dtr field of the op phase having zero nbytes.
+ */
+ all_true = op->cmd.dtr &&
+ (!op->addr.nbytes || op->addr.dtr) &&
+ (!op->dummy.nbytes || op->dummy.dtr) &&
+ (!op->data.nbytes || op->data.dtr);
+
all_false = !op->cmd.dtr && !op->addr.dtr && !op->dummy.dtr &&
!op->data.dtr;
diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
index 21fe2e655c5..9ce2c0f254f 100644
--- a/drivers/spi/cadence_qspi_apb.c
+++ b/drivers/spi/cadence_qspi_apb.c
@@ -120,7 +120,16 @@ static int cadence_qspi_set_protocol(struct cadence_spi_priv *priv,
{
int ret;
- priv->dtr = op->data.dtr && op->cmd.dtr && op->addr.dtr;
+ /*
+ * For an op to be DTR, cmd phase along with every other non-empty
+ * phase should have dtr field set to 1. If an op phase has zero
+ * nbytes, ignore its dtr field; otherwise, check its dtr field.
+ * Also, dummy checks not performed here Since supports_op()
+ * already checks that all or none of the fields are DTR.
+ */
+ priv->dtr = op->cmd.dtr &&
+ (!op->addr.nbytes || op->addr.dtr) &&
+ (!op->data.nbytes || op->data.dtr);
ret = cadence_qspi_buswidth_to_inst_type(op->cmd.buswidth);
if (ret < 0)
@@ -367,6 +376,9 @@ int cadence_qspi_apb_exec_flash_cmd(void *reg_base, unsigned int reg)
if (!cadence_qspi_wait_idle(reg_base))
return -EIO;
+ /* Flush the CMDCTRL reg after the execution */
+ writel(0, reg_base + CQSPI_REG_CMDCTRL);
+
return 0;
}
@@ -453,11 +465,6 @@ int cadence_qspi_apb_command_read(struct cadence_spi_priv *priv,
unsigned int dummy_clk;
u8 opcode;
- if (rxlen > CQSPI_STIG_DATA_LEN_MAX || !rxbuf) {
- printf("QSPI: Invalid input arguments rxlen %u\n", rxlen);
- return -EINVAL;
- }
-
if (priv->dtr)
opcode = op->cmd.opcode >> 8;
else
@@ -540,26 +547,12 @@ int cadence_qspi_apb_command_write(struct cadence_spi_priv *priv,
unsigned int reg = 0;
unsigned int wr_data;
unsigned int wr_len;
+ unsigned int dummy_clk;
unsigned int txlen = op->data.nbytes;
const void *txbuf = op->data.buf.out;
void *reg_base = priv->regbase;
- u32 addr;
u8 opcode;
- /* Reorder address to SPI bus order if only transferring address */
- if (!txlen) {
- addr = cpu_to_be32(op->addr.val);
- if (op->addr.nbytes == 3)
- addr >>= 8;
- txbuf = &addr;
- txlen = op->addr.nbytes;
- }
-
- if (txlen > CQSPI_STIG_DATA_LEN_MAX) {
- printf("QSPI: Invalid input arguments txlen %u\n", txlen);
- return -EINVAL;
- }
-
if (priv->dtr)
opcode = op->cmd.opcode >> 8;
else
@@ -567,6 +560,27 @@ int cadence_qspi_apb_command_write(struct cadence_spi_priv *priv,
reg |= opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
+ /* setup ADDR BIT field */
+ if (op->addr.nbytes) {
+ writel(op->addr.val, priv->regbase + CQSPI_REG_CMDADDRESS);
+ /*
+ * address bytes are zero indexed
+ */
+ reg |= (((op->addr.nbytes - 1) &
+ CQSPI_REG_CMDCTRL_ADD_BYTES_MASK) <<
+ CQSPI_REG_CMDCTRL_ADD_BYTES_LSB);
+ reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB);
+ }
+
+ /* Set up dummy cycles. */
+ dummy_clk = cadence_qspi_calc_dummy(op, priv->dtr);
+ if (dummy_clk > CQSPI_DUMMY_CLKS_MAX)
+ return -EOPNOTSUPP;
+
+ if (dummy_clk)
+ reg |= (dummy_clk & CQSPI_REG_CMDCTRL_DUMMY_MASK)
+ << CQSPI_REG_CMDCTRL_DUMMY_LSB;
+
if (txlen) {
/* writing data = yes */
reg |= (0x1 << CQSPI_REG_CMDCTRL_WR_EN_LSB);
diff --git a/drivers/spi/npcm_fiu_spi.c b/drivers/spi/npcm_fiu_spi.c
index 7000fe5860d..73c506442ae 100644
--- a/drivers/spi/npcm_fiu_spi.c
+++ b/drivers/spi/npcm_fiu_spi.c
@@ -11,6 +11,7 @@
#include <linux/bitfield.h>
#include <linux/log2.h>
#include <linux/iopoll.h>
+#include <power/regulator.h>
#define DW_SIZE 4
#define CHUNK_SIZE 16
@@ -34,6 +35,34 @@
#define UMA_CTS_RDYST BIT(24)
#define UMA_CTS_DEV_NUM_MASK GENMASK(9, 8)
+/* Direct Write Configuration Register */
+#define DWR_CFG_WBURST_MASK GENMASK(25, 24)
+#define DWR_CFG_ADDSIZ_MASK GENMASK(17, 16)
+#define DWR_CFG_ABPCK_MASK GENMASK(11, 10)
+#define DRW_CFG_DBPCK_MASK GENMASK(9, 8)
+#define DRW_CFG_WRCMD 2
+enum {
+ DWR_WBURST_1_BYTE,
+ DWR_WBURST_16_BYTE = 3,
+};
+
+enum {
+ DWR_ADDSIZ_24_BIT,
+ DWR_ADDSIZ_32_BIT,
+};
+
+enum {
+ DWR_ABPCK_BIT_PER_CLK,
+ DWR_ABPCK_2_BIT_PER_CLK,
+ DWR_ABPCK_4_BIT_PER_CLK,
+};
+
+enum {
+ DWR_DBPCK_BIT_PER_CLK,
+ DWR_DBPCK_2_BIT_PER_CLK,
+ DWR_DBPCK_4_BIT_PER_CLK,
+};
+
struct npcm_fiu_regs {
unsigned int drd_cfg;
unsigned int dwr_cfg;
@@ -67,19 +96,10 @@ struct npcm_fiu_regs {
struct npcm_fiu_priv {
struct npcm_fiu_regs *regs;
- struct clk clk;
};
static int npcm_fiu_spi_set_speed(struct udevice *bus, uint speed)
{
- struct npcm_fiu_priv *priv = dev_get_priv(bus);
- int ret;
-
- debug("%s: set speed %u\n", bus->name, speed);
- ret = clk_set_rate(&priv->clk, speed);
- if (ret < 0)
- return ret;
-
return 0;
}
@@ -349,13 +369,38 @@ static int npcm_fiu_exec_op(struct spi_slave *slave,
static int npcm_fiu_spi_probe(struct udevice *bus)
{
struct npcm_fiu_priv *priv = dev_get_priv(bus);
- int ret;
+ struct udevice *vqspi_supply;
+ int vqspi_uv;
priv->regs = (struct npcm_fiu_regs *)dev_read_addr_ptr(bus);
- ret = clk_get_by_index(bus, 0, &priv->clk);
- if (ret < 0)
- return ret;
+ if (IS_ENABLED(CONFIG_DM_REGULATOR)) {
+ device_get_supply_regulator(bus, "vqspi-supply", &vqspi_supply);
+ vqspi_uv = dev_read_u32_default(bus, "vqspi-microvolt", 0);
+ /* Set IO voltage */
+ if (vqspi_supply && vqspi_uv)
+ regulator_set_value(vqspi_supply, vqspi_uv);
+ }
+
+ return 0;
+}
+
+static int npcm_fiu_spi_bind(struct udevice *bus)
+{
+ struct npcm_fiu_regs *regs;
+
+ if (dev_read_bool(bus, "nuvoton,spix-mode")) {
+ regs = dev_read_addr_ptr(bus);
+ if (!regs)
+ return -EINVAL;
+
+ /* Setup direct write cfg for SPIX */
+ writel(FIELD_PREP(DWR_CFG_WBURST_MASK, DWR_WBURST_16_BYTE) |
+ FIELD_PREP(DWR_CFG_ADDSIZ_MASK, DWR_ADDSIZ_24_BIT) |
+ FIELD_PREP(DWR_CFG_ABPCK_MASK, DWR_ABPCK_4_BIT_PER_CLK) |
+ FIELD_PREP(DRW_CFG_DBPCK_MASK, DWR_DBPCK_4_BIT_PER_CLK) |
+ DRW_CFG_WRCMD, &regs->dwr_cfg);
+ }
return 0;
}
@@ -384,4 +429,5 @@ U_BOOT_DRIVER(npcm_fiu_spi) = {
.ops = &npcm_fiu_spi_ops,
.priv_auto = sizeof(struct npcm_fiu_priv),
.probe = npcm_fiu_spi_probe,
+ .bind = npcm_fiu_spi_bind,
};
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index 8e8995fc537..b7eca583595 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -181,8 +181,12 @@ bool spi_mem_dtr_supports_op(struct spi_slave *slave,
if (op->dummy.nbytes && op->dummy.buswidth == 8 && op->dummy.nbytes % 2)
return false;
- if (op->data.dir != SPI_MEM_NO_DATA &&
- op->dummy.buswidth == 8 && op->data.nbytes % 2)
+ /*
+ * Transactions of odd length do not make sense for 8D-8D-8D mode
+ * because a byte is transferred in just half a cycle.
+ */
+ if (op->data.dir != SPI_MEM_NO_DATA && op->data.dir != SPI_MEM_DATA_IN &&
+ op->data.buswidth == 8 && op->data.nbytes % 2)
return false;
return spi_mem_check_buswidth(slave, op);
diff --git a/drivers/spi/spi-sn-f-ospi.c b/drivers/spi/spi-sn-f-ospi.c
index ebf2903d3ea..e3633a52608 100644
--- a/drivers/spi/spi-sn-f-ospi.c
+++ b/drivers/spi/spi-sn-f-ospi.c
@@ -556,7 +556,7 @@ static bool f_ospi_supports_op(struct spi_slave *slave,
if (!f_ospi_supports_op_width(op))
return false;
- return true;
+ return spi_mem_default_supports_op(slave, op);
}
static int f_ospi_adjust_op_size(struct spi_slave *slave, struct spi_mem_op *op)
diff --git a/drivers/spi/spi-synquacer.c b/drivers/spi/spi-synquacer.c
index 0cae3dfc778..0f5d0a30c39 100644
--- a/drivers/spi/spi-synquacer.c
+++ b/drivers/spi/spi-synquacer.c
@@ -186,7 +186,7 @@ static void synquacer_spi_config(struct udevice *dev, void *rx, const void *tx)
struct udevice *bus = dev->parent;
struct synquacer_spi_priv *priv = dev_get_priv(bus);
struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
- u32 val, div, bus_width;
+ u32 val, div, bus_width = 1;
int rwflag;
rwflag = (rx ? 1 : 0) | (tx ? 2 : 0);
@@ -211,6 +211,8 @@ static void synquacer_spi_config(struct udevice *dev, void *rx, const void *tx)
bus_width = 4;
else if (priv->mode & SPI_TX_OCTAL)
bus_width = 8;
+ else
+ log_warning("SPI mode not configured, setting to byte mode\n");
div = DIV_ROUND_UP(125000000, priv->speed);
diff --git a/drivers/usb/host/ehci-mx6.c b/drivers/usb/host/ehci-mx6.c
index 91633f013a5..fae20838c60 100644
--- a/drivers/usb/host/ehci-mx6.c
+++ b/drivers/usb/host/ehci-mx6.c
@@ -703,6 +703,10 @@ static int ehci_usb_probe(struct udevice *dev)
usb_internal_phy_clock_gate(priv->phy_addr, 1);
usb_phy_enable(ehci, priv->phy_addr);
#endif
+#else
+ ret = generic_setup_phy(dev, &priv->phy, 0);
+ if (ret)
+ goto err_regulator;
#endif
#if CONFIG_IS_ENABLED(DM_REGULATOR)
@@ -725,12 +729,6 @@ static int ehci_usb_probe(struct udevice *dev)
mdelay(10);
-#if defined(CONFIG_PHY)
- ret = generic_setup_phy(dev, &priv->phy, 0);
- if (ret)
- goto err_regulator;
-#endif
-
hccr = (struct ehci_hccr *)((uintptr_t)&ehci->caplength);
hcor = (struct ehci_hcor *)((uintptr_t)hccr +
HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 334d64c9485..fcc0e85d2e6 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -466,6 +466,17 @@ config VIDEO_BCM2835
that same resolution (or as near as possible) and 32bpp depth, so
that U-Boot can access it with full colour depth.
+config VIDEO_LCD_ENDEAVORU
+ tristate "Endeavoru 720x1280 DSI video mode panel"
+ depends on PANEL && BACKLIGHT
+ select VIDEO_MIPI_DSI
+ help
+ Say Y here if you want to enable support for the IPS-LCD panel
+ module for HTC One X. Driver supports a family of panels,
+ made at least by 3 vendors (Sharp, Sony and AUO), but set up
+ using the same DSI command sequence. The panel has a 720x1280
+ resolution and uses 24 bit RGB per pixel.
+
config VIDEO_LCD_ORISETECH_OTM8009A
bool "OTM8009A DSI LCD panel support"
select VIDEO_MIPI_DSI
@@ -480,6 +491,24 @@ config VIDEO_LCD_RAYDIUM_RM68200
Say Y here if you want to enable support for Raydium RM68200
720x1280 DSI video mode panel.
+config VIDEO_LCD_RENESAS_R61307
+ tristate "Renesas R61307 DSI video mode panel"
+ depends on PANEL && BACKLIGHT
+ select VIDEO_MIPI_DSI
+ help
+ Say Y here if you want to enable support for KOE tx13d100vm0eaa
+ IPS-LCD module with Renesas R69328 IC. The panel has a 1024x768
+ resolution and uses 24 bit RGB per pixel.
+
+config VIDEO_LCD_RENESAS_R69328
+ tristate "Renesas R69328 720x1280 DSI video mode panel"
+ depends on PANEL && BACKLIGHT
+ select VIDEO_MIPI_DSI
+ help
+ Say Y here if you want to enable support for JDI dx12d100vm0eaa
+ IPS-LCD module with Renesas R69328 IC. The panel has a 720x1280
+ resolution and uses 24 bit RGB per pixel.
+
config VIDEO_LCD_SSD2828
bool "SSD2828 bridge chip"
---help---
@@ -606,6 +635,15 @@ config ATMEL_HLCD
help
HLCDC supports video output to an attached LCD panel.
+config BACKLIGHT_LM3533
+ bool "Backlight Driver for LM3533"
+ depends on BACKLIGHT
+ select DM_I2C
+ help
+ Say Y to enable the backlight driver for National Semiconductor / TI
+ LM3533 Lighting Power chip. Only Bank A is supported as for now.
+ Supported backlight level range is from 2 to 255 with step of 1.
+
source "drivers/video/ti/Kconfig"
source "drivers/video/exynos/Kconfig"
@@ -886,7 +924,7 @@ endif # SPLASH_SCREEN
config VIDEO_BMP_GZIP
bool "Gzip compressed BMP image support"
- depends on CMD_BMP || SPLASH_SCREEN
+ depends on BMP || SPLASH_SCREEN
help
If this option is set, additionally to standard BMP
images, gzipped BMP images can be displayed via the
@@ -923,4 +961,225 @@ config BMP_32BPP
endif # VIDEO
+config SPL_VIDEO
+ bool "Enable driver model support for LCD/video"
+ depends on SPL_DM
+ help
+ The video subsystem adds a small amount of overhead to the image.
+ If this is acceptable and you have a need to use video drivers in
+ SPL, enable this option. It might provide a cleaner interface to
+ setting up video within SPL, and allows the same drivers to be
+ used as U-Boot proper.
+
+if SPL_VIDEO
+source "drivers/video/tidss/Kconfig"
+
+config SPL_VIDEO_LOGO
+ bool "Show the U-Boot logo on the display at SPL"
+ default y if !SPL_SPLASH_SCREEN
+ select SPL_VIDEO_BMP_RLE8
+ help
+ This enables showing the U-Boot logo on the display when a video
+ device is probed. It appears at the top right. The logo itself is at
+ tools/logos/u-boot_logo.bmp and looks best when the display has a
+ black background.
+
+config SPL_SPLASH_SCREEN
+ bool "Show a splash-screen image at SPL"
+ help
+ If this option is set, the environment is checked for a variable
+ "splashimage" at spl stage.
+
+config SPL_SYS_WHITE_ON_BLACK
+ bool "Display console as white on a black background at SPL"
+ help
+ Normally the display is black on a white background, Enable this
+ option to invert this, i.e. white on a black background at spl stage.
+ This can be better in low-light situations or to reduce eye strain in
+ some cases.
+
+config SPL_VIDEO_PCI_DEFAULT_FB_SIZE
+ hex "Default framebuffer size to use if no drivers request it at SPL"
+ default 0x1000000 if X86 && PCI
+ default 0 if !(X86 && PCI)
+ help
+ Generally, video drivers request the amount of memory they need for
+ the frame buffer when they are bound, by setting the size field in
+ struct video_uc_plat. That memory is then reserved for use after
+ relocation. But PCI drivers cannot be bound before relocation unless
+ they are mentioned in the devicetree.
+
+ With this value set appropriately, it is possible for PCI video
+ devices to have a framebuffer allocated by U-Boot.
+
+ Note: the framebuffer needs to be large enough to store all pixels at
+ maximum resolution. For example, at 1920 x 1200 with 32 bits per
+ pixel, 2560 * 1600 * 32 / 8 = 0xfa0000 bytes are needed.
+
+config SPL_CONSOLE_SCROLL_LINES
+ int "Number of lines to scroll the console by at SPL"
+ default 1
+ help
+ When the console need to be scrolled, this is the number of
+ lines to scroll by. It defaults to 1. Increasing this makes the
+ console jump but can help speed up operation when scrolling
+ is slow.
+
+config SPL_CONSOLE_NORMAL
+ bool "Support a simple text console at SPL"
+ default y
+ help
+ Support drawing text on the frame buffer console so that it can be
+ used as a console. Rotation is not supported by this driver (see
+ CONFIG_CONSOLE_ROTATION for that). A built-in 8x16 font is used
+ for the display.
+
+config SPL_BACKLIGHT
+ bool "Enable panel backlight uclass support at SPL"
+ default y
+ help
+ This provides backlight uclass driver that enables basic panel
+ backlight support.
+
+config SPL_PANEL
+ bool "Enable panel uclass support at SPL"
+ default y
+ help
+ This provides panel uclass driver that enables basic panel support.
+
+config SPL_SIMPLE_PANEL
+ bool "Enable simple panel support at SPL"
+ depends on SPL_PANEL && SPL_BACKLIGHT && SPL_DM_GPIO
+ default y
+ help
+ This turns on a simple panel driver that enables a compatible
+ video panel.
+
+config SPL_SYS_WHITE_ON_BLACK
+ bool "Display console as white on a black background at SPL"
+ help
+ Normally the display is black on a white background, Enable this
+ option to invert this, i.e. white on a black background at spl stage.
+ This can be better in low-light situations or to reduce eye strain in
+ some cases.
+
+if SPL_SPLASH_SCREEN
+
+config SPL_SPLASH_SCREEN_ALIGN
+ bool "Allow positioning the splash image anywhere on the display at SPL"
+ help
+ If this option is set the splash image can be freely positioned
+ on the screen only at SPL. Environment variable "splashpos" specifies
+ the position as "x,y". If a positive number is given it is used as
+ number of pixel from left/top. If a negative number is given it
+ is used as number of pixel from right/bottom.
+
+config SPL_SPLASH_SOURCE
+ bool "Control the source of the splash image at SPL"
+ help
+ Use the splash_source.c library. This library provides facilities to
+ declare board specific splash image locations, routines for loading
+ splash image from supported locations, and a way of controlling the
+ selected splash location using the "splashsource" environment
+ variable.
+
+ This CONFIG works as follows:
+
+ - If splashsource is set to a supported location name as defined by
+ board code, use that splash location.
+ - If splashsource is undefined, use the first splash location as
+ default.
+ - If splashsource is set to an unsupported value, do not load a splash
+ screen.
+
+ A splash source location can describe either storage with raw data, a
+ storage formatted with a file system or a FIT image. In case of a
+ filesystem, the splash screen data is loaded as a file. The name of
+ the splash screen file can be controlled with the environment variable
+ "splashfile".
+
+ To enable loading the splash image from a FIT image, CONFIG_FIT must
+ be enabled. The FIT image has to start at the 'offset' field address
+ in the selected splash location. The name of splash image within the
+ FIT shall be specified by the environment variable "splashfile".
+
+ In case the environment variable "splashfile" is not defined the
+ default name 'splash.bmp' will be used.
+
+endif # SPL_SPLASH_SCREEN
+
+config SPL_VIDEO_BMP_GZIP
+ bool "Gzip compressed BMP image support at SPL"
+ depends on SPL_SPLASH_SCREEN || SPL_BMP
+ help
+ If this option is set, additionally to standard BMP
+ images, gzipped BMP images can be displayed via the
+ splashscreen supportat SPL stage.
+
+config SPL_VIDEO_LOGO_MAX_SIZE
+ hex "Maximum size of the bitmap logo in bytes at SPL"
+ default 0x100000
+ help
+ Sets the maximum uncompressed size of the logo. This is needed when
+ decompressing a BMP file using the gzip algorithm, since it cannot
+ read the size from the bitmap header.
+
+config SPL_VIDEO_BMP_RLE8
+ bool "Run length encoded BMP image (RLE8) support at SPL"
+ help
+ If this option is set, the 8-bit RLE compressed BMP images
+ is supported.
+
+config SPL_BMP_16BPP
+ bool "16-bit-per-pixel BMP image support at SPL"
+ help
+ Support display of bitmaps file with 16-bit-per-pixel
+
+config SPL_BMP_24BPP
+ bool "24-bit-per-pixel BMP image support at SPL"
+ help
+ Support display of bitmaps file with 24-bit-per-pixel.
+
+config SPL_BMP_32BPP
+ bool "32-bit-per-pixel BMP image support at SPL"
+ help
+ Support display of bitmaps file with 32-bit-per-pixel.
+
+config SPL_VIDEO_BPP8
+ bool "Support 8-bit-per-pixel displays at SPL"
+ default y
+ help
+ Support drawing text and bitmaps onto a 8-bit-per-pixel display.
+ Enabling this will include code to support this display. Without
+ this option, such displays will not be supported and console output
+ will be empty.
+
+config SPL_VIDEO_BPP16
+ bool "Support 16-bit-per-pixel displays at SPL"
+ default y
+ help
+ Support drawing text and bitmaps onto a 16-bit-per-pixel display.
+ Enabling this will include code to support this display. Without
+ this option, such displays will not be supported and console output
+ will be empty.
+
+config SPL_VIDEO_BPP32
+ bool "Support 32-bit-per-pixel displays at SPL"
+ default y
+ help
+ Support drawing text and bitmaps onto a 32-bit-per-pixel display.
+ Enabling this will include code to support this display. Without
+ this option, such displays will not be supported and console output
+ will be empty.
+
+config SPL_HIDE_LOGO_VERSION
+ bool "Hide the version information on the splash screen at SPL"
+ help
+ Normally the U-Boot version string is shown on the display when the
+ splash screen is enabled. This information is not otherwise visible
+ since video starts up after U-Boot has displayed the initial banner.
+
+ Enable this option to hide this information.
+endif
+
endmenu
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 4d75771745d..9a53cd14187 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -4,12 +4,12 @@
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
ifdef CONFIG_DM
-obj-$(CONFIG_BACKLIGHT) += backlight-uclass.o
+obj-$(CONFIG_$(SPL_TPL_)BACKLIGHT) += backlight-uclass.o
obj-$(CONFIG_BACKLIGHT_GPIO) += backlight_gpio.o
obj-$(CONFIG_BACKLIGHT_PWM) += pwm_backlight.o
-obj-$(CONFIG_CONSOLE_NORMAL) += console_normal.o
+obj-$(CONFIG_$(SPL_TPL_)CONSOLE_NORMAL) += console_normal.o
obj-$(CONFIG_CONSOLE_ROTATION) += console_rotate.o
-ifdef CONFIG_CONSOLE_NORMAL
+ifdef CONFIG_$(SPL_TPL_)CONSOLE_NORMAL
obj-y += console_core.o
else ifdef CONFIG_CONSOLE_ROTATION
obj-y += console_core.o
@@ -18,21 +18,22 @@ obj-$(CONFIG_CONSOLE_ROTATION) += console_core.o
obj-$(CONFIG_CONSOLE_TRUETYPE) += console_truetype.o fonts/
obj-$(CONFIG_DISPLAY) += display-uclass.o
obj-$(CONFIG_VIDEO_MIPI_DSI) += dsi-host-uclass.o
-obj-$(CONFIG_VIDEO) += video-uclass.o vidconsole-uclass.o
-obj-$(CONFIG_VIDEO) += video_bmp.o
-obj-$(CONFIG_PANEL) += panel-uclass.o
+obj-$(CONFIG_$(SPL_TPL_)VIDEO) += video-uclass.o vidconsole-uclass.o
+obj-$(CONFIG_$(SPL_TPL_)VIDEO) += video_bmp.o
+obj-$(CONFIG_$(SPL_TPL_)PANEL) += panel-uclass.o
obj-$(CONFIG_PANEL_HX8238D) += hx8238d.o
-obj-$(CONFIG_SIMPLE_PANEL) += simple_panel.o
+obj-$(CONFIG_$(SPL_TPL_)SIMPLE_PANEL) += simple_panel.o
obj-$(CONFIG_VIDEO_LOGO) += u_boot_logo.o
endif
+obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_backlight.o
obj-${CONFIG_EXYNOS_FB} += exynos/
obj-${CONFIG_VIDEO_ROCKCHIP} += rockchip/
obj-${CONFIG_VIDEO_STM32} += stm32/
obj-${CONFIG_VIDEO_TEGRA124} += tegra124/
-obj-${CONFIG_VIDEO_TIDSS} += tidss/
+obj-${CONFIG_$(SPL_)VIDEO_TIDSS} += tidss/
obj-y += ti/
obj-$(CONFIG_ATMEL_HLCD) += atmel_hlcdfb.o
@@ -52,9 +53,12 @@ obj-$(CONFIG_VIDEO_EFI) += efi.o
obj-$(CONFIG_VIDEO_IPUV3) += 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_HITACHI_TX18D42VM) += hitachi_tx18d42vm_lcd.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
+obj-$(CONFIG_VIDEO_LCD_RENESAS_R69328) += renesas-r69328.o
obj-$(CONFIG_VIDEO_LCD_SSD2828) += ssd2828.o
obj-$(CONFIG_VIDEO_LCD_TDO_TL070WSH30) += tdo-tl070wsh30.o
obj-$(CONFIG_VIDEO_MCDE_SIMPLE) += mcde_simple.o
diff --git a/drivers/video/bridge/Kconfig b/drivers/video/bridge/Kconfig
index 765f7380b89..2311ca2d1a5 100644
--- a/drivers/video/bridge/Kconfig
+++ b/drivers/video/bridge/Kconfig
@@ -33,3 +33,10 @@ config VIDEO_BRIDGE_ANALOGIX_ANX6345
help
The Analogix ANX6345 is RGB-to-DP converter. It enables an eDP LCD
panel to be connected to an parallel LCD interface.
+
+config VIDEO_BRIDGE_SOLOMON_SSD2825
+ bool "Solomon SSD2825 bridge driver"
+ depends on PANEL && DM_GPIO
+ select VIDEO_MIPI_DSI
+ help
+ Solomon SSD2824 SPI RGB-DSI bridge driver wrapped into panel uClass.
diff --git a/drivers/video/bridge/Makefile b/drivers/video/bridge/Makefile
index 45e54ac1768..22625c8bc67 100644
--- a/drivers/video/bridge/Makefile
+++ b/drivers/video/bridge/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_VIDEO_BRIDGE) += video-bridge-uclass.o
obj-$(CONFIG_VIDEO_BRIDGE_PARADE_PS862X) += ps862x.o
obj-$(CONFIG_VIDEO_BRIDGE_NXP_PTN3460) += ptn3460.o
obj-$(CONFIG_VIDEO_BRIDGE_ANALOGIX_ANX6345) += anx6345.o
+obj-$(CONFIG_VIDEO_BRIDGE_SOLOMON_SSD2825) += ssd2825.o
diff --git a/drivers/video/bridge/ssd2825.c b/drivers/video/bridge/ssd2825.c
new file mode 100644
index 00000000000..cea20dcffa5
--- /dev/null
+++ b/drivers/video/bridge/ssd2825.c
@@ -0,0 +1,520 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <log.h>
+#include <misc.h>
+#include <mipi_display.h>
+#include <mipi_dsi.h>
+#include <backlight.h>
+#include <panel.h>
+#include <spi.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <asm/gpio.h>
+
+#define SSD2825_DEVICE_ID_REG 0xB0
+#define SSD2825_RGB_INTERFACE_CTRL_REG_1 0xB1
+#define SSD2825_RGB_INTERFACE_CTRL_REG_2 0xB2
+#define SSD2825_RGB_INTERFACE_CTRL_REG_3 0xB3
+#define SSD2825_RGB_INTERFACE_CTRL_REG_4 0xB4
+#define SSD2825_RGB_INTERFACE_CTRL_REG_5 0xB5
+#define SSD2825_RGB_INTERFACE_CTRL_REG_6 0xB6
+#define SSD2825_NON_BURST BIT(2)
+#define SSD2825_BURST BIT(3)
+#define SSD2825_PCKL_HIGH BIT(13)
+#define SSD2825_HSYNC_HIGH BIT(14)
+#define SSD2825_VSYNC_HIGH BIT(15)
+#define SSD2825_CONFIGURATION_REG 0xB7
+#define SSD2825_CONF_REG_HS BIT(0)
+#define SSD2825_CONF_REG_CKE BIT(1)
+#define SSD2825_CONF_REG_SLP BIT(2)
+#define SSD2825_CONF_REG_VEN BIT(3)
+#define SSD2825_CONF_REG_HCLK BIT(4)
+#define SSD2825_CONF_REG_CSS BIT(5)
+#define SSD2825_CONF_REG_DCS BIT(6)
+#define SSD2825_CONF_REG_REN BIT(7)
+#define SSD2825_CONF_REG_ECD BIT(8)
+#define SSD2825_CONF_REG_EOT BIT(9)
+#define SSD2825_CONF_REG_LPE BIT(10)
+#define SSD2825_VC_CTRL_REG 0xB8
+#define SSD2825_PLL_CTRL_REG 0xB9
+#define SSD2825_PLL_CONFIGURATION_REG 0xBA
+#define SSD2825_CLOCK_CTRL_REG 0xBB
+#define SSD2825_PACKET_SIZE_CTRL_REG_1 0xBC
+#define SSD2825_PACKET_SIZE_CTRL_REG_2 0xBD
+#define SSD2825_PACKET_SIZE_CTRL_REG_3 0xBE
+#define SSD2825_PACKET_DROP_REG 0xBF
+#define SSD2825_OPERATION_CTRL_REG 0xC0
+#define SSD2825_MAX_RETURN_SIZE_REG 0xC1
+#define SSD2825_RETURN_DATA_COUNT_REG 0xC2
+#define SSD2825_ACK_RESPONSE_REG 0xC3
+#define SSD2825_LINE_CTRL_REG 0xC4
+#define SSD2825_INTERRUPT_CTRL_REG 0xC5
+#define SSD2825_INTERRUPT_STATUS_REG 0xC6
+#define SSD2825_ERROR_STATUS_REG 0xC7
+#define SSD2825_DATA_FORMAT_REG 0xC8
+#define SSD2825_DELAY_ADJ_REG_1 0xC9
+#define SSD2825_DELAY_ADJ_REG_2 0xCA
+#define SSD2825_DELAY_ADJ_REG_3 0xCB
+#define SSD2825_DELAY_ADJ_REG_4 0xCC
+#define SSD2825_DELAY_ADJ_REG_5 0xCD
+#define SSD2825_DELAY_ADJ_REG_6 0xCE
+#define SSD2825_HS_TX_TIMER_REG_1 0xCF
+#define SSD2825_HS_TX_TIMER_REG_2 0xD0
+#define SSD2825_LP_RX_TIMER_REG_1 0xD1
+#define SSD2825_LP_RX_TIMER_REG_2 0xD2
+#define SSD2825_TE_STATUS_REG 0xD3
+#define SSD2825_SPI_READ_REG 0xD4
+#define SSD2825_PLL_LOCK_REG 0xD5
+#define SSD2825_TEST_REG 0xD6
+#define SSD2825_TE_COUNT_REG 0xD7
+#define SSD2825_ANALOG_CTRL_REG_1 0xD8
+#define SSD2825_ANALOG_CTRL_REG_2 0xD9
+#define SSD2825_ANALOG_CTRL_REG_3 0xDA
+#define SSD2825_ANALOG_CTRL_REG_4 0xDB
+#define SSD2825_INTERRUPT_OUT_CTRL_REG 0xDC
+#define SSD2825_RGB_INTERFACE_CTRL_REG_7 0xDD
+#define SSD2825_LANE_CONFIGURATION_REG 0xDE
+#define SSD2825_DELAY_ADJ_REG_7 0xDF
+#define SSD2825_INPUT_PIN_CTRL_REG_1 0xE0
+#define SSD2825_INPUT_PIN_CTRL_REG_2 0xE1
+#define SSD2825_BIDIR_PIN_CTRL_REG_1 0xE2
+#define SSD2825_BIDIR_PIN_CTRL_REG_2 0xE3
+#define SSD2825_BIDIR_PIN_CTRL_REG_3 0xE4
+#define SSD2825_BIDIR_PIN_CTRL_REG_4 0xE5
+#define SSD2825_BIDIR_PIN_CTRL_REG_5 0xE6
+#define SSD2825_BIDIR_PIN_CTRL_REG_6 0xE7
+#define SSD2825_BIDIR_PIN_CTRL_REG_7 0xE8
+#define SSD2825_CABC_BRIGHTNESS_CTRL_REG_1 0xE9
+#define SSD2825_CABC_BRIGHTNESS_CTRL_REG_2 0xEA
+#define SSD2825_CABC_BRIGHTNESS_STATUS_REG 0xEB
+#define SSD2825_READ_REG 0xFF
+#define SSD2825_SPI_READ_REG_RESET 0xFA
+
+#define SSD2825_CMD_MASK 0x00
+#define SSD2825_DAT_MASK 0x01
+
+#define SSD2825_CMD_SEND BIT(0)
+#define SSD2825_DAT_SEND BIT(1)
+#define SSD2825_DSI_SEND BIT(2)
+
+#define SSD2828_LP_CLOCK_DIVIDER(n) (((n) - 1) & 0x3F)
+#define SSD2825_LP_MIN_CLK 5000 /* KHz */
+#define SSD2825_REF_MIN_CLK 2000 /* KHz */
+
+struct ssd2825_bridge_priv {
+ struct mipi_dsi_host host;
+ struct mipi_dsi_device device;
+
+ struct udevice *panel;
+ struct display_timing timing;
+
+ struct gpio_desc power_gpio;
+ struct gpio_desc reset_gpio;
+
+ struct clk *tx_clk;
+
+ u32 pll_freq_kbps; /* PLL in kbps */
+};
+
+static int ssd2825_spi_write(struct udevice *dev, int reg,
+ const void *buf, int flags)
+{
+ u8 command[2];
+
+ if (flags & SSD2825_CMD_SEND) {
+ command[0] = SSD2825_CMD_MASK;
+ command[1] = reg;
+ dm_spi_xfer(dev, 9, &command,
+ NULL, SPI_XFER_ONCE);
+ }
+
+ if (flags & SSD2825_DAT_SEND) {
+ u16 data = *(u16 *)buf;
+ u8 cmd1, cmd2;
+
+ /* send low byte first and then high byte */
+ cmd1 = (data & 0x00FF);
+ cmd2 = (data & 0xFF00) >> 8;
+
+ command[0] = SSD2825_DAT_MASK;
+ command[1] = cmd1;
+ dm_spi_xfer(dev, 9, &command,
+ NULL, SPI_XFER_ONCE);
+
+ command[0] = SSD2825_DAT_MASK;
+ command[1] = cmd2;
+ dm_spi_xfer(dev, 9, &command,
+ NULL, SPI_XFER_ONCE);
+ }
+
+ if (flags & SSD2825_DSI_SEND) {
+ u16 data = *(u16 *)buf;
+ data &= 0x00FF;
+
+ debug("%s: dsi command (0x%x)\n",
+ __func__, data);
+
+ command[0] = SSD2825_DAT_MASK;
+ command[1] = data;
+ dm_spi_xfer(dev, 9, &command,
+ NULL, SPI_XFER_ONCE);
+ }
+
+ return 0;
+}
+
+static int ssd2825_spi_read(struct udevice *dev, int reg,
+ void *data, int flags)
+{
+ u8 command[2];
+
+ command[0] = SSD2825_CMD_MASK;
+ command[1] = SSD2825_SPI_READ_REG;
+ dm_spi_xfer(dev, 9, &command,
+ NULL, SPI_XFER_ONCE);
+
+ command[0] = SSD2825_DAT_MASK;
+ command[1] = SSD2825_SPI_READ_REG_RESET;
+ dm_spi_xfer(dev, 9, &command,
+ NULL, SPI_XFER_ONCE);
+
+ command[0] = SSD2825_DAT_MASK;
+ command[1] = 0;
+ dm_spi_xfer(dev, 9, &command,
+ NULL, SPI_XFER_ONCE);
+
+ command[0] = SSD2825_CMD_MASK;
+ command[1] = reg;
+ dm_spi_xfer(dev, 9, &command,
+ NULL, SPI_XFER_ONCE);
+
+ command[0] = SSD2825_CMD_MASK;
+ command[1] = SSD2825_SPI_READ_REG_RESET;
+ dm_spi_xfer(dev, 9, &command,
+ NULL, SPI_XFER_ONCE);
+
+ dm_spi_xfer(dev, 16, NULL,
+ (u8 *)data, SPI_XFER_ONCE);
+
+ return 0;
+}
+
+static void ssd2825_write_register(struct udevice *dev, u8 reg,
+ u16 command)
+{
+ ssd2825_spi_write(dev, reg, &command,
+ SSD2825_CMD_SEND |
+ SSD2825_DAT_SEND);
+}
+
+static void ssd2825_write_dsi(struct udevice *dev, const u8 *command,
+ int len)
+{
+ int i;
+
+ ssd2825_spi_write(dev, SSD2825_PACKET_SIZE_CTRL_REG_1, &len,
+ SSD2825_CMD_SEND | SSD2825_DAT_SEND);
+
+ ssd2825_spi_write(dev, SSD2825_PACKET_DROP_REG, NULL,
+ SSD2825_CMD_SEND);
+
+ for (i = 0; i < len; i++)
+ ssd2825_spi_write(dev, 0, &command[i], SSD2825_DSI_SEND);
+}
+
+static ssize_t ssd2825_bridge_transfer(struct mipi_dsi_host *host,
+ const struct mipi_dsi_msg *msg)
+{
+ struct udevice *dev = (struct udevice *)host->dev;
+ u8 buf = *(u8 *)msg->tx_buf;
+ u16 config;
+ int ret;
+
+ ret = ssd2825_spi_read(dev, SSD2825_CONFIGURATION_REG,
+ &config, 0);
+ if (ret)
+ return ret;
+
+ switch (msg->type) {
+ case MIPI_DSI_DCS_SHORT_WRITE:
+ case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
+ case MIPI_DSI_DCS_LONG_WRITE:
+ config |= SSD2825_CONF_REG_DCS;
+ break;
+ case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
+ case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
+ case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
+ case MIPI_DSI_GENERIC_LONG_WRITE:
+ config &= ~SSD2825_CONF_REG_DCS;
+ break;
+ default:
+ return 0;
+ }
+
+ ssd2825_write_register(dev, SSD2825_CONFIGURATION_REG, config);
+ ssd2825_write_register(dev, SSD2825_VC_CTRL_REG, 0x0000);
+ ssd2825_write_dsi(dev, msg->tx_buf, msg->tx_len);
+
+ if (buf == MIPI_DCS_SET_DISPLAY_ON) {
+ ssd2825_write_register(dev, SSD2825_CONFIGURATION_REG,
+ SSD2825_CONF_REG_HS | SSD2825_CONF_REG_VEN |
+ SSD2825_CONF_REG_DCS | SSD2825_CONF_REG_ECD |
+ SSD2825_CONF_REG_EOT);
+ ssd2825_write_register(dev, SSD2825_PLL_CTRL_REG, 0x0001);
+ ssd2825_write_register(dev, SSD2825_VC_CTRL_REG, 0x0000);
+ }
+
+ return 0;
+}
+
+static const struct mipi_dsi_host_ops ssd2825_bridge_host_ops = {
+ .transfer = ssd2825_bridge_transfer,
+};
+
+/*
+ * PLL configuration register settings.
+ *
+ * See the "PLL Configuration Register Description" in the SSD2825 datasheet.
+ */
+static u16 construct_pll_config(struct ssd2825_bridge_priv *priv,
+ u32 desired_pll_freq_kbps, u32 reference_freq_khz)
+{
+ u32 div_factor = 1, mul_factor, fr = 0;
+
+ while (reference_freq_khz / (div_factor + 1) >= SSD2825_REF_MIN_CLK)
+ div_factor++;
+ if (div_factor > 31)
+ div_factor = 31;
+
+ mul_factor = DIV_ROUND_UP(desired_pll_freq_kbps * div_factor,
+ reference_freq_khz);
+
+ priv->pll_freq_kbps = reference_freq_khz * mul_factor / div_factor;
+
+ if (priv->pll_freq_kbps >= 501000)
+ fr = 3;
+ else if (priv->pll_freq_kbps >= 251000)
+ fr = 2;
+ else if (priv->pll_freq_kbps >= 126000)
+ fr = 1;
+
+ return (fr << 14) | (div_factor << 8) | mul_factor;
+}
+
+static void ssd2825_setup_pll(struct udevice *dev)
+{
+ struct ssd2825_bridge_priv *priv = dev_get_priv(dev);
+ struct mipi_dsi_device *device = &priv->device;
+ struct display_timing *dt = &priv->timing;
+ u16 pll_config, lp_div;
+ u32 pclk_mult, tx_freq_khz, pd_lines;
+
+ tx_freq_khz = clk_get_rate(priv->tx_clk) / 1000;
+ pd_lines = mipi_dsi_pixel_format_to_bpp(device->format);
+ pclk_mult = pd_lines / device->lanes + 1;
+
+ pll_config = construct_pll_config(priv, pclk_mult *
+ dt->pixelclock.typ / 1000,
+ tx_freq_khz);
+
+ lp_div = priv->pll_freq_kbps / (SSD2825_LP_MIN_CLK * 8);
+
+ /* Disable PLL */
+ ssd2825_write_register(dev, SSD2825_PLL_CTRL_REG, 0x0000);
+ ssd2825_write_register(dev, SSD2825_LINE_CTRL_REG, 0x0001);
+
+ /* Set delays */
+ ssd2825_write_register(dev, SSD2825_DELAY_ADJ_REG_1, 0x2103);
+
+ /* Set PLL coeficients */
+ ssd2825_write_register(dev, SSD2825_PLL_CONFIGURATION_REG, pll_config);
+
+ /* Clock Control Register */
+ ssd2825_write_register(dev, SSD2825_CLOCK_CTRL_REG,
+ SSD2828_LP_CLOCK_DIVIDER(lp_div));
+
+ /* Enable PLL */
+ ssd2825_write_register(dev, SSD2825_PLL_CTRL_REG, 0x0001);
+ ssd2825_write_register(dev, SSD2825_VC_CTRL_REG, 0x0000);
+}
+
+static int ssd2825_bridge_enable_panel(struct udevice *dev)
+{
+ struct ssd2825_bridge_priv *priv = dev_get_priv(dev);
+ struct mipi_dsi_device *device = &priv->device;
+ struct display_timing *dt = &priv->timing;
+ int ret;
+
+ ret = clk_prepare_enable(priv->tx_clk);
+ if (ret) {
+ log_err("error enabling tx_clk (%d)\n", ret);
+ return ret;
+ }
+
+ ret = dm_gpio_set_value(&priv->power_gpio, 1);
+ if (ret) {
+ log_err("error changing power-gpios (%d)\n", ret);
+ return ret;
+ }
+ mdelay(10);
+
+ ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+ if (ret) {
+ log_err("error changing reset-gpios (%d)\n", ret);
+ return ret;
+ }
+ mdelay(10);
+
+ ret = dm_gpio_set_value(&priv->reset_gpio, 1);
+ if (ret) {
+ log_err("error changing reset-gpios (%d)\n", ret);
+ return ret;
+ }
+ mdelay(10);
+
+ /* Perform panel HW setup */
+ ret = panel_enable_backlight(priv->panel);
+ if (ret)
+ return ret;
+
+ /* Perform SW reset */
+ ssd2825_write_register(dev, SSD2825_OPERATION_CTRL_REG, 0x0100);
+
+ /* Set panel timings */
+ ssd2825_write_register(dev, SSD2825_RGB_INTERFACE_CTRL_REG_1,
+ dt->vsync_len.typ << 8 | dt->hsync_len.typ);
+ ssd2825_write_register(dev, SSD2825_RGB_INTERFACE_CTRL_REG_2,
+ (dt->vsync_len.typ + dt->vback_porch.typ) << 8 |
+ (dt->hsync_len.typ + dt->hback_porch.typ));
+ ssd2825_write_register(dev, SSD2825_RGB_INTERFACE_CTRL_REG_3,
+ dt->vfront_porch.typ << 8 | dt->hfront_porch.typ);
+ ssd2825_write_register(dev, SSD2825_RGB_INTERFACE_CTRL_REG_4,
+ dt->hactive.typ);
+ ssd2825_write_register(dev, SSD2825_RGB_INTERFACE_CTRL_REG_5,
+ dt->vactive.typ);
+ ssd2825_write_register(dev, SSD2825_RGB_INTERFACE_CTRL_REG_6,
+ SSD2825_HSYNC_HIGH | SSD2825_VSYNC_HIGH |
+ SSD2825_PCKL_HIGH | SSD2825_NON_BURST |
+ (3 - device->format));
+ ssd2825_write_register(dev, SSD2825_LANE_CONFIGURATION_REG,
+ device->lanes - 1);
+ ssd2825_write_register(dev, SSD2825_TEST_REG, 0x0004);
+
+ /* Call PLL configuration */
+ ssd2825_setup_pll(dev);
+
+ mdelay(10);
+
+ /* Initial DSI configuration register set */
+ ssd2825_write_register(dev, SSD2825_CONFIGURATION_REG,
+ SSD2825_CONF_REG_CKE | SSD2825_CONF_REG_DCS |
+ SSD2825_CONF_REG_ECD | SSD2825_CONF_REG_EOT);
+ ssd2825_write_register(dev, SSD2825_VC_CTRL_REG, 0x0000);
+
+ /* Set up SW panel configuration */
+ ret = panel_set_backlight(priv->panel, BACKLIGHT_DEFAULT);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int ssd2825_bridge_set_panel(struct udevice *dev, int percent)
+{
+ return 0;
+}
+
+static int ssd2825_bridge_panel_timings(struct udevice *dev,
+ struct display_timing *timing)
+{
+ struct ssd2825_bridge_priv *priv = dev_get_priv(dev);
+
+ memcpy(timing, &priv->timing, sizeof(*timing));
+
+ return 0;
+}
+
+static int ssd2825_bridge_probe(struct udevice *dev)
+{
+ struct ssd2825_bridge_priv *priv = dev_get_priv(dev);
+ struct spi_slave *slave = dev_get_parent_priv(dev);
+ struct mipi_dsi_device *device = &priv->device;
+ struct mipi_dsi_panel_plat *mipi_plat;
+ int ret;
+
+ ret = spi_claim_bus(slave);
+ if (ret) {
+ log_err("SPI bus allocation failed (%d)\n", ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev,
+ "panel", &priv->panel);
+ if (ret) {
+ log_err("cannot get panel: ret=%d\n", ret);
+ return ret;
+ }
+
+ panel_get_display_timing(priv->panel, &priv->timing);
+
+ mipi_plat = dev_get_plat(priv->panel);
+ mipi_plat->device = device;
+
+ priv->host.dev = (struct device *)dev;
+ priv->host.ops = &ssd2825_bridge_host_ops;
+
+ device->host = &priv->host;
+ device->lanes = mipi_plat->lanes;
+ device->format = mipi_plat->format;
+ device->mode_flags = mipi_plat->mode_flags;
+
+ /* get panel gpios */
+ ret = gpio_request_by_name(dev, "power-gpios", 0,
+ &priv->power_gpio, GPIOD_IS_OUT);
+ if (ret) {
+ log_err("could not decode power-gpios (%d)\n", ret);
+ return ret;
+ }
+
+ ret = gpio_request_by_name(dev, "reset-gpios", 0,
+ &priv->reset_gpio, GPIOD_IS_OUT);
+ if (ret) {
+ log_err("could not decode reset-gpios (%d)\n", ret);
+ return ret;
+ }
+
+ /* get clk */
+ priv->tx_clk = devm_clk_get(dev, "tx_clk");
+ if (IS_ERR(priv->tx_clk)) {
+ log_err("cannot get tx_clk: %ld\n", PTR_ERR(priv->tx_clk));
+ return PTR_ERR(priv->tx_clk);
+ }
+
+ return 0;
+}
+
+static const struct panel_ops ssd2825_bridge_ops = {
+ .enable_backlight = ssd2825_bridge_enable_panel,
+ .set_backlight = ssd2825_bridge_set_panel,
+ .get_display_timing = ssd2825_bridge_panel_timings,
+};
+
+static const struct udevice_id ssd2825_bridge_ids[] = {
+ { .compatible = "solomon,ssd2825" },
+ { }
+};
+
+U_BOOT_DRIVER(ssd2825) = {
+ .name = "ssd2825",
+ .id = UCLASS_PANEL,
+ .of_match = ssd2825_bridge_ids,
+ .ops = &ssd2825_bridge_ops,
+ .probe = ssd2825_bridge_probe,
+ .priv_auto = sizeof(struct ssd2825_bridge_priv),
+};
diff --git a/drivers/video/console_core.c b/drivers/video/console_core.c
index d4f79c656a9..1f93b1b85fa 100644
--- a/drivers/video/console_core.c
+++ b/drivers/video/console_core.c
@@ -46,11 +46,11 @@ static int console_set_font(struct udevice *dev, struct video_fontdata *fontdata
int check_bpix_support(int bpix)
{
- if (bpix == VIDEO_BPP8 && IS_ENABLED(CONFIG_VIDEO_BPP8))
+ if (bpix == VIDEO_BPP8 && CONFIG_IS_ENABLED(VIDEO_BPP8))
return 0;
- else if (bpix == VIDEO_BPP16 && IS_ENABLED(CONFIG_VIDEO_BPP16))
+ else if (bpix == VIDEO_BPP16 && CONFIG_IS_ENABLED(VIDEO_BPP16))
return 0;
- else if (bpix == VIDEO_BPP32 && IS_ENABLED(CONFIG_VIDEO_BPP32))
+ else if (bpix == VIDEO_BPP32 && CONFIG_IS_ENABLED(VIDEO_BPP32))
return 0;
else
return -ENOSYS;
diff --git a/drivers/video/endeavoru-panel.c b/drivers/video/endeavoru-panel.c
new file mode 100644
index 00000000000..79a272128b8
--- /dev/null
+++ b/drivers/video/endeavoru-panel.c
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <common.h>
+#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 endeavoru_panel_priv {
+ struct udevice *vdd;
+ struct udevice *vddio;
+
+ struct udevice *backlight;
+
+ struct gpio_desc reset_gpio;
+};
+
+static struct display_timing default_timing = {
+ .pixelclock.typ = 63200000,
+ .hactive.typ = 720,
+ .hfront_porch.typ = 55,
+ .hback_porch.typ = 29,
+ .hsync_len.typ = 16,
+ .vactive.typ = 1280,
+ .vfront_porch.typ = 2,
+ .vback_porch.typ = 1,
+ .vsync_len.typ = 1,
+};
+
+static void dcs_write_one(struct mipi_dsi_device *dsi, u8 cmd, u8 data)
+{
+ mipi_dsi_dcs_write(dsi, cmd, &data, 1);
+}
+
+/*
+ * This panel is not able to auto-increment all cmd addresses so for some of
+ * them, we need to send them one by one...
+ */
+#define dcs_write_seq(dsi, cmd, seq...) \
+({ \
+ static const u8 d[] = { seq }; \
+ unsigned int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(d) ; i++) \
+ dcs_write_one(dsi, cmd + i, d[i]); \
+})
+
+static int endeavoru_panel_enable_backlight(struct udevice *dev)
+{
+ struct endeavoru_panel_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = dm_gpio_set_value(&priv->reset_gpio, 1);
+ if (ret) {
+ log_err("error changing reset-gpios (%d)\n", ret);
+ return ret;
+ }
+ mdelay(5);
+
+ ret = regulator_set_enable_if_allowed(priv->vddio, 1);
+ if (ret) {
+ log_err("error enabling iovcc-supply (%d)\n", ret);
+ return ret;
+ }
+ mdelay(1);
+
+ ret = regulator_set_enable_if_allowed(priv->vdd, 1);
+ if (ret) {
+ log_err("error enabling vcc-supply (%d)\n", ret);
+ return ret;
+ }
+ mdelay(20);
+
+ ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+ if (ret) {
+ log_err("error changing reset-gpios (%d)\n", ret);
+ return ret;
+ }
+ mdelay(2);
+
+ /* Reset panel */
+ ret = dm_gpio_set_value(&priv->reset_gpio, 1);
+ if (ret) {
+ log_err("error changing reset-gpios (%d)\n", ret);
+ return ret;
+ }
+ mdelay(1);
+
+ ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+ if (ret) {
+ log_err("error changing reset-gpios (%d)\n", ret);
+ return ret;
+ }
+ mdelay(25);
+
+ return 0;
+}
+
+static int endeavoru_panel_set_backlight(struct udevice *dev, int percent)
+{
+ struct endeavoru_panel_priv *priv = dev_get_priv(dev);
+ struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
+ struct mipi_dsi_device *dsi = plat->device;
+ int ret;
+
+ dcs_write_one(dsi, 0xc2, 0x08);
+
+ /* color enhancement 2.2 */
+ dcs_write_one(dsi, 0xff, 0x03);
+ dcs_write_one(dsi, 0xfe, 0x08);
+ dcs_write_one(dsi, 0x18, 0x00);
+ dcs_write_one(dsi, 0x19, 0x00);
+ dcs_write_one(dsi, 0x1a, 0x00);
+ dcs_write_one(dsi, 0x25, 0x26);
+
+ dcs_write_seq(dsi, 0x00, 0x00, 0x05, 0x10, 0x17,
+ 0x22, 0x26, 0x29, 0x29, 0x26, 0x23,
+ 0x17, 0x12, 0x06, 0x02, 0x01, 0x00);
+
+ dcs_write_one(dsi, 0xfb, 0x01);
+ dcs_write_one(dsi, 0xff, 0x00);
+ dcs_write_one(dsi, 0xfe, 0x01);
+
+ mipi_dsi_dcs_exit_sleep_mode(dsi);
+
+ mdelay(105);
+
+ dcs_write_one(dsi, 0x35, 0x00);
+
+ /* PWM frequency adjust */
+ dcs_write_one(dsi, 0xff, 0x04);
+ dcs_write_one(dsi, 0x0a, 0x07);
+ dcs_write_one(dsi, 0x09, 0x20);
+ dcs_write_one(dsi, 0xff, 0x00);
+
+ dcs_write_one(dsi, 0xff, 0xee);
+ dcs_write_one(dsi, 0x12, 0x50);
+ dcs_write_one(dsi, 0x13, 0x02);
+ dcs_write_one(dsi, 0x6a, 0x60);
+ dcs_write_one(dsi, 0xfb, 0x01);
+ dcs_write_one(dsi, 0xff, 0x00);
+
+ mipi_dsi_dcs_set_display_on(dsi);
+
+ mdelay(42);
+
+ dcs_write_one(dsi, 0xba, 0x01);
+
+ dcs_write_one(dsi, 0x53, 0x24);
+ dcs_write_one(dsi, 0x55, 0x80);
+ dcs_write_one(dsi, 0x5e, 0x06);
+
+ ret = backlight_enable(priv->backlight);
+ if (ret)
+ return ret;
+
+ /* Set backlight */
+ dcs_write_one(dsi, 0x51, 0x96);
+
+ ret = backlight_set_brightness(priv->backlight, percent);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int endeavoru_panel_timings(struct udevice *dev,
+ struct display_timing *timing)
+{
+ memcpy(timing, &default_timing, sizeof(*timing));
+ return 0;
+}
+
+static int endeavoru_panel_of_to_plat(struct udevice *dev)
+{
+ struct endeavoru_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_err("cannot get backlight: ret = %d\n", ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
+ "vdd-supply", &priv->vdd);
+ if (ret) {
+ log_err("cannot get vdd-supply: ret = %d\n", ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
+ "vddio-supply", &priv->vddio);
+ if (ret) {
+ log_err("cannot get vddio-supply: ret = %d\n", ret);
+ return ret;
+ }
+
+ ret = gpio_request_by_name(dev, "reset-gpios", 0,
+ &priv->reset_gpio, GPIOD_IS_OUT);
+ if (ret) {
+ log_err("could not decode reser-gpios (%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int endeavoru_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_VIDEO;
+
+ return 0;
+}
+
+static const struct panel_ops endeavoru_panel_ops = {
+ .enable_backlight = endeavoru_panel_enable_backlight,
+ .set_backlight = endeavoru_panel_set_backlight,
+ .get_display_timing = endeavoru_panel_timings,
+};
+
+static const struct udevice_id endeavoru_panel_ids[] = {
+ { .compatible = "htc,edge-panel" },
+ { }
+};
+
+U_BOOT_DRIVER(endeavoru_panel) = {
+ .name = "endeavoru_panel",
+ .id = UCLASS_PANEL,
+ .of_match = endeavoru_panel_ids,
+ .ops = &endeavoru_panel_ops,
+ .of_to_plat = endeavoru_panel_of_to_plat,
+ .probe = endeavoru_panel_probe,
+ .plat_auto = sizeof(struct mipi_dsi_panel_plat),
+ .priv_auto = sizeof(struct endeavoru_panel_priv),
+};
diff --git a/drivers/video/lm3533_backlight.c b/drivers/video/lm3533_backlight.c
new file mode 100644
index 00000000000..00297a09b7f
--- /dev/null
+++ b/drivers/video/lm3533_backlight.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#define LOG_CATEGORY UCLASS_PANEL_BACKLIGHT
+
+#include <backlight.h>
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <asm/gpio.h>
+
+#define LM3533_BL_MIN_BRIGHTNESS 0x02
+#define LM3533_BL_MAX_BRIGHTNESS 0xFF
+
+#define LM3533_SINK_OUTPUT_CONFIG_1 0x10
+#define LM3533_CONTROL_BANK_A_PWM 0x14
+#define LM3533_CONTROL_BANK_AB_BRIGHTNESS 0x1A
+#define LM3533_CONTROL_BANK_A_FULLSCALE_CURRENT 0x1F
+#define LM3533_CONTROL_BANK_ENABLE 0x27
+#define LM3533_OVP_FREQUENCY_PWM_POLARITY 0x2C
+#define LM3533_BRIGHTNESS_REGISTER_A 0x40
+
+struct lm3533_backlight_priv {
+ struct gpio_desc enable_gpio;
+ u32 def_bl_lvl;
+};
+
+static int lm3533_backlight_enable(struct udevice *dev)
+{
+ struct lm3533_backlight_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ dm_gpio_set_value(&priv->enable_gpio, 1);
+ mdelay(5);
+
+ /* HVLED 1 & 2 are controlled by Bank A */
+ ret = dm_i2c_reg_write(dev, LM3533_SINK_OUTPUT_CONFIG_1, 0x00);
+ if (ret)
+ return ret;
+
+ /* PWM input is disabled for CABC */
+ ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_A_PWM, 0x00);
+ if (ret)
+ return ret;
+
+ /* Linear & Control Bank A is configured for register Current control */
+ ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_AB_BRIGHTNESS, 0x02);
+ if (ret)
+ return ret;
+
+ /* Full-Scale Current (20.2mA) */
+ ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_A_FULLSCALE_CURRENT, 0x13);
+ if (ret)
+ return ret;
+
+ /* Control Bank A is enable */
+ ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_ENABLE, 0x01);
+ if (ret)
+ return ret;
+
+ ret = dm_i2c_reg_write(dev, LM3533_OVP_FREQUENCY_PWM_POLARITY, 0x0A);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int lm3533_backlight_set_brightness(struct udevice *dev, int percent)
+{
+ struct lm3533_backlight_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ if (percent == BACKLIGHT_DEFAULT)
+ percent = priv->def_bl_lvl;
+
+ if (percent < LM3533_BL_MIN_BRIGHTNESS)
+ percent = LM3533_BL_MIN_BRIGHTNESS;
+
+ if (percent > LM3533_BL_MAX_BRIGHTNESS)
+ percent = LM3533_BL_MAX_BRIGHTNESS;
+
+ /* Set brightness level */
+ ret = dm_i2c_reg_write(dev, LM3533_BRIGHTNESS_REGISTER_A,
+ percent);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int lm3533_backlight_probe(struct udevice *dev)
+{
+ struct lm3533_backlight_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ if (device_get_uclass_id(dev->parent) != UCLASS_I2C)
+ return -EPROTONOSUPPORT;
+
+ ret = gpio_request_by_name(dev, "enable-gpios", 0,
+ &priv->enable_gpio, GPIOD_IS_OUT);
+ if (ret) {
+ log_err("Could not decode enable-gpios (%d)\n", ret);
+ return ret;
+ }
+
+ priv->def_bl_lvl = dev_read_u32_default(dev, "default-brightness-level",
+ LM3533_BL_MAX_BRIGHTNESS);
+
+ return 0;
+}
+
+static const struct backlight_ops lm3533_backlight_ops = {
+ .enable = lm3533_backlight_enable,
+ .set_brightness = lm3533_backlight_set_brightness,
+};
+
+static const struct udevice_id lm3533_backlight_ids[] = {
+ { .compatible = "ti,lm3533" },
+ { }
+};
+
+U_BOOT_DRIVER(lm3533_backlight) = {
+ .name = "lm3533_backlight",
+ .id = UCLASS_PANEL_BACKLIGHT,
+ .of_match = lm3533_backlight_ids,
+ .probe = lm3533_backlight_probe,
+ .ops = &lm3533_backlight_ops,
+ .priv_auto = sizeof(struct lm3533_backlight_priv),
+};
diff --git a/drivers/video/renesas-r61307.c b/drivers/video/renesas-r61307.c
new file mode 100644
index 00000000000..426fdc6224a
--- /dev/null
+++ b/drivers/video/renesas-r61307.c
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Renesas R61307 panel driver
+ *
+ * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <common.h>
+#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>
+
+/*
+ * The datasheet is not publicly available, all values are
+ * taken from the downstream. If you have access to datasheets,
+ * corrections are welcome.
+ */
+
+#define R61307_MACP 0xB0 /* Manufacturer CMD Protect */
+
+#define R61307_INVERSION 0xC1
+#define R61307_GAMMA_SET_A 0xC8 /* Gamma Setting A */
+#define R61307_GAMMA_SET_B 0xC9 /* Gamma Setting B */
+#define R61307_GAMMA_SET_C 0xCA /* Gamma Setting C */
+#define R61307_CONTRAST_SET 0xCC
+
+struct renesas_r61307_priv {
+ struct udevice *vcc;
+ struct udevice *iovcc;
+
+ struct udevice *backlight;
+
+ struct gpio_desc reset_gpio;
+
+ bool dig_cont_adj;
+ bool inversion;
+ u32 gamma;
+};
+
+static const u8 macp_on[] = {
+ R61307_MACP, 0x03
+};
+
+static const u8 macp_off[] = {
+ R61307_MACP, 0x04
+};
+
+static const u8 address_mode[] = {
+ MIPI_DCS_SET_ADDRESS_MODE
+};
+
+static const u8 contrast_setting[] = {
+ R61307_CONTRAST_SET,
+ 0xdc, 0xb4, 0xff
+};
+
+static const u8 column_inversion[] = {
+ R61307_INVERSION,
+ 0x00, 0x50, 0x03, 0x22,
+ 0x16, 0x06, 0x60, 0x11
+};
+
+static const u8 line_inversion[] = {
+ R61307_INVERSION,
+ 0x00, 0x10, 0x03, 0x22,
+ 0x16, 0x06, 0x60, 0x01
+};
+
+static const u8 gamma_setting[][25] = {
+ {},
+ {
+ R61307_GAMMA_SET_A,
+ 0x00, 0x06, 0x0a, 0x0f,
+ 0x14, 0x1f, 0x1f, 0x17,
+ 0x12, 0x0c, 0x09, 0x06,
+ 0x00, 0x06, 0x0a, 0x0f,
+ 0x14, 0x1f, 0x1f, 0x17,
+ 0x12, 0x0c, 0x09, 0x06
+ },
+ {
+ R61307_GAMMA_SET_A,
+ 0x00, 0x05, 0x0b, 0x0f,
+ 0x11, 0x1d, 0x20, 0x18,
+ 0x18, 0x09, 0x07, 0x06,
+ 0x00, 0x05, 0x0b, 0x0f,
+ 0x11, 0x1d, 0x20, 0x18,
+ 0x18, 0x09, 0x07, 0x06
+ },
+ {
+ R61307_GAMMA_SET_A,
+ 0x0b, 0x0d, 0x10, 0x14,
+ 0x13, 0x1d, 0x20, 0x18,
+ 0x12, 0x09, 0x07, 0x06,
+ 0x0a, 0x0c, 0x10, 0x14,
+ 0x13, 0x1d, 0x20, 0x18,
+ 0x12, 0x09, 0x07, 0x06
+ },
+};
+
+static struct display_timing default_timing = {
+ .pixelclock.typ = 62000000,
+ .hactive.typ = 768,
+ .hfront_porch.typ = 116,
+ .hback_porch.typ = 81,
+ .hsync_len.typ = 5,
+ .vactive.typ = 1024,
+ .vfront_porch.typ = 24,
+ .vback_porch.typ = 8,
+ .vsync_len.typ = 2,
+};
+
+static int renesas_r61307_enable_backlight(struct udevice *dev)
+{
+ struct renesas_r61307_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = regulator_set_enable_if_allowed(priv->vcc, 1);
+ if (ret) {
+ log_err("enabling vcc-supply failed (%d)\n", ret);
+ return ret;
+ }
+ mdelay(5);
+
+ ret = regulator_set_enable_if_allowed(priv->iovcc, 1);
+ if (ret) {
+ log_err("enabling iovcc-supply failed (%d)\n", ret);
+ return ret;
+ }
+
+ ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+ if (ret) {
+ log_err("changing reset-gpio failed (%d)\n", ret);
+ return ret;
+ }
+ mdelay(5);
+
+ ret = dm_gpio_set_value(&priv->reset_gpio, 1);
+ if (ret) {
+ log_err("changing reset-gpio failed (%d)\n", ret);
+ return ret;
+ }
+
+ mdelay(5);
+
+ return 0;
+}
+
+static int renesas_r61307_set_backlight(struct udevice *dev, int percent)
+{
+ struct renesas_r61307_priv *priv = dev_get_priv(dev);
+ struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
+ struct mipi_dsi_device *dsi = plat->device;
+ int ret;
+
+ ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+ if (ret < 0) {
+ log_err("failed to exit sleep mode: %d\n", ret);
+ return ret;
+ }
+
+ mdelay(80);
+
+ mipi_dsi_dcs_write_buffer(dsi, address_mode,
+ sizeof(address_mode));
+
+ mdelay(20);
+
+ ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT << 4);
+ if (ret < 0) {
+ log_err("failed to set pixel format: %d\n", ret);
+ return ret;
+ }
+
+ /* MACP Off */
+ mipi_dsi_generic_write(dsi, macp_off, sizeof(macp_off));
+
+ if (priv->dig_cont_adj)
+ mipi_dsi_generic_write(dsi, contrast_setting,
+ sizeof(contrast_setting));
+
+ if (priv->gamma)
+ mipi_dsi_generic_write(dsi, gamma_setting[priv->gamma],
+ sizeof(gamma_setting[priv->gamma]));
+
+ if (priv->inversion)
+ mipi_dsi_generic_write(dsi, column_inversion,
+ sizeof(column_inversion));
+ else
+ mipi_dsi_generic_write(dsi, line_inversion,
+ sizeof(line_inversion));
+
+ /* MACP On */
+ mipi_dsi_generic_write(dsi, macp_on, sizeof(macp_on));
+
+ ret = mipi_dsi_dcs_set_display_on(dsi);
+ if (ret < 0) {
+ log_err("failed to set display on: %d\n", ret);
+ return ret;
+ }
+
+ mdelay(50);
+
+ ret = backlight_enable(priv->backlight);
+ if (ret)
+ return ret;
+
+ ret = backlight_set_brightness(priv->backlight, percent);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int renesas_r61307_timings(struct udevice *dev,
+ struct display_timing *timing)
+{
+ memcpy(timing, &default_timing, sizeof(*timing));
+ return 0;
+}
+
+static int renesas_r61307_of_to_plat(struct udevice *dev)
+{
+ struct renesas_r61307_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
+ "backlight", &priv->backlight);
+ if (ret) {
+ log_err("Cannot get backlight: ret = %d\n", ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
+ "vcc-supply", &priv->vcc);
+ if (ret) {
+ log_err("Cannot get vcc-supply: ret = %d\n", ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
+ "iovcc-supply", &priv->iovcc);
+ if (ret) {
+ log_err("Cannot get iovcc-supply: ret = %d\n", ret);
+ return ret;
+ }
+
+ ret = gpio_request_by_name(dev, "reset-gpios", 0,
+ &priv->reset_gpio, GPIOD_IS_OUT);
+ if (ret) {
+ log_err("Could not decode reser-gpios (%d)\n", ret);
+ return ret;
+ }
+
+ priv->dig_cont_adj = dev_read_bool(dev, "renesas,contrast");
+ priv->inversion = dev_read_bool(dev, "renesas,inversion");
+ priv->gamma = dev_read_u32_default(dev, "renesas,gamma", 0);
+
+ return 0;
+}
+
+static int renesas_r61307_probe(struct udevice *dev)
+{
+ struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
+
+ /* fill characteristics of DSI data link */
+ plat->lanes = 4;
+ plat->format = MIPI_DSI_FMT_RGB888;
+ plat->mode_flags = MIPI_DSI_MODE_VIDEO;
+
+ return 0;
+}
+
+static const struct panel_ops renesas_r61307_ops = {
+ .enable_backlight = renesas_r61307_enable_backlight,
+ .set_backlight = renesas_r61307_set_backlight,
+ .get_display_timing = renesas_r61307_timings,
+};
+
+static const struct udevice_id renesas_r61307_ids[] = {
+ { .compatible = "koe,tx13d100vm0eaa" },
+ { .compatible = "hitachi,tx13d100vm0eaa" },
+ { }
+};
+
+U_BOOT_DRIVER(renesas_r61307) = {
+ .name = "renesas_r61307",
+ .id = UCLASS_PANEL,
+ .of_match = renesas_r61307_ids,
+ .ops = &renesas_r61307_ops,
+ .of_to_plat = renesas_r61307_of_to_plat,
+ .probe = renesas_r61307_probe,
+ .plat_auto = sizeof(struct mipi_dsi_panel_plat),
+ .priv_auto = sizeof(struct renesas_r61307_priv),
+};
diff --git a/drivers/video/renesas-r69328.c b/drivers/video/renesas-r69328.c
new file mode 100644
index 00000000000..d2f71694681
--- /dev/null
+++ b/drivers/video/renesas-r69328.c
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Renesas R69328 panel driver
+ *
+ * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <common.h>
+#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>
+
+/*
+ * The datasheet is not publicly available, all values are
+ * taken from the downstream. If you have access to datasheets,
+ * corrections are welcome.
+ */
+
+#define R69328_MACP 0xB0 /* Manufacturer Command Access Protect */
+
+#define R69328_GAMMA_SET_A 0xC8 /* Gamma Setting A */
+#define R69328_GAMMA_SET_B 0xC9 /* Gamma Setting B */
+#define R69328_GAMMA_SET_C 0xCA /* Gamma Setting C */
+
+#define R69328_POWER_SET 0xD1
+
+struct renesas_r69328_priv {
+ struct udevice *backlight;
+
+ struct gpio_desc enable_gpio;
+ struct gpio_desc reset_gpio;
+};
+
+static const u8 address_mode[] = {
+ MIPI_DCS_SET_ADDRESS_MODE
+};
+
+#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 = 68000000,
+ .hactive.typ = 720,
+ .hfront_porch.typ = 92,
+ .hback_porch.typ = 62,
+ .hsync_len.typ = 4,
+ .vactive.typ = 1280,
+ .vfront_porch.typ = 6,
+ .vback_porch.typ = 3,
+ .vsync_len.typ = 1,
+};
+
+static int renesas_r69328_enable_backlight(struct udevice *dev)
+{
+ struct renesas_r69328_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = dm_gpio_set_value(&priv->enable_gpio, 1);
+ if (ret) {
+ log_err("error changing enable-gpios (%d)\n", ret);
+ return ret;
+ }
+ mdelay(5);
+
+ ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+ if (ret) {
+ log_err("error changing reset-gpios (%d)\n", ret);
+ return ret;
+ }
+ mdelay(5);
+
+ ret = dm_gpio_set_value(&priv->reset_gpio, 1);
+ if (ret) {
+ log_err("error changing reset-gpios (%d)\n", ret);
+ return ret;
+ }
+
+ mdelay(5);
+
+ return 0;
+}
+
+static int renesas_r69328_set_backlight(struct udevice *dev, int percent)
+{
+ struct renesas_r69328_priv *priv = dev_get_priv(dev);
+ struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
+ struct mipi_dsi_device *dsi = plat->device;
+ int ret;
+
+ mipi_dsi_dcs_write_buffer(dsi, address_mode,
+ sizeof(address_mode));
+
+ ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT << 4);
+ if (ret < 0) {
+ log_err("failed to set pixel format: %d\n", ret);
+ return ret;
+ }
+
+ ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+ if (ret < 0) {
+ log_err("failed to exit sleep mode: %d\n", ret);
+ return ret;
+ }
+
+ mdelay(100);
+
+ /* MACP Off */
+ dsi_generic_write_seq(dsi, R69328_MACP, 0x04);
+
+ dsi_generic_write_seq(dsi, R69328_POWER_SET, 0x14,
+ 0x1d, 0x21, 0x67, 0x11, 0x9a);
+
+ dsi_generic_write_seq(dsi, R69328_GAMMA_SET_A, 0x00,
+ 0x1a, 0x20, 0x28, 0x25, 0x24,
+ 0x26, 0x15, 0x13, 0x11, 0x18,
+ 0x1e, 0x1c, 0x00, 0x00, 0x1a,
+ 0x20, 0x28, 0x25, 0x24, 0x26,
+ 0x15, 0x13, 0x11, 0x18, 0x1e,
+ 0x1c, 0x00);
+ dsi_generic_write_seq(dsi, R69328_GAMMA_SET_B, 0x00,
+ 0x1a, 0x20, 0x28, 0x25, 0x24,
+ 0x26, 0x15, 0x13, 0x11, 0x18,
+ 0x1e, 0x1c, 0x00, 0x00, 0x1a,
+ 0x20, 0x28, 0x25, 0x24, 0x26,
+ 0x15, 0x13, 0x11, 0x18, 0x1e,
+ 0x1c, 0x00);
+ dsi_generic_write_seq(dsi, R69328_GAMMA_SET_C, 0x00,
+ 0x1a, 0x20, 0x28, 0x25, 0x24,
+ 0x26, 0x15, 0x13, 0x11, 0x18,
+ 0x1e, 0x1c, 0x00, 0x00, 0x1a,
+ 0x20, 0x28, 0x25, 0x24, 0x26,
+ 0x15, 0x13, 0x11, 0x18, 0x1e,
+ 0x1c, 0x00);
+
+ /* MACP On */
+ dsi_generic_write_seq(dsi, R69328_MACP, 0x03);
+
+ ret = mipi_dsi_dcs_set_display_on(dsi);
+ if (ret < 0) {
+ log_err("failed to set display on: %d\n", ret);
+ return ret;
+ }
+
+ mdelay(50);
+
+ ret = backlight_enable(priv->backlight);
+ if (ret)
+ return ret;
+
+ ret = backlight_set_brightness(priv->backlight, percent);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int renesas_r69328_timings(struct udevice *dev,
+ struct display_timing *timing)
+{
+ memcpy(timing, &default_timing, sizeof(*timing));
+ return 0;
+}
+
+static int renesas_r69328_of_to_plat(struct udevice *dev)
+{
+ struct renesas_r69328_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
+ "backlight", &priv->backlight);
+ if (ret) {
+ log_err("cannot get backlight: ret = %d\n", ret);
+ return ret;
+ }
+
+ ret = gpio_request_by_name(dev, "enable-gpios", 0,
+ &priv->enable_gpio, GPIOD_IS_OUT);
+ if (ret) {
+ log_err("could not decode enable-gpios (%d)\n", ret);
+ return ret;
+ }
+
+ ret = gpio_request_by_name(dev, "reset-gpios", 0,
+ &priv->reset_gpio, GPIOD_IS_OUT);
+ if (ret) {
+ log_err("could not decode reser-gpios (%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int renesas_r69328_probe(struct udevice *dev)
+{
+ struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
+
+ /* fill characteristics of DSI data link */
+ plat->lanes = 4;
+ plat->format = MIPI_DSI_FMT_RGB888;
+ plat->mode_flags = MIPI_DSI_MODE_VIDEO;
+
+ return 0;
+}
+
+static const struct panel_ops renesas_r69328_ops = {
+ .enable_backlight = renesas_r69328_enable_backlight,
+ .set_backlight = renesas_r69328_set_backlight,
+ .get_display_timing = renesas_r69328_timings,
+};
+
+static const struct udevice_id renesas_r69328_ids[] = {
+ { .compatible = "jdi,dx12d100vm0eaa" },
+ { }
+};
+
+U_BOOT_DRIVER(renesas_r69328) = {
+ .name = "renesas_r69328",
+ .id = UCLASS_PANEL,
+ .of_match = renesas_r69328_ids,
+ .ops = &renesas_r69328_ops,
+ .of_to_plat = renesas_r69328_of_to_plat,
+ .probe = renesas_r69328_probe,
+ .plat_auto = sizeof(struct mipi_dsi_panel_plat),
+ .priv_auto = sizeof(struct renesas_r69328_priv),
+};
diff --git a/drivers/video/tegra20/Kconfig b/drivers/video/tegra20/Kconfig
index 5b1dfbfbbed..f5c4843e119 100644
--- a/drivers/video/tegra20/Kconfig
+++ b/drivers/video/tegra20/Kconfig
@@ -15,3 +15,10 @@ config VIDEO_DSI_TEGRA30
help
T30 has native support for DSI panels. This option enables support
for such panels which can be used on endeavoru and tf600t.
+
+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
index e82ee96962f..f0b534c5794 100644
--- a/drivers/video/tegra20/Makefile
+++ b/drivers/video/tegra20/Makefile
@@ -2,3 +2,4 @@
obj-$(CONFIG_VIDEO_TEGRA20) += tegra-dc.o
obj-$(CONFIG_VIDEO_DSI_TEGRA30) += tegra-dsi.o mipi-phy.o
+obj-$(CONFIG_TEGRA_BACKLIGHT_PWM) += tegra-pwm-backlight.o
diff --git a/drivers/video/tegra20/tegra-pwm-backlight.c b/drivers/video/tegra20/tegra-pwm-backlight.c
new file mode 100644
index 00000000000..bb677daa8a1
--- /dev/null
+++ b/drivers/video/tegra20/tegra-pwm-backlight.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#define LOG_CATEGORY UCLASS_PANEL_BACKLIGHT
+
+#include <backlight.h>
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/arch/display.h>
+
+#define TEGRA_DISPLAY_A_BASE 0x54200000
+#define TEGRA_DISPLAY_B_BASE 0x54240000
+
+#define TEGRA_PWM_BL_MIN_BRIGHTNESS 0x10
+#define TEGRA_PWM_BL_MAX_BRIGHTNESS 0xFF
+
+#define TEGRA_PWM_BL_PERIOD 0xFF
+#define TEGRA_PWM_BL_CLK_DIV 0x14
+#define TEGRA_PWM_BL_CLK_SELECT 0x00
+
+#define PM_PERIOD_SHIFT 18
+#define PM_CLK_DIVIDER_SHIFT 4
+
+#define TEGRA_PWM_PM0 0
+#define TEGRA_PWM_PM1 1
+
+struct tegra_pwm_backlight_priv {
+ struct dc_ctlr *dc; /* Display controller regmap */
+
+ u32 pwm_source;
+ u32 period;
+ u32 clk_div;
+ u32 clk_select;
+ u32 dft_brightness;
+};
+
+static int tegra_pwm_backlight_set_brightness(struct udevice *dev, int percent)
+{
+ struct tegra_pwm_backlight_priv *priv = dev_get_priv(dev);
+ struct dc_cmd_reg *cmd = &priv->dc->cmd;
+ struct dc_com_reg *com = &priv->dc->com;
+ unsigned int ctrl;
+ unsigned long out_sel;
+ unsigned long cmd_state;
+
+ if (percent == BACKLIGHT_DEFAULT)
+ percent = priv->dft_brightness;
+
+ if (percent < TEGRA_PWM_BL_MIN_BRIGHTNESS)
+ percent = TEGRA_PWM_BL_MIN_BRIGHTNESS;
+
+ if (percent > TEGRA_PWM_BL_MAX_BRIGHTNESS)
+ percent = TEGRA_PWM_BL_MAX_BRIGHTNESS;
+
+ ctrl = ((priv->period << PM_PERIOD_SHIFT) |
+ (priv->clk_div << PM_CLK_DIVIDER_SHIFT) |
+ priv->clk_select);
+
+ /* The new value should be effected immediately */
+ cmd_state = readl(&cmd->state_access);
+ writel((cmd_state | (1 << 2)), &cmd->state_access);
+
+ switch (priv->pwm_source) {
+ case TEGRA_PWM_PM0:
+ /* Select the LM0 on PM0 */
+ out_sel = readl(&com->pin_output_sel[5]);
+ out_sel &= ~(7 << 0);
+ out_sel |= (3 << 0);
+ writel(out_sel, &com->pin_output_sel[5]);
+ writel(ctrl, &com->pm0_ctrl);
+ writel(percent, &com->pm0_duty_cycle);
+ break;
+ case TEGRA_PWM_PM1:
+ /* Select the LM1 on PM1 */
+ out_sel = readl(&com->pin_output_sel[5]);
+ out_sel &= ~(7 << 4);
+ out_sel |= (3 << 4);
+ writel(out_sel, &com->pin_output_sel[5]);
+ writel(ctrl, &com->pm1_ctrl);
+ writel(percent, &com->pm1_duty_cycle);
+ break;
+ default:
+ break;
+ }
+
+ writel(cmd_state, &cmd->state_access);
+ return 0;
+}
+
+static int tegra_pwm_backlight_enable(struct udevice *dev)
+{
+ struct tegra_pwm_backlight_priv *priv = dev_get_priv(dev);
+
+ return tegra_pwm_backlight_set_brightness(dev, priv->dft_brightness);
+}
+
+static int tegra_pwm_backlight_probe(struct udevice *dev)
+{
+ struct tegra_pwm_backlight_priv *priv = dev_get_priv(dev);
+
+ if (dev_read_bool(dev, "nvidia,display-b-base"))
+ priv->dc = (struct dc_ctlr *)TEGRA_DISPLAY_B_BASE;
+ else
+ priv->dc = (struct dc_ctlr *)TEGRA_DISPLAY_A_BASE;
+
+ if (!priv->dc) {
+ log_err("no display controller address\n");
+ return -EINVAL;
+ }
+
+ priv->pwm_source =
+ dev_read_u32_default(dev, "nvidia,pwm-source",
+ TEGRA_PWM_PM0);
+ priv->period =
+ dev_read_u32_default(dev, "nvidia,period",
+ TEGRA_PWM_BL_PERIOD);
+ priv->clk_div =
+ dev_read_u32_default(dev, "nvidia,clock-div",
+ TEGRA_PWM_BL_CLK_DIV);
+ priv->clk_select =
+ dev_read_u32_default(dev, "nvidia,clock-select",
+ TEGRA_PWM_BL_CLK_SELECT);
+ priv->dft_brightness =
+ dev_read_u32_default(dev, "nvidia,default-brightness",
+ TEGRA_PWM_BL_MAX_BRIGHTNESS);
+
+ return 0;
+}
+
+static const struct backlight_ops tegra_pwm_backlight_ops = {
+ .enable = tegra_pwm_backlight_enable,
+ .set_brightness = tegra_pwm_backlight_set_brightness,
+};
+
+static const struct udevice_id tegra_pwm_backlight_ids[] = {
+ { .compatible = "nvidia,tegra-pwm-backlight" },
+ { }
+};
+
+U_BOOT_DRIVER(tegra_pwm_backlight) = {
+ .name = "tegra_pwm_backlight",
+ .id = UCLASS_PANEL_BACKLIGHT,
+ .of_match = tegra_pwm_backlight_ids,
+ .probe = tegra_pwm_backlight_probe,
+ .ops = &tegra_pwm_backlight_ops,
+ .priv_auto = sizeof(struct tegra_pwm_backlight_priv),
+};
diff --git a/drivers/video/tidss/Kconfig b/drivers/video/tidss/Kconfig
index 2a5e56ea4ee..95086f3a5d6 100644
--- a/drivers/video/tidss/Kconfig
+++ b/drivers/video/tidss/Kconfig
@@ -16,3 +16,9 @@ menuconfig VIDEO_TIDSS
DPI . This option enables these supports which can be used on
devices which have OLDI or HDMI display connected.
+config SPL_VIDEO_TIDSS
+ bool "Enable TIDSS video support in SPL Stage"
+ depends on SPL_VIDEO
+ help
+ This options enables tidss driver in SPL stage. If
+ you need to use tidss at SPL stage use this config.
diff --git a/drivers/video/tidss/Makefile b/drivers/video/tidss/Makefile
index f4f8c6c470a..a29cee2a414 100644
--- a/drivers/video/tidss/Makefile
+++ b/drivers/video/tidss/Makefile
@@ -9,4 +9,4 @@
# Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
-obj-${CONFIG_VIDEO_TIDSS} = tidss_drv.o
+obj-${CONFIG_$(SPL_)VIDEO_TIDSS} = tidss_drv.o
diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c
index 1225de23332..a21fde0e1d4 100644
--- a/drivers/video/vidconsole-uclass.c
+++ b/drivers/video/vidconsole-uclass.c
@@ -86,7 +86,7 @@ static void vidconsole_newline(struct udevice *dev)
struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
struct udevice *vid_dev = dev->parent;
struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
- const int rows = CONFIG_CONSOLE_SCROLL_LINES;
+ const int rows = CONFIG_VAL(CONSOLE_SCROLL_LINES);
int i, ret;
priv->xcur_frac = priv->xstart_frac;
diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c
index da89f431441..8396bdfb11e 100644
--- a/drivers/video/video-uclass.c
+++ b/drivers/video/video-uclass.c
@@ -132,7 +132,7 @@ int video_reserve(ulong *addrp)
/* Allocate space for PCI video devices in case there were not bound */
if (*addrp == gd->video_top)
- *addrp -= CONFIG_VIDEO_PCI_DEFAULT_FB_SIZE;
+ *addrp -= CONFIG_VAL(VIDEO_PCI_DEFAULT_FB_SIZE);
gd->video_bottom = *addrp;
gd->fb_base = *addrp;
@@ -149,7 +149,7 @@ int video_fill(struct udevice *dev, u32 colour)
switch (priv->bpix) {
case VIDEO_BPP16:
- if (IS_ENABLED(CONFIG_VIDEO_BPP16)) {
+ if (CONFIG_IS_ENABLED(VIDEO_BPP16)) {
u16 *ppix = priv->fb;
u16 *end = priv->fb + priv->fb_size;
@@ -158,7 +158,7 @@ int video_fill(struct udevice *dev, u32 colour)
break;
}
case VIDEO_BPP32:
- if (IS_ENABLED(CONFIG_VIDEO_BPP32)) {
+ if (CONFIG_IS_ENABLED(VIDEO_BPP32)) {
u32 *ppix = priv->fb;
u32 *end = priv->fb + priv->fb_size;
@@ -212,14 +212,14 @@ u32 video_index_to_colour(struct video_priv *priv, unsigned int idx)
{
switch (priv->bpix) {
case VIDEO_BPP16:
- if (IS_ENABLED(CONFIG_VIDEO_BPP16)) {
+ if (CONFIG_IS_ENABLED(VIDEO_BPP16)) {
return ((colours[idx].r >> 3) << 11) |
((colours[idx].g >> 2) << 5) |
((colours[idx].b >> 3) << 0);
}
break;
case VIDEO_BPP32:
- if (IS_ENABLED(CONFIG_VIDEO_BPP32)) {
+ if (CONFIG_IS_ENABLED(VIDEO_BPP32)) {
if (priv->format == VIDEO_X2R10G10B10)
return (colours[idx].r << 22) |
(colours[idx].g << 12) |
@@ -513,8 +513,8 @@ static int video_post_probe(struct udevice *dev)
return ret;
}
- if (IS_ENABLED(CONFIG_VIDEO_LOGO) &&
- !IS_ENABLED(CONFIG_SPLASH_SCREEN) && !plat->hide_logo) {
+ if (CONFIG_IS_ENABLED(VIDEO_LOGO) &&
+ !CONFIG_IS_ENABLED(SPLASH_SCREEN) && !plat->hide_logo) {
ret = show_splash(dev);
if (ret) {
log_debug("Cannot show splash screen\n");
diff --git a/drivers/video/video_bmp.c b/drivers/video/video_bmp.c
index 6188a13e44e..47e52c4f69c 100644
--- a/drivers/video/video_bmp.c
+++ b/drivers/video/video_bmp.c
@@ -320,7 +320,7 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y,
switch (bmp_bpix) {
case 1:
case 8:
- if (IS_ENABLED(CONFIG_VIDEO_BMP_RLE8)) {
+ if (CONFIG_IS_ENABLED(VIDEO_BMP_RLE8)) {
u32 compression = get_unaligned_le32(
&bmp->header.compression);
debug("compressed %d %d\n", compression, BMP_BI_RLE8);
@@ -348,7 +348,7 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y,
}
break;
case 16:
- if (IS_ENABLED(CONFIG_BMP_16BPP)) {
+ if (CONFIG_IS_ENABLED(BMP_16BPP)) {
for (i = 0; i < height; ++i) {
schedule();
for (j = 0; j < width; j++) {
@@ -361,7 +361,7 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y,
}
break;
case 24:
- if (IS_ENABLED(CONFIG_BMP_24BPP)) {
+ if (CONFIG_IS_ENABLED(BMP_24BPP)) {
for (i = 0; i < height; ++i) {
for (j = 0; j < width; j++) {
if (bpix == 16) {
@@ -395,7 +395,7 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y,
}
break;
case 32:
- if (IS_ENABLED(CONFIG_BMP_32BPP)) {
+ if (CONFIG_IS_ENABLED(BMP_32BPP)) {
for (i = 0; i < height; ++i) {
for (j = 0; j < width; j++) {
if (eformat == VIDEO_X2R10G10B10) {