From: Andrey Smirnov <andrew.smirnov@gmail.com>
To: barebox@lists.infradead.org
Cc: Andrey Smirnov <andrew.smirnov@gmail.com>
Subject: [PATCH 07/12] mci: imx-esdhc-pbl: Share IO accessors with regular driver
Date: Mon, 2 Dec 2019 07:19:49 -0800 [thread overview]
Message-ID: <20191202151954.16032-8-andrew.smirnov@gmail.com> (raw)
In-Reply-To: <20191202151954.16032-1-andrew.smirnov@gmail.com>
With a bit of a change to PBL ESDHC initialization code it is possible
to share all of the low-level I/O accessor code with the regular
driver, including sharing definitions of flags describing HW's quirks.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/mci/Makefile | 4 +-
drivers/mci/imx-esdhc-common.c | 47 ++++++++++
drivers/mci/imx-esdhc-pbl.c | 151 +++++++++++++++------------------
drivers/mci/imx-esdhc.c | 126 +--------------------------
drivers/mci/imx-esdhc.h | 98 +++++++++++++++++++++
5 files changed, 218 insertions(+), 208 deletions(-)
create mode 100644 drivers/mci/imx-esdhc-common.c
diff --git a/drivers/mci/Makefile b/drivers/mci/Makefile
index e2e3ba7ef..cfb84a899 100644
--- a/drivers/mci/Makefile
+++ b/drivers/mci/Makefile
@@ -5,8 +5,8 @@ obj-$(CONFIG_MCI_BCM283X) += mci-bcm2835.o
obj-$(CONFIG_MCI_BCM283X_SDHOST) += bcm2835-sdhost.o
obj-$(CONFIG_MCI_DOVE) += dove-sdhci.o
obj-$(CONFIG_MCI_IMX) += imx.o
-obj-$(CONFIG_MCI_IMX_ESDHC) += imx-esdhc.o
-pbl-$(CONFIG_MCI_IMX_ESDHC_PBL) += imx-esdhc-pbl.o
+obj-$(CONFIG_MCI_IMX_ESDHC) += imx-esdhc.o imx-esdhc-common.o
+pbl-$(CONFIG_MCI_IMX_ESDHC_PBL) += imx-esdhc-pbl.o imx-esdhc-common.o
obj-$(CONFIG_MCI_MXS) += mxs.o
obj-$(CONFIG_MCI_OMAP_HSMMC) += omap_hsmmc.o
obj-$(CONFIG_MCI_PXA) += pxamci.o
diff --git a/drivers/mci/imx-esdhc-common.c b/drivers/mci/imx-esdhc-common.c
new file mode 100644
index 000000000..bcdf661ed
--- /dev/null
+++ b/drivers/mci/imx-esdhc-common.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <common.h>
+#include <io.h>
+#include <mci.h>
+
+#include "sdhci.h"
+#include "imx-esdhc.h"
+
+static u32 esdhc_op_read32_le(struct sdhci *sdhci, int reg)
+{
+ struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
+
+ return readl(host->regs + reg);
+}
+
+static u32 esdhc_op_read32_be(struct sdhci *sdhci, int reg)
+{
+ struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
+
+ return in_be32(host->regs + reg);
+}
+
+static void esdhc_op_write32_le(struct sdhci *sdhci, int reg, u32 val)
+{
+ struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
+
+ writel(val, host->regs + reg);
+}
+
+static void esdhc_op_write32_be(struct sdhci *sdhci, int reg, u32 val)
+{
+ struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
+
+ out_be32(host->regs + reg, val);
+}
+
+void esdhc_populate_sdhci(struct fsl_esdhc_host *host)
+{
+ if (host->socdata->flags & ESDHC_FLAG_BIGENDIAN) {
+ host->sdhci.read32 = esdhc_op_read32_be;
+ host->sdhci.write32 = esdhc_op_write32_be;
+ } else {
+ host->sdhci.read32 = esdhc_op_read32_le;
+ host->sdhci.write32 = esdhc_op_write32_le;
+ }
+}
diff --git a/drivers/mci/imx-esdhc-pbl.c b/drivers/mci/imx-esdhc-pbl.c
index e81f0f107..08f28471c 100644
--- a/drivers/mci/imx-esdhc-pbl.c
+++ b/drivers/mci/imx-esdhc-pbl.c
@@ -30,28 +30,6 @@
#define SECTOR_SIZE 512
#define SECTOR_WML (SECTOR_SIZE / sizeof(u32))
-struct esdhc {
- void __iomem *regs;
- bool is_mx6;
- bool is_be;
-};
-
-static uint32_t esdhc_read32(struct esdhc *esdhc, int reg)
-{
- if (esdhc->is_be)
- return in_be32(esdhc->regs + reg);
- else
- return readl(esdhc->regs + reg);
-}
-
-static void esdhc_write32(struct esdhc *esdhc, int reg, uint32_t val)
-{
- if (esdhc->is_be)
- out_be32(esdhc->regs + reg, val);
- else
- writel(val, esdhc->regs + reg);
-}
-
static void __udelay(int us)
{
volatile int i;
@@ -86,7 +64,7 @@ static u32 esdhc_xfertyp(struct mci_cmd *cmd, struct mci_data *data)
return command << 16 | xfertyp;
}
-static int esdhc_do_data(struct esdhc *esdhc, struct mci_data *data)
+static int esdhc_do_data(struct fsl_esdhc_host *host, struct mci_data *data)
{
char *buffer;
u32 databuf;
@@ -97,14 +75,14 @@ static int esdhc_do_data(struct esdhc *esdhc, struct mci_data *data)
buffer = data->dest;
size = data->blocksize * data->blocks;
- irqstat = esdhc_read32(esdhc, SDHCI_INT_STATUS);
+ irqstat = sdhci_read32(&host->sdhci, SDHCI_INT_STATUS);
while (size) {
int i;
int timeout = 1000000;
while (1) {
- present = esdhc_read32(esdhc, SDHCI_PRESENT_STATE) & SDHCI_BUFFER_READ_ENABLE;
+ present = sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & SDHCI_BUFFER_READ_ENABLE;
if (present)
break;
if (!--timeout) {
@@ -114,7 +92,7 @@ static int esdhc_do_data(struct esdhc *esdhc, struct mci_data *data)
}
for (i = 0; i < SECTOR_WML; i++) {
- databuf = esdhc_read32(esdhc, SDHCI_BUFFER);
+ databuf = sdhci_read32(&host->sdhci, SDHCI_BUFFER);
*((u32 *)buffer) = databuf;
buffer += 4;
size -= 4;
@@ -125,49 +103,49 @@ static int esdhc_do_data(struct esdhc *esdhc, struct mci_data *data)
}
static int
-esdhc_send_cmd(struct esdhc *esdhc, struct mci_cmd *cmd, struct mci_data *data)
+esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd, struct mci_data *data)
{
u32 xfertyp, mixctrl;
u32 irqstat;
int ret;
int timeout;
- esdhc_write32(esdhc, SDHCI_INT_STATUS, -1);
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, -1);
/* Wait at least 8 SD clock cycles before the next command */
__udelay(1);
if (data) {
/* Set up for a data transfer if we have one */
- esdhc_write32(esdhc, SDHCI_BLOCK_SIZE__BLOCK_COUNT, data->blocks << 16 | SECTOR_SIZE);
+ sdhci_write32(&host->sdhci, SDHCI_BLOCK_SIZE__BLOCK_COUNT, data->blocks << 16 | SECTOR_SIZE);
}
/* Figure out the transfer arguments */
xfertyp = esdhc_xfertyp(cmd, data);
/* Send the command */
- esdhc_write32(esdhc, SDHCI_ARGUMENT, cmd->cmdarg);
+ sdhci_write32(&host->sdhci, SDHCI_ARGUMENT, cmd->cmdarg);
- if (esdhc->is_mx6) {
+ if (esdhc_is_usdhc(host)) {
/* write lower-half of xfertyp to mixctrl */
mixctrl = xfertyp & 0xFFFF;
/* Keep the bits 22-25 of the register as is */
- mixctrl |= (esdhc_read32(esdhc, IMX_SDHCI_MIXCTRL) & (0xF << 22));
- esdhc_write32(esdhc, IMX_SDHCI_MIXCTRL, mixctrl);
+ mixctrl |= (sdhci_read32(&host->sdhci, IMX_SDHCI_MIXCTRL) & (0xF << 22));
+ sdhci_write32(&host->sdhci, IMX_SDHCI_MIXCTRL, mixctrl);
}
- esdhc_write32(esdhc, SDHCI_TRANSFER_MODE__COMMAND, xfertyp);
+ sdhci_write32(&host->sdhci, SDHCI_TRANSFER_MODE__COMMAND, xfertyp);
/* Wait for the command to complete */
timeout = 10000;
- while (!(esdhc_read32(esdhc, SDHCI_INT_STATUS) & SDHCI_INT_CMD_COMPLETE)) {
+ while (!(sdhci_read32(&host->sdhci, SDHCI_INT_STATUS) & SDHCI_INT_CMD_COMPLETE)) {
__udelay(1);
if (!timeout--)
return -ETIMEDOUT;
}
- irqstat = esdhc_read32(esdhc, SDHCI_INT_STATUS);
- esdhc_write32(esdhc, SDHCI_INT_STATUS, irqstat);
+ irqstat = sdhci_read32(&host->sdhci, SDHCI_INT_STATUS);
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, irqstat);
if (irqstat & CMD_ERR)
return -EIO;
@@ -176,20 +154,20 @@ esdhc_send_cmd(struct esdhc *esdhc, struct mci_cmd *cmd, struct mci_data *data)
return -ETIMEDOUT;
/* Copy the response to the response buffer */
- cmd->response[0] = esdhc_read32(esdhc, SDHCI_RESPONSE_0);
+ cmd->response[0] = sdhci_read32(&host->sdhci, SDHCI_RESPONSE_0);
/* Wait until all of the blocks are transferred */
if (data) {
- ret = esdhc_do_data(esdhc, data);
+ ret = esdhc_do_data(host, data);
if (ret)
return ret;
}
- esdhc_write32(esdhc, SDHCI_INT_STATUS, -1);
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, -1);
/* Wait for the bus to be idle */
timeout = 10000;
- while (esdhc_read32(esdhc, SDHCI_PRESENT_STATE) & (SDHCI_CMD_INHIBIT_CMD |
+ while (sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & (SDHCI_CMD_INHIBIT_CMD |
SDHCI_CMD_INHIBIT_DATA | SDHCI_DATA_LINE_ACTIVE)) {
__udelay(1);
if (!timeout--)
@@ -199,22 +177,22 @@ esdhc_send_cmd(struct esdhc *esdhc, struct mci_cmd *cmd, struct mci_data *data)
return 0;
}
-static int esdhc_read_blocks(struct esdhc *esdhc, void *dst, size_t len)
+static int esdhc_read_blocks(struct fsl_esdhc_host *host, void *dst, size_t len)
{
struct mci_cmd cmd;
struct mci_data data;
u32 val;
int ret;
- esdhc_write32(esdhc, SDHCI_INT_ENABLE,
+ sdhci_write32(&host->sdhci, SDHCI_INT_ENABLE,
SDHCI_INT_CMD_COMPLETE | SDHCI_INT_XFER_COMPLETE |
SDHCI_INT_CARD_INT | SDHCI_INT_TIMEOUT | SDHCI_INT_CRC |
SDHCI_INT_END_BIT | SDHCI_INT_INDEX | SDHCI_INT_DATA_TIMEOUT |
SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT | SDHCI_INT_DMA);
- val = esdhc_read32(esdhc, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET);
+ val = sdhci_read32(&host->sdhci, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET);
val |= SYSCTL_HCKEN | SYSCTL_IPGEN;
- esdhc_write32(esdhc, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, val);
+ sdhci_write32(&host->sdhci, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, val);
cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
cmd.cmdarg = 0;
@@ -225,7 +203,7 @@ static int esdhc_read_blocks(struct esdhc *esdhc, void *dst, size_t len)
data.blocksize = SECTOR_SIZE;
data.flags = MMC_DATA_READ;
- ret = esdhc_send_cmd(esdhc, &cmd, &data);
+ ret = esdhc_send_cmd(host, &cmd, &data);
if (ret) {
pr_debug("send command failed with %d\n", ret);
return ret;
@@ -235,13 +213,13 @@ static int esdhc_read_blocks(struct esdhc *esdhc, void *dst, size_t len)
cmd.cmdarg = 0;
cmd.resp_type = MMC_RSP_R1b;
- esdhc_send_cmd(esdhc, &cmd, NULL);
+ esdhc_send_cmd(host, &cmd, NULL);
return 0;
}
#ifdef CONFIG_ARCH_IMX
-static int esdhc_search_header(struct esdhc *esdhc,
+static int esdhc_search_header(struct fsl_esdhc_host *host,
struct imx_flash_header_v2 **header_pointer,
void *buffer, u32 *offset)
{
@@ -251,7 +229,7 @@ static int esdhc_search_header(struct esdhc *esdhc,
struct imx_flash_header_v2 *hdr;
for (i = 0; i < header_count; i++) {
- ret = esdhc_read_blocks(esdhc, buf,
+ ret = esdhc_read_blocks(host, buf,
*offset + SZ_1K + SECTOR_SIZE);
if (ret)
return ret;
@@ -288,7 +266,7 @@ static int esdhc_search_header(struct esdhc *esdhc,
}
static int
-esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, ptrdiff_t entry,
+esdhc_start_image(struct fsl_esdhc_host *host, ptrdiff_t address, ptrdiff_t entry,
u32 offset)
{
@@ -301,7 +279,7 @@ esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, ptrdiff_t entry,
len = imx_image_size();
len = ALIGN(len, SECTOR_SIZE);
- ret = esdhc_search_header(esdhc, &hdr, buf, &offset);
+ ret = esdhc_search_header(host, &hdr, buf, &offset);
if (ret)
return ret;
@@ -336,7 +314,7 @@ esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, ptrdiff_t entry,
buf = (void *)(entry - ofs);
}
- ret = esdhc_read_blocks(esdhc, buf, offset + len);
+ ret = esdhc_read_blocks(host, buf, offset + len);
if (ret) {
pr_err("Loading image failed with %d\n", ret);
return ret;
@@ -351,32 +329,36 @@ esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, ptrdiff_t entry,
bb();
}
-static void imx_esdhc_init(struct esdhc *esdhc)
+static void imx_esdhc_init(struct fsl_esdhc_host *host,
+ struct esdhc_soc_data *data)
{
- esdhc->is_be = 0;
- esdhc->is_mx6 = 1;
+ data->flags = ESDHC_FLAG_USDHC;
+ host->socdata = data;
+ esdhc_populate_sdhci(host);
- esdhc_write32(esdhc, IMX_SDHCI_WML,
+ sdhci_write32(&host->sdhci, IMX_SDHCI_WML,
FIELD_PREP(WML_WR_BRST_LEN, 16) |
FIELD_PREP(WML_WR_WML_MASK, SECTOR_WML) |
FIELD_PREP(WML_RD_BRST_LEN, 16) |
FIELD_PREP(WML_RD_WML_MASK, SECTOR_WML));
}
-static int imx8_esdhc_init(struct esdhc *esdhc, int instance)
+static int imx8_esdhc_init(struct fsl_esdhc_host *host,
+ struct esdhc_soc_data *data,
+ int instance)
{
switch (instance) {
case 0:
- esdhc->regs = IOMEM(MX8MQ_USDHC1_BASE_ADDR);
+ host->regs = IOMEM(MX8MQ_USDHC1_BASE_ADDR);
break;
case 1:
- esdhc->regs = IOMEM(MX8MQ_USDHC2_BASE_ADDR);
+ host->regs = IOMEM(MX8MQ_USDHC2_BASE_ADDR);
break;
default:
return -EINVAL;
}
- imx_esdhc_init(esdhc);
+ imx_esdhc_init(host, data);
return 0;
}
@@ -395,28 +377,29 @@ static int imx8_esdhc_init(struct esdhc *esdhc, int instance)
*/
int imx6_esdhc_start_image(int instance)
{
- struct esdhc esdhc;
+ struct esdhc_soc_data data;
+ struct fsl_esdhc_host host;
switch (instance) {
case 0:
- esdhc.regs = IOMEM(MX6_USDHC1_BASE_ADDR);
+ host.regs = IOMEM(MX6_USDHC1_BASE_ADDR);
break;
case 1:
- esdhc.regs = IOMEM(MX6_USDHC2_BASE_ADDR);
+ host.regs = IOMEM(MX6_USDHC2_BASE_ADDR);
break;
case 2:
- esdhc.regs = IOMEM(MX6_USDHC3_BASE_ADDR);
+ host.regs = IOMEM(MX6_USDHC3_BASE_ADDR);
break;
case 3:
- esdhc.regs = IOMEM(MX6_USDHC4_BASE_ADDR);
+ host.regs = IOMEM(MX6_USDHC4_BASE_ADDR);
break;
default:
return -EINVAL;
}
- imx_esdhc_init(&esdhc);
+ imx_esdhc_init(&host, &data);
- return esdhc_start_image(&esdhc, 0x10000000, 0x10000000, 0);
+ return esdhc_start_image(&host, 0x10000000, 0x10000000, 0);
}
/**
@@ -433,14 +416,15 @@ int imx6_esdhc_start_image(int instance)
*/
int imx8_esdhc_start_image(int instance)
{
- struct esdhc esdhc;
+ struct esdhc_soc_data data;
+ struct fsl_esdhc_host host;
int ret;
- ret = imx8_esdhc_init(&esdhc, instance);
+ ret = imx8_esdhc_init(&host, &data, instance);
if (ret)
return ret;
- return esdhc_start_image(&esdhc, MX8MQ_DDR_CSD1_BASE_ADDR,
+ return esdhc_start_image(&host, MX8MQ_DDR_CSD1_BASE_ADDR,
MX8MQ_ATF_BL33_BASE_ADDR, SZ_32K);
}
@@ -448,11 +432,12 @@ int imx8_esdhc_load_piggy(int instance)
{
void *buf, *piggy;
struct imx_flash_header_v2 *hdr = NULL;
- struct esdhc esdhc;
+ struct esdhc_soc_data data;
+ struct fsl_esdhc_host host;
int ret, len;
int offset = SZ_32K;
- ret = imx8_esdhc_init(&esdhc, instance);
+ ret = imx8_esdhc_init(&host, &data, instance);
if (ret)
return ret;
@@ -463,14 +448,14 @@ int imx8_esdhc_load_piggy(int instance)
*/
buf = (void *)MX8MQ_ATF_BL33_BASE_ADDR + SZ_32M;
- ret = esdhc_search_header(&esdhc, &hdr, buf, &offset);
+ ret = esdhc_search_header(&host, &hdr, buf, &offset);
if (ret)
return ret;
len = offset + hdr->boot_data.size + piggydata_size();
len = ALIGN(len, SECTOR_SIZE);
- ret = esdhc_read_blocks(&esdhc, buf, len);
+ ret = esdhc_read_blocks(&host, buf, len);
/*
* Calculate location of the piggydata at the offset loaded into RAM
@@ -508,29 +493,33 @@ int ls1046a_esdhc_start_image(unsigned long r0, unsigned long r1, unsigned long
{
int ret;
uint32_t val;
- struct esdhc esdhc = {
+ struct esdhc_soc_data data = {
+ .flags = ESDHC_FLAG_BIGENDIAN,
+ };
+ struct fsl_esdhc_host host = {
.regs = IOMEM(0x01560000),
- .is_be = true,
+ .socdata = &data,
};
unsigned long sdram = 0x80000000;
void (*barebox)(unsigned long, unsigned long, unsigned long) =
(void *)(sdram + LS1046A_SD_IMAGE_OFFSET);
- esdhc_write32(&esdhc, IMX_SDHCI_WML, 0);
+ esdhc_populate_sdhci(&host);
+ sdhci_write32(&host.sdhci, IMX_SDHCI_WML, 0);
/*
* The ROM leaves us here with a clock frequency of around 400kHz. Speed
* this up a bit. FIXME: The resulting frequency has not yet been verified
* to work on all cards.
*/
- val = esdhc_read32(&esdhc, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET);
+ val = sdhci_read32(&host.sdhci, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET);
val &= ~0x0000fff0;
val |= (8 << 8) | (3 << 4);
- esdhc_write32(&esdhc, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, val);
+ sdhci_write32(&host.sdhci, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, val);
- esdhc_write32(&esdhc, ESDHC_DMA_SYSCTL, ESDHC_SYSCTL_DMA_SNOOP);
+ sdhci_write32(&host.sdhci, ESDHC_DMA_SYSCTL, ESDHC_SYSCTL_DMA_SNOOP);
- ret = esdhc_read_blocks(&esdhc, (void *)sdram,
+ ret = esdhc_read_blocks(&host, (void *)sdram,
ALIGN(barebox_image_size + LS1046A_SD_IMAGE_OFFSET, 512));
if (ret) {
pr_err("%s: reading blocks failed with: %d\n", __func__, ret);
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index b6dd75d2c..9dbf5bccc 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -39,131 +39,13 @@
#include "sdhci.h"
#include "imx-esdhc.h"
-/*
- * The CMDTYPE of the CMD register (offset 0xE) should be set to
- * "11" when the STOP CMD12 is issued on imx53 to abort one
- * open ended multi-blk IO. Otherwise the TC INT wouldn't
- * be generated.
- * In exact block transfer, the controller doesn't complete the
- * operations automatically as required at the end of the
- * transfer and remains on hold if the abort command is not sent.
- * As a result, the TC flag is not asserted and SW received timeout
- * exeception. Bit1 of Vendor Spec registor is used to fix it.
- */
-#define ESDHC_FLAG_MULTIBLK_NO_INT BIT(1)
-/*
- * The flag enables the workaround for ESDHC errata ENGcm07207 which
- * affects i.MX25 and i.MX35.
- */
-#define ESDHC_FLAG_ENGCM07207 BIT(2)
-/*
- * The flag tells that the ESDHC controller is an USDHC block that is
- * integrated on the i.MX6 series.
- */
-#define ESDHC_FLAG_USDHC BIT(3)
-/* The IP supports manual tuning process */
-#define ESDHC_FLAG_MAN_TUNING BIT(4)
-/* The IP supports standard tuning process */
-#define ESDHC_FLAG_STD_TUNING BIT(5)
-/* The IP has SDHCI_CAPABILITIES_1 register */
-#define ESDHC_FLAG_HAVE_CAP1 BIT(6)
-
-/*
- * The IP has errata ERR004536
- * uSDHC: ADMA Length Mismatch Error occurs if the AHB read access is slow,
- * when reading data from the card
- */
-#define ESDHC_FLAG_ERR004536 BIT(7)
-/* The IP supports HS200 mode */
-#define ESDHC_FLAG_HS200 BIT(8)
-/* The IP supports HS400 mode */
-#define ESDHC_FLAG_HS400 BIT(9)
-
-/* Need to access registers in bigendian mode */
-#define ESDHC_FLAG_BIGENDIAN BIT(10)
-/* Enable cache snooping */
-#define ESDHC_FLAG_CACHE_SNOOPING BIT(11)
#define PRSSTAT_DAT0 0x01000000
#define PRSSTAT_SDSTB 0x00000008
-struct esdhc_soc_data {
- u32 flags;
- const char *clkidx;
-};
-
-struct fsl_esdhc_host {
- struct mci_host mci;
- void __iomem *regs;
- struct device_d *dev;
- struct clk *clk;
- const struct esdhc_soc_data *socdata;
- struct sdhci sdhci;
-};
#define to_fsl_esdhc(mci) container_of(mci, struct fsl_esdhc_host, mci)
-static inline int esdhc_is_usdhc(struct fsl_esdhc_host *data)
-{
- return !!(data->socdata->flags & ESDHC_FLAG_USDHC);
-}
-
-static inline struct fsl_esdhc_host *sdhci_to_esdhc(struct sdhci *sdhci)
-{
- return container_of(sdhci, struct fsl_esdhc_host, sdhci);
-}
-
-static u32 esdhc_op_read32_le(struct sdhci *sdhci, int reg)
-{
- struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
-
- return readl(host->regs + reg);
-}
-
-static u32 esdhc_op_read32_be(struct sdhci *sdhci, int reg)
-{
- struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
-
- return in_be32(host->regs + reg);
-}
-
-static void esdhc_op_write32_le(struct sdhci *sdhci, int reg, u32 val)
-{
- struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
-
- writel(val, host->regs + reg);
-}
-
-static void esdhc_op_write32_be(struct sdhci *sdhci, int reg, u32 val)
-{
- struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
-
- out_be32(host->regs + reg, val);
-}
-
-static inline void esdhc_clrsetbits32(struct fsl_esdhc_host *host, unsigned int reg,
- u32 clear, u32 set)
-{
- u32 val;
-
- val = sdhci_read32(&host->sdhci, reg);
- val &= ~clear;
- val |= set;
- sdhci_write32(&host->sdhci, reg, val);
-}
-
-static inline void esdhc_clrbits32(struct fsl_esdhc_host *host, unsigned int reg,
- u32 clear)
-{
- esdhc_clrsetbits32(host, reg, clear, 0);
-}
-
-static inline void esdhc_setbits32(struct fsl_esdhc_host *host, unsigned int reg,
- u32 set)
-{
- esdhc_clrsetbits32(host, reg, 0, set);
-}
-
static int esdhc_setup_data(struct fsl_esdhc_host *host, struct mci_data *data,
dma_addr_t dma)
{
@@ -578,13 +460,7 @@ static int fsl_esdhc_probe(struct device_d *dev)
}
host->regs = IOMEM(iores->start);
- if (host->socdata->flags & ESDHC_FLAG_BIGENDIAN) {
- host->sdhci.read32 = esdhc_op_read32_be;
- host->sdhci.write32 = esdhc_op_write32_be;
- } else {
- host->sdhci.read32 = esdhc_op_read32_le;
- host->sdhci.write32 = esdhc_op_write32_le;
- }
+ esdhc_populate_sdhci(host);
caps = sdhci_read32(&host->sdhci, SDHCI_CAPABILITIES);
diff --git a/drivers/mci/imx-esdhc.h b/drivers/mci/imx-esdhc.h
index ad05c4c0b..e5647187b 100644
--- a/drivers/mci/imx-esdhc.h
+++ b/drivers/mci/imx-esdhc.h
@@ -69,4 +69,102 @@
#define ESDHC_DMA_SYSCTL 0x40c /* Layerscape specific */
#define ESDHC_SYSCTL_DMA_SNOOP BIT(6)
+
+/*
+ * The CMDTYPE of the CMD register (offset 0xE) should be set to
+ * "11" when the STOP CMD12 is issued on imx53 to abort one
+ * open ended multi-blk IO. Otherwise the TC INT wouldn't
+ * be generated.
+ * In exact block transfer, the controller doesn't complete the
+ * operations automatically as required at the end of the
+ * transfer and remains on hold if the abort command is not sent.
+ * As a result, the TC flag is not asserted and SW received timeout
+ * exeception. Bit1 of Vendor Spec registor is used to fix it.
+ */
+#define ESDHC_FLAG_MULTIBLK_NO_INT BIT(1)
+/*
+ * The flag enables the workaround for ESDHC errata ENGcm07207 which
+ * affects i.MX25 and i.MX35.
+ */
+#define ESDHC_FLAG_ENGCM07207 BIT(2)
+/*
+ * The flag tells that the ESDHC controller is an USDHC block that is
+ * integrated on the i.MX6 series.
+ */
+#define ESDHC_FLAG_USDHC BIT(3)
+/* The IP supports manual tuning process */
+#define ESDHC_FLAG_MAN_TUNING BIT(4)
+/* The IP supports standard tuning process */
+#define ESDHC_FLAG_STD_TUNING BIT(5)
+/* The IP has SDHCI_CAPABILITIES_1 register */
+#define ESDHC_FLAG_HAVE_CAP1 BIT(6)
+
+/*
+ * The IP has errata ERR004536
+ * uSDHC: ADMA Length Mismatch Error occurs if the AHB read access is slow,
+ * when reading data from the card
+ */
+#define ESDHC_FLAG_ERR004536 BIT(7)
+/* The IP supports HS200 mode */
+#define ESDHC_FLAG_HS200 BIT(8)
+/* The IP supports HS400 mode */
+#define ESDHC_FLAG_HS400 BIT(9)
+/* Need to access registers in bigendian mode */
+#define ESDHC_FLAG_BIGENDIAN BIT(10)
+/* Enable cache snooping */
+#define ESDHC_FLAG_CACHE_SNOOPING BIT(11)
+
+struct esdhc_soc_data {
+ u32 flags;
+ const char *clkidx;
+};
+
+struct fsl_esdhc_host {
+ struct mci_host mci;
+ struct clk *clk;
+ struct device_d *dev;
+ void __iomem *regs;
+ const struct esdhc_soc_data *socdata;
+ struct sdhci sdhci;
+};
+
+
+static inline int esdhc_is_usdhc(struct fsl_esdhc_host *data)
+{
+ return !!(data->socdata->flags & ESDHC_FLAG_USDHC);
+}
+
+static inline struct fsl_esdhc_host *sdhci_to_esdhc(struct sdhci *sdhci)
+{
+ return container_of(sdhci, struct fsl_esdhc_host, sdhci);
+}
+
+static inline void
+esdhc_clrsetbits32(struct fsl_esdhc_host *host, unsigned int reg,
+ u32 clear, u32 set)
+{
+ u32 val;
+
+ val = sdhci_read32(&host->sdhci, reg);
+ val &= ~clear;
+ val |= set;
+ sdhci_write32(&host->sdhci, reg, val);
+}
+
+static inline void
+esdhc_clrbits32(struct fsl_esdhc_host *host, unsigned int reg,
+ u32 clear)
+{
+ esdhc_clrsetbits32(host, reg, clear, 0);
+}
+
+static inline void
+esdhc_setbits32(struct fsl_esdhc_host *host, unsigned int reg,
+ u32 set)
+{
+ esdhc_clrsetbits32(host, reg, 0, set);
+}
+
+void esdhc_populate_sdhci(struct fsl_esdhc_host *host);
+
#endif /* __FSL_ESDHC_H__ */
--
2.21.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
next prev parent reply other threads:[~2019-12-02 15:20 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-12-02 15:19 [PATCH 00/12] Share i.MX ESDHC PBL and PIO code Andrey Smirnov
2019-12-02 15:19 ` [PATCH 01/12] mci: imx-esdhc: Drop unnecessary type conversion Andrey Smirnov
2019-12-02 15:19 ` [PATCH 02/12] mci: imx-esdhc: Drop unused type definition Andrey Smirnov
2019-12-02 15:19 ` [PATCH 03/12] mci: imx-esdhc: Drop extra helper varaible Andrey Smirnov
2019-12-02 15:19 ` [PATCH 04/12] mci: imx-esdhc-pbl: Don't setup DMA registers Andrey Smirnov
2019-12-02 15:19 ` [PATCH 05/12] mci: imx-esdhc-pbl: Share initialization code Andrey Smirnov
2019-12-02 15:19 ` [PATCH 06/12] mci: imx-esdhc-pbl: Drop 'wrap_wml' flag Andrey Smirnov
2019-12-02 15:19 ` Andrey Smirnov [this message]
2019-12-02 15:19 ` [PATCH 08/12] mci: imx-esdhc-pbl: Use sdhci_transfer_data() Andrey Smirnov
2019-12-02 15:19 ` [PATCH 09/12] mci: imx-esdhc-pbl: Use sdhci_set_cmd_xfer_mode() Andrey Smirnov
2019-12-02 15:19 ` [PATCH 10/12] mci: imx-esdhc: Share code for esdhc_(setup|do)_data operations Andrey Smirnov
2019-12-02 15:19 ` [PATCH 11/12] mci: imx-esdhc: Introduce esdhc_poll() Andrey Smirnov
2019-12-02 15:19 ` [PATCH 12/12] mci: imx-esdhc: Share code for esdhc_send_cmd() Andrey Smirnov
2019-12-04 8:42 ` [PATCH 00/12] Share i.MX ESDHC PBL and PIO code Sascha Hauer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20191202151954.16032-8-andrew.smirnov@gmail.com \
--to=andrew.smirnov@gmail.com \
--cc=barebox@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox