Lines Matching +full:mmc +full:- +full:host

1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2013-2014 Renesas Electronics Europe Ltd.
10 #include <linux/dma-mapping.h>
16 #include <linux/mmc/host.h>
17 #include <linux/mmc/mmc.h>
18 #include <linux/mmc/sd.h>
19 #include <linux/mmc/sdio.h>
159 struct mmc_host *mmc; member
169 size_t offset; /* offset within a page, including sg->offset */
209 static void usdhi6_write(struct usdhi6_host *host, u32 reg, u32 data) in usdhi6_write() argument
211 iowrite32(data, host->base + reg); in usdhi6_write()
212 dev_vdbg(mmc_dev(host->mmc), "%s(0x%p + 0x%x) = 0x%x\n", __func__, in usdhi6_write()
213 host->base, reg, data); in usdhi6_write()
216 static void usdhi6_write16(struct usdhi6_host *host, u32 reg, u16 data) in usdhi6_write16() argument
218 iowrite16(data, host->base + reg); in usdhi6_write16()
219 dev_vdbg(mmc_dev(host->mmc), "%s(0x%p + 0x%x) = 0x%x\n", __func__, in usdhi6_write16()
220 host->base, reg, data); in usdhi6_write16()
223 static u32 usdhi6_read(struct usdhi6_host *host, u32 reg) in usdhi6_read() argument
225 u32 data = ioread32(host->base + reg); in usdhi6_read()
226 dev_vdbg(mmc_dev(host->mmc), "%s(0x%p + 0x%x) = 0x%x\n", __func__, in usdhi6_read()
227 host->base, reg, data); in usdhi6_read()
231 static u16 usdhi6_read16(struct usdhi6_host *host, u32 reg) in usdhi6_read16() argument
233 u16 data = ioread16(host->base + reg); in usdhi6_read16()
234 dev_vdbg(mmc_dev(host->mmc), "%s(0x%p + 0x%x) = 0x%x\n", __func__, in usdhi6_read16()
235 host->base, reg, data); in usdhi6_read16()
239 static void usdhi6_irq_enable(struct usdhi6_host *host, u32 info1, u32 info2) in usdhi6_irq_enable() argument
241 host->status_mask = USDHI6_SD_INFO1_IRQ & ~info1; in usdhi6_irq_enable()
242 host->status2_mask = USDHI6_SD_INFO2_IRQ & ~info2; in usdhi6_irq_enable()
243 usdhi6_write(host, USDHI6_SD_INFO1_MASK, host->status_mask); in usdhi6_irq_enable()
244 usdhi6_write(host, USDHI6_SD_INFO2_MASK, host->status2_mask); in usdhi6_irq_enable()
247 static void usdhi6_wait_for_resp(struct usdhi6_host *host) in usdhi6_wait_for_resp() argument
249 usdhi6_irq_enable(host, USDHI6_SD_INFO1_RSP_END | in usdhi6_wait_for_resp()
254 static void usdhi6_wait_for_brwe(struct usdhi6_host *host, bool read) in usdhi6_wait_for_brwe() argument
256 usdhi6_irq_enable(host, USDHI6_SD_INFO1_ACCESS_END | in usdhi6_wait_for_brwe()
261 static void usdhi6_only_cd(struct usdhi6_host *host) in usdhi6_only_cd() argument
264 usdhi6_irq_enable(host, USDHI6_SD_INFO1_CARD_CD, 0); in usdhi6_only_cd()
267 static void usdhi6_mask_all(struct usdhi6_host *host) in usdhi6_mask_all() argument
269 usdhi6_irq_enable(host, 0, 0); in usdhi6_mask_all()
272 static int usdhi6_error_code(struct usdhi6_host *host) in usdhi6_error_code() argument
276 usdhi6_write(host, USDHI6_SD_STOP, USDHI6_SD_STOP_STP); in usdhi6_error_code()
278 if (host->io_error & in usdhi6_error_code()
280 u32 rsp54 = usdhi6_read(host, USDHI6_SD_RSP54); in usdhi6_error_code()
281 int opc = host->mrq ? host->mrq->cmd->opcode : -1; in usdhi6_error_code()
283 err = usdhi6_read(host, USDHI6_SD_ERR_STS2); in usdhi6_error_code()
285 if (host->wait == USDHI6_WAIT_FOR_CMD) in usdhi6_error_code()
286 dev_dbg(mmc_dev(host->mmc), in usdhi6_error_code()
287 "T-out sts 0x%x, resp 0x%x, state %u, CMD%d\n", in usdhi6_error_code()
288 err, rsp54, host->wait, opc); in usdhi6_error_code()
290 dev_warn(mmc_dev(host->mmc), in usdhi6_error_code()
291 "T-out sts 0x%x, resp 0x%x, state %u, CMD%d\n", in usdhi6_error_code()
292 err, rsp54, host->wait, opc); in usdhi6_error_code()
293 return -ETIMEDOUT; in usdhi6_error_code()
296 err = usdhi6_read(host, USDHI6_SD_ERR_STS1); in usdhi6_error_code()
298 dev_warn(mmc_dev(host->mmc), "Err sts 0x%x, state %u, CMD%d\n", in usdhi6_error_code()
299 err, host->wait, host->mrq ? host->mrq->cmd->opcode : -1); in usdhi6_error_code()
300 if (host->io_error & USDHI6_SD_INFO2_ILA) in usdhi6_error_code()
301 return -EILSEQ; in usdhi6_error_code()
303 return -EIO; in usdhi6_error_code()
306 /* Scatter-Gather management */
310 * adjacent pages are mapped to non-adjacent virtual addresses. That's why we
314 static void usdhi6_blk_bounce(struct usdhi6_host *host, in usdhi6_blk_bounce() argument
317 struct mmc_data *data = host->mrq->data; in usdhi6_blk_bounce()
318 size_t blk_head = host->head_len; in usdhi6_blk_bounce()
320 dev_dbg(mmc_dev(host->mmc), "%s(): CMD%u of %u SG: %ux%u @ 0x%x\n", in usdhi6_blk_bounce()
321 __func__, host->mrq->cmd->opcode, data->sg_len, in usdhi6_blk_bounce()
322 data->blksz, data->blocks, sg->offset); in usdhi6_blk_bounce()
324 host->head_pg.page = host->pg.page; in usdhi6_blk_bounce()
325 host->head_pg.mapped = host->pg.mapped; in usdhi6_blk_bounce()
326 host->pg.page = nth_page(host->pg.page, 1); in usdhi6_blk_bounce()
327 host->pg.mapped = kmap(host->pg.page); in usdhi6_blk_bounce()
329 host->blk_page = host->bounce_buf; in usdhi6_blk_bounce()
330 host->offset = 0; in usdhi6_blk_bounce()
332 if (data->flags & MMC_DATA_READ) in usdhi6_blk_bounce()
335 memcpy(host->bounce_buf, host->head_pg.mapped + PAGE_SIZE - blk_head, in usdhi6_blk_bounce()
337 memcpy(host->bounce_buf + blk_head, host->pg.mapped, in usdhi6_blk_bounce()
338 data->blksz - blk_head); in usdhi6_blk_bounce()
342 static void usdhi6_sg_prep(struct usdhi6_host *host) in usdhi6_sg_prep() argument
344 struct mmc_request *mrq = host->mrq; in usdhi6_sg_prep()
345 struct mmc_data *data = mrq->data; in usdhi6_sg_prep()
347 usdhi6_write(host, USDHI6_SD_SECCNT, data->blocks); in usdhi6_sg_prep()
349 host->sg = data->sg; in usdhi6_sg_prep()
351 host->offset = host->sg->offset; in usdhi6_sg_prep()
355 static void *usdhi6_sg_map(struct usdhi6_host *host) in usdhi6_sg_map() argument
357 struct mmc_data *data = host->mrq->data; in usdhi6_sg_map()
358 struct scatterlist *sg = data->sg_len > 1 ? host->sg : data->sg; in usdhi6_sg_map()
359 size_t head = PAGE_SIZE - sg->offset; in usdhi6_sg_map()
360 size_t blk_head = head % data->blksz; in usdhi6_sg_map()
362 WARN(host->pg.page, "%p not properly unmapped!\n", host->pg.page); in usdhi6_sg_map()
363 if (WARN(sg_dma_len(sg) % data->blksz, in usdhi6_sg_map()
365 sg_dma_len(sg), data->blksz)) in usdhi6_sg_map()
368 host->pg.page = sg_page(sg); in usdhi6_sg_map()
369 host->pg.mapped = kmap(host->pg.page); in usdhi6_sg_map()
370 host->offset = sg->offset; in usdhi6_sg_map()
373 * Block size must be a power of 2 for multi-block transfers, in usdhi6_sg_map()
376 host->head_len = blk_head; in usdhi6_sg_map()
378 if (head < data->blksz) in usdhi6_sg_map()
383 usdhi6_blk_bounce(host, sg); in usdhi6_sg_map()
385 host->blk_page = host->pg.mapped; in usdhi6_sg_map()
387 dev_dbg(mmc_dev(host->mmc), "Mapped %p (%lx) at %p + %u for CMD%u @ 0x%p\n", in usdhi6_sg_map()
388 host->pg.page, page_to_pfn(host->pg.page), host->pg.mapped, in usdhi6_sg_map()
389 sg->offset, host->mrq->cmd->opcode, host->mrq); in usdhi6_sg_map()
391 return host->blk_page + host->offset; in usdhi6_sg_map()
395 static void usdhi6_sg_unmap(struct usdhi6_host *host, bool force) in usdhi6_sg_unmap() argument
397 struct mmc_data *data = host->mrq->data; in usdhi6_sg_unmap()
398 struct page *page = host->head_pg.page; in usdhi6_sg_unmap()
401 /* Previous block was cross-page boundary */ in usdhi6_sg_unmap()
402 struct scatterlist *sg = data->sg_len > 1 ? in usdhi6_sg_unmap()
403 host->sg : data->sg; in usdhi6_sg_unmap()
404 size_t blk_head = host->head_len; in usdhi6_sg_unmap()
406 if (!data->error && data->flags & MMC_DATA_READ) { in usdhi6_sg_unmap()
407 memcpy(host->head_pg.mapped + PAGE_SIZE - blk_head, in usdhi6_sg_unmap()
408 host->bounce_buf, blk_head); in usdhi6_sg_unmap()
409 memcpy(host->pg.mapped, host->bounce_buf + blk_head, in usdhi6_sg_unmap()
410 data->blksz - blk_head); in usdhi6_sg_unmap()
416 host->head_pg.page = NULL; in usdhi6_sg_unmap()
418 if (!force && sg_dma_len(sg) + sg->offset > in usdhi6_sg_unmap()
419 (host->page_idx << PAGE_SHIFT) + data->blksz - blk_head) in usdhi6_sg_unmap()
424 page = host->pg.page; in usdhi6_sg_unmap()
431 host->pg.page = NULL; in usdhi6_sg_unmap()
435 static void usdhi6_sg_advance(struct usdhi6_host *host) in usdhi6_sg_advance() argument
437 struct mmc_data *data = host->mrq->data; in usdhi6_sg_advance()
441 if (host->head_pg.page) { in usdhi6_sg_advance()
442 /* Finished a cross-page block, jump to the new page */ in usdhi6_sg_advance()
443 host->page_idx++; in usdhi6_sg_advance()
444 host->offset = data->blksz - host->head_len; in usdhi6_sg_advance()
445 host->blk_page = host->pg.mapped; in usdhi6_sg_advance()
446 usdhi6_sg_unmap(host, false); in usdhi6_sg_advance()
448 host->offset += data->blksz; in usdhi6_sg_advance()
450 if (host->offset == PAGE_SIZE) { in usdhi6_sg_advance()
452 host->offset = 0; in usdhi6_sg_advance()
453 host->page_idx++; in usdhi6_sg_advance()
458 * Now host->blk_page + host->offset point at the end of our last block in usdhi6_sg_advance()
459 * and host->page_idx is the index of the page, in which our new block in usdhi6_sg_advance()
463 done = (host->page_idx << PAGE_SHIFT) + host->offset; in usdhi6_sg_advance()
464 total = host->sg->offset + sg_dma_len(host->sg); in usdhi6_sg_advance()
466 dev_dbg(mmc_dev(host->mmc), "%s(): %zu of %zu @ %zu\n", __func__, in usdhi6_sg_advance()
467 done, total, host->offset); in usdhi6_sg_advance()
469 if (done < total && host->offset) { in usdhi6_sg_advance()
471 if (host->offset + data->blksz > PAGE_SIZE) in usdhi6_sg_advance()
473 usdhi6_blk_bounce(host, host->sg); in usdhi6_sg_advance()
479 usdhi6_sg_unmap(host, false); in usdhi6_sg_advance()
487 struct scatterlist *next = sg_next(host->sg); in usdhi6_sg_advance()
489 host->page_idx = 0; in usdhi6_sg_advance()
492 host->wait = USDHI6_WAIT_FOR_DATA_END; in usdhi6_sg_advance()
493 host->sg = next; in usdhi6_sg_advance()
495 if (WARN(next && sg_dma_len(next) % data->blksz, in usdhi6_sg_advance()
497 sg_dma_len(next), data->blksz)) in usdhi6_sg_advance()
498 data->error = -EINVAL; in usdhi6_sg_advance()
506 host->pg.page = nth_page(sg_page(host->sg), host->page_idx); in usdhi6_sg_advance()
507 host->pg.mapped = kmap(host->pg.page); in usdhi6_sg_advance()
508 host->blk_page = host->pg.mapped; in usdhi6_sg_advance()
510 dev_dbg(mmc_dev(host->mmc), "Mapped %p (%lx) at %p for CMD%u @ 0x%p\n", in usdhi6_sg_advance()
511 host->pg.page, page_to_pfn(host->pg.page), host->pg.mapped, in usdhi6_sg_advance()
512 host->mrq->cmd->opcode, host->mrq); in usdhi6_sg_advance()
517 static void usdhi6_dma_release(struct usdhi6_host *host) in usdhi6_dma_release() argument
519 host->dma_active = false; in usdhi6_dma_release()
520 if (host->chan_tx) { in usdhi6_dma_release()
521 struct dma_chan *chan = host->chan_tx; in usdhi6_dma_release()
522 host->chan_tx = NULL; in usdhi6_dma_release()
525 if (host->chan_rx) { in usdhi6_dma_release()
526 struct dma_chan *chan = host->chan_rx; in usdhi6_dma_release()
527 host->chan_rx = NULL; in usdhi6_dma_release()
532 static void usdhi6_dma_stop_unmap(struct usdhi6_host *host) in usdhi6_dma_stop_unmap() argument
534 struct mmc_data *data = host->mrq->data; in usdhi6_dma_stop_unmap()
536 if (!host->dma_active) in usdhi6_dma_stop_unmap()
539 usdhi6_write(host, USDHI6_CC_EXT_MODE, 0); in usdhi6_dma_stop_unmap()
540 host->dma_active = false; in usdhi6_dma_stop_unmap()
542 if (data->flags & MMC_DATA_READ) in usdhi6_dma_stop_unmap()
543 dma_unmap_sg(host->chan_rx->device->dev, data->sg, in usdhi6_dma_stop_unmap()
544 data->sg_len, DMA_FROM_DEVICE); in usdhi6_dma_stop_unmap()
546 dma_unmap_sg(host->chan_tx->device->dev, data->sg, in usdhi6_dma_stop_unmap()
547 data->sg_len, DMA_TO_DEVICE); in usdhi6_dma_stop_unmap()
552 struct usdhi6_host *host = arg; in usdhi6_dma_complete() local
553 struct mmc_request *mrq = host->mrq; in usdhi6_dma_complete()
555 if (WARN(!mrq || !mrq->data, "%s: NULL data in DMA completion for %p!\n", in usdhi6_dma_complete()
556 dev_name(mmc_dev(host->mmc)), mrq)) in usdhi6_dma_complete()
559 dev_dbg(mmc_dev(host->mmc), "%s(): CMD%u DMA completed\n", __func__, in usdhi6_dma_complete()
560 mrq->cmd->opcode); in usdhi6_dma_complete()
562 usdhi6_dma_stop_unmap(host); in usdhi6_dma_complete()
563 usdhi6_wait_for_brwe(host, mrq->data->flags & MMC_DATA_READ); in usdhi6_dma_complete()
566 static int usdhi6_dma_setup(struct usdhi6_host *host, struct dma_chan *chan, in usdhi6_dma_setup() argument
569 struct mmc_data *data = host->mrq->data; in usdhi6_dma_setup()
570 struct scatterlist *sg = data->sg; in usdhi6_dma_setup()
572 dma_cookie_t cookie = -EINVAL; in usdhi6_dma_setup()
584 return -EINVAL; in usdhi6_dma_setup()
587 ret = dma_map_sg(chan->device->dev, sg, data->sg_len, data_dir); in usdhi6_dma_setup()
589 host->dma_active = true; in usdhi6_dma_setup()
595 desc->callback = usdhi6_dma_complete; in usdhi6_dma_setup()
596 desc->callback_param = host; in usdhi6_dma_setup()
600 dev_dbg(mmc_dev(host->mmc), "%s(): mapped %d -> %d, cookie %d @ %p\n", in usdhi6_dma_setup()
601 __func__, data->sg_len, ret, cookie, desc); in usdhi6_dma_setup()
607 usdhi6_dma_release(host); in usdhi6_dma_setup()
608 dev_warn(mmc_dev(host->mmc), in usdhi6_dma_setup()
615 static int usdhi6_dma_start(struct usdhi6_host *host) in usdhi6_dma_start() argument
617 if (!host->chan_rx || !host->chan_tx) in usdhi6_dma_start()
618 return -ENODEV; in usdhi6_dma_start()
620 if (host->mrq->data->flags & MMC_DATA_READ) in usdhi6_dma_start()
621 return usdhi6_dma_setup(host, host->chan_rx, DMA_DEV_TO_MEM); in usdhi6_dma_start()
623 return usdhi6_dma_setup(host, host->chan_tx, DMA_MEM_TO_DEV); in usdhi6_dma_start()
626 static void usdhi6_dma_kill(struct usdhi6_host *host) in usdhi6_dma_kill() argument
628 struct mmc_data *data = host->mrq->data; in usdhi6_dma_kill()
630 dev_dbg(mmc_dev(host->mmc), "%s(): SG of %u: %ux%u\n", in usdhi6_dma_kill()
631 __func__, data->sg_len, data->blocks, data->blksz); in usdhi6_dma_kill()
633 if (data->flags & MMC_DATA_READ) in usdhi6_dma_kill()
634 dmaengine_terminate_sync(host->chan_rx); in usdhi6_dma_kill()
636 dmaengine_terminate_sync(host->chan_tx); in usdhi6_dma_kill()
639 static void usdhi6_dma_check_error(struct usdhi6_host *host) in usdhi6_dma_check_error() argument
641 struct mmc_data *data = host->mrq->data; in usdhi6_dma_check_error()
643 dev_dbg(mmc_dev(host->mmc), "%s(): IO error %d, status 0x%x\n", in usdhi6_dma_check_error()
644 __func__, host->io_error, usdhi6_read(host, USDHI6_SD_INFO1)); in usdhi6_dma_check_error()
646 if (host->io_error) { in usdhi6_dma_check_error()
647 data->error = usdhi6_error_code(host); in usdhi6_dma_check_error()
648 data->bytes_xfered = 0; in usdhi6_dma_check_error()
649 usdhi6_dma_kill(host); in usdhi6_dma_check_error()
650 usdhi6_dma_release(host); in usdhi6_dma_check_error()
651 dev_warn(mmc_dev(host->mmc), in usdhi6_dma_check_error()
652 "DMA failed: %d, falling back to PIO\n", data->error); in usdhi6_dma_check_error()
661 if (host->irq_status & USDHI6_SD_INFO1_RSP_END) in usdhi6_dma_check_error()
662 dev_warn(mmc_dev(host->mmc), "Unexpected response received!\n"); in usdhi6_dma_check_error()
665 static void usdhi6_dma_kick(struct usdhi6_host *host) in usdhi6_dma_kick() argument
667 if (host->mrq->data->flags & MMC_DATA_READ) in usdhi6_dma_kick()
668 dma_async_issue_pending(host->chan_rx); in usdhi6_dma_kick()
670 dma_async_issue_pending(host->chan_tx); in usdhi6_dma_kick()
673 static void usdhi6_dma_request(struct usdhi6_host *host, phys_addr_t start) in usdhi6_dma_request() argument
681 host->chan_tx = dma_request_chan(mmc_dev(host->mmc), "tx"); in usdhi6_dma_request()
682 dev_dbg(mmc_dev(host->mmc), "%s: TX: got channel %p\n", __func__, in usdhi6_dma_request()
683 host->chan_tx); in usdhi6_dma_request()
685 if (IS_ERR(host->chan_tx)) { in usdhi6_dma_request()
686 host->chan_tx = NULL; in usdhi6_dma_request()
694 ret = dmaengine_slave_config(host->chan_tx, &cfg); in usdhi6_dma_request()
698 host->chan_rx = dma_request_chan(mmc_dev(host->mmc), "rx"); in usdhi6_dma_request()
699 dev_dbg(mmc_dev(host->mmc), "%s: RX: got channel %p\n", __func__, in usdhi6_dma_request()
700 host->chan_rx); in usdhi6_dma_request()
702 if (IS_ERR(host->chan_rx)) { in usdhi6_dma_request()
703 host->chan_rx = NULL; in usdhi6_dma_request()
711 ret = dmaengine_slave_config(host->chan_rx, &cfg); in usdhi6_dma_request()
718 dma_release_channel(host->chan_rx); in usdhi6_dma_request()
719 host->chan_rx = NULL; in usdhi6_dma_request()
721 dma_release_channel(host->chan_tx); in usdhi6_dma_request()
722 host->chan_tx = NULL; in usdhi6_dma_request()
727 static void usdhi6_clk_set(struct usdhi6_host *host, struct mmc_ios *ios) in usdhi6_clk_set() argument
729 unsigned long rate = ios->clock; in usdhi6_clk_set()
733 for (i = 1000; i; i--) { in usdhi6_clk_set()
734 if (usdhi6_read(host, USDHI6_SD_INFO2) & USDHI6_SD_INFO2_SCLKDIVEN) in usdhi6_clk_set()
740 dev_err(mmc_dev(host->mmc), "SD bus busy, clock set aborted\n"); in usdhi6_clk_set()
744 val = usdhi6_read(host, USDHI6_SD_CLK_CTRL) & ~USDHI6_SD_CLK_CTRL_DIV_MASK; in usdhi6_clk_set()
749 if (host->imclk <= rate) { in usdhi6_clk_set()
750 if (ios->timing != MMC_TIMING_UHS_DDR50) { in usdhi6_clk_set()
751 /* Cannot have 1-to-1 clock in DDR mode */ in usdhi6_clk_set()
752 new_rate = host->imclk; in usdhi6_clk_set()
755 new_rate = host->imclk / 2; in usdhi6_clk_set()
759 roundup_pow_of_two(DIV_ROUND_UP(host->imclk, rate)); in usdhi6_clk_set()
761 new_rate = host->imclk / div; in usdhi6_clk_set()
764 if (host->rate == new_rate) in usdhi6_clk_set()
767 host->rate = new_rate; in usdhi6_clk_set()
769 dev_dbg(mmc_dev(host->mmc), "target %lu, div %u, set %lu\n", in usdhi6_clk_set()
777 if (host->imclk == rate || host->imclk == host->rate || !rate) in usdhi6_clk_set()
778 usdhi6_write(host, USDHI6_SD_CLK_CTRL, in usdhi6_clk_set()
782 host->rate = 0; in usdhi6_clk_set()
786 usdhi6_write(host, USDHI6_SD_CLK_CTRL, val); in usdhi6_clk_set()
788 if (host->imclk == rate || host->imclk == host->rate || in usdhi6_clk_set()
790 usdhi6_write(host, USDHI6_SD_CLK_CTRL, in usdhi6_clk_set()
794 static void usdhi6_set_power(struct usdhi6_host *host, struct mmc_ios *ios) in usdhi6_set_power() argument
796 struct mmc_host *mmc = host->mmc; in usdhi6_set_power() local
798 if (!IS_ERR(mmc->supply.vmmc)) in usdhi6_set_power()
800 mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, in usdhi6_set_power()
801 ios->power_mode ? ios->vdd : 0); in usdhi6_set_power()
804 static int usdhi6_reset(struct usdhi6_host *host) in usdhi6_reset() argument
808 usdhi6_write(host, USDHI6_SOFT_RST, USDHI6_SOFT_RST_RESERVED); in usdhi6_reset()
810 usdhi6_write(host, USDHI6_SOFT_RST, USDHI6_SOFT_RST_RESERVED | USDHI6_SOFT_RST_RESET); in usdhi6_reset()
811 for (i = 1000; i; i--) in usdhi6_reset()
812 if (usdhi6_read(host, USDHI6_SOFT_RST) & USDHI6_SOFT_RST_RESET) in usdhi6_reset()
815 return i ? 0 : -ETIMEDOUT; in usdhi6_reset()
818 static void usdhi6_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) in usdhi6_set_ios() argument
820 struct usdhi6_host *host = mmc_priv(mmc); in usdhi6_set_ios() local
824 dev_dbg(mmc_dev(mmc), "%uHz, OCR: %u, power %u, bus-width %u, timing %u\n", in usdhi6_set_ios()
825 ios->clock, ios->vdd, ios->power_mode, ios->bus_width, ios->timing); in usdhi6_set_ios()
827 switch (ios->power_mode) { in usdhi6_set_ios()
829 usdhi6_set_power(host, ios); in usdhi6_set_ios()
830 usdhi6_only_cd(host); in usdhi6_set_ios()
837 ret = usdhi6_reset(host); in usdhi6_set_ios()
839 dev_err(mmc_dev(mmc), "Cannot reset the interface!\n"); in usdhi6_set_ios()
841 usdhi6_set_power(host, ios); in usdhi6_set_ios()
842 usdhi6_only_cd(host); in usdhi6_set_ios()
846 option = usdhi6_read(host, USDHI6_SD_OPTION); in usdhi6_set_ios()
852 if (ios->bus_width == MMC_BUS_WIDTH_1) { in usdhi6_set_ios()
853 if (ios->timing == MMC_TIMING_UHS_DDR50) in usdhi6_set_ios()
854 dev_err(mmc_dev(mmc), in usdhi6_set_ios()
860 mode = ios->timing == MMC_TIMING_UHS_DDR50; in usdhi6_set_ios()
862 usdhi6_write(host, USDHI6_SD_OPTION, option); in usdhi6_set_ios()
863 usdhi6_write(host, USDHI6_SDIF_MODE, mode); in usdhi6_set_ios()
867 if (host->rate != ios->clock) in usdhi6_set_ios()
868 usdhi6_clk_set(host, ios); in usdhi6_set_ios()
872 static void usdhi6_timeout_set(struct usdhi6_host *host) in usdhi6_timeout_set() argument
874 struct mmc_request *mrq = host->mrq; in usdhi6_timeout_set()
878 if (!mrq->data) in usdhi6_timeout_set()
879 ticks = host->rate / 1000 * mrq->cmd->busy_timeout; in usdhi6_timeout_set()
881 ticks = host->rate / 1000000 * (mrq->data->timeout_ns / 1000) + in usdhi6_timeout_set()
882 mrq->data->timeout_clks; in usdhi6_timeout_set()
891 val = order_base_2(ticks) - 13; in usdhi6_timeout_set()
893 dev_dbg(mmc_dev(host->mmc), "Set %s timeout %lu ticks @ %lu Hz\n", in usdhi6_timeout_set()
894 mrq->data ? "data" : "cmd", ticks, host->rate); in usdhi6_timeout_set()
897 usdhi6_write(host, USDHI6_SD_OPTION, (val << USDHI6_SD_OPTION_TIMEOUT_SHIFT) | in usdhi6_timeout_set()
898 (usdhi6_read(host, USDHI6_SD_OPTION) & ~USDHI6_SD_OPTION_TIMEOUT_MASK)); in usdhi6_timeout_set()
901 static void usdhi6_request_done(struct usdhi6_host *host) in usdhi6_request_done() argument
903 struct mmc_request *mrq = host->mrq; in usdhi6_request_done()
904 struct mmc_data *data = mrq->data; in usdhi6_request_done()
906 if (WARN(host->pg.page || host->head_pg.page, in usdhi6_request_done()
908 host->pg.page, host->head_pg.page, host->wait, mrq->cmd->opcode, in usdhi6_request_done()
909 data ? (data->flags & MMC_DATA_READ ? 'R' : 'W') : '-', in usdhi6_request_done()
910 data ? host->offset : 0, data ? data->blocks : 0, in usdhi6_request_done()
911 data ? data->blksz : 0, data ? data->sg_len : 0)) in usdhi6_request_done()
912 usdhi6_sg_unmap(host, true); in usdhi6_request_done()
914 if (mrq->cmd->error || in usdhi6_request_done()
915 (data && data->error) || in usdhi6_request_done()
916 (mrq->stop && mrq->stop->error)) in usdhi6_request_done()
917 dev_dbg(mmc_dev(host->mmc), "%s(CMD%d: %ux%u): err %d %d %d\n", in usdhi6_request_done()
918 __func__, mrq->cmd->opcode, data ? data->blocks : 0, in usdhi6_request_done()
919 data ? data->blksz : 0, in usdhi6_request_done()
920 mrq->cmd->error, in usdhi6_request_done()
921 data ? data->error : 1, in usdhi6_request_done()
922 mrq->stop ? mrq->stop->error : 1); in usdhi6_request_done()
925 usdhi6_write(host, USDHI6_CC_EXT_MODE, 0); in usdhi6_request_done()
926 host->wait = USDHI6_WAIT_FOR_REQUEST; in usdhi6_request_done()
927 host->mrq = NULL; in usdhi6_request_done()
929 mmc_request_done(host->mmc, mrq); in usdhi6_request_done()
932 static int usdhi6_cmd_flags(struct usdhi6_host *host) in usdhi6_cmd_flags() argument
934 struct mmc_request *mrq = host->mrq; in usdhi6_cmd_flags()
935 struct mmc_command *cmd = mrq->cmd; in usdhi6_cmd_flags()
936 u16 opc = cmd->opcode; in usdhi6_cmd_flags()
938 if (host->app_cmd) { in usdhi6_cmd_flags()
939 host->app_cmd = false; in usdhi6_cmd_flags()
943 if (mrq->data) { in usdhi6_cmd_flags()
946 if (mrq->data->flags & MMC_DATA_READ) in usdhi6_cmd_flags()
949 if (cmd->opcode == MMC_READ_MULTIPLE_BLOCK || in usdhi6_cmd_flags()
950 cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK || in usdhi6_cmd_flags()
951 (cmd->opcode == SD_IO_RW_EXTENDED && in usdhi6_cmd_flags()
952 mrq->data->blocks > 1)) { in usdhi6_cmd_flags()
954 if (!mrq->stop) in usdhi6_cmd_flags()
975 dev_warn(mmc_dev(host->mmc), in usdhi6_cmd_flags()
978 return -EINVAL; in usdhi6_cmd_flags()
985 static int usdhi6_rq_start(struct usdhi6_host *host) in usdhi6_rq_start() argument
987 struct mmc_request *mrq = host->mrq; in usdhi6_rq_start()
988 struct mmc_command *cmd = mrq->cmd; in usdhi6_rq_start()
989 struct mmc_data *data = mrq->data; in usdhi6_rq_start()
990 int opc = usdhi6_cmd_flags(host); in usdhi6_rq_start()
996 for (i = 1000; i; i--) { in usdhi6_rq_start()
997 if (!(usdhi6_read(host, USDHI6_SD_INFO2) & USDHI6_SD_INFO2_CBSY)) in usdhi6_rq_start()
1003 dev_dbg(mmc_dev(host->mmc), "Command active, request aborted\n"); in usdhi6_rq_start()
1004 return -EAGAIN; in usdhi6_rq_start()
1011 host->page_idx = 0; in usdhi6_rq_start()
1013 if (cmd->opcode == SD_IO_RW_EXTENDED && data->blocks > 1) { in usdhi6_rq_start()
1014 switch (data->blksz) { in usdhi6_rq_start()
1021 if (mrq->stop) in usdhi6_rq_start()
1022 ret = -EINVAL; in usdhi6_rq_start()
1025 ret = -EINVAL; in usdhi6_rq_start()
1027 } else if ((cmd->opcode == MMC_READ_MULTIPLE_BLOCK || in usdhi6_rq_start()
1028 cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) && in usdhi6_rq_start()
1029 data->blksz != 512) { in usdhi6_rq_start()
1030 ret = -EINVAL; in usdhi6_rq_start()
1034 dev_warn(mmc_dev(host->mmc), "%s(): %u blocks of %u bytes\n", in usdhi6_rq_start()
1035 __func__, data->blocks, data->blksz); in usdhi6_rq_start()
1036 return -EINVAL; in usdhi6_rq_start()
1039 if (cmd->opcode == MMC_READ_MULTIPLE_BLOCK || in usdhi6_rq_start()
1040 cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK || in usdhi6_rq_start()
1041 (cmd->opcode == SD_IO_RW_EXTENDED && in usdhi6_rq_start()
1042 data->blocks > 1)) in usdhi6_rq_start()
1043 usdhi6_sg_prep(host); in usdhi6_rq_start()
1045 usdhi6_write(host, USDHI6_SD_SIZE, data->blksz); in usdhi6_rq_start()
1047 if ((data->blksz >= USDHI6_MIN_DMA || in usdhi6_rq_start()
1048 data->blocks > 1) && in usdhi6_rq_start()
1049 (data->blksz % 4 || in usdhi6_rq_start()
1050 data->sg->offset % 4)) in usdhi6_rq_start()
1051 dev_dbg(mmc_dev(host->mmc), in usdhi6_rq_start()
1052 "Bad SG of %u: %ux%u @ %u\n", data->sg_len, in usdhi6_rq_start()
1053 data->blksz, data->blocks, data->sg->offset); in usdhi6_rq_start()
1056 use_dma = data->blksz >= USDHI6_MIN_DMA && in usdhi6_rq_start()
1057 !(data->blksz % 4) && in usdhi6_rq_start()
1058 usdhi6_dma_start(host) >= DMA_MIN_COOKIE; in usdhi6_rq_start()
1061 usdhi6_write(host, USDHI6_CC_EXT_MODE, USDHI6_CC_EXT_MODE_SDRW); in usdhi6_rq_start()
1063 dev_dbg(mmc_dev(host->mmc), in usdhi6_rq_start()
1065 __func__, cmd->opcode, data->blocks, data->blksz, in usdhi6_rq_start()
1066 data->sg_len, use_dma ? "DMA" : "PIO", in usdhi6_rq_start()
1067 data->flags & MMC_DATA_READ ? "read" : "write", in usdhi6_rq_start()
1068 data->sg->offset, mrq->stop ? " + stop" : ""); in usdhi6_rq_start()
1070 dev_dbg(mmc_dev(host->mmc), "%s(): request opcode %u\n", in usdhi6_rq_start()
1071 __func__, cmd->opcode); in usdhi6_rq_start()
1075 usdhi6_wait_for_resp(host); in usdhi6_rq_start()
1077 host->wait = USDHI6_WAIT_FOR_CMD; in usdhi6_rq_start()
1078 schedule_delayed_work(&host->timeout_work, host->timeout); in usdhi6_rq_start()
1081 usdhi6_write(host, USDHI6_SD_STOP, in usdhi6_rq_start()
1082 data && data->blocks > 1 ? USDHI6_SD_STOP_SEC : 0); in usdhi6_rq_start()
1083 usdhi6_write(host, USDHI6_SD_ARG, cmd->arg); in usdhi6_rq_start()
1086 usdhi6_write(host, USDHI6_SD_CMD, opc); in usdhi6_rq_start()
1091 static void usdhi6_request(struct mmc_host *mmc, struct mmc_request *mrq) in usdhi6_request() argument
1093 struct usdhi6_host *host = mmc_priv(mmc); in usdhi6_request() local
1096 cancel_delayed_work_sync(&host->timeout_work); in usdhi6_request()
1098 host->mrq = mrq; in usdhi6_request()
1099 host->sg = NULL; in usdhi6_request()
1101 usdhi6_timeout_set(host); in usdhi6_request()
1102 ret = usdhi6_rq_start(host); in usdhi6_request()
1104 mrq->cmd->error = ret; in usdhi6_request()
1105 usdhi6_request_done(host); in usdhi6_request()
1109 static int usdhi6_get_cd(struct mmc_host *mmc) in usdhi6_get_cd() argument
1111 struct usdhi6_host *host = mmc_priv(mmc); in usdhi6_get_cd() local
1113 u32 status = usdhi6_read(host, USDHI6_SD_INFO1) & USDHI6_SD_INFO1_CD; in usdhi6_get_cd()
1122 return !status ^ !(mmc->caps2 & MMC_CAP2_CD_ACTIVE_HIGH); in usdhi6_get_cd()
1125 static int usdhi6_get_ro(struct mmc_host *mmc) in usdhi6_get_ro() argument
1127 struct usdhi6_host *host = mmc_priv(mmc); in usdhi6_get_ro() local
1129 u32 status = usdhi6_read(host, USDHI6_SD_INFO1) & USDHI6_SD_INFO1_WP; in usdhi6_get_ro()
1132 * level status.WP RO_ACTIVE_HIGH card read-only in usdhi6_get_ro()
1138 return !status ^ !(mmc->caps2 & MMC_CAP2_RO_ACTIVE_HIGH); in usdhi6_get_ro()
1141 static void usdhi6_enable_sdio_irq(struct mmc_host *mmc, int enable) in usdhi6_enable_sdio_irq() argument
1143 struct usdhi6_host *host = mmc_priv(mmc); in usdhi6_enable_sdio_irq() local
1145 dev_dbg(mmc_dev(mmc), "%s(): %sable\n", __func__, enable ? "en" : "dis"); in usdhi6_enable_sdio_irq()
1148 host->sdio_mask = USDHI6_SDIO_INFO1_IRQ & ~USDHI6_SDIO_INFO1_IOIRQ; in usdhi6_enable_sdio_irq()
1149 usdhi6_write(host, USDHI6_SDIO_INFO1_MASK, host->sdio_mask); in usdhi6_enable_sdio_irq()
1150 usdhi6_write(host, USDHI6_SDIO_MODE, 1); in usdhi6_enable_sdio_irq()
1152 usdhi6_write(host, USDHI6_SDIO_MODE, 0); in usdhi6_enable_sdio_irq()
1153 usdhi6_write(host, USDHI6_SDIO_INFO1_MASK, USDHI6_SDIO_INFO1_IRQ); in usdhi6_enable_sdio_irq()
1154 host->sdio_mask = USDHI6_SDIO_INFO1_IRQ; in usdhi6_enable_sdio_irq()
1158 static int usdhi6_set_pinstates(struct usdhi6_host *host, int voltage) in usdhi6_set_pinstates() argument
1160 if (IS_ERR(host->pins_uhs)) in usdhi6_set_pinstates()
1166 return pinctrl_select_state(host->pinctrl, in usdhi6_set_pinstates()
1167 host->pins_uhs); in usdhi6_set_pinstates()
1170 return pinctrl_select_default_state(mmc_dev(host->mmc)); in usdhi6_set_pinstates()
1174 static int usdhi6_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) in usdhi6_sig_volt_switch() argument
1178 ret = mmc_regulator_set_vqmmc(mmc, ios); in usdhi6_sig_volt_switch()
1182 ret = usdhi6_set_pinstates(mmc_priv(mmc), ios->signal_voltage); in usdhi6_sig_volt_switch()
1184 dev_warn_once(mmc_dev(mmc), in usdhi6_sig_volt_switch()
1189 static int usdhi6_card_busy(struct mmc_host *mmc) in usdhi6_card_busy() argument
1191 struct usdhi6_host *host = mmc_priv(mmc); in usdhi6_card_busy() local
1192 u32 tmp = usdhi6_read(host, USDHI6_SD_INFO2); in usdhi6_card_busy()
1210 static void usdhi6_resp_cmd12(struct usdhi6_host *host) in usdhi6_resp_cmd12() argument
1212 struct mmc_command *cmd = host->mrq->stop; in usdhi6_resp_cmd12()
1213 cmd->resp[0] = usdhi6_read(host, USDHI6_SD_RSP10); in usdhi6_resp_cmd12()
1216 static void usdhi6_resp_read(struct usdhi6_host *host) in usdhi6_resp_read() argument
1218 struct mmc_command *cmd = host->mrq->cmd; in usdhi6_resp_read()
1219 u32 *rsp = cmd->resp, tmp = 0; in usdhi6_resp_read()
1223 * RSP10 39-8 in usdhi6_resp_read()
1224 * RSP32 71-40 in usdhi6_resp_read()
1225 * RSP54 103-72 in usdhi6_resp_read()
1226 * RSP76 127-104 in usdhi6_resp_read()
1227 * R2-type response: in usdhi6_resp_read()
1239 if (!(host->irq_status & USDHI6_SD_INFO1_RSP_END)) { in usdhi6_resp_read()
1240 dev_err(mmc_dev(host->mmc), in usdhi6_resp_read()
1241 "CMD%d: response expected but is missing!\n", cmd->opcode); in usdhi6_resp_read()
1248 rsp[3 - i] = tmp >> 24; in usdhi6_resp_read()
1249 tmp = usdhi6_read(host, USDHI6_SD_RSP10 + i * 8); in usdhi6_resp_read()
1250 rsp[3 - i] |= tmp << 8; in usdhi6_resp_read()
1252 else if (cmd->opcode == MMC_READ_MULTIPLE_BLOCK || in usdhi6_resp_read()
1253 cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) in usdhi6_resp_read()
1255 rsp[0] = usdhi6_read(host, USDHI6_SD_RSP54); in usdhi6_resp_read()
1257 rsp[0] = usdhi6_read(host, USDHI6_SD_RSP10); in usdhi6_resp_read()
1259 dev_dbg(mmc_dev(host->mmc), "Response 0x%x\n", rsp[0]); in usdhi6_resp_read()
1262 static int usdhi6_blk_read(struct usdhi6_host *host) in usdhi6_blk_read() argument
1264 struct mmc_data *data = host->mrq->data; in usdhi6_blk_read()
1268 if (host->io_error) { in usdhi6_blk_read()
1269 data->error = usdhi6_error_code(host); in usdhi6_blk_read()
1273 if (host->pg.page) { in usdhi6_blk_read()
1274 p = host->blk_page + host->offset; in usdhi6_blk_read()
1276 p = usdhi6_sg_map(host); in usdhi6_blk_read()
1278 data->error = -ENOMEM; in usdhi6_blk_read()
1283 for (i = 0; i < data->blksz / 4; i++, p++) in usdhi6_blk_read()
1284 *p = usdhi6_read(host, USDHI6_SD_BUF0); in usdhi6_blk_read()
1286 rest = data->blksz % 4; in usdhi6_blk_read()
1288 u16 d = usdhi6_read16(host, USDHI6_SD_BUF0); in usdhi6_blk_read()
1297 dev_dbg(mmc_dev(host->mmc), "%s(): %d\n", __func__, data->error); in usdhi6_blk_read()
1298 host->wait = USDHI6_WAIT_FOR_REQUEST; in usdhi6_blk_read()
1299 return data->error; in usdhi6_blk_read()
1302 static int usdhi6_blk_write(struct usdhi6_host *host) in usdhi6_blk_write() argument
1304 struct mmc_data *data = host->mrq->data; in usdhi6_blk_write()
1308 if (host->io_error) { in usdhi6_blk_write()
1309 data->error = usdhi6_error_code(host); in usdhi6_blk_write()
1313 if (host->pg.page) { in usdhi6_blk_write()
1314 p = host->blk_page + host->offset; in usdhi6_blk_write()
1316 p = usdhi6_sg_map(host); in usdhi6_blk_write()
1318 data->error = -ENOMEM; in usdhi6_blk_write()
1323 for (i = 0; i < data->blksz / 4; i++, p++) in usdhi6_blk_write()
1324 usdhi6_write(host, USDHI6_SD_BUF0, *p); in usdhi6_blk_write()
1326 rest = data->blksz % 4; in usdhi6_blk_write()
1334 usdhi6_write16(host, USDHI6_SD_BUF0, d); in usdhi6_blk_write()
1340 dev_dbg(mmc_dev(host->mmc), "%s(): %d\n", __func__, data->error); in usdhi6_blk_write()
1341 host->wait = USDHI6_WAIT_FOR_REQUEST; in usdhi6_blk_write()
1342 return data->error; in usdhi6_blk_write()
1345 static int usdhi6_stop_cmd(struct usdhi6_host *host) in usdhi6_stop_cmd() argument
1347 struct mmc_request *mrq = host->mrq; in usdhi6_stop_cmd()
1349 switch (mrq->cmd->opcode) { in usdhi6_stop_cmd()
1352 if (mrq->stop->opcode == MMC_STOP_TRANSMISSION) { in usdhi6_stop_cmd()
1353 host->wait = USDHI6_WAIT_FOR_STOP; in usdhi6_stop_cmd()
1358 dev_err(mmc_dev(host->mmc), in usdhi6_stop_cmd()
1360 mrq->stop->opcode, mrq->cmd->opcode); in usdhi6_stop_cmd()
1361 mrq->stop->error = -EOPNOTSUPP; in usdhi6_stop_cmd()
1364 return -EOPNOTSUPP; in usdhi6_stop_cmd()
1367 static bool usdhi6_end_cmd(struct usdhi6_host *host) in usdhi6_end_cmd() argument
1369 struct mmc_request *mrq = host->mrq; in usdhi6_end_cmd()
1370 struct mmc_command *cmd = mrq->cmd; in usdhi6_end_cmd()
1372 if (host->io_error) { in usdhi6_end_cmd()
1373 cmd->error = usdhi6_error_code(host); in usdhi6_end_cmd()
1377 usdhi6_resp_read(host); in usdhi6_end_cmd()
1379 if (!mrq->data) in usdhi6_end_cmd()
1382 if (host->dma_active) { in usdhi6_end_cmd()
1383 usdhi6_dma_kick(host); in usdhi6_end_cmd()
1384 if (!mrq->stop) in usdhi6_end_cmd()
1385 host->wait = USDHI6_WAIT_FOR_DMA; in usdhi6_end_cmd()
1386 else if (usdhi6_stop_cmd(host) < 0) in usdhi6_end_cmd()
1388 } else if (mrq->data->flags & MMC_DATA_READ) { in usdhi6_end_cmd()
1389 if (cmd->opcode == MMC_READ_MULTIPLE_BLOCK || in usdhi6_end_cmd()
1390 (cmd->opcode == SD_IO_RW_EXTENDED && in usdhi6_end_cmd()
1391 mrq->data->blocks > 1)) in usdhi6_end_cmd()
1392 host->wait = USDHI6_WAIT_FOR_MREAD; in usdhi6_end_cmd()
1394 host->wait = USDHI6_WAIT_FOR_READ; in usdhi6_end_cmd()
1396 if (cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK || in usdhi6_end_cmd()
1397 (cmd->opcode == SD_IO_RW_EXTENDED && in usdhi6_end_cmd()
1398 mrq->data->blocks > 1)) in usdhi6_end_cmd()
1399 host->wait = USDHI6_WAIT_FOR_MWRITE; in usdhi6_end_cmd()
1401 host->wait = USDHI6_WAIT_FOR_WRITE; in usdhi6_end_cmd()
1407 static bool usdhi6_read_block(struct usdhi6_host *host) in usdhi6_read_block() argument
1410 int ret = usdhi6_blk_read(host); in usdhi6_read_block()
1414 * cross-page, in which case for single-block IO host->page_idx == 0. in usdhi6_read_block()
1417 usdhi6_sg_unmap(host, true); in usdhi6_read_block()
1422 host->wait = USDHI6_WAIT_FOR_DATA_END; in usdhi6_read_block()
1426 static bool usdhi6_mread_block(struct usdhi6_host *host) in usdhi6_mread_block() argument
1428 int ret = usdhi6_blk_read(host); in usdhi6_mread_block()
1433 usdhi6_sg_advance(host); in usdhi6_mread_block()
1435 return !host->mrq->data->error && in usdhi6_mread_block()
1436 (host->wait != USDHI6_WAIT_FOR_DATA_END || !host->mrq->stop); in usdhi6_mread_block()
1439 static bool usdhi6_write_block(struct usdhi6_host *host) in usdhi6_write_block() argument
1441 int ret = usdhi6_blk_write(host); in usdhi6_write_block()
1444 usdhi6_sg_unmap(host, true); in usdhi6_write_block()
1449 host->wait = USDHI6_WAIT_FOR_DATA_END; in usdhi6_write_block()
1453 static bool usdhi6_mwrite_block(struct usdhi6_host *host) in usdhi6_mwrite_block() argument
1455 int ret = usdhi6_blk_write(host); in usdhi6_mwrite_block()
1460 usdhi6_sg_advance(host); in usdhi6_mwrite_block()
1462 return !host->mrq->data->error && in usdhi6_mwrite_block()
1463 (host->wait != USDHI6_WAIT_FOR_DATA_END || !host->mrq->stop); in usdhi6_mwrite_block()
1470 struct usdhi6_host *host = dev_id; in usdhi6_sd_bh() local
1476 cancel_delayed_work_sync(&host->timeout_work); in usdhi6_sd_bh()
1478 mrq = host->mrq; in usdhi6_sd_bh()
1482 cmd = mrq->cmd; in usdhi6_sd_bh()
1483 data = mrq->data; in usdhi6_sd_bh()
1485 switch (host->wait) { in usdhi6_sd_bh()
1491 io_wait = usdhi6_end_cmd(host); in usdhi6_sd_bh()
1495 io_wait = usdhi6_mread_block(host); in usdhi6_sd_bh()
1499 io_wait = usdhi6_read_block(host); in usdhi6_sd_bh()
1503 io_wait = usdhi6_mwrite_block(host); in usdhi6_sd_bh()
1507 io_wait = usdhi6_write_block(host); in usdhi6_sd_bh()
1510 usdhi6_dma_check_error(host); in usdhi6_sd_bh()
1513 usdhi6_write(host, USDHI6_SD_STOP, 0); in usdhi6_sd_bh()
1514 if (host->io_error) { in usdhi6_sd_bh()
1515 int ret = usdhi6_error_code(host); in usdhi6_sd_bh()
1516 if (mrq->stop) in usdhi6_sd_bh()
1517 mrq->stop->error = ret; in usdhi6_sd_bh()
1519 mrq->data->error = ret; in usdhi6_sd_bh()
1520 dev_warn(mmc_dev(host->mmc), "%s(): %d\n", __func__, ret); in usdhi6_sd_bh()
1523 usdhi6_resp_cmd12(host); in usdhi6_sd_bh()
1524 mrq->stop->error = 0; in usdhi6_sd_bh()
1527 if (host->io_error) { in usdhi6_sd_bh()
1528 mrq->data->error = usdhi6_error_code(host); in usdhi6_sd_bh()
1529 dev_warn(mmc_dev(host->mmc), "%s(): %d\n", __func__, in usdhi6_sd_bh()
1530 mrq->data->error); in usdhi6_sd_bh()
1534 cmd->error = -EFAULT; in usdhi6_sd_bh()
1535 dev_err(mmc_dev(host->mmc), "Invalid state %u\n", host->wait); in usdhi6_sd_bh()
1536 usdhi6_request_done(host); in usdhi6_sd_bh()
1541 schedule_delayed_work(&host->timeout_work, host->timeout); in usdhi6_sd_bh()
1543 if (!host->dma_active) in usdhi6_sd_bh()
1544 usdhi6_wait_for_brwe(host, mrq->data->flags & MMC_DATA_READ); in usdhi6_sd_bh()
1548 if (!cmd->error) { in usdhi6_sd_bh()
1550 if (!data->error) { in usdhi6_sd_bh()
1551 if (host->wait != USDHI6_WAIT_FOR_STOP && in usdhi6_sd_bh()
1552 host->mrq->stop && in usdhi6_sd_bh()
1553 !host->mrq->stop->error && in usdhi6_sd_bh()
1554 !usdhi6_stop_cmd(host)) { in usdhi6_sd_bh()
1556 usdhi6_wait_for_resp(host); in usdhi6_sd_bh()
1558 schedule_delayed_work(&host->timeout_work, in usdhi6_sd_bh()
1559 host->timeout); in usdhi6_sd_bh()
1564 data->bytes_xfered = data->blocks * data->blksz; in usdhi6_sd_bh()
1567 dev_warn(mmc_dev(host->mmc), "%s(): data error %d\n", in usdhi6_sd_bh()
1568 __func__, data->error); in usdhi6_sd_bh()
1569 usdhi6_sg_unmap(host, true); in usdhi6_sd_bh()
1571 } else if (cmd->opcode == MMC_APP_CMD) { in usdhi6_sd_bh()
1572 host->app_cmd = true; in usdhi6_sd_bh()
1576 usdhi6_request_done(host); in usdhi6_sd_bh()
1583 struct usdhi6_host *host = dev_id; in usdhi6_sd() local
1586 status = usdhi6_read(host, USDHI6_SD_INFO1) & ~host->status_mask & in usdhi6_sd()
1588 status2 = usdhi6_read(host, USDHI6_SD_INFO2) & ~host->status2_mask; in usdhi6_sd()
1590 usdhi6_only_cd(host); in usdhi6_sd()
1592 dev_dbg(mmc_dev(host->mmc), in usdhi6_sd()
1602 usdhi6_write(host, USDHI6_SD_INFO1, in usdhi6_sd()
1610 usdhi6_write(host, USDHI6_SD_INFO2, in usdhi6_sd()
1614 host->io_error = error; in usdhi6_sd()
1615 host->irq_status = status; in usdhi6_sd()
1619 if (host->wait != USDHI6_WAIT_FOR_CMD || in usdhi6_sd()
1621 dev_warn(mmc_dev(host->mmc), in usdhi6_sd()
1625 dev_dbg(mmc_dev(host->mmc), in usdhi6_sd()
1635 struct usdhi6_host *host = dev_id; in usdhi6_sdio() local
1636 u32 status = usdhi6_read(host, USDHI6_SDIO_INFO1) & ~host->sdio_mask; in usdhi6_sdio()
1638 dev_dbg(mmc_dev(host->mmc), "%s(): status 0x%x\n", __func__, status); in usdhi6_sdio()
1643 usdhi6_write(host, USDHI6_SDIO_INFO1, ~status); in usdhi6_sdio()
1645 mmc_signal_sdio_irq(host->mmc); in usdhi6_sdio()
1652 struct usdhi6_host *host = dev_id; in usdhi6_cd() local
1653 struct mmc_host *mmc = host->mmc; in usdhi6_cd() local
1657 status = usdhi6_read(host, USDHI6_SD_INFO1) & ~host->status_mask & in usdhi6_cd()
1664 usdhi6_write(host, USDHI6_SD_INFO1, ~status); in usdhi6_cd()
1666 if (!work_pending(&mmc->detect.work) && in usdhi6_cd()
1668 !mmc->card) || in usdhi6_cd()
1670 mmc->card))) in usdhi6_cd()
1671 mmc_detect_change(mmc, msecs_to_jiffies(100)); in usdhi6_cd()
1677 * Actually this should not be needed, if the built-in timeout works reliably in
1684 struct usdhi6_host *host = container_of(d, struct usdhi6_host, timeout_work); in usdhi6_timeout_work() local
1685 struct mmc_request *mrq = host->mrq; in usdhi6_timeout_work()
1686 struct mmc_data *data = mrq ? mrq->data : NULL; in usdhi6_timeout_work()
1689 dev_warn(mmc_dev(host->mmc), in usdhi6_timeout_work()
1691 host->dma_active ? "DMA" : "PIO", in usdhi6_timeout_work()
1692 host->wait, mrq ? mrq->cmd->opcode : -1, in usdhi6_timeout_work()
1693 usdhi6_read(host, USDHI6_SD_INFO1), in usdhi6_timeout_work()
1694 usdhi6_read(host, USDHI6_SD_INFO2), host->irq_status); in usdhi6_timeout_work()
1696 if (host->dma_active) { in usdhi6_timeout_work()
1697 usdhi6_dma_kill(host); in usdhi6_timeout_work()
1698 usdhi6_dma_stop_unmap(host); in usdhi6_timeout_work()
1701 switch (host->wait) { in usdhi6_timeout_work()
1703 dev_err(mmc_dev(host->mmc), "Invalid state %u\n", host->wait); in usdhi6_timeout_work()
1706 usdhi6_error_code(host); in usdhi6_timeout_work()
1708 mrq->cmd->error = -ETIMEDOUT; in usdhi6_timeout_work()
1711 usdhi6_error_code(host); in usdhi6_timeout_work()
1712 mrq->stop->error = -ETIMEDOUT; in usdhi6_timeout_work()
1719 sg = host->sg ?: data->sg; in usdhi6_timeout_work()
1720 dev_dbg(mmc_dev(host->mmc), in usdhi6_timeout_work()
1722 data->flags & MMC_DATA_READ ? 'R' : 'W', host->page_idx, in usdhi6_timeout_work()
1723 host->offset, data->blocks, data->blksz, data->sg_len, in usdhi6_timeout_work()
1724 sg_dma_len(sg), sg->offset); in usdhi6_timeout_work()
1725 usdhi6_sg_unmap(host, true); in usdhi6_timeout_work()
1728 usdhi6_error_code(host); in usdhi6_timeout_work()
1729 data->error = -ETIMEDOUT; in usdhi6_timeout_work()
1733 usdhi6_request_done(host); in usdhi6_timeout_work()
1746 struct device *dev = &pdev->dev; in usdhi6_probe()
1747 struct mmc_host *mmc; in usdhi6_probe() local
1748 struct usdhi6_host *host; in usdhi6_probe() local
1754 if (!dev->of_node) in usdhi6_probe()
1755 return -ENODEV; in usdhi6_probe()
1765 mmc = mmc_alloc_host(sizeof(struct usdhi6_host), dev); in usdhi6_probe()
1766 if (!mmc) in usdhi6_probe()
1767 return -ENOMEM; in usdhi6_probe()
1769 ret = mmc_regulator_get_supply(mmc); in usdhi6_probe()
1773 ret = mmc_of_parse(mmc); in usdhi6_probe()
1777 host = mmc_priv(mmc); in usdhi6_probe()
1778 host->mmc = mmc; in usdhi6_probe()
1779 host->wait = USDHI6_WAIT_FOR_REQUEST; in usdhi6_probe()
1780 host->timeout = msecs_to_jiffies(USDHI6_REQ_TIMEOUT_MS); in usdhi6_probe()
1783 * future improvement should instead respect the cmd->busy_timeout. in usdhi6_probe()
1785 mmc->max_busy_timeout = USDHI6_REQ_TIMEOUT_MS; in usdhi6_probe()
1787 host->pinctrl = devm_pinctrl_get(&pdev->dev); in usdhi6_probe()
1788 if (IS_ERR(host->pinctrl)) { in usdhi6_probe()
1789 ret = PTR_ERR(host->pinctrl); in usdhi6_probe()
1793 host->pins_uhs = pinctrl_lookup_state(host->pinctrl, "state_uhs"); in usdhi6_probe()
1795 host->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); in usdhi6_probe()
1796 if (IS_ERR(host->base)) { in usdhi6_probe()
1797 ret = PTR_ERR(host->base); in usdhi6_probe()
1801 host->clk = devm_clk_get(dev, NULL); in usdhi6_probe()
1802 if (IS_ERR(host->clk)) { in usdhi6_probe()
1803 ret = PTR_ERR(host->clk); in usdhi6_probe()
1807 host->imclk = clk_get_rate(host->clk); in usdhi6_probe()
1809 ret = clk_prepare_enable(host->clk); in usdhi6_probe()
1813 version = usdhi6_read(host, USDHI6_VERSION); in usdhi6_probe()
1815 ret = -EPERM; in usdhi6_probe()
1820 dev_info(dev, "A USDHI6ROL0 SD host detected with %d ports\n", in usdhi6_probe()
1821 usdhi6_read(host, USDHI6_SD_PORT_SEL) >> USDHI6_SD_PORT_SEL_PORTS_SHIFT); in usdhi6_probe()
1823 usdhi6_mask_all(host); in usdhi6_probe()
1827 dev_name(dev), host); in usdhi6_probe()
1831 mmc->caps |= MMC_CAP_NEEDS_POLL; in usdhi6_probe()
1835 dev_name(dev), host); in usdhi6_probe()
1840 dev_name(dev), host); in usdhi6_probe()
1844 INIT_DELAYED_WORK(&host->timeout_work, usdhi6_timeout_work); in usdhi6_probe()
1846 usdhi6_dma_request(host, res->start); in usdhi6_probe()
1848 mmc->ops = &usdhi6_ops; in usdhi6_probe()
1849 mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | in usdhi6_probe()
1852 mmc->max_segs = 32; in usdhi6_probe()
1853 mmc->max_blk_size = 512; in usdhi6_probe()
1854 mmc->max_req_size = PAGE_SIZE * mmc->max_segs; in usdhi6_probe()
1855 mmc->max_blk_count = mmc->max_req_size / mmc->max_blk_size; in usdhi6_probe()
1857 * Setting .max_seg_size to 1 page would simplify our page-mapping code, in usdhi6_probe()
1861 * run-time and we fall back to PIO, we will continue getting large in usdhi6_probe()
1864 mmc->max_seg_size = mmc->max_req_size; in usdhi6_probe()
1865 if (!mmc->f_max) in usdhi6_probe()
1866 mmc->f_max = host->imclk; in usdhi6_probe()
1867 mmc->f_min = host->imclk / 512; in usdhi6_probe()
1869 platform_set_drvdata(pdev, host); in usdhi6_probe()
1871 ret = mmc_add_host(mmc); in usdhi6_probe()
1878 usdhi6_dma_release(host); in usdhi6_probe()
1880 clk_disable_unprepare(host->clk); in usdhi6_probe()
1882 mmc_free_host(mmc); in usdhi6_probe()
1889 struct usdhi6_host *host = platform_get_drvdata(pdev); in usdhi6_remove() local
1891 mmc_remove_host(host->mmc); in usdhi6_remove()
1893 usdhi6_mask_all(host); in usdhi6_remove()
1894 cancel_delayed_work_sync(&host->timeout_work); in usdhi6_remove()
1895 usdhi6_dma_release(host); in usdhi6_remove()
1896 clk_disable_unprepare(host->clk); in usdhi6_remove()
1897 mmc_free_host(host->mmc); in usdhi6_remove()
1912 MODULE_DESCRIPTION("Renesas usdhi6rol0 SD/SDIO host driver");