* [PATCH 1/8] mci: sdhci: Set 8-bit host caps
@ 2023-07-10 17:23 Jules Maselbas
2023-07-10 17:23 ` [PATCH 2/8] mci: sdhci: Add registers defines Jules Maselbas
` (6 more replies)
0 siblings, 7 replies; 13+ messages in thread
From: Jules Maselbas @ 2023-07-10 17:23 UTC (permalink / raw)
To: barebox; +Cc: Jules Maselbas
Set the mci::host_cap MMC_CAP_8_BIT_DATA if supported by the hardware.
Signed-off-by: Jules Maselbas <jmaselbas@kalray.eu>
---
drivers/mci/sdhci.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index 635884e2a2..f6deea4020 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -568,6 +568,9 @@ int sdhci_setup_host(struct sdhci *host)
if (host->caps & SDHCI_CAN_DO_HISPD)
mci->host_caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
+ if (host->caps & SDHCI_CAN_DO_8BIT)
+ mci->host_caps |= MMC_CAP_8_BIT_DATA;
+
host->sdma_boundary = SDHCI_DMA_BOUNDARY_512K;
return 0;
--
2.17.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 2/8] mci: sdhci: Add registers defines
2023-07-10 17:23 [PATCH 1/8] mci: sdhci: Set 8-bit host caps Jules Maselbas
@ 2023-07-10 17:23 ` Jules Maselbas
2023-07-10 17:23 ` [PATCH 3/8] mci: Add dwcmshc-sdhci driver Jules Maselbas
` (5 subsequent siblings)
6 siblings, 0 replies; 13+ messages in thread
From: Jules Maselbas @ 2023-07-10 17:23 UTC (permalink / raw)
To: barebox; +Cc: Jules Maselbas
Signed-off-by: Jules Maselbas <jmaselbas@kalray.eu>
---
drivers/mci/sdhci.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index fe8c25cb9c..50179de0e6 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -117,6 +117,9 @@
#define SDHCI_INT_ERROR_ENABLE 0x36
#define SDHCI_SIGNAL_ENABLE 0x38
#define SDHCI_ACMD12_ERR__HOST_CONTROL2 0x3C
+#define SDHCI_HOST_CONTROL2 0x3E
+#define SDHCI_CTRL_64BIT_ADDR BIT(13)
+#define SDHCI_CTRL_V4_MODE BIT(12)
#define SDHCI_CAPABILITIES 0x40
#define SDHCI_TIMEOUT_CLK_MASK GENMASK(5, 0)
#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080
@@ -173,6 +176,9 @@
#define SDHCI_CLOCK_MUL_SHIFT 16
+#define SDHCI_ADMA_ADDRESS 0x58
+#define SDHCI_ADMA_ADDRESS_HI 0x5c
+
#define SDHCI_MMC_BOOT 0xC4
#define SDHCI_MAX_DIV_SPEC_200 256
--
2.17.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 3/8] mci: Add dwcmshc-sdhci driver
2023-07-10 17:23 [PATCH 1/8] mci: sdhci: Set 8-bit host caps Jules Maselbas
2023-07-10 17:23 ` [PATCH 2/8] mci: sdhci: Add registers defines Jules Maselbas
@ 2023-07-10 17:23 ` Jules Maselbas
2023-07-10 19:47 ` Sam Ravnborg
2023-07-10 17:23 ` [PATCH 4/8] mci: sdhci: Actually return the error code instead of 0 Jules Maselbas
` (4 subsequent siblings)
6 siblings, 1 reply; 13+ messages in thread
From: Jules Maselbas @ 2023-07-10 17:23 UTC (permalink / raw)
To: barebox; +Cc: Jules Maselbas
This driver initially started as a modification of dove-sdhci driver,
it has been heavily reworked to be closer to rockchip-dwcmshc-sdhci by
using more common sdhci code.
Signed-off-by: Jules Maselbas <jmaselbas@kalray.eu>
---
drivers/mci/Kconfig | 8 +
drivers/mci/Makefile | 1 +
drivers/mci/dwcmshc-sdhci.c | 520 ++++++++++++++++++++++++++++++++++++
3 files changed, 529 insertions(+)
create mode 100644 drivers/mci/dwcmshc-sdhci.c
diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig
index bbdca67e9d..1fde0c8ffe 100644
--- a/drivers/mci/Kconfig
+++ b/drivers/mci/Kconfig
@@ -58,6 +58,14 @@ config MCI_MMC_GPP_PARTITIONS
comment "--- MCI host drivers ---"
+config MCI_DWC_MSHC
+ bool "Synopsys DesignWare Cores MSHC"
+ depends on HAS_DMA
+ select MCI_SDHCI
+ help
+ This selects support for the Synopsys DesignWare Mobile Storage Host Controller
+ block (DWC_mshc), this provides host support for SD/eMMC interfaces, in SDMA mode.
+
config MCI_DW
bool "Synopsys DesignWare Memory Card Interface"
depends on HAS_DMA
diff --git a/drivers/mci/Makefile b/drivers/mci/Makefile
index e3dc5ad8ae..35d11fb439 100644
--- a/drivers/mci/Makefile
+++ b/drivers/mci/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_MCI_ROCKCHIP_DWCMSHC) += rockchip-dwcmshc-sdhci.o
obj-$(CONFIG_MCI_TEGRA) += tegra-sdmmc.o
obj-$(CONFIG_MCI_SPI) += mci_spi.o
obj-$(CONFIG_MCI_DW) += dw_mmc.o
+obj-$(CONFIG_MCI_DWC_MSHC) += dwcmshc-sdhci.o
obj-$(CONFIG_MCI_MMCI) += mmci.o
obj-$(CONFIG_MCI_STM32_SDMMC2) += stm32_sdmmc2.o
obj-pbl-$(CONFIG_MCI_SDHCI) += sdhci.o
diff --git a/drivers/mci/dwcmshc-sdhci.c b/drivers/mci/dwcmshc-sdhci.c
new file mode 100644
index 0000000000..1e0af06f50
--- /dev/null
+++ b/drivers/mci/dwcmshc-sdhci.c
@@ -0,0 +1,520 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2019 Yann Sionneau, Kalray Inc.
+// SPDX-FileCopyrightText: 2023 Jules Maselbas, Kalray Inc.
+
+#include <clock.h>
+#include <common.h>
+#include <init.h>
+#include <io.h>
+#include <dma.h>
+#include <malloc.h>
+#include <mci.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include "sdhci.h"
+
+#define CARD_STATUS_MASK (0x1e00)
+#define CARD_STATUS_TRAN (4 << 9)
+static int dwcmshc_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
+ struct mci_data *data);
+
+struct dwcmshc_host {
+ struct mci_host mci;
+ struct sdhci sdhci;
+ unsigned int in_abort_sequence;
+};
+
+#define priv_from_mci_host(h) container_of(h, struct dwcmshc_host, mci)
+
+static inline int dwcmshc_sdma_supported(struct dwcmshc_host *host)
+{
+ return host->sdhci.caps & SDHCI_CAN_DO_SDMA;
+}
+
+static inline void dwcmshc_write_dma_addr(struct dwcmshc_host *host, u64 addr)
+{
+ sdhci_write32(&host->sdhci, SDHCI_ADMA_ADDRESS, addr & 0xffffffff);
+ sdhci_write32(&host->sdhci, SDHCI_ADMA_ADDRESS_HI, addr >> 32);
+}
+
+static inline u64 dwcmshc_read_dma_addr(struct dwcmshc_host *host)
+{
+ u64 addrh, addrl;
+
+ addrl = sdhci_read32(&host->sdhci, SDHCI_ADMA_ADDRESS);
+ addrh = sdhci_read32(&host->sdhci, SDHCI_ADMA_ADDRESS_HI);
+
+ return (addrh << 32) | addrl;
+}
+
+static int dwcmshc_wait_for_done(struct dwcmshc_host *host, u16 mask)
+{
+ u16 status;
+ u64 start;
+ u64 addr;
+
+ start = get_time_ns();
+ while (1) {
+ status = sdhci_read16(&host->sdhci, SDHCI_INT_NORMAL_STATUS);
+ if (status & SDHCI_INT_ERROR) {
+ dev_err(host->mci.hw_dev,
+ "SDHCI_INT_ERROR, normal int status: %04x\n",
+ status);
+ return -EPERM;
+ }
+ /* this special quirk is necessary, as the dma
+ * engine stops on dma boundary and will only
+ * restart after acknowledging it this way.
+ */
+ if (status & SDHCI_INT_DMA) {
+ sdhci_write16(&host->sdhci, SDHCI_INT_NORMAL_STATUS, SDHCI_INT_DMA);
+ addr = dwcmshc_read_dma_addr(host);
+ dwcmshc_write_dma_addr(host, addr);
+ }
+ if (status & mask)
+ break;
+ if (is_timeout(start, 10000 * MSECOND)) {
+ dev_err(host->mci.hw_dev, "SDHCI timeout while waiting for done\n");
+ return -ETIMEDOUT;
+ }
+ }
+ return 0;
+}
+
+static int dwcmshc_wait_for_status_mask(struct dwcmshc_host *host,
+ struct mci_cmd *cmd, u16 mask)
+{
+ int ret;
+
+ ret = dwcmshc_wait_for_done(host, mask);
+ if (ret) {
+ dev_err(host->mci.hw_dev, "error on command %d\n", cmd->cmdidx);
+ dev_err(host->mci.hw_dev, "state = %04x %04x interrupt = %04x %04x\n",
+ sdhci_read16(&host->sdhci, SDHCI_PRESENT_STATE),
+ sdhci_read16(&host->sdhci, SDHCI_PRESENT_STATE1),
+ sdhci_read16(&host->sdhci, SDHCI_INT_NORMAL_STATUS),
+ sdhci_read16(&host->sdhci, SDHCI_INT_ERROR_STATUS));
+ }
+ sdhci_write16(&host->sdhci, SDHCI_INT_NORMAL_STATUS, mask);
+ return ret;
+}
+
+static void sdhci_rx_pio(struct sdhci *sdhci, struct mci_data *data,
+ unsigned int block)
+{
+ u32 *buf = (u32 *)data->dest;
+ int i;
+
+ buf += block * data->blocksize / sizeof(u32);
+
+ for (i = 0; i < data->blocksize / sizeof(u32); i++)
+ buf[i] = sdhci_read32(sdhci, SDHCI_BUFFER);
+}
+
+static void sdhci_tx_pio(struct sdhci *sdhci, struct mci_data *data,
+ unsigned int block)
+{
+ const u32 *buf = (const u32 *)data->src;
+ int i;
+
+ buf += block * data->blocksize / sizeof(u32);
+
+ for (i = 0; i < data->blocksize / sizeof(u32); i++)
+ sdhci_write32(sdhci, SDHCI_BUFFER, buf[i]);
+}
+
+static int dwcmshc_pio_xfer(struct dwcmshc_host *host, struct mci_cmd *cmd,
+ struct mci_data *data)
+{
+ unsigned int i;
+ u16 sts;
+ int ret;
+
+ if (data->flags & MMC_DATA_READ)
+ sts = SDHCI_INT_DATA_AVAIL;
+ else
+ sts = SDHCI_INT_SPACE_AVAIL;
+
+ for (i = 0; i < data->blocks; i++) {
+ ret = dwcmshc_wait_for_status_mask(host, cmd, sts);
+ if (ret)
+ return ret;
+
+ if (data->flags & MMC_DATA_READ)
+ sdhci_rx_pio(&host->sdhci, data, i);
+ else
+ sdhci_tx_pio(&host->sdhci, data, i);
+ }
+
+ return 0;
+}
+
+static void mci_setup_cmd(struct mci_cmd *p, unsigned int cmd, unsigned int arg,
+ unsigned int response)
+{
+ p->cmdidx = cmd;
+ p->cmdarg = arg;
+ p->resp_type = response;
+}
+
+static int do_abort_sequence(struct mci_host *mci, struct mci_cmd *current_cmd)
+{
+ int ret = 0;
+ struct dwcmshc_host *host = priv_from_mci_host(mci);
+ struct mci_cmd cmd;
+ u64 start;
+
+ host->in_abort_sequence = 1;
+
+ mci_setup_cmd(&cmd, MMC_CMD_STOP_TRANSMISSION, 0, MMC_RSP_R1b);
+ ret = dwcmshc_mci_send_cmd(mci, &cmd, NULL);
+ if (ret) {
+ dev_err(host->mci.hw_dev, "Abort failed at first cmd12!\n");
+ goto out;
+ }
+ mci_setup_cmd(&cmd, MMC_CMD_SEND_STATUS, mci->mci->rca << 16,
+ MMC_RSP_R1);
+ ret = dwcmshc_mci_send_cmd(mci, &cmd, NULL);
+ if (ret) {
+ dev_err(host->mci.hw_dev, "Abort failed at first cmd13!\n");
+ goto out;
+ }
+
+ if ((cmd.response[0] & CARD_STATUS_MASK) == CARD_STATUS_TRAN)
+ goto out; /* All is OK! */
+
+ mci_setup_cmd(&cmd, MMC_CMD_STOP_TRANSMISSION, 0, MMC_RSP_R1b);
+ ret = dwcmshc_mci_send_cmd(mci, &cmd, NULL);
+ if (ret) {
+ dev_err(host->mci.hw_dev, "Abort failed at second cmd12!\n");
+ goto out;
+ }
+
+ mci_setup_cmd(&cmd, MMC_CMD_SEND_STATUS, mci->mci->rca << 16,
+ MMC_RSP_R1);
+ ret = dwcmshc_mci_send_cmd(mci, &cmd, NULL);
+ if (ret) {
+ dev_err(host->mci.hw_dev, "Abort failed at second cmd13!\n");
+ goto out;
+ }
+
+ if ((cmd.response[0] & CARD_STATUS_MASK) == CARD_STATUS_TRAN) {
+ goto out; /* All is OK! */
+ } else {
+ dev_err(host->mci.hw_dev,
+ "Abort sequence failed to put card in TRAN state!\n");
+ ret = 1;
+ goto out;
+ }
+
+out:
+ /* Perform SW reset if in abort sequence */
+ sdhci_write8(&host->sdhci, SDHCI_SOFTWARE_RESET,
+ SDHCI_RESET_DATA | SDHCI_RESET_CMD);
+ start = get_time_ns();
+ while (sdhci_read8(&host->sdhci, SDHCI_SOFTWARE_RESET) != 0) {
+ if (is_timeout(start, 50 * MSECOND)) {
+ dev_err(host->mci.hw_dev,
+ "SDHCI data reset timeout\n");
+ break;
+ }
+ }
+ host->in_abort_sequence = 0;
+ return ret;
+}
+
+static int dwcmshc_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
+ struct mci_data *data)
+{
+ struct dwcmshc_host *host = priv_from_mci_host(mci);
+ dma_addr_t dma = SDHCI_NO_DMA;
+ u32 mask, command, xfer;
+ int ret;
+
+ if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION
+ && host->in_abort_sequence == 0)
+ return do_abort_sequence(mci, cmd);
+
+ /* Do not wait for CMD_INHIBIT_DAT on stop commands */
+ mask = SDHCI_CMD_INHIBIT_CMD;
+ if (cmd->cmdidx != MMC_CMD_STOP_TRANSMISSION)
+ mask |= SDHCI_CMD_INHIBIT_DATA;
+
+ /* Wait for bus idle */
+ ret = wait_on_timeout(50 * MSECOND,
+ !(sdhci_read16(&host->sdhci, SDHCI_PRESENT_STATE) & mask));
+ if (ret) {
+ dev_err(host->mci.hw_dev, "SDHCI timeout while waiting for idle\n");
+ return -ETIMEDOUT;
+ }
+
+ if (data)
+ dev_dbg(host->mci.hw_dev, "cmd %d arg %d bcnt %d bsize %d\n",
+ cmd->cmdidx, cmd->cmdarg, data->blocks, data->blocksize);
+ else
+ dev_dbg(host->mci.hw_dev, "cmd %d arg %d\n", cmd->cmdidx, cmd->cmdarg);
+
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0);
+
+ /* setup transfer data */
+ if (data) {
+ unsigned char hostctrl1;
+ hostctrl1 = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL);
+ hostctrl1 &= ~SDHCI_CTRL_DMA_MASK; /* SDMA */
+ sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL, hostctrl1);
+
+ sdhci_setup_data_dma(&host->sdhci, data, &dma);
+
+ if (dwcmshc_sdma_supported(host))
+ dwcmshc_write_dma_addr(host, dma);
+ }
+
+ sdhci_write8(&host->sdhci, SDHCI_TIMEOUT_CONTROL, 0xe);
+
+ sdhci_set_cmd_xfer_mode(&host->sdhci, cmd, data,
+ dma == SDHCI_NO_DMA ? false : true,
+ &command, &xfer);
+
+ sdhci_write16(&host->sdhci, SDHCI_TRANSFER_MODE, xfer);
+
+ sdhci_write32(&host->sdhci, SDHCI_ARGUMENT, cmd->cmdarg);
+ sdhci_write16(&host->sdhci, SDHCI_COMMAND, command);
+
+ ret = dwcmshc_wait_for_status_mask(host, cmd, SDHCI_INT_CMD_COMPLETE);
+ if (ret)
+ goto error;
+
+ sdhci_read_response(&host->sdhci, cmd);
+
+ if (data) {
+ if (dma_mapping_error(mci->hw_dev, dma)) {
+ ret = dwcmshc_pio_xfer(host, cmd, data);
+ if (ret) {
+ dev_err(host->mci.hw_dev, "error during PIO xfer\n");
+ goto error;
+ }
+ }
+ ret = dwcmshc_wait_for_status_mask(host, cmd,
+ SDHCI_INT_XFER_COMPLETE);
+ if (ret)
+ goto error;
+ }
+
+error:
+ if (data && !dma_mapping_error(mci->hw_dev, dma)) {
+ u32 len = data->blocks * data->blocksize;
+ if (data->flags & MMC_DATA_READ)
+ dma_unmap_single(mci->hw_dev, dma, len, DMA_FROM_DEVICE);
+ else
+ dma_unmap_single(mci->hw_dev, dma, len, DMA_TO_DEVICE);
+ }
+
+ if (ret) {
+ sdhci_reset(&host->sdhci, SDHCI_RESET_CMD);
+ sdhci_reset(&host->sdhci, SDHCI_RESET_DATA);
+ }
+
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0);
+ return ret;
+}
+
+static u16 dwcmshc_get_clock_divider(struct dwcmshc_host *host, u32 reqclk)
+{
+ u16 div;
+
+ for (div = 1; div < SDHCI_MAX_DIV_SPEC_300; div += 2)
+ if ((host->sdhci.max_clk / div) <= reqclk)
+ break;
+ div /= 2;
+
+ return div;
+}
+
+static void dwcmshc_mci_set_ios(struct mci_host *mci, struct mci_ios *ios)
+{
+ struct dwcmshc_host *host = priv_from_mci_host(mci);
+ u16 val;
+
+ debug("%s: clock = %u, bus-width = %d, timing = %02x\n", __func__,
+ ios->clock, ios->bus_width, ios->timing);
+
+ /* stop clock */
+ sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, 0);
+
+ if (!ios->clock)
+ return;
+
+ /* enable bus power */
+ val = SDHCI_BUS_VOLTAGE_330;
+ sdhci_write8(&host->sdhci, SDHCI_POWER_CONTROL, val | SDHCI_BUS_POWER_EN);
+ udelay(400);
+
+ /* set bus width */
+ sdhci_set_bus_width(&host->sdhci, ios->bus_width);
+
+ val = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL);
+ if (ios->clock > 26000000)
+ val |= SDHCI_CTRL_HISPD;
+ else
+ val &= ~SDHCI_CTRL_HISPD;
+ sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL, val);
+
+ /* set bus clock */
+ sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, 0);
+ val = dwcmshc_get_clock_divider(host, ios->clock);
+ val = SDHCI_CLOCK_INT_EN | SDHCI_FREQ_SEL(val) | ((val & 0x300) >> 2);
+ sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, val);
+
+ /* wait for internal clock stable */
+ if (wait_on_timeout(20 * MSECOND,
+ sdhci_read16(&host->sdhci, SDHCI_CLOCK_CONTROL)
+ & SDHCI_CLOCK_INT_STABLE)) {
+ dev_err(host->mci.hw_dev, "SDHCI clock stable timeout\n");
+ return;
+ }
+
+ /* enable bus clock */
+ sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, val | SDHCI_CLOCK_CARD_EN);
+}
+
+static int dwcmshc_mci_init(struct mci_host *mci, struct device *dev)
+{
+ struct dwcmshc_host *host = priv_from_mci_host(mci);
+ u16 ctrl2;
+
+ /* reset mshci controller */
+ sdhci_write8(&host->sdhci, SDHCI_SOFTWARE_RESET, SDHCI_RESET_ALL);
+
+ /* wait for reset completion */
+ if (wait_on_timeout(100 * MSECOND,
+ (sdhci_read8(&host->sdhci, SDHCI_SOFTWARE_RESET)
+ & SDHCI_RESET_ALL) == 0)) {
+ dev_err(dev, "SDHCI reset timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ sdhci_write16(&host->sdhci, SDHCI_INT_ERROR_ENABLE, ~0);
+ sdhci_write16(&host->sdhci, SDHCI_INT_ENABLE, ~0);
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0);
+ sdhci_write32(&host->sdhci, SDHCI_SIGNAL_ENABLE, ~0);
+
+ /* Enable host version4 */
+ ctrl2 = sdhci_read16(&host->sdhci, SDHCI_HOST_CONTROL2);
+ ctrl2 |= SDHCI_CTRL_V4_MODE;
+ sdhci_write16(&host->sdhci, SDHCI_HOST_CONTROL2, ctrl2);
+
+ /* Enable 64-bit addressing */
+ ctrl2 = sdhci_read16(&host->sdhci, SDHCI_HOST_CONTROL2);
+ ctrl2 |= SDHCI_CTRL_64BIT_ADDR;
+ sdhci_write16(&host->sdhci, SDHCI_HOST_CONTROL2, ctrl2);
+
+ dev_dbg(host->mci.hw_dev, "host version4: %s\n",
+ ctrl2 & SDHCI_CTRL_V4_MODE ? "enabled" : "disabled");
+
+ return 0;
+}
+
+static int dwcmshc_detect(struct device *dev)
+{
+ struct dwcmshc_host *host = dev->priv;
+
+ return mci_detect_card(&host->mci);
+}
+
+static int dwcmshc_mci_card_present(struct mci_host *mci)
+{
+ struct dwcmshc_host *host = priv_from_mci_host(mci);
+ u32 pstate;
+
+ pstate = sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE);
+ return pstate & SDHCI_CARD_PRESENT;
+}
+
+static void dwcmshc_set_dma_mask(struct device *dev)
+{
+ struct dwcmshc_host *host = dev->priv;
+
+ if (host->sdhci.caps & SDHCI_CAN_64BIT_V4)
+ dma_set_mask(dev, DMA_BIT_MASK(64));
+ else
+ dma_set_mask(dev, DMA_BIT_MASK(32));
+}
+
+static int dwcmshc_probe(struct device *dev)
+{
+ struct dwcmshc_host *host;
+ struct resource *iores;
+ struct mci_host *mci;
+ struct clk *clk;
+ int ret;
+
+ host = xzalloc(sizeof(*host));
+ mci = &host->mci;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores)) {
+ ret = PTR_ERR(iores);
+ goto err_mem_req;
+ }
+
+ clk = clk_get(dev, NULL);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ goto err_clk_get;
+ }
+ clk_enable(clk);
+
+ host->sdhci.base = IOMEM(iores->start);
+ host->sdhci.mci = mci;
+ host->sdhci.max_clk = clk_get_rate(clk);
+
+ mci->hw_dev = dev;
+ mci->init = dwcmshc_mci_init;
+ mci->set_ios = dwcmshc_mci_set_ios;
+ mci->send_cmd = dwcmshc_mci_send_cmd;
+ mci->card_present = dwcmshc_mci_card_present;
+
+ mci_of_parse(&host->mci);
+ sdhci_setup_host(&host->sdhci);
+
+ mci->max_req_size = 0x8000;
+ mci->f_max = clk_get_rate(clk);
+ mci->f_min = mci->f_max / SDHCI_MAX_DIV_SPEC_300;
+
+ dev->priv = host;
+ dev->detect = dwcmshc_detect;
+
+ dwcmshc_set_dma_mask(dev);
+
+ dev_dbg(host->mci.hw_dev, "host controller version: %u\n",
+ host->sdhci.version);
+
+ ret = mci_register(&host->mci);
+ if (ret)
+ goto err_register;
+
+ return ret;
+
+err_register:
+ clk_disable(clk);
+ clk_put(clk);
+err_clk_get:
+ release_region(iores);
+err_mem_req:
+ free(host);
+
+ return ret;
+}
+
+static struct of_device_id dwcmshc_dt_ids[] = {
+ { .compatible = "snps,dwcmshc-sdhci", },
+ { }
+};
+
+static struct driver dwcmshc_driver = {
+ .name = "dwcmshc-sdhci",
+ .probe = dwcmshc_probe,
+ .of_compatible = DRV_OF_COMPAT(dwcmshc_dt_ids),
+};
+device_platform_driver(dwcmshc_driver);
--
2.17.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 4/8] mci: sdhci: Actually return the error code instead of 0
2023-07-10 17:23 [PATCH 1/8] mci: sdhci: Set 8-bit host caps Jules Maselbas
2023-07-10 17:23 ` [PATCH 2/8] mci: sdhci: Add registers defines Jules Maselbas
2023-07-10 17:23 ` [PATCH 3/8] mci: Add dwcmshc-sdhci driver Jules Maselbas
@ 2023-07-10 17:23 ` Jules Maselbas
2023-07-10 17:23 ` [PATCH 5/8] mci: sdhci: Add sd host v4 mode Jules Maselbas
` (3 subsequent siblings)
6 siblings, 0 replies; 13+ messages in thread
From: Jules Maselbas @ 2023-07-10 17:23 UTC (permalink / raw)
To: barebox; +Cc: Jules Maselbas
The sdhci_transfer_data_dma function always returned 0 even in case of
an error, fix this.
Fixes: 60b608b271 ("mci: sdhci: Add DMA transfer helpers")
Signed-off-by: Jules Maselbas <jmaselbas@kalray.eu>
---
drivers/mci/sdhci.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index f6deea4020..a980e34314 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -244,7 +244,7 @@ int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_data *data,
else
dma_unmap_single(dev, dma, nbytes, DMA_TO_DEVICE);
- return 0;
+ return ret;
}
int sdhci_transfer_data_pio(struct sdhci *sdhci, struct mci_data *data)
--
2.17.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 5/8] mci: sdhci: Add sd host v4 mode
2023-07-10 17:23 [PATCH 1/8] mci: sdhci: Set 8-bit host caps Jules Maselbas
` (2 preceding siblings ...)
2023-07-10 17:23 ` [PATCH 4/8] mci: sdhci: Actually return the error code instead of 0 Jules Maselbas
@ 2023-07-10 17:23 ` Jules Maselbas
2023-07-10 17:23 ` [PATCH 6/8] mci: sdhci: Add 64-bit DMA addressing suport for V4 mode Jules Maselbas
` (2 subsequent siblings)
6 siblings, 0 replies; 13+ messages in thread
From: Jules Maselbas @ 2023-07-10 17:23 UTC (permalink / raw)
To: barebox; +Cc: Jules Maselbas
Adapted from Linux commit:
8<----------------------------------------------------------------------
commit b3f80b434f7261c7ef8922f78589942d02e104f9
Author: Chunyan Zhang <zhang.chunyan@linaro.org>
Date: Thu Aug 30 16:21:38 2018 +0800
mmc: sdhci: Add sd host v4 mode
For SD host controller version 4.00 or later ones, there're two
modes of implementation - Version 3.00 compatible mode or
Version 4 mode. This patch introduced an interface to enable
v4 mode.
Signed-off-by: Chunyan Zhang <zhang.chunyan@linaro.org>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
8<----------------------------------------------------------------------
Signed-off-by: Jules Maselbas <jmaselbas@kalray.eu>
---
drivers/mci/sdhci.c | 21 +++++++++++++++++++++
drivers/mci/sdhci.h | 2 ++
2 files changed, 23 insertions(+)
diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index a980e34314..bce4ff2a14 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -480,6 +480,24 @@ void sdhci_set_clock(struct sdhci *host, unsigned int clock, unsigned int input_
sdhci_enable_clk(host, clk);
}
+static void sdhci_do_enable_v4_mode(struct sdhci *host)
+{
+ u16 ctrl2;
+
+ ctrl2 = sdhci_read16(host, SDHCI_HOST_CONTROL2);
+ if (ctrl2 & SDHCI_CTRL_V4_MODE)
+ return;
+
+ ctrl2 |= SDHCI_CTRL_V4_MODE;
+ sdhci_write16(host, SDHCI_HOST_CONTROL2, ctrl2);
+}
+
+void sdhci_enable_v4_mode(struct sdhci *host)
+{
+ host->v4_mode = true;
+ sdhci_do_enable_v4_mode(host);
+}
+
void __sdhci_read_caps(struct sdhci *host, const u16 *ver,
const u32 *caps, const u32 *caps1)
{
@@ -497,6 +515,9 @@ void __sdhci_read_caps(struct sdhci *host, const u16 *ver,
sdhci_reset(host, SDHCI_RESET_ALL);
+ if (host->v4_mode)
+ sdhci_do_enable_v4_mode(host);
+
of_property_read_u64(np, "sdhci-caps-mask", &dt_caps_mask);
of_property_read_u64(np, "sdhci-caps", &dt_caps);
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index 50179de0e6..1f5d0564fc 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -201,6 +201,7 @@ struct sdhci {
enum mci_timing timing;
bool preset_enabled; /* Preset is enabled */
+ bool v4_mode; /* Host Version 4 Enable */
unsigned int quirks;
#define SDHCI_QUIRK_MISSING_CAPS BIT(27)
@@ -279,6 +280,7 @@ u16 sdhci_calc_clk(struct sdhci *host, unsigned int clock,
unsigned int *actual_clock, unsigned int input_clock);
void sdhci_set_clock(struct sdhci *host, unsigned int clock, unsigned int input_clock);
void sdhci_enable_clk(struct sdhci *host, u16 clk);
+void sdhci_enable_v4_mode(struct sdhci *host);
int sdhci_setup_host(struct sdhci *host);
void __sdhci_read_caps(struct sdhci *host, const u16 *ver,
const u32 *caps, const u32 *caps1);
--
2.17.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 6/8] mci: sdhci: Add 64-bit DMA addressing suport for V4 mode
2023-07-10 17:23 [PATCH 1/8] mci: sdhci: Set 8-bit host caps Jules Maselbas
` (3 preceding siblings ...)
2023-07-10 17:23 ` [PATCH 5/8] mci: sdhci: Add sd host v4 mode Jules Maselbas
@ 2023-07-10 17:23 ` Jules Maselbas
2023-07-10 17:23 ` [PATCH 7/8] mci: sdhci: Force DMA update to the next block boundary Jules Maselbas
2023-07-10 17:23 ` [PATCH 8/8] mci: dwcmshc: Use sdhci_enable_v4_mode() Jules Maselbas
6 siblings, 0 replies; 13+ messages in thread
From: Jules Maselbas @ 2023-07-10 17:23 UTC (permalink / raw)
To: barebox; +Cc: Jules Maselbas
Adapted from Linux commit:
8<----------------------------------------------------------------------
commit 685e444bbaa0a5ed959f39dbb2f219eb44c30421
Author: Chunyan Zhang <zhang.chunyan@linaro.org>
Date: Thu Aug 30 16:21:40 2018 +0800
mmc: sdhci: Add ADMA2 64-bit addressing support for V4 mode
ADMA2 64-bit addressing support is divided into V3 mode and V4 mode.
So there are two kinds of descriptors for ADMA2 64-bit addressing
i.e. 96-bit Descriptor for V3 mode, and 128-bit Descriptor for V4
mode. 128-bit Descriptor is aligned to 8-byte.
For V4 mode, ADMA2 64-bit addressing is enabled via Host Control 2
register.
Signed-off-by: Chunyan Zhang <zhang.chunyan@linaro.org>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
[Ulf: Fixed conflict while applying]
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
8<----------------------------------------------------------------------
Signed-off-by: Jules Maselbas <jmaselbas@kalray.eu>
---
drivers/mci/sdhci.c | 64 +++++++++++++++++++++++++++++++++++++++++++--
drivers/mci/sdhci.h | 15 +++++++++++
2 files changed, 77 insertions(+), 2 deletions(-)
diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index bce4ff2a14..4aca3af5aa 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -111,6 +111,35 @@ void sdhci_set_bus_width(struct sdhci *host, int width)
sdhci_write8(host, SDHCI_HOST_CONTROL, ctrl);
}
+static inline bool sdhci_can_64bit_dma(struct sdhci *host)
+{
+ /*
+ * According to SD Host Controller spec v4.10, bit[27] added from
+ * version 4.10 in Capabilities Register is used as 64-bit System
+ * Address support for V4 mode.
+ */
+ if (host->version >= SDHCI_SPEC_410 && host->v4_mode)
+ return host->caps & SDHCI_CAN_64BIT_V4;
+
+ return host->caps & SDHCI_CAN_64BIT;
+}
+
+
+static void sdhci_set_adma_addr(struct sdhci *host, dma_addr_t addr)
+{
+ sdhci_write32(host, SDHCI_ADMA_ADDRESS, lower_32_bits(addr));
+ if (host->flags & SDHCI_USE_64_BIT_DMA)
+ sdhci_write32(host, SDHCI_ADMA_ADDRESS_HI, upper_32_bits(addr));
+}
+
+static void sdhci_set_sdma_addr(struct sdhci *host, dma_addr_t addr)
+{
+ if (host->v4_mode)
+ sdhci_set_adma_addr(host, addr);
+ else
+ sdhci_write32(host, SDHCI_DMA_ADDRESS, addr);
+}
+
#ifdef __PBL__
/*
* Stubs to make timeout logic below work in PBL
@@ -160,6 +189,33 @@ void sdhci_setup_data_pio(struct sdhci *sdhci, struct mci_data *data)
SDHCI_TRANSFER_BLOCK_SIZE(data->blocksize) | data->blocks << 16);
}
+static void sdhci_config_dma(struct sdhci *host)
+{
+ u8 ctrl;
+ u16 ctrl2;
+
+ if (host->version < SDHCI_SPEC_200)
+ return;
+
+ ctrl = sdhci_read8(host, SDHCI_HOST_CONTROL);
+ /* Note if DMA Select is zero then SDMA is selected */
+ ctrl &= ~SDHCI_CTRL_DMA_MASK;
+ sdhci_write8(host, SDHCI_HOST_CONTROL, ctrl);
+
+ if (host->flags & SDHCI_USE_64_BIT_DMA) {
+ /*
+ * If v4 mode, all supported DMA can be 64-bit addressing if
+ * controller supports 64-bit system address, otherwise only
+ * ADMA can support 64-bit addressing.
+ */
+ if (host->v4_mode) {
+ ctrl2 = sdhci_read16(host, SDHCI_HOST_CONTROL2);
+ ctrl2 |= SDHCI_CTRL_64BIT_ADDR;
+ sdhci_write16(host, SDHCI_HOST_CONTROL2, ctrl2);
+ }
+ }
+}
+
void sdhci_setup_data_dma(struct sdhci *sdhci, struct mci_data *data,
dma_addr_t *dma)
{
@@ -188,7 +244,8 @@ void sdhci_setup_data_dma(struct sdhci *sdhci, struct mci_data *data,
return;
}
- sdhci_write32(sdhci, SDHCI_DMA_ADDRESS, *dma);
+ sdhci_config_dma(sdhci);
+ sdhci_set_sdma_addr(sdhci, *dma);
}
int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_data *data,
@@ -230,7 +287,7 @@ int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_data *data,
* the interrupt and kick the DMA engine again.
*/
sdhci_write32(sdhci, SDHCI_INT_STATUS, SDHCI_INT_DMA);
- sdhci_write32(sdhci, SDHCI_DMA_ADDRESS, addr);
+ sdhci_set_sdma_addr(sdhci, dma);
}
if (irqstat & SDHCI_INT_XFER_COMPLETE)
@@ -594,5 +651,8 @@ int sdhci_setup_host(struct sdhci *host)
host->sdma_boundary = SDHCI_DMA_BOUNDARY_512K;
+ if (sdhci_can_64bit_dma(host))
+ host->flags |= SDHCI_USE_64_BIT_DMA;
+
return 0;
}
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index 1f5d0564fc..f3ffd62dff 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -197,6 +197,21 @@ struct sdhci {
int max_clk; /* Max possible freq (Hz) */
int clk_mul; /* Clock Muliplier value */
+ int flags; /* Host attributes */
+#define SDHCI_USE_SDMA (1<<0) /* Host is SDMA capable */
+#define SDHCI_USE_ADMA (1<<1) /* Host is ADMA capable */
+#define SDHCI_REQ_USE_DMA (1<<2) /* Use DMA for this req. */
+#define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */
+#define SDHCI_SDR50_NEEDS_TUNING (1<<4) /* SDR50 needs tuning */
+#define SDHCI_AUTO_CMD12 (1<<6) /* Auto CMD12 support */
+#define SDHCI_AUTO_CMD23 (1<<7) /* Auto CMD23 support */
+#define SDHCI_PV_ENABLED (1<<8) /* Preset value enabled */
+#define SDHCI_USE_64_BIT_DMA (1<<12) /* Use 64-bit DMA */
+#define SDHCI_HS400_TUNING (1<<13) /* Tuning for HS400 */
+#define SDHCI_SIGNALING_330 (1<<14) /* Host is capable of 3.3V signaling */
+#define SDHCI_SIGNALING_180 (1<<15) /* Host is capable of 1.8V signaling */
+#define SDHCI_SIGNALING_120 (1<<16) /* Host is capable of 1.2V signaling */
+
unsigned int version; /* SDHCI spec. version */
enum mci_timing timing;
--
2.17.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 7/8] mci: sdhci: Force DMA update to the next block boundary
2023-07-10 17:23 [PATCH 1/8] mci: sdhci: Set 8-bit host caps Jules Maselbas
` (4 preceding siblings ...)
2023-07-10 17:23 ` [PATCH 6/8] mci: sdhci: Add 64-bit DMA addressing suport for V4 mode Jules Maselbas
@ 2023-07-10 17:23 ` Jules Maselbas
2023-07-11 9:46 ` Jules Maselbas
2023-07-11 13:40 ` [PATCH] fixup! " Jules Maselbas
2023-07-10 17:23 ` [PATCH 8/8] mci: dwcmshc: Use sdhci_enable_v4_mode() Jules Maselbas
6 siblings, 2 replies; 13+ messages in thread
From: Jules Maselbas @ 2023-07-10 17:23 UTC (permalink / raw)
To: barebox; +Cc: Jules Maselbas
When working with 64-bit DMA the DMA addresse is stored in two 32-bit
registers, different from the usual 32-bit one. Copy what is done by
Linux which simple and is also a workaround for some broken controller.
Note: in case the 64-bit DMA address needs to be read, it must be done
by reading the 32-bit LSB first (SDHCI_ADMA_ADDRESS) and then the MSB
(SDHCI_ADMA_ADDRESS_HI).
Adapted from Linux commit:
8<----------------------------------------------------------------------
commit f6a03cbf43e586211f8ea088148c8ecd3fc4b5be
Author: Mikko Vinni <mmvinni@yahoo.com>
Date: Tue Apr 12 09:36:18 2011 -0400
mmc: sdhci: work around broken dma boundary behavior
Some SD host controllers (noticed on an integrated JMicron SD reader on an
HP Pavilion dv5-1250eo laptop) don't update the dma address register before
signaling a dma interrupt due to a dma boundary. Update the register
manually to the next boundary (by default 512KiB), at which the transfer
stopped.
As long as each transfer is at most 512KiB in size (guaranteed by a BUG_ON
in sdhci_prepare_data()) and the boundary is kept at the default value,
this fix is needed at most once per transfer. Smaller boundaries are taken
care of by counting the transferred bytes.
Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=28462
Signed-off-by: Mikko Vinni <mmvinni@yahoo.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
8<----------------------------------------------------------------------
Signed-off-by: Jules Maselbas <jmaselbas@kalray.eu>
---
drivers/mci/sdhci.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index 4aca3af5aa..4c8e73d94d 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -279,8 +279,18 @@ int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_data *data,
goto out;
}
+ /*
+ * We currently don't do anything fancy with DMA
+ * boundaries, but as we can't disable the feature
+ * we need to at least restart the transfer.
+ *
+ * According to the spec sdhci_readl(host, SDHCI_DMA_ADDRESS)
+ * should return a valid address to continue from, but as
+ * some controllers are faulty, don't trust them.
+ */
if (irqstat & SDHCI_INT_DMA) {
- u32 addr = sdhci_read32(sdhci, SDHCI_DMA_ADDRESS);
+ /* Force update to the next DMA block boundary. */
+ dma += sdhci->sdma_boundary;
/*
* DMA engine has stopped on buffer boundary. Acknowledge
--
2.17.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 8/8] mci: dwcmshc: Use sdhci_enable_v4_mode()
2023-07-10 17:23 [PATCH 1/8] mci: sdhci: Set 8-bit host caps Jules Maselbas
` (5 preceding siblings ...)
2023-07-10 17:23 ` [PATCH 7/8] mci: sdhci: Force DMA update to the next block boundary Jules Maselbas
@ 2023-07-10 17:23 ` Jules Maselbas
6 siblings, 0 replies; 13+ messages in thread
From: Jules Maselbas @ 2023-07-10 17:23 UTC (permalink / raw)
To: barebox; +Cc: Jules Maselbas
Enable the use of the common sdhci code path by using sdhci_enable_v4_mode().
This removes a bunch of functions that configured v4_mode and 64-bit dma in
the dwcmshc driver, which is now handled by common sdhci code.
Signed-off-by: Jules Maselbas <jmaselbas@kalray.eu>
---
drivers/mci/dwcmshc-sdhci.c | 174 ++----------------------------------
1 file changed, 7 insertions(+), 167 deletions(-)
diff --git a/drivers/mci/dwcmshc-sdhci.c b/drivers/mci/dwcmshc-sdhci.c
index 1e0af06f50..a95e3bd1e9 100644
--- a/drivers/mci/dwcmshc-sdhci.c
+++ b/drivers/mci/dwcmshc-sdhci.c
@@ -27,129 +27,6 @@ struct dwcmshc_host {
#define priv_from_mci_host(h) container_of(h, struct dwcmshc_host, mci)
-static inline int dwcmshc_sdma_supported(struct dwcmshc_host *host)
-{
- return host->sdhci.caps & SDHCI_CAN_DO_SDMA;
-}
-
-static inline void dwcmshc_write_dma_addr(struct dwcmshc_host *host, u64 addr)
-{
- sdhci_write32(&host->sdhci, SDHCI_ADMA_ADDRESS, addr & 0xffffffff);
- sdhci_write32(&host->sdhci, SDHCI_ADMA_ADDRESS_HI, addr >> 32);
-}
-
-static inline u64 dwcmshc_read_dma_addr(struct dwcmshc_host *host)
-{
- u64 addrh, addrl;
-
- addrl = sdhci_read32(&host->sdhci, SDHCI_ADMA_ADDRESS);
- addrh = sdhci_read32(&host->sdhci, SDHCI_ADMA_ADDRESS_HI);
-
- return (addrh << 32) | addrl;
-}
-
-static int dwcmshc_wait_for_done(struct dwcmshc_host *host, u16 mask)
-{
- u16 status;
- u64 start;
- u64 addr;
-
- start = get_time_ns();
- while (1) {
- status = sdhci_read16(&host->sdhci, SDHCI_INT_NORMAL_STATUS);
- if (status & SDHCI_INT_ERROR) {
- dev_err(host->mci.hw_dev,
- "SDHCI_INT_ERROR, normal int status: %04x\n",
- status);
- return -EPERM;
- }
- /* this special quirk is necessary, as the dma
- * engine stops on dma boundary and will only
- * restart after acknowledging it this way.
- */
- if (status & SDHCI_INT_DMA) {
- sdhci_write16(&host->sdhci, SDHCI_INT_NORMAL_STATUS, SDHCI_INT_DMA);
- addr = dwcmshc_read_dma_addr(host);
- dwcmshc_write_dma_addr(host, addr);
- }
- if (status & mask)
- break;
- if (is_timeout(start, 10000 * MSECOND)) {
- dev_err(host->mci.hw_dev, "SDHCI timeout while waiting for done\n");
- return -ETIMEDOUT;
- }
- }
- return 0;
-}
-
-static int dwcmshc_wait_for_status_mask(struct dwcmshc_host *host,
- struct mci_cmd *cmd, u16 mask)
-{
- int ret;
-
- ret = dwcmshc_wait_for_done(host, mask);
- if (ret) {
- dev_err(host->mci.hw_dev, "error on command %d\n", cmd->cmdidx);
- dev_err(host->mci.hw_dev, "state = %04x %04x interrupt = %04x %04x\n",
- sdhci_read16(&host->sdhci, SDHCI_PRESENT_STATE),
- sdhci_read16(&host->sdhci, SDHCI_PRESENT_STATE1),
- sdhci_read16(&host->sdhci, SDHCI_INT_NORMAL_STATUS),
- sdhci_read16(&host->sdhci, SDHCI_INT_ERROR_STATUS));
- }
- sdhci_write16(&host->sdhci, SDHCI_INT_NORMAL_STATUS, mask);
- return ret;
-}
-
-static void sdhci_rx_pio(struct sdhci *sdhci, struct mci_data *data,
- unsigned int block)
-{
- u32 *buf = (u32 *)data->dest;
- int i;
-
- buf += block * data->blocksize / sizeof(u32);
-
- for (i = 0; i < data->blocksize / sizeof(u32); i++)
- buf[i] = sdhci_read32(sdhci, SDHCI_BUFFER);
-}
-
-static void sdhci_tx_pio(struct sdhci *sdhci, struct mci_data *data,
- unsigned int block)
-{
- const u32 *buf = (const u32 *)data->src;
- int i;
-
- buf += block * data->blocksize / sizeof(u32);
-
- for (i = 0; i < data->blocksize / sizeof(u32); i++)
- sdhci_write32(sdhci, SDHCI_BUFFER, buf[i]);
-}
-
-static int dwcmshc_pio_xfer(struct dwcmshc_host *host, struct mci_cmd *cmd,
- struct mci_data *data)
-{
- unsigned int i;
- u16 sts;
- int ret;
-
- if (data->flags & MMC_DATA_READ)
- sts = SDHCI_INT_DATA_AVAIL;
- else
- sts = SDHCI_INT_SPACE_AVAIL;
-
- for (i = 0; i < data->blocks; i++) {
- ret = dwcmshc_wait_for_status_mask(host, cmd, sts);
- if (ret)
- return ret;
-
- if (data->flags & MMC_DATA_READ)
- sdhci_rx_pio(&host->sdhci, data, i);
- else
- sdhci_tx_pio(&host->sdhci, data, i);
- }
-
- return 0;
-}
-
static void mci_setup_cmd(struct mci_cmd *p, unsigned int cmd, unsigned int arg,
unsigned int response)
{
@@ -257,18 +134,7 @@ static int dwcmshc_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0);
- /* setup transfer data */
- if (data) {
- unsigned char hostctrl1;
- hostctrl1 = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL);
- hostctrl1 &= ~SDHCI_CTRL_DMA_MASK; /* SDMA */
- sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL, hostctrl1);
-
- sdhci_setup_data_dma(&host->sdhci, data, &dma);
-
- if (dwcmshc_sdma_supported(host))
- dwcmshc_write_dma_addr(host, dma);
- }
+ sdhci_setup_data_dma(&host->sdhci, data, &dma);
sdhci_write8(&host->sdhci, SDHCI_TIMEOUT_CONTROL, 0xe);
@@ -281,35 +147,14 @@ static int dwcmshc_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
sdhci_write32(&host->sdhci, SDHCI_ARGUMENT, cmd->cmdarg);
sdhci_write16(&host->sdhci, SDHCI_COMMAND, command);
- ret = dwcmshc_wait_for_status_mask(host, cmd, SDHCI_INT_CMD_COMPLETE);
+ ret = sdhci_wait_for_done(&host->sdhci, SDHCI_INT_CMD_COMPLETE);
if (ret)
goto error;
sdhci_read_response(&host->sdhci, cmd);
- if (data) {
- if (dma_mapping_error(mci->hw_dev, dma)) {
- ret = dwcmshc_pio_xfer(host, cmd, data);
- if (ret) {
- dev_err(host->mci.hw_dev, "error during PIO xfer\n");
- goto error;
- }
- }
- ret = dwcmshc_wait_for_status_mask(host, cmd,
- SDHCI_INT_XFER_COMPLETE);
- if (ret)
- goto error;
- }
-
+ ret = sdhci_transfer_data(&host->sdhci, data, dma);
error:
- if (data && !dma_mapping_error(mci->hw_dev, dma)) {
- u32 len = data->blocks * data->blocksize;
- if (data->flags & MMC_DATA_READ)
- dma_unmap_single(mci->hw_dev, dma, len, DMA_FROM_DEVICE);
- else
- dma_unmap_single(mci->hw_dev, dma, len, DMA_TO_DEVICE);
- }
-
if (ret) {
sdhci_reset(&host->sdhci, SDHCI_RESET_CMD);
sdhci_reset(&host->sdhci, SDHCI_RESET_DATA);
@@ -399,15 +244,7 @@ static int dwcmshc_mci_init(struct mci_host *mci, struct device *dev)
sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0);
sdhci_write32(&host->sdhci, SDHCI_SIGNAL_ENABLE, ~0);
- /* Enable host version4 */
- ctrl2 = sdhci_read16(&host->sdhci, SDHCI_HOST_CONTROL2);
- ctrl2 |= SDHCI_CTRL_V4_MODE;
- sdhci_write16(&host->sdhci, SDHCI_HOST_CONTROL2, ctrl2);
-
- /* Enable 64-bit addressing */
- ctrl2 = sdhci_read16(&host->sdhci, SDHCI_HOST_CONTROL2);
- ctrl2 |= SDHCI_CTRL_64BIT_ADDR;
- sdhci_write16(&host->sdhci, SDHCI_HOST_CONTROL2, ctrl2);
+ sdhci_enable_v4_mode(&host->sdhci);
dev_dbg(host->mci.hw_dev, "host version4: %s\n",
ctrl2 & SDHCI_CTRL_V4_MODE ? "enabled" : "disabled");
@@ -476,6 +313,9 @@ static int dwcmshc_probe(struct device *dev)
mci->card_present = dwcmshc_mci_card_present;
mci_of_parse(&host->mci);
+
+ /* Enable host_version4 */
+ sdhci_enable_v4_mode(&host->sdhci);
sdhci_setup_host(&host->sdhci);
mci->max_req_size = 0x8000;
--
2.17.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 3/8] mci: Add dwcmshc-sdhci driver
2023-07-10 17:23 ` [PATCH 3/8] mci: Add dwcmshc-sdhci driver Jules Maselbas
@ 2023-07-10 19:47 ` Sam Ravnborg
2023-07-11 8:12 ` Jules Maselbas
0 siblings, 1 reply; 13+ messages in thread
From: Sam Ravnborg @ 2023-07-10 19:47 UTC (permalink / raw)
To: Jules Maselbas; +Cc: barebox
Hi Jules.
On Mon, Jul 10, 2023 at 07:23:30PM +0200, Jules Maselbas wrote:
> This driver initially started as a modification of dove-sdhci driver,
> it has been heavily reworked to be closer to rockchip-dwcmshc-sdhci by
> using more common sdhci code.
>
> Signed-off-by: Jules Maselbas <jmaselbas@kalray.eu>
> ---
> drivers/mci/Kconfig | 8 +
> drivers/mci/Makefile | 1 +
> drivers/mci/dwcmshc-sdhci.c | 520 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 529 insertions(+)
> create mode 100644 drivers/mci/dwcmshc-sdhci.c
Unless there are good reasons that I miss you could squash this with
patch 8. It looks funny that you add a driver and then delete a lot of
code because you updated some infrastructure later.
This is to have a clean git history, which one could always ague about.
Sam
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 3/8] mci: Add dwcmshc-sdhci driver
2023-07-10 19:47 ` Sam Ravnborg
@ 2023-07-11 8:12 ` Jules Maselbas
2023-07-26 13:11 ` Sascha Hauer
0 siblings, 1 reply; 13+ messages in thread
From: Jules Maselbas @ 2023-07-11 8:12 UTC (permalink / raw)
To: Sam Ravnborg; +Cc: barebox
Hi Sam,
On Mon, Jul 10, 2023 at 09:47:03PM +0200, Sam Ravnborg wrote:
> Unless there are good reasons that I miss you could squash this with
> patch 8. It looks funny that you add a driver and then delete a lot of
> code because you updated some infrastructure later.
The reason for this is to be able to revert generic sdhci changes, in case
it breaks other drivers, without completly reverting the dwcmshc driver.
I have only tested the generic changes on the newly added driver.
Cheers
-- Jules
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 7/8] mci: sdhci: Force DMA update to the next block boundary
2023-07-10 17:23 ` [PATCH 7/8] mci: sdhci: Force DMA update to the next block boundary Jules Maselbas
@ 2023-07-11 9:46 ` Jules Maselbas
2023-07-11 13:40 ` [PATCH] fixup! " Jules Maselbas
1 sibling, 0 replies; 13+ messages in thread
From: Jules Maselbas @ 2023-07-11 9:46 UTC (permalink / raw)
To: barebox
On Mon, Jul 10, 2023 at 07:23:34PM +0200, Jules Maselbas wrote:
> When working with 64-bit DMA the DMA addresse is stored in two 32-bit
> registers, different from the usual 32-bit one. Copy what is done by
> Linux which simple and is also a workaround for some broken controller.
>
> Note: in case the 64-bit DMA address needs to be read, it must be done
> by reading the 32-bit LSB first (SDHCI_ADMA_ADDRESS) and then the MSB
> (SDHCI_ADMA_ADDRESS_HI).
>
> Adapted from Linux commit:
> 8<----------------------------------------------------------------------
> commit f6a03cbf43e586211f8ea088148c8ecd3fc4b5be
> Author: Mikko Vinni <mmvinni@yahoo.com>
> Date: Tue Apr 12 09:36:18 2011 -0400
>
> mmc: sdhci: work around broken dma boundary behavior
>
> Some SD host controllers (noticed on an integrated JMicron SD reader on an
> HP Pavilion dv5-1250eo laptop) don't update the dma address register before
> signaling a dma interrupt due to a dma boundary. Update the register
> manually to the next boundary (by default 512KiB), at which the transfer
> stopped.
>
> As long as each transfer is at most 512KiB in size (guaranteed by a BUG_ON
> in sdhci_prepare_data()) and the boundary is kept at the default value,
> this fix is needed at most once per transfer. Smaller boundaries are taken
> care of by counting the transferred bytes.
>
> Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=28462
>
> Signed-off-by: Mikko Vinni <mmvinni@yahoo.com>
> Signed-off-by: Chris Ball <cjb@laptop.org>
> 8<----------------------------------------------------------------------
>
> Signed-off-by: Jules Maselbas <jmaselbas@kalray.eu>
> ---
> drivers/mci/sdhci.c | 12 +++++++++++-
> 1 file changed, 11 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
> index 4aca3af5aa..4c8e73d94d 100644
> --- a/drivers/mci/sdhci.c
> +++ b/drivers/mci/sdhci.c
> @@ -279,8 +279,18 @@ int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_data *data,
> goto out;
> }
>
> + /*
> + * We currently don't do anything fancy with DMA
> + * boundaries, but as we can't disable the feature
> + * we need to at least restart the transfer.
> + *
> + * According to the spec sdhci_readl(host, SDHCI_DMA_ADDRESS)
> + * should return a valid address to continue from, but as
> + * some controllers are faulty, don't trust them.
> + */
> if (irqstat & SDHCI_INT_DMA) {
> - u32 addr = sdhci_read32(sdhci, SDHCI_DMA_ADDRESS);
> + /* Force update to the next DMA block boundary. */
> + dma += sdhci->sdma_boundary;
I've modified this to increase the dma addresse instead of aligning the addresse
to the next boundary...
I don't know why this works in my case, but by reading the SDHCI spec this should
really be aligned on a boundary, maybe the behavior is different when v4_mode is
enabled.
>
> /*
> * DMA engine has stopped on buffer boundary. Acknowledge
> --
> 2.17.1
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH] fixup! mci: sdhci: Force DMA update to the next block boundary
2023-07-10 17:23 ` [PATCH 7/8] mci: sdhci: Force DMA update to the next block boundary Jules Maselbas
2023-07-11 9:46 ` Jules Maselbas
@ 2023-07-11 13:40 ` Jules Maselbas
1 sibling, 0 replies; 13+ messages in thread
From: Jules Maselbas @ 2023-07-11 13:40 UTC (permalink / raw)
To: barebox; +Cc: Jules Maselbas
straight copy from Linux didn't worked because the macro SDHCI_DMA_BOUNDARY_512K
(default value of sdhci::sdma_boundary) is not a size but the enum value to be
written in the transfer control register.
Signed-off-by: Jules Maselbas <jmaselbas@kalray.eu>
---
drivers/mci/sdhci.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index 4c8e73d94d..b0b83bfaa9 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -289,8 +289,10 @@ int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_data *data,
* some controllers are faulty, don't trust them.
*/
if (irqstat & SDHCI_INT_DMA) {
+ int boundary_cfg = (sdhci->sdma_boundary >> 12) & 0x7;
+ dma_addr_t boundary_size = 4096 << boundary_cfg;
/* Force update to the next DMA block boundary. */
- dma += sdhci->sdma_boundary;
+ dma = (dma & ~(boundary_size - 1)) + boundary_size;
/*
* DMA engine has stopped on buffer boundary. Acknowledge
--
2.17.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 3/8] mci: Add dwcmshc-sdhci driver
2023-07-11 8:12 ` Jules Maselbas
@ 2023-07-26 13:11 ` Sascha Hauer
0 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2023-07-26 13:11 UTC (permalink / raw)
To: Jules Maselbas; +Cc: Sam Ravnborg, barebox
On Tue, Jul 11, 2023 at 10:12:39AM +0200, Jules Maselbas wrote:
> Hi Sam,
>
> On Mon, Jul 10, 2023 at 09:47:03PM +0200, Sam Ravnborg wrote:
> > Unless there are good reasons that I miss you could squash this with
> > patch 8. It looks funny that you add a driver and then delete a lot of
> > code because you updated some infrastructure later.
>
> The reason for this is to be able to revert generic sdhci changes, in case
> it breaks other drivers, without completly reverting the dwcmshc driver.
> I have only tested the generic changes on the newly added driver.
Please resend the series with first the generic sdhci changes and then
your driver using it. Should we have to revert the generic sdhci changes
then we can still extract the necessary changes to your driver from the
v1 series.
As a reviewer I don't want to review code that is deleted later in the
series.
Sascha
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2023-07-26 13:12 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-10 17:23 [PATCH 1/8] mci: sdhci: Set 8-bit host caps Jules Maselbas
2023-07-10 17:23 ` [PATCH 2/8] mci: sdhci: Add registers defines Jules Maselbas
2023-07-10 17:23 ` [PATCH 3/8] mci: Add dwcmshc-sdhci driver Jules Maselbas
2023-07-10 19:47 ` Sam Ravnborg
2023-07-11 8:12 ` Jules Maselbas
2023-07-26 13:11 ` Sascha Hauer
2023-07-10 17:23 ` [PATCH 4/8] mci: sdhci: Actually return the error code instead of 0 Jules Maselbas
2023-07-10 17:23 ` [PATCH 5/8] mci: sdhci: Add sd host v4 mode Jules Maselbas
2023-07-10 17:23 ` [PATCH 6/8] mci: sdhci: Add 64-bit DMA addressing suport for V4 mode Jules Maselbas
2023-07-10 17:23 ` [PATCH 7/8] mci: sdhci: Force DMA update to the next block boundary Jules Maselbas
2023-07-11 9:46 ` Jules Maselbas
2023-07-11 13:40 ` [PATCH] fixup! " Jules Maselbas
2023-07-10 17:23 ` [PATCH 8/8] mci: dwcmshc: Use sdhci_enable_v4_mode() Jules Maselbas
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox