diff options
Diffstat (limited to 'drivers')
25 files changed, 382 insertions, 72 deletions
diff --git a/drivers/adc/rockchip-saradc.c b/drivers/adc/rockchip-saradc.c index e464d33f226..e0cbab6aa06 100644 --- a/drivers/adc/rockchip-saradc.c +++ b/drivers/adc/rockchip-saradc.c @@ -131,7 +131,7 @@ int rockchip_saradc_of_to_plat(struct udevice *dev) } priv->data = data; - uc_pdata->data_mask = (1 << priv->data->num_bits) - 1;; + uc_pdata->data_mask = (1 << priv->data->num_bits) - 1; uc_pdata->data_format = ADC_DATA_FORMAT_BIN; uc_pdata->data_timeout_us = SARADC_TIMEOUT / 5; uc_pdata->channel_mask = (1 << priv->data->num_channels) - 1; diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig index 509d01d41ef..66ce4cc29ba 100644 --- a/drivers/bootcount/Kconfig +++ b/drivers/bootcount/Kconfig @@ -68,15 +68,15 @@ config BOOTCOUNT_ENV "bootcount" is stored in the environment. To prevent a saveenv on all reboots, the environment variable "upgrade_available" is used. If "upgrade_available" is - 0, "bootcount" is always 0, if "upgrade_available" is - 1 "bootcount" is incremented in the environment. + 0, "bootcount" is always 0. If "upgrade_available" is 1, + "bootcount" is incremented in the environment. So the Userspace Application must set the "upgrade_available" - and "bootcount" variable to 0, if a boot was successfully. + and "bootcount" variables to 0, if the system booted successfully. config BOOTCOUNT_RAM bool "Boot counter in RAM" help - Store the bootcount in DRAM protected against against bit errors + Store the bootcount in DRAM protected against bit errors due to short power loss or holding a system in RESET. config BOOTCOUNT_I2C @@ -173,7 +173,7 @@ config BOOTCOUNT_BOOTLIMIT help Set the Maximum number of reboot cycles allowed without the boot counter being cleared. - If set to 0 do not set a boot limit in the environment. + If set to 0, do not set a boot limit in the environment. config BOOTCOUNT_ALEN int "I2C address length" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index f922a7c323d..bb4eee5d99b 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -29,7 +29,7 @@ obj-$(CONFIG_CLK_BOSTON) += clk_boston.o obj-$(CONFIG_CLK_CDCE9XX) += clk-cdce9xx.o obj-$(CONFIG_CLK_EXYNOS) += exynos/ obj-$(CONFIG_CLK_HSDK) += clk-hsdk-cgu.o -obj-$(CONFIG_CLK_K210) += clk_kendryte.o +obj-$(CONFIG_CLK_K210) += clk_k210.o obj-$(CONFIG_CLK_MPC83XX) += mpc83xx_clk.o obj-$(CONFIG_CLK_MPFS) += microchip/ obj-$(CONFIG_CLK_MVEBU) += mvebu/ diff --git a/drivers/clk/clk_kendryte.c b/drivers/clk/clk_k210.c index 97efda5b6f0..1961efaa5e7 100644 --- a/drivers/clk/clk_kendryte.c +++ b/drivers/clk/clk_k210.c @@ -14,7 +14,7 @@ #include <serial.h> #include <dt-bindings/clock/k210-sysctl.h> #include <dt-bindings/mfd/k210-sysctl.h> -#include <kendryte/pll.h> +#include <k210/pll.h> #include <linux/bitfield.h> DECLARE_GLOBAL_DATA_PTR; @@ -1271,7 +1271,7 @@ static int k210_clk_probe(struct udevice *dev) } static const struct udevice_id k210_clk_ids[] = { - { .compatible = "kendryte,k210-clk" }, + { .compatible = "canaan,k210-clk" }, { }, }; diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c index 5539becc197..335911c46bb 100644 --- a/drivers/i2c/i2c-uclass.c +++ b/drivers/i2c/i2c-uclass.c @@ -280,7 +280,7 @@ static int i2c_probe_chip(struct udevice *bus, uint chip_addr, if (ops->probe_chip) { ret = ops->probe_chip(bus, chip_addr, chip_flags); - if (!ret || ret != -ENOSYS) + if (ret != -ENOSYS) return ret; } diff --git a/drivers/misc/atsha204a-i2c.c b/drivers/misc/atsha204a-i2c.c index 715dabb2799..b89463babb5 100644 --- a/drivers/misc/atsha204a-i2c.c +++ b/drivers/misc/atsha204a-i2c.c @@ -240,10 +240,10 @@ int atsha204a_wakeup(struct udevice *dev) } debug("success\n"); - break; + return 0; } - return 0; + return -ETIMEDOUT; } int atsha204a_idle(struct udevice *dev) @@ -280,6 +280,7 @@ static int atsha204a_transaction(struct udevice *dev, struct atsha204a_req *req, } do { + udelay(ATSHA204A_EXECTIME); res = atsha204a_recv_resp(dev, resp); if (!res || res == -EMSGSIZE || res == -EBADMSG) break; @@ -287,7 +288,6 @@ static int atsha204a_transaction(struct udevice *dev, struct atsha204a_req *req, debug("ATSHA204A transaction polling for response " "(timeout = %d)\n", timeout); - udelay(ATSHA204A_EXECTIME); timeout -= ATSHA204A_EXECTIME; } while (timeout > 0); @@ -388,7 +388,7 @@ static int atsha204a_of_to_plat(struct udevice *dev) fdt_addr_t *priv = dev_get_priv(dev); fdt_addr_t addr; - addr = fdtdec_get_addr(gd->fdt_blob, dev_of_offset(dev), "reg"); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) { debug("Can't get ATSHA204A I2C base address\n"); return -ENXIO; diff --git a/drivers/misc/mxc_ocotp.c b/drivers/misc/mxc_ocotp.c index b1893a5c7eb..8ee18f29d9b 100644 --- a/drivers/misc/mxc_ocotp.c +++ b/drivers/misc/mxc_ocotp.c @@ -6,7 +6,7 @@ * Based on Dirk Behme's * https://github.com/dirkbehme/u-boot-imx6/blob/28b17e9/drivers/misc/imx_otp.c, * which is based on Freescale's - * http://git.freescale.com/git/cgit.cgi/imx/uboot-imx.git/tree/drivers/misc/imx_otp.c?h=imx_v2009.08_1.1.0&id=9aa74e6, + * https://source.codeaurora.org/external/imx/uboot-imx/tree/drivers/misc/imx_otp.c?id=9aa74e6, * which is: * Copyright (C) 2011 Freescale Semiconductor, Inc. */ diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index 697e3c641d0..02208a5ade4 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -827,13 +827,16 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode) struct mmc *mmc = &plat->mmc; u32 irqstaten = esdhc_read32(®s->irqstaten); u32 irqsigen = esdhc_read32(®s->irqsigen); - int i, ret = -ETIMEDOUT; - u32 val, mixctrl; + int i, err, ret = -ETIMEDOUT; + u32 val, mixctrl, tmp; /* clock tuning is not needed for upto 52MHz */ if (mmc->clock <= 52000000) return 0; + /* make sure the card clock keep on */ + esdhc_setbits32(®s->vendorspec, VENDORSPEC_FRC_SDCLK_ON); + /* This is readw/writew SDHCI_HOST_CONTROL2 when tuning */ if (priv->flags & ESDHC_FLAG_STD_TUNING) { val = esdhc_read32(®s->autoc12err); @@ -893,6 +896,12 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode) esdhc_stop_tuning(mmc); + /* change to default setting, let host control the card clock */ + esdhc_clrbits32(®s->vendorspec, VENDORSPEC_FRC_SDCLK_ON); + err = readx_poll_timeout(esdhc_read32, ®s->prsstat, tmp, tmp & PRSSTAT_SDOFF, 100); + if (err) + dev_warn(dev, "card clock not gate off as expect.\n"); + return ret; } #endif @@ -1567,14 +1576,24 @@ static int __maybe_unused fsl_esdhc_set_enhanced_strobe(struct udevice *dev) static int fsl_esdhc_wait_dat0(struct udevice *dev, int state, int timeout_us) { - int ret; + int ret, err; u32 tmp; struct fsl_esdhc_priv *priv = dev_get_priv(dev); struct fsl_esdhc *regs = priv->esdhc_regs; + /* make sure the card clock keep on */ + esdhc_setbits32(®s->vendorspec, VENDORSPEC_FRC_SDCLK_ON); + ret = readx_poll_timeout(esdhc_read32, ®s->prsstat, tmp, !!(tmp & PRSSTAT_DAT0) == !!state, timeout_us); + + /* change to default setting, let host control the card clock */ + esdhc_clrbits32(®s->vendorspec, VENDORSPEC_FRC_SDCLK_ON); + err = readx_poll_timeout(esdhc_read32, ®s->prsstat, tmp, tmp & PRSSTAT_SDOFF, 100); + if (err) + dev_warn(dev, "card clock not gate off as expect.\n"); + return ret; } diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c index b91df05de4f..f3f9d83ba36 100644 --- a/drivers/mmc/rockchip_sdhci.c +++ b/drivers/mmc/rockchip_sdhci.c @@ -22,6 +22,8 @@ #include <asm/arch-rockchip/clock.h> #include <asm/arch-rockchip/hardware.h> +/* DWCMSHC specific Mode Select value */ +#define DWCMSHC_CTRL_HS400 0x7 /* 400KHz is max freq for card ID etc. Use that as min */ #define EMMC_MIN_FREQ 400000 #define KHz (1000) @@ -42,6 +44,17 @@ ((((x) >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK) ==\ PHYCTRL_DLLRDY_DONE) +#define ARASAN_VENDOR_REGISTER 0x78 +#define ARASAN_VENDOR_ENHANCED_STROBE BIT(0) + +/* DWC IP vendor area 1 pointer */ +#define DWCMSHC_P_VENDOR_AREA1 0xe8 +#define DWCMSHC_AREA1_MASK GENMASK(11, 0) +/* Offset inside the vendor area 1 */ +#define DWCMSHC_EMMC_CONTROL 0x2c +#define DWCMSHC_CARD_IS_EMMC BIT(0) +#define DWCMSHC_ENHANCED_STROBE BIT(8) + /* Rockchip specific Registers */ #define DWCMSHC_EMMC_DLL_CTRL 0x800 #define DWCMSHC_EMMC_DLL_CTRL_RESET BIT(1) @@ -57,8 +70,14 @@ #define DWCMSHC_EMMC_DLL_INC_VALUE 2 #define DWCMSHC_EMMC_DLL_INC 8 #define DWCMSHC_EMMC_DLL_DLYENA BIT(27) -#define DLL_TXCLK_TAPNUM_DEFAULT 0x10 -#define DLL_STRBIN_TAPNUM_DEFAULT 0x3 +#define DLL_TXCLK_TAPNUM_DEFAULT 0xA + +#define DLL_STRBIN_TAPNUM_DEFAULT 0x8 +#define DLL_STRBIN_TAPNUM_FROM_SW BIT(24) +#define DLL_STRBIN_DELAY_NUM_SEL BIT(26) +#define DLL_STRBIN_DELAY_NUM_OFFSET 16 +#define DLL_STRBIN_DELAY_NUM_DEFAULT 0x16 + #define DLL_TXCLK_TAPNUM_FROM_SW BIT(24) #define DWCMSHC_EMMC_DLL_LOCKED BIT(8) #define DWCMSHC_EMMC_DLL_TIMEOUT BIT(9) @@ -117,6 +136,19 @@ struct sdhci_data { * Return: 0 if successful, -ve on error */ int (*set_ios_post)(struct sdhci_host *host); + + /** + * set_enhanced_strobe() - Set HS400 Enhanced Strobe config + * + * This is the set_enhanced_strobe() SDHCI operation that should + * be used for the hardware this driver data is associated with. + * Normally, this is used to set any host-specific configuration + * necessary for HS400 ES. + * + * @host: SDHCI host structure + * Return: 0 if successful, -ve on error + */ + int (*set_enhanced_strobe)(struct sdhci_host *host); }; static int rk3399_emmc_phy_init(struct udevice *dev) @@ -206,6 +238,21 @@ static int rk3399_emmc_get_phy(struct udevice *dev) return 0; } +static int rk3399_sdhci_set_enhanced_strobe(struct sdhci_host *host) +{ + struct mmc *mmc = host->mmc; + u32 vendor; + + vendor = sdhci_readl(host, ARASAN_VENDOR_REGISTER); + if (mmc->selected_mode == MMC_HS_400_ES) + vendor |= ARASAN_VENDOR_ENHANCED_STROBE; + else + vendor &= ~ARASAN_VENDOR_ENHANCED_STROBE; + sdhci_writel(host, vendor, ARASAN_VENDOR_REGISTER); + + return 0; +} + static void rk3399_sdhci_set_control_reg(struct sdhci_host *host) { struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, host); @@ -217,6 +264,15 @@ static void rk3399_sdhci_set_control_reg(struct sdhci_host *host) rk3399_emmc_phy_power_off(priv->phy); sdhci_set_control_reg(host); + + /* + * Reinitializing the device tries to set it to lower-speed modes + * first, which fails if the Enhanced Strobe bit is set, making + * the device impossible to use. Set the correct value here to + * let reinitialization attempts succeed. + */ + if (CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT)) + rk3399_sdhci_set_enhanced_strobe(host); }; static int rk3399_sdhci_set_ios_post(struct sdhci_host *host) @@ -287,7 +343,8 @@ static int rk3568_sdhci_emmc_set_clock(struct sdhci_host *host, unsigned int clo sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK); extra = DWCMSHC_EMMC_DLL_DLYENA | - DLL_STRBIN_TAPNUM_DEFAULT; + DLL_STRBIN_TAPNUM_DEFAULT | + DLL_STRBIN_TAPNUM_FROM_SW; sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN); } else { /* reset the clock phase when the frequency is lower than 100MHz */ @@ -295,7 +352,15 @@ static int rk3568_sdhci_emmc_set_clock(struct sdhci_host *host, unsigned int clo extra = DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL; sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK); sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK); - sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_STRBIN); + /* + * Before switching to hs400es mode, the driver will enable + * enhanced strobe first. PHY needs to configure the parameters + * of enhanced strobe first. + */ + extra = DWCMSHC_EMMC_DLL_DLYENA | + DLL_STRBIN_DELAY_NUM_SEL | + DLL_STRBIN_DELAY_NUM_DEFAULT << DLL_STRBIN_DELAY_NUM_OFFSET; + sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN); } return 0; @@ -306,11 +371,30 @@ static int rk3568_emmc_get_phy(struct udevice *dev) return 0; } +static int rk3568_sdhci_set_enhanced_strobe(struct sdhci_host *host) +{ + struct mmc *mmc = host->mmc; + u32 vendor; + int reg; + + reg = (sdhci_readl(host, DWCMSHC_P_VENDOR_AREA1) & DWCMSHC_AREA1_MASK) + + DWCMSHC_EMMC_CONTROL; + + vendor = sdhci_readl(host, reg); + if (mmc->selected_mode == MMC_HS_400_ES) + vendor |= DWCMSHC_ENHANCED_STROBE; + else + vendor &= ~DWCMSHC_ENHANCED_STROBE; + sdhci_writel(host, vendor, reg); + + return 0; +} + static int rk3568_sdhci_set_ios_post(struct sdhci_host *host) { struct mmc *mmc = host->mmc; uint clock = mmc->tran_speed; - u32 reg; + u32 reg, vendor_reg; if (!clock) clock = mmc->clock; @@ -320,8 +404,15 @@ static int rk3568_sdhci_set_ios_post(struct sdhci_host *host) if (mmc->selected_mode == MMC_HS_400 || mmc->selected_mode == MMC_HS_400_ES) { reg = sdhci_readw(host, SDHCI_HOST_CONTROL2); reg &= ~SDHCI_CTRL_UHS_MASK; - reg |= SDHCI_CTRL_HS400; + reg |= DWCMSHC_CTRL_HS400; sdhci_writew(host, reg, SDHCI_HOST_CONTROL2); + + vendor_reg = (sdhci_readl(host, DWCMSHC_P_VENDOR_AREA1) & DWCMSHC_AREA1_MASK) + + DWCMSHC_EMMC_CONTROL; + /* set CARD_IS_EMMC bit to enable Data Strobe for HS400 */ + reg = sdhci_readw(host, vendor_reg); + reg |= DWCMSHC_CARD_IS_EMMC; + sdhci_writew(host, reg, vendor_reg); } else { sdhci_set_uhs_timing(host); } @@ -409,10 +500,22 @@ static int rockchip_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) return ret; } +static int rockchip_sdhci_set_enhanced_strobe(struct sdhci_host *host) +{ + struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, host); + struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(priv->dev); + + if (data->set_enhanced_strobe) + return data->set_enhanced_strobe(host); + + return -ENOTSUPP; +} + static struct sdhci_ops rockchip_sdhci_ops = { .set_ios_post = rockchip_sdhci_set_ios_post, .platform_execute_tuning = &rockchip_sdhci_execute_tuning, .set_control_reg = rockchip_sdhci_set_control_reg, + .set_enhanced_strobe = rockchip_sdhci_set_enhanced_strobe, }; static int rockchip_sdhci_probe(struct udevice *dev) @@ -495,12 +598,14 @@ static const struct sdhci_data rk3399_data = { .emmc_phy_init = rk3399_emmc_phy_init, .set_control_reg = rk3399_sdhci_set_control_reg, .set_ios_post = rk3399_sdhci_set_ios_post, + .set_enhanced_strobe = rk3399_sdhci_set_enhanced_strobe, }; static const struct sdhci_data rk3568_data = { .get_phy = rk3568_emmc_get_phy, .emmc_phy_init = rk3568_emmc_phy_init, .set_ios_post = rk3568_sdhci_set_ios_post, + .set_enhanced_strobe = rk3568_sdhci_set_enhanced_strobe, }; static const struct udevice_id sdhci_ids[] = { diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 766e4a6b0c5..bf989a594f7 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -513,6 +513,7 @@ void sdhci_set_uhs_timing(struct sdhci_host *host) reg |= SDHCI_CTRL_UHS_SDR104; break; case MMC_HS_400: + case MMC_HS_400_ES: reg |= SDHCI_CTRL_HS400; break; default: @@ -666,6 +667,7 @@ static int sdhci_set_ios(struct mmc *mmc) mmc->selected_mode == MMC_DDR_52 || mmc->selected_mode == MMC_HS_200 || mmc->selected_mode == MMC_HS_400 || + mmc->selected_mode == MMC_HS_400_ES || mmc->selected_mode == UHS_SDR25 || mmc->selected_mode == UHS_SDR50 || mmc->selected_mode == UHS_SDR104 || @@ -799,6 +801,19 @@ static int sdhci_wait_dat0(struct udevice *dev, int state, return -ETIMEDOUT; } +#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) +static int sdhci_set_enhanced_strobe(struct udevice *dev) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); + struct sdhci_host *host = mmc->priv; + + if (host->ops && host->ops->set_enhanced_strobe) + return host->ops->set_enhanced_strobe(host); + + return -ENOTSUPP; +} +#endif + const struct dm_mmc_ops sdhci_ops = { .send_cmd = sdhci_send_command, .set_ios = sdhci_set_ios, @@ -808,6 +823,9 @@ const struct dm_mmc_ops sdhci_ops = { .execute_tuning = sdhci_execute_tuning, #endif .wait_dat0 = sdhci_wait_dat0, +#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) + .set_enhanced_strobe = sdhci_set_enhanced_strobe, +#endif }; #else static const struct mmc_ops sdhci_ops = { diff --git a/drivers/mmc/xenon_sdhci.c b/drivers/mmc/xenon_sdhci.c index e292f2903d8..2f8805096c1 100644 --- a/drivers/mmc/xenon_sdhci.c +++ b/drivers/mmc/xenon_sdhci.c @@ -439,6 +439,8 @@ static const struct sdhci_ops xenon_sdhci_ops = { .set_ios_post = xenon_sdhci_set_ios_post }; +static struct dm_mmc_ops xenon_mmc_ops; + static int xenon_sdhci_probe(struct udevice *dev) { struct xenon_sdhci_plat *plat = dev_get_plat(dev); @@ -452,6 +454,9 @@ static int xenon_sdhci_probe(struct udevice *dev) host->mmc->dev = dev; upriv->mmc = host->mmc; + xenon_mmc_ops = sdhci_ops; + xenon_mmc_ops.wait_dat0 = NULL; + /* Set quirks */ host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_32BIT_DMA_ADDR; @@ -568,7 +573,7 @@ U_BOOT_DRIVER(xenon_sdhci_drv) = { .id = UCLASS_MMC, .of_match = xenon_sdhci_ids, .of_to_plat = xenon_sdhci_of_to_plat, - .ops = &sdhci_ops, + .ops = &xenon_mmc_ops, .bind = xenon_sdhci_bind, .probe = xenon_sdhci_probe, .remove = xenon_sdhci_remove, diff --git a/drivers/mtd/nand/raw/mxs_nand.c b/drivers/mtd/nand/raw/mxs_nand.c index 748056a43e6..ee5d7fde9ce 100644 --- a/drivers/mtd/nand/raw/mxs_nand.c +++ b/drivers/mtd/nand/raw/mxs_nand.c @@ -195,6 +195,7 @@ static inline int mxs_nand_legacy_calc_ecc_layout(struct bch_geometry *geo, struct nand_chip *chip = mtd_to_nand(mtd); struct mxs_nand_info *nand_info = nand_get_controller_data(chip); unsigned int block_mark_bit_offset; + int corr, ds_corr; /* The default for the length of Galois Field. */ geo->gf_len = 13; @@ -225,6 +226,17 @@ static inline int mxs_nand_legacy_calc_ecc_layout(struct bch_geometry *geo, geo->ecc_strength = min(round_down(geo->ecc_strength, 2), nand_info->max_ecc_strength_supported); + /* check ecc strength, same as nand_ecc_is_strong_enough() did*/ + if (chip->ecc_step_ds) { + corr = mtd->writesize * geo->ecc_strength / + geo->ecc_chunkn_size; + ds_corr = mtd->writesize * chip->ecc_strength_ds / + chip->ecc_step_ds; + if (corr < ds_corr || + geo->ecc_strength < chip->ecc_strength_ds) + return -EINVAL; + } + block_mark_bit_offset = mtd->writesize * 8 - (geo->ecc_strength * geo->gf_len * (geo->ecc_chunk_count - 1) + MXS_NAND_METADATA_SIZE * 8); @@ -1111,6 +1123,7 @@ static int mxs_nand_set_geometry(struct mtd_info *mtd, struct bch_geometry *geo) struct nand_chip *chip = mtd_to_nand(mtd); struct nand_chip *nand = mtd_to_nand(mtd); struct mxs_nand_info *nand_info = nand_get_controller_data(nand); + int err; if (chip->ecc_strength_ds > nand_info->max_ecc_strength_supported) { printf("unsupported NAND chip, minimum ecc required %d\n" @@ -1118,19 +1131,57 @@ static int mxs_nand_set_geometry(struct mtd_info *mtd, struct bch_geometry *geo) return -EINVAL; } - if ((!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0) && - mtd->oobsize < 1024) || nand_info->legacy_bch_geometry) { - dev_warn(mtd->dev, "use legacy bch geometry\n"); - return mxs_nand_legacy_calc_ecc_layout(geo, mtd); + /* use the legacy bch setting by default */ + if ((!nand_info->use_minimum_ecc && mtd->oobsize < 1024) || + !(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0)) { + dev_dbg(mtd->dev, "use legacy bch geometry\n"); + err = mxs_nand_legacy_calc_ecc_layout(geo, mtd); + if (!err) + return 0; } - if (mtd->oobsize > 1024 || chip->ecc_step_ds < mtd->oobsize) - return mxs_nand_calc_ecc_for_large_oob(geo, mtd); + /* for large oob nand */ + if (mtd->oobsize > 1024) { + dev_dbg(mtd->dev, "use large oob bch geometry\n"); + err = mxs_nand_calc_ecc_for_large_oob(geo, mtd); + if (!err) + return 0; + } - return mxs_nand_calc_ecc_layout_by_info(geo, mtd, - chip->ecc_strength_ds, chip->ecc_step_ds); + /* otherwise use the minimum ecc nand chips required */ + dev_dbg(mtd->dev, "use minimum ecc bch geometry\n"); + err = mxs_nand_calc_ecc_layout_by_info(geo, mtd, chip->ecc_strength_ds, + chip->ecc_step_ds); - return 0; + if (err) + dev_err(mtd->dev, "none of the bch geometry setting works\n"); + + return err; +} + +void mxs_nand_dump_geo(struct mtd_info *mtd) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + struct mxs_nand_info *nand_info = nand_get_controller_data(nand); + struct bch_geometry *geo = &nand_info->bch_geometry; + + dev_dbg(mtd->dev, "BCH Geometry :\n" + "GF Length\t\t: %u\n" + "ECC Strength\t\t: %u\n" + "ECC for Meta\t\t: %u\n" + "ECC Chunk0 Size\t\t: %u\n" + "ECC Chunkn Size\t\t: %u\n" + "ECC Chunk Count\t\t: %u\n" + "Block Mark Byte Offset\t: %u\n" + "Block Mark Bit Offset\t: %u\n", + geo->gf_len, + geo->ecc_strength, + geo->ecc_for_meta, + geo->ecc_chunk0_size, + geo->ecc_chunkn_size, + geo->ecc_chunk_count, + geo->block_mark_byte_offset, + geo->block_mark_bit_offset); } /* @@ -1159,6 +1210,8 @@ int mxs_nand_setup_ecc(struct mtd_info *mtd) if (ret) return ret; + mxs_nand_dump_geo(mtd); + /* Configure BCH and set NFC geometry */ mxs_reset_block(&bch_regs->hw_bch_ctrl_reg); diff --git a/drivers/mtd/nand/raw/mxs_nand_dt.c b/drivers/mtd/nand/raw/mxs_nand_dt.c index 878796d5552..b9833a646f0 100644 --- a/drivers/mtd/nand/raw/mxs_nand_dt.c +++ b/drivers/mtd/nand/raw/mxs_nand_dt.c @@ -92,8 +92,6 @@ static int mxs_nand_dt_probe(struct udevice *dev) info->use_minimum_ecc = dev_read_bool(dev, "fsl,use-minimum-ecc"); - info->legacy_bch_geometry = dev_read_bool(dev, "fsl,legacy-bch-geometry"); - if (IS_ENABLED(CONFIG_CLK) && IS_ENABLED(CONFIG_IMX8)) { /* Assigned clock already set clock */ struct clk gpmi_clk; diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index eee65949d77..fb3279b405e 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -12,6 +12,7 @@ #include <log.h> #include <nand.h> #include <reset.h> +#include <asm/gpio.h> #include <dm/device_compat.h> #include <linux/bitfield.h> #include <linux/bitops.h> @@ -149,6 +150,7 @@ struct stm32_fmc2_timings { struct stm32_fmc2_nand { struct nand_chip chip; struct stm32_fmc2_timings timings; + struct gpio_desc wp_gpio; int ncs; int cs_used[FMC2_MAX_CE]; }; @@ -824,6 +826,9 @@ static int stm32_fmc2_nfc_parse_child(struct stm32_fmc2_nfc *nfc, ofnode node) nand->cs_used[i] = cs[i]; } + gpio_request_by_name_nodev(node, "wp-gpios", 0, &nand->wp_gpio, + GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); + nand->chip.flash_node = node; return 0; @@ -972,6 +977,10 @@ static int stm32_fmc2_nfc_probe(struct udevice *dev) chip->ecc.size = FMC2_ECC_STEP_SIZE; chip->ecc.strength = FMC2_ECC_BCH8; + /* Disable Write Protect */ + if (dm_gpio_is_valid(&nand->wp_gpio)) + dm_gpio_set_value(&nand->wp_gpio, 0); + ret = nand_scan_ident(mtd, nand->ncs, NULL); if (ret) return ret; diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index ddddd13433c..030c38f5cc1 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -18,7 +18,7 @@ obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/ obj-$(CONFIG_PINCTRL_PIC32) += pinctrl_pic32.o obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/ -obj-$(CONFIG_PINCTRL_K210) += pinctrl-kendryte.o +obj-$(CONFIG_PINCTRL_K210) += pinctrl-k210.o obj-$(CONFIG_PINCTRL_MESON) += meson/ obj-$(CONFIG_PINCTRL_MTK) += mediatek/ obj-$(CONFIG_PINCTRL_MSCC) += mscc/ diff --git a/drivers/pinctrl/pinctrl-kendryte.c b/drivers/pinctrl/pinctrl-k210.c index 09d51ca6769..13f0a342686 100644 --- a/drivers/pinctrl/pinctrl-kendryte.c +++ b/drivers/pinctrl/pinctrl-k210.c @@ -511,7 +511,7 @@ static int k210_pc_get_drive(unsigned max_strength_ua) { int i; - for (i = K210_PC_DRIVE_MAX; i; i--) + for (i = K210_PC_DRIVE_MAX; i >= 0; i--) if (k210_pc_drive_strength[i] < max_strength_ua) return i; @@ -536,7 +536,7 @@ static int k210_pc_pinconf_set(struct udevice *dev, unsigned pin_selector, break; case PIN_CONFIG_BIAS_PULL_UP: if (argument) - val |= K210_PC_PD; + val |= K210_PC_PU; else return -EINVAL; break; @@ -679,6 +679,7 @@ static int k210_pc_probe(struct udevice *dev) { int ret, i, j; struct k210_pc_priv *priv = dev_get_priv(dev); + struct ofnode_phandle_args args; priv->fpioa = dev_read_addr_ptr(dev); if (!priv->fpioa) @@ -692,15 +693,23 @@ static int k210_pc_probe(struct udevice *dev) if (ret && ret != -ENOSYS && ret != -ENOTSUPP) goto err; - priv->sysctl = syscon_regmap_lookup_by_phandle(dev, "kendryte,sysctl"); + ret = dev_read_phandle_with_args(dev, "canaan,k210-sysctl-power", + NULL, 1, 0, &args); + if (ret) + goto err; + + if (args.args_count != 1) { + ret = -EINVAL; + goto err; + } + + priv->sysctl = syscon_node_to_regmap(args.node); if (IS_ERR(priv->sysctl)) { - ret = -ENODEV; + ret = PTR_ERR(priv->sysctl); goto err; } - ret = dev_read_u32(dev, "kendryte,power-offset", &priv->power_offset); - if (ret) - goto err; + priv->power_offset = args.args[0]; debug("%s: fpioa = %p sysctl = %p power offset = %x\n", __func__, priv->fpioa, (void *)priv->sysctl->ranges[0].start, @@ -726,7 +735,7 @@ err: } static const struct udevice_id k210_pc_ids[] = { - { .compatible = "kendryte,k210-fpioa" }, + { .compatible = "canaan,k210-fpioa" }, { } }; diff --git a/drivers/ram/rockchip/sdram_rk3188.c b/drivers/ram/rockchip/sdram_rk3188.c index d9ed8adfcfd..be8ba4464d4 100644 --- a/drivers/ram/rockchip/sdram_rk3188.c +++ b/drivers/ram/rockchip/sdram_rk3188.c @@ -762,7 +762,7 @@ static int sdram_init(struct dram_info *dram, * CS1, n=2 * CS0 & CS1, n = 3 */ - sdram_params->ch[channel].rank = 2, + sdram_params->ch[channel].rank = 2; clrsetbits_le32(&publ->pgcr, 0xF << 18, (sdram_params->ch[channel].rank | 1) << 18); diff --git a/drivers/ram/rockchip/sdram_rk3288.c b/drivers/ram/rockchip/sdram_rk3288.c index f3e4a2808ab..227a3cc6a88 100644 --- a/drivers/ram/rockchip/sdram_rk3288.c +++ b/drivers/ram/rockchip/sdram_rk3288.c @@ -862,7 +862,7 @@ static int sdram_init(struct dram_info *dram, * CS1, n=2 * CS0 & CS1, n = 3 */ - sdram_params->ch[channel].rank = 2, + sdram_params->ch[channel].rank = 2; clrsetbits_le32(&publ->pgcr, 0xF << 18, (sdram_params->ch[channel].rank | 1) << 18); diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c index 4d78aa5cb13..528a171b454 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr.c +++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c @@ -27,6 +27,8 @@ #define RCC_DDRITFCR_DPHYAPBRST (BIT(17)) #define RCC_DDRITFCR_DPHYRST (BIT(18)) #define RCC_DDRITFCR_DPHYCTLRST (BIT(19)) +#define RCC_DDRITFCR_DDRCKMOD_MASK GENMASK(22, 20) +#define RCC_DDRITFCR_DDRCKMOD_ASR BIT(20) struct reg_desc { const char *name; @@ -651,6 +653,26 @@ static void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl, wait_sw_done_ack(ctl); } +static void stm32mp1_asr_enable(struct ddr_info *priv) +{ + struct stm32mp1_ddrctl *ctl = priv->ctl; + + clrsetbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCKMOD_MASK, + RCC_DDRITFCR_DDRCKMOD_ASR); + + start_sw_done(ctl); + + setbits_le32(&ctl->hwlpctl, DDRCTRL_HWLPCTL_HW_LP_EN); + writel(DDRCTRL_PWRTMG_POWERDOWN_TO_X32(0x10) | + DDRCTRL_PWRTMG_SELFREF_TO_X32(0x01), + &ctl->pwrtmg); + setbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE); + setbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_SELFREF_EN); + + setbits_le32(&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); + wait_sw_done_ack(ctl); +} + /* board-specific DDR power initializations. */ __weak int board_ddr_power_init(enum ddr_type ddr_type) { @@ -822,6 +844,9 @@ start: stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3, config->c_reg.pwrctl); +/* Enable auto-self-refresh, which saves a bit of power at runtime. */ + stm32mp1_asr_enable(priv); + /* enable uMCTL2 AXI port 0 and 1 */ setbits_le32(&priv->ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN); setbits_le32(&priv->ctl->pctrl_1, DDRCTRL_PCTRL_N_PORT_EN); diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h b/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h index f1a26e31f6c..42be1ba57c7 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h +++ b/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h @@ -265,8 +265,14 @@ struct stm32mp1_ddrphy { #define DDRCTRL_PWRCTL_SELFREF_EN BIT(0) #define DDRCTRL_PWRCTL_POWERDOWN_EN BIT(1) +#define DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE BIT(3) #define DDRCTRL_PWRCTL_SELFREF_SW BIT(5) +#define DDRCTRL_PWRTMG_SELFREF_TO_X32(n) (((n) & 0xff) << 16) +#define DDRCTRL_PWRTMG_POWERDOWN_TO_X32(n) ((n) & 0x1f) + +#define DDRCTRL_HWLPCTL_HW_LP_EN BIT(0) + #define DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH BIT(0) #define DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_MASK GENMASK(27, 16) diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c index fc22f540fe6..47bea0b376a 100644 --- a/drivers/spi/designware_spi.c +++ b/drivers/spi/designware_spi.c @@ -194,6 +194,20 @@ static int dw_spi_apb_init(struct udevice *bus, struct dw_spi_priv *priv) return 0; } +static int dw_spi_apb_k210_init(struct udevice *bus, struct dw_spi_priv *priv) +{ + /* + * The Canaan Kendryte K210 SoC DW apb_ssi v4 spi controller is + * documented to have a 32 word deep TX and RX FIFO, which + * spi_hw_init() detects. However, when the RX FIFO is filled up to + * 32 entries (RXFLR = 32), an RX FIFO overrun error occurs. Avoid + * this problem by force setting fifo_len to 31. + */ + priv->fifo_len = 31; + + return dw_spi_apb_init(bus, priv); +} + static int dw_spi_dwc_init(struct udevice *bus, struct dw_spi_priv *priv) { priv->max_xfer = 32; @@ -252,7 +266,7 @@ static int dw_spi_of_to_plat(struct udevice *bus) static void spi_hw_init(struct udevice *bus, struct dw_spi_priv *priv) { dw_write(priv, DW_SPI_SSIENR, 0); - dw_write(priv, DW_SPI_IMR, 0xff); + dw_write(priv, DW_SPI_IMR, 0); dw_write(priv, DW_SPI_SSIENR, 1); /* @@ -758,8 +772,8 @@ static const struct udevice_id dw_spi_ids[] = { */ { .compatible = "altr,socfpga-spi", .data = (ulong)dw_spi_apb_init }, { .compatible = "altr,socfpga-arria10-spi", .data = (ulong)dw_spi_apb_init }, - { .compatible = "canaan,kendryte-k210-spi", .data = (ulong)dw_spi_apb_init }, - { .compatible = "canaan,kendryte-k210-ssi", .data = (ulong)dw_spi_dwc_init }, + { .compatible = "canaan,k210-spi", .data = (ulong)dw_spi_apb_k210_init}, + { .compatible = "canaan,k210-ssi", .data = (ulong)dw_spi_dwc_init }, { .compatible = "intel,stratix10-spi", .data = (ulong)dw_spi_apb_init }, { .compatible = "intel,agilex-spi", .data = (ulong)dw_spi_apb_init }, { .compatible = "mscc,ocelot-spi", .data = (ulong)dw_spi_apb_init }, diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index 2748270ad6a..77988f78ab3 100644 --- a/drivers/usb/gadget/dwc2_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -996,8 +996,9 @@ static int dwc2_udc_otg_of_to_plat(struct udevice *dev) plat->rx_fifo_sz = dev_read_u32_default(dev, "g-rx-fifo-size", 0); plat->np_tx_fifo_sz = dev_read_u32_default(dev, "g-np-tx-fifo-size", 0); - plat->tx_fifo_sz_nb = - dev_read_size(dev, "g-tx-fifo-size") / sizeof(u32); + ret = dev_read_size(dev, "g-tx-fifo-size"); + if (ret > 0) + plat->tx_fifo_sz_nb = ret / sizeof(u32); if (plat->tx_fifo_sz_nb > DWC2_MAX_HW_ENDPOINTS) plat->tx_fifo_sz_nb = DWC2_MAX_HW_ENDPOINTS; if (plat->tx_fifo_sz_nb) { diff --git a/drivers/video/stm32/stm32_ltdc.c b/drivers/video/stm32/stm32_ltdc.c index 87e5fd54d9a..e741e74739c 100644 --- a/drivers/video/stm32/stm32_ltdc.c +++ b/drivers/video/stm32/stm32_ltdc.c @@ -338,6 +338,7 @@ static int stm32_ltdc_probe(struct udevice *dev) struct display_timing timings; struct clk pclk; struct reset_ctl rst; + ulong rate; int ret; priv->regs = (void *)dev_read_addr(dev); @@ -375,13 +376,13 @@ static int stm32_ltdc_probe(struct udevice *dev) } } - ret = clk_set_rate(&pclk, timings.pixelclock.typ); - if (ret) - dev_warn(dev, "fail to set pixel clock %d hz\n", - timings.pixelclock.typ); + rate = clk_set_rate(&pclk, timings.pixelclock.typ); + if (IS_ERR_VALUE(rate)) + dev_warn(dev, "fail to set pixel clock %d hz, ret=%ld\n", + timings.pixelclock.typ, rate); dev_dbg(dev, "Set pixel clock req %d hz get %ld hz\n", - timings.pixelclock.typ, clk_get_rate(&pclk)); + timings.pixelclock.typ, rate); ret = reset_get_by_index(dev, 0, &rst); if (ret) { diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c index 5215114b2d8..9ae032e9c2d 100644 --- a/drivers/video/video-uclass.c +++ b/drivers/video/video-uclass.c @@ -33,7 +33,8 @@ * information represents the requires size and alignment of the frame buffer * for the device. The values can be an over-estimate but cannot be too * small. The actual values will be suppled (in the same manner) by the bind() - * method after relocation. + * method after relocation. Additionally driver can allocate frame buffer + * itself by setting plat->base. * * This information is then picked up by video_reserve() which works out how * much memory is needed for all devices. This is allocated between @@ -78,6 +79,10 @@ static ulong alloc_fb(struct udevice *dev, ulong *addrp) if (!plat->size) return 0; + /* Allow drivers to allocate the frame buffer themselves */ + if (plat->base) + return 0; + align = plat->align ? plat->align : 1 << 20; base = *addrp - plat->size; base &= ~(align - 1); diff --git a/drivers/video/video_bmp.c b/drivers/video/video_bmp.c index c8c3fd3549d..4d2d961696a 100644 --- a/drivers/video/video_bmp.c +++ b/drivers/video/video_bmp.c @@ -31,6 +31,18 @@ static uint get_bmp_col_16bpp(struct bmp_color_table_entry cte) } /** + * get_bmp_col_x2r10g10b10() - Convert a colour-table entry into a x2r10g10b10 pixel value + * + * Return: value to write to the x2r10g10b10 frame buffer for this palette entry + */ +static u32 get_bmp_col_x2r10g10b10(struct bmp_color_table_entry *cte) +{ + return ((cte->red << 22U) | + (cte->green << 12U) | + (cte->blue << 2U)); +} + +/** * write_pix8() - Write a pixel from a BMP image into the framebuffer * * This handles frame buffers with 8, 16, 24 or 32 bits per pixel @@ -42,8 +54,8 @@ static uint get_bmp_col_16bpp(struct bmp_color_table_entry cte) * which is either written directly (bpix == 8) or used to look up the * palette to get a colour to write */ -static void write_pix8(u8 *fb, uint bpix, struct bmp_color_table_entry *palette, - u8 *bmap) +static void write_pix8(u8 *fb, uint bpix, enum video_format eformat, + struct bmp_color_table_entry *palette, u8 *bmap) { if (bpix == 8) { *fb++ = *bmap; @@ -57,6 +69,8 @@ static void write_pix8(u8 *fb, uint bpix, struct bmp_color_table_entry *palette, *fb++ = cte->red; *fb++ = cte->green; *fb++ = cte->blue; + } else if (eformat == VIDEO_X2R10G10B10) { + *(u32 *)fb = get_bmp_col_x2r10g10b10(cte); } else { *fb++ = cte->blue; *fb++ = cte->green; @@ -66,28 +80,29 @@ static void write_pix8(u8 *fb, uint bpix, struct bmp_color_table_entry *palette, } } -static void draw_unencoded_bitmap(u8 **fbp, uint bpix, uchar *bmap, +static void draw_unencoded_bitmap(u8 **fbp, uint bpix, + enum video_format eformat, uchar *bmap, struct bmp_color_table_entry *palette, int cnt) { u8 *fb = *fbp; while (cnt > 0) { - write_pix8(fb, bpix, palette, bmap++); + write_pix8(fb, bpix, eformat, palette, bmap++); fb += bpix / 8; cnt--; } *fbp = fb; } -static void draw_encoded_bitmap(u8 **fbp, uint bpix, +static void draw_encoded_bitmap(u8 **fbp, uint bpix, enum video_format eformat, struct bmp_color_table_entry *palette, u8 *bmap, int cnt) { u8 *fb = *fbp; while (cnt > 0) { - write_pix8(fb, bpix, palette, bmap); + write_pix8(fb, bpix, eformat, palette, bmap); fb += bpix / 8; cnt--; } @@ -106,6 +121,7 @@ static void video_display_rle8_bitmap(struct udevice *dev, int x, y; int decode = 1; uint bytes_per_pixel = bpix / 8; + enum video_format eformat = priv->format; debug("%s\n", __func__); bmap = (uchar *)bmp + get_unaligned_le32(&bmp->header.data_offset); @@ -148,7 +164,7 @@ static void video_display_rle8_bitmap(struct udevice *dev, else cnt = runlen; draw_unencoded_bitmap( - &fb, bpix, + &fb, bpix, eformat, bmap, palette, cnt); } x += runlen; @@ -173,8 +189,9 @@ static void video_display_rle8_bitmap(struct udevice *dev, cnt = width - x; else cnt = runlen; - draw_encoded_bitmap(&fb, bpix, palette, - &bmap[1], cnt); + draw_encoded_bitmap(&fb, bpix, eformat, + palette, &bmap[1], + cnt); } x += runlen; } @@ -224,6 +241,7 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y, unsigned long width, height, byte_width; unsigned long pwidth = priv->xsize; unsigned colours, bpix, bmp_bpix; + enum video_format eformat; struct bmp_color_table_entry *palette; int hdr_size; int ret; @@ -245,6 +263,7 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y, colours = 1 << bmp_bpix; bpix = VNBITS(priv->bpix); + eformat = priv->format; if (bpix != 1 && bpix != 8 && bpix != 16 && bpix != 32) { printf("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n", @@ -312,7 +331,7 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y, for (i = 0; i < height; ++i) { WATCHDOG_RESET(); for (j = 0; j < width; j++) { - write_pix8(fb, bpix, palette, bmap); + write_pix8(fb, bpix, eformat, palette, bmap); bmap++; fb += bpix / 8; } @@ -345,6 +364,16 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y, (bmap[0] >> 3); bmap += 3; fb += 2; + } else if (eformat == VIDEO_X2R10G10B10) { + u32 pix; + + pix = *bmap++ << 2U; + pix |= *bmap++ << 12U; + pix |= *bmap++ << 22U; + *fb++ = pix & 0xff; + *fb++ = (pix >> 8) & 0xff; + *fb++ = (pix >> 16) & 0xff; + *fb++ = pix >> 24; } else { *fb++ = *bmap++; *fb++ = *bmap++; @@ -361,10 +390,23 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y, if (IS_ENABLED(CONFIG_BMP_32BPP)) { for (i = 0; i < height; ++i) { for (j = 0; j < width; j++) { - *fb++ = *bmap++; - *fb++ = *bmap++; - *fb++ = *bmap++; - *fb++ = *bmap++; + if (eformat == VIDEO_X2R10G10B10) { + u32 pix; + + pix = *bmap++ << 2U; + pix |= *bmap++ << 12U; + pix |= *bmap++ << 22U; + pix |= (*bmap++ >> 6) << 30U; + *fb++ = pix & 0xff; + *fb++ = (pix >> 8) & 0xff; + *fb++ = (pix >> 16) & 0xff; + *fb++ = pix >> 24; + } else { + *fb++ = *bmap++; + *fb++ = *bmap++; + *fb++ = *bmap++; + *fb++ = *bmap++; + } } fb -= priv->line_length + width * (bpix / 8); } |