diff options
Diffstat (limited to 'drivers/mmc/host/atmel-mci.c')
-rw-r--r-- | drivers/mmc/host/atmel-mci.c | 92 |
1 files changed, 78 insertions, 14 deletions
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index e94476beca18..6f56ef025ab5 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c | |||
@@ -91,6 +91,11 @@ struct atmel_mci_dma { | |||
91 | * @regs: Pointer to MMIO registers. | 91 | * @regs: Pointer to MMIO registers. |
92 | * @sg: Scatterlist entry currently being processed by PIO or PDC code. | 92 | * @sg: Scatterlist entry currently being processed by PIO or PDC code. |
93 | * @pio_offset: Offset into the current scatterlist entry. | 93 | * @pio_offset: Offset into the current scatterlist entry. |
94 | * @buffer: Buffer used if we don't have the r/w proof capability. We | ||
95 | * don't have the time to switch pdc buffers so we have to use only | ||
96 | * one buffer for the full transaction. | ||
97 | * @buf_size: size of the buffer. | ||
98 | * @phys_buf_addr: buffer address needed for pdc. | ||
94 | * @cur_slot: The slot which is currently using the controller. | 99 | * @cur_slot: The slot which is currently using the controller. |
95 | * @mrq: The request currently being processed on @cur_slot, | 100 | * @mrq: The request currently being processed on @cur_slot, |
96 | * or NULL if the controller is idle. | 101 | * or NULL if the controller is idle. |
@@ -166,6 +171,9 @@ struct atmel_mci { | |||
166 | 171 | ||
167 | struct scatterlist *sg; | 172 | struct scatterlist *sg; |
168 | unsigned int pio_offset; | 173 | unsigned int pio_offset; |
174 | unsigned int *buffer; | ||
175 | unsigned int buf_size; | ||
176 | dma_addr_t buf_phys_addr; | ||
169 | 177 | ||
170 | struct atmel_mci_slot *cur_slot; | 178 | struct atmel_mci_slot *cur_slot; |
171 | struct mmc_request *mrq; | 179 | struct mmc_request *mrq; |
@@ -480,6 +488,11 @@ err: | |||
480 | dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); | 488 | dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); |
481 | } | 489 | } |
482 | 490 | ||
491 | static inline unsigned int atmci_get_version(struct atmel_mci *host) | ||
492 | { | ||
493 | return atmci_readl(host, ATMCI_VERSION) & 0x00000fff; | ||
494 | } | ||
495 | |||
483 | static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host, | 496 | static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host, |
484 | unsigned int ns) | 497 | unsigned int ns) |
485 | { | 498 | { |
@@ -603,6 +616,7 @@ static void atmci_pdc_set_single_buf(struct atmel_mci *host, | |||
603 | enum atmci_xfer_dir dir, enum atmci_pdc_buf buf_nb) | 616 | enum atmci_xfer_dir dir, enum atmci_pdc_buf buf_nb) |
604 | { | 617 | { |
605 | u32 pointer_reg, counter_reg; | 618 | u32 pointer_reg, counter_reg; |
619 | unsigned int buf_size; | ||
606 | 620 | ||
607 | if (dir == XFER_RECEIVE) { | 621 | if (dir == XFER_RECEIVE) { |
608 | pointer_reg = ATMEL_PDC_RPR; | 622 | pointer_reg = ATMEL_PDC_RPR; |
@@ -617,8 +631,15 @@ static void atmci_pdc_set_single_buf(struct atmel_mci *host, | |||
617 | counter_reg += ATMEL_PDC_SCND_BUF_OFF; | 631 | counter_reg += ATMEL_PDC_SCND_BUF_OFF; |
618 | } | 632 | } |
619 | 633 | ||
620 | atmci_writel(host, pointer_reg, sg_dma_address(host->sg)); | 634 | if (!host->caps.has_rwproof) { |
621 | if (host->data_size <= sg_dma_len(host->sg)) { | 635 | buf_size = host->buf_size; |
636 | atmci_writel(host, pointer_reg, host->buf_phys_addr); | ||
637 | } else { | ||
638 | buf_size = sg_dma_len(host->sg); | ||
639 | atmci_writel(host, pointer_reg, sg_dma_address(host->sg)); | ||
640 | } | ||
641 | |||
642 | if (host->data_size <= buf_size) { | ||
622 | if (host->data_size & 0x3) { | 643 | if (host->data_size & 0x3) { |
623 | /* If size is different from modulo 4, transfer bytes */ | 644 | /* If size is different from modulo 4, transfer bytes */ |
624 | atmci_writel(host, counter_reg, host->data_size); | 645 | atmci_writel(host, counter_reg, host->data_size); |
@@ -670,7 +691,15 @@ static void atmci_pdc_cleanup(struct atmel_mci *host) | |||
670 | */ | 691 | */ |
671 | static void atmci_pdc_complete(struct atmel_mci *host) | 692 | static void atmci_pdc_complete(struct atmel_mci *host) |
672 | { | 693 | { |
694 | int transfer_size = host->data->blocks * host->data->blksz; | ||
695 | |||
673 | atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); | 696 | atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); |
697 | |||
698 | if ((!host->caps.has_rwproof) | ||
699 | && (host->data->flags & MMC_DATA_READ)) | ||
700 | sg_copy_from_buffer(host->data->sg, host->data->sg_len, | ||
701 | host->buffer, transfer_size); | ||
702 | |||
674 | atmci_pdc_cleanup(host); | 703 | atmci_pdc_cleanup(host); |
675 | 704 | ||
676 | /* | 705 | /* |
@@ -818,6 +847,12 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data) | |||
818 | /* Configure PDC */ | 847 | /* Configure PDC */ |
819 | host->data_size = data->blocks * data->blksz; | 848 | host->data_size = data->blocks * data->blksz; |
820 | sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, dir); | 849 | sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, dir); |
850 | |||
851 | if ((!host->caps.has_rwproof) | ||
852 | && (host->data->flags & MMC_DATA_WRITE)) | ||
853 | sg_copy_to_buffer(host->data->sg, host->data->sg_len, | ||
854 | host->buffer, host->data_size); | ||
855 | |||
821 | if (host->data_size) | 856 | if (host->data_size) |
822 | atmci_pdc_set_both_buf(host, | 857 | atmci_pdc_set_both_buf(host, |
823 | ((dir == DMA_FROM_DEVICE) ? XFER_RECEIVE : XFER_TRANSMIT)); | 858 | ((dir == DMA_FROM_DEVICE) ? XFER_RECEIVE : XFER_TRANSMIT)); |
@@ -1877,13 +1912,26 @@ static int __init atmci_init_slot(struct atmel_mci *host, | |||
1877 | mmc->caps |= MMC_CAP_SDIO_IRQ; | 1912 | mmc->caps |= MMC_CAP_SDIO_IRQ; |
1878 | if (host->caps.has_highspeed) | 1913 | if (host->caps.has_highspeed) |
1879 | mmc->caps |= MMC_CAP_SD_HIGHSPEED; | 1914 | mmc->caps |= MMC_CAP_SD_HIGHSPEED; |
1880 | if (slot_data->bus_width >= 4) | 1915 | /* |
1916 | * Without the read/write proof capability, it is strongly suggested to | ||
1917 | * use only one bit for data to prevent fifo underruns and overruns | ||
1918 | * which will corrupt data. | ||
1919 | */ | ||
1920 | if ((slot_data->bus_width >= 4) && host->caps.has_rwproof) | ||
1881 | mmc->caps |= MMC_CAP_4_BIT_DATA; | 1921 | mmc->caps |= MMC_CAP_4_BIT_DATA; |
1882 | 1922 | ||
1883 | mmc->max_segs = 64; | 1923 | if (atmci_get_version(host) < 0x200) { |
1884 | mmc->max_req_size = 32768 * 512; | 1924 | mmc->max_segs = 256; |
1885 | mmc->max_blk_size = 32768; | 1925 | mmc->max_blk_size = 4095; |
1886 | mmc->max_blk_count = 512; | 1926 | mmc->max_blk_count = 256; |
1927 | mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; | ||
1928 | mmc->max_seg_size = mmc->max_blk_size * mmc->max_segs; | ||
1929 | } else { | ||
1930 | mmc->max_segs = 64; | ||
1931 | mmc->max_req_size = 32768 * 512; | ||
1932 | mmc->max_blk_size = 32768; | ||
1933 | mmc->max_blk_count = 512; | ||
1934 | } | ||
1887 | 1935 | ||
1888 | /* Assume card is present initially */ | 1936 | /* Assume card is present initially */ |
1889 | set_bit(ATMCI_CARD_PRESENT, &slot->flags); | 1937 | set_bit(ATMCI_CARD_PRESENT, &slot->flags); |
@@ -2007,11 +2055,6 @@ static bool atmci_configure_dma(struct atmel_mci *host) | |||
2007 | } | 2055 | } |
2008 | } | 2056 | } |
2009 | 2057 | ||
2010 | static inline unsigned int atmci_get_version(struct atmel_mci *host) | ||
2011 | { | ||
2012 | return atmci_readl(host, ATMCI_VERSION) & 0x00000fff; | ||
2013 | } | ||
2014 | |||
2015 | /* | 2058 | /* |
2016 | * HSMCI (High Speed MCI) module is not fully compatible with MCI module. | 2059 | * HSMCI (High Speed MCI) module is not fully compatible with MCI module. |
2017 | * HSMCI provides DMA support and a new config register but no more supports | 2060 | * HSMCI provides DMA support and a new config register but no more supports |
@@ -2138,14 +2181,20 @@ static int __init atmci_probe(struct platform_device *pdev) | |||
2138 | if (pdata->slot[0].bus_width) { | 2181 | if (pdata->slot[0].bus_width) { |
2139 | ret = atmci_init_slot(host, &pdata->slot[0], | 2182 | ret = atmci_init_slot(host, &pdata->slot[0], |
2140 | 0, ATMCI_SDCSEL_SLOT_A, ATMCI_SDIOIRQA); | 2183 | 0, ATMCI_SDCSEL_SLOT_A, ATMCI_SDIOIRQA); |
2141 | if (!ret) | 2184 | if (!ret) { |
2142 | nr_slots++; | 2185 | nr_slots++; |
2186 | host->buf_size = host->slot[0]->mmc->max_req_size; | ||
2187 | } | ||
2143 | } | 2188 | } |
2144 | if (pdata->slot[1].bus_width) { | 2189 | if (pdata->slot[1].bus_width) { |
2145 | ret = atmci_init_slot(host, &pdata->slot[1], | 2190 | ret = atmci_init_slot(host, &pdata->slot[1], |
2146 | 1, ATMCI_SDCSEL_SLOT_B, ATMCI_SDIOIRQB); | 2191 | 1, ATMCI_SDCSEL_SLOT_B, ATMCI_SDIOIRQB); |
2147 | if (!ret) | 2192 | if (!ret) { |
2148 | nr_slots++; | 2193 | nr_slots++; |
2194 | if (host->slot[1]->mmc->max_req_size > host->buf_size) | ||
2195 | host->buf_size = | ||
2196 | host->slot[1]->mmc->max_req_size; | ||
2197 | } | ||
2149 | } | 2198 | } |
2150 | 2199 | ||
2151 | if (!nr_slots) { | 2200 | if (!nr_slots) { |
@@ -2153,6 +2202,17 @@ static int __init atmci_probe(struct platform_device *pdev) | |||
2153 | goto err_init_slot; | 2202 | goto err_init_slot; |
2154 | } | 2203 | } |
2155 | 2204 | ||
2205 | if (!host->caps.has_rwproof) { | ||
2206 | host->buffer = dma_alloc_coherent(&pdev->dev, host->buf_size, | ||
2207 | &host->buf_phys_addr, | ||
2208 | GFP_KERNEL); | ||
2209 | if (!host->buffer) { | ||
2210 | ret = -ENOMEM; | ||
2211 | dev_err(&pdev->dev, "buffer allocation failed\n"); | ||
2212 | goto err_init_slot; | ||
2213 | } | ||
2214 | } | ||
2215 | |||
2156 | dev_info(&pdev->dev, | 2216 | dev_info(&pdev->dev, |
2157 | "Atmel MCI controller at 0x%08lx irq %d, %u slots\n", | 2217 | "Atmel MCI controller at 0x%08lx irq %d, %u slots\n", |
2158 | host->mapbase, irq, nr_slots); | 2218 | host->mapbase, irq, nr_slots); |
@@ -2179,6 +2239,10 @@ static int __exit atmci_remove(struct platform_device *pdev) | |||
2179 | 2239 | ||
2180 | platform_set_drvdata(pdev, NULL); | 2240 | platform_set_drvdata(pdev, NULL); |
2181 | 2241 | ||
2242 | if (host->buffer) | ||
2243 | dma_free_coherent(&pdev->dev, host->buf_size, | ||
2244 | host->buffer, host->buf_phys_addr); | ||
2245 | |||
2182 | for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { | 2246 | for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { |
2183 | if (host->slot[i]) | 2247 | if (host->slot[i]) |
2184 | atmci_cleanup_slot(host->slot[i], i); | 2248 | atmci_cleanup_slot(host->slot[i], i); |