diff options
Diffstat (limited to 'drivers/mmc')
| -rw-r--r-- | drivers/mmc/host/sdhci.c | 163 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci.h | 7 |
2 files changed, 75 insertions, 95 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 8b1f412144cf..c3a5db72ddd7 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c | |||
| @@ -173,119 +173,95 @@ static void sdhci_led_control(struct led_classdev *led, | |||
| 173 | * * | 173 | * * |
| 174 | \*****************************************************************************/ | 174 | \*****************************************************************************/ |
| 175 | 175 | ||
| 176 | static inline char* sdhci_sg_to_buffer(struct sdhci_host* host) | ||
| 177 | { | ||
| 178 | return sg_virt(host->cur_sg); | ||
| 179 | } | ||
| 180 | |||
| 181 | static inline int sdhci_next_sg(struct sdhci_host* host) | ||
| 182 | { | ||
| 183 | /* | ||
| 184 | * Skip to next SG entry. | ||
| 185 | */ | ||
| 186 | host->cur_sg++; | ||
| 187 | host->num_sg--; | ||
| 188 | |||
| 189 | /* | ||
| 190 | * Any entries left? | ||
| 191 | */ | ||
| 192 | if (host->num_sg > 0) { | ||
| 193 | host->offset = 0; | ||
| 194 | host->remain = host->cur_sg->length; | ||
| 195 | } | ||
| 196 | |||
| 197 | return host->num_sg; | ||
| 198 | } | ||
| 199 | |||
| 200 | static void sdhci_read_block_pio(struct sdhci_host *host) | 176 | static void sdhci_read_block_pio(struct sdhci_host *host) |
| 201 | { | 177 | { |
| 202 | int blksize, chunk_remain; | 178 | unsigned long flags; |
| 203 | u32 data; | 179 | size_t blksize, len, chunk; |
| 204 | char *buffer; | 180 | u32 scratch; |
| 205 | int size; | 181 | u8 *buf; |
| 206 | 182 | ||
| 207 | DBG("PIO reading\n"); | 183 | DBG("PIO reading\n"); |
| 208 | 184 | ||
| 209 | blksize = host->data->blksz; | 185 | blksize = host->data->blksz; |
| 210 | chunk_remain = 0; | 186 | chunk = 0; |
| 211 | data = 0; | ||
| 212 | 187 | ||
| 213 | buffer = sdhci_sg_to_buffer(host) + host->offset; | 188 | local_irq_save(flags); |
| 214 | 189 | ||
| 215 | while (blksize) { | 190 | while (blksize) { |
| 216 | if (chunk_remain == 0) { | 191 | if (!sg_miter_next(&host->sg_miter)) |
| 217 | data = readl(host->ioaddr + SDHCI_BUFFER); | 192 | BUG(); |
| 218 | chunk_remain = min(blksize, 4); | ||
| 219 | } | ||
| 220 | 193 | ||
| 221 | size = min(host->remain, chunk_remain); | 194 | len = min(host->sg_miter.length, blksize); |
| 222 | 195 | ||
| 223 | chunk_remain -= size; | 196 | blksize -= len; |
| 224 | blksize -= size; | 197 | host->sg_miter.consumed = len; |
| 225 | host->offset += size; | ||
| 226 | host->remain -= size; | ||
| 227 | 198 | ||
| 228 | while (size) { | 199 | buf = host->sg_miter.addr; |
| 229 | *buffer = data & 0xFF; | ||
| 230 | buffer++; | ||
| 231 | data >>= 8; | ||
| 232 | size--; | ||
| 233 | } | ||
| 234 | 200 | ||
| 235 | if (host->remain == 0) { | 201 | while (len) { |
| 236 | if (sdhci_next_sg(host) == 0) { | 202 | if (chunk == 0) { |
| 237 | BUG_ON(blksize != 0); | 203 | scratch = readl(host->ioaddr + SDHCI_BUFFER); |
| 238 | return; | 204 | chunk = 4; |
| 239 | } | 205 | } |
| 240 | buffer = sdhci_sg_to_buffer(host); | 206 | |
| 207 | *buf = scratch & 0xFF; | ||
| 208 | |||
| 209 | buf++; | ||
| 210 | scratch >>= 8; | ||
| 211 | chunk--; | ||
| 212 | len--; | ||
| 241 | } | 213 | } |
| 242 | } | 214 | } |
| 215 | |||
| 216 | sg_miter_stop(&host->sg_miter); | ||
| 217 | |||
| 218 | local_irq_restore(flags); | ||
| 243 | } | 219 | } |
| 244 | 220 | ||
| 245 | static void sdhci_write_block_pio(struct sdhci_host *host) | 221 | static void sdhci_write_block_pio(struct sdhci_host *host) |
| 246 | { | 222 | { |
| 247 | int blksize, chunk_remain; | 223 | unsigned long flags; |
| 248 | u32 data; | 224 | size_t blksize, len, chunk; |
| 249 | char *buffer; | 225 | u32 scratch; |
| 250 | int bytes, size; | 226 | u8 *buf; |
| 251 | 227 | ||
| 252 | DBG("PIO writing\n"); | 228 | DBG("PIO writing\n"); |
| 253 | 229 | ||
| 254 | blksize = host->data->blksz; | 230 | blksize = host->data->blksz; |
| 255 | chunk_remain = 4; | 231 | chunk = 0; |
| 256 | data = 0; | 232 | scratch = 0; |
| 257 | 233 | ||
| 258 | bytes = 0; | 234 | local_irq_save(flags); |
| 259 | buffer = sdhci_sg_to_buffer(host) + host->offset; | ||
| 260 | 235 | ||
| 261 | while (blksize) { | 236 | while (blksize) { |
| 262 | size = min(host->remain, chunk_remain); | 237 | if (!sg_miter_next(&host->sg_miter)) |
| 263 | 238 | BUG(); | |
| 264 | chunk_remain -= size; | ||
| 265 | blksize -= size; | ||
| 266 | host->offset += size; | ||
| 267 | host->remain -= size; | ||
| 268 | |||
| 269 | while (size) { | ||
| 270 | data >>= 8; | ||
| 271 | data |= (u32)*buffer << 24; | ||
| 272 | buffer++; | ||
| 273 | size--; | ||
| 274 | } | ||
| 275 | 239 | ||
| 276 | if (chunk_remain == 0) { | 240 | len = min(host->sg_miter.length, blksize); |
| 277 | writel(data, host->ioaddr + SDHCI_BUFFER); | 241 | |
| 278 | chunk_remain = min(blksize, 4); | 242 | blksize -= len; |
| 279 | } | 243 | host->sg_miter.consumed = len; |
| 244 | |||
| 245 | buf = host->sg_miter.addr; | ||
| 280 | 246 | ||
| 281 | if (host->remain == 0) { | 247 | while (len) { |
| 282 | if (sdhci_next_sg(host) == 0) { | 248 | scratch |= (u32)*buf << (chunk * 8); |
| 283 | BUG_ON(blksize != 0); | 249 | |
| 284 | return; | 250 | buf++; |
| 251 | chunk++; | ||
| 252 | len--; | ||
| 253 | |||
| 254 | if ((chunk == 4) || ((len == 0) && (blksize == 0))) { | ||
| 255 | writel(scratch, host->ioaddr + SDHCI_BUFFER); | ||
| 256 | chunk = 0; | ||
| 257 | scratch = 0; | ||
| 285 | } | 258 | } |
| 286 | buffer = sdhci_sg_to_buffer(host); | ||
| 287 | } | 259 | } |
| 288 | } | 260 | } |
| 261 | |||
| 262 | sg_miter_stop(&host->sg_miter); | ||
| 263 | |||
| 264 | local_irq_restore(flags); | ||
| 289 | } | 265 | } |
| 290 | 266 | ||
| 291 | static void sdhci_transfer_pio(struct sdhci_host *host) | 267 | static void sdhci_transfer_pio(struct sdhci_host *host) |
| @@ -294,7 +270,7 @@ static void sdhci_transfer_pio(struct sdhci_host *host) | |||
| 294 | 270 | ||
| 295 | BUG_ON(!host->data); | 271 | BUG_ON(!host->data); |
| 296 | 272 | ||
| 297 | if (host->num_sg == 0) | 273 | if (host->blocks == 0) |
| 298 | return; | 274 | return; |
| 299 | 275 | ||
| 300 | if (host->data->flags & MMC_DATA_READ) | 276 | if (host->data->flags & MMC_DATA_READ) |
| @@ -308,7 +284,8 @@ static void sdhci_transfer_pio(struct sdhci_host *host) | |||
| 308 | else | 284 | else |
| 309 | sdhci_write_block_pio(host); | 285 | sdhci_write_block_pio(host); |
| 310 | 286 | ||
| 311 | if (host->num_sg == 0) | 287 | host->blocks--; |
| 288 | if (host->blocks == 0) | ||
| 312 | break; | 289 | break; |
| 313 | } | 290 | } |
| 314 | 291 | ||
| @@ -713,11 +690,9 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) | |||
| 713 | } | 690 | } |
| 714 | 691 | ||
| 715 | if (!(host->flags & SDHCI_REQ_USE_DMA)) { | 692 | if (!(host->flags & SDHCI_REQ_USE_DMA)) { |
| 716 | host->cur_sg = data->sg; | 693 | sg_miter_start(&host->sg_miter, |
| 717 | host->num_sg = data->sg_len; | 694 | data->sg, data->sg_len, SG_MITER_ATOMIC); |
| 718 | 695 | host->blocks = data->blocks; | |
| 719 | host->offset = 0; | ||
| 720 | host->remain = host->cur_sg->length; | ||
| 721 | } | 696 | } |
| 722 | 697 | ||
| 723 | /* We do not handle DMA boundaries, so set it to max (512 KiB) */ | 698 | /* We do not handle DMA boundaries, so set it to max (512 KiB) */ |
| @@ -1583,9 +1558,15 @@ int sdhci_add_host(struct sdhci_host *host) | |||
| 1583 | } | 1558 | } |
| 1584 | } | 1559 | } |
| 1585 | 1560 | ||
| 1586 | /* XXX: Hack to get MMC layer to avoid highmem */ | 1561 | /* |
| 1587 | if (!(host->flags & SDHCI_USE_DMA)) | 1562 | * If we use DMA, then it's up to the caller to set the DMA |
| 1588 | mmc_dev(host->mmc)->dma_mask = NULL; | 1563 | * mask, but PIO does not need the hw shim so we set a new |
| 1564 | * mask here in that case. | ||
| 1565 | */ | ||
| 1566 | if (!(host->flags & SDHCI_USE_DMA)) { | ||
| 1567 | host->dma_mask = DMA_BIT_MASK(64); | ||
| 1568 | mmc_dev(host->mmc)->dma_mask = &host->dma_mask; | ||
| 1569 | } | ||
| 1589 | 1570 | ||
| 1590 | host->max_clk = | 1571 | host->max_clk = |
| 1591 | (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; | 1572 | (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; |
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 5bb355281765..a06bf8b89343 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h | |||
| @@ -212,6 +212,7 @@ struct sdhci_host { | |||
| 212 | 212 | ||
| 213 | /* Internal data */ | 213 | /* Internal data */ |
| 214 | struct mmc_host *mmc; /* MMC structure */ | 214 | struct mmc_host *mmc; /* MMC structure */ |
| 215 | u64 dma_mask; /* custom DMA mask */ | ||
| 215 | 216 | ||
| 216 | #ifdef CONFIG_LEDS_CLASS | 217 | #ifdef CONFIG_LEDS_CLASS |
| 217 | struct led_classdev led; /* LED control */ | 218 | struct led_classdev led; /* LED control */ |
| @@ -238,10 +239,8 @@ struct sdhci_host { | |||
| 238 | struct mmc_data *data; /* Current data request */ | 239 | struct mmc_data *data; /* Current data request */ |
| 239 | unsigned int data_early:1; /* Data finished before cmd */ | 240 | unsigned int data_early:1; /* Data finished before cmd */ |
| 240 | 241 | ||
| 241 | struct scatterlist *cur_sg; /* We're working on this */ | 242 | struct sg_mapping_iter sg_miter; /* SG state for PIO */ |
| 242 | int num_sg; /* Entries left */ | 243 | unsigned int blocks; /* remaining PIO blocks */ |
| 243 | int offset; /* Offset into current sg */ | ||
| 244 | int remain; /* Bytes left in current */ | ||
| 245 | 244 | ||
| 246 | int sg_count; /* Mapped sg entries */ | 245 | int sg_count; /* Mapped sg entries */ |
| 247 | 246 | ||
