diff --git a/buildroot-external/board/raspberrypi/uboot-boot.sh b/buildroot-external/board/raspberrypi/uboot-boot.sh index 8b0b6649d..6a3ed9f81 100644 --- a/buildroot-external/board/raspberrypi/uboot-boot.sh +++ b/buildroot-external/board/raspberrypi/uboot-boot.sh @@ -36,12 +36,12 @@ for BOOT_SLOT in "${BOOT_ORDER}"; do done if test -n "${bootargs}"; then - #saveenv + saveenv else echo "No valid slot found, resetting tries to 3" setenv BOOT_A_LEFT 3 setenv BOOT_B_LEFT 3 - #saveenv + saveenv reset fi diff --git a/buildroot-external/board/raspberrypi/uboot.config b/buildroot-external/board/raspberrypi/uboot.config index acc0e2a45..c89061bf2 100644 --- a/buildroot-external/board/raspberrypi/uboot.config +++ b/buildroot-external/board/raspberrypi/uboot.config @@ -18,7 +18,6 @@ CONFIG_PINCTRL=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_DWC2=y -CONFIG_USB_STORAGE=y CONFIG_USB_KEYBOARD=y CONFIG_USB_HOST_ETHER=y CONFIG_USB_ETHER_SMSC95XX=y diff --git a/buildroot-external/patches/uboot/0002-mmc-unirqify-bcm2835-sdhost-and-fix-writes.patch b/buildroot-external/patches/uboot/0002-mmc-unirqify-bcm2835-sdhost-and-fix-writes.patch new file mode 100644 index 000000000..62d84c820 --- /dev/null +++ b/buildroot-external/patches/uboot/0002-mmc-unirqify-bcm2835-sdhost-and-fix-writes.patch @@ -0,0 +1,409 @@ +From patchwork Wed May 23 20:24:51 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [U-Boot] mmc: Unirqify bcm2835_sdhost and fix writes +X-Patchwork-Submitter: Alexander Graf +X-Patchwork-Id: 919394 +X-Patchwork-Delegate: agraf@suse.de +Message-Id: <20180523202451.68781-1-agraf@suse.de> +To: u-boot@lists.denx.de +Date: Wed, 23 May 2018 22:24:51 +0200 +From: Alexander Graf +List-Id: U-Boot discussion + +The bcm2835 sdhost driver has a problem with "write multiple" commands. +It seems to boil down to the fact that the controller dislikes its FIFO +to get drained at the end of a block when a write multiple blocks command +is in flight. + +The easy fix is to simply get rid of all the IRQ driven logic and make +the driver push as much data into the FIFO as it can. That way we never +drain and we never run into the problem. + +Reported-by: Jan Leonhardt +Signed-off-by: Alexander Graf +--- + drivers/mmc/bcm2835_sdhost.c | 265 ++++++++----------------------------------- + 1 file changed, 47 insertions(+), 218 deletions(-) + +diff --git a/drivers/mmc/bcm2835_sdhost.c b/drivers/mmc/bcm2835_sdhost.c +index 96428333b0..1ce019af57 100644 +--- a/drivers/mmc/bcm2835_sdhost.c ++++ b/drivers/mmc/bcm2835_sdhost.c +@@ -163,7 +163,6 @@ struct bcm2835_host { + int clock; /* Current clock speed */ + unsigned int max_clk; /* Max possible freq */ + unsigned int blocks; /* remaining PIO blocks */ +- int irq; /* Device IRQ */ + + u32 ns_per_fifo_word; + +@@ -173,14 +172,7 @@ struct bcm2835_host { + + struct mmc_cmd *cmd; /* Current command */ + struct mmc_data *data; /* Current data request */ +- bool data_complete:1;/* Data finished before cmd */ + bool use_busy:1; /* Wait for busy interrupt */ +- bool wait_data_complete:1; /* Wait for data */ +- +- /* for threaded irq handler */ +- bool irq_block; +- bool irq_busy; +- bool irq_data; + + struct udevice *dev; + struct mmc *mmc; +@@ -240,17 +232,9 @@ static void bcm2835_reset_internal(struct bcm2835_host *host) + writel(host->cdiv, host->ioaddr + SDCDIV); + } + +-static int bcm2835_finish_command(struct bcm2835_host *host); +- +-static void bcm2835_wait_transfer_complete(struct bcm2835_host *host) ++static int bcm2835_wait_transfer_complete(struct bcm2835_host *host) + { +- int timediff; +- u32 alternate_idle; +- +- alternate_idle = (host->data->flags & MMC_DATA_READ) ? +- SDEDM_FSM_READWAIT : SDEDM_FSM_WRITESTART1; +- +- timediff = 0; ++ int timediff = 0; + + while (1) { + u32 edm, fsm; +@@ -261,7 +245,10 @@ static void bcm2835_wait_transfer_complete(struct bcm2835_host *host) + if ((fsm == SDEDM_FSM_IDENTMODE) || + (fsm == SDEDM_FSM_DATAMODE)) + break; +- if (fsm == alternate_idle) { ++ ++ if ((fsm == SDEDM_FSM_READWAIT) || ++ (fsm == SDEDM_FSM_WRITESTART1) || ++ (fsm == SDEDM_FSM_READDATA)) { + writel(edm | SDEDM_FORCE_DATA_MODE, + host->ioaddr + SDEDM); + break; +@@ -273,9 +260,11 @@ static void bcm2835_wait_transfer_complete(struct bcm2835_host *host) + "wait_transfer_complete - still waiting after %d retries\n", + timediff); + bcm2835_dumpregs(host); +- return; ++ return -ETIMEDOUT; + } + } ++ ++ return 0; + } + + static int bcm2835_transfer_block_pio(struct bcm2835_host *host, bool is_read) +@@ -322,6 +311,9 @@ static int bcm2835_transfer_block_pio(struct bcm2835_host *host, bool is_read) + fsm_state != SDEDM_FSM_READCRC)) || + (!is_read && + (fsm_state != SDEDM_FSM_WRITEDATA && ++ fsm_state != SDEDM_FSM_WRITEWAIT1 && ++ fsm_state != SDEDM_FSM_WRITEWAIT2 && ++ fsm_state != SDEDM_FSM_WRITECRC && + fsm_state != SDEDM_FSM_WRITESTART1 && + fsm_state != SDEDM_FSM_WRITESTART2))) { + hsts = readl(host->ioaddr + SDHSTS); +@@ -358,9 +350,8 @@ static int bcm2835_transfer_pio(struct bcm2835_host *host) + + is_read = (host->data->flags & MMC_DATA_READ) != 0; + ret = bcm2835_transfer_block_pio(host, is_read); +- +- if (host->wait_data_complete) +- bcm2835_wait_transfer_complete(host); ++ if (ret) ++ return ret; + + sdhsts = readl(host->ioaddr + SDHSTS); + if (sdhsts & (SDHSTS_CRC16_ERROR | +@@ -379,21 +370,8 @@ static int bcm2835_transfer_pio(struct bcm2835_host *host) + return ret; + } + +-static void bcm2835_set_transfer_irqs(struct bcm2835_host *host) +-{ +- u32 all_irqs = SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN | +- SDHCFG_BUSY_IRPT_EN; +- +- host->hcfg = (host->hcfg & ~all_irqs) | +- SDHCFG_DATA_IRPT_EN | +- SDHCFG_BUSY_IRPT_EN; +- +- writel(host->hcfg, host->ioaddr + SDHCFG); +-} +- +-static +-void bcm2835_prepare_data(struct bcm2835_host *host, struct mmc_cmd *cmd, +- struct mmc_data *data) ++static void bcm2835_prepare_data(struct bcm2835_host *host, struct mmc_cmd *cmd, ++ struct mmc_data *data) + { + WARN_ON(host->data); + +@@ -401,14 +379,9 @@ void bcm2835_prepare_data(struct bcm2835_host *host, struct mmc_cmd *cmd, + if (!data) + return; + +- host->wait_data_complete = cmd->cmdidx != MMC_CMD_READ_MULTIPLE_BLOCK; +- host->data_complete = false; +- + /* Use PIO */ + host->blocks = data->blocks; + +- bcm2835_set_transfer_irqs(host); +- + writel(data->blocksize, host->ioaddr + SDHBCT); + writel(data->blocks, host->ioaddr + SDHBLC); + } +@@ -483,36 +456,6 @@ static int bcm2835_send_command(struct bcm2835_host *host, struct mmc_cmd *cmd, + return 0; + } + +-static int bcm2835_transfer_complete(struct bcm2835_host *host) +-{ +- int ret = 0; +- +- WARN_ON(!host->data_complete); +- +- host->data = NULL; +- +- return ret; +-} +- +-static void bcm2835_finish_data(struct bcm2835_host *host) +-{ +- host->hcfg &= ~(SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN); +- writel(host->hcfg, host->ioaddr + SDHCFG); +- +- host->data_complete = true; +- +- if (host->cmd) { +- /* Data managed to finish before the +- * command completed. Make sure we do +- * things in the proper order. +- */ +- dev_dbg(dev, "Finished early - HSTS %08x\n", +- readl(host->ioaddr + SDHSTS)); +- } else { +- bcm2835_transfer_complete(host); +- } +-} +- + static int bcm2835_finish_command(struct bcm2835_host *host) + { + struct mmc_cmd *cmd = host->cmd; +@@ -562,8 +505,6 @@ static int bcm2835_finish_command(struct bcm2835_host *host) + + /* Processed actual command. */ + host->cmd = NULL; +- if (host->data && host->data_complete) +- ret = bcm2835_transfer_complete(host); + + return ret; + } +@@ -608,159 +549,44 @@ static int bcm2835_check_data_error(struct bcm2835_host *host, u32 intmask) + return ret; + } + +-static void bcm2835_busy_irq(struct bcm2835_host *host) +-{ +- if (WARN_ON(!host->cmd)) { +- bcm2835_dumpregs(host); +- return; +- } +- +- if (WARN_ON(!host->use_busy)) { +- bcm2835_dumpregs(host); +- return; +- } +- host->use_busy = false; +- +- bcm2835_finish_command(host); +-} +- +-static void bcm2835_data_irq(struct bcm2835_host *host, u32 intmask) ++static int bcm2835_transmit(struct bcm2835_host *host) + { ++ u32 intmask = readl(host->ioaddr + SDHSTS); + int ret; + +- /* +- * There are no dedicated data/space available interrupt +- * status bits, so it is necessary to use the single shared +- * data/space available FIFO status bits. It is therefore not +- * an error to get here when there is no data transfer in +- * progress. +- */ +- if (!host->data) +- return; +- ++ /* Check for errors */ + ret = bcm2835_check_data_error(host, intmask); + if (ret) +- goto finished; +- +- if (host->data->flags & MMC_DATA_WRITE) { +- /* Use the block interrupt for writes after the first block */ +- host->hcfg &= ~(SDHCFG_DATA_IRPT_EN); +- host->hcfg |= SDHCFG_BLOCK_IRPT_EN; +- writel(host->hcfg, host->ioaddr + SDHCFG); +- bcm2835_transfer_pio(host); +- } else { +- bcm2835_transfer_pio(host); +- host->blocks--; +- if ((host->blocks == 0)) +- goto finished; +- } +- return; ++ return ret; + +-finished: +- host->hcfg &= ~(SDHCFG_DATA_IRPT_EN | SDHCFG_BLOCK_IRPT_EN); +- writel(host->hcfg, host->ioaddr + SDHCFG); +-} +- +-static void bcm2835_data_threaded_irq(struct bcm2835_host *host) +-{ +- if (!host->data) +- return; +- if ((host->blocks == 0)) +- bcm2835_finish_data(host); +-} +- +-static void bcm2835_block_irq(struct bcm2835_host *host) +-{ +- if (WARN_ON(!host->data)) { +- bcm2835_dumpregs(host); +- return; +- } +- +- WARN_ON(!host->blocks); +- if ((--host->blocks == 0)) +- bcm2835_finish_data(host); +- else +- bcm2835_transfer_pio(host); +-} ++ ret = bcm2835_check_cmd_error(host, intmask); ++ if (ret) ++ return ret; + +-static irqreturn_t bcm2835_irq(int irq, void *dev_id) +-{ +- irqreturn_t result = IRQ_NONE; +- struct bcm2835_host *host = dev_id; +- u32 intmask; +- +- intmask = readl(host->ioaddr + SDHSTS); +- +- writel(SDHSTS_BUSY_IRPT | +- SDHSTS_BLOCK_IRPT | +- SDHSTS_SDIO_IRPT | +- SDHSTS_DATA_FLAG, +- host->ioaddr + SDHSTS); +- +- if (intmask & SDHSTS_BLOCK_IRPT) { +- bcm2835_check_data_error(host, intmask); +- host->irq_block = true; +- result = IRQ_WAKE_THREAD; ++ /* Handle wait for busy end */ ++ if (host->use_busy && (intmask & SDHSTS_BUSY_IRPT)) { ++ writel(SDHSTS_BUSY_IRPT, host->ioaddr + SDHSTS); ++ host->use_busy = false; ++ bcm2835_finish_command(host); + } + +- if (intmask & SDHSTS_BUSY_IRPT) { +- if (!bcm2835_check_cmd_error(host, intmask)) { +- host->irq_busy = true; +- result = IRQ_WAKE_THREAD; +- } else { +- result = IRQ_HANDLED; ++ /* Handle PIO data transfer */ ++ if (host->data) { ++ ret = bcm2835_transfer_pio(host); ++ if (ret) ++ return ret; ++ host->blocks--; ++ if (host->blocks == 0) { ++ /* Wait for command to complete for real */ ++ ret = bcm2835_wait_transfer_complete(host); ++ if (ret) ++ return ret; ++ /* Transfer complete */ ++ host->data = NULL; + } + } + +- /* There is no true data interrupt status bit, so it is +- * necessary to qualify the data flag with the interrupt +- * enable bit. +- */ +- if ((intmask & SDHSTS_DATA_FLAG) && +- (host->hcfg & SDHCFG_DATA_IRPT_EN)) { +- bcm2835_data_irq(host, intmask); +- host->irq_data = true; +- result = IRQ_WAKE_THREAD; +- } +- +- return result; +-} +- +-static irqreturn_t bcm2835_threaded_irq(int irq, void *dev_id) +-{ +- struct bcm2835_host *host = dev_id; +- +- if (host->irq_block) { +- host->irq_block = false; +- bcm2835_block_irq(host); +- } +- +- if (host->irq_busy) { +- host->irq_busy = false; +- bcm2835_busy_irq(host); +- } +- +- if (host->irq_data) { +- host->irq_data = false; +- bcm2835_data_threaded_irq(host); +- } +- +- return IRQ_HANDLED; +-} +- +-static void bcm2835_irq_poll(struct bcm2835_host *host) +-{ +- u32 intmask; +- +- while (1) { +- intmask = readl(host->ioaddr + SDHSTS); +- if (intmask & (SDHSTS_BUSY_IRPT | SDHSTS_BLOCK_IRPT | +- SDHSTS_SDIO_IRPT | SDHSTS_DATA_FLAG)) { +- bcm2835_irq(0, host); +- bcm2835_threaded_irq(0, host); +- return; +- } +- } ++ return 0; + } + + static void bcm2835_set_clock(struct bcm2835_host *host, unsigned int clock) +@@ -864,8 +690,11 @@ static int bcm2835_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, + } + + /* Wait for completion of busy signal or data transfer */ +- while (host->use_busy || host->data) +- bcm2835_irq_poll(host); ++ while (host->use_busy || host->data) { ++ ret = bcm2835_transmit(host); ++ if (ret) ++ break; ++ } + + return ret; + } +