mmc: sdhci: Add 64-bit ADMA support
Add 64-bit ADMA support including: - add 64-bit ADMA descriptor - add SDHCI_USE_64_BIT_DMA flag - set upper 32-bits of DMA addresses - ability to select 64-bit ADMA - ability to use 64-bit ADMA sizes and alignment - display "ADMA 64-bit" when host is added It is assumed that a 64-bit capable device has set a 64-bit DMA mask and *must* do 64-bit DMA. A driver has the opportunity to change that during the first call to ->enable_dma(). Similarly SDHCI_QUIRK2_BROKEN_64_BIT_DMA must be left to the drivers to implement. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
This commit is contained in:
Родитель
0545230f17
Коммит
e57a5f61ea
|
@ -117,10 +117,17 @@ static void sdhci_dumpregs(struct sdhci_host *host)
|
|||
pr_debug(DRIVER_NAME ": Host ctl2: 0x%08x\n",
|
||||
sdhci_readw(host, SDHCI_HOST_CONTROL2));
|
||||
|
||||
if (host->flags & SDHCI_USE_ADMA)
|
||||
pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
|
||||
readl(host->ioaddr + SDHCI_ADMA_ERROR),
|
||||
readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
|
||||
if (host->flags & SDHCI_USE_ADMA) {
|
||||
if (host->flags & SDHCI_USE_64_BIT_DMA)
|
||||
pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x\n",
|
||||
readl(host->ioaddr + SDHCI_ADMA_ERROR),
|
||||
readl(host->ioaddr + SDHCI_ADMA_ADDRESS_HI),
|
||||
readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
|
||||
else
|
||||
pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
|
||||
readl(host->ioaddr + SDHCI_ADMA_ERROR),
|
||||
readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
|
||||
}
|
||||
|
||||
pr_debug(DRIVER_NAME ": ===========================================\n");
|
||||
}
|
||||
|
@ -446,19 +453,25 @@ static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags)
|
|||
local_irq_restore(*flags);
|
||||
}
|
||||
|
||||
static void sdhci_adma_write_desc(void *desc, u32 addr, int len, unsigned cmd)
|
||||
static void sdhci_adma_write_desc(struct sdhci_host *host, void *desc,
|
||||
dma_addr_t addr, int len, unsigned cmd)
|
||||
{
|
||||
struct sdhci_adma2_32_desc *dma_desc = desc;
|
||||
struct sdhci_adma2_64_desc *dma_desc = desc;
|
||||
|
||||
/* 32-bit and 64-bit descriptors have these members in same position */
|
||||
dma_desc->cmd = cpu_to_le16(cmd);
|
||||
dma_desc->len = cpu_to_le16(len);
|
||||
dma_desc->addr = cpu_to_le32(addr);
|
||||
dma_desc->addr_lo = cpu_to_le32((u32)addr);
|
||||
|
||||
if (host->flags & SDHCI_USE_64_BIT_DMA)
|
||||
dma_desc->addr_hi = cpu_to_le32((u64)addr >> 32);
|
||||
}
|
||||
|
||||
static void sdhci_adma_mark_end(void *desc)
|
||||
{
|
||||
struct sdhci_adma2_32_desc *dma_desc = desc;
|
||||
struct sdhci_adma2_64_desc *dma_desc = desc;
|
||||
|
||||
/* 32-bit and 64-bit descriptors have 'cmd' in same position */
|
||||
dma_desc->cmd |= cpu_to_le16(ADMA2_END);
|
||||
}
|
||||
|
||||
|
@ -527,7 +540,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
|
|||
}
|
||||
|
||||
/* tran, valid */
|
||||
sdhci_adma_write_desc(desc, align_addr, offset,
|
||||
sdhci_adma_write_desc(host, desc, align_addr, offset,
|
||||
ADMA2_TRAN_VALID);
|
||||
|
||||
BUG_ON(offset > 65536);
|
||||
|
@ -544,7 +557,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
|
|||
BUG_ON(len > 65536);
|
||||
|
||||
/* tran, valid */
|
||||
sdhci_adma_write_desc(desc, addr, len, ADMA2_TRAN_VALID);
|
||||
sdhci_adma_write_desc(host, desc, addr, len, ADMA2_TRAN_VALID);
|
||||
desc += host->desc_sz;
|
||||
|
||||
/*
|
||||
|
@ -568,7 +581,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
|
|||
*/
|
||||
|
||||
/* nop, end, valid */
|
||||
sdhci_adma_write_desc(desc, 0, 0, ADMA2_NOP_END_VALID);
|
||||
sdhci_adma_write_desc(host, desc, 0, 0, ADMA2_NOP_END_VALID);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -827,6 +840,10 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
|
|||
} else {
|
||||
sdhci_writel(host, host->adma_addr,
|
||||
SDHCI_ADMA_ADDRESS);
|
||||
if (host->flags & SDHCI_USE_64_BIT_DMA)
|
||||
sdhci_writel(host,
|
||||
(u64)host->adma_addr >> 32,
|
||||
SDHCI_ADMA_ADDRESS_HI);
|
||||
}
|
||||
} else {
|
||||
int sg_cnt;
|
||||
|
@ -860,10 +877,14 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
|
|||
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
|
||||
ctrl &= ~SDHCI_CTRL_DMA_MASK;
|
||||
if ((host->flags & SDHCI_REQ_USE_DMA) &&
|
||||
(host->flags & SDHCI_USE_ADMA))
|
||||
ctrl |= SDHCI_CTRL_ADMA32;
|
||||
else
|
||||
(host->flags & SDHCI_USE_ADMA)) {
|
||||
if (host->flags & SDHCI_USE_64_BIT_DMA)
|
||||
ctrl |= SDHCI_CTRL_ADMA64;
|
||||
else
|
||||
ctrl |= SDHCI_CTRL_ADMA32;
|
||||
} else {
|
||||
ctrl |= SDHCI_CTRL_SDMA;
|
||||
}
|
||||
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
|
||||
}
|
||||
|
||||
|
@ -2296,12 +2317,19 @@ static void sdhci_adma_show_error(struct sdhci_host *host)
|
|||
sdhci_dumpregs(host);
|
||||
|
||||
while (true) {
|
||||
struct sdhci_adma2_32_desc *dma_desc = desc;
|
||||
struct sdhci_adma2_64_desc *dma_desc = desc;
|
||||
|
||||
DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
|
||||
name, desc, le32_to_cpu(dma_desc->addr),
|
||||
le16_to_cpu(dma_desc->len),
|
||||
le16_to_cpu(dma_desc->cmd));
|
||||
if (host->flags & SDHCI_USE_64_BIT_DMA)
|
||||
DBG("%s: %p: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n",
|
||||
name, desc, le32_to_cpu(dma_desc->addr_hi),
|
||||
le32_to_cpu(dma_desc->addr_lo),
|
||||
le16_to_cpu(dma_desc->len),
|
||||
le16_to_cpu(dma_desc->cmd));
|
||||
else
|
||||
DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
|
||||
name, desc, le32_to_cpu(dma_desc->addr_lo),
|
||||
le16_to_cpu(dma_desc->len),
|
||||
le16_to_cpu(dma_desc->cmd));
|
||||
|
||||
desc += host->desc_sz;
|
||||
|
||||
|
@ -2852,6 +2880,16 @@ int sdhci_add_host(struct sdhci_host *host)
|
|||
host->flags &= ~SDHCI_USE_ADMA;
|
||||
}
|
||||
|
||||
/*
|
||||
* It is assumed that a 64-bit capable device has set a 64-bit DMA mask
|
||||
* and *must* do 64-bit DMA. A driver has the opportunity to change
|
||||
* that during the first call to ->enable_dma(). Similarly
|
||||
* SDHCI_QUIRK2_BROKEN_64_BIT_DMA must be left to the drivers to
|
||||
* implement.
|
||||
*/
|
||||
if (sdhci_readl(host, SDHCI_CAPABILITIES) & SDHCI_CAN_64BIT)
|
||||
host->flags |= SDHCI_USE_64_BIT_DMA;
|
||||
|
||||
if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
|
||||
if (host->ops->enable_dma) {
|
||||
if (host->ops->enable_dma(host)) {
|
||||
|
@ -2863,6 +2901,10 @@ int sdhci_add_host(struct sdhci_host *host)
|
|||
}
|
||||
}
|
||||
|
||||
/* SDMA does not support 64-bit DMA */
|
||||
if (host->flags & SDHCI_USE_64_BIT_DMA)
|
||||
host->flags &= ~SDHCI_USE_SDMA;
|
||||
|
||||
if (host->flags & SDHCI_USE_ADMA) {
|
||||
/*
|
||||
* The DMA descriptor table size is calculated as the maximum
|
||||
|
@ -2870,13 +2912,23 @@ int sdhci_add_host(struct sdhci_host *host)
|
|||
* descriptor for each segment, plus 1 for a nop end descriptor,
|
||||
* all multipled by the descriptor size.
|
||||
*/
|
||||
host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
|
||||
SDHCI_ADMA2_32_DESC_SZ;
|
||||
host->align_buffer_sz = SDHCI_MAX_SEGS *
|
||||
SDHCI_ADMA2_32_ALIGN;
|
||||
host->desc_sz = SDHCI_ADMA2_32_DESC_SZ;
|
||||
host->align_sz = SDHCI_ADMA2_32_ALIGN;
|
||||
host->align_mask = SDHCI_ADMA2_32_ALIGN - 1;
|
||||
if (host->flags & SDHCI_USE_64_BIT_DMA) {
|
||||
host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
|
||||
SDHCI_ADMA2_64_DESC_SZ;
|
||||
host->align_buffer_sz = SDHCI_MAX_SEGS *
|
||||
SDHCI_ADMA2_64_ALIGN;
|
||||
host->desc_sz = SDHCI_ADMA2_64_DESC_SZ;
|
||||
host->align_sz = SDHCI_ADMA2_64_ALIGN;
|
||||
host->align_mask = SDHCI_ADMA2_64_ALIGN - 1;
|
||||
} else {
|
||||
host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
|
||||
SDHCI_ADMA2_32_DESC_SZ;
|
||||
host->align_buffer_sz = SDHCI_MAX_SEGS *
|
||||
SDHCI_ADMA2_32_ALIGN;
|
||||
host->desc_sz = SDHCI_ADMA2_32_DESC_SZ;
|
||||
host->align_sz = SDHCI_ADMA2_32_ALIGN;
|
||||
host->align_mask = SDHCI_ADMA2_32_ALIGN - 1;
|
||||
}
|
||||
host->adma_table = dma_alloc_coherent(mmc_dev(mmc),
|
||||
host->adma_table_sz,
|
||||
&host->adma_addr,
|
||||
|
@ -3289,7 +3341,8 @@ int sdhci_add_host(struct sdhci_host *host)
|
|||
|
||||
pr_info("%s: SDHCI controller on %s [%s] using %s\n",
|
||||
mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)),
|
||||
(host->flags & SDHCI_USE_ADMA) ? "ADMA" :
|
||||
(host->flags & SDHCI_USE_ADMA) ?
|
||||
(host->flags & SDHCI_USE_64_BIT_DMA) ? "ADMA 64-bit" : "ADMA" :
|
||||
(host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO");
|
||||
|
||||
sdhci_enable_card_detection(host);
|
||||
|
|
|
@ -227,6 +227,7 @@
|
|||
/* 55-57 reserved */
|
||||
|
||||
#define SDHCI_ADMA_ADDRESS 0x58
|
||||
#define SDHCI_ADMA_ADDRESS_HI 0x5C
|
||||
|
||||
/* 60-FB reserved */
|
||||
|
||||
|
@ -279,6 +280,23 @@ struct sdhci_adma2_32_desc {
|
|||
__le32 addr;
|
||||
} __packed __aligned(SDHCI_ADMA2_32_ALIGN);
|
||||
|
||||
/* ADMA2 64-bit DMA descriptor size */
|
||||
#define SDHCI_ADMA2_64_DESC_SZ 12
|
||||
|
||||
/* ADMA2 64-bit DMA alignment */
|
||||
#define SDHCI_ADMA2_64_ALIGN 8
|
||||
|
||||
/*
|
||||
* ADMA2 64-bit descriptor. Note 12-byte descriptor can't always be 8-byte
|
||||
* aligned.
|
||||
*/
|
||||
struct sdhci_adma2_64_desc {
|
||||
__le16 cmd;
|
||||
__le16 len;
|
||||
__le32 addr_lo;
|
||||
__le32 addr_hi;
|
||||
} __packed __aligned(4);
|
||||
|
||||
#define ADMA2_TRAN_VALID 0x21
|
||||
#define ADMA2_NOP_END_VALID 0x3
|
||||
#define ADMA2_END 0x2
|
||||
|
|
|
@ -100,6 +100,8 @@ struct sdhci_host {
|
|||
#define SDHCI_QUIRK2_BROKEN_DDR50 (1<<7)
|
||||
/* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */
|
||||
#define SDHCI_QUIRK2_STOP_WITH_TC (1<<8)
|
||||
/* Controller does not support 64-bit DMA */
|
||||
#define SDHCI_QUIRK2_BROKEN_64_BIT_DMA (1<<9)
|
||||
|
||||
int irq; /* Device IRQ */
|
||||
void __iomem *ioaddr; /* Mapped address */
|
||||
|
@ -130,6 +132,7 @@ struct sdhci_host {
|
|||
#define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */
|
||||
#define SDHCI_SDR104_NEEDS_TUNING (1<<10) /* SDR104/HS200 needs tuning */
|
||||
#define SDHCI_USING_RETUNING_TIMER (1<<11) /* Host is using a retuning timer for the card */
|
||||
#define SDHCI_USE_64_BIT_DMA (1<<12) /* Use 64-bit DMA */
|
||||
|
||||
unsigned int version; /* SDHCI spec. version */
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче