Browse Source

drivers: synopsys: Fix synopsys MMC driver

There are some issues with synopsys MMC driver:
- CMD8 should not expect data (for SD)
- ACMD51 should expect data (Send SCR for SD)
- dw_prepare should not dictate size to be MMC_BLOCK_SIZE, block size is
now handled in the dw_prepare function
- after the CMD completes, when doing dw_read, we need to invalidate cache
and wait for the data transfer to complete
- Need to set FIFO threshold, otherwise DMA might never get the interrupt
to read or write

Signed-off-by: Tien Hock, Loh <tien.hock.loh@intel.com>
pull/1858/head
Tien Hock, Loh 6 years ago
parent
commit
3d0f30bb54
  1. 29
      drivers/synopsys/emmc/dw_mmc.c
  2. 1
      include/drivers/synopsys/dw_mmc.h

29
drivers/synopsys/emmc/dw_mmc.c

@ -243,6 +243,11 @@ static int dw_send_cmd(struct mmc_cmd *cmd)
op = CMD_WAIT_PRVDATA_COMPLETE; op = CMD_WAIT_PRVDATA_COMPLETE;
break; break;
case 8: case 8:
if (dw_params.mmc_dev_type == MMC_IS_EMMC)
op = CMD_DATA_TRANS_EXPECT | CMD_WAIT_PRVDATA_COMPLETE;
else
op = CMD_WAIT_PRVDATA_COMPLETE;
break;
case 17: case 17:
case 18: case 18:
op = CMD_DATA_TRANS_EXPECT | CMD_WAIT_PRVDATA_COMPLETE; op = CMD_DATA_TRANS_EXPECT | CMD_WAIT_PRVDATA_COMPLETE;
@ -252,6 +257,9 @@ static int dw_send_cmd(struct mmc_cmd *cmd)
op = CMD_WRITE | CMD_DATA_TRANS_EXPECT | op = CMD_WRITE | CMD_DATA_TRANS_EXPECT |
CMD_WAIT_PRVDATA_COMPLETE; CMD_WAIT_PRVDATA_COMPLETE;
break; break;
case 51:
op = CMD_DATA_TRANS_EXPECT;
break;
default: default:
op = 0; op = 0;
break; break;
@ -337,7 +345,6 @@ static int dw_prepare(int lba, uintptr_t buf, size_t size)
uintptr_t base; uintptr_t base;
assert(((buf & DWMMC_ADDRESS_MASK) == 0) && assert(((buf & DWMMC_ADDRESS_MASK) == 0) &&
((size % MMC_BLOCK_SIZE) == 0) &&
(dw_params.desc_size > 0) && (dw_params.desc_size > 0) &&
((dw_params.reg_base & MMC_BLOCK_MASK) == 0) && ((dw_params.reg_base & MMC_BLOCK_MASK) == 0) &&
((dw_params.desc_base & MMC_BLOCK_MASK) == 0) && ((dw_params.desc_base & MMC_BLOCK_MASK) == 0) &&
@ -352,6 +359,12 @@ static int dw_prepare(int lba, uintptr_t buf, size_t size)
base = dw_params.reg_base; base = dw_params.reg_base;
desc = (struct dw_idmac_desc *)dw_params.desc_base; desc = (struct dw_idmac_desc *)dw_params.desc_base;
mmio_write_32(base + DWMMC_BYTCNT, size); mmio_write_32(base + DWMMC_BYTCNT, size);
if (size < MMC_BLOCK_SIZE)
mmio_write_32(base + DWMMC_BLKSIZ, size);
else
mmio_write_32(base + DWMMC_BLKSIZ, MMC_BLOCK_SIZE);
mmio_write_32(base + DWMMC_RINTSTS, ~0); mmio_write_32(base + DWMMC_RINTSTS, ~0);
for (i = 0; i < desc_cnt; i++) { for (i = 0; i < desc_cnt; i++) {
desc[i].des0 = IDMAC_DES0_OWN | IDMAC_DES0_CH | IDMAC_DES0_DIC; desc[i].des0 = IDMAC_DES0_OWN | IDMAC_DES0_CH | IDMAC_DES0_DIC;
@ -375,11 +388,22 @@ static int dw_prepare(int lba, uintptr_t buf, size_t size)
flush_dcache_range(dw_params.desc_base, flush_dcache_range(dw_params.desc_base,
desc_cnt * DWMMC_DMA_MAX_BUFFER_SIZE); desc_cnt * DWMMC_DMA_MAX_BUFFER_SIZE);
return 0; return 0;
} }
static int dw_read(int lba, uintptr_t buf, size_t size) static int dw_read(int lba, uintptr_t buf, size_t size)
{ {
uint32_t data = 0;
int timeout = TIMEOUT;
do {
data = mmio_read_32(dw_params.reg_base + DWMMC_RINTSTS);
udelay(50);
} while (!(data & INT_DTO) && timeout-- > 0);
inv_dcache_range(buf, size);
return 0; return 0;
} }
@ -401,6 +425,9 @@ void dw_mmc_init(dw_mmc_params_t *params, struct mmc_device_info *info)
(params->bus_width == MMC_BUS_WIDTH_8))); (params->bus_width == MMC_BUS_WIDTH_8)));
memcpy(&dw_params, params, sizeof(dw_mmc_params_t)); memcpy(&dw_params, params, sizeof(dw_mmc_params_t));
mmio_write_32(dw_params.reg_base + DWMMC_FIFOTH, 0x103ff);
mmc_init(&dw_mmc_ops, params->clk_rate, params->bus_width, mmc_init(&dw_mmc_ops, params->clk_rate, params->bus_width,
params->flags, info); params->flags, info);
dw_params.mmc_dev_type = info->mmc_dev_type;
} }

1
include/drivers/synopsys/dw_mmc.h

@ -16,6 +16,7 @@ typedef struct dw_mmc_params {
int clk_rate; int clk_rate;
int bus_width; int bus_width;
unsigned int flags; unsigned int flags;
enum mmc_device_type mmc_dev_type;
} dw_mmc_params_t; } dw_mmc_params_t;
void dw_mmc_init(dw_mmc_params_t *params, struct mmc_device_info *info); void dw_mmc_init(dw_mmc_params_t *params, struct mmc_device_info *info);

Loading…
Cancel
Save