Commit acdc8e71 authored by Neil Armstrong's avatar Neil Armstrong Committed by Ulf Hansson

mmc: meson-gx: add dram-access-quirk

On the Amlogic G12A SoC family, (only) the SDIO controller fails to access
the data from DRAM, leading to a broken controller.

But each MMC controller has 1,5KiB of SRAM after the registers, that can
be used as bounce buffer to avoid direct DRAM access from the integrated
DMAs (this SRAM may be used by the boot ROM when DRAM is not yet initialized).

The quirk is to disable the chained descriptor for this controller, and
use this SRAM memory zone as buffer for the bounce buffer fallback mode.

The performance hit hasn't been evaluated, but the fix has been tested
using a WiFi AP6398S SDIO module, and the iperf3 Bandwidth measurement gave
55.2 Mbits/sec over a 63 Hours long test, with the SDIO ios set as High-Speed
at 50MHz clock. It gave 170 Mbits/sec as SDR104 and 200MHz clock.
Reviewed-by: default avatarKevin Hilman <khilman@baylibre.com>
Tested-by: default avatarGuillaume La Roque <glaroque@baylibre.com>
Signed-off-by: default avatarNeil Armstrong <narmstrong@baylibre.com>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent 5a46b6fa
......@@ -116,6 +116,9 @@
#define SD_EMMC_TXD 0x94
#define SD_EMMC_LAST_REG SD_EMMC_TXD
#define SD_EMMC_SRAM_DATA_BUF_LEN 1536
#define SD_EMMC_SRAM_DATA_BUF_OFF 0x200
#define SD_EMMC_CFG_BLK_SIZE 512 /* internal buffer max: 512 bytes */
#define SD_EMMC_CFG_RESP_TIMEOUT 256 /* in clock cycles */
#define SD_EMMC_CMD_TIMEOUT 1024 /* in ms */
......@@ -155,6 +158,8 @@ struct meson_host {
unsigned long req_rate;
bool ddr;
bool dram_access_quirk;
struct pinctrl *pinctrl;
struct pinctrl_state *pins_default;
struct pinctrl_state *pins_clk_gate;
......@@ -219,11 +224,20 @@ static struct mmc_command *meson_mmc_get_next_command(struct mmc_command *cmd)
static void meson_mmc_get_transfer_mode(struct mmc_host *mmc,
struct mmc_request *mrq)
{
struct meson_host *host = mmc_priv(mmc);
struct mmc_data *data = mrq->data;
struct scatterlist *sg;
int i;
bool use_desc_chain_mode = true;
/*
* When Controller DMA cannot directly access DDR memory, disable
* support for Chain Mode to directly use the internal SRAM using
* the bounce buffer mode.
*/
if (host->dram_access_quirk)
return;
/*
* Broken SDIO with AP6255-based WiFi on Khadas VIM Pro has been
* reported. For some strange reason this occurs in descriptor
......@@ -1036,6 +1050,10 @@ static int meson_mmc_probe(struct platform_device *pdev)
host->dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, host);
/* The G12A SDIO Controller needs an SRAM bounce buffer */
host->dram_access_quirk = device_property_read_bool(&pdev->dev,
"amlogic,dram-access-quirk");
/* Get regulators and the supported OCR mask */
host->vqmmc_enabled = false;
ret = mmc_regulator_get_supply(mmc);
......@@ -1133,9 +1151,16 @@ static int meson_mmc_probe(struct platform_device *pdev)
goto err_init_clk;
mmc->caps |= MMC_CAP_CMD23;
if (host->dram_access_quirk) {
/* Limit to the available sram memory */
mmc->max_segs = SD_EMMC_SRAM_DATA_BUF_LEN / mmc->max_blk_size;
mmc->max_blk_count = mmc->max_segs;
} else {
mmc->max_blk_count = CMD_CFG_LENGTH_MASK;
mmc->max_segs = SD_EMMC_DESC_BUF_LEN /
sizeof(struct sd_emmc_desc);
}
mmc->max_req_size = mmc->max_blk_count * mmc->max_blk_size;
mmc->max_segs = SD_EMMC_DESC_BUF_LEN / sizeof(struct sd_emmc_desc);
mmc->max_seg_size = mmc->max_req_size;
/*
......@@ -1145,6 +1170,17 @@ static int meson_mmc_probe(struct platform_device *pdev)
*/
mmc->caps2 &= ~MMC_CAP2_HS400;
if (host->dram_access_quirk) {
/*
* The MMC Controller embeds 1,5KiB of internal SRAM
* that can be used to be used as bounce buffer.
* In the case of the G12A SDIO controller, use these
* instead of the DDR memory
*/
host->bounce_buf_size = SD_EMMC_SRAM_DATA_BUF_LEN;
host->bounce_buf = host->regs + SD_EMMC_SRAM_DATA_BUF_OFF;
host->bounce_dma_addr = res->start + SD_EMMC_SRAM_DATA_BUF_OFF;
} else {
/* data bounce buffer */
host->bounce_buf_size = mmc->max_req_size;
host->bounce_buf =
......@@ -1155,6 +1191,7 @@ static int meson_mmc_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto err_free_irq;
}
}
host->descs = dma_alloc_coherent(host->dev, SD_EMMC_DESC_BUF_LEN,
&host->descs_dma_addr, GFP_KERNEL);
......@@ -1170,6 +1207,7 @@ static int meson_mmc_probe(struct platform_device *pdev)
return 0;
err_bounce_buf:
if (!host->dram_access_quirk)
dma_free_coherent(host->dev, host->bounce_buf_size,
host->bounce_buf, host->bounce_dma_addr);
err_free_irq:
......@@ -1195,6 +1233,8 @@ static int meson_mmc_remove(struct platform_device *pdev)
dma_free_coherent(host->dev, SD_EMMC_DESC_BUF_LEN,
host->descs, host->descs_dma_addr);
if (!host->dram_access_quirk)
dma_free_coherent(host->dev, host->bounce_buf_size,
host->bounce_buf, host->bounce_dma_addr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment