Michael Walle | 02016c6 | 2020-09-23 12:42:51 +0200 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0+ |
| 2 | /* |
| 3 | * SDHCI ADMA2 helper functions. |
| 4 | */ |
| 5 | |
Michael Walle | 02016c6 | 2020-09-23 12:42:51 +0200 | [diff] [blame] | 6 | #include <cpu_func.h> |
| 7 | #include <sdhci.h> |
| 8 | #include <malloc.h> |
| 9 | #include <asm/cache.h> |
| 10 | |
Ian Roberts | 6853d89 | 2024-04-22 15:00:02 -0400 | [diff] [blame] | 11 | void sdhci_adma_write_desc(struct sdhci_host *host, void **next_desc, |
| 12 | dma_addr_t addr, int len, bool end) |
Michael Walle | 02016c6 | 2020-09-23 12:42:51 +0200 | [diff] [blame] | 13 | { |
Ian Roberts | 6853d89 | 2024-04-22 15:00:02 -0400 | [diff] [blame] | 14 | struct sdhci_adma_desc *desc = *next_desc; |
Michael Walle | 02016c6 | 2020-09-23 12:42:51 +0200 | [diff] [blame] | 15 | u8 attr; |
| 16 | |
| 17 | attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA; |
| 18 | if (end) |
| 19 | attr |= ADMA_DESC_ATTR_END; |
| 20 | |
| 21 | desc->attr = attr; |
Ian Roberts | 6853d89 | 2024-04-22 15:00:02 -0400 | [diff] [blame] | 22 | desc->len = len & 0xffff; |
Michael Walle | 02016c6 | 2020-09-23 12:42:51 +0200 | [diff] [blame] | 23 | desc->reserved = 0; |
| 24 | desc->addr_lo = lower_32_bits(addr); |
Greg Malysa | eb92ef1 | 2024-03-25 22:28:08 -0400 | [diff] [blame] | 25 | #ifdef CONFIG_MMC_SDHCI_ADMA_64BIT |
Michael Walle | 02016c6 | 2020-09-23 12:42:51 +0200 | [diff] [blame] | 26 | desc->addr_hi = upper_32_bits(addr); |
| 27 | #endif |
Ian Roberts | 6853d89 | 2024-04-22 15:00:02 -0400 | [diff] [blame] | 28 | |
| 29 | *next_desc += ADMA_DESC_LEN; |
| 30 | } |
| 31 | |
| 32 | static inline void __sdhci_adma_write_desc(struct sdhci_host *host, |
| 33 | void **desc, dma_addr_t addr, |
| 34 | int len, bool end) |
| 35 | { |
| 36 | if (host && host->ops && host->ops->adma_write_desc) |
| 37 | host->ops->adma_write_desc(host, desc, addr, len, end); |
| 38 | else |
| 39 | sdhci_adma_write_desc(host, desc, addr, len, end); |
Michael Walle | 02016c6 | 2020-09-23 12:42:51 +0200 | [diff] [blame] | 40 | } |
| 41 | |
| 42 | /** |
| 43 | * sdhci_prepare_adma_table() - Populate the ADMA table |
| 44 | * |
Ian Roberts | 6853d89 | 2024-04-22 15:00:02 -0400 | [diff] [blame] | 45 | * @host: Pointer to the sdhci_host |
Michael Walle | 02016c6 | 2020-09-23 12:42:51 +0200 | [diff] [blame] | 46 | * @table: Pointer to the ADMA table |
| 47 | * @data: Pointer to MMC data |
| 48 | * @addr: DMA address to write to or read from |
| 49 | * |
| 50 | * Fill the ADMA table according to the MMC data to read from or write to the |
| 51 | * given DMA address. |
| 52 | * Please note, that the table size depends on CONFIG_SYS_MMC_MAX_BLK_COUNT and |
| 53 | * we don't have to check for overflow. |
| 54 | */ |
Ian Roberts | 6853d89 | 2024-04-22 15:00:02 -0400 | [diff] [blame] | 55 | void sdhci_prepare_adma_table(struct sdhci_host *host, |
| 56 | struct sdhci_adma_desc *table, |
| 57 | struct mmc_data *data, dma_addr_t start_addr) |
Michael Walle | 02016c6 | 2020-09-23 12:42:51 +0200 | [diff] [blame] | 58 | { |
Ian Roberts | 6853d89 | 2024-04-22 15:00:02 -0400 | [diff] [blame] | 59 | dma_addr_t addr = start_addr; |
Michael Walle | 02016c6 | 2020-09-23 12:42:51 +0200 | [diff] [blame] | 60 | uint trans_bytes = data->blocksize * data->blocks; |
Ian Roberts | 6853d89 | 2024-04-22 15:00:02 -0400 | [diff] [blame] | 61 | void *next_desc = table; |
| 62 | int i = DIV_ROUND_UP(trans_bytes, ADMA_MAX_LEN); |
Michael Walle | 02016c6 | 2020-09-23 12:42:51 +0200 | [diff] [blame] | 63 | |
| 64 | while (--i) { |
Ian Roberts | 6853d89 | 2024-04-22 15:00:02 -0400 | [diff] [blame] | 65 | __sdhci_adma_write_desc(host, &next_desc, addr, |
| 66 | ADMA_MAX_LEN, false); |
Michael Walle | 02016c6 | 2020-09-23 12:42:51 +0200 | [diff] [blame] | 67 | addr += ADMA_MAX_LEN; |
| 68 | trans_bytes -= ADMA_MAX_LEN; |
Michael Walle | 02016c6 | 2020-09-23 12:42:51 +0200 | [diff] [blame] | 69 | } |
| 70 | |
Ian Roberts | 6853d89 | 2024-04-22 15:00:02 -0400 | [diff] [blame] | 71 | __sdhci_adma_write_desc(host, &next_desc, addr, trans_bytes, true); |
Michael Walle | 02016c6 | 2020-09-23 12:42:51 +0200 | [diff] [blame] | 72 | |
Ian Roberts | 6853d89 | 2024-04-22 15:00:02 -0400 | [diff] [blame] | 73 | flush_cache((phys_addr_t)table, |
| 74 | ROUND(next_desc - (void *)table, |
Michael Walle | 02016c6 | 2020-09-23 12:42:51 +0200 | [diff] [blame] | 75 | ARCH_DMA_MINALIGN)); |
| 76 | } |
| 77 | |
| 78 | /** |
| 79 | * sdhci_adma_init() - initialize the ADMA descriptor table |
| 80 | * |
Heinrich Schuchardt | 47b4c02 | 2022-01-19 18:05:50 +0100 | [diff] [blame] | 81 | * Return: pointer to the allocated descriptor table or NULL in case of an |
Michael Walle | 02016c6 | 2020-09-23 12:42:51 +0200 | [diff] [blame] | 82 | * error. |
| 83 | */ |
| 84 | struct sdhci_adma_desc *sdhci_adma_init(void) |
| 85 | { |
| 86 | return memalign(ARCH_DMA_MINALIGN, ADMA_TABLE_SZ); |
| 87 | } |