Jorge Ramirez-Ortiz | 3545696 | 2021-06-13 20:55:53 +0200 | [diff] [blame] | 1 | // SPDX-License-Identifier: MIT |
| 2 | /* |
| 3 | * Copyright(c) 2015 - 2020 Xilinx, Inc. |
| 4 | * |
| 5 | * Jorge Ramirez-Ortiz <jorge@foundries.io> |
| 6 | */ |
| 7 | |
| 8 | #include <common.h> |
| 9 | #include <cpu_func.h> |
| 10 | #include <asm/arch/hardware.h> |
| 11 | #include <asm/arch/ecc_spl_init.h> |
| 12 | #include <asm/io.h> |
| 13 | #include <linux/delay.h> |
| 14 | |
| 15 | #define ZDMA_TRANSFER_MAX_LEN (0x3FFFFFFFU - 7U) |
| 16 | #define ZDMA_CH_STATUS ((ADMA_CH0_BASEADDR) + 0x0000011CU) |
| 17 | #define ZDMA_CH_STATUS_STATE_MASK 0x00000003U |
| 18 | #define ZDMA_CH_STATUS_STATE_DONE 0x00000000U |
| 19 | #define ZDMA_CH_STATUS_STATE_ERR 0x00000003U |
| 20 | #define ZDMA_CH_CTRL0 ((ADMA_CH0_BASEADDR) + 0x00000110U) |
| 21 | #define ZDMA_CH_CTRL0_POINT_TYPE_MASK (u32)0x00000040U |
| 22 | #define ZDMA_CH_CTRL0_POINT_TYPE_NORMAL (u32)0x00000000U |
| 23 | #define ZDMA_CH_CTRL0_MODE_MASK (u32)0x00000030U |
| 24 | #define ZDMA_CH_CTRL0_MODE_WR_ONLY (u32)0x00000010U |
| 25 | #define ZDMA_CH_CTRL0_TOTAL_BYTE_COUNT ((ADMA_CH0_BASEADDR) + 0x00000188U) |
| 26 | #define ZDMA_CH_WR_ONLY_WORD0 ((ADMA_CH0_BASEADDR) + 0x00000148U) |
| 27 | #define ZDMA_CH_WR_ONLY_WORD1 ((ADMA_CH0_BASEADDR) + 0x0000014CU) |
| 28 | #define ZDMA_CH_WR_ONLY_WORD2 ((ADMA_CH0_BASEADDR) + 0x00000150U) |
| 29 | #define ZDMA_CH_WR_ONLY_WORD3 ((ADMA_CH0_BASEADDR) + 0x00000154U) |
| 30 | #define ZDMA_CH_DST_DSCR_WORD0 ((ADMA_CH0_BASEADDR) + 0x00000138U) |
| 31 | #define ZDMA_CH_DST_DSCR_WORD0_LSB_MASK 0xFFFFFFFFU |
| 32 | #define ZDMA_CH_DST_DSCR_WORD1 ((ADMA_CH0_BASEADDR) + 0x0000013CU) |
| 33 | #define ZDMA_CH_DST_DSCR_WORD1_MSB_MASK 0x0001FFFFU |
| 34 | #define ZDMA_CH_SRC_DSCR_WORD2 ((ADMA_CH0_BASEADDR) + 0x00000130U) |
| 35 | #define ZDMA_CH_DST_DSCR_WORD2 ((ADMA_CH0_BASEADDR) + 0x00000140U) |
| 36 | #define ZDMA_CH_CTRL2 ((ADMA_CH0_BASEADDR) + 0x00000200U) |
| 37 | #define ZDMA_CH_CTRL2_EN_MASK 0x00000001U |
| 38 | #define ZDMA_CH_ISR ((ADMA_CH0_BASEADDR) + 0x00000100U) |
| 39 | #define ZDMA_CH_ISR_DMA_DONE_MASK 0x00000400U |
| 40 | #define ECC_INIT_VAL_WORD 0xDEADBEEFU |
| 41 | |
| 42 | #define ZDMA_IDLE_TIMEOUT_USEC 1000000 |
| 43 | #define ZDMA_DONE_TIMEOUT_USEC 5000000 |
| 44 | |
| 45 | static void ecc_zdma_restore(void) |
| 46 | { |
| 47 | /* Restore reset values for the DMA registers used */ |
| 48 | writel(ZDMA_CH_CTRL0, 0x00000080U); |
| 49 | writel(ZDMA_CH_WR_ONLY_WORD0, 0x00000000U); |
| 50 | writel(ZDMA_CH_WR_ONLY_WORD1, 0x00000000U); |
| 51 | writel(ZDMA_CH_WR_ONLY_WORD2, 0x00000000U); |
| 52 | writel(ZDMA_CH_WR_ONLY_WORD3, 0x00000000U); |
| 53 | writel(ZDMA_CH_DST_DSCR_WORD0, 0x00000000U); |
| 54 | writel(ZDMA_CH_DST_DSCR_WORD1, 0x00000000U); |
| 55 | writel(ZDMA_CH_SRC_DSCR_WORD2, 0x00000000U); |
| 56 | writel(ZDMA_CH_DST_DSCR_WORD2, 0x00000000U); |
| 57 | writel(ZDMA_CH_CTRL0_TOTAL_BYTE_COUNT, 0x00000000U); |
| 58 | } |
| 59 | |
| 60 | static void ecc_dram_bank_init(u64 addr, u64 len) |
| 61 | { |
| 62 | bool retry = true; |
| 63 | u32 timeout; |
| 64 | u64 bytes; |
| 65 | u32 size; |
| 66 | u64 src; |
| 67 | u32 reg; |
| 68 | |
| 69 | if (!len) |
| 70 | return; |
| 71 | retry: |
| 72 | bytes = len; |
| 73 | src = addr; |
| 74 | ecc_zdma_restore(); |
| 75 | while (bytes > 0) { |
| 76 | size = bytes > ZDMA_TRANSFER_MAX_LEN ? |
| 77 | ZDMA_TRANSFER_MAX_LEN : (u32)bytes; |
| 78 | |
| 79 | /* Wait until the DMA is in idle state */ |
| 80 | timeout = ZDMA_IDLE_TIMEOUT_USEC; |
| 81 | do { |
| 82 | udelay(1); |
| 83 | reg = readl(ZDMA_CH_STATUS); |
| 84 | reg &= ZDMA_CH_STATUS_STATE_MASK; |
| 85 | if (!timeout--) { |
| 86 | puts("error, ECC DMA failed to idle\n"); |
| 87 | goto done; |
| 88 | } |
| 89 | |
| 90 | } while ((reg != ZDMA_CH_STATUS_STATE_DONE) && |
| 91 | (reg != ZDMA_CH_STATUS_STATE_ERR)); |
| 92 | |
| 93 | /* Enable Simple (Write Only) Mode */ |
| 94 | reg = readl(ZDMA_CH_CTRL0); |
| 95 | reg &= (ZDMA_CH_CTRL0_POINT_TYPE_MASK | |
| 96 | ZDMA_CH_CTRL0_MODE_MASK); |
| 97 | reg |= (ZDMA_CH_CTRL0_POINT_TYPE_NORMAL | |
| 98 | ZDMA_CH_CTRL0_MODE_WR_ONLY); |
| 99 | writel(reg, ZDMA_CH_CTRL0); |
| 100 | |
| 101 | /* Fill in the data to be written */ |
| 102 | writel(ECC_INIT_VAL_WORD, ZDMA_CH_WR_ONLY_WORD0); |
| 103 | writel(ECC_INIT_VAL_WORD, ZDMA_CH_WR_ONLY_WORD1); |
| 104 | writel(ECC_INIT_VAL_WORD, ZDMA_CH_WR_ONLY_WORD2); |
| 105 | writel(ECC_INIT_VAL_WORD, ZDMA_CH_WR_ONLY_WORD3); |
| 106 | |
| 107 | /* Write Destination Address */ |
| 108 | writel((u32)(src & ZDMA_CH_DST_DSCR_WORD0_LSB_MASK), |
| 109 | ZDMA_CH_DST_DSCR_WORD0); |
| 110 | writel((u32)((src >> 32) & ZDMA_CH_DST_DSCR_WORD1_MSB_MASK), |
| 111 | ZDMA_CH_DST_DSCR_WORD1); |
| 112 | |
| 113 | /* Size to be Transferred. Recommended to set both src and dest sizes */ |
| 114 | writel(size, ZDMA_CH_SRC_DSCR_WORD2); |
| 115 | writel(size, ZDMA_CH_DST_DSCR_WORD2); |
| 116 | |
| 117 | /* DMA Enable */ |
| 118 | reg = readl(ZDMA_CH_CTRL2); |
| 119 | reg |= ZDMA_CH_CTRL2_EN_MASK; |
| 120 | writel(reg, ZDMA_CH_CTRL2); |
| 121 | |
| 122 | /* Check the status of the transfer by polling on DMA Done */ |
| 123 | timeout = ZDMA_DONE_TIMEOUT_USEC; |
| 124 | do { |
| 125 | udelay(1); |
| 126 | reg = readl(ZDMA_CH_ISR); |
| 127 | reg &= ZDMA_CH_ISR_DMA_DONE_MASK; |
| 128 | if (!timeout--) { |
| 129 | puts("error, ECC DMA timeout\n"); |
| 130 | goto done; |
| 131 | } |
| 132 | } while (reg != ZDMA_CH_ISR_DMA_DONE_MASK); |
| 133 | |
| 134 | /* Clear DMA status */ |
| 135 | reg = readl(ZDMA_CH_ISR); |
| 136 | reg |= ZDMA_CH_ISR_DMA_DONE_MASK; |
| 137 | writel(ZDMA_CH_ISR_DMA_DONE_MASK, ZDMA_CH_ISR); |
| 138 | |
| 139 | /* Read the channel status for errors */ |
| 140 | reg = readl(ZDMA_CH_STATUS); |
| 141 | if (reg == ZDMA_CH_STATUS_STATE_ERR) { |
| 142 | if (retry) { |
| 143 | retry = false; |
| 144 | goto retry; |
| 145 | } |
| 146 | puts("error, ECC DMA error\n"); |
| 147 | break; |
| 148 | } |
| 149 | |
| 150 | bytes -= size; |
| 151 | src += size; |
| 152 | } |
| 153 | done: |
| 154 | ecc_zdma_restore(); |
| 155 | } |
| 156 | |
| 157 | void zynqmp_ecc_init(void) |
| 158 | { |
| 159 | ecc_dram_bank_init(CONFIG_SPL_ZYNQMP_DRAM_BANK1_BASE, |
| 160 | CONFIG_SPL_ZYNQMP_DRAM_BANK1_LEN); |
| 161 | ecc_dram_bank_init(CONFIG_SPL_ZYNQMP_DRAM_BANK2_BASE, |
| 162 | CONFIG_SPL_ZYNQMP_DRAM_BANK2_LEN); |
| 163 | } |