Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 307967
b: refs/heads/master
c: 7a90dcc
h: refs/heads/master
i:
  307965: 09e30c5
  307963: 3a01582
  307959: b4a0b30
  307951: bab495c
  307935: e2949cd
  307903: f566fa0
  307839: ce8b474
  307711: 9d4255a
v: v3
  • Loading branch information
Ludovic Desroches authored and Chris Ball committed May 17, 2012
1 parent c949b61 commit a4eb8d8
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 15 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 705ad0472bd55fa38e6c594b2d6318c31e86068a
refs/heads/master: 7a90dcc2d7ceb64bb37044a8d2ee462b936ddf73
92 changes: 78 additions & 14 deletions trunk/drivers/mmc/host/atmel-mci.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ struct atmel_mci_dma {
* @regs: Pointer to MMIO registers.
* @sg: Scatterlist entry currently being processed by PIO or PDC code.
* @pio_offset: Offset into the current scatterlist entry.
* @buffer: Buffer used if we don't have the r/w proof capability. We
* don't have the time to switch pdc buffers so we have to use only
* one buffer for the full transaction.
* @buf_size: size of the buffer.
* @phys_buf_addr: buffer address needed for pdc.
* @cur_slot: The slot which is currently using the controller.
* @mrq: The request currently being processed on @cur_slot,
* or NULL if the controller is idle.
Expand Down Expand Up @@ -166,6 +171,9 @@ struct atmel_mci {

struct scatterlist *sg;
unsigned int pio_offset;
unsigned int *buffer;
unsigned int buf_size;
dma_addr_t buf_phys_addr;

struct atmel_mci_slot *cur_slot;
struct mmc_request *mrq;
Expand Down Expand Up @@ -480,6 +488,11 @@ static void atmci_init_debugfs(struct atmel_mci_slot *slot)
dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
}

static inline unsigned int atmci_get_version(struct atmel_mci *host)
{
return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
}

static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host,
unsigned int ns)
{
Expand Down Expand Up @@ -603,6 +616,7 @@ static void atmci_pdc_set_single_buf(struct atmel_mci *host,
enum atmci_xfer_dir dir, enum atmci_pdc_buf buf_nb)
{
u32 pointer_reg, counter_reg;
unsigned int buf_size;

if (dir == XFER_RECEIVE) {
pointer_reg = ATMEL_PDC_RPR;
Expand All @@ -617,8 +631,15 @@ static void atmci_pdc_set_single_buf(struct atmel_mci *host,
counter_reg += ATMEL_PDC_SCND_BUF_OFF;
}

atmci_writel(host, pointer_reg, sg_dma_address(host->sg));
if (host->data_size <= sg_dma_len(host->sg)) {
if (!host->caps.has_rwproof) {
buf_size = host->buf_size;
atmci_writel(host, pointer_reg, host->buf_phys_addr);
} else {
buf_size = sg_dma_len(host->sg);
atmci_writel(host, pointer_reg, sg_dma_address(host->sg));
}

if (host->data_size <= buf_size) {
if (host->data_size & 0x3) {
/* If size is different from modulo 4, transfer bytes */
atmci_writel(host, counter_reg, host->data_size);
Expand Down Expand Up @@ -670,7 +691,15 @@ static void atmci_pdc_cleanup(struct atmel_mci *host)
*/
static void atmci_pdc_complete(struct atmel_mci *host)
{
int transfer_size = host->data->blocks * host->data->blksz;

atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);

if ((!host->caps.has_rwproof)
&& (host->data->flags & MMC_DATA_READ))
sg_copy_from_buffer(host->data->sg, host->data->sg_len,
host->buffer, transfer_size);

atmci_pdc_cleanup(host);

/*
Expand Down Expand Up @@ -818,6 +847,12 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
/* Configure PDC */
host->data_size = data->blocks * data->blksz;
sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, dir);

if ((!host->caps.has_rwproof)
&& (host->data->flags & MMC_DATA_WRITE))
sg_copy_to_buffer(host->data->sg, host->data->sg_len,
host->buffer, host->data_size);

if (host->data_size)
atmci_pdc_set_both_buf(host,
((dir == DMA_FROM_DEVICE) ? XFER_RECEIVE : XFER_TRANSMIT));
Expand Down Expand Up @@ -1877,13 +1912,26 @@ static int __init atmci_init_slot(struct atmel_mci *host,
mmc->caps |= MMC_CAP_SDIO_IRQ;
if (host->caps.has_highspeed)
mmc->caps |= MMC_CAP_SD_HIGHSPEED;
if (slot_data->bus_width >= 4)
/*
* Without the read/write proof capability, it is strongly suggested to
* use only one bit for data to prevent fifo underruns and overruns
* which will corrupt data.
*/
if ((slot_data->bus_width >= 4) && host->caps.has_rwproof)
mmc->caps |= MMC_CAP_4_BIT_DATA;

mmc->max_segs = 64;
mmc->max_req_size = 32768 * 512;
mmc->max_blk_size = 32768;
mmc->max_blk_count = 512;
if (atmci_get_version(host) < 0x200) {
mmc->max_segs = 256;
mmc->max_blk_size = 4095;
mmc->max_blk_count = 256;
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
mmc->max_seg_size = mmc->max_blk_size * mmc->max_segs;
} else {
mmc->max_segs = 64;
mmc->max_req_size = 32768 * 512;
mmc->max_blk_size = 32768;
mmc->max_blk_count = 512;
}

/* Assume card is present initially */
set_bit(ATMCI_CARD_PRESENT, &slot->flags);
Expand Down Expand Up @@ -2007,11 +2055,6 @@ static bool atmci_configure_dma(struct atmel_mci *host)
}
}

static inline unsigned int atmci_get_version(struct atmel_mci *host)
{
return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
}

/*
* HSMCI (High Speed MCI) module is not fully compatible with MCI module.
* HSMCI provides DMA support and a new config register but no more supports
Expand Down Expand Up @@ -2138,21 +2181,38 @@ static int __init atmci_probe(struct platform_device *pdev)
if (pdata->slot[0].bus_width) {
ret = atmci_init_slot(host, &pdata->slot[0],
0, ATMCI_SDCSEL_SLOT_A, ATMCI_SDIOIRQA);
if (!ret)
if (!ret) {
nr_slots++;
host->buf_size = host->slot[0]->mmc->max_req_size;
}
}
if (pdata->slot[1].bus_width) {
ret = atmci_init_slot(host, &pdata->slot[1],
1, ATMCI_SDCSEL_SLOT_B, ATMCI_SDIOIRQB);
if (!ret)
if (!ret) {
nr_slots++;
if (host->slot[1]->mmc->max_req_size > host->buf_size)
host->buf_size =
host->slot[1]->mmc->max_req_size;
}
}

if (!nr_slots) {
dev_err(&pdev->dev, "init failed: no slot defined\n");
goto err_init_slot;
}

if (!host->caps.has_rwproof) {
host->buffer = dma_alloc_coherent(&pdev->dev, host->buf_size,
&host->buf_phys_addr,
GFP_KERNEL);
if (!host->buffer) {
ret = -ENOMEM;
dev_err(&pdev->dev, "buffer allocation failed\n");
goto err_init_slot;
}
}

dev_info(&pdev->dev,
"Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
host->mapbase, irq, nr_slots);
Expand All @@ -2179,6 +2239,10 @@ static int __exit atmci_remove(struct platform_device *pdev)

platform_set_drvdata(pdev, NULL);

if (host->buffer)
dma_free_coherent(&pdev->dev, host->buf_size,
host->buffer, host->buf_phys_addr);

for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
if (host->slot[i])
atmci_cleanup_slot(host->slot[i], i);
Expand Down

0 comments on commit a4eb8d8

Please sign in to comment.