From 5f9338ad56e6b1168905e73ecfcd5e1b7b1a32e2 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Fri, 30 Jul 2021 14:23:54 +0200 Subject: [PATCH 1/6] fastboot: fix partition name truncation in environment lookup strlcat() need to be passed the full buffer length. The incorrect call caused truncation of partition names for fastboot_raw_partition_... and fastboot_partition_alias_... env lookup to much less than PART_NAME_LEN. Fixes: 69a752983171 ("fastboot: Fix possible buffer overrun") Signed-off-by: Matthias Schiffer Reviewed-by: Sean Anderson --- drivers/fastboot/fb_mmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c index cbb3f7b1de..2738dc836e 100644 --- a/drivers/fastboot/fb_mmc.c +++ b/drivers/fastboot/fb_mmc.c @@ -40,7 +40,7 @@ static int raw_part_get_info_by_name(struct blk_desc *dev_desc, /* check for raw partition descriptor */ strcpy(env_desc_name, "fastboot_raw_partition_"); - strlcat(env_desc_name, name, PART_NAME_LEN); + strlcat(env_desc_name, name, sizeof(env_desc_name)); raw_part_desc = strdup(env_get(env_desc_name)); if (raw_part_desc == NULL) return -ENODEV; @@ -114,7 +114,7 @@ static int part_get_info_by_name_or_alias(struct blk_desc **dev_desc, /* check for alias */ strcpy(env_alias_name, "fastboot_partition_alias_"); - strlcat(env_alias_name, name, PART_NAME_LEN); + strlcat(env_alias_name, name, sizeof(env_alias_name)); aliased_part_name = env_get(env_alias_name); if (aliased_part_name != NULL) ret = do_get_part_info(dev_desc, aliased_part_name, From 0892a7e5fa5ce38f58e0e6636ae56c6f60c080e0 Mon Sep 17 00:00:00 2001 From: Zhengxun Li Date: Tue, 14 Sep 2021 13:43:51 +0800 Subject: [PATCH 2/6] mtd: rawnand: Add Macronix raw NAND controller driver Add a driver for Macronix raw NAND controller. This patch referred from linux mxic_nand.c. The difference from the linux version is described here. 1. In order to adapt to the uboot nand framework, add function binding (cmdfunc, read_byte, read_buf, write_buf). 2. Added parsing command format to use hardware correctly. 3. Remove the incompatible functions of Uboot. Signed-off-by: Zhengxun Li --- drivers/mtd/nand/raw/Kconfig | 6 + drivers/mtd/nand/raw/Makefile | 1 + drivers/mtd/nand/raw/mxic_nand.c | 603 +++++++++++++++++++++++++++++++ 3 files changed, 610 insertions(+) create mode 100644 drivers/mtd/nand/raw/mxic_nand.c diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 790ee34403..332f9d7591 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -398,6 +398,12 @@ config NAND_MXS_USE_MINIMUM_ECC endif +config NAND_MXIC + bool "Macronix raw NAND controller" + select SYS_NAND_SELF_INIT + help + This selects the Macronix raw NAND controller driver. + config NAND_ZYNQ bool "Support for Zynq Nand controller" select SYS_NAND_SELF_INIT diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index a5ed2c536f..6ec3581d20 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o obj-$(CONFIG_NAND_OMAP_ELM) += omap_elm.o obj-$(CONFIG_NAND_PLAT) += nand_plat.o obj-$(CONFIG_NAND_SUNXI) += sunxi_nand.o +obj-$(CONFIG_NAND_MXIC) += mxic_nand.o obj-$(CONFIG_NAND_ZYNQ) += zynq_nand.o obj-$(CONFIG_NAND_STM32_FMC2) += stm32_fmc2_nand.o obj-$(CONFIG_CORTINA_NAND) += cortina_nand.o diff --git a/drivers/mtd/nand/raw/mxic_nand.c b/drivers/mtd/nand/raw/mxic_nand.c new file mode 100644 index 0000000000..e54df4615e --- /dev/null +++ b/drivers/mtd/nand/raw/mxic_nand.c @@ -0,0 +1,603 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Macronix International Co., Ltd. + * + * Author: + * Zhengxun Li + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HC_CFG 0x0 +#define HC_CFG_IF_CFG(x) ((x) << 27) +#define HC_CFG_DUAL_SLAVE BIT(31) +#define HC_CFG_INDIVIDUAL BIT(30) +#define HC_CFG_NIO(x) (((x) / 4) << 27) +#define HC_CFG_TYPE(s, t) ((t) << (23 + ((s) * 2))) +#define HC_CFG_TYPE_SPI_NOR 0 +#define HC_CFG_TYPE_SPI_NAND 1 +#define HC_CFG_TYPE_SPI_RAM 2 +#define HC_CFG_TYPE_RAW_NAND 3 +#define HC_CFG_SLV_ACT(x) ((x) << 21) +#define HC_CFG_CLK_PH_EN BIT(20) +#define HC_CFG_CLK_POL_INV BIT(19) +#define HC_CFG_BIG_ENDIAN BIT(18) +#define HC_CFG_DATA_PASS BIT(17) +#define HC_CFG_IDLE_SIO_LVL(x) ((x) << 16) +#define HC_CFG_MAN_START_EN BIT(3) +#define HC_CFG_MAN_START BIT(2) +#define HC_CFG_MAN_CS_EN BIT(1) +#define HC_CFG_MAN_CS_ASSERT BIT(0) + +#define INT_STS 0x4 +#define INT_STS_EN 0x8 +#define INT_SIG_EN 0xc +#define INT_STS_ALL GENMASK(31, 0) +#define INT_RDY_PIN BIT(26) +#define INT_RDY_SR BIT(25) +#define INT_LNR_SUSP BIT(24) +#define INT_ECC_ERR BIT(17) +#define INT_CRC_ERR BIT(16) +#define INT_LWR_DIS BIT(12) +#define INT_LRD_DIS BIT(11) +#define INT_SDMA_INT BIT(10) +#define INT_DMA_FINISH BIT(9) +#define INT_RX_NOT_FULL BIT(3) +#define INT_RX_NOT_EMPTY BIT(2) +#define INT_TX_NOT_FULL BIT(1) +#define INT_TX_EMPTY BIT(0) + +#define HC_EN 0x10 +#define HC_EN_BIT BIT(0) + +#define TXD(x) (0x14 + ((x) * 4)) +#define RXD 0x24 + +#define SS_CTRL(s) (0x30 + ((s) * 4)) +#define LRD_CFG 0x44 +#define LWR_CFG 0x80 +#define RWW_CFG 0x70 +#define OP_READ BIT(23) +#define OP_DUMMY_CYC(x) ((x) << 17) +#define OP_ADDR_BYTES(x) ((x) << 14) +#define OP_CMD_BYTES(x) (((x) - 1) << 13) +#define OP_OCTA_CRC_EN BIT(12) +#define OP_DQS_EN BIT(11) +#define OP_ENHC_EN BIT(10) +#define OP_PREAMBLE_EN BIT(9) +#define OP_DATA_DDR BIT(8) +#define OP_DATA_BUSW(x) ((x) << 6) +#define OP_ADDR_DDR BIT(5) +#define OP_ADDR_BUSW(x) ((x) << 3) +#define OP_CMD_DDR BIT(2) +#define OP_CMD_BUSW(x) (x) +#define OP_BUSW_1 0 +#define OP_BUSW_2 1 +#define OP_BUSW_4 2 +#define OP_BUSW_8 3 + +#define OCTA_CRC 0x38 +#define OCTA_CRC_IN_EN(s) BIT(3 + ((s) * 16)) +#define OCTA_CRC_CHUNK(s, x) ((fls((x) / 32)) << (1 + ((s) * 16))) +#define OCTA_CRC_OUT_EN(s) BIT(0 + ((s) * 16)) + +#define ONFI_DIN_CNT(s) (0x3c + (s)) + +#define LRD_CTRL 0x48 +#define RWW_CTRL 0x74 +#define LWR_CTRL 0x84 +#define LMODE_EN BIT(31) +#define LMODE_SLV_ACT(x) ((x) << 21) +#define LMODE_CMD1(x) ((x) << 8) +#define LMODE_CMD0(x) (x) + +#define LRD_ADDR 0x4c +#define LWR_ADDR 0x88 +#define LRD_RANGE 0x50 +#define LWR_RANGE 0x8c + +#define AXI_SLV_ADDR 0x54 + +#define DMAC_RD_CFG 0x58 +#define DMAC_WR_CFG 0x94 +#define DMAC_CFG_PERIPH_EN BIT(31) +#define DMAC_CFG_ALLFLUSH_EN BIT(30) +#define DMAC_CFG_LASTFLUSH_EN BIT(29) +#define DMAC_CFG_QE(x) (((x) + 1) << 16) +#define DMAC_CFG_BURST_LEN(x) (((x) + 1) << 12) +#define DMAC_CFG_BURST_SZ(x) ((x) << 8) +#define DMAC_CFG_DIR_READ BIT(1) +#define DMAC_CFG_START BIT(0) + +#define DMAC_RD_CNT 0x5c +#define DMAC_WR_CNT 0x98 + +#define SDMA_ADDR 0x60 + +#define DMAM_CFG 0x64 +#define DMAM_CFG_START BIT(31) +#define DMAM_CFG_CONT BIT(30) +#define DMAM_CFG_SDMA_GAP(x) (fls((x) / 8192) << 2) +#define DMAM_CFG_DIR_READ BIT(1) +#define DMAM_CFG_EN BIT(0) + +#define DMAM_CNT 0x68 + +#define LNR_TIMER_TH 0x6c + +#define RDM_CFG0 0x78 +#define RDM_CFG0_POLY(x) (x) + +#define RDM_CFG1 0x7c +#define RDM_CFG1_RDM_EN BIT(31) +#define RDM_CFG1_SEED(x) (x) + +#define LWR_SUSP_CTRL 0x90 +#define LWR_SUSP_CTRL_EN BIT(31) + +#define DMAS_CTRL 0x9c +#define DMAS_CTRL_EN BIT(31) +#define DMAS_CTRL_DIR_READ BIT(30) + +#define DATA_STROB 0xa0 +#define DATA_STROB_EDO_EN BIT(2) +#define DATA_STROB_INV_POL BIT(1) +#define DATA_STROB_DELAY_2CYC BIT(0) + +#define IDLY_CODE(x) (0xa4 + ((x) * 4)) +#define IDLY_CODE_VAL(x, v) ((v) << (((x) % 4) * 8)) + +#define GPIO 0xc4 +#define GPIO_PT(x) BIT(3 + ((x) * 16)) +#define GPIO_RESET(x) BIT(2 + ((x) * 16)) +#define GPIO_HOLDB(x) BIT(1 + ((x) * 16)) +#define GPIO_WPB(x) BIT((x) * 16) + +#define HC_VER 0xd0 + +#define HW_TEST(x) (0xe0 + ((x) * 4)) + +#define MXIC_NFC_MAX_CLK_HZ 50000000 +#define IRQ_TIMEOUT 1000 + +struct mxic_nand_ctrl { + struct clk *send_clk; + struct clk *send_dly_clk; + void __iomem *regs; + struct nand_chip nand_chip; +}; + +/* + * struct mxic_nfc_command_format - Defines NAND flash command format + * @start_cmd: First cycle command (Start command) + * @end_cmd: Second cycle command (Last command) + * @addr_len: Number of address cycles required to send the address + * @read: Direction of command + */ + +struct mxic_nfc_command_format { + int start_cmd; + int end_cmd; + u8 addr_len; + bool read; +}; + +/* The NAND flash operations command format */ +static const struct mxic_nfc_command_format mxic_nand_commands[] = { + {NAND_CMD_READ0, NAND_CMD_READSTART, 5, 1 }, + {NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, 2, 1 }, + {NAND_CMD_READID, NAND_CMD_NONE, 1, 1 }, + {NAND_CMD_STATUS, NAND_CMD_NONE, 0, 1 }, + {NAND_CMD_SEQIN, NAND_CMD_NONE, 5, 0 }, + {NAND_CMD_PAGEPROG, NAND_CMD_NONE, 0, 0 }, + {NAND_CMD_CACHEDPROG, NAND_CMD_NONE, 0, 0 }, + {NAND_CMD_RNDIN, NAND_CMD_NONE, 2, 0 }, + {NAND_CMD_ERASE1, NAND_CMD_NONE, 3, 0 }, + {NAND_CMD_ERASE2, NAND_CMD_NONE, 0, 0 }, + {NAND_CMD_RESET, NAND_CMD_NONE, 0, 0 }, + {NAND_CMD_PARAM, NAND_CMD_NONE, 1, 1 }, + {NAND_CMD_GET_FEATURES, NAND_CMD_NONE, 1, 1 }, + {NAND_CMD_SET_FEATURES, NAND_CMD_NONE, 1, 0 }, + {NAND_CMD_NONE, NAND_CMD_NONE, 0, 0 }, +}; + +static int mxic_nfc_clk_enable(struct mxic_nand_ctrl *nfc) +{ + int ret; + + ret = clk_prepare_enable(nfc->send_clk); + if (ret) + return ret; + + ret = clk_prepare_enable(nfc->send_dly_clk); + if (ret) + goto err_send_dly_clk; + + return ret; + +err_send_dly_clk: + clk_disable_unprepare(nfc->send_clk); + + return ret; +} + +static void mxic_nfc_clk_disable(struct mxic_nand_ctrl *nfc) +{ + clk_disable_unprepare(nfc->send_clk); + clk_disable_unprepare(nfc->send_dly_clk); +} + +static void mxic_nfc_set_input_delay(struct mxic_nand_ctrl *nfc, u8 idly_code) +{ + writel(IDLY_CODE_VAL(0, idly_code) | + IDLY_CODE_VAL(1, idly_code) | + IDLY_CODE_VAL(2, idly_code) | + IDLY_CODE_VAL(3, idly_code), + nfc->regs + IDLY_CODE(0)); + writel(IDLY_CODE_VAL(4, idly_code) | + IDLY_CODE_VAL(5, idly_code) | + IDLY_CODE_VAL(6, idly_code) | + IDLY_CODE_VAL(7, idly_code), + nfc->regs + IDLY_CODE(1)); +} + +static int mxic_nfc_clk_setup(struct mxic_nand_ctrl *nfc, unsigned long freq) +{ + int ret; + + ret = clk_set_rate(nfc->send_clk, freq); + if (ret) + return ret; + + ret = clk_set_rate(nfc->send_dly_clk, freq); + if (ret) + return ret; + + /* + * A constant delay range from 0x0 ~ 0x1F for input delay, + * the unit is 78 ps, the max input delay is 2.418 ns. + */ + mxic_nfc_set_input_delay(nfc, 0xf); + + return 0; +} + +static int mxic_nfc_set_freq(struct mxic_nand_ctrl *nfc, unsigned long freq) +{ + int ret; + + if (freq > MXIC_NFC_MAX_CLK_HZ) + freq = MXIC_NFC_MAX_CLK_HZ; + + mxic_nfc_clk_disable(nfc); + ret = mxic_nfc_clk_setup(nfc, freq); + if (ret) + return ret; + + ret = mxic_nfc_clk_enable(nfc); + if (ret) + return ret; + + return 0; +} + +static void mxic_nfc_hw_init(struct mxic_nand_ctrl *nfc) +{ + writel(HC_CFG_NIO(8) | HC_CFG_TYPE(1, HC_CFG_TYPE_RAW_NAND) | + HC_CFG_SLV_ACT(0) | HC_CFG_MAN_CS_EN | + HC_CFG_IDLE_SIO_LVL(1), nfc->regs + HC_CFG); + writel(INT_STS_ALL, nfc->regs + INT_STS_EN); + writel(INT_RDY_PIN, nfc->regs + INT_SIG_EN); + writel(0x0, nfc->regs + ONFI_DIN_CNT(0)); + writel(0, nfc->regs + LRD_CFG); + writel(0, nfc->regs + LRD_CTRL); + writel(0x0, nfc->regs + HC_EN); +} + +static void mxic_nfc_cs_enable(struct mxic_nand_ctrl *nfc) +{ + writel(readl(nfc->regs + HC_CFG) | HC_CFG_MAN_CS_EN, + nfc->regs + HC_CFG); + writel(HC_CFG_MAN_CS_ASSERT | readl(nfc->regs + HC_CFG), + nfc->regs + HC_CFG); +} + +static void mxic_nfc_cs_disable(struct mxic_nand_ctrl *nfc) +{ + writel(~HC_CFG_MAN_CS_ASSERT & readl(nfc->regs + HC_CFG), + nfc->regs + HC_CFG); +} + +static int mxic_nfc_data_xfer(struct mxic_nand_ctrl *nfc, const void *txbuf, + void *rxbuf, unsigned int len) +{ + unsigned int pos = 0; + + while (pos < len) { + unsigned int nbytes = len - pos; + u32 data = 0xffffffff; + u32 sts; + int ret; + + if (nbytes > 4) + nbytes = 4; + + if (txbuf) + memcpy(&data, txbuf + pos, nbytes); + + ret = readl_poll_timeout(nfc->regs + INT_STS, sts, + sts & INT_TX_EMPTY, 1000000); + if (ret) + return ret; + + writel(data, nfc->regs + TXD(nbytes % 4)); + + ret = readl_poll_timeout(nfc->regs + INT_STS, sts, + sts & INT_TX_EMPTY, 1000000); + if (ret) + return ret; + + ret = readl_poll_timeout(nfc->regs + INT_STS, sts, + sts & INT_RX_NOT_EMPTY, 1000000); + if (ret) + return ret; + + data = readl(nfc->regs + RXD); + if (rxbuf) { + data >>= (8 * (4 - nbytes)); + memcpy(rxbuf + pos, &data, nbytes); + } + + WARN_ON(readl(nfc->regs + INT_STS) & INT_RX_NOT_EMPTY); + + pos += nbytes; + } + + return 0; +} + +static uint8_t mxic_nfc_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct mxic_nand_ctrl *nfc = nand_get_controller_data(chip); + u8 data; + + writel(0x0, nfc->regs + ONFI_DIN_CNT(0)); + writel(OP_DATA_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) | + OP_READ, nfc->regs + SS_CTRL(0)); + + mxic_nfc_data_xfer(nfc, NULL, &data, 1); + + return data; +} + +static void mxic_nfc_read_buf(struct mtd_info *mtd, uint8_t *rxbuf, int rlen) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct mxic_nand_ctrl *nfc = nand_get_controller_data(chip); + + writel(0x0, nfc->regs + ONFI_DIN_CNT(0)); + writel(OP_DATA_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) | + OP_READ, nfc->regs + SS_CTRL(0)); + + mxic_nfc_data_xfer(nfc, NULL, rxbuf, rlen); +} + +static void mxic_nfc_write_buf(struct mtd_info *mtd, const uint8_t *txbuf, + int wlen) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct mxic_nand_ctrl *nfc = nand_get_controller_data(chip); + + writel(wlen, nfc->regs + ONFI_DIN_CNT(0)); + writel(OP_DATA_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F), + nfc->regs + SS_CTRL(0)); + + mxic_nfc_data_xfer(nfc, txbuf, NULL, wlen); +} + +static void mxic_nfc_cmd_function(struct mtd_info *mtd, unsigned int command, + int column, int page_addr) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct mxic_nand_ctrl *nfc = nand_get_controller_data(chip); + const struct mxic_nfc_command_format *cmd = NULL; + u32 sts; + u8 index, addr[5]; + + /* Emulate NAND_CMD_READOOB */ + if (command == NAND_CMD_READOOB) { + column += mtd->writesize; + command = NAND_CMD_READ0; + } + + /* Get the command format */ + for (index = 0; index < ARRAY_SIZE(mxic_nand_commands); index++) + if (command == mxic_nand_commands[index].start_cmd) + break; + + cmd = &mxic_nand_commands[index]; + + if (!(command == NAND_CMD_PAGEPROG || + command == NAND_CMD_CACHEDPROG || + command == NAND_CMD_ERASE2)) + mxic_nfc_cs_disable(nfc); + + mxic_nfc_cs_enable(nfc); + + if (column != -1) { + addr[0] = column; + addr[1] = column >> 8; + + if (page_addr != -1) { + addr[2] = page_addr; + addr[3] = page_addr >> 8; + addr[4] = page_addr >> 16; + } + } else if (page_addr != -1) { + addr[0] = page_addr; + addr[1] = page_addr >> 8; + addr[2] = page_addr >> 16; + } + + writel(0, nfc->regs + HC_EN); + writel(HC_EN_BIT, nfc->regs + HC_EN); + writel(OP_CMD_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) | OP_CMD_BYTES(0), + nfc->regs + SS_CTRL(0)); + + mxic_nfc_data_xfer(nfc, &cmd->start_cmd, NULL, 1); + + if (cmd->addr_len) { + writel(OP_ADDR_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) | + OP_ADDR_BYTES(cmd->addr_len), nfc->regs + SS_CTRL(0)); + + mxic_nfc_data_xfer(nfc, &addr, NULL, cmd->addr_len); + } + + if (cmd->end_cmd != NAND_CMD_NONE) { + writel(0, nfc->regs + HC_EN); + writel(HC_EN_BIT, nfc->regs + HC_EN); + writel(OP_CMD_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) | + OP_CMD_BYTES(0), nfc->regs + SS_CTRL(0)); + + mxic_nfc_data_xfer(nfc, &cmd->end_cmd, NULL, 1); + } + + readl_poll_timeout(nfc->regs + INT_STS, sts, sts & INT_RDY_PIN, + 1000000); + + if (command == NAND_CMD_PAGEPROG || + command == NAND_CMD_CACHEDPROG || + command == NAND_CMD_ERASE2 || + command == NAND_CMD_RESET) { + mxic_nfc_cs_disable(nfc); + } +} + +static int mxic_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr, + const struct nand_data_interface *conf) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct mxic_nand_ctrl *nfc = nand_get_controller_data(chip); + const struct nand_sdr_timings *sdr; + unsigned long freq; + int ret; + + sdr = nand_get_sdr_timings(conf); + if (IS_ERR(sdr)) + return PTR_ERR(sdr); + + if (chipnr == NAND_DATA_IFACE_CHECK_ONLY) + return 0; + + freq = 1000000000 / (sdr->tRC_min / 1000); + + ret = mxic_nfc_set_freq(nfc, freq); + if (ret) + WARN_ON("Set freq failed\n"); + + if (sdr->tRC_min < 30000) + writel(DATA_STROB_EDO_EN, nfc->regs + DATA_STROB); + + return 0; +} + +/* Dummy implementation: we don't support multiple chips */ +static void mxic_nfc_select_chip(struct mtd_info *mtd, int chipnr) +{ + switch (chipnr) { + case -1: + case 0: + break; + + default: + BUG(); + } +} + +static int mxic_nfc_probe(struct udevice *dev) +{ + struct mxic_nand_ctrl *nfc = dev_get_priv(dev); + struct nand_chip *nand_chip = &nfc->nand_chip; + struct mtd_info *mtd; + ofnode child; + int err; + + nfc->regs = (void *)dev_read_addr(dev); + + nfc->send_clk = devm_clk_get(dev, "send"); + if (IS_ERR(nfc->send_clk)) + return PTR_ERR(nfc->send_clk); + + nfc->send_dly_clk = devm_clk_get(dev, "send_dly"); + if (IS_ERR(nfc->send_dly_clk)) + return PTR_ERR(nfc->send_dly_clk); + + mtd = nand_to_mtd(nand_chip); + + ofnode_for_each_subnode(child, dev_ofnode(dev)) + nand_set_flash_node(nand_chip, child); + + nand_set_controller_data(nand_chip, nfc); + + nand_chip->select_chip = mxic_nfc_select_chip; + nand_chip->setup_data_interface = mxic_nfc_setup_data_interface; + nand_chip->cmdfunc = mxic_nfc_cmd_function; + nand_chip->read_byte = mxic_nfc_read_byte; + nand_chip->read_buf = mxic_nfc_read_buf; + nand_chip->write_buf = mxic_nfc_write_buf; + + mxic_nfc_hw_init(nfc); + + err = nand_scan(mtd, 1); + if (err) + return err; + + err = nand_register(0, mtd); + if (err) { + dev_err(dev, "Failed to register MTD: %d\n", err); + return err; + } + + return 0; +} + +static const struct udevice_id mxic_nfc_of_ids[] = { + { .compatible = "mxic,multi-itfc-v009-nand-controller" }, + { /* Sentinel */ } +}; + +U_BOOT_DRIVER(mxic_nfc) = { + .name = "mxic_nfc", + .id = UCLASS_MTD, + .of_match = mxic_nfc_of_ids, + .probe = mxic_nfc_probe, + .priv_auto = sizeof(struct mxic_nand_ctrl), +}; + +void board_nand_init(void) +{ + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_MTD, + DM_DRIVER_GET(mxic_nfc), &dev); + if (ret && ret != -ENODEV) + pr_err("Failed to initialize %s. (error %d)\n", dev->name, + ret); +} From 41130eb8937e43b2307fb67ebb60f0190fc01438 Mon Sep 17 00:00:00 2001 From: Ricardo Salveti Date: Sun, 26 Sep 2021 21:36:04 +0300 Subject: [PATCH 3/6] fs: fat: check for buffer size before reading blocks This patch optimizes the commit mentioned below by avoiding running a set of commands which are useless in the case when size < mydata->sect_size and sect_count would be 0. Fixes: 5b3ddb17ba ("fs/fat/fat.c: Do not perform zero block reads if there are no blocks left") Signed-off-by: Ricardo Salveti Co-developed-by: Oleksandr Suvorov Signed-off-by: Oleksandr Suvorov --- fs/fat/fat.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 7021138b98..65f77c4f75 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -275,22 +275,19 @@ get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size) buffer += mydata->sect_size; size -= mydata->sect_size; } - } else { - __u32 idx; + } else if (size >= mydata->sect_size) { + __u32 bytes_read; + __u32 sect_count = size / mydata->sect_size; - idx = size / mydata->sect_size; - if (idx == 0) - ret = 0; - else - ret = disk_read(startsect, idx, buffer); - if (ret != idx) { + ret = disk_read(startsect, sect_count, buffer); + if (ret != sect_count) { debug("Error reading data (got %d)\n", ret); return -1; } - startsect += idx; - idx *= mydata->sect_size; - buffer += idx; - size -= idx; + bytes_read = sect_count * mydata->sect_size; + startsect += sect_count; + buffer += bytes_read; + size -= bytes_read; } if (size) { ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size); From 07c652400d4e67cd11ada02b84c60e73bb031130 Mon Sep 17 00:00:00 2001 From: Mark Tomlinson Date: Tue, 28 Sep 2021 10:10:42 +1300 Subject: [PATCH 4/6] rtc: ds1307: Handle oscillator-stop bit correctly The DS1307 driver was originally based on the DS1337 driver. However, the functionality of the clock set/get functions has diverged. In the original DS1337 driver, the set/get functions did the following: 1) Setting the clock ensured the oscillator was enabled. 2) Getting the clock checked and reset the oscillator-stop flag. The DS1307 does not have an oscillator-stop flag, but the driver tried (incorrectly) to emulate this by ensuring the oscillator was running. It really makes no sense to start a stopped clock without setting it. This patch makes the DS1307 driver behave like the original DS1337 driver again. For the DS1307 itself, this is just a removal of code, since there is no oscillator-fail bit to check or reset, and the clock is started when it is set. Since the DS1307 driver can now also be used for the DS1337 and DS1340 which do have this bit, add code to handle the oscillator-stop bit in the same was the original DS1337 driver did -- i.e. report that the oscillator had stopped and clear the flag. This means that setting the date using the date command (which does both a get and a set) will now clear the oscillator-stop flag in addition to setting and starting the clock. The old-style (non-DM) code has not been updated and will be removed in a future patch. Note that this older code does not support the DS1337, as there is a separate driver for this. Also note that the original (DM) code used the wrong control-register address for the DS1337. Signed-off-by: Mark Tomlinson --- drivers/rtc/ds1307.c | 72 ++++++++++++-------------------------------- 1 file changed, 20 insertions(+), 52 deletions(-) diff --git a/drivers/rtc/ds1307.c b/drivers/rtc/ds1307.c index 3be97c9d93..1963565c5e 100644 --- a/drivers/rtc/ds1307.c +++ b/drivers/rtc/ds1307.c @@ -41,6 +41,12 @@ enum ds_type { #define RTC_YR_REG_ADDR 0x06 #define RTC_CTL_REG_ADDR 0x07 +#define DS1337_CTL_REG_ADDR 0x0e +#define DS1337_STAT_REG_ADDR 0x0f +#define DS1340_STAT_REG_ADDR 0x09 + +#define RTC_STAT_BIT_OSF 0x80 + #define RTC_SEC_BIT_CH 0x80 /* Clock Halt (in Register 0) */ /* DS1307-specific bits */ @@ -248,6 +254,11 @@ static int ds1307_rtc_set(struct udevice *dev, const struct rtc_time *tm) if (ret < 0) return ret; + if (type == ds_1337) { + /* Ensure oscillator is enabled */ + dm_i2c_reg_write(dev, DS1337_CTL_REG_ADDR, 0); + } + return 0; } @@ -257,62 +268,19 @@ static int ds1307_rtc_get(struct udevice *dev, struct rtc_time *tm) uchar buf[7]; enum ds_type type = dev_get_driver_data(dev); -read_rtc: ret = dm_i2c_read(dev, 0, buf, sizeof(buf)); if (ret < 0) return ret; - if (type == ds_1307) { - if (buf[RTC_SEC_REG_ADDR] & RTC_SEC_BIT_CH) { - printf("### Warning: RTC oscillator has stopped\n"); - /* clear the CH flag */ - buf[RTC_SEC_REG_ADDR] &= ~RTC_SEC_BIT_CH; - dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, - buf[RTC_SEC_REG_ADDR]); - return -1; - } - } else if (type == ds_1337) { - if (buf[RTC_CTL_REG_ADDR] & DS1337_CTL_BIT_EOSC) { - printf("### Warning: RTC oscillator has stopped\n"); - /* clear the not oscillator enable (~EOSC) flag */ - buf[RTC_CTL_REG_ADDR] &= ~DS1337_CTL_BIT_EOSC; - dm_i2c_reg_write(dev, RTC_CTL_REG_ADDR, - buf[RTC_CTL_REG_ADDR]); - return -1; - } - } else if (type == ds_1340) { - if (buf[RTC_SEC_REG_ADDR] & DS1340_SEC_BIT_EOSC) { - printf("### Warning: RTC oscillator has stopped\n"); - /* clear the not oscillator enable (~EOSC) flag */ - buf[RTC_SEC_REG_ADDR] &= ~DS1340_SEC_BIT_EOSC; - dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, - buf[RTC_SEC_REG_ADDR]); - return -1; - } - } else if (type == m41t11) { - /* clock halted? turn it on, so clock can tick. */ - if (buf[RTC_SEC_REG_ADDR] & RTC_SEC_BIT_CH) { - buf[RTC_SEC_REG_ADDR] &= ~RTC_SEC_BIT_CH; - dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, - MCP7941X_BIT_ST); - dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, - buf[RTC_SEC_REG_ADDR]); - goto read_rtc; - } - } else if (type == mcp794xx) { - /* make sure that the backup battery is enabled */ - if (!(buf[RTC_DAY_REG_ADDR] & MCP7941X_BIT_VBATEN)) { - dm_i2c_reg_write(dev, RTC_DAY_REG_ADDR, - buf[RTC_DAY_REG_ADDR] | - MCP7941X_BIT_VBATEN); - } + if (type == ds_1337 || type == ds_1340) { + uint reg = (type == ds_1337) ? DS1337_STAT_REG_ADDR : + DS1340_STAT_REG_ADDR; + int status = dm_i2c_reg_read(dev, reg); - /* clock halted? turn it on, so clock can tick. */ - if (!(buf[RTC_SEC_REG_ADDR] & MCP7941X_BIT_ST)) { - dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, - MCP7941X_BIT_ST); - printf("Started RTC\n"); - goto read_rtc; + if (status >= 0 && (status & RTC_STAT_BIT_OSF)) { + printf("### Warning: RTC oscillator has stopped\n"); + /* clear the OSF flag */ + dm_i2c_reg_write(dev, reg, status & ~RTC_STAT_BIT_OSF); } } @@ -361,7 +329,7 @@ static int ds1307_rtc_reset(struct udevice *dev) /* Write control register in order to enable oscillator output * (not EOSC) and set a default rate of 32.768kHz (RS2|RS1). */ - ret = dm_i2c_reg_write(dev, RTC_CTL_REG_ADDR, + ret = dm_i2c_reg_write(dev, DS1337_CTL_REG_ADDR, DS1337_CTL_BIT_RS2 | DS1337_CTL_BIT_RS1); } else if (type == ds_1340 || type == mcp794xx || type == m41t11) { /* Reset clock calibration, frequency test and output level. */ From 2c6bcab6e6e11030611b785d5bad50484424b128 Mon Sep 17 00:00:00 2001 From: Vagrant Cascadian Date: Tue, 28 Sep 2021 10:11:46 -0700 Subject: [PATCH 5/6] tools/image-host.c: Fix spelling of "expected". Signed-off-by: Vagrant Cascadian Reviewed-by: Simon Glass --- tools/image-host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/image-host.c b/tools/image-host.c index d3a882ec29..a6b0a94420 100644 --- a/tools/image-host.c +++ b/tools/image-host.c @@ -313,7 +313,7 @@ static int fit_image_read_data(char *filename, unsigned char *data, /* Check that we have read all the file */ if (n != sbuf.st_size) { - printf("Can't read all file %s (read %zd bytes, expexted %lld)\n", + printf("Can't read all file %s (read %zd bytes, expected %lld)\n", filename, n, (long long)sbuf.st_size); goto err; } From 30ac0b496b842ee38d941a3790c8c004f6275d04 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Mon, 4 Oct 2021 11:24:51 +0200 Subject: [PATCH 6/6] nvme: invalidate correct memory range after read The current code invalidates the range after the read buffer since the buffer pointer gets incremented in the read loop. Use a temporary pointer to make sure we have a pristine pointer to invalidate the correct memory range after read. Fixes: 704e040a51d2 ("nvme: Apply cache operations on the DMA buffers") Reviewed-by: Andre Przywara Signed-off-by: Stefan Agner --- drivers/nvme/nvme.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c index f6465ea7f4..3c529a2fce 100644 --- a/drivers/nvme/nvme.c +++ b/drivers/nvme/nvme.c @@ -743,6 +743,7 @@ static ulong nvme_blk_rw(struct udevice *udev, lbaint_t blknr, u64 prp2; u64 total_len = blkcnt << desc->log2blksz; u64 temp_len = total_len; + uintptr_t temp_buffer = (uintptr_t)buffer; u64 slba = blknr; u16 lbas = 1 << (dev->max_transfer_shift - ns->lba_shift); @@ -770,19 +771,19 @@ static ulong nvme_blk_rw(struct udevice *udev, lbaint_t blknr, } if (nvme_setup_prps(dev, &prp2, - lbas << ns->lba_shift, (ulong)buffer)) + lbas << ns->lba_shift, temp_buffer)) return -EIO; c.rw.slba = cpu_to_le64(slba); slba += lbas; c.rw.length = cpu_to_le16(lbas - 1); - c.rw.prp1 = cpu_to_le64((ulong)buffer); + c.rw.prp1 = cpu_to_le64(temp_buffer); c.rw.prp2 = cpu_to_le64(prp2); status = nvme_submit_sync_cmd(dev->queues[NVME_IO_Q], &c, NULL, IO_TIMEOUT); if (status) break; temp_len -= (u32)lbas << ns->lba_shift; - buffer += lbas << ns->lba_shift; + temp_buffer += lbas << ns->lba_shift; } if (read)