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