diff options
Diffstat (limited to 'drivers')
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, ®s->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) { |