From 4438592c920bbfdf3c584aa51779f1a84526eb72 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 5 Oct 2022 13:19:38 +0300 Subject: mmc: sdhci: Remove local_irq_{save,restore}() around k[un]map_atomic() A long time ago the kmap_atomic API required a slot to be provided which risked the possibility that other code might use the same slot at the same time. Disabling interrupts prevented the possibility of an interrupt handler doing that. However, that went away with commit 3e4d3af501cc ("mm: stack based kmap_atomic()"). When the second argument to kmap_atomic was removed by commit 482fce997e14 ("mmc: remove the second argument of k[un]map_atomic()"), local_irq_{save,restore}() should have been removed also. Remove it now. Signed-off-by: Adrian Hunter Link: https://lore.kernel.org/r/20221005101951.3165-2-adrian.hunter@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index c7ad32a75b57..1db67a6e431e 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -706,16 +706,14 @@ static int sdhci_pre_dma_transfer(struct sdhci_host *host, return sg_count; } -static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags) +static char *sdhci_kmap_atomic(struct scatterlist *sg) { - local_irq_save(*flags); return kmap_atomic(sg_page(sg)) + sg->offset; } -static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags) +static void sdhci_kunmap_atomic(void *buffer) { kunmap_atomic(buffer); - local_irq_restore(*flags); } void sdhci_adma_write_desc(struct sdhci_host *host, void **desc, @@ -757,7 +755,6 @@ static void sdhci_adma_table_pre(struct sdhci_host *host, struct mmc_data *data, int sg_count) { struct scatterlist *sg; - unsigned long flags; dma_addr_t addr, align_addr; void *desc, *align; char *buffer; @@ -789,9 +786,9 @@ static void sdhci_adma_table_pre(struct sdhci_host *host, SDHCI_ADMA2_MASK; if (offset) { if (data->flags & MMC_DATA_WRITE) { - buffer = sdhci_kmap_atomic(sg, &flags); + buffer = sdhci_kmap_atomic(sg); memcpy(align, buffer, offset); - sdhci_kunmap_atomic(buffer, &flags); + sdhci_kunmap_atomic(buffer); } /* tran, valid */ @@ -852,7 +849,6 @@ static void sdhci_adma_table_post(struct sdhci_host *host, int i, size; void *align; char *buffer; - unsigned long flags; if (data->flags & MMC_DATA_READ) { bool has_unaligned = false; @@ -875,9 +871,9 @@ static void sdhci_adma_table_post(struct sdhci_host *host, size = SDHCI_ADMA2_ALIGN - (sg_dma_address(sg) & SDHCI_ADMA2_MASK); - buffer = sdhci_kmap_atomic(sg, &flags); + buffer = sdhci_kmap_atomic(sg); memcpy(buffer, align, size); - sdhci_kunmap_atomic(buffer, &flags); + sdhci_kunmap_atomic(buffer); align += SDHCI_ADMA2_ALIGN; } -- cgit v1.2.3 From e467c154f748b9fd1b3cbff685b58091b532c90e Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 5 Oct 2022 13:19:39 +0300 Subject: mmc: sdhci: Remove local_irq_{save,restore}() around sg_miter_{next,stop}() sg_miter_next() using an sg_mapping_iter with flag SG_MITER_ATOMIC uses kmap_atomic() to map pages. A long time ago the kmap_atomic API required a slot to be provided which risked the possibility that other code might use the same slot at the same time. Disabling interrupts prevented the possibility of an interrupt handler doing that. However, that went away with commit 3e4d3af501cc ("mm: stack based kmap_atomic()"). Remove local_irq_{save,restore}() around sg_miter_{next,stop}(). Signed-off-by: Adrian Hunter Link: https://lore.kernel.org/r/20221005101951.3165-3-adrian.hunter@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1db67a6e431e..a14cc08e5318 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -526,7 +526,6 @@ static inline bool sdhci_has_requests(struct sdhci_host *host) static void sdhci_read_block_pio(struct sdhci_host *host) { - unsigned long flags; size_t blksize, len, chunk; u32 scratch; u8 *buf; @@ -536,8 +535,6 @@ static void sdhci_read_block_pio(struct sdhci_host *host) blksize = host->data->blksz; chunk = 0; - local_irq_save(flags); - while (blksize) { BUG_ON(!sg_miter_next(&host->sg_miter)); @@ -564,13 +561,10 @@ static void sdhci_read_block_pio(struct sdhci_host *host) } sg_miter_stop(&host->sg_miter); - - local_irq_restore(flags); } static void sdhci_write_block_pio(struct sdhci_host *host) { - unsigned long flags; size_t blksize, len, chunk; u32 scratch; u8 *buf; @@ -581,8 +575,6 @@ static void sdhci_write_block_pio(struct sdhci_host *host) chunk = 0; scratch = 0; - local_irq_save(flags); - while (blksize) { BUG_ON(!sg_miter_next(&host->sg_miter)); @@ -609,8 +601,6 @@ static void sdhci_write_block_pio(struct sdhci_host *host) } sg_miter_stop(&host->sg_miter); - - local_irq_restore(flags); } static void sdhci_transfer_pio(struct sdhci_host *host) -- cgit v1.2.3 From 47722e3fd92482c036be43a4ba62698c8b8b63b8 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 5 Oct 2022 13:19:40 +0300 Subject: mmc: sdhci: Replace kmap_atomic() with kmap_local_page() kmap_local_page() is equivalent to kmap_atomic() except that it does not disable page faults or preemption. Where possible kmap_local_page() is preferred to kmap_atomic() - refer kernel highmem documentation. In this case, there is no need to disable page faults or preemption, so replace kmap_atomic() with kmap_local_page(), and, correspondingly, kunmap_atomic() with kunmap_local(). Signed-off-by: Adrian Hunter Link: https://lore.kernel.org/r/20221005101951.3165-4-adrian.hunter@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index a14cc08e5318..ebb71d235c38 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -698,12 +698,12 @@ static int sdhci_pre_dma_transfer(struct sdhci_host *host, static char *sdhci_kmap_atomic(struct scatterlist *sg) { - return kmap_atomic(sg_page(sg)) + sg->offset; + return kmap_local_page(sg_page(sg)) + sg->offset; } static void sdhci_kunmap_atomic(void *buffer) { - kunmap_atomic(buffer); + kunmap_local(buffer); } void sdhci_adma_write_desc(struct sdhci_host *host, void **desc, -- cgit v1.2.3 From 8ff683f6a293650a7fa5025f41a164987b585f07 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 5 Oct 2022 13:19:41 +0300 Subject: mmc: bcm2835: Remove local_irq_{save,restore}() around k[un]map_atomic() A long time ago the kmap_atomic API required a slot to be provided which risked the possibility that other code might use the same slot at the same time. Disabling interrupts prevented the possibility of an interrupt handler doing that. However, that went away with commit 3e4d3af501cc ("mm: stack based kmap_atomic()"). Unfortunately, that unnecessary pattern of code has been copied since and persists in bcm2385.c. Remove it. Signed-off-by: Adrian Hunter Link: https://lore.kernel.org/r/20221005101951.3165-5-adrian.hunter@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/bcm2835.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c index 641ab4f42125..49acbfa87ab8 100644 --- a/drivers/mmc/host/bcm2835.c +++ b/drivers/mmc/host/bcm2835.c @@ -1068,7 +1068,6 @@ static void bcm2835_dma_complete_work(struct work_struct *work) } if (host->drain_words) { - unsigned long flags; void *page; u32 *buf; @@ -1076,7 +1075,6 @@ static void bcm2835_dma_complete_work(struct work_struct *work) host->drain_page += host->drain_offset >> PAGE_SHIFT; host->drain_offset &= ~PAGE_MASK; } - local_irq_save(flags); page = kmap_atomic(host->drain_page); buf = page + host->drain_offset; @@ -1089,7 +1087,6 @@ static void bcm2835_dma_complete_work(struct work_struct *work) } kunmap_atomic(page); - local_irq_restore(flags); } bcm2835_finish_data(host); -- cgit v1.2.3 From e9c9722220057d19d80478c0edda3fbf237a73f7 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 5 Oct 2022 13:19:42 +0300 Subject: mmc: bcm2835: Remove local_irq_{save,restore}() around sg_miter_{next,stop}() sg_miter_next() using an sg_mapping_iter with flag SG_MITER_ATOMIC uses kmap_atomic() to map pages. A long time ago the kmap_atomic API required a slot to be provided which risked the possibility that other code might use the same slot at the same time. Disabling interrupts prevented the possibility of an interrupt handler doing that. However, that went away with commit 3e4d3af501cc ("mm: stack based kmap_atomic()"). Remove local_irq_{save,restore}() around sg_miter_{next,stop}(). Signed-off-by: Adrian Hunter Link: https://lore.kernel.org/r/20221005101951.3165-6-adrian.hunter@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/bcm2835.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c index 49acbfa87ab8..440773e3ba55 100644 --- a/drivers/mmc/host/bcm2835.c +++ b/drivers/mmc/host/bcm2835.c @@ -327,7 +327,6 @@ static void bcm2835_dma_complete(void *param) static void bcm2835_transfer_block_pio(struct bcm2835_host *host, bool is_read) { - unsigned long flags; size_t blksize; unsigned long wait_max; @@ -335,8 +334,6 @@ static void bcm2835_transfer_block_pio(struct bcm2835_host *host, bool is_read) wait_max = jiffies + msecs_to_jiffies(500); - local_irq_save(flags); - while (blksize) { int copy_words; u32 hsts = 0; @@ -421,8 +418,6 @@ static void bcm2835_transfer_block_pio(struct bcm2835_host *host, bool is_read) } sg_miter_stop(&host->sg_miter); - - local_irq_restore(flags); } static void bcm2835_transfer_pio(struct bcm2835_host *host) -- cgit v1.2.3 From 07e23c14e1d341fa350a6f0659c6ac84544bb7c4 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 5 Oct 2022 13:19:43 +0300 Subject: mmc: bcm2835: Replace kmap_atomic() with kmap_local_page() kmap_local_page() is equivalent to kmap_atomic() except that it does not disable page faults or preemption. Where possible kmap_local_page() is preferred to kmap_atomic() - refer kernel highmem documentation. In this case, there is no need to disable page faults or preemption, so replace kmap_atomic() with kmap_local_page(), and, correspondingly, kunmap_atomic() with kunmap_local(). Signed-off-by: Adrian Hunter Link: https://lore.kernel.org/r/20221005101951.3165-7-adrian.hunter@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/bcm2835.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c index 440773e3ba55..8648f7e63ca1 100644 --- a/drivers/mmc/host/bcm2835.c +++ b/drivers/mmc/host/bcm2835.c @@ -1070,7 +1070,7 @@ static void bcm2835_dma_complete_work(struct work_struct *work) host->drain_page += host->drain_offset >> PAGE_SHIFT; host->drain_offset &= ~PAGE_MASK; } - page = kmap_atomic(host->drain_page); + page = kmap_local_page(host->drain_page); buf = page + host->drain_offset; while (host->drain_words) { @@ -1081,7 +1081,7 @@ static void bcm2835_dma_complete_work(struct work_struct *work) host->drain_words--; } - kunmap_atomic(page); + kunmap_local(page); } bcm2835_finish_data(host); -- cgit v1.2.3 From 1550217a8b448008d9f590ffe46e1fc3caa3160d Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 5 Oct 2022 13:19:44 +0300 Subject: mmc: mmc_test: Remove local_irq_{save,restore}() around sg_copy_{from,to}_buffer() sg_copy_{from,to}_buffer() call sg_copy_buffer() which uses an sg_mapping_iter with flag SG_MITER_ATOMIC, so then sg_miter_next() uses kmap_atomic() to map pages. A long time ago the kmap_atomic API required a slot to be provided which risked the possibility that other code might use the same slot at the same time. Disabling interrupts prevented the possibility of an interrupt handler doing that. However, that went away with commit 3e4d3af501cc ("mm: stack based kmap_atomic()"). Remove local_irq_{save,restore}() around sg_copy_{from,to}_buffer(). Signed-off-by: Adrian Hunter Link: https://lore.kernel.org/r/20221005101951.3165-8-adrian.hunter@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc_test.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c index 155ce2bdfe62..156d34b2ed4d 100644 --- a/drivers/mmc/core/mmc_test.c +++ b/drivers/mmc/core/mmc_test.c @@ -932,7 +932,6 @@ static int mmc_test_transfer(struct mmc_test_card *test, unsigned blocks, unsigned blksz, int write) { int ret, i; - unsigned long flags; if (write) { for (i = 0; i < blocks * blksz; i++) @@ -940,9 +939,7 @@ static int mmc_test_transfer(struct mmc_test_card *test, } else { memset(test->scratch, 0, BUFFER_SIZE); } - local_irq_save(flags); sg_copy_from_buffer(sg, sg_len, test->scratch, BUFFER_SIZE); - local_irq_restore(flags); ret = mmc_test_set_blksize(test, blksz); if (ret) @@ -987,9 +984,7 @@ static int mmc_test_transfer(struct mmc_test_card *test, return RESULT_FAIL; } } else { - local_irq_save(flags); sg_copy_to_buffer(sg, sg_len, test->scratch, BUFFER_SIZE); - local_irq_restore(flags); for (i = 0; i < blocks * blksz; i++) { if (test->scratch[i] != (u8)i) return RESULT_FAIL; -- cgit v1.2.3 From b7093c10967e732236bcc5b2e8ba5fc87b5a57a8 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 5 Oct 2022 13:19:45 +0300 Subject: mmc: tifm_sd: Remove local_irq_{save,restore}() around tifm_sd_transfer_data() tifm_sd_transfer_data() calls functions that ultimate use kmap_atomic() to map pages. A long time ago the kmap_atomic API required a slot to be provided which risked the possibility that other code might use the same slot at the same time. Disabling interrupts prevented the possibility of an interrupt handler doing that. However, that went away with commit 3e4d3af501cc ("mm: stack based kmap_atomic()"). When the second argument to kmap_atomic was removed by commit 482fce997e14 ("mmc: remove the second argument of k[un]map_atomic()"), local_irq_{save,restore}() should have been removed also. Remove it now. Signed-off-by: Adrian Hunter Link: https://lore.kernel.org/r/20221005101951.3165-9-adrian.hunter@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/tifm_sd.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index 63917070b1a7..ed1685add446 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -506,7 +506,6 @@ static void tifm_sd_card_event(struct tifm_dev *sock) unsigned int host_status = 0; int cmd_error = 0; struct mmc_command *cmd = NULL; - unsigned long flags; spin_lock(&sock->lock); host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock)); @@ -570,9 +569,7 @@ static void tifm_sd_card_event(struct tifm_dev *sock) if (host_status & (TIFM_MMCSD_AE | TIFM_MMCSD_AF | TIFM_MMCSD_BRS)) { - local_irq_save(flags); tifm_sd_transfer_data(host); - local_irq_restore(flags); host_status &= ~TIFM_MMCSD_AE; } } -- cgit v1.2.3 From 36bbdc3096e160ffe0ba93053e6e11a98ef14691 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 5 Oct 2022 13:19:46 +0300 Subject: mmc: tifm_sd: Remove local_irq_{save,restore}() around tifm_sd_bounce_block() tifm_sd_bounce_block() calls functions that ultimate use kmap_atomic() to map pages. A long time ago the kmap_atomic API required a slot to be provided which risked the possibility that other code might use the same slot at the same time. Disabling interrupts prevented the possibility of an interrupt handler doing that. However, that went away with commit 3e4d3af501cc ("mm: stack based kmap_atomic()"). When the second argument to kmap_atomic was removed by commit 482fce997e14 ("mmc: remove the second argument of k[un]map_atomic()"), local_irq_{save,restore}() should have been removed also. Remove it now. Signed-off-by: Adrian Hunter Link: https://lore.kernel.org/r/20221005101951.3165-10-adrian.hunter@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/tifm_sd.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index ed1685add446..d539f9b48422 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -264,16 +264,13 @@ static int tifm_sd_set_dma_data(struct tifm_sd *host, struct mmc_data *r_data) unsigned int t_size = TIFM_DMA_TSIZE * r_data->blksz; unsigned int dma_len, dma_blk_cnt, dma_off; struct scatterlist *sg = NULL; - unsigned long flags; if (host->sg_pos == host->sg_len) return 1; if (host->cmd_flags & DATA_CARRY) { host->cmd_flags &= ~DATA_CARRY; - local_irq_save(flags); tifm_sd_bounce_block(host, r_data); - local_irq_restore(flags); if (host->sg_pos == host->sg_len) return 1; } @@ -300,11 +297,9 @@ static int tifm_sd_set_dma_data(struct tifm_sd *host, struct mmc_data *r_data) if (dma_blk_cnt) sg = &r_data->sg[host->sg_pos]; else if (dma_len) { - if (r_data->flags & MMC_DATA_WRITE) { - local_irq_save(flags); + if (r_data->flags & MMC_DATA_WRITE) tifm_sd_bounce_block(host, r_data); - local_irq_restore(flags); - } else + else host->cmd_flags |= DATA_CARRY; sg = &host->bounce_buf; -- cgit v1.2.3 From 4526cdaf9df8bef093bb9a5b0db09a1978a811f8 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 5 Oct 2022 13:19:47 +0300 Subject: mmc: tifm_sd: Replace kmap_atomic() with kmap_local_page() kmap_local_page() is equivalent to kmap_atomic() except that it does not disable page faults or preemption. Where possible kmap_local_page() is preferred to kmap_atomic() - refer kernel highmem documentation. In this case, there is no need to disable page faults or preemption, so replace kmap_atomic() with kmap_local_page(), and, correspondingly, kunmap_atomic() with kunmap_local(). Signed-off-by: Adrian Hunter Link: https://lore.kernel.org/r/20221005101951.3165-11-adrian.hunter@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/tifm_sd.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index d539f9b48422..b5a2f2f25ad9 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -116,7 +116,7 @@ static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg, unsigned char *buf; unsigned int pos = 0, val; - buf = kmap_atomic(pg) + off; + buf = kmap_local_page(pg) + off; if (host->cmd_flags & DATA_CARRY) { buf[pos++] = host->bounce_buf_data[0]; host->cmd_flags &= ~DATA_CARRY; @@ -132,7 +132,7 @@ static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg, } buf[pos++] = (val >> 8) & 0xff; } - kunmap_atomic(buf - off); + kunmap_local(buf - off); } static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg, @@ -142,7 +142,7 @@ static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg, unsigned char *buf; unsigned int pos = 0, val; - buf = kmap_atomic(pg) + off; + buf = kmap_local_page(pg) + off; if (host->cmd_flags & DATA_CARRY) { val = host->bounce_buf_data[0] | ((buf[pos++] << 8) & 0xff00); writel(val, sock->addr + SOCK_MMCSD_DATA); @@ -159,7 +159,7 @@ static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg, val |= (buf[pos++] << 8) & 0xff00; writel(val, sock->addr + SOCK_MMCSD_DATA); } - kunmap_atomic(buf - off); + kunmap_local(buf - off); } static void tifm_sd_transfer_data(struct tifm_sd *host) @@ -210,13 +210,13 @@ static void tifm_sd_copy_page(struct page *dst, unsigned int dst_off, struct page *src, unsigned int src_off, unsigned int count) { - unsigned char *src_buf = kmap_atomic(src) + src_off; - unsigned char *dst_buf = kmap_atomic(dst) + dst_off; + unsigned char *src_buf = kmap_local_page(src) + src_off; + unsigned char *dst_buf = kmap_local_page(dst) + dst_off; memcpy(dst_buf, src_buf, count); - kunmap_atomic(dst_buf - dst_off); - kunmap_atomic(src_buf - src_off); + kunmap_local(dst_buf - dst_off); + kunmap_local(src_buf - src_off); } static void tifm_sd_bounce_block(struct tifm_sd *host, struct mmc_data *r_data) -- cgit v1.2.3 From 14c9825f968ccfe34cc606a87e374133feeed7ac Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 5 Oct 2022 13:19:48 +0300 Subject: mmc: tmio_mmc_core: Remove local_irq_{save,restore}() around k[un]map_atomic() A long time ago the kmap_atomic API required a slot to be provided which risked the possibility that other code might use the same slot at the same time. Disabling interrupts prevented the possibility of an interrupt handler doing that. However, that went away with commit 3e4d3af501cc ("mm: stack based kmap_atomic()"). When the second argument to kmap_atomic was removed by commit 482fce997e14 ("mmc: remove the second argument of k[un]map_atomic()"), local_irq_{save,restore}() should have been removed also. Remove it now. Signed-off-by: Adrian Hunter Reviewed-by: Wolfram Sang Link: https://lore.kernel.org/r/20221005101951.3165-12-adrian.hunter@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi_sys_dmac.c | 5 ++--- drivers/mmc/host/tmio_mmc.h | 7 ++----- drivers/mmc/host/tmio_mmc_core.c | 10 ++++------ 3 files changed, 8 insertions(+), 14 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c index 99e3426df702..e9cc6c15d229 100644 --- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c @@ -254,12 +254,11 @@ static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host) /* The only sg element can be unaligned, use our bounce buffer then */ if (!aligned) { - unsigned long flags; - void *sg_vaddr = tmio_mmc_kmap_atomic(sg, &flags); + void *sg_vaddr = tmio_mmc_kmap_atomic(sg); sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length); - tmio_mmc_kunmap_atomic(sg, &flags, sg_vaddr); + tmio_mmc_kunmap_atomic(sg, sg_vaddr); host->sg_ptr = &host->bounce_sg; sg = host->sg_ptr; } diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 501613c74406..22375790b57b 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -204,18 +204,15 @@ void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i); void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i); irqreturn_t tmio_mmc_irq(int irq, void *devid); -static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg, - unsigned long *flags) +static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg) { - local_irq_save(*flags); return kmap_atomic(sg_page(sg)) + sg->offset; } static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg, - unsigned long *flags, void *virt) + void *virt) { kunmap_atomic(virt - sg->offset); - local_irq_restore(*flags); } #ifdef CONFIG_PM diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index 437048bb8027..6d50c0dd53fe 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -412,7 +412,6 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) void *sg_virt; unsigned short *buf; unsigned int count; - unsigned long flags; if (host->dma_on) { pr_err("PIO IRQ in DMA mode!\n"); @@ -422,7 +421,7 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) return; } - sg_virt = tmio_mmc_kmap_atomic(host->sg_ptr, &flags); + sg_virt = tmio_mmc_kmap_atomic(host->sg_ptr); buf = (unsigned short *)(sg_virt + host->sg_off); count = host->sg_ptr->length - host->sg_off; @@ -437,7 +436,7 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) host->sg_off += count; - tmio_mmc_kunmap_atomic(host->sg_ptr, &flags, sg_virt); + tmio_mmc_kunmap_atomic(host->sg_ptr, sg_virt); if (host->sg_off == host->sg_ptr->length) tmio_mmc_next_sg(host); @@ -446,11 +445,10 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) static void tmio_mmc_check_bounce_buffer(struct tmio_mmc_host *host) { if (host->sg_ptr == &host->bounce_sg) { - unsigned long flags; - void *sg_vaddr = tmio_mmc_kmap_atomic(host->sg_orig, &flags); + void *sg_vaddr = tmio_mmc_kmap_atomic(host->sg_orig); memcpy(sg_vaddr, host->bounce_buf, host->bounce_sg.length); - tmio_mmc_kunmap_atomic(host->sg_orig, &flags, sg_vaddr); + tmio_mmc_kunmap_atomic(host->sg_orig, sg_vaddr); } } -- cgit v1.2.3 From 8e8d695fa567ab4d669cd04b8d655cb736c6ad87 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 5 Oct 2022 13:19:49 +0300 Subject: mmc: tmio_mmc_core: Replace kmap_atomic() with kmap_local_page() kmap_local_page() is equivalent to kmap_atomic() except that it does not disable page faults or preemption. Where possible kmap_local_page() is preferred to kmap_atomic() - refer kernel highmem documentation. In this case, there is no need to disable page faults or preemption, so replace kmap_atomic() with kmap_local_page(), and, correspondingly, kunmap_atomic() with kunmap_local(). Signed-off-by: Adrian Hunter Reviewed-by: Wolfram Sang Link: https://lore.kernel.org/r/20221005101951.3165-13-adrian.hunter@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/tmio_mmc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 22375790b57b..e36ff80108e6 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -206,13 +206,13 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid); static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg) { - return kmap_atomic(sg_page(sg)) + sg->offset; + return kmap_local_page(sg_page(sg)) + sg->offset; } static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg, void *virt) { - kunmap_atomic(virt - sg->offset); + kunmap_local(virt - sg->offset); } #ifdef CONFIG_PM -- cgit v1.2.3 From 2fc458f75e1c2e8b9b9a7f6a09698994fe10a7aa Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 5 Oct 2022 13:19:50 +0300 Subject: mmc: au1xmmc: Replace kmap_atomic() with kmap_local_page() kmap_local_page() is equivalent to kmap_atomic() except that it does not disable page faults or preemption. Where possible kmap_local_page() is preferred to kmap_atomic() - refer kernel highmem documentation. In this case, there is no need to disable page faults or preemption, so replace kmap_atomic() with kmap_local_page(), and, correspondingly, kunmap_atomic() with kunmap_local(). Signed-off-by: Adrian Hunter Link: https://lore.kernel.org/r/20221005101951.3165-14-adrian.hunter@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/au1xmmc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index c88b039dc9fb..82dd0ae40305 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -388,7 +388,7 @@ static void au1xmmc_send_pio(struct au1xmmc_host *host) /* This is the pointer to the data buffer */ sg = &data->sg[host->pio.index]; - sg_ptr = kmap_atomic(sg_page(sg)) + sg->offset + host->pio.offset; + sg_ptr = kmap_local_page(sg_page(sg)) + sg->offset + host->pio.offset; /* This is the space left inside the buffer */ sg_len = data->sg[host->pio.index].length - host->pio.offset; @@ -409,7 +409,7 @@ static void au1xmmc_send_pio(struct au1xmmc_host *host) __raw_writel((unsigned long)val, HOST_TXPORT(host)); wmb(); /* drain writebuffer */ } - kunmap_atomic(sg_ptr); + kunmap_local(sg_ptr); host->pio.len -= count; host->pio.offset += count; @@ -446,7 +446,7 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host) if (host->pio.index < host->dma.len) { sg = &data->sg[host->pio.index]; - sg_ptr = kmap_atomic(sg_page(sg)) + sg->offset + host->pio.offset; + sg_ptr = kmap_local_page(sg_page(sg)) + sg->offset + host->pio.offset; /* This is the space left inside the buffer */ sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset; @@ -488,7 +488,7 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host) sg_ptr[count] = (unsigned char)(val & 0xFF); } if (sg_ptr) - kunmap_atomic(sg_ptr); + kunmap_local(sg_ptr); host->pio.len -= count; host->pio.offset += count; -- cgit v1.2.3 From cdb1ad52703b52e95696c38408ee9e3cf514dc4b Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 5 Oct 2022 13:19:51 +0300 Subject: mmc: wbsd: Replace kmap_atomic() with kmap_local_page() kmap_local_page() is equivalent to kmap_atomic() except that it does not disable page faults or preemption. Where possible kmap_local_page() is preferred to kmap_atomic() - refer kernel highmem documentation. In this case, there is no need to disable page faults or preemption, so replace kmap_atomic() with kmap_local_page(), and, correspondingly, kunmap_atomic() with kunmap_local(). Signed-off-by: Adrian Hunter Link: https://lore.kernel.org/r/20221005101951.3165-15-adrian.hunter@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/wbsd.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index 67ecd342fe5f..2219144c166a 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -267,7 +267,7 @@ static inline int wbsd_next_sg(struct wbsd_host *host) static inline char *wbsd_map_sg(struct wbsd_host *host) { - return kmap_atomic(sg_page(host->cur_sg)) + host->cur_sg->offset; + return kmap_local_page(sg_page(host->cur_sg)) + host->cur_sg->offset; } static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data) @@ -439,7 +439,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host) * End of scatter list entry? */ if (host->remain == 0) { - kunmap_atomic(buffer); + kunmap_local(buffer); /* * Get next entry. Check if last. */ @@ -451,7 +451,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host) } } } - kunmap_atomic(buffer); + kunmap_local(buffer); /* * This is a very dirty hack to solve a @@ -505,7 +505,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host) * End of scatter list entry? */ if (host->remain == 0) { - kunmap_atomic(buffer); + kunmap_local(buffer); /* * Get next entry. Check if last. */ @@ -517,7 +517,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host) } } } - kunmap_atomic(buffer); + kunmap_local(buffer); /* * The controller stops sending interrupts for -- cgit v1.2.3 From 50bfe185c42a2199b65fc759cb1b2e6a0a915427 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 24 Oct 2022 11:17:59 -0700 Subject: mmc: sdhci-brcmstb: Allow building with COMPILE_TEST This driver is pretty simple, and it can be useful to build it (for validation purposes) without BMIPS or ARCH_BRCMSTB. It technically depends on CONFIG_OF to do anything useful at runtime, but it still works out OK for compile-testing using the !OF stubs. Signed-off-by: Brian Norris Acked-by: Florian Fainelli Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20221024181759.2355583-1-briannorris@chromium.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index fb1062a6394c..2df2000d16dc 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -1040,10 +1040,10 @@ config MMC_SDHCI_MICROCHIP_PIC32 config MMC_SDHCI_BRCMSTB tristate "Broadcom SDIO/SD/MMC support" - depends on ARCH_BRCMSTB || BMIPS_GENERIC + depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST depends on MMC_SDHCI_PLTFM select MMC_CQHCI - default y + default ARCH_BRCMSTB || BMIPS_GENERIC help This selects support for the SDIO/SD/MMC Host Controller on Broadcom STB SoCs. -- cgit v1.2.3 From d7a1830e3ebe065141b8d4781cd931a4128bc421 Mon Sep 17 00:00:00 2001 From: Giulio Benetti Date: Tue, 18 Oct 2022 01:56:00 +0200 Subject: mmc: sdhci-esdhc-imx: improve imxrt1050 data i.MXRT1050 usdhc is not affected by ESDHC_FLAG_ERR004536 so let's remove it. It supports ESDHC_FLAG_STD_TUNING and ESDHC_FLAG_HAVE_CAP1 so let's add them. Signed-off-by: Giulio Benetti Reviewed-by: Haibo Chen Link: https://lore.kernel.org/r/20221017235602.86250-3-giulio.benetti@benettiengineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-esdhc-imx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index ffeb5759830f..12bc466508cc 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -307,7 +307,8 @@ static struct esdhc_soc_data usdhc_imx7ulp_data = { | ESDHC_FLAG_STATE_LOST_IN_LPMODE, }; static struct esdhc_soc_data usdhc_imxrt1050_data = { - .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_HS200 | ESDHC_FLAG_ERR004536, + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING + | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200, }; static struct esdhc_soc_data usdhc_imx8qxp_data = { -- cgit v1.2.3 From 1ad0dcb984c51db655f38ed97bb88545fd55f407 Mon Sep 17 00:00:00 2001 From: wangjianli Date: Sat, 22 Oct 2022 14:22:37 +0800 Subject: mmc: host: Fix repeated words in comments Delete the redundant word 'the'. Signed-off-by: wangjianli Link: https://lore.kernel.org/r/20221022062237.10333-1-wangjianli@cdjrlc.com Link: https://lore.kernel.org/r/20221022062331.11395-1-wangjianli@cdjrlc.com Link: https://lore.kernel.org/r/20221022062505.13155-1-wangjianli@cdjrlc.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 2 +- drivers/mmc/host/sdhci-acpi.c | 2 +- drivers/mmc/host/sdhci-esdhc-imx.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index c78bbc22e0d1..d35607128322 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1363,7 +1363,7 @@ static void __dw_mci_start_request(struct dw_mci *host, * is just about to roll over. * * We do this whole thing under spinlock and only if the - * command hasn't already completed (indicating the the irq + * command hasn't already completed (indicating the irq * already ran so we don't want the timeout). */ spin_lock_irqsave(&host->irq_lock, irqflags); diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index 4cca4c90769b..bddfaba091a9 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -648,7 +648,7 @@ static int sdhci_acpi_emmc_amd_probe_slot(struct platform_device *pdev, * in reading a garbage value and using the wrong presets. * * Since HS400 and HS200 presets must be identical, we could - * instead use the the SDR104 preset register. + * instead use the SDR104 preset register. * * If the above issues are resolved we could remove this quirk for * firmware that that has valid presets (i.e., SDR12 <= 12 MHz). diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 12bc466508cc..9f7eea4f948f 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -1455,7 +1455,7 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) /* * On i.MX8MM, we are running Dual Linux OS, with 1st Linux using SD Card - * as rootfs storage, 2nd Linux using eMMC as rootfs storage. We let the + * as rootfs storage, 2nd Linux using eMMC as rootfs storage. We let * the 1st linux configure power/clock for the 2nd Linux. * * When the 2nd Linux is booting into rootfs stage, we let the 1st Linux -- cgit v1.2.3 From 24e961b93d292d0dd6380213d22a071a99ea787d Mon Sep 17 00:00:00 2001 From: Sam Shih Date: Tue, 25 Oct 2022 15:29:53 +0200 Subject: mmc: mediatek: add support for MT7986 SoC Adding mt7986 own characteristics and of_device_id to have support of MT7986 SoC. Signed-off-by: Sam Shih Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20221025132953.81286-7-linux@fw-web.de Signed-off-by: Ulf Hansson --- drivers/mmc/host/mtk-sd.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 26bc59b5a7cc..709c6488ec44 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -552,6 +552,19 @@ static const struct mtk_mmc_compatible mt7622_compat = { .support_64g = false, }; +static const struct mtk_mmc_compatible mt7986_compat = { + .clk_div_bits = 12, + .recheck_sdio_irq = true, + .hs400_tune = false, + .pad_tune_reg = MSDC_PAD_TUNE0, + .async_fifo = true, + .data_tune = true, + .busy_check = true, + .stop_clk_fix = true, + .enhance_rx = true, + .support_64g = true, +}; + static const struct mtk_mmc_compatible mt8135_compat = { .clk_div_bits = 8, .recheck_sdio_irq = true, @@ -609,6 +622,7 @@ static const struct of_device_id msdc_of_ids[] = { { .compatible = "mediatek,mt6795-mmc", .data = &mt6795_compat}, { .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat}, { .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat}, + { .compatible = "mediatek,mt7986-mmc", .data = &mt7986_compat}, { .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat}, { .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat}, { .compatible = "mediatek,mt8183-mmc", .data = &mt8183_compat}, -- cgit v1.2.3 From 0614b0ae13c23d14907369085554eaecbdba8f7d Mon Sep 17 00:00:00 2001 From: Sai Krishna Potthuri Date: Wed, 19 Oct 2022 11:18:57 +0530 Subject: mmc: sdhci-of-arasan: Add support for dynamic configuration Add dynamic configuration support for Xilinx ZynqMP which takes care of configuring the SD secure space configuration registers using EEMI APIs, performing SD reset assert and deassert. High level sequence: - Check for the PM dynamic configuration support, if no error proceed with SD dynamic configurations(next steps) otherwise skip the dynamic configuration. - Put the SD Controller in reset. - Configure SD Fixed configurations. - Configure the SD Slot Type. - Configure the BASE_CLOCK. - Configure the 8-bit support. - Bring the SD Controller out of reset. - Wait for 1msec delay. Signed-off-by: Sai Krishna Potthuri Acked-by: Michal Simek Link: https://lore.kernel.org/r/20221019054857.8286-1-sai.krishna.potthuri@amd.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-arasan.c | 69 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index cfb891430174..89c431a34c43 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -1522,6 +1523,65 @@ static int sdhci_arasan_register_sdclk(struct sdhci_arasan_data *sdhci_arasan, return 0; } +static int sdhci_zynqmp_set_dynamic_config(struct device *dev, + struct sdhci_arasan_data *sdhci_arasan) +{ + struct sdhci_host *host = sdhci_arasan->host; + struct clk_hw *hw = &sdhci_arasan->clk_data.sdcardclk_hw; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + const char *clk_name = clk_hw_get_name(hw); + u32 mhz, node_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 : NODE_SD_1; + struct reset_control *rstc; + int ret; + + /* Obtain SDHC reset control */ + rstc = devm_reset_control_get_optional_exclusive(dev, NULL); + if (IS_ERR(rstc)) { + dev_err(dev, "Cannot get SDHC reset.\n"); + return PTR_ERR(rstc); + } + + ret = reset_control_assert(rstc); + if (ret) + return ret; + + ret = zynqmp_pm_set_sd_config(node_id, SD_CONFIG_FIXED, 0); + if (ret) + return ret; + + ret = zynqmp_pm_set_sd_config(node_id, SD_CONFIG_EMMC_SEL, + !!(host->mmc->caps & MMC_CAP_NONREMOVABLE)); + if (ret) + return ret; + + mhz = DIV_ROUND_CLOSEST_ULL(clk_get_rate(pltfm_host->clk), 1000000); + if (mhz > 100 && mhz <= 200) + mhz = 200; + else if (mhz > 50 && mhz <= 100) + mhz = 100; + else if (mhz > 25 && mhz <= 50) + mhz = 50; + else + mhz = 25; + + ret = zynqmp_pm_set_sd_config(node_id, SD_CONFIG_BASECLK, mhz); + if (ret) + return ret; + + ret = zynqmp_pm_set_sd_config(node_id, SD_CONFIG_8BIT, + !!(host->mmc->caps & MMC_CAP_8_BIT_DATA)); + if (ret) + return ret; + + ret = reset_control_deassert(rstc); + if (ret) + return ret; + + usleep_range(1000, 1500); + + return 0; +} + static int sdhci_arasan_add_host(struct sdhci_arasan_data *sdhci_arasan) { struct sdhci_host *host = sdhci_arasan->host; @@ -1686,6 +1746,15 @@ static int sdhci_arasan_probe(struct platform_device *pdev) goto unreg_clk; } + if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) { + ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_SET_SD_CONFIG); + if (!ret) { + ret = sdhci_zynqmp_set_dynamic_config(dev, sdhci_arasan); + if (ret) + goto unreg_clk; + } + } + sdhci_arasan->phy = ERR_PTR(-ENODEV); if (of_device_is_compatible(np, "arasan,sdhci-5.1")) { sdhci_arasan->phy = devm_phy_get(dev, "phy_arasan"); -- cgit v1.2.3 From 08b863bb034cfda73ac2d37faab9d54185f04231 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 26 Oct 2022 12:42:09 -0700 Subject: mmc: sdhci-*: Convert drivers to new sdhci_and_cqhci_reset() An earlier patch ("mmc: cqhci: Provide helper for resetting both SDHCI and CQHCI") does these operations for us. I keep these as a separate patch, since the earlier patch is a prerequisite to some important bugfixes that need to be backported via linux-stable. Signed-off-by: Brian Norris Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20221026124150.v4.7.Ia91f031f5f770af7bd2ff3e28b398f277606d970@changeid Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-msm.c | 10 ++-------- drivers/mmc/host/sdhci-pci-core.c | 11 ++--------- drivers/mmc/host/sdhci-pci-gli.c | 11 ++--------- 3 files changed, 6 insertions(+), 26 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 3a091a387ecb..03f76384ab3f 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -19,6 +19,7 @@ #include #include +#include "sdhci-cqhci.h" #include "sdhci-pltfm.h" #include "cqhci.h" @@ -2304,13 +2305,6 @@ static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps); } -static void sdhci_msm_reset(struct sdhci_host *host, u8 mask) -{ - if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL)) - cqhci_deactivate(host->mmc); - sdhci_reset(host, mask); -} - static int sdhci_msm_register_vreg(struct sdhci_msm_host *msm_host) { int ret; @@ -2450,7 +2444,7 @@ static const struct of_device_id sdhci_msm_dt_match[] = { MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match); static const struct sdhci_ops sdhci_msm_ops = { - .reset = sdhci_msm_reset, + .reset = sdhci_and_cqhci_reset, .set_clock = sdhci_msm_set_clock, .get_min_clock = sdhci_msm_get_min_clock, .get_max_clock = sdhci_msm_get_max_clock, diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 28dc65023fa9..1f05950bbb83 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -38,6 +38,7 @@ #include "cqhci.h" #include "sdhci.h" +#include "sdhci-cqhci.h" #include "sdhci-pci.h" static void sdhci_pci_hw_reset(struct sdhci_host *host); @@ -234,14 +235,6 @@ static void sdhci_pci_dumpregs(struct mmc_host *mmc) sdhci_dumpregs(mmc_priv(mmc)); } -static void sdhci_cqhci_reset(struct sdhci_host *host, u8 mask) -{ - if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL) && - host->mmc->cqe_private) - cqhci_deactivate(host->mmc); - sdhci_reset(host, mask); -} - /*****************************************************************************\ * * * Hardware specific quirk handling * @@ -703,7 +696,7 @@ static const struct sdhci_ops sdhci_intel_glk_ops = { .set_power = sdhci_intel_set_power, .enable_dma = sdhci_pci_enable_dma, .set_bus_width = sdhci_set_bus_width, - .reset = sdhci_cqhci_reset, + .reset = sdhci_and_cqhci_reset, .set_uhs_signaling = sdhci_intel_set_uhs_signaling, .hw_reset = sdhci_pci_hw_reset, .irq = sdhci_cqhci_irq, diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c index 4d509f656188..633a8ee8f8c5 100644 --- a/drivers/mmc/host/sdhci-pci-gli.c +++ b/drivers/mmc/host/sdhci-pci-gli.c @@ -15,6 +15,7 @@ #include #include #include "sdhci.h" +#include "sdhci-cqhci.h" #include "sdhci-pci.h" #include "cqhci.h" @@ -922,14 +923,6 @@ cleanup: return ret; } -static void sdhci_gl9763e_reset(struct sdhci_host *host, u8 mask) -{ - if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL) && - host->mmc->cqe_private) - cqhci_deactivate(host->mmc); - sdhci_reset(host, mask); -} - static void gli_set_gl9763e(struct sdhci_pci_slot *slot) { struct pci_dev *pdev = slot->chip->pdev; @@ -1136,7 +1129,7 @@ static const struct sdhci_ops sdhci_gl9763e_ops = { .set_clock = sdhci_set_clock, .enable_dma = sdhci_pci_enable_dma, .set_bus_width = sdhci_set_bus_width, - .reset = sdhci_gl9763e_reset, + .reset = sdhci_and_cqhci_reset, .set_uhs_signaling = sdhci_set_gl9763e_signaling, .voltage_switch = sdhci_gli_voltage_switch, .irq = sdhci_gl9763e_cqhci_irq, -- cgit v1.2.3 From 4fb2786961c517d0a6e4e8bf947d6f7259155d6a Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Fri, 28 Oct 2022 17:04:29 +0800 Subject: mmc: sdhci-esdhc-imx: reset the tuning logic before execute tuning For standard tuning method on usdhc, the previous tuning result can impact current tuning result, let current tuning can't set the correct delay cell. And from the logic, this is also reasonable for manual tuning method. So reset the tuning logic before execute tuning. To avoid compile issue, this patch also move the esdhc_reset_tuning() upper. Find this issue when support SDIO WiFi in band wakeup feature. After system resume back, will do re-tuning, but then meet data CRC error. Do not meet this issue on SD/eMMC, because we already call esdhc_reset_tuning() when config the legency ios, and SD/eMMC need to re-init when system resume back, but SDIO device don't do re-init if it has MMC_PM_KEEP_POWER pm_flags. Signed-off-by: Haibo Chen Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/1666947869-7904-1-git-send-email-haibo.chen@nxp.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-esdhc-imx.c | 82 ++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 38 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 9f7eea4f948f..89ef0c80ac37 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -1013,6 +1013,44 @@ static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) SDHCI_HOST_CONTROL); } +static void esdhc_reset_tuning(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); + u32 ctrl; + int ret; + + /* Reset the tuning circuit */ + if (esdhc_is_usdhc(imx_data)) { + if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { + ctrl = readl(host->ioaddr + ESDHC_MIX_CTRL); + ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; + ctrl &= ~ESDHC_MIX_CTRL_FBCLK_SEL; + writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL); + writel(0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); + } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { + ctrl = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); + ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; + ctrl &= ~ESDHC_MIX_CTRL_EXE_TUNE; + writel(ctrl, host->ioaddr + SDHCI_AUTO_CMD_STATUS); + /* Make sure ESDHC_MIX_CTRL_EXE_TUNE cleared */ + ret = readl_poll_timeout(host->ioaddr + SDHCI_AUTO_CMD_STATUS, + ctrl, !(ctrl & ESDHC_MIX_CTRL_EXE_TUNE), 1, 50); + if (ret == -ETIMEDOUT) + dev_warn(mmc_dev(host->mmc), + "Warning! clear execute tuning bit failed\n"); + /* + * SDHCI_INT_DATA_AVAIL is W1C bit, set this bit will clear the + * usdhc IP internal logic flag execute_tuning_with_clr_buf, which + * will finally make sure the normal data transfer logic correct. + */ + ctrl = readl(host->ioaddr + SDHCI_INT_STATUS); + ctrl |= SDHCI_INT_DATA_AVAIL; + writel(ctrl, host->ioaddr + SDHCI_INT_STATUS); + } + } +} + static int usdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) { struct sdhci_host *host = mmc_priv(mmc); @@ -1024,6 +1062,12 @@ static int usdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) if (host->timing == MMC_TIMING_UHS_DDR50) return 0; + /* + * Reset tuning circuit logic. If not, the previous tuning result + * will impact current tuning, make current tuning can't set the + * correct delay cell. + */ + esdhc_reset_tuning(host); return sdhci_execute_tuning(mmc, opcode); } @@ -1197,44 +1241,6 @@ static void esdhc_set_strobe_dll(struct sdhci_host *host) "warning! HS400 strobe DLL status REF/SLV not lock in 50us, STROBE DLL status is %x!\n", v); } -static void esdhc_reset_tuning(struct sdhci_host *host) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); - u32 ctrl; - int ret; - - /* Reset the tuning circuit */ - if (esdhc_is_usdhc(imx_data)) { - if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { - ctrl = readl(host->ioaddr + ESDHC_MIX_CTRL); - ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; - ctrl &= ~ESDHC_MIX_CTRL_FBCLK_SEL; - writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL); - writel(0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); - } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { - ctrl = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); - ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; - ctrl &= ~ESDHC_MIX_CTRL_EXE_TUNE; - writel(ctrl, host->ioaddr + SDHCI_AUTO_CMD_STATUS); - /* Make sure ESDHC_MIX_CTRL_EXE_TUNE cleared */ - ret = readl_poll_timeout(host->ioaddr + SDHCI_AUTO_CMD_STATUS, - ctrl, !(ctrl & ESDHC_MIX_CTRL_EXE_TUNE), 1, 50); - if (ret == -ETIMEDOUT) - dev_warn(mmc_dev(host->mmc), - "Warning! clear execute tuning bit failed\n"); - /* - * SDHCI_INT_DATA_AVAIL is W1C bit, set this bit will clear the - * usdhc IP internal logic flag execute_tuning_with_clr_buf, which - * will finally make sure the normal data transfer logic correct. - */ - ctrl = readl(host->ioaddr + SDHCI_INT_STATUS); - ctrl |= SDHCI_INT_DATA_AVAIL; - writel(ctrl, host->ioaddr + SDHCI_INT_STATUS); - } - } -} - static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing) { u32 m; -- cgit v1.2.3 From dc4e9e2aa82a697ff1fccf6dbdd9f648afc7d71a Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 28 Oct 2022 15:56:37 -0700 Subject: mmc: sdhci-pci: Set PROBE_PREFER_ASYNCHRONOUS This driver often takes on the order of 10ms to start, but in some cases as much as 190ms. It shouldn't have many cross-device dependencies to race with, nor racy access to shared state with other drivers, so this should be a relatively low risk change. We've done similarly with a variety of other MMC host drivers already. This driver was pinpointed as part of a survey of top slowest initcalls (i.e., are built in, and probing synchronously) on a lab of ChromeOS systems. Signed-off-by: Brian Norris Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20221028155633.1.I6c4bfb31e88fad934e7360242cb662e01612c1bb@changeid Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 1f05950bbb83..c359f867df0a 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -2276,7 +2276,8 @@ static struct pci_driver sdhci_driver = { .probe = sdhci_pci_probe, .remove = sdhci_pci_remove, .driver = { - .pm = &sdhci_pci_pm_ops + .pm = &sdhci_pci_pm_ops, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; -- cgit v1.2.3 From 654993b3e1eb7ce22e5d5bf5df95730c3fb7013a Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 1 Nov 2022 11:52:42 +0100 Subject: mmc: sdhci_am654: Use dev_err_probe() for mmc_of_parse() return code Checking phandle references like mmc-pwrseq can result in -EPROBE_DEFER. Signed-off-by: Matthias Schiffer Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20221101105242.2019036-1-matthias.schiffer@ew.tq-group.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci_am654.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index c2333c7acac9..7ef828942df3 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -836,7 +836,7 @@ static int sdhci_am654_probe(struct platform_device *pdev) ret = mmc_of_parse(host->mmc); if (ret) { - dev_err(dev, "parsing dt failed (%d)\n", ret); + dev_err_probe(dev, ret, "parsing dt failed\n"); goto pm_runtime_put; } -- cgit v1.2.3 From ff50df9ac28b5a6a93ab8bed58c74ad8f12c756a Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 2 Nov 2022 14:01:05 +0200 Subject: mmc: Remove duplicate words in comments Remove duplicate words in comments found using the following commands: pcregrep --color=always -n \ '([^a-zA-Z_])([a-zA-Z_]+)[[:space:]]+\2[^a-zA-Z_]' \ drivers/mmc/host/*.[ch] drivers/mmc/core/*.[ch] \ include/linux/mmc/*.h \ include/uapi/linux/mmc/*.h | \ grep -v 'long long' pcregrep --color=always -n -M \ '([^a-zA-Z_])([a-zA-Z_]+)[ \t]*\n[[:space:]*]+\2[^a-zA-Z_]' \ drivers/mmc/host/*.[ch] \ drivers/mmc/core/*.[ch] \ include/linux/mmc/*.h \ include/uapi/linux/mmc/*.h Signed-off-by: Adrian Hunter Link: https://lore.kernel.org/r/20221102120105.5747-1-adrian.hunter@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 4 ++-- drivers/mmc/core/host.c | 2 +- drivers/mmc/host/sdhci-acpi.c | 2 +- drivers/mmc/host/sdhci-bcm-kona.c | 2 +- drivers/mmc/host/sdhci-omap.c | 2 +- drivers/mmc/host/sdhci.h | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index de1cc9e1ae57..d87b8a28f56a 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -56,7 +56,7 @@ static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; /* * Enabling software CRCs on the data blocks can be a significant (30%) * performance cost, and for other reasons may not always be desired. - * So we allow it it to be disabled. + * So we allow it to be disabled. */ bool use_spi_crc = 1; module_param(use_spi_crc, bool, 0); @@ -527,7 +527,7 @@ EXPORT_SYMBOL(mmc_cqe_post_req); * mmc_cqe_recovery - Recover from CQE errors. * @host: MMC host to recover * - * Recovery consists of stopping CQE, stopping eMMC, discarding the queue in + * Recovery consists of stopping CQE, stopping eMMC, discarding the queue * in eMMC, and discarding the queue in CQE. CQE must call * mmc_cqe_request_done() on all requests. An error is returned if the eMMC * fails to discard its queue. diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index b89dca1f15e9..5457c8aeeea1 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -269,7 +269,7 @@ EXPORT_SYMBOL(mmc_of_parse_clk_phase); * @host: host whose properties should be parsed. * * To keep the rest of the MMC subsystem unaware of whether DT has been - * used to to instantiate and configure this host instance or not, we + * used to instantiate and configure this host instance or not, we * parse the properties and set respective generic mmc-host flags and * parameters. */ diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index bddfaba091a9..8f0e639236b1 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -651,7 +651,7 @@ static int sdhci_acpi_emmc_amd_probe_slot(struct platform_device *pdev, * instead use the SDR104 preset register. * * If the above issues are resolved we could remove this quirk for - * firmware that that has valid presets (i.e., SDR12 <= 12 MHz). + * firmware that has valid presets (i.e., SDR12 <= 12 MHz). */ host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c index 61a12f2f7f03..6a93a54fe067 100644 --- a/drivers/mmc/host/sdhci-bcm-kona.c +++ b/drivers/mmc/host/sdhci-bcm-kona.c @@ -168,7 +168,7 @@ static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host, /* * JEDEC and SD spec specify supplying 74 continuous clocks to * device after power up. With minimum bus (100KHz) that - * that translates to 740us + * translates to 740us */ if (power_mode != MMC_POWER_OFF) udelay(740); diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 033be559a730..8ed9256b83da 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -370,7 +370,7 @@ static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode) /* * Stage 1: Search for a maximum pass window ignoring any - * any single point failures. If the tuning value ends up + * single point failures. If the tuning value ends up * near it, move away from it in stage 2 below */ while (phase_delay <= MAX_PHASE_DELAY) { diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 87a3aaa07438..b6f31a7d6152 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -345,7 +345,7 @@ struct sdhci_adma2_64_desc { */ #define SDHCI_MAX_SEGS 128 -/* Allow for a a command request and a data request at the same time */ +/* Allow for a command request and a data request at the same time */ #define SDHCI_MAX_MRQS 2 /* -- cgit v1.2.3 From 7b438d0377fbd520b475a68bdd9de1692393f22d Mon Sep 17 00:00:00 2001 From: Mengqi Zhang Date: Sun, 6 Nov 2022 11:39:24 +0800 Subject: mmc: mtk-sd: add Inline Crypto Engine clock control Add crypto clock control and ungate it before CQHCI init. Signed-off-by: Mengqi Zhang Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20221106033924.9854-2-mengqi.zhang@mediatek.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/mtk-sd.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 709c6488ec44..422817f7d559 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -452,6 +452,7 @@ struct msdc_host { struct clk *bus_clk; /* bus clock which used to access register */ struct clk *src_clk_cg; /* msdc source clock control gate */ struct clk *sys_clk_cg; /* msdc subsys clock control gate */ + struct clk *crypto_clk; /* msdc crypto clock control gate */ struct clk_bulk_data bulk_clks[MSDC_NR_CLOCKS]; u32 mclk; /* mmc subsystem clock frequency */ u32 src_clk_freq; /* source clock frequency */ @@ -840,6 +841,7 @@ static void msdc_set_busy_timeout(struct msdc_host *host, u64 ns, u64 clks) static void msdc_gate_clock(struct msdc_host *host) { clk_bulk_disable_unprepare(MSDC_NR_CLOCKS, host->bulk_clks); + clk_disable_unprepare(host->crypto_clk); clk_disable_unprepare(host->src_clk_cg); clk_disable_unprepare(host->src_clk); clk_disable_unprepare(host->bus_clk); @@ -855,6 +857,7 @@ static int msdc_ungate_clock(struct msdc_host *host) clk_prepare_enable(host->bus_clk); clk_prepare_enable(host->src_clk); clk_prepare_enable(host->src_clk_cg); + clk_prepare_enable(host->crypto_clk); ret = clk_bulk_prepare_enable(MSDC_NR_CLOCKS, host->bulk_clks); if (ret) { dev_err(host->dev, "Cannot enable pclk/axi/ahb clock gates\n"); @@ -2670,6 +2673,15 @@ static int msdc_drv_probe(struct platform_device *pdev) goto host_free; } + /* only eMMC has crypto property */ + if (!(mmc->caps2 & MMC_CAP2_NO_MMC)) { + host->crypto_clk = devm_clk_get_optional(&pdev->dev, "crypto"); + if (IS_ERR(host->crypto_clk)) + host->crypto_clk = NULL; + else + mmc->caps2 |= MMC_CAP2_CRYPTO; + } + host->irq = platform_get_irq(pdev, 0); if (host->irq < 0) { ret = -EINVAL; -- cgit v1.2.3 From e93d1468f429475a753d6baa79b853b7ee5ef8c0 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 1 Nov 2022 14:30:15 +0800 Subject: mmc: alcor: fix return value check of mmc_add_host() mmc_add_host() may return error, if we ignore its return value, the memory that allocated in mmc_alloc_host() will be leaked and it will lead a kernel crash because of deleting not added device in the remove path. So fix this by checking the return value and calling mmc_free_host() in the error path. Fixes: c5413ad815a6 ("mmc: add new Alcor Micro Cardreader SD/MMC driver") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20221101063023.1664968-2-yangyingliang@huawei.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/alcor.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/alcor.c b/drivers/mmc/host/alcor.c index bfb8efeb7eb8..d01df01d4b4d 100644 --- a/drivers/mmc/host/alcor.c +++ b/drivers/mmc/host/alcor.c @@ -1114,7 +1114,10 @@ static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev) alcor_hw_init(host); dev_set_drvdata(&pdev->dev, host); - mmc_add_host(mmc); + ret = mmc_add_host(mmc); + if (ret) + goto free_host; + return 0; free_host: -- cgit v1.2.3 From 0ca18d09c744fb030ae9bc5836c3e357e0237dea Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 1 Nov 2022 14:30:16 +0800 Subject: mmc: moxart: fix return value check of mmc_add_host() mmc_add_host() may return error, if we ignore its return value, the memory that allocated in mmc_alloc_host() will be leaked and it will lead a kernel crash because of deleting not added device in the remove path. So fix this by checking the return value and goto error path which will call mmc_free_host(). Fixes: 1b66e94e6b99 ("mmc: moxart: Add MOXA ART SD/MMC driver") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20221101063023.1664968-3-yangyingliang@huawei.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/moxart-mmc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c index dfc3ffd5b1f8..52ed30f2d9f4 100644 --- a/drivers/mmc/host/moxart-mmc.c +++ b/drivers/mmc/host/moxart-mmc.c @@ -665,7 +665,9 @@ static int moxart_probe(struct platform_device *pdev) goto out; dev_set_drvdata(dev, mmc); - mmc_add_host(mmc); + ret = mmc_add_host(mmc); + if (ret) + goto out; dev_dbg(dev, "IRQ=%d, FIFO is %d bytes\n", irq, host->fifo_width); -- cgit v1.2.3 From cde600af7b413c9fe03e85c58c4279df90e91d13 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 1 Nov 2022 14:30:17 +0800 Subject: mmc: mxcmmc: fix return value check of mmc_add_host() mmc_add_host() may return error, if we ignore its return value, the memory that allocated in mmc_alloc_host() will be leaked and it will lead a kernel crash because of deleting not added device in the remove path. So fix this by checking the return value and goto error path which will call mmc_free_host(). Fixes: d96be879ff46 ("mmc: Add a MX2/MX3 specific SDHC driver") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20221101063023.1664968-4-yangyingliang@huawei.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/mxcmmc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 2cf0413407ea..668f865f3efb 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -1143,7 +1143,9 @@ static int mxcmci_probe(struct platform_device *pdev) timer_setup(&host->watchdog, mxcmci_watchdog, 0); - mmc_add_host(mmc); + ret = mmc_add_host(mmc); + if (ret) + goto out_free_dma; return 0; -- cgit v1.2.3 From 80e1ef3afb8bfbe768380b70ffe1b6cab87d1a3b Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 1 Nov 2022 14:30:18 +0800 Subject: mmc: pxamci: fix return value check of mmc_add_host() mmc_add_host() may return error, if we ignore its return value, the memory that allocated in mmc_alloc_host() will be leaked and it will lead a kernel crash because of deleting not added device in the remove path. So fix this by checking the return value and goto error path which will call mmc_free_host(), besides, ->exit() need be called to uninit the pdata. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20221101063023.1664968-5-yangyingliang@huawei.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/pxamci.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index e4003f6058eb..2a988f942b6c 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -763,7 +763,12 @@ static int pxamci_probe(struct platform_device *pdev) dev_warn(dev, "gpio_ro and get_ro() both defined\n"); } - mmc_add_host(mmc); + ret = mmc_add_host(mmc); + if (ret) { + if (host->pdata && host->pdata->exit) + host->pdata->exit(dev, mmc); + goto out; + } return 0; -- cgit v1.2.3 From 0c87db77423a282b3b38b8a6daf057b822680516 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 1 Nov 2022 14:30:19 +0800 Subject: mmc: rtsx_pci: fix return value check of mmc_add_host() mmc_add_host() may return error, if we ignore its return value, the memory that allocated in mmc_alloc_host() will be leaked and it will lead a kernel crash because of deleting not added device in the remove path. So fix this by checking the return value and calling mmc_free_host() in the error path, beside, runtime PM also needs be disabled. Fixes: ff984e57d36e ("mmc: Add realtek pcie sdmmc host driver") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20221101063023.1664968-6-yangyingliang@huawei.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/rtsx_pci_sdmmc.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index e1580f78c6b2..8098726dcc0b 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -1474,6 +1474,7 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev) struct realtek_pci_sdmmc *host; struct rtsx_pcr *pcr; struct pcr_handle *handle = pdev->dev.platform_data; + int ret; if (!handle) return -ENXIO; @@ -1511,7 +1512,13 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev) pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_use_autosuspend(&pdev->dev); - mmc_add_host(mmc); + ret = mmc_add_host(mmc); + if (ret) { + pm_runtime_dont_use_autosuspend(&pdev->dev); + pm_runtime_disable(&pdev->dev); + mmc_free_host(mmc); + return ret; + } return 0; } -- cgit v1.2.3 From fc38a5a10e9e5a75eb9189854abeb8405b214cc9 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 1 Nov 2022 14:30:20 +0800 Subject: mmc: rtsx_usb_sdmmc: fix return value check of mmc_add_host() mmc_add_host() may return error, if we ignore its return value, the memory that allocated in mmc_alloc_host() will be leaked and it will lead a kernel crash because of deleting not added device in the remove path. So fix this by checking the return value and calling mmc_free_host() in the error path, besides, led_classdev_unregister() and pm_runtime_disable() also need be called. Fixes: c7f6558d84af ("mmc: Add realtek USB sdmmc host driver") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20221101063023.1664968-7-yangyingliang@huawei.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/rtsx_usb_sdmmc.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c index 5798aee06653..2c650cd58693 100644 --- a/drivers/mmc/host/rtsx_usb_sdmmc.c +++ b/drivers/mmc/host/rtsx_usb_sdmmc.c @@ -1329,6 +1329,7 @@ static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev) #ifdef RTSX_USB_USE_LEDS_CLASS int err; #endif + int ret; ucr = usb_get_intfdata(to_usb_interface(pdev->dev.parent)); if (!ucr) @@ -1365,7 +1366,15 @@ static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev) INIT_WORK(&host->led_work, rtsx_usb_update_led); #endif - mmc_add_host(mmc); + ret = mmc_add_host(mmc); + if (ret) { +#ifdef RTSX_USB_USE_LEDS_CLASS + led_classdev_unregister(&host->led); +#endif + mmc_free_host(mmc); + pm_runtime_disable(&pdev->dev); + return ret; + } return 0; } -- cgit v1.2.3 From f670744a316ea983113a65313dcd387b5a992444 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 1 Nov 2022 14:30:21 +0800 Subject: mmc: toshsd: fix return value check of mmc_add_host() mmc_add_host() may return error, if we ignore its return value, the memory that allocated in mmc_alloc_host() will be leaked and it will lead a kernel crash because of deleting not added device in the remove path. So fix this by checking the return value and goto error path which will call mmc_free_host(), besides, free_irq() also needs be called. Fixes: a5eb8bbd66cc ("mmc: add Toshiba PCI SD controller driver") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20221101063023.1664968-8-yangyingliang@huawei.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/toshsd.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/toshsd.c b/drivers/mmc/host/toshsd.c index 8d037c2071ab..497791ffada6 100644 --- a/drivers/mmc/host/toshsd.c +++ b/drivers/mmc/host/toshsd.c @@ -651,7 +651,9 @@ static int toshsd_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) goto unmap; - mmc_add_host(mmc); + ret = mmc_add_host(mmc); + if (ret) + goto free_irq; base = pci_resource_start(pdev, 0); dev_dbg(&pdev->dev, "MMIO %pa, IRQ %d\n", &base, pdev->irq); @@ -660,6 +662,8 @@ static int toshsd_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return 0; +free_irq: + free_irq(pdev->irq, host); unmap: pci_iounmap(pdev, host->ioaddr); release: -- cgit v1.2.3 From 0613ad2401f88bdeae5594c30afe318e93b14676 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 1 Nov 2022 14:30:22 +0800 Subject: mmc: vub300: fix return value check of mmc_add_host() mmc_add_host() may return error, if we ignore its return value, the memory that allocated in mmc_alloc_host() will be leaked and it will lead a kernel crash because of deleting not added device in the remove path. So fix this by checking the return value and goto error path which will call mmc_free_host(), besides, the timer added before mmc_add_host() needs be del. And this patch fixes another missing call mmc_free_host() if usb_control_msg() fails. Fixes: 88095e7b473a ("mmc: Add new VUB300 USB-to-SD/SDIO/MMC driver") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20221101063023.1664968-9-yangyingliang@huawei.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/vub300.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index 97beece62fec..ab36ec479747 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -2299,14 +2299,14 @@ static int vub300_probe(struct usb_interface *interface, 0x0000, 0x0000, &vub300->system_port_status, sizeof(vub300->system_port_status), 1000); if (retval < 0) { - goto error4; + goto error5; } else if (sizeof(vub300->system_port_status) == retval) { vub300->card_present = (0x0001 & vub300->system_port_status.port_flags) ? 1 : 0; vub300->read_only = (0x0010 & vub300->system_port_status.port_flags) ? 1 : 0; } else { - goto error4; + goto error5; } usb_set_intfdata(interface, vub300); INIT_DELAYED_WORK(&vub300->pollwork, vub300_pollwork_thread); @@ -2329,8 +2329,13 @@ static int vub300_probe(struct usb_interface *interface, "USB vub300 remote SDIO host controller[%d]" "connected with no SD/SDIO card inserted\n", interface_to_InterfaceNumber(interface)); - mmc_add_host(mmc); + retval = mmc_add_host(mmc); + if (retval) + goto error6; + return 0; +error6: + del_timer_sync(&vub300->inactivity_timer); error5: mmc_free_host(mmc); /* -- cgit v1.2.3 From 29276d56f6ed138db0f38cd31aedc0b725c8c76c Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 1 Nov 2022 14:30:23 +0800 Subject: mmc: wmt-sdmmc: fix return value check of mmc_add_host() mmc_add_host() may return error, if we ignore its return value, the memory that allocated in mmc_alloc_host() will be leaked and it will lead a kernel crash because of deleting not added device in the remove path. So fix this by checking the return value and goto error path which will call mmc_free_host(), besides, clk_disable_unprepare() also needs be called. Fixes: 3a96dff0f828 ("mmc: SD/MMC Host Controller for Wondermedia WM8505/WM8650") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20221101063023.1664968-10-yangyingliang@huawei.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/wmt-sdmmc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c index 9b5c503e3a3f..9aa3027ca25e 100644 --- a/drivers/mmc/host/wmt-sdmmc.c +++ b/drivers/mmc/host/wmt-sdmmc.c @@ -856,11 +856,15 @@ static int wmt_mci_probe(struct platform_device *pdev) /* configure the controller to a known 'ready' state */ wmt_reset_hardware(mmc); - mmc_add_host(mmc); + ret = mmc_add_host(mmc); + if (ret) + goto fail7; dev_info(&pdev->dev, "WMT SDHC Controller initialized\n"); return 0; +fail7: + clk_disable_unprepare(priv->clk_sdmmc); fail6: clk_put(priv->clk_sdmmc); fail5_and_a_half: -- cgit v1.2.3 From 5c1a2b77cd1b59112cf22b3e338f7e416797ad32 Mon Sep 17 00:00:00 2001 From: Gabriel Somlo Date: Mon, 7 Nov 2022 10:55:16 -0500 Subject: mmc: litex_mmc: ensure `host->irq == 0` if polling Ensure the flag is explicitly set to 0 if we determine that polling is needed during driver probe, to cover all possible cases. Fixes: 92e099104729 ("mmc: Add driver for LiteX's LiteSDCard interface") Signed-off-by: Gabriel Somlo Link: https://lore.kernel.org/r/20221107155516.2535912-1-gsomlo@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/litex_mmc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/litex_mmc.c b/drivers/mmc/host/litex_mmc.c index 6ba0d63b8c07..39c6707fdfdb 100644 --- a/drivers/mmc/host/litex_mmc.c +++ b/drivers/mmc/host/litex_mmc.c @@ -502,6 +502,7 @@ static int litex_mmc_irq_init(struct platform_device *pdev, use_polling: host->mmc->caps |= MMC_CAP_NEEDS_POLL; + host->irq = 0; return 0; } -- cgit v1.2.3 From 9e6e8c43726673ca2abcaac87640b9215fd72f4c Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 8 Nov 2022 20:28:19 +0800 Subject: mmc: atmel-mci: fix return value check of mmc_add_host() mmc_add_host() may return error, if we ignore its return value, it will lead two issues: 1. The memory that allocated in mmc_alloc_host() is leaked. 2. In the remove() path, mmc_remove_host() will be called to delete device, but it's not added yet, it will lead a kernel crash because of null-ptr-deref in device_del(). So fix this by checking the return value and calling mmc_free_host() in the error path. Fixes: 7d2be0749a59 ("atmel-mci: Driver for Atmel on-chip MMC controllers") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20221108122819.429975-1-yangyingliang@huawei.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/atmel-mci.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 91d52ba7a39f..bb9bbf1c927b 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -2222,6 +2222,7 @@ static int atmci_init_slot(struct atmel_mci *host, { struct mmc_host *mmc; struct atmel_mci_slot *slot; + int ret; mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev); if (!mmc) @@ -2305,11 +2306,13 @@ static int atmci_init_slot(struct atmel_mci *host, host->slot[id] = slot; mmc_regulator_get_supply(mmc); - mmc_add_host(mmc); + ret = mmc_add_host(mmc); + if (ret) { + mmc_free_host(mmc); + return ret; + } if (gpio_is_valid(slot->detect_pin)) { - int ret; - timer_setup(&slot->detect_timer, atmci_detect_change, 0); ret = request_irq(gpio_to_irq(slot->detect_pin), -- cgit v1.2.3 From a525cad241c339ca00bf7ebf03c5180f2a9b767c Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 8 Nov 2022 20:13:16 +0800 Subject: mmc: omap_hsmmc: fix return value check of mmc_add_host() mmc_add_host() may return error, if we ignore its return value, it will lead two issues: 1. The memory that allocated in mmc_alloc_host() is leaked. 2. In the remove() path, mmc_remove_host() will be called to delete device, but it's not added yet, it will lead a kernel crash because of null-ptr-deref in device_del(). Fix this by checking the return value and goto error path wihch will call mmc_free_host(). Fixes: a45c6cb81647 ("[ARM] 5369/1: omap mmc: Add new omap hsmmc controller for 2430 and 34xx, v3") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20221108121316.340354-1-yangyingliang@huawei.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index fca30add563e..4bd744755205 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1946,7 +1946,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev) if (!ret) mmc->caps |= MMC_CAP_SDIO_IRQ; - mmc_add_host(mmc); + ret = mmc_add_host(mmc); + if (ret) + goto err_irq; if (mmc_pdata(host)->name != NULL) { ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name); -- cgit v1.2.3 From 90935f16f2650ab7416fa2ffbe5c28cb39cf3f1e Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 8 Nov 2022 20:34:17 +0800 Subject: mmc: meson-gx: fix return value check of mmc_add_host() mmc_add_host() may return error, if we ignore its return value, it will lead two issues: 1. The memory that allocated in mmc_alloc_host() is leaked. 2. In the remove() path, mmc_remove_host() will be called to delete device, but it's not added yet, it will lead a kernel crash because of null-ptr-deref in device_del(). Fix this by checking the return value and goto error path which will call mmc_free_host(). Fixes: 51c5d8447bd7 ("MMC: meson: initial support for GX platforms") Signed-off-by: Yang Yingliang Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20221108123417.479045-1-yangyingliang@huawei.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/meson-gx-mmc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index df05e60bed9a..6e5ea0213b47 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -1335,7 +1335,9 @@ static int meson_mmc_probe(struct platform_device *pdev) } mmc->ops = &meson_mmc_ops; - mmc_add_host(mmc); + ret = mmc_add_host(mmc); + if (ret) + goto err_free_irq; return 0; -- cgit v1.2.3 From e4e46fb61e3bb4628170810d3f2b996b709b90d9 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 8 Nov 2022 21:09:49 +0800 Subject: mmc: via-sdmmc: fix return value check of mmc_add_host() mmc_add_host() may return error, if we ignore its return value, it will lead two issues: 1. The memory that allocated in mmc_alloc_host() is leaked. 2. In the remove() path, mmc_remove_host() will be called to delete device, but it's not added yet, it will lead a kernel crash because of null-ptr-deref in device_del(). Fix this by checking the return value and goto error path which will call mmc_free_host(). Fixes: f0bf7f61b840 ("mmc: Add new via-sdmmc host controller driver") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20221108130949.1067699-1-yangyingliang@huawei.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/via-sdmmc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c index 88662a90ed96..a2b0d9461665 100644 --- a/drivers/mmc/host/via-sdmmc.c +++ b/drivers/mmc/host/via-sdmmc.c @@ -1151,7 +1151,9 @@ static int via_sd_probe(struct pci_dev *pcidev, pcidev->subsystem_device == 0x3891) sdhost->quirks = VIA_CRDR_QUIRK_300MS_PWRDELAY; - mmc_add_host(mmc); + ret = mmc_add_host(mmc); + if (ret) + goto unmap; return 0; -- cgit v1.2.3 From dc5b9b50fc9d1334407e316e6e29a5097ef833bd Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 9 Nov 2022 21:32:37 +0800 Subject: mmc: wbsd: fix return value check of mmc_add_host() mmc_add_host() may return error, if we ignore its return value, it will lead two issues: 1. The memory that allocated in mmc_alloc_host() is leaked. 2. In the remove() path, mmc_remove_host() will be called to delete device, but it's not added yet, it will lead a kernel crash because of null-ptr-deref in device_del(). So fix this by checking the return value and goto error path which will call mmc_free_host(), besides, other resources also need be released. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20221109133237.3273558-1-yangyingliang@huawei.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/wbsd.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index 2219144c166a..521af9251f33 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -1698,7 +1698,17 @@ static int wbsd_init(struct device *dev, int base, int irq, int dma, */ wbsd_init_device(host); - mmc_add_host(mmc); + ret = mmc_add_host(mmc); + if (ret) { + if (!pnp) + wbsd_chip_poweroff(host); + + wbsd_release_resources(host); + wbsd_free_mmc(dev); + + mmc_free_host(mmc); + return ret; + } pr_info("%s: W83L51xD", mmc_hostname(mmc)); if (host->chip_id != 0) -- cgit v1.2.3 From b38a20f29a49ae04d23750d104b25400b792b98c Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 9 Nov 2022 21:35:39 +0800 Subject: mmc: mmci: fix return value check of mmc_add_host() mmc_add_host() may return error, if we ignore its return value, it will lead two issues: 1. The memory that allocated in mmc_alloc_host() is leaked. 2. In the remove() path, mmc_remove_host() will be called to delete device, but it's not added yet, it will lead a kernel crash because of null-ptr-deref in device_del(). So fix this by checking the return value and goto error path which will call mmc_free_host(). Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20221109133539.3275664-1-yangyingliang@huawei.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 012aa85489d8..b9e5dfe74e5c 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -2256,7 +2256,9 @@ static int mmci_probe(struct amba_device *dev, pm_runtime_set_autosuspend_delay(&dev->dev, 50); pm_runtime_use_autosuspend(&dev->dev); - mmc_add_host(mmc); + ret = mmc_add_host(mmc); + if (ret) + goto clk_disable; pm_runtime_put(&dev->dev); return 0; -- cgit v1.2.3 From 4b323f02b6e8df1b04292635ef829e7f723bf50e Mon Sep 17 00:00:00 2001 From: Yu Zhe Date: Thu, 10 Nov 2022 15:28:19 +0800 Subject: mmc: mtk-sd: fix two spelling mistakes in comment spelling mistake fix : "alreay" -> "already" "checksume" -> "checksum" Signed-off-by: Yu Zhe Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20221110072819.11530-1-yuzhe@nfschina.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/mtk-sd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 422817f7d559..abadfc319053 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -750,7 +750,7 @@ static inline void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma, else bd[j].bd_info &= ~BDMA_DESC_EOL; - /* checksume need to clear first */ + /* checksum need to clear first */ bd[j].bd_info &= ~BDMA_DESC_CHECKSUM; bd[j].bd_info |= msdc_dma_calcs((u8 *)(&bd[j]), 16) << 8; } @@ -1229,7 +1229,7 @@ static bool msdc_cmd_done(struct msdc_host *host, int events, !host->hs400_tuning)) /* * should not clear fifo/interrupt as the tune data - * may have alreay come when cmd19/cmd21 gets response + * may have already come when cmd19/cmd21 gets response * CRC error. */ msdc_reset_hw(host); -- cgit v1.2.3 From bd724b279f554629e5f74d50a43e2435791482e1 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Fri, 11 Nov 2022 17:10:29 +0900 Subject: mmc: f-sdh30: Add reset control support Add reset control support for F_SDH30 controller. This is optional. Signed-off-by: Kunihiko Hayashi Acked-by: Jassi Brar Link: https://lore.kernel.org/r/20221111081033.3813-3-hayashi.kunihiko@socionext.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci_f_sdh30.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci_f_sdh30.c b/drivers/mmc/host/sdhci_f_sdh30.c index 3f5977979cf2..7f4553b28180 100644 --- a/drivers/mmc/host/sdhci_f_sdh30.c +++ b/drivers/mmc/host/sdhci_f_sdh30.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "sdhci-pltfm.h" #include "sdhci_f_sdh30.h" @@ -21,6 +22,7 @@ struct f_sdhost_priv { struct clk *clk_iface; struct clk *clk; + struct reset_control *rst; u32 vendor_hs200; struct device *dev; bool enable_cmd_dat_delay; @@ -150,6 +152,16 @@ static int sdhci_f_sdh30_probe(struct platform_device *pdev) ret = clk_prepare_enable(priv->clk); if (ret) goto err_clk; + + priv->rst = devm_reset_control_get_optional_shared(dev, NULL); + if (IS_ERR(priv->rst)) { + ret = PTR_ERR(priv->rst); + goto err_rst; + } + + ret = reset_control_deassert(priv->rst); + if (ret) + goto err_rst; } /* init vendor specific regs */ @@ -175,6 +187,8 @@ static int sdhci_f_sdh30_probe(struct platform_device *pdev) return 0; err_add_host: + reset_control_assert(priv->rst); +err_rst: clk_disable_unprepare(priv->clk); err_clk: clk_disable_unprepare(priv->clk_iface); @@ -191,8 +205,9 @@ static int sdhci_f_sdh30_remove(struct platform_device *pdev) sdhci_remove_host(host, readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); - clk_disable_unprepare(priv->clk_iface); + reset_control_assert(priv->rst); clk_disable_unprepare(priv->clk); + clk_disable_unprepare(priv->clk_iface); sdhci_free_host(host); platform_set_drvdata(pdev, NULL); -- cgit v1.2.3 From 5914a9b16c842056c946665a39aa0ac5923a2d1f Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Fri, 11 Nov 2022 17:10:31 +0900 Subject: mmc: f-sdh30: Add compatible string for Socionext F_SDH30_E51 Add a compatible string for Socionext F_SDH30_E51. Since this IP is transferred to Socionext, so append it to Copyright and MODULE_AUTHOR as vendor name. F_SDH30_E51 is a higher version of F_SDH30 that supports eMMC 5.1, though, currently there are no new features for this IP in this driver, just add the compatible string. Signed-off-by: Kunihiko Hayashi Link: https://lore.kernel.org/r/20221111081033.3813-5-hayashi.kunihiko@socionext.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci_f_sdh30.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci_f_sdh30.c b/drivers/mmc/host/sdhci_f_sdh30.c index 7f4553b28180..556f4601643d 100644 --- a/drivers/mmc/host/sdhci_f_sdh30.c +++ b/drivers/mmc/host/sdhci_f_sdh30.c @@ -5,6 +5,7 @@ * Copyright (C) 2013 - 2015 Fujitsu Semiconductor, Ltd * Vincent Yang * Copyright (C) 2015 Linaro Ltd Andy Green + * Copyright (C) 2019 Socionext Inc. */ #include @@ -218,6 +219,7 @@ static int sdhci_f_sdh30_remove(struct platform_device *pdev) #ifdef CONFIG_OF static const struct of_device_id f_sdh30_dt_ids[] = { { .compatible = "fujitsu,mb86s70-sdhci-3.0" }, + { .compatible = "socionext,f-sdh30-e51-mmc" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, f_sdh30_dt_ids); @@ -247,5 +249,5 @@ module_platform_driver(sdhci_f_sdh30_driver); MODULE_DESCRIPTION("F_SDH30 SD Card Controller driver"); MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("FUJITSU SEMICONDUCTOR LTD."); +MODULE_AUTHOR("FUJITSU SEMICONDUCTOR LTD., Socionext Inc."); MODULE_ALIAS("platform:f_sdh30"); -- cgit v1.2.3 From e2d2dcc82504b1beee9f2542e8b43b8c43829302 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Fri, 11 Nov 2022 17:10:32 +0900 Subject: mmc: f-sdh30: Add support for non-removable media To use F_SDH30 for non-removable meda like eMMC, need to enable FORCE_CARD_INSERT bit to skip the delay for detection. Signed-off-by: Kunihiko Hayashi Acked-by: Jassi Brar Link: https://lore.kernel.org/r/20221111081033.3813-6-hayashi.kunihiko@socionext.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci_f_sdh30.c | 7 +++++++ drivers/mmc/host/sdhci_f_sdh30.h | 3 +++ 2 files changed, 10 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci_f_sdh30.c b/drivers/mmc/host/sdhci_f_sdh30.c index 556f4601643d..afbe17312cb6 100644 --- a/drivers/mmc/host/sdhci_f_sdh30.c +++ b/drivers/mmc/host/sdhci_f_sdh30.c @@ -77,6 +77,13 @@ static void sdhci_f_sdh30_reset(struct sdhci_host *host, u8 mask) ctl |= F_SDH30_CMD_DAT_DELAY; sdhci_writel(host, ctl, F_SDH30_ESD_CONTROL); } + + if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) && + !(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { + ctl = sdhci_readl(host, F_SDH30_TEST); + ctl |= F_SDH30_FORCE_CARD_INSERT; + sdhci_writel(host, ctl, F_SDH30_TEST); + } } static const struct sdhci_ops sdhci_f_sdh30_ops = { diff --git a/drivers/mmc/host/sdhci_f_sdh30.h b/drivers/mmc/host/sdhci_f_sdh30.h index fc1ad28f7ca9..7c3c66291d42 100644 --- a/drivers/mmc/host/sdhci_f_sdh30.h +++ b/drivers/mmc/host/sdhci_f_sdh30.h @@ -29,4 +29,7 @@ #define F_SDH30_CMD_DAT_DELAY BIT(9) #define F_SDH30_EMMC_HS200 BIT(24) +#define F_SDH30_TEST 0x158 +#define F_SDH30_FORCE_CARD_INSERT BIT(6) + #define F_SDH30_MIN_CLOCK 400000 -- cgit v1.2.3 From aae9d3a440736691b3c1cb09ae2c32c4f1ee2e67 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Fri, 11 Nov 2022 17:10:33 +0900 Subject: mmc: f-sdh30: Add quirks for broken timeout clock capability There is a case where the timeout clock is not supplied to the capability. Add a quirk for that. Signed-off-by: Kunihiko Hayashi Acked-by: Jassi Brar Link: https://lore.kernel.org/r/20221111081033.3813-7-hayashi.kunihiko@socionext.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci_f_sdh30.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci_f_sdh30.c b/drivers/mmc/host/sdhci_f_sdh30.c index afbe17312cb6..a202a69a4b08 100644 --- a/drivers/mmc/host/sdhci_f_sdh30.c +++ b/drivers/mmc/host/sdhci_f_sdh30.c @@ -188,6 +188,9 @@ static int sdhci_f_sdh30_probe(struct platform_device *pdev) if (reg & SDHCI_CAN_DO_8BIT) priv->vendor_hs200 = F_SDH30_EMMC_HS200; + if (!(reg & SDHCI_TIMEOUT_CLK_MASK)) + host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK; + ret = sdhci_add_host(host); if (ret) goto err_add_host; -- cgit v1.2.3 From a8687078fc5e7606b3e91f32cb6ba2574d83736d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 6 Oct 2022 21:04:47 +0200 Subject: mmc: renesas_sdhi: remove accessor function for internal_dmac This accessor function does not help readability but makes it worse. Because I soon need to read from the registers as well and don't want to add another function like this, I chose to remove the existing one and use the accessor directly. I also switch from writeq to writel because no 64 bit register is actually involved. Signed-off-by: Wolfram Sang Tested-by: Duy Nguyen Tested-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20221006190452.5316-2-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi_internal_dmac.c | 31 +++++++-------------------- 1 file changed, 8 insertions(+), 23 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 42937596c4c4..48bea0bd75e8 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -279,13 +279,6 @@ static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = { }; MODULE_DEVICE_TABLE(of, renesas_sdhi_internal_dmac_of_match); -static void -renesas_sdhi_internal_dmac_dm_write(struct tmio_mmc_host *host, - int addr, u64 val) -{ - writeq(val, host->ctl + addr); -} - static void renesas_sdhi_internal_dmac_enable_dma(struct tmio_mmc_host *host, bool enable) { @@ -295,8 +288,7 @@ renesas_sdhi_internal_dmac_enable_dma(struct tmio_mmc_host *host, bool enable) return; if (!enable) - renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO1, - INFO1_CLEAR); + writel(INFO1_CLEAR, host->ctl + DM_CM_INFO1); if (priv->dma_priv.enable) priv->dma_priv.enable(host, enable); @@ -309,10 +301,8 @@ renesas_sdhi_internal_dmac_abort_dma(struct tmio_mmc_host *host) renesas_sdhi_internal_dmac_enable_dma(host, false); - renesas_sdhi_internal_dmac_dm_write(host, DM_CM_RST, - RST_RESERVED_BITS & ~val); - renesas_sdhi_internal_dmac_dm_write(host, DM_CM_RST, - RST_RESERVED_BITS | val); + writel(RST_RESERVED_BITS & ~val, host->ctl + DM_CM_RST); + writel(RST_RESERVED_BITS | val, host->ctl + DM_CM_RST); clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags); @@ -397,10 +387,8 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host, renesas_sdhi_internal_dmac_enable_dma(host, true); /* set dma parameters */ - renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_MODE, - dtran_mode); - renesas_sdhi_internal_dmac_dm_write(host, DM_DTRAN_ADDR, - sg_dma_address(sg)); + writel(dtran_mode, host->ctl + DM_CM_DTRAN_MODE); + writel(sg_dma_address(sg), host->ctl + DM_DTRAN_ADDR); host->dma_on = true; @@ -420,8 +408,7 @@ static void renesas_sdhi_internal_dmac_issue_tasklet_fn(unsigned long arg) tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND); /* start the DMAC */ - renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_CTRL, - DTRAN_CTRL_DM_START); + writel(DTRAN_CTRL_DM_START, host->ctl + DM_CM_DTRAN_CTRL); } static bool renesas_sdhi_internal_dmac_complete(struct tmio_mmc_host *host) @@ -502,10 +489,8 @@ renesas_sdhi_internal_dmac_request_dma(struct tmio_mmc_host *host, struct renesas_sdhi *priv = host_to_priv(host); /* Disable DMAC interrupts, we don't use them */ - renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO1_MASK, - INFO1_MASK_CLEAR); - renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO2_MASK, - INFO2_MASK_CLEAR); + writel(INFO1_MASK_CLEAR, host->ctl + DM_CM_INFO1_MASK); + writel(INFO2_MASK_CLEAR, host->ctl + DM_CM_INFO2_MASK); /* Each value is set to non-zero to assume "enabling" each DMA */ host->chan_rx = host->chan_tx = (void *)0xdeadbeaf; -- cgit v1.2.3 From 7f3ea248cd1b2ea9b49f6f3523250bc8e622dd5e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 6 Oct 2022 21:04:48 +0200 Subject: mmc: renesas_sdhi: improve naming of DMA struct Commit 058db2868cd8 ("mmc: tmio, renesas_sdhi: move struct tmio_mmc_dma to renesas_sdhi.h") is correct. The DMA struct should be prefixed with 'renesas_sdhi' to avoid confusion about is namespace. Fix some indentation while here. Signed-off-by: Wolfram Sang Tested-by: Duy Nguyen Tested-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20221006190452.5316-3-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi.h | 8 ++++---- drivers/mmc/host/renesas_sdhi_core.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h index c4abfee1ebae..b661892847f6 100644 --- a/drivers/mmc/host/renesas_sdhi.h +++ b/drivers/mmc/host/renesas_sdhi.h @@ -53,12 +53,12 @@ struct renesas_sdhi_of_data_with_quirks { const struct renesas_sdhi_quirks *quirks; }; -struct tmio_mmc_dma { +struct renesas_sdhi_dma { enum dma_slave_buswidth dma_buswidth; bool (*filter)(struct dma_chan *chan, void *arg); void (*enable)(struct tmio_mmc_host *host, bool enable); - struct completion dma_dataend; - struct tasklet_struct dma_complete; + struct completion dma_dataend; + struct tasklet_struct dma_complete; }; struct renesas_sdhi { @@ -66,7 +66,7 @@ struct renesas_sdhi { struct clk *clkh; struct clk *clk_cd; struct tmio_mmc_data mmc_data; - struct tmio_mmc_dma dma_priv; + struct renesas_sdhi_dma dma_priv; const struct renesas_sdhi_quirks *quirks; struct pinctrl *pinctrl; struct pinctrl_state *pins_default, *pins_uhs; diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index b970699743e0..0733951325e9 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -908,7 +908,7 @@ int renesas_sdhi_probe(struct platform_device *pdev, { struct tmio_mmc_data *mmd = pdev->dev.platform_data; struct tmio_mmc_data *mmc_data; - struct tmio_mmc_dma *dma_priv; + struct renesas_sdhi_dma *dma_priv; struct tmio_mmc_host *host; struct renesas_sdhi *priv; int num_irqs, irq, ret, i; -- cgit v1.2.3 From af728d7ae20483add9f8d3c81280dc6298a0aa2e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 6 Oct 2022 21:04:49 +0200 Subject: mmc: tmio: add callback for dma irq We don't want to rely only on the access_end irq in the future, so implement a callback for dma irqs. Signed-off-by: Wolfram Sang Tested-by: Duy Nguyen Tested-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20221006190452.5316-4-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/tmio_mmc.h | 1 + drivers/mmc/host/tmio_mmc_core.c | 3 +++ 2 files changed, 4 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index e36ff80108e6..f3afbed7d340 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -128,6 +128,7 @@ struct tmio_mmc_dma_ops { /* optional */ void (*end)(struct tmio_mmc_host *host); /* held host->lock */ + bool (*dma_irq)(struct tmio_mmc_host *host); }; struct tmio_mmc_host { diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index 6d50c0dd53fe..61f616c5b190 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -668,6 +668,9 @@ static bool __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host, int ireg, return true; } + if (host->dma_ops && host->dma_ops->dma_irq && host->dma_ops->dma_irq(host)) + return true; + return false; } -- cgit v1.2.3 From ec9e80ae1719de541c719116a1ca0a0c70e9240c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 6 Oct 2022 21:04:50 +0200 Subject: mmc: renesas_sdhi: add quirk for broken register layout Some early Gen3 SoCs have the DTRANEND1 bit at a different location than all later SoCs. Because we need the bit soon, add a quirk so we know which bit to use. Signed-off-by: Wolfram Sang Tested-by: Duy Nguyen Tested-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20221006190452.5316-5-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi.h | 1 + drivers/mmc/host/renesas_sdhi_internal_dmac.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h index b661892847f6..fa88b721364c 100644 --- a/drivers/mmc/host/renesas_sdhi.h +++ b/drivers/mmc/host/renesas_sdhi.h @@ -44,6 +44,7 @@ struct renesas_sdhi_quirks { bool fixed_addr_mode; bool dma_one_rx_only; bool manual_tap_correction; + bool old_info1_layout; u32 hs400_bad_taps; const u8 (*hs400_calib_table)[SDHI_CALIB_TABLE_MAX]; }; diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 48bea0bd75e8..630ec1e785d6 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -49,7 +49,8 @@ /* DM_CM_INFO1 and DM_CM_INFO1_MASK */ #define INFO1_CLEAR 0 #define INFO1_MASK_CLEAR GENMASK_ULL(31, 0) -#define INFO1_DTRANEND1 BIT(17) +#define INFO1_DTRANEND1 BIT(20) +#define INFO1_DTRANEND1_OLD BIT(17) #define INFO1_DTRANEND0 BIT(16) /* DM_CM_INFO2 and DM_CM_INFO2_MASK */ @@ -165,6 +166,7 @@ static const struct renesas_sdhi_quirks sdhi_quirks_4tap_nohs400_one_rx = { .hs400_disabled = true, .hs400_4taps = true, .dma_one_rx_only = true, + .old_info1_layout = true, }; static const struct renesas_sdhi_quirks sdhi_quirks_4tap = { -- cgit v1.2.3 From c330601c9c93392000c077d973b182cc0164b9ac Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 6 Oct 2022 21:04:51 +0200 Subject: mmc: renesas_sdhi: take DMA end interrupts into account So far, we have been relying on access_end interrupts only to mark DMA transfers as done implying that DMA end interrupts have occurred by then anyhow. On some SoCs under some conditions, this turned out to be not enough. So, we enable DMA interrupts as well and make sure that both events, DMA irq and access_end irq, have happened before finishing the DMA transfer. Signed-off-by: Wolfram Sang Tested-by: Duy Nguyen Tested-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20221006190452.5316-6-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi.h | 5 +++ drivers/mmc/host/renesas_sdhi_internal_dmac.c | 51 +++++++++++++++++++++++---- 2 files changed, 49 insertions(+), 7 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h index fa88b721364c..8f96457c9739 100644 --- a/drivers/mmc/host/renesas_sdhi.h +++ b/drivers/mmc/host/renesas_sdhi.h @@ -54,7 +54,12 @@ struct renesas_sdhi_of_data_with_quirks { const struct renesas_sdhi_quirks *quirks; }; +/* We want both end_flags to be set before we mark DMA as finished */ +#define SDHI_DMA_END_FLAG_DMA BIT(0) +#define SDHI_DMA_END_FLAG_ACCESS BIT(1) + struct renesas_sdhi_dma { + unsigned long end_flags; enum dma_slave_buswidth dma_buswidth; bool (*filter)(struct dma_chan *chan, void *arg); void (*enable)(struct tmio_mmc_host *host, bool enable); diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 630ec1e785d6..f6d1e04a627f 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -47,7 +47,6 @@ #define RST_RESERVED_BITS GENMASK_ULL(31, 0) /* DM_CM_INFO1 and DM_CM_INFO1_MASK */ -#define INFO1_CLEAR 0 #define INFO1_MASK_CLEAR GENMASK_ULL(31, 0) #define INFO1_DTRANEND1 BIT(20) #define INFO1_DTRANEND1_OLD BIT(17) @@ -285,12 +284,14 @@ static void renesas_sdhi_internal_dmac_enable_dma(struct tmio_mmc_host *host, bool enable) { struct renesas_sdhi *priv = host_to_priv(host); + u32 dma_irqs = INFO1_DTRANEND0 | + (priv->quirks && priv->quirks->old_info1_layout ? + INFO1_DTRANEND1_OLD : INFO1_DTRANEND1); if (!host->chan_tx || !host->chan_rx) return; - if (!enable) - writel(INFO1_CLEAR, host->ctl + DM_CM_INFO1); + writel(enable ? ~dma_irqs : INFO1_MASK_CLEAR, host->ctl + DM_CM_INFO1_MASK); if (priv->dma_priv.enable) priv->dma_priv.enable(host, enable); @@ -311,12 +312,36 @@ renesas_sdhi_internal_dmac_abort_dma(struct tmio_mmc_host *host) renesas_sdhi_internal_dmac_enable_dma(host, true); } +static bool renesas_sdhi_internal_dmac_dma_irq(struct tmio_mmc_host *host) +{ + struct renesas_sdhi *priv = host_to_priv(host); + struct renesas_sdhi_dma *dma_priv = &priv->dma_priv; + + u32 dma_irqs = INFO1_DTRANEND0 | + (priv->quirks && priv->quirks->old_info1_layout ? + INFO1_DTRANEND1_OLD : INFO1_DTRANEND1); + u32 status = readl(host->ctl + DM_CM_INFO1); + + if (status & dma_irqs) { + writel(status ^ dma_irqs, host->ctl + DM_CM_INFO1); + set_bit(SDHI_DMA_END_FLAG_DMA, &dma_priv->end_flags); + if (test_bit(SDHI_DMA_END_FLAG_ACCESS, &dma_priv->end_flags)) + tasklet_schedule(&dma_priv->dma_complete); + } + + return status & dma_irqs; +} + static void renesas_sdhi_internal_dmac_dataend_dma(struct tmio_mmc_host *host) { struct renesas_sdhi *priv = host_to_priv(host); + struct renesas_sdhi_dma *dma_priv = &priv->dma_priv; - tasklet_schedule(&priv->dma_priv.dma_complete); + set_bit(SDHI_DMA_END_FLAG_ACCESS, &dma_priv->end_flags); + if (test_bit(SDHI_DMA_END_FLAG_DMA, &dma_priv->end_flags) || + host->data->error) + tasklet_schedule(&dma_priv->dma_complete); } /* @@ -386,6 +411,7 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host, dtran_mode |= DTRAN_MODE_CH_NUM_CH0; } + priv->dma_priv.end_flags = 0; renesas_sdhi_internal_dmac_enable_dma(host, true); /* set dma parameters */ @@ -406,11 +432,19 @@ force_pio: static void renesas_sdhi_internal_dmac_issue_tasklet_fn(unsigned long arg) { struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg; + struct renesas_sdhi *priv = host_to_priv(host); tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND); - /* start the DMAC */ - writel(DTRAN_CTRL_DM_START, host->ctl + DM_CM_DTRAN_CTRL); + if (!host->cmd->error) { + /* start the DMAC */ + writel(DTRAN_CTRL_DM_START, host->ctl + DM_CM_DTRAN_CTRL); + } else { + /* on CMD errors, simulate DMA end immediately */ + set_bit(SDHI_DMA_END_FLAG_DMA, &priv->dma_priv.end_flags); + if (test_bit(SDHI_DMA_END_FLAG_ACCESS, &priv->dma_priv.end_flags)) + tasklet_schedule(&priv->dma_priv.dma_complete); + } } static bool renesas_sdhi_internal_dmac_complete(struct tmio_mmc_host *host) @@ -490,9 +524,11 @@ renesas_sdhi_internal_dmac_request_dma(struct tmio_mmc_host *host, { struct renesas_sdhi *priv = host_to_priv(host); - /* Disable DMAC interrupts, we don't use them */ + /* Disable DMAC interrupts initially */ writel(INFO1_MASK_CLEAR, host->ctl + DM_CM_INFO1_MASK); writel(INFO2_MASK_CLEAR, host->ctl + DM_CM_INFO2_MASK); + writel(0, host->ctl + DM_CM_INFO1); + writel(0, host->ctl + DM_CM_INFO2); /* Each value is set to non-zero to assume "enabling" each DMA */ host->chan_rx = host->chan_tx = (void *)0xdeadbeaf; @@ -524,6 +560,7 @@ static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = { .abort = renesas_sdhi_internal_dmac_abort_dma, .dataend = renesas_sdhi_internal_dmac_dataend_dma, .end = renesas_sdhi_internal_dmac_end_dma, + .dma_irq = renesas_sdhi_internal_dmac_dma_irq, }; static int renesas_sdhi_internal_dmac_probe(struct platform_device *pdev) -- cgit v1.2.3 From 8840e1c13cb40d2a207f875f3c730f399a21d4d4 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 2 Nov 2022 13:54:29 +0100 Subject: mmc: tmio: remove tmio_mmc_k(un)map_atomic helpers After a8402aed8ca5 ("mmc: tmio_mmc_core: Remove local_irq_{save,restore}() around k[un]map_atomic()") and ac91578a6812 ("mmc: tmio_mmc_core: Replace kmap_atomic() with kmap_local_page()"), the helpers contain just a single call. Putting it directly in the code makes it actually more readable. More so, because we now avoid the 'offset' calculation when mapping/unmapping and just use it when we need it in the copy routines. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20221102125430.28466-2-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi_sys_dmac.c | 6 +++--- drivers/mmc/host/tmio_mmc.h | 11 ----------- drivers/mmc/host/tmio_mmc_core.c | 13 +++++++------ 3 files changed, 10 insertions(+), 20 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c index e9cc6c15d229..c4545cb143dd 100644 --- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c @@ -254,11 +254,11 @@ static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host) /* The only sg element can be unaligned, use our bounce buffer then */ if (!aligned) { - void *sg_vaddr = tmio_mmc_kmap_atomic(sg); + void *sg_vaddr = kmap_local_page(sg_page(sg)); sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); - memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length); - tmio_mmc_kunmap_atomic(sg, sg_vaddr); + memcpy(host->bounce_buf, sg_vaddr + sg->offset, host->bounce_sg.length); + kunmap_local(sg_vaddr); host->sg_ptr = &host->bounce_sg; sg = host->sg_ptr; } diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index f3afbed7d340..de56e6534aea 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -205,17 +205,6 @@ void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i); void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i); irqreturn_t tmio_mmc_irq(int irq, void *devid); -static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg) -{ - return kmap_local_page(sg_page(sg)) + sg->offset; -} - -static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg, - void *virt) -{ - kunmap_local(virt - sg->offset); -} - #ifdef CONFIG_PM int tmio_mmc_host_runtime_suspend(struct device *dev); int tmio_mmc_host_runtime_resume(struct device *dev); diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index 61f616c5b190..e24c3d284515 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -421,8 +421,8 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) return; } - sg_virt = tmio_mmc_kmap_atomic(host->sg_ptr); - buf = (unsigned short *)(sg_virt + host->sg_off); + sg_virt = kmap_local_page(sg_page(host->sg_ptr)); + buf = (unsigned short *)(sg_virt + host->sg_ptr->offset + host->sg_off); count = host->sg_ptr->length - host->sg_off; if (count > data->blksz) @@ -436,7 +436,7 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) host->sg_off += count; - tmio_mmc_kunmap_atomic(host->sg_ptr, sg_virt); + kunmap_local(sg_virt); if (host->sg_off == host->sg_ptr->length) tmio_mmc_next_sg(host); @@ -445,10 +445,11 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) static void tmio_mmc_check_bounce_buffer(struct tmio_mmc_host *host) { if (host->sg_ptr == &host->bounce_sg) { - void *sg_vaddr = tmio_mmc_kmap_atomic(host->sg_orig); + void *sg_virt = kmap_local_page(sg_page(host->sg_orig)); - memcpy(sg_vaddr, host->bounce_buf, host->bounce_sg.length); - tmio_mmc_kunmap_atomic(host->sg_orig, sg_vaddr); + memcpy(sg_virt + host->sg_orig->offset, host->bounce_buf, + host->bounce_sg.length); + kunmap_local(sg_virt); } } -- cgit v1.2.3 From 43c487c28f9c353a9690f975e7b7dc56be144427 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 2 Nov 2022 13:54:30 +0100 Subject: mmc: tmio: remove 'alignment_shift' from platform data There is only one alignment shift for one type of Renesas SDHI. Encode it directly in its DMA driver to reduce complexity and ease further simplifications. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20221102125430.28466-3-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi_core.c | 1 - drivers/mmc/host/renesas_sdhi_sys_dmac.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 0733951325e9..b93ab11f112a 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -1018,7 +1018,6 @@ int renesas_sdhi_probe(struct platform_device *pdev, dma_priv->filter = shdma_chan_filter; dma_priv->enable = renesas_sdhi_enable_dma; - mmc_data->alignment_shift = 1; /* 2-byte alignment */ mmc_data->capabilities |= MMC_CAP_MMC_HIGHSPEED; /* diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c index c4545cb143dd..b559ad38b667 100644 --- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c @@ -160,7 +160,7 @@ static void renesas_sdhi_sys_dmac_start_dma_rx(struct tmio_mmc_host *host) dma_cookie_t cookie; int ret, i; bool aligned = true, multiple = true; - unsigned int align = (1 << host->pdata->alignment_shift) - 1; + unsigned int align = 1; /* 2-byte alignment */ for_each_sg(sg, sg_tmp, host->sg_len, i) { if (sg_tmp->offset & align) @@ -232,7 +232,7 @@ static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host) dma_cookie_t cookie; int ret, i; bool aligned = true, multiple = true; - unsigned int align = (1 << host->pdata->alignment_shift) - 1; + unsigned int align = 1; /* 2-byte alignment */ for_each_sg(sg, sg_tmp, host->sg_len, i) { if (sg_tmp->offset & align) -- cgit v1.2.3 From 63abdf7237a7ab9e3ee30782d64d968a087c7e7a Mon Sep 17 00:00:00 2001 From: Charl Liu Date: Fri, 11 Nov 2022 04:23:14 -0800 Subject: mmc: sdhci: Fix the SD tuning issue that the SDHCI_TRANSFER_MODE is cleared incorrectly When cmd->opcode == MMC_SEND_TUNING_BLOCK, the SDHCI_TRANSFER_MODE should also be kept Signed-off-by: Charl Liu Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20221111122314.307-1-charl.liu@bayhubtech.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index ebb71d235c38..64750fbb0ac8 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1452,7 +1452,7 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, if (host->quirks2 & SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD) { /* must not clear SDHCI_TRANSFER_MODE when tuning */ - if (cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200) + if (!mmc_op_tuning(cmd->opcode)) sdhci_writew(host, 0x0, SDHCI_TRANSFER_MODE); } else { /* clear Auto CMD settings for no data CMDs */ -- cgit v1.2.3 From ef87bd81cb881377c1eaf512167b0522c825b012 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Mon, 14 Nov 2022 17:02:15 -0600 Subject: mmc: dw_mmc-pltfm: socfpga: add method to configure clk-phase The clock-phase settings for the SDMMC controller in the SoCFPGA platforms reside in a register in the System Manager. Add a method to access that register through the syscon interface. Signed-off-by: Dinh Nguyen Link: https://lore.kernel.org/r/20221114230217.202634-4-dinguyen@kernel.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc-pltfm.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c index 9901208be797..13e55cff8237 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.c +++ b/drivers/mmc/host/dw_mmc-pltfm.c @@ -17,10 +17,16 @@ #include #include #include +#include +#include #include "dw_mmc.h" #include "dw_mmc-pltfm.h" +#define SOCFPGA_DW_MMC_CLK_PHASE_STEP 45 +#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel, reg_shift) \ + ((((smplsel) & 0x7) << reg_shift) | (((drvsel) & 0x7) << 0)) + int dw_mci_pltfm_register(struct platform_device *pdev, const struct dw_mci_drv_data *drv_data) { @@ -62,9 +68,42 @@ const struct dev_pm_ops dw_mci_pltfm_pmops = { }; EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops); +static int dw_mci_socfpga_priv_init(struct dw_mci *host) +{ + struct device_node *np = host->dev->of_node; + struct regmap *sys_mgr_base_addr; + u32 clk_phase[2] = {0}, reg_offset, reg_shift; + int i, rc, hs_timing; + + rc = of_property_read_variable_u32_array(np, "clk-phase-sd-hs", &clk_phase[0], 2, 0); + if (rc < 0) + return 0; + + sys_mgr_base_addr = altr_sysmgr_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon"); + if (IS_ERR(sys_mgr_base_addr)) { + dev_warn(host->dev, "clk-phase-sd-hs was specified, but failed to find altr,sys-mgr regmap!\n"); + return 0; + } + + of_property_read_u32_index(np, "altr,sysmgr-syscon", 1, ®_offset); + of_property_read_u32_index(np, "altr,sysmgr-syscon", 2, ®_shift); + + for (i = 0; i < ARRAY_SIZE(clk_phase); i++) + clk_phase[i] /= SOCFPGA_DW_MMC_CLK_PHASE_STEP; + + hs_timing = SYSMGR_SDMMC_CTRL_SET(clk_phase[0], clk_phase[1], reg_shift); + regmap_write(sys_mgr_base_addr, reg_offset, hs_timing); + + return 0; +} + +static const struct dw_mci_drv_data socfpga_drv_data = { + .init = dw_mci_socfpga_priv_init, +}; + static const struct of_device_id dw_mci_pltfm_match[] = { { .compatible = "snps,dw-mshc", }, - { .compatible = "altr,socfpga-dw-mshc", }, + { .compatible = "altr,socfpga-dw-mshc", .data = &socfpga_drv_data, }, { .compatible = "img,pistachio-dw-mshc", }, {}, }; -- cgit v1.2.3 From fa30beccca969ad2fb9431faf1f12ecb6fdb14ce Mon Sep 17 00:00:00 2001 From: ye xingchen Date: Thu, 17 Nov 2022 15:24:11 +0800 Subject: mmc: pwrseq: Use device_match_of_node() Replace the open-code with device_match_of_node(). Signed-off-by: ye xingchen Link: https://lore.kernel.org/r/202211171524116446204@zte.com.cn Signed-off-by: Ulf Hansson --- drivers/mmc/core/pwrseq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/core/pwrseq.c b/drivers/mmc/core/pwrseq.c index ef675f364bf0..2374669b588a 100644 --- a/drivers/mmc/core/pwrseq.c +++ b/drivers/mmc/core/pwrseq.c @@ -29,7 +29,7 @@ int mmc_pwrseq_alloc(struct mmc_host *host) mutex_lock(&pwrseq_list_mutex); list_for_each_entry(p, &pwrseq_list, pwrseq_node) { - if (p->dev->of_node == np) { + if (device_match_of_node(p->dev, np)) { if (!try_module_get(p->owner)) dev_err(host->parent, "increasing module refcount failed\n"); -- cgit v1.2.3 From 3d4f9898c1c74323dd61d6a8a0efca9401232ad4 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 20 Nov 2022 12:34:54 +0100 Subject: mmc: renesas_sdhi: alway populate SCC pointer We need the SCC pointer to reset the device, so populate it even when we don't need it for tuning. Fixes: 45bffc371fef ("mmc: renesas_sdhi: only reset SCC when its pointer is populated") Signed-off-by: Takeshi Saito Signed-off-by: Takeshi Kihara Signed-off-by: Wolfram Sang Reviewed-by: Yoshihiro Shimoda Tested-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20221120113457.42010-2-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi_core.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index b93ab11f112a..4372197dc2a9 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -1067,11 +1067,14 @@ int renesas_sdhi_probe(struct platform_device *pdev, if (ver >= SDHI_VER_GEN3_SD) host->get_timeout_cycles = renesas_sdhi_gen3_get_cycles; + /* Check for SCC so we can reset it if needed */ + if (of_data && of_data->scc_offset && ver >= SDHI_VER_GEN2_SDR104) + priv->scc_ctl = host->ctl + of_data->scc_offset; + /* Enable tuning iff we have an SCC and a supported mode */ - if (of_data && of_data->scc_offset && - (host->mmc->caps & MMC_CAP_UHS_SDR104 || - host->mmc->caps2 & (MMC_CAP2_HS200_1_8V_SDR | - MMC_CAP2_HS400_1_8V))) { + if (priv->scc_ctl && (host->mmc->caps & MMC_CAP_UHS_SDR104 || + host->mmc->caps2 & (MMC_CAP2_HS200_1_8V_SDR | + MMC_CAP2_HS400_1_8V))) { const struct renesas_sdhi_scc *taps = of_data->taps; bool use_4tap = quirks && quirks->hs400_4taps; bool hit = false; @@ -1091,7 +1094,6 @@ int renesas_sdhi_probe(struct platform_device *pdev, if (!hit) dev_warn(&host->pdev->dev, "Unknown clock rate for tuning\n"); - priv->scc_ctl = host->ctl + of_data->scc_offset; host->check_retune = renesas_sdhi_check_scc_error; host->ops.execute_tuning = renesas_sdhi_execute_tuning; host->ops.prepare_hs400_tuning = renesas_sdhi_prepare_hs400_tuning; -- cgit v1.2.3 From 0da69dd2155019ed4c444ede0e79ce7a4a6af627 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 20 Nov 2022 12:34:55 +0100 Subject: mmc: renesas_sdhi: better reset from HS400 mode Up to now, HS400 adjustment mode was only disabled on soft reset when a calibration table was in use. It is safer, though, to disable it as soon as the instance has an adjustment related quirk set, i.e. bad taps or a calibration table. Signed-off-by: Wolfram Sang Reviewed-by: Yoshihiro Shimoda Tested-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20221120113457.42010-3-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 4372197dc2a9..d2521cf1411d 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -546,7 +546,7 @@ static void renesas_sdhi_reset_hs400_mode(struct tmio_mmc_host *host, SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) & sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2)); - if (priv->adjust_hs400_calib_table) + if (priv->quirks && (priv->quirks->hs400_calib_table || priv->quirks->hs400_bad_taps)) renesas_sdhi_adjust_hs400_mode_disable(host); sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | -- cgit v1.2.3 From 48c917fa998c00980167ba732c8ccbf603c9fb70 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 20 Nov 2022 12:34:56 +0100 Subject: mmc: renesas_sdhi: add helper to access quirks Add a macro to check for a quirk because it a) ensures that the check for non-empty 'quirks' struct is not forgotten and b) is easier to read. Convert existing quirk access as well. Signed-off-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Reviewed-by: Yoshihiro Shimoda Tested-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20221120113457.42010-4-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi.h | 2 ++ drivers/mmc/host/renesas_sdhi_core.c | 18 +++++++++--------- drivers/mmc/host/renesas_sdhi_internal_dmac.c | 8 ++++---- 3 files changed, 15 insertions(+), 13 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h index 8f96457c9739..ea2a85174a09 100644 --- a/drivers/mmc/host/renesas_sdhi.h +++ b/drivers/mmc/host/renesas_sdhi.h @@ -38,6 +38,8 @@ struct renesas_sdhi_of_data { #define SDHI_CALIB_TABLE_MAX 32 +#define sdhi_has_quirk(p, q) ((p)->quirks && (p)->quirks->q) + struct renesas_sdhi_quirks { bool hs400_disabled; bool hs400_4taps; diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index d2521cf1411d..ad8f79fe01b2 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -141,7 +141,7 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host, if (priv->clkh) { /* HS400 with 4TAP needs different clock settings */ - bool use_4tap = priv->quirks && priv->quirks->hs400_4taps; + bool use_4tap = sdhi_has_quirk(priv, hs400_4taps); bool need_slow_clkh = host->mmc->ios.timing == MMC_TIMING_MMC_HS400; clkh_shift = use_4tap && need_slow_clkh ? 1 : 2; ref_clk = priv->clkh; @@ -383,7 +383,7 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc) struct tmio_mmc_host *host = mmc_priv(mmc); struct renesas_sdhi *priv = host_to_priv(host); u32 bad_taps = priv->quirks ? priv->quirks->hs400_bad_taps : 0; - bool use_4tap = priv->quirks && priv->quirks->hs400_4taps; + bool use_4tap = sdhi_has_quirk(priv, hs400_4taps); sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); @@ -395,7 +395,7 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc) sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, priv->scc_tappos_hs400); - if (priv->quirks && priv->quirks->manual_tap_correction) + if (sdhi_has_quirk(priv, manual_tap_correction)) sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN & sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); @@ -546,7 +546,7 @@ static void renesas_sdhi_reset_hs400_mode(struct tmio_mmc_host *host, SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) & sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2)); - if (priv->quirks && (priv->quirks->hs400_calib_table || priv->quirks->hs400_bad_taps)) + if (sdhi_has_quirk(priv, hs400_calib_table) || sdhi_has_quirk(priv, hs400_bad_taps)) renesas_sdhi_adjust_hs400_mode_disable(host); sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | @@ -732,7 +732,7 @@ static bool renesas_sdhi_manual_correction(struct tmio_mmc_host *host, bool use_ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0); /* Change TAP position according to correction status */ - if (priv->quirks && priv->quirks->manual_tap_correction && + if (sdhi_has_quirk(priv, manual_tap_correction) && host->mmc->ios.timing == MMC_TIMING_MMC_HS400) { u32 bad_taps = priv->quirks ? priv->quirks->hs400_bad_taps : 0; /* @@ -796,7 +796,7 @@ static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host, struct mmc_request *mrq) { struct renesas_sdhi *priv = host_to_priv(host); - bool use_4tap = priv->quirks && priv->quirks->hs400_4taps; + bool use_4tap = sdhi_has_quirk(priv, hs400_4taps); bool ret = false; /* @@ -990,7 +990,7 @@ int renesas_sdhi_probe(struct platform_device *pdev, host->multi_io_quirk = renesas_sdhi_multi_io_quirk; host->dma_ops = dma_ops; - if (quirks && quirks->hs400_disabled) + if (sdhi_has_quirk(priv, hs400_disabled)) host->mmc->caps2 &= ~(MMC_CAP2_HS400 | MMC_CAP2_HS400_ES); /* For some SoC, we disable internal WP. GPIO may override this */ @@ -1055,7 +1055,7 @@ int renesas_sdhi_probe(struct platform_device *pdev, if (ver == SDHI_VER_GEN2_SDR50) mmc_data->flags &= ~TMIO_MMC_HAVE_CBSY; - if (ver == SDHI_VER_GEN3_SDMMC && quirks && quirks->hs400_calib_table) { + if (ver == SDHI_VER_GEN3_SDMMC && sdhi_has_quirk(priv, hs400_calib_table)) { host->fixup_request = renesas_sdhi_fixup_request; priv->adjust_hs400_calib_table = *( res->start == SDHI_GEN3_MMC0_ADDR ? @@ -1076,7 +1076,7 @@ int renesas_sdhi_probe(struct platform_device *pdev, host->mmc->caps2 & (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS400_1_8V))) { const struct renesas_sdhi_scc *taps = of_data->taps; - bool use_4tap = quirks && quirks->hs400_4taps; + bool use_4tap = sdhi_has_quirk(priv, hs400_4taps); bool hit = false; for (i = 0; i < of_data->taps_num; i++) { diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index f6d1e04a627f..29f562115c66 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -285,7 +285,7 @@ renesas_sdhi_internal_dmac_enable_dma(struct tmio_mmc_host *host, bool enable) { struct renesas_sdhi *priv = host_to_priv(host); u32 dma_irqs = INFO1_DTRANEND0 | - (priv->quirks && priv->quirks->old_info1_layout ? + (sdhi_has_quirk(priv, old_info1_layout) ? INFO1_DTRANEND1_OLD : INFO1_DTRANEND1); if (!host->chan_tx || !host->chan_rx) @@ -318,7 +318,7 @@ static bool renesas_sdhi_internal_dmac_dma_irq(struct tmio_mmc_host *host) struct renesas_sdhi_dma *dma_priv = &priv->dma_priv; u32 dma_irqs = INFO1_DTRANEND0 | - (priv->quirks && priv->quirks->old_info1_layout ? + (sdhi_has_quirk(priv, old_info1_layout) ? INFO1_DTRANEND1_OLD : INFO1_DTRANEND1); u32 status = readl(host->ctl + DM_CM_INFO1); @@ -396,7 +396,7 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host, struct scatterlist *sg = host->sg_ptr; u32 dtran_mode = DTRAN_MODE_BUS_WIDTH; - if (!(priv->quirks && priv->quirks->fixed_addr_mode)) + if (!sdhi_has_quirk(priv, fixed_addr_mode)) dtran_mode |= DTRAN_MODE_ADDR_MODE; if (!renesas_sdhi_internal_dmac_map(host, data, COOKIE_MAPPED)) @@ -404,7 +404,7 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host, if (data->flags & MMC_DATA_READ) { dtran_mode |= DTRAN_MODE_CH_NUM_CH1; - if (priv->quirks && priv->quirks->dma_one_rx_only && + if (sdhi_has_quirk(priv, dma_one_rx_only) && test_and_set_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags)) goto force_pio_with_unmap; } else { -- cgit v1.2.3 From afc9b96b505ca04f3d8ce7bd2a2ca16b39855198 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 20 Nov 2022 12:34:57 +0100 Subject: mmc: renesas_sdhi: use new convenience macro from MMC core Makes the code more readable. Signed-off-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Reviewed-by: Yoshihiro Shimoda Tested-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20221120113457.42010-5-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index ad8f79fe01b2..345934e4f59e 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -1073,8 +1073,7 @@ int renesas_sdhi_probe(struct platform_device *pdev, /* Enable tuning iff we have an SCC and a supported mode */ if (priv->scc_ctl && (host->mmc->caps & MMC_CAP_UHS_SDR104 || - host->mmc->caps2 & (MMC_CAP2_HS200_1_8V_SDR | - MMC_CAP2_HS400_1_8V))) { + host->mmc->caps2 & MMC_CAP2_HSX00_1_8V)) { const struct renesas_sdhi_scc *taps = of_data->taps; bool use_4tap = sdhi_has_quirk(priv, hs400_4taps); bool hit = false; -- cgit v1.2.3 From 4e268fed8b1861616af28f9cfb4eed8ca5d7af6c Mon Sep 17 00:00:00 2001 From: Tony Huang Date: Mon, 21 Nov 2022 18:06:49 +0800 Subject: mmc: Add mmc driver for Sunplus SP7021 This is a patch for mmc driver for Sunplus SP7021 SOC. Supports eMMC 4.41 DDR 104MB/s speed mode. Acked-by: Arnd Bergmann Signed-off-by: Tony Huang Link: https://lore.kernel.org/r/c92d67596f3cc10d41585b9ab82be7da2cc4c9d8.1669023361.git.tonyhuang.sunplus@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/Kconfig | 9 + drivers/mmc/host/Makefile | 1 + drivers/mmc/host/sunplus-mmc.c | 1000 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1010 insertions(+) create mode 100644 drivers/mmc/host/sunplus-mmc.c (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 2df2000d16dc..5e19a961c34d 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -14,6 +14,15 @@ config MMC_DEBUG added host drivers please don't invent their private macro for debugging. +config MMC_SUNPLUS + tristate "Sunplus SP7021 MMC Controller" + depends on ARCH_SUNPLUS || COMPILE_TEST + help + If you say yes here, you will get support for eMMC host interface + on Sunplus SoCs. + + If unsure, say N + config MMC_ARMMMCI tristate "ARM AMBA Multimedia Card Interface support" depends on ARM_AMBA diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 4e4ceb32c4b4..ba0c6d0cd85d 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -97,6 +97,7 @@ obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o obj-$(CONFIG_MMC_SDHCI_BRCMSTB) += sdhci-brcmstb.o obj-$(CONFIG_MMC_SDHCI_OMAP) += sdhci-omap.o obj-$(CONFIG_MMC_SDHCI_SPRD) += sdhci-sprd.o +obj-$(CONFIG_MMC_SUNPLUS) += sunplus-mmc.o obj-$(CONFIG_MMC_CQHCI) += cqhci.o cqhci-y += cqhci-core.o cqhci-$(CONFIG_MMC_CRYPTO) += cqhci-crypto.o diff --git a/drivers/mmc/host/sunplus-mmc.c b/drivers/mmc/host/sunplus-mmc.c new file mode 100644 index 000000000000..5c36daf09bfb --- /dev/null +++ b/drivers/mmc/host/sunplus-mmc.c @@ -0,0 +1,1000 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Sunplus Inc. + * Author: Tony Huang + * Author: Li-hao Kuo + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SPMMC_MIN_CLK 400000 +#define SPMMC_MAX_CLK 52000000 +#define SPMMC_MAX_BLK_COUNT 65536 +#define SPMMC_MAX_TUNABLE_DLY 7 +#define SPMMC_TIMEOUT_US 500000 +#define SPMMC_POLL_DELAY_US 10 + +#define SPMMC_CARD_MEDIATYPE_SRCDST_REG 0x0000 +#define SPMMC_MEDIA_TYPE GENMASK(2, 0) +#define SPMMC_DMA_SOURCE GENMASK(6, 4) +#define SPMMC_DMA_DESTINATION GENMASK(10, 8) +#define SPMMC_MEDIA_NONE 0 +#define SPMMC_MEDIA_SD 6 +#define SPMMC_MEDIA_MS 7 + +#define SPMMC_SDRAM_SECTOR_0_SIZE_REG 0x0008 +#define SPMMC_DMA_BASE_ADDR_REG 0x000C +#define SPMMC_HW_DMA_CTRL_REG 0x0010 +#define SPMMC_HW_DMA_RST BIT(9) +#define SPMMC_DMAIDLE BIT(10) + +#define SPMMC_MAX_DMA_MEMORY_SECTORS 8 + +#define SPMMC_SDRAM_SECTOR_1_ADDR_REG 0x0018 +#define SPMMC_SDRAM_SECTOR_1_LENG_REG 0x001C +#define SPMMC_SDRAM_SECTOR_2_ADDR_REG 0x0020 +#define SPMMC_SDRAM_SECTOR_2_LENG_REG 0x0024 +#define SPMMC_SDRAM_SECTOR_3_ADDR_REG 0x0028 +#define SPMMC_SDRAM_SECTOR_3_LENG_REG 0x002C +#define SPMMC_SDRAM_SECTOR_4_ADDR_REG 0x0030 +#define SPMMC_SDRAM_SECTOR_4_LENG_REG 0x0034 +#define SPMMC_SDRAM_SECTOR_5_ADDR_REG 0x0038 +#define SPMMC_SDRAM_SECTOR_5_LENG_REG 0x003C +#define SPMMC_SDRAM_SECTOR_6_ADDR_REG 0x0040 +#define SPMMC_SDRAM_SECTOR_6_LENG_REG 0x0044 +#define SPMMC_SDRAM_SECTOR_7_ADDR_REG 0x0048 +#define SPMMC_SDRAM_SECTOR_7_LENG_REG 0x004C + +#define SPMMC_SD_INT_REG 0x0088 +#define SPMMC_SDINT_SDCMPEN BIT(0) +#define SPMMC_SDINT_SDCMP BIT(1) +#define SPMMC_SDINT_SDCMPCLR BIT(2) +#define SPMMC_SDINT_SDIOEN BIT(3) +#define SPMMC_SDINT_SDIO BIT(4) +#define SPMMC_SDINT_SDIOCLR BIT(5) + +#define SPMMC_SD_PAGE_NUM_REG 0x008C + +#define SPMMC_SD_CONFIG0_REG 0x0090 +#define SPMMC_SD_PIO_MODE BIT(0) +#define SPMMC_SD_DDR_MODE BIT(1) +#define SPMMC_SD_LEN_MODE BIT(2) +#define SPMMC_SD_TRANS_MODE GENMASK(5, 4) +#define SPMMC_SD_AUTO_RESPONSE BIT(6) +#define SPMMC_SD_CMD_DUMMY BIT(7) +#define SPMMC_SD_RSP_CHK_EN BIT(8) +#define SPMMC_SDIO_MODE BIT(9) +#define SPMMC_SD_MMC_MODE BIT(10) +#define SPMMC_SD_DATA_WD BIT(11) +#define SPMMC_RX4_EN BIT(14) +#define SPMMC_SD_RSP_TYPE BIT(15) +#define SPMMC_MMC8_EN BIT(18) +#define SPMMC_CLOCK_DIVISION GENMASK(31, 20) + +#define SPMMC_SDIO_CTRL_REG 0x0094 +#define SPMMC_INT_MULTI_TRIG BIT(6) + +#define SPMMC_SD_RST_REG 0x0098 +#define SPMMC_SD_CTRL_REG 0x009C +#define SPMMC_NEW_COMMAND_TRIGGER BIT(0) +#define SPMMC_DUMMY_CLOCK_TRIGGER BIT(1) + +#define SPMMC_SD_STATUS_REG 0x00A0 +#define SPMMC_SDSTATUS_DUMMY_READY BIT(0) +#define SPMMC_SDSTATUS_RSP_BUF_FULL BIT(1) +#define SPMMC_SDSTATUS_TX_DATA_BUF_EMPTY BIT(2) +#define SPMMC_SDSTATUS_RX_DATA_BUF_FULL BIT(3) +#define SPMMC_SDSTATUS_CMD_PIN_STATUS BIT(4) +#define SPMMC_SDSTATUS_DAT0_PIN_STATUS BIT(5) +#define SPMMC_SDSTATUS_RSP_TIMEOUT BIT(6) +#define SPMMC_SDSTATUS_CARD_CRC_CHECK_TIMEOUT BIT(7) +#define SPMMC_SDSTATUS_STB_TIMEOUT BIT(8) +#define SPMMC_SDSTATUS_RSP_CRC7_ERROR BIT(9) +#define SPMMC_SDSTATUS_CRC_TOKEN_CHECK_ERROR BIT(10) +#define SPMMC_SDSTATUS_RDATA_CRC16_ERROR BIT(11) +#define SPMMC_SDSTATUS_SUSPEND_STATE_READY BIT(12) +#define SPMMC_SDSTATUS_BUSY_CYCLE BIT(13) +#define SPMMC_SDSTATUS_DAT1_PIN_STATUS BIT(14) +#define SPMMC_SDSTATUS_SD_SENSE_STATUS BIT(15) +#define SPMMC_SDSTATUS_BOOT_ACK_TIMEOUT BIT(16) +#define SPMMC_SDSTATUS_BOOT_DATA_TIMEOUT BIT(17) +#define SPMMC_SDSTATUS_BOOT_ACK_ERROR BIT(18) + +#define SPMMC_SD_STATE_REG 0x00A4 +#define SPMMC_CRCTOKEN_CHECK_RESULT GENMASK(6, 4) +#define SPMMC_SDSTATE_ERROR BIT(13) +#define SPMMC_SDSTATE_FINISH BIT(14) + +#define SPMMC_SD_HW_STATE_REG 0x00A8 +#define SPMMC_SD_BLOCKSIZE_REG 0x00AC + +#define SPMMC_SD_CONFIG1_REG 0x00B0 +#define SPMMC_TX_DUMMY_NUM GENMASK(8, 0) +#define SPMMC_SD_HIGH_SPEED_EN BIT(31) + +#define SPMMC_SD_TIMING_CONFIG0_REG 0x00B4 +#define SPMMC_SD_CLOCK_DELAY GENMASK(2, 0) +#define SPMMC_SD_WRITE_DATA_DELAY GENMASK(6, 4) +#define SPMMC_SD_WRITE_COMMAND_DELAY GENMASK(10, 8) +#define SPMMC_SD_READ_RESPONSE_DELAY GENMASK(14, 12) +#define SPMMC_SD_READ_DATA_DELAY GENMASK(18, 16) +#define SPMMC_SD_READ_CRC_DELAY GENMASK(22, 20) + +#define SPMMC_SD_PIODATATX_REG 0x00BC +#define SPMMC_SD_PIODATARX_REG 0x00C0 +#define SPMMC_SD_CMDBUF0_3_REG 0x00C4 +#define SPMMC_SD_CMDBUF4_REG 0x00C8 +#define SPMMC_SD_RSPBUF0_3_REG 0x00CC +#define SPMMC_SD_RSPBUF4_5_REG 0x00D0 + +#define SPMMC_MAX_RETRIES (8 * 8) + +struct spmmc_tuning_info { + int enable_tuning; + int need_tuning; + int retried; /* how many times has been retried */ + u32 rd_crc_dly:3; + u32 rd_dat_dly:3; + u32 rd_rsp_dly:3; + u32 wr_cmd_dly:3; + u32 wr_dat_dly:3; + u32 clk_dly:3; +}; + +#define SPMMC_DMA_MODE 0 +#define SPMMC_PIO_MODE 1 + +struct spmmc_host { + void __iomem *base; + struct clk *clk; + struct reset_control *rstc; + struct mmc_host *mmc; + struct mmc_request *mrq; /* current mrq */ + int irq; + int dmapio_mode; + struct spmmc_tuning_info tuning_info; + int dma_int_threshold; + int dma_use_int; +}; + +static inline int spmmc_wait_finish(struct spmmc_host *host) +{ + u32 state; + + return readl_poll_timeout(host->base + SPMMC_SD_STATE_REG, state, + (state & SPMMC_SDSTATE_FINISH), + SPMMC_POLL_DELAY_US, SPMMC_TIMEOUT_US); +} + +static inline int spmmc_wait_sdstatus(struct spmmc_host *host, unsigned int status_bit) +{ + u32 status; + + return readl_poll_timeout(host->base + SPMMC_SD_STATUS_REG, status, + (status & status_bit), + SPMMC_POLL_DELAY_US, SPMMC_TIMEOUT_US); +} + +#define spmmc_wait_rspbuf_full(host) spmmc_wait_sdstatus(host, SPMMC_SDSTATUS_RSP_BUF_FULL) +#define spmmc_wait_rxbuf_full(host) spmmc_wait_sdstatus(host, SPMMC_SDSTATUS_RX_DATA_BUF_FULL) +#define spmmc_wait_txbuf_empty(host) spmmc_wait_sdstatus(host, SPMMC_SDSTATUS_TX_DATA_BUF_EMPTY) + +static void spmmc_get_rsp(struct spmmc_host *host, struct mmc_command *cmd) +{ + u32 value0_3, value4_5; + + if (!(cmd->flags & MMC_RSP_PRESENT)) + return; + if (cmd->flags & MMC_RSP_136) { + if (spmmc_wait_rspbuf_full(host)) + return; + value0_3 = readl(host->base + SPMMC_SD_RSPBUF0_3_REG); + value4_5 = readl(host->base + SPMMC_SD_RSPBUF4_5_REG) & 0xffff; + cmd->resp[0] = (value0_3 << 8) | (value4_5 >> 8); + cmd->resp[1] = value4_5 << 24; + value0_3 = readl(host->base + SPMMC_SD_RSPBUF0_3_REG); + value4_5 = readl(host->base + SPMMC_SD_RSPBUF4_5_REG) & 0xffff; + cmd->resp[1] |= value0_3 >> 8; + cmd->resp[2] = value0_3 << 24; + cmd->resp[2] |= value4_5 << 8; + value0_3 = readl(host->base + SPMMC_SD_RSPBUF0_3_REG); + value4_5 = readl(host->base + SPMMC_SD_RSPBUF4_5_REG) & 0xffff; + cmd->resp[2] |= value0_3 >> 24; + cmd->resp[3] = value0_3 << 8; + cmd->resp[3] |= value4_5 >> 8; + } else { + if (spmmc_wait_rspbuf_full(host)) + return; + value0_3 = readl(host->base + SPMMC_SD_RSPBUF0_3_REG); + value4_5 = readl(host->base + SPMMC_SD_RSPBUF4_5_REG) & 0xffff; + cmd->resp[0] = (value0_3 << 8) | (value4_5 >> 8); + cmd->resp[1] = value4_5 << 24; + } +} + +static void spmmc_set_bus_clk(struct spmmc_host *host, int clk) +{ + unsigned int clkdiv; + int f_min = host->mmc->f_min; + int f_max = host->mmc->f_max; + u32 value = readl(host->base + SPMMC_SD_CONFIG0_REG); + + if (clk < f_min) + clk = f_min; + if (clk > f_max) + clk = f_max; + + clkdiv = (clk_get_rate(host->clk) + clk) / clk - 1; + if (clkdiv > 0xfff) + clkdiv = 0xfff; + value &= ~SPMMC_CLOCK_DIVISION; + value |= FIELD_PREP(SPMMC_CLOCK_DIVISION, clkdiv); + writel(value, host->base + SPMMC_SD_CONFIG0_REG); +} + +static void spmmc_set_bus_timing(struct spmmc_host *host, unsigned int timing) +{ + u32 value = readl(host->base + SPMMC_SD_CONFIG1_REG); + int clkdiv = FIELD_GET(SPMMC_CLOCK_DIVISION, readl(host->base + SPMMC_SD_CONFIG0_REG)); + int delay = clkdiv / 2 < 7 ? clkdiv / 2 : 7; + int hs_en = 1, ddr_enabled = 0; + + switch (timing) { + case MMC_TIMING_LEGACY: + hs_en = 0; + break; + case MMC_TIMING_MMC_HS: + case MMC_TIMING_SD_HS: + case MMC_TIMING_UHS_SDR50: + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_MMC_HS200: + hs_en = 1; + break; + case MMC_TIMING_UHS_DDR50: + ddr_enabled = 1; + break; + case MMC_TIMING_MMC_DDR52: + ddr_enabled = 1; + break; + default: + hs_en = 0; + break; + } + + if (hs_en) { + value |= SPMMC_SD_HIGH_SPEED_EN; + writel(value, host->base + SPMMC_SD_CONFIG1_REG); + value = readl(host->base + SPMMC_SD_TIMING_CONFIG0_REG); + value &= ~SPMMC_SD_WRITE_DATA_DELAY; + value |= FIELD_PREP(SPMMC_SD_WRITE_DATA_DELAY, delay); + value &= ~SPMMC_SD_WRITE_COMMAND_DELAY; + value |= FIELD_PREP(SPMMC_SD_WRITE_COMMAND_DELAY, delay); + writel(value, host->base + SPMMC_SD_TIMING_CONFIG0_REG); + } else { + value &= ~SPMMC_SD_HIGH_SPEED_EN; + writel(value, host->base + SPMMC_SD_CONFIG1_REG); + } + if (ddr_enabled) { + value = readl(host->base + SPMMC_SD_CONFIG0_REG); + value |= SPMMC_SD_DDR_MODE; + writel(value, host->base + SPMMC_SD_CONFIG0_REG); + } else { + value = readl(host->base + SPMMC_SD_CONFIG0_REG); + value &= ~SPMMC_SD_DDR_MODE; + writel(value, host->base + SPMMC_SD_CONFIG0_REG); + } +} + +static void spmmc_set_bus_width(struct spmmc_host *host, int width) +{ + u32 value = readl(host->base + SPMMC_SD_CONFIG0_REG); + + switch (width) { + case MMC_BUS_WIDTH_8: + value &= ~SPMMC_SD_DATA_WD; + value |= SPMMC_MMC8_EN; + break; + case MMC_BUS_WIDTH_4: + value |= SPMMC_SD_DATA_WD; + value &= ~SPMMC_MMC8_EN; + break; + default: + value &= ~SPMMC_SD_DATA_WD; + value &= ~SPMMC_MMC8_EN; + break; + }; + writel(value, host->base + SPMMC_SD_CONFIG0_REG); +} + +/* + * select the working mode of controller: sd/sdio/emmc + */ +static void spmmc_set_sdmmc_mode(struct spmmc_host *host) +{ + u32 value = readl(host->base + SPMMC_SD_CONFIG0_REG); + + value |= SPMMC_SD_MMC_MODE; + value &= ~SPMMC_SDIO_MODE; + writel(value, host->base + SPMMC_SD_CONFIG0_REG); +} + +static void spmmc_sw_reset(struct spmmc_host *host) +{ + u32 value; + + /* + * Must reset dma operation first, or it will + * be stuck on sd_state == 0x1c00 because of + * a controller software reset bug + */ + value = readl(host->base + SPMMC_HW_DMA_CTRL_REG); + value |= SPMMC_DMAIDLE; + writel(value, host->base + SPMMC_HW_DMA_CTRL_REG); + value &= ~SPMMC_DMAIDLE; + writel(value, host->base + SPMMC_HW_DMA_CTRL_REG); + value = readl(host->base + SPMMC_HW_DMA_CTRL_REG); + value |= SPMMC_HW_DMA_RST; + writel(value, host->base + SPMMC_HW_DMA_CTRL_REG); + writel(0x7, host->base + SPMMC_SD_RST_REG); + readl_poll_timeout_atomic(host->base + SPMMC_SD_HW_STATE_REG, value, + !(value & BIT(6)), 1, SPMMC_TIMEOUT_US); +} + +static void spmmc_prepare_cmd(struct spmmc_host *host, struct mmc_command *cmd) +{ + u32 value; + + /* add start bit, according to spec, command format */ + value = ((cmd->opcode | 0x40) << 24) | (cmd->arg >> 8); + writel(value, host->base + SPMMC_SD_CMDBUF0_3_REG); + writeb(cmd->arg & 0xff, host->base + SPMMC_SD_CMDBUF4_REG); + + /* disable interrupt if needed */ + value = readl(host->base + SPMMC_SD_INT_REG); + value |= SPMMC_SDINT_SDCMPCLR; + value &= ~SPMMC_SDINT_SDCMPEN; + writel(value, host->base + SPMMC_SD_INT_REG); + + value = readl(host->base + SPMMC_SD_CONFIG0_REG); + value &= ~SPMMC_SD_TRANS_MODE; + value |= SPMMC_SD_CMD_DUMMY; + if (cmd->flags & MMC_RSP_PRESENT) { + value |= SPMMC_SD_AUTO_RESPONSE; + } else { + value &= ~SPMMC_SD_AUTO_RESPONSE; + writel(value, host->base + SPMMC_SD_CONFIG0_REG); + + return; + } + /* + * Currently, host is not capable of checking R2's CRC7, + * thus, enable crc7 check only for 48 bit response commands + */ + if (cmd->flags & MMC_RSP_CRC && !(cmd->flags & MMC_RSP_136)) + value |= SPMMC_SD_RSP_CHK_EN; + else + value &= ~SPMMC_SD_RSP_CHK_EN; + + if (cmd->flags & MMC_RSP_136) + value |= SPMMC_SD_RSP_TYPE; + else + value &= ~SPMMC_SD_RSP_TYPE; + writel(value, host->base + SPMMC_SD_CONFIG0_REG); +} + +static void spmmc_prepare_data(struct spmmc_host *host, struct mmc_data *data) +{ + u32 value, srcdst; + + writel(data->blocks - 1, host->base + SPMMC_SD_PAGE_NUM_REG); + writel(data->blksz - 1, host->base + SPMMC_SD_BLOCKSIZE_REG); + value = readl(host->base + SPMMC_SD_CONFIG0_REG); + if (data->flags & MMC_DATA_READ) { + value &= ~SPMMC_SD_TRANS_MODE; + value |= FIELD_PREP(SPMMC_SD_TRANS_MODE, 2); + value &= ~SPMMC_SD_AUTO_RESPONSE; + value &= ~SPMMC_SD_CMD_DUMMY; + srcdst = readl(host->base + SPMMC_CARD_MEDIATYPE_SRCDST_REG); + srcdst &= ~SPMMC_DMA_SOURCE; + srcdst |= FIELD_PREP(SPMMC_DMA_SOURCE, 0x2); + srcdst &= ~SPMMC_DMA_DESTINATION; + srcdst |= FIELD_PREP(SPMMC_DMA_DESTINATION, 0x1); + writel(srcdst, host->base + SPMMC_CARD_MEDIATYPE_SRCDST_REG); + } else { + value &= ~SPMMC_SD_TRANS_MODE; + value |= FIELD_PREP(SPMMC_SD_TRANS_MODE, 1); + srcdst = readl(host->base + SPMMC_CARD_MEDIATYPE_SRCDST_REG); + srcdst &= ~SPMMC_DMA_SOURCE; + srcdst |= FIELD_PREP(SPMMC_DMA_SOURCE, 0x1); + srcdst &= ~SPMMC_DMA_DESTINATION; + srcdst |= FIELD_PREP(SPMMC_DMA_DESTINATION, 0x2); + writel(srcdst, host->base + SPMMC_CARD_MEDIATYPE_SRCDST_REG); + } + + value |= SPMMC_SD_LEN_MODE; + if (host->dmapio_mode == SPMMC_DMA_MODE) { + struct scatterlist *sg; + dma_addr_t dma_addr; + unsigned int dma_size; + int i, count = 1; + + count = dma_map_sg(host->mmc->parent, data->sg, data->sg_len, + mmc_get_dma_dir(data)); + if (!count || count > SPMMC_MAX_DMA_MEMORY_SECTORS) { + data->error = -EINVAL; + + return; + } + for_each_sg(data->sg, sg, count, i) { + dma_addr = sg_dma_address(sg); + dma_size = sg_dma_len(sg) / data->blksz - 1; + if (i == 0) { + writel(dma_addr, host->base + SPMMC_DMA_BASE_ADDR_REG); + writel(dma_size, host->base + SPMMC_SDRAM_SECTOR_0_SIZE_REG); + } else if (i == 1) { + writel(dma_addr, host->base + SPMMC_SDRAM_SECTOR_1_ADDR_REG); + writel(dma_size, host->base + SPMMC_SDRAM_SECTOR_1_LENG_REG); + } else if (i == 2) { + writel(dma_addr, host->base + SPMMC_SDRAM_SECTOR_2_ADDR_REG); + writel(dma_size, host->base + SPMMC_SDRAM_SECTOR_2_LENG_REG); + } else if (i == 3) { + writel(dma_addr, host->base + SPMMC_SDRAM_SECTOR_3_ADDR_REG); + writel(dma_size, host->base + SPMMC_SDRAM_SECTOR_3_LENG_REG); + } else if (i == 4) { + writel(dma_addr, host->base + SPMMC_SDRAM_SECTOR_4_ADDR_REG); + writel(dma_size, host->base + SPMMC_SDRAM_SECTOR_4_LENG_REG); + } else if (i == 5) { + writel(dma_addr, host->base + SPMMC_SDRAM_SECTOR_5_ADDR_REG); + writel(dma_size, host->base + SPMMC_SDRAM_SECTOR_5_LENG_REG); + } else if (i == 6) { + writel(dma_addr, host->base + SPMMC_SDRAM_SECTOR_6_ADDR_REG); + writel(dma_size, host->base + SPMMC_SDRAM_SECTOR_6_LENG_REG); + } else if (i == 7) { + writel(dma_addr, host->base + SPMMC_SDRAM_SECTOR_7_ADDR_REG); + writel(dma_size, host->base + SPMMC_SDRAM_SECTOR_7_LENG_REG); + } + } + value &= ~SPMMC_SD_PIO_MODE; + writel(value, host->base + SPMMC_SD_CONFIG0_REG); + /* enable interrupt if needed */ + if (data->blksz * data->blocks > host->dma_int_threshold) { + host->dma_use_int = 1; + value = readl(host->base + SPMMC_SD_INT_REG); + value &= ~SPMMC_SDINT_SDCMPEN; + value |= FIELD_PREP(SPMMC_SDINT_SDCMPEN, 1); /* sdcmpen */ + writel(value, host->base + SPMMC_SD_INT_REG); + } + } else { + value |= SPMMC_SD_PIO_MODE; + value |= SPMMC_RX4_EN; + writel(value, host->base + SPMMC_SD_CONFIG0_REG); + } +} + +static inline void spmmc_trigger_transaction(struct spmmc_host *host) +{ + u32 value = readl(host->base + SPMMC_SD_CTRL_REG); + + value |= SPMMC_NEW_COMMAND_TRIGGER; + writel(value, host->base + SPMMC_SD_CTRL_REG); +} + +static void spmmc_send_stop_cmd(struct spmmc_host *host) +{ + struct mmc_command stop = {}; + u32 value; + + stop.opcode = MMC_STOP_TRANSMISSION; + stop.arg = 0; + stop.flags = MMC_RSP_R1B; + spmmc_prepare_cmd(host, &stop); + value = readl(host->base + SPMMC_SD_INT_REG); + value &= ~SPMMC_SDINT_SDCMPEN; + value |= FIELD_PREP(SPMMC_SDINT_SDCMPEN, 0); + writel(value, host->base + SPMMC_SD_INT_REG); + spmmc_trigger_transaction(host); + readl_poll_timeout(host->base + SPMMC_SD_STATE_REG, value, + (value & SPMMC_SDSTATE_FINISH), 1, SPMMC_TIMEOUT_US); +} + +static int spmmc_check_error(struct spmmc_host *host, struct mmc_request *mrq) +{ + int ret = 0; + struct mmc_command *cmd = mrq->cmd; + struct mmc_data *data = mrq->data; + + u32 value = readl(host->base + SPMMC_SD_STATE_REG); + u32 crc_token = FIELD_GET(SPMMC_CRCTOKEN_CHECK_RESULT, value); + + if (value & SPMMC_SDSTATE_ERROR) { + u32 timing_cfg0 = 0; + + value = readl(host->base + SPMMC_SD_STATUS_REG); + + if (host->tuning_info.enable_tuning) { + timing_cfg0 = readl(host->base + SPMMC_SD_TIMING_CONFIG0_REG); + host->tuning_info.rd_crc_dly = FIELD_GET(SPMMC_SD_READ_CRC_DELAY, + timing_cfg0); + host->tuning_info.rd_dat_dly = FIELD_GET(SPMMC_SD_READ_DATA_DELAY, + timing_cfg0); + host->tuning_info.rd_rsp_dly = FIELD_GET(SPMMC_SD_READ_RESPONSE_DELAY, + timing_cfg0); + host->tuning_info.wr_cmd_dly = FIELD_GET(SPMMC_SD_WRITE_COMMAND_DELAY, + timing_cfg0); + host->tuning_info.wr_dat_dly = FIELD_GET(SPMMC_SD_WRITE_DATA_DELAY, + timing_cfg0); + } + + if (value & SPMMC_SDSTATUS_RSP_TIMEOUT) { + ret = -ETIMEDOUT; + host->tuning_info.wr_cmd_dly++; + } else if (value & SPMMC_SDSTATUS_RSP_CRC7_ERROR) { + ret = -EILSEQ; + host->tuning_info.rd_rsp_dly++; + } else if (data) { + if ((value & SPMMC_SDSTATUS_STB_TIMEOUT)) { + ret = -ETIMEDOUT; + host->tuning_info.rd_dat_dly++; + } else if (value & SPMMC_SDSTATUS_RDATA_CRC16_ERROR) { + ret = -EILSEQ; + host->tuning_info.rd_dat_dly++; + } else if (value & SPMMC_SDSTATUS_CARD_CRC_CHECK_TIMEOUT) { + ret = -ETIMEDOUT; + host->tuning_info.rd_crc_dly++; + } else if (value & SPMMC_SDSTATUS_CRC_TOKEN_CHECK_ERROR) { + ret = -EILSEQ; + if (crc_token == 0x5) + host->tuning_info.wr_dat_dly++; + else + host->tuning_info.rd_crc_dly++; + } + } + cmd->error = ret; + if (data) { + data->error = ret; + data->bytes_xfered = 0; + } + if (!host->tuning_info.need_tuning && host->tuning_info.enable_tuning) + cmd->retries = SPMMC_MAX_RETRIES; + spmmc_sw_reset(host); + + if (host->tuning_info.enable_tuning) { + timing_cfg0 &= ~SPMMC_SD_READ_CRC_DELAY; + timing_cfg0 |= FIELD_PREP(SPMMC_SD_READ_CRC_DELAY, + host->tuning_info.rd_crc_dly); + timing_cfg0 &= ~SPMMC_SD_READ_DATA_DELAY; + timing_cfg0 |= FIELD_PREP(SPMMC_SD_READ_DATA_DELAY, + host->tuning_info.rd_dat_dly); + timing_cfg0 &= ~SPMMC_SD_READ_RESPONSE_DELAY; + timing_cfg0 |= FIELD_PREP(SPMMC_SD_READ_RESPONSE_DELAY, + host->tuning_info.rd_rsp_dly); + timing_cfg0 &= ~SPMMC_SD_WRITE_COMMAND_DELAY; + timing_cfg0 |= FIELD_PREP(SPMMC_SD_WRITE_COMMAND_DELAY, + host->tuning_info.wr_cmd_dly); + timing_cfg0 &= ~SPMMC_SD_WRITE_DATA_DELAY; + timing_cfg0 |= FIELD_PREP(SPMMC_SD_WRITE_DATA_DELAY, + host->tuning_info.wr_dat_dly); + writel(timing_cfg0, host->base + SPMMC_SD_TIMING_CONFIG0_REG); + } + } else if (data) { + data->error = 0; + data->bytes_xfered = data->blocks * data->blksz; + } + host->tuning_info.need_tuning = ret; + + return ret; +} + +/* + * the strategy is: + * 1. if several continuous delays are acceptable, we choose a middle one; + * 2. otherwise, we choose the first one. + */ +static inline int spmmc_find_best_delay(u8 candidate_dly) +{ + int f, w, value; + + if (!candidate_dly) + return 0; + f = ffs(candidate_dly) - 1; + w = hweight8(candidate_dly); + value = ((1 << w) - 1) << f; + if (0xff == (value & ~candidate_dly)) + return (f + w / 2); + else + return (f); +} + +static void spmmc_xfer_data_pio(struct spmmc_host *host, struct mmc_data *data) +{ + u32 *buf; + int data_left = data->blocks * data->blksz; + int consumed, remain; + + struct sg_mapping_iter sg_miter; + unsigned int flags = 0; + + if (data->flags & MMC_DATA_WRITE) + flags |= SG_MITER_FROM_SG; + else + flags |= SG_MITER_TO_SG; + sg_miter_start(&sg_miter, data->sg, data->sg_len, flags); + while (data_left > 0) { + consumed = 0; + if (!sg_miter_next(&sg_miter)) + break; + buf = sg_miter.addr; + remain = sg_miter.length; + do { + if (data->flags & MMC_DATA_WRITE) { + if (spmmc_wait_txbuf_empty(host)) + goto done; + writel(*buf, host->base + SPMMC_SD_PIODATATX_REG); + } else { + if (spmmc_wait_rxbuf_full(host)) + goto done; + *buf = readl(host->base + SPMMC_SD_PIODATARX_REG); + } + buf++; + /* tx/rx 4 bytes one time in pio mode */ + consumed += 4; + remain -= 4; + } while (remain); + sg_miter.consumed = consumed; + data_left -= consumed; + } +done: + sg_miter_stop(&sg_miter); +} + +static void spmmc_controller_init(struct spmmc_host *host) +{ + u32 value; + int ret = reset_control_assert(host->rstc); + + if (!ret) { + usleep_range(1000, 1250); + ret = reset_control_deassert(host->rstc); + } + + value = readl(host->base + SPMMC_CARD_MEDIATYPE_SRCDST_REG); + value &= ~SPMMC_MEDIA_TYPE; + value |= FIELD_PREP(SPMMC_MEDIA_TYPE, SPMMC_MEDIA_SD); + writel(value, host->base + SPMMC_CARD_MEDIATYPE_SRCDST_REG); +} + +/* + * 1. unmap scatterlist if needed; + * 2. get response & check error conditions; + * 3. notify mmc layer the request is done + */ +static void spmmc_finish_request(struct spmmc_host *host, struct mmc_request *mrq) +{ + struct mmc_command *cmd; + struct mmc_data *data; + + if (!mrq) + return; + + cmd = mrq->cmd; + data = mrq->data; + + if (data && SPMMC_DMA_MODE == host->dmapio_mode) { + dma_unmap_sg(host->mmc->parent, data->sg, data->sg_len, mmc_get_dma_dir(data)); + host->dma_use_int = 0; + } + + spmmc_get_rsp(host, cmd); + spmmc_check_error(host, mrq); + if (mrq->stop) + spmmc_send_stop_cmd(host); + + host->mrq = NULL; + mmc_request_done(host->mmc, mrq); +} + +/* Interrupt Service Routine */ +static irqreturn_t spmmc_irq(int irq, void *dev_id) +{ + struct spmmc_host *host = dev_id; + u32 value = readl(host->base + SPMMC_SD_INT_REG); + + if ((value & SPMMC_SDINT_SDCMP) && (value & SPMMC_SDINT_SDCMPEN)) { + value &= ~SPMMC_SDINT_SDCMPEN; + value |= SPMMC_SDINT_SDCMPCLR; + writel(value, host->base + SPMMC_SD_INT_REG); + return IRQ_WAKE_THREAD; + } + return IRQ_HANDLED; +} + +static void spmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct spmmc_host *host = mmc_priv(mmc); + struct mmc_data *data; + struct mmc_command *cmd; + + host->mrq = mrq; + data = mrq->data; + cmd = mrq->cmd; + + spmmc_prepare_cmd(host, cmd); + /* we need manually read response R2. */ + if (cmd->flags & MMC_RSP_136) { + spmmc_trigger_transaction(host); + spmmc_get_rsp(host, cmd); + spmmc_wait_finish(host); + spmmc_check_error(host, mrq); + host->mrq = NULL; + mmc_request_done(host->mmc, mrq); + } else { + if (data) + spmmc_prepare_data(host, data); + + if (host->dmapio_mode == SPMMC_PIO_MODE && data) { + u32 value; + /* pio data transfer do not use interrupt */ + value = readl(host->base + SPMMC_SD_INT_REG); + value &= ~SPMMC_SDINT_SDCMPEN; + writel(value, host->base + SPMMC_SD_INT_REG); + spmmc_trigger_transaction(host); + spmmc_xfer_data_pio(host, data); + spmmc_wait_finish(host); + spmmc_finish_request(host, mrq); + } else { + if (host->dma_use_int) { + spmmc_trigger_transaction(host); + } else { + spmmc_trigger_transaction(host); + spmmc_wait_finish(host); + spmmc_finish_request(host, mrq); + } + } + } +} + +static void spmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct spmmc_host *host = (struct spmmc_host *)mmc_priv(mmc); + + spmmc_set_bus_clk(host, ios->clock); + spmmc_set_bus_timing(host, ios->timing); + spmmc_set_bus_width(host, ios->bus_width); + /* ensure mode is correct, because we might have hw reset the controller */ + spmmc_set_sdmmc_mode(host); +} + +/* + * Return values for the get_cd callback should be: + * 0 for a absent card + * 1 for a present card + * -ENOSYS when not supported (equal to NULL callback) + * or a negative errno value when something bad happened + */ +static int spmmc_get_cd(struct mmc_host *mmc) +{ + int ret = 0; + + if (mmc_can_gpio_cd(mmc)) + ret = mmc_gpio_get_cd(mmc); + + if (ret < 0) + ret = 0; + + return ret; +} + +static int spmmc_execute_tuning(struct mmc_host *mmc, u32 opcode) +{ + struct spmmc_host *host = mmc_priv(mmc); + u8 smpl_dly = 0, candidate_dly = 0; + u32 value; + + host->tuning_info.enable_tuning = 0; + do { + value = readl(host->base + SPMMC_SD_TIMING_CONFIG0_REG); + value &= ~SPMMC_SD_READ_RESPONSE_DELAY; + value |= FIELD_PREP(SPMMC_SD_READ_RESPONSE_DELAY, smpl_dly); + value &= ~SPMMC_SD_READ_DATA_DELAY; + value |= FIELD_PREP(SPMMC_SD_READ_DATA_DELAY, smpl_dly); + value &= ~SPMMC_SD_READ_CRC_DELAY; + value |= FIELD_PREP(SPMMC_SD_READ_CRC_DELAY, smpl_dly); + writel(value, host->base + SPMMC_SD_TIMING_CONFIG0_REG); + + if (!mmc_send_tuning(mmc, opcode, NULL)) { + candidate_dly |= (1 << smpl_dly); + break; + } + } while (smpl_dly++ <= SPMMC_MAX_TUNABLE_DLY); + host->tuning_info.enable_tuning = 1; + + if (candidate_dly) { + smpl_dly = spmmc_find_best_delay(candidate_dly); + value = readl(host->base + SPMMC_SD_TIMING_CONFIG0_REG); + value &= ~SPMMC_SD_READ_RESPONSE_DELAY; + value |= FIELD_PREP(SPMMC_SD_READ_RESPONSE_DELAY, smpl_dly); + value &= ~SPMMC_SD_READ_DATA_DELAY; + value |= FIELD_PREP(SPMMC_SD_READ_DATA_DELAY, smpl_dly); + value &= ~SPMMC_SD_READ_CRC_DELAY; + value |= FIELD_PREP(SPMMC_SD_READ_CRC_DELAY, smpl_dly); + writel(value, host->base + SPMMC_SD_TIMING_CONFIG0_REG); + return 0; + } + + return -EIO; +} + +static const struct mmc_host_ops spmmc_ops = { + .request = spmmc_request, + .set_ios = spmmc_set_ios, + .get_cd = spmmc_get_cd, + .execute_tuning = spmmc_execute_tuning, +}; + +static irqreturn_t spmmc_func_finish_req(int irq, void *dev_id) +{ + struct spmmc_host *host = dev_id; + + spmmc_finish_request(host, host->mrq); + + return IRQ_HANDLED; +} + +static int spmmc_drv_probe(struct platform_device *pdev) +{ + struct mmc_host *mmc; + struct resource *res; + struct spmmc_host *host; + int ret = 0; + + mmc = mmc_alloc_host(sizeof(*host), &pdev->dev); + if (!mmc) { + ret = -ENOMEM; + goto probe_free_host; + } + + host = mmc_priv(mmc); + host->mmc = mmc; + host->dmapio_mode = SPMMC_DMA_MODE; + host->dma_int_threshold = 1024; + + host->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(host->base)) + return PTR_ERR(host->base); + + host->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(host->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(host->clk), "clk get fail\n"); + + host->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); + if (IS_ERR(host->rstc)) + return dev_err_probe(&pdev->dev, PTR_ERR(host->rstc), "rst get fail\n"); + + host->irq = platform_get_irq(pdev, 0); + if (host->irq <= 0) + return host->irq; + + ret = devm_request_threaded_irq(&pdev->dev, host->irq, + spmmc_irq, spmmc_func_finish_req, IRQF_SHARED, + NULL, host); + if (ret) + return ret; + + ret = clk_prepare_enable(host->clk); + if (ret) + return dev_err_probe(&pdev->dev, ret, "failed to enable clk\n"); + + ret = mmc_of_parse(mmc); + if (ret) + goto probe_free_host; + + mmc->ops = &spmmc_ops; + mmc->f_min = SPMMC_MIN_CLK; + if (mmc->f_max > SPMMC_MAX_CLK) + mmc->f_max = SPMMC_MAX_CLK; + + ret = mmc_regulator_get_supply(mmc); + if (ret) + goto probe_free_host; + + if (!mmc->ocr_avail) + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + mmc->max_seg_size = SPMMC_MAX_BLK_COUNT * 512; + mmc->max_segs = SPMMC_MAX_DMA_MEMORY_SECTORS; + mmc->max_req_size = SPMMC_MAX_BLK_COUNT * 512; + mmc->max_blk_size = 512; + mmc->max_blk_count = SPMMC_MAX_BLK_COUNT; + + dev_set_drvdata(&pdev->dev, host); + spmmc_controller_init(host); + spmmc_set_sdmmc_mode(host); + host->tuning_info.enable_tuning = 1; + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + mmc_add_host(mmc); + + return ret; + +probe_free_host: + if (mmc) + mmc_free_host(mmc); + + return ret; +} + +static int spmmc_drv_remove(struct platform_device *dev) +{ + struct spmmc_host *host = platform_get_drvdata(dev); + + mmc_remove_host(host->mmc); + pm_runtime_get_sync(&dev->dev); + clk_disable_unprepare(host->clk); + pm_runtime_put_noidle(&dev->dev); + pm_runtime_disable(&dev->dev); + platform_set_drvdata(dev, NULL); + mmc_free_host(host->mmc); + + return 0; +} + +static int spmmc_pm_runtime_suspend(struct device *dev) +{ + struct spmmc_host *host; + + host = dev_get_drvdata(dev); + clk_disable_unprepare(host->clk); + + return 0; +} + +static int spmmc_pm_runtime_resume(struct device *dev) +{ + struct spmmc_host *host; + + host = dev_get_drvdata(dev); + + return clk_prepare_enable(host->clk); +} + +static DEFINE_RUNTIME_DEV_PM_OPS(spmmc_pm_ops, spmmc_pm_runtime_suspend, + spmmc_pm_runtime_resume, NULL); + +static const struct of_device_id spmmc_of_table[] = { + { + .compatible = "sunplus,sp7021-mmc", + }, + {/* sentinel */} +}; +MODULE_DEVICE_TABLE(of, spmmc_of_table); + +static struct platform_driver spmmc_driver = { + .probe = spmmc_drv_probe, + .remove = spmmc_drv_remove, + .driver = { + .name = "spmmc", + .pm = pm_ptr(&spmmc_pm_ops), + .of_match_table = spmmc_of_table, + }, +}; +module_platform_driver(spmmc_driver); + +MODULE_AUTHOR("Tony Huang "); +MODULE_AUTHOR("Li-hao Kuo "); +MODULE_DESCRIPTION("Sunplus MMC controller driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From ffbace4378dc1aedb02248bbbe5d231754e4df3a Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 22 Nov 2022 09:05:54 +0100 Subject: mmc: renesas_sdhi: use plain numbers for end_flags Linux *_bit accessors take plain bit numbers, no need for BIT(). Fixes: c330601c9c93 ("mmc: renesas_sdhi: take DMA end interrupts into account") Reported-by: kernel test robot Reported-by: Dan Carpenter Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20221122080554.4468-1-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h index ea2a85174a09..68da3da9e2e5 100644 --- a/drivers/mmc/host/renesas_sdhi.h +++ b/drivers/mmc/host/renesas_sdhi.h @@ -57,8 +57,8 @@ struct renesas_sdhi_of_data_with_quirks { }; /* We want both end_flags to be set before we mark DMA as finished */ -#define SDHI_DMA_END_FLAG_DMA BIT(0) -#define SDHI_DMA_END_FLAG_ACCESS BIT(1) +#define SDHI_DMA_END_FLAG_DMA 0 +#define SDHI_DMA_END_FLAG_ACCESS 1 struct renesas_sdhi_dma { unsigned long end_flags; -- cgit v1.2.3 From e81bdae440fa7cc7dcbfb4f0fcfafb1f4350bc31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=B6hle?= Date: Sun, 27 Nov 2022 17:46:31 +0000 Subject: mmc: core: Remove non-data R1B ioctl workaround The workaround of pretending R1B non-data transfers are data transfers in order for the busy timeout to be respected by the host controller driver is removed. It wasn't useful in a long time. Initially the workaround ensured that R1B commands did not time out by setting the data timeout to be the command timeout in commit cb87ea28ed9e ("mmc: core: Add mmc CMD+ACMD passthrough ioctl"). This was moved inside an if-clause with idata->buf_bytes being set in commit 4d6144de8ba2 ("mmc: core: check for zero length ioctl data"). Since the workaround is now inside the idata->buf_bytes clause and intended to fix R1B non-data transfers, that do not have buf_bytes set, we can remove the workaround altogether. This was dead code, since data transfers doesn't use R1B commands. Signed-off-by: Christian Loehle Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/57d4aceb25254e448bd3e575bd99b0c2@hyperstone.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index db6d8a099910..20da7ed43e6d 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -514,19 +514,6 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, if (idata->ic.data_timeout_ns) data.timeout_ns = idata->ic.data_timeout_ns; - if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) { - /* - * Pretend this is a data transfer and rely on the - * host driver to compute timeout. When all host - * drivers support cmd.cmd_timeout for R1B, this - * can be changed to: - * - * mrq.data = NULL; - * cmd.cmd_timeout = idata->ic.cmd_timeout_ms; - */ - data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000; - } - mrq.data = &data; } -- cgit v1.2.3 From 1e8cb505f3d4a3e9c31238a45509a17e688525a0 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Wed, 23 Nov 2022 10:12:21 +0800 Subject: mmc: Remove unneeded semicolon ./drivers/mmc/host/sunplus-mmc.c:321:2-3: Unneeded semicolon Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=3238 Reported-by: Abaci Robot Signed-off-by: Yang Li Link: https://lore.kernel.org/r/20221123021221.9646-1-yang.lee@linux.alibaba.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sunplus-mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sunplus-mmc.c b/drivers/mmc/host/sunplus-mmc.c index 5c36daf09bfb..db5e0dcdfa7f 100644 --- a/drivers/mmc/host/sunplus-mmc.c +++ b/drivers/mmc/host/sunplus-mmc.c @@ -318,7 +318,7 @@ static void spmmc_set_bus_width(struct spmmc_host *host, int width) value &= ~SPMMC_SD_DATA_WD; value &= ~SPMMC_MMC8_EN; break; - }; + } writel(value, host->base + SPMMC_SD_CONFIG0_REG); } -- cgit v1.2.3 From b98e7e8daf0ebab9dcc36812378a71e1be0b5089 Mon Sep 17 00:00:00 2001 From: ChanWoo Lee Date: Thu, 24 Nov 2022 17:00:31 +0900 Subject: mmc: Avoid open coding by using mmc_op_tuning() Replace code with the already defined function. No functional changes. Signed-off-by: ChanWoo Lee Reviewed-by: Adrian Hunter Link: https://lore.kernel.org/r/20221124080031.14690-1-cw9316.lee@samsung.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 3 +-- drivers/mmc/host/dw_mmc.c | 3 +-- drivers/mmc/host/mtk-sd.c | 8 ++------ drivers/mmc/host/sdhci-msm.c | 3 +-- drivers/mmc/host/sdhci-pci-o2micro.c | 3 +-- drivers/mmc/host/sdhci-tegra.c | 8 ++------ drivers/mmc/host/sdhci.c | 9 ++------- 7 files changed, 10 insertions(+), 27 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index d87b8a28f56a..c04f5016807b 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -142,8 +142,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) int err = cmd->error; /* Flag re-tuning needed on CRC errors */ - if (cmd->opcode != MMC_SEND_TUNING_BLOCK && - cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200 && + if (!mmc_op_tuning(cmd->opcode) && !host->retune_crc_disable && (err == -EILSEQ || (mrq->sbc && mrq->sbc->error == -EILSEQ) || (mrq->data && mrq->data->error == -EILSEQ) || diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index d35607128322..a0e2fdbee690 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -334,8 +334,7 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd) cmdr == MMC_READ_MULTIPLE_BLOCK || cmdr == MMC_WRITE_BLOCK || cmdr == MMC_WRITE_MULTIPLE_BLOCK || - cmdr == MMC_SEND_TUNING_BLOCK || - cmdr == MMC_SEND_TUNING_BLOCK_HS200 || + mmc_op_tuning(cmdr) || cmdr == MMC_GEN_CMD) { stop->opcode = MMC_STOP_TRANSMISSION; stop->arg = 0; diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index abadfc319053..edade0e54a0c 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -1224,9 +1224,7 @@ static bool msdc_cmd_done(struct msdc_host *host, int events, if (!sbc_error && !(events & MSDC_INT_CMDRDY)) { if (events & MSDC_INT_CMDTMO || - (cmd->opcode != MMC_SEND_TUNING_BLOCK && - cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200 && - !host->hs400_tuning)) + (!mmc_op_tuning(cmd->opcode) && !host->hs400_tuning)) /* * should not clear fifo/interrupt as the tune data * may have already come when cmd19/cmd21 gets response @@ -1320,9 +1318,7 @@ static void msdc_cmd_next(struct msdc_host *host, { if ((cmd->error && !(cmd->error == -EILSEQ && - (cmd->opcode == MMC_SEND_TUNING_BLOCK || - cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200 || - host->hs400_tuning))) || + (mmc_op_tuning(cmd->opcode) || host->hs400_tuning))) || (mrq->sbc && mrq->sbc->error)) msdc_request_done(host, mrq); else if (cmd == mrq->sbc) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 03f76384ab3f..4ac8651d0b29 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -2219,8 +2219,7 @@ static int __sdhci_msm_check_write(struct sdhci_host *host, u16 val, int reg) if (!msm_host->use_cdr) break; if ((msm_host->transfer_mode & SDHCI_TRNS_READ) && - SDHCI_GET_CMD(val) != MMC_SEND_TUNING_BLOCK_HS200 && - SDHCI_GET_CMD(val) != MMC_SEND_TUNING_BLOCK) + !mmc_op_tuning(SDHCI_GET_CMD(val))) sdhci_msm_set_cdr(host, true); else sdhci_msm_set_cdr(host, false); diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c index bca1d095b759..98cadff47b2b 100644 --- a/drivers/mmc/host/sdhci-pci-o2micro.c +++ b/drivers/mmc/host/sdhci-pci-o2micro.c @@ -326,8 +326,7 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode) (host->timing != MMC_TIMING_UHS_SDR50)) return sdhci_execute_tuning(mmc, opcode); - if (WARN_ON((opcode != MMC_SEND_TUNING_BLOCK_HS200) && - (opcode != MMC_SEND_TUNING_BLOCK))) + if (WARN_ON(!mmc_op_tuning(opcode))) return -EINVAL; /* Force power mode enter L0 */ diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index c71000a07656..9fc8a61eca54 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -268,13 +268,9 @@ static void tegra210_sdhci_writew(struct sdhci_host *host, u16 val, int reg) { bool is_tuning_cmd = 0; bool clk_enabled; - u8 cmd; - if (reg == SDHCI_COMMAND) { - cmd = SDHCI_GET_CMD(val); - is_tuning_cmd = cmd == MMC_SEND_TUNING_BLOCK || - cmd == MMC_SEND_TUNING_BLOCK_HS200; - } + if (reg == SDHCI_COMMAND) + is_tuning_cmd = mmc_op_tuning(SDHCI_GET_CMD(val)); if (is_tuning_cmd) clk_enabled = tegra_sdhci_configure_card_clk(host, 0); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 64750fbb0ac8..af7a1d75c458 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1693,8 +1693,7 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) flags |= SDHCI_CMD_INDEX; /* CMD19 is special in that the Data Present Select should be set */ - if (cmd->data || cmd->opcode == MMC_SEND_TUNING_BLOCK || - cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) + if (cmd->data || mmc_op_tuning(cmd->opcode)) flags |= SDHCI_CMD_DATA; timeout = jiffies; @@ -3374,8 +3373,6 @@ static void sdhci_adma_show_error(struct sdhci_host *host) static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) { - u32 command; - /* * CMD19 generates _only_ Buffer Read Ready interrupt if * use sdhci_send_tuning. @@ -3384,9 +3381,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) * SDHCI_INT_DATA_AVAIL always there, stuck in irq storm. */ if (intmask & SDHCI_INT_DATA_AVAIL && !host->data) { - command = SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)); - if (command == MMC_SEND_TUNING_BLOCK || - command == MMC_SEND_TUNING_BLOCK_HS200) { + if (mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)))) { host->tuning_done = 1; wake_up(&host->buf_ready_int); return; -- cgit v1.2.3 From 5c5301a147df77eb4479be9af74f65a334206602 Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Sat, 26 Nov 2022 18:25:20 +0800 Subject: mmc: core: refactor debugfs code Now, CONFIG_DEBUG_FS is scattered in various functions, to make code clean centralized processing CONFIG_DEBUG_FS in mmc debugfs module. Signed-off-by: Ye Bin Link: https://lore.kernel.org/r/20221126102520.2824574-1-yebin@huaweicloud.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/bus.c | 4 ---- drivers/mmc/core/core.h | 15 +++++++++++++++ drivers/mmc/core/host.c | 4 ---- 3 files changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index d8762fa3d5cd..36679f4e9acc 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -359,9 +359,7 @@ int mmc_add_card(struct mmc_card *card) uhs_bus_speed_mode, type, card->rca); } -#ifdef CONFIG_DEBUG_FS mmc_add_card_debugfs(card); -#endif card->dev.of_node = mmc_of_find_child_device(card->host, 0); device_enable_async_suspend(&card->dev); @@ -383,9 +381,7 @@ void mmc_remove_card(struct mmc_card *card) { struct mmc_host *host = card->host; -#ifdef CONFIG_DEBUG_FS mmc_remove_card_debugfs(card); -#endif if (mmc_card_present(card)) { if (mmc_host_is_spi(card->host)) { diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index f5f3f623ea49..37091a6589ed 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -86,11 +86,26 @@ int mmc_attach_sdio(struct mmc_host *host); extern bool use_spi_crc; /* Debugfs information for hosts and cards */ +#ifdef CONFIG_DEBUG_FS void mmc_add_host_debugfs(struct mmc_host *host); void mmc_remove_host_debugfs(struct mmc_host *host); void mmc_add_card_debugfs(struct mmc_card *card); void mmc_remove_card_debugfs(struct mmc_card *card); +#else +static inline void mmc_add_host_debugfs(struct mmc_host *host) +{ +} +static inline void mmc_remove_host_debugfs(struct mmc_host *host) +{ +} +static inline void mmc_add_card_debugfs(struct mmc_card *card) +{ +} +static inline void mmc_remove_card_debugfs(struct mmc_card *card) +{ +} +#endif int mmc_execute_tuning(struct mmc_card *card); int mmc_hs200_to_hs400(struct mmc_card *card); diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 5457c8aeeea1..d17eda753b7e 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -629,9 +629,7 @@ int mmc_add_host(struct mmc_host *host) led_trigger_register_simple(dev_name(&host->class_dev), &host->led); -#ifdef CONFIG_DEBUG_FS mmc_add_host_debugfs(host); -#endif mmc_start_host(host); return 0; @@ -651,9 +649,7 @@ void mmc_remove_host(struct mmc_host *host) { mmc_stop_host(host); -#ifdef CONFIG_DEBUG_FS mmc_remove_host_debugfs(host); -#endif device_del(&host->class_dev); -- cgit v1.2.3 From e026a3f9172f5c9aacff270b929a166c3ea1b6f7 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Mon, 28 Nov 2022 17:38:47 +0800 Subject: mmc: mmc-hsq: Use fifo to dispatch mmc_request Current next_tag selection will cause a large delay in some requests and destroy the scheduling results of the block scheduling layer. Because the issued mrq tags cannot ensure that each time is sequential, especially when the IO load is heavy. In the fio performance test, we found that 4k random read data was sent to mmc_hsq to start calling request_atomic It takes nearly 200ms to process the request, while mmc_hsq has processed thousands of other requests. So we use fifo here to ensure the first in, first out feature of the request and avoid adding additional delay to the request. Reviewed-by: Wenchao Chen Signed-off-by: Michael Wu Link: https://lore.kernel.org/r/20221128093847.22768-1-michael@allwinnertech.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmc_hsq.c | 40 +++++++++++++++------------------------- drivers/mmc/host/mmc_hsq.h | 5 +++++ 2 files changed, 20 insertions(+), 25 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mmc_hsq.c b/drivers/mmc/host/mmc_hsq.c index 9d35453e7371..424dc7b07858 100644 --- a/drivers/mmc/host/mmc_hsq.c +++ b/drivers/mmc/host/mmc_hsq.c @@ -13,9 +13,6 @@ #include "mmc_hsq.h" -#define HSQ_NUM_SLOTS 64 -#define HSQ_INVALID_TAG HSQ_NUM_SLOTS - static void mmc_hsq_retry_handler(struct work_struct *work) { struct mmc_hsq *hsq = container_of(work, struct mmc_hsq, retry_work); @@ -73,7 +70,6 @@ static void mmc_hsq_pump_requests(struct mmc_hsq *hsq) static void mmc_hsq_update_next_tag(struct mmc_hsq *hsq, int remains) { - struct hsq_slot *slot; int tag; /* @@ -82,29 +78,12 @@ static void mmc_hsq_update_next_tag(struct mmc_hsq *hsq, int remains) */ if (!remains) { hsq->next_tag = HSQ_INVALID_TAG; + hsq->tail_tag = HSQ_INVALID_TAG; return; } - /* - * Increasing the next tag and check if the corresponding request is - * available, if yes, then we found a candidate request. - */ - if (++hsq->next_tag != HSQ_INVALID_TAG) { - slot = &hsq->slot[hsq->next_tag]; - if (slot->mrq) - return; - } - - /* Othersie we should iterate all slots to find a available tag. */ - for (tag = 0; tag < HSQ_NUM_SLOTS; tag++) { - slot = &hsq->slot[tag]; - if (slot->mrq) - break; - } - - if (tag == HSQ_NUM_SLOTS) - tag = HSQ_INVALID_TAG; - + tag = hsq->tag_slot[hsq->next_tag]; + hsq->tag_slot[hsq->next_tag] = HSQ_INVALID_TAG; hsq->next_tag = tag; } @@ -233,8 +212,14 @@ static int mmc_hsq_request(struct mmc_host *mmc, struct mmc_request *mrq) * Set the next tag as current request tag if no available * next tag. */ - if (hsq->next_tag == HSQ_INVALID_TAG) + if (hsq->next_tag == HSQ_INVALID_TAG) { hsq->next_tag = tag; + hsq->tail_tag = tag; + hsq->tag_slot[hsq->tail_tag] = HSQ_INVALID_TAG; + } else { + hsq->tag_slot[hsq->tail_tag] = tag; + hsq->tail_tag = tag; + } hsq->qcnt++; @@ -339,8 +324,10 @@ static const struct mmc_cqe_ops mmc_hsq_ops = { int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc) { + int i; hsq->num_slots = HSQ_NUM_SLOTS; hsq->next_tag = HSQ_INVALID_TAG; + hsq->tail_tag = HSQ_INVALID_TAG; hsq->slot = devm_kcalloc(mmc_dev(mmc), hsq->num_slots, sizeof(struct hsq_slot), GFP_KERNEL); @@ -351,6 +338,9 @@ int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc) hsq->mmc->cqe_private = hsq; mmc->cqe_ops = &mmc_hsq_ops; + for (i = 0; i < HSQ_NUM_SLOTS; i++) + hsq->tag_slot[i] = HSQ_INVALID_TAG; + INIT_WORK(&hsq->retry_work, mmc_hsq_retry_handler); spin_lock_init(&hsq->lock); init_waitqueue_head(&hsq->wait_queue); diff --git a/drivers/mmc/host/mmc_hsq.h b/drivers/mmc/host/mmc_hsq.h index ffdd9cd172c3..1808024fc6c5 100644 --- a/drivers/mmc/host/mmc_hsq.h +++ b/drivers/mmc/host/mmc_hsq.h @@ -2,6 +2,9 @@ #ifndef LINUX_MMC_HSQ_H #define LINUX_MMC_HSQ_H +#define HSQ_NUM_SLOTS 64 +#define HSQ_INVALID_TAG HSQ_NUM_SLOTS + struct hsq_slot { struct mmc_request *mrq; }; @@ -17,6 +20,8 @@ struct mmc_hsq { int next_tag; int num_slots; int qcnt; + int tail_tag; + int tag_slot[HSQ_NUM_SLOTS]; bool enabled; bool waiting_for_idle; -- cgit v1.2.3 From beaba9e46cffca7fcf00bec7cf52fe52a9dcf918 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 28 Nov 2022 15:32:58 +0200 Subject: mmc: sdhci: Avoid unnecessary ->set_clock() To avoid glitches on the clock line, the card clock is disabled when making timing changes. Do not do that separately for HISPD and UHS settings. Tested-by: Haibo Chen Signed-off-by: Adrian Hunter Link: https://lore.kernel.org/r/20221128133259.38305-4-adrian.hunter@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index af7a1d75c458..aacdd3c51ced 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2403,8 +2403,21 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (host->version >= SDHCI_SPEC_300) { u16 clk, ctrl_2; + /* + * According to SDHCI Spec v3.00, if the Preset Value + * Enable in the Host Control 2 register is set, we + * need to reset SD Clock Enable before changing High + * Speed Enable to avoid generating clock glitches. + */ + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + if (clk & SDHCI_CLOCK_CARD_EN) { + clk &= ~SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + } + + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); + if (!host->preset_enabled) { - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); /* * We only need to set Driver Strength if the * preset value enable is not set. @@ -2427,30 +2440,8 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); host->drv_type = ios->drv_type; - } else { - /* - * According to SDHC Spec v3.00, if the Preset Value - * Enable in the Host Control 2 register is set, we - * need to reset SD Clock Enable before changing High - * Speed Enable to avoid generating clock gliches. - */ - - /* Reset SD Clock Enable */ - clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); - clk &= ~SDHCI_CLOCK_CARD_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); - - /* Re-enable SD Clock */ - host->ops->set_clock(host, host->clock); } - /* Reset SD Clock Enable */ - clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); - clk &= ~SDHCI_CLOCK_CARD_EN; - sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); - host->ops->set_uhs_signaling(host, ios->timing); host->timing = ios->timing; -- cgit v1.2.3 From fc02e2b52389c8fde02852b2f959c0b45f042bbd Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Wed, 30 Nov 2022 21:49:20 +0800 Subject: mmc: core: Normalize the error handling branch in sd_read_ext_regs() Let's use pr_err() to output the error messages and let's extend a comment to clarify why returning 0 (success) in one case make sense. Fixes: c784f92769ae ("mmc: core: Read the SD function extension registers for power management") Signed-off-by: Zhen Lei [Ulf: Clarified the comment and the commit-msg] Link: https://lore.kernel.org/r/20221130134920.2109-1-thunder.leizhen@huawei.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/sd.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 3662bf5320ce..72b664ed90cf 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1259,7 +1259,7 @@ static int sd_read_ext_regs(struct mmc_card *card) */ err = sd_read_ext_reg(card, 0, 0, 0, 512, gen_info_buf); if (err) { - pr_warn("%s: error %d reading general info of SD ext reg\n", + pr_err("%s: error %d reading general info of SD ext reg\n", mmc_hostname(card->host), err); goto out; } @@ -1273,7 +1273,12 @@ static int sd_read_ext_regs(struct mmc_card *card) /* Number of extensions to be find. */ num_ext = gen_info_buf[4]; - /* We support revision 0, but limit it to 512 bytes for simplicity. */ + /* + * We only support revision 0 and limit it to 512 bytes for simplicity. + * No matter what, let's return zero to allow us to continue using the + * card, even if we can't support the features from the SD function + * extensions registers. + */ if (rev != 0 || len > 512) { pr_warn("%s: non-supported SD ext reg layout\n", mmc_hostname(card->host)); @@ -1288,7 +1293,7 @@ static int sd_read_ext_regs(struct mmc_card *card) for (i = 0; i < num_ext; i++) { err = sd_parse_ext_reg(card, gen_info_buf, &next_ext_addr); if (err) { - pr_warn("%s: error %d parsing SD ext reg\n", + pr_err("%s: error %d parsing SD ext reg\n", mmc_hostname(card->host), err); goto out; } -- cgit v1.2.3 From 496182a389627a60d1b12be32d1640b14c678b8b Mon Sep 17 00:00:00 2001 From: zhang songyi Date: Fri, 2 Dec 2022 10:31:57 +0800 Subject: mmc: sdhci: Remove unneeded semicolon The semicolon after the "}" is unneeded. Signed-off-by: zhang songyi Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/202212021031575255977@zte.com.cn Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index aacdd3c51ced..edf052ccb176 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2289,7 +2289,7 @@ static bool sdhci_timing_has_preset(unsigned char timing) case MMC_TIMING_UHS_DDR50: case MMC_TIMING_MMC_DDR52: return true; - }; + } return false; } -- cgit v1.2.3 From c8d2d76d7646dc9b2d377699f68dce5403ad9b80 Mon Sep 17 00:00:00 2001 From: Andy Tang Date: Fri, 2 Dec 2022 15:59:05 +0800 Subject: mmc: sdhci-of-esdhc: limit the SDHC clock frequency The highest clock frequency for eMMC HS200 mode on ls1043a is 116.7Mhz according to its specification. So add the limit to gate the frequency. Signed-off-by: Andy Tang Link: https://lore.kernel.org/r/20221202075905.25363-1-andy.tang@nxp.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-esdhc.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index e0266638381d..9d875bb531a8 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -42,6 +42,12 @@ static const struct esdhc_clk_fixup ls1021a_esdhc_clk = { .max_clk[MMC_TIMING_SD_HS] = 46500000, }; +static const struct esdhc_clk_fixup ls1043a_esdhc_clk = { + .sd_dflt_max_clk = 25000000, + .max_clk[MMC_TIMING_UHS_SDR104] = 116700000, + .max_clk[MMC_TIMING_MMC_HS200] = 116700000, +}; + static const struct esdhc_clk_fixup ls1046a_esdhc_clk = { .sd_dflt_max_clk = 25000000, .max_clk[MMC_TIMING_UHS_SDR104] = 167000000, @@ -63,6 +69,7 @@ static const struct esdhc_clk_fixup p1010_esdhc_clk = { static const struct of_device_id sdhci_esdhc_of_match[] = { { .compatible = "fsl,ls1021a-esdhc", .data = &ls1021a_esdhc_clk}, + { .compatible = "fsl,ls1043a-esdhc", .data = &ls1043a_esdhc_clk}, { .compatible = "fsl,ls1046a-esdhc", .data = &ls1046a_esdhc_clk}, { .compatible = "fsl,ls1012a-esdhc", .data = &ls1012a_esdhc_clk}, { .compatible = "fsl,p1010-esdhc", .data = &p1010_esdhc_clk}, -- cgit v1.2.3 From 4a44cd249604e29e7b90ae796d7692f5773dd348 Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Sun, 4 Dec 2022 16:24:16 +0800 Subject: mmc: vub300: fix warning - do not call blocking ops when !TASK_RUNNING vub300_enable_sdio_irq() works with mutex and need TASK_RUNNING here. Ensure that we mark current as TASK_RUNNING for sleepable context. [ 77.554641] do not call blocking ops when !TASK_RUNNING; state=1 set at [] sdio_irq_thread+0x17d/0x5b0 [ 77.554652] WARNING: CPU: 2 PID: 1983 at kernel/sched/core.c:9813 __might_sleep+0x116/0x160 [ 77.554905] CPU: 2 PID: 1983 Comm: ksdioirqd/mmc1 Tainted: G OE 6.1.0-rc5 #1 [ 77.554910] Hardware name: Intel(R) Client Systems NUC8i7BEH/NUC8BEB, BIOS BECFL357.86A.0081.2020.0504.1834 05/04/2020 [ 77.554912] RIP: 0010:__might_sleep+0x116/0x160 [ 77.554920] RSP: 0018:ffff888107b7fdb8 EFLAGS: 00010282 [ 77.554923] RAX: 0000000000000000 RBX: ffff888118c1b740 RCX: 0000000000000000 [ 77.554926] RDX: 0000000000000001 RSI: 0000000000000004 RDI: ffffed1020f6ffa9 [ 77.554928] RBP: ffff888107b7fde0 R08: 0000000000000001 R09: ffffed1043ea60ba [ 77.554930] R10: ffff88821f5305cb R11: ffffed1043ea60b9 R12: ffffffff93aa3a60 [ 77.554932] R13: 000000000000011b R14: 7fffffffffffffff R15: ffffffffc0558660 [ 77.554934] FS: 0000000000000000(0000) GS:ffff88821f500000(0000) knlGS:0000000000000000 [ 77.554937] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 77.554939] CR2: 00007f8a44010d68 CR3: 000000024421a003 CR4: 00000000003706e0 [ 77.554942] Call Trace: [ 77.554944] [ 77.554952] mutex_lock+0x78/0xf0 [ 77.554973] vub300_enable_sdio_irq+0x103/0x3c0 [vub300] [ 77.554981] sdio_irq_thread+0x25c/0x5b0 [ 77.555006] kthread+0x2b8/0x370 [ 77.555017] ret_from_fork+0x1f/0x30 [ 77.555023] [ 77.555025] ---[ end trace 0000000000000000 ]--- Fixes: 88095e7b473a ("mmc: Add new VUB300 USB-to-SD/SDIO/MMC driver") Signed-off-by: Deren Wu Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/87dc45b122d26d63c80532976813c9365d7160b3.1670140888.git.deren.wu@mediatek.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/vub300.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index ab36ec479747..72f65f32abbc 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -2049,6 +2049,7 @@ static void vub300_enable_sdio_irq(struct mmc_host *mmc, int enable) return; kref_get(&vub300->kref); if (enable) { + set_current_state(TASK_RUNNING); mutex_lock(&vub300->irq_mutex); if (vub300->irqs_queued) { vub300->irqs_queued -= 1; @@ -2064,6 +2065,7 @@ static void vub300_enable_sdio_irq(struct mmc_host *mmc, int enable) vub300_queue_poll_work(vub300, 0); } mutex_unlock(&vub300->irq_mutex); + set_current_state(TASK_INTERRUPTIBLE); } else { vub300->irq_enabled = 0; } -- cgit v1.2.3 From a234442c0b51163841762748e7e22c3718337923 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 5 Dec 2022 16:04:06 -0800 Subject: mmc: sdhci-brcmstb: Resolve "unused" warnings with CONFIG_OF=n MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With W=1, we can see this gcc warning: drivers/mmc/host/sdhci-brcmstb.c:182:34: warning: ‘sdhci_brcm_of_match’ defined but not used [-Wunused-const-variable=] 182 | static const struct of_device_id sdhci_brcm_of_match[] = { | ^~~~~~~~~~~~~~~~~~~ Rather than play around more with #ifdef's, the simplest solution is to just mark this __maybe_unused. Fixes: 50bfe185c42a ("mmc: sdhci-brcmstb: Allow building with COMPILE_TEST") Reported-by: kernel test robot Link: https://lore.kernel.org/all/202212060700.NjMecjxS-lkp@intel.com/ Signed-off-by: Brian Norris Acked-by: Florian Fainelli Link: https://lore.kernel.org/r/20221205160353.1.I5fa28f1045f17fb9285d507accf139f8b2a8f4b5@changeid Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-brcmstb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c index 55d8bd232695..f2cf3d70db79 100644 --- a/drivers/mmc/host/sdhci-brcmstb.c +++ b/drivers/mmc/host/sdhci-brcmstb.c @@ -179,7 +179,7 @@ static const struct brcmstb_match_priv match_priv_7216 = { .ops = &sdhci_brcmstb_ops_7216, }; -static const struct of_device_id sdhci_brcm_of_match[] = { +static const struct of_device_id __maybe_unused sdhci_brcm_of_match[] = { { .compatible = "brcm,bcm7425-sdhci", .data = &match_priv_7425 }, { .compatible = "brcm,bcm7445-sdhci", .data = &match_priv_7445 }, { .compatible = "brcm,bcm7216-sdhci", .data = &match_priv_7216 }, -- cgit v1.2.3 From 07548a391df07637a057caa5bd07cafb6157fe79 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 6 Dec 2022 17:59:42 +0100 Subject: mmc: sdhci-tegra: Sort includes alphabetically Sort includes alphabetically to make it easier to add new ones subsequently. Acked-by: Adrian Hunter Signed-off-by: Thierry Reding Link: https://lore.kernel.org/r/20221206165945.3551774-4-thierry.reding@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-tegra.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 9fc8a61eca54..afa9cbf9cb6f 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -3,28 +3,28 @@ * Copyright (C) 2010 Google, Inc. */ +#include #include #include #include -#include +#include #include -#include -#include -#include #include -#include +#include +#include +#include +#include +#include +#include +#include #include +#include #include +#include #include #include #include #include -#include -#include -#include -#include -#include -#include #include -- cgit v1.2.3 From 8f00ad01fcd457d5e8c09c97f7a963be09e59b99 Mon Sep 17 00:00:00 2001 From: Prathamesh Shete Date: Tue, 6 Dec 2022 17:59:43 +0100 Subject: mmc: sdhci-tegra: Separate Tegra194 and Tegra234 SoC data Create new SoC data structure for Tegra234 platforms. Additional features, tap value configurations are added/updated for Tegra234 platform hence separate Tegra194 and Tegra234 SoC data. Signed-off-by: Aniruddha Tvs Rao Signed-off-by: Prathamesh Shete Acked-by: Adrian Hunter Acked-by: Thierry Reding Signed-off-by: Thierry Reding Link: https://lore.kernel.org/r/20221206165945.3551774-5-thierry.reding@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-tegra.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index afa9cbf9cb6f..f3f5a4abcafb 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -1553,7 +1553,21 @@ static const struct sdhci_tegra_soc_data soc_data_tegra194 = { .max_tap_delay = 139, }; +static const struct sdhci_tegra_soc_data soc_data_tegra234 = { + .pdata = &sdhci_tegra186_pdata, + .dma_mask = DMA_BIT_MASK(39), + .nvquirks = NVQUIRK_NEEDS_PAD_CONTROL | + NVQUIRK_HAS_PADCALIB | + NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | + NVQUIRK_ENABLE_SDR50 | + NVQUIRK_ENABLE_SDR104 | + NVQUIRK_HAS_TMCLK, + .min_tap_delay = 95, + .max_tap_delay = 111, +}; + static const struct of_device_id sdhci_tegra_dt_match[] = { + { .compatible = "nvidia,tegra234-sdhci", .data = &soc_data_tegra234 }, { .compatible = "nvidia,tegra194-sdhci", .data = &soc_data_tegra194 }, { .compatible = "nvidia,tegra186-sdhci", .data = &soc_data_tegra186 }, { .compatible = "nvidia,tegra210-sdhci", .data = &soc_data_tegra210 }, -- cgit v1.2.3 From 03813c81e62559489afa1b461ab159b5641d66f8 Mon Sep 17 00:00:00 2001 From: Prathamesh Shete Date: Tue, 6 Dec 2022 17:59:44 +0100 Subject: mmc: sdhci-tegra: Add support to program MC stream ID SMMU clients are supposed to program stream ID from their respective address spaces instead of MC override. Define NVQUIRK_PROGRAM_STREAMID and use it to program SMMU stream ID from the SDMMC client address space. Signed-off-by: Aniruddha TVS Rao Signed-off-by: Prathamesh Shete Acked-by: Adrian Hunter Acked-by: Thierry Reding Signed-off-by: Thierry Reding Link: https://lore.kernel.org/r/20221206165945.3551774-6-thierry.reding@gmail.com [Ulf: Fixed a checkpatch error] Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-tegra.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index f3f5a4abcafb..fbe3a2e870bf 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -3,6 +3,7 @@ * Copyright (C) 2010 Google, Inc. */ +#include #include #include #include @@ -10,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -95,6 +97,8 @@ #define SDHCI_TEGRA_AUTO_CAL_STATUS 0x1ec #define SDHCI_TEGRA_AUTO_CAL_ACTIVE BIT(31) +#define SDHCI_TEGRA_CIF2AXI_CTRL_0 0x1fc + #define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0) #define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1) #define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2) @@ -122,6 +126,7 @@ #define NVQUIRK_HAS_TMCLK BIT(10) #define NVQUIRK_HAS_ANDROID_GPT_SECTOR BIT(11) +#define NVQUIRK_PROGRAM_STREAMID BIT(12) /* SDMMC CQE Base Address for Tegra Host Ver 4.1 and Higher */ #define SDHCI_TEGRA_CQE_BASE_ADDR 0xF000 @@ -178,6 +183,7 @@ struct sdhci_tegra { bool enable_hwcq; unsigned long curr_clk_rate; u8 tuned_tap_delay; + u32 stream_id; }; static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) @@ -1561,6 +1567,7 @@ static const struct sdhci_tegra_soc_data soc_data_tegra234 = { NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | NVQUIRK_ENABLE_SDR50 | NVQUIRK_ENABLE_SDR104 | + NVQUIRK_PROGRAM_STREAMID | NVQUIRK_HAS_TMCLK, .min_tap_delay = 95, .max_tap_delay = 111, @@ -1627,6 +1634,19 @@ cleanup: return ret; } +/* Program MC streamID for DMA transfers */ +static void sdhci_tegra_program_stream_id(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + + if (tegra_host->soc_data->nvquirks & NVQUIRK_PROGRAM_STREAMID) { + tegra_sdhci_writel(host, FIELD_PREP(GENMASK(15, 8), tegra_host->stream_id) | + FIELD_PREP(GENMASK(7, 0), tegra_host->stream_id), + SDHCI_TEGRA_CIF2AXI_CTRL_0); + } +} + static int sdhci_tegra_probe(struct platform_device *pdev) { const struct sdhci_tegra_soc_data *soc_data; @@ -1687,6 +1707,12 @@ static int sdhci_tegra_probe(struct platform_device *pdev) tegra_sdhci_parse_dt(host); + if (tegra_host->soc_data->nvquirks & NVQUIRK_PROGRAM_STREAMID && + !tegra_dev_iommu_get_stream_id(&pdev->dev, &tegra_host->stream_id)) { + dev_warn(mmc_dev(host->mmc), "missing IOMMU stream ID\n"); + tegra_host->stream_id = 0x7f; + } + tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power", GPIOD_OUT_HIGH); if (IS_ERR(tegra_host->power_gpio)) { @@ -1772,6 +1798,8 @@ static int sdhci_tegra_probe(struct platform_device *pdev) if (rc) goto err_add_host; + sdhci_tegra_program_stream_id(host); + return 0; err_add_host: @@ -1868,6 +1896,8 @@ static int sdhci_tegra_resume(struct device *dev) if (ret) return ret; + sdhci_tegra_program_stream_id(host); + ret = sdhci_resume_host(host); if (ret) goto disable_clk; -- cgit v1.2.3 From acc13958c2b2623c17e2450b8cd6881b698756d3 Mon Sep 17 00:00:00 2001 From: Prathamesh Shete Date: Tue, 6 Dec 2022 17:59:45 +0100 Subject: mmc: sdhci-tegra: Issue CMD and DAT resets together In case of error condition to avoid system crash Tegra SDMMC controller requires CMD and DAT resets issued together. SDHCI controller FSM goes into bad state due to rapid SD card hot-plug event. Issuing reset on the CMD FSM before DATA FSM results in kernel panic, hence add support to issue CMD and DAT resets together. This is applicable to Tegra186 and later chips. Signed-off-by: Aniruddha TVS Rao Signed-off-by: Prathamesh Shete Acked-by: Adrian Hunter Acked-by: Thierry Reding Signed-off-by: Thierry Reding Link: https://lore.kernel.org/r/20221206165945.3551774-7-thierry.reding@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-tegra.c | 3 ++- drivers/mmc/host/sdhci.c | 5 +++++ drivers/mmc/host/sdhci.h | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index fbe3a2e870bf..bff084f178c9 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -1528,7 +1528,8 @@ static const struct sdhci_pltfm_data sdhci_tegra186_pdata = { SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, - .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER, .ops = &tegra186_sdhci_ops, }; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index edf052ccb176..f3af1bd0f7b9 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -270,6 +270,11 @@ enum sdhci_reset_reason { static void sdhci_reset_for_reason(struct sdhci_host *host, enum sdhci_reset_reason reason) { + if (host->quirks2 & SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER) { + sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); + return; + } + switch (reason) { case SDHCI_RESET_FOR_INIT: sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index b6f31a7d6152..605eaee805f7 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -478,6 +478,8 @@ struct sdhci_host { * block count. */ #define SDHCI_QUIRK2_USE_32BIT_BLK_CNT (1<<18) +/* Issue CMD and DATA reset together */ +#define SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER (1<<19) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ -- cgit v1.2.3 From 19dafe9c6b86cc15979e514787fc743041ebc08d Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Fri, 9 Dec 2022 11:41:34 +0800 Subject: mmc: sdhci-of-esdhc: Modify mismatched function name No functional modification involved. drivers/mmc/host/sdhci-of-esdhc.c:243: warning: expecting prototype for _fixup(). Prototype was for esdhc_writel_fixup() instead. drivers/mmc/host/sdhci-of-esdhc.c:117: warning: expecting prototype for _fixup(). Prototype was for esdhc_readl_fixup() instead. Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=3397 Reported-by: Abaci Robot Signed-off-by: Jiapeng Chong Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20221209034134.38477-1-jiapeng.chong@linux.alibaba.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-esdhc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 9d875bb531a8..4712adac7f7c 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -98,7 +98,7 @@ struct sdhci_esdhc { }; /** - * esdhc_read*_fixup - Fixup the value read from incompatible eSDHC register + * esdhc_readl_fixup - Fixup the value read from incompatible eSDHC register * to make it compatible with SD spec. * * @host: pointer to sdhci_host @@ -223,7 +223,7 @@ static u8 esdhc_readb_fixup(struct sdhci_host *host, } /** - * esdhc_write*_fixup - Fixup the SD spec register value so that it could be + * esdhc_writel_fixup - Fixup the SD spec register value so that it could be * written into eSDHC register. * * @host: pointer to sdhci_host -- cgit v1.2.3 From ff874dbc4f868af128b412a9bd92637103cf11d7 Mon Sep 17 00:00:00 2001 From: Wenchao Chen Date: Wed, 7 Dec 2022 13:19:09 +0800 Subject: mmc: sdhci-sprd: Disable CLK_AUTO when the clock is less than 400K When the clock is less than 400K, some SD cards fail to initialize because CLK_AUTO is enabled. Fixes: fb8bd90f83c4 ("mmc: sdhci-sprd: Add Spreadtrum's initial host controller") Signed-off-by: Wenchao Chen Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20221207051909.32126-1-wenchao.chen@unisoc.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-sprd.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c index bec3f9e3cd3f..525f979e2a97 100644 --- a/drivers/mmc/host/sdhci-sprd.c +++ b/drivers/mmc/host/sdhci-sprd.c @@ -228,13 +228,15 @@ static inline void _sdhci_sprd_set_clock(struct sdhci_host *host, div = ((div & 0x300) >> 2) | ((div & 0xFF) << 8); sdhci_enable_clk(host, div); - /* enable auto gate sdhc_enable_auto_gate */ - val = sdhci_readl(host, SDHCI_SPRD_REG_32_BUSY_POSI); - mask = SDHCI_SPRD_BIT_OUTR_CLK_AUTO_EN | - SDHCI_SPRD_BIT_INNR_CLK_AUTO_EN; - if (mask != (val & mask)) { - val |= mask; - sdhci_writel(host, val, SDHCI_SPRD_REG_32_BUSY_POSI); + /* Enable CLK_AUTO when the clock is greater than 400K. */ + if (clk > 400000) { + val = sdhci_readl(host, SDHCI_SPRD_REG_32_BUSY_POSI); + mask = SDHCI_SPRD_BIT_OUTR_CLK_AUTO_EN | + SDHCI_SPRD_BIT_INNR_CLK_AUTO_EN; + if (mask != (val & mask)) { + val |= mask; + sdhci_writel(host, val, SDHCI_SPRD_REG_32_BUSY_POSI); + } } } -- cgit v1.2.3