1 /* 2 * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <stdint.h> 9 10 #include <platform_def.h> 11 12 #include <arch_helpers.h> 13 #include <common/debug.h> 14 #include <drivers/io/io_block.h> 15 #include <lib/mmio.h> 16 #include <lib/utils_def.h> 17 18 #include "uniphier.h" 19 20 #define NAND_CMD_READ0 0 21 #define NAND_CMD_READSTART 0x30 22 23 #define DENALI_ECC_ENABLE 0x0e0 24 #define DENALI_PAGES_PER_BLOCK 0x150 25 #define DENALI_DEVICE_MAIN_AREA_SIZE 0x170 26 #define DENALI_DEVICE_SPARE_AREA_SIZE 0x180 27 #define DENALI_TWO_ROW_ADDR_CYCLES 0x190 28 #define DENALI_INTR_STATUS0 0x410 29 #define DENALI_INTR_ECC_UNCOR_ERR BIT(1) 30 #define DENALI_INTR_DMA_CMD_COMP BIT(2) 31 #define DENALI_INTR_INT_ACT BIT(12) 32 33 #define DENALI_DMA_ENABLE 0x700 34 35 #define DENALI_HOST_ADDR 0x00 36 #define DENALI_HOST_DATA 0x10 37 38 #define DENALI_MAP01 (1 << 26) 39 #define DENALI_MAP10 (2 << 26) 40 #define DENALI_MAP11 (3 << 26) 41 42 #define DENALI_MAP11_CMD ((DENALI_MAP11) | 0) 43 #define DENALI_MAP11_ADDR ((DENALI_MAP11) | 1) 44 #define DENALI_MAP11_DATA ((DENALI_MAP11) | 2) 45 46 #define DENALI_ACCESS_DEFAULT_AREA 0x42 47 48 #define UNIPHIER_NAND_BBT_UNKNOWN 0xff 49 50 struct uniphier_nand { 51 uintptr_t host_base; 52 uintptr_t reg_base; 53 int pages_per_block; 54 int page_size; 55 int two_row_addr_cycles; 56 uint8_t bbt[16]; 57 }; 58 59 struct uniphier_nand uniphier_nand; 60 61 static void uniphier_nand_host_write(struct uniphier_nand *nand, 62 uint32_t addr, uint32_t data) 63 { 64 mmio_write_32(nand->host_base + DENALI_HOST_ADDR, addr); 65 mmio_write_32(nand->host_base + DENALI_HOST_DATA, data); 66 } 67 68 static uint32_t uniphier_nand_host_read(struct uniphier_nand *nand, 69 uint32_t addr) 70 { 71 mmio_write_32(nand->host_base + DENALI_HOST_ADDR, addr); 72 return mmio_read_32(nand->host_base + DENALI_HOST_DATA); 73 } 74 75 static int uniphier_nand_block_isbad(struct uniphier_nand *nand, int block) 76 { 77 int page = nand->pages_per_block * block; 78 int column = nand->page_size; 79 uint8_t bbm; 80 uint32_t status; 81 int is_bad; 82 83 /* use cache if available */ 84 if (block < ARRAY_SIZE(nand->bbt) && 85 nand->bbt[block] != UNIPHIER_NAND_BBT_UNKNOWN) 86 return nand->bbt[block]; 87 88 mmio_write_32(nand->reg_base + DENALI_ECC_ENABLE, 0); 89 90 mmio_write_32(nand->reg_base + DENALI_INTR_STATUS0, -1); 91 92 uniphier_nand_host_write(nand, DENALI_MAP11_CMD, NAND_CMD_READ0); 93 uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, column & 0xff); 94 uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, (column >> 8) & 0xff); 95 uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, page & 0xff); 96 uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, (page >> 8) & 0xff); 97 if (!nand->two_row_addr_cycles) 98 uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, 99 (page >> 16) & 0xff); 100 uniphier_nand_host_write(nand, DENALI_MAP11_CMD, NAND_CMD_READSTART); 101 102 do { 103 status = mmio_read_32(nand->reg_base + DENALI_INTR_STATUS0); 104 } while (!(status & DENALI_INTR_INT_ACT)); 105 106 bbm = uniphier_nand_host_read(nand, DENALI_MAP11_DATA); 107 108 is_bad = bbm != 0xff; 109 110 /* if possible, save the result for future re-use */ 111 if (block < ARRAY_SIZE(nand->bbt)) 112 nand->bbt[block] = is_bad; 113 114 if (is_bad) 115 WARN("found bad block at %d. skip.\n", block); 116 117 return is_bad; 118 } 119 120 static int uniphier_nand_read_pages(struct uniphier_nand *nand, uintptr_t buf, 121 int page_start, int page_count) 122 { 123 uint32_t status; 124 125 mmio_write_32(nand->reg_base + DENALI_ECC_ENABLE, 1); 126 mmio_write_32(nand->reg_base + DENALI_DMA_ENABLE, 1); 127 128 mmio_write_32(nand->reg_base + DENALI_INTR_STATUS0, -1); 129 130 /* use Data DMA (64bit) */ 131 mmio_write_32(nand->host_base + DENALI_HOST_ADDR, 132 DENALI_MAP10 | page_start); 133 134 /* 135 * 1. setup transfer type, interrupt when complete, 136 * burst len = 64 bytes, the number of pages 137 */ 138 mmio_write_32(nand->host_base + DENALI_HOST_DATA, 139 0x01002000 | (64 << 16) | page_count); 140 141 /* 2. set memory low address */ 142 mmio_write_32(nand->host_base + DENALI_HOST_DATA, buf); 143 144 /* 3. set memory high address */ 145 mmio_write_32(nand->host_base + DENALI_HOST_DATA, buf >> 32); 146 147 do { 148 status = mmio_read_32(nand->reg_base + DENALI_INTR_STATUS0); 149 } while (!(status & DENALI_INTR_DMA_CMD_COMP)); 150 151 mmio_write_32(nand->reg_base + DENALI_DMA_ENABLE, 0); 152 153 if (status & DENALI_INTR_ECC_UNCOR_ERR) { 154 ERROR("uncorrectable error in page range %d-%d", 155 page_start, page_start + page_count - 1); 156 return -EBADMSG; 157 } 158 159 return 0; 160 } 161 162 static size_t __uniphier_nand_read(struct uniphier_nand *nand, int lba, 163 uintptr_t buf, size_t size) 164 { 165 int pages_per_block = nand->pages_per_block; 166 int page_size = nand->page_size; 167 int blocks_to_skip = lba / pages_per_block; 168 int pages_to_read = div_round_up(size, page_size); 169 int page = lba % pages_per_block; 170 int block = 0; 171 uintptr_t p = buf; 172 int page_count, ret; 173 174 while (blocks_to_skip) { 175 ret = uniphier_nand_block_isbad(nand, block); 176 if (ret < 0) 177 goto out; 178 179 if (!ret) 180 blocks_to_skip--; 181 182 block++; 183 } 184 185 while (pages_to_read) { 186 ret = uniphier_nand_block_isbad(nand, block); 187 if (ret < 0) 188 goto out; 189 190 if (ret) { 191 block++; 192 continue; 193 } 194 195 page_count = MIN(pages_per_block - page, pages_to_read); 196 197 ret = uniphier_nand_read_pages(nand, p, 198 block * pages_per_block + page, 199 page_count); 200 if (ret) 201 goto out; 202 203 block++; 204 page = 0; 205 p += page_size * page_count; 206 pages_to_read -= page_count; 207 } 208 209 out: 210 /* number of read bytes */ 211 return MIN(size, p - buf); 212 } 213 214 static size_t uniphier_nand_read(int lba, uintptr_t buf, size_t size) 215 { 216 size_t count; 217 218 inv_dcache_range(buf, size); 219 220 count = __uniphier_nand_read(&uniphier_nand, lba, buf, size); 221 222 inv_dcache_range(buf, size); 223 224 return count; 225 } 226 227 static struct io_block_dev_spec uniphier_nand_dev_spec = { 228 .ops = { 229 .read = uniphier_nand_read, 230 }, 231 /* fill .block_size at run-time */ 232 }; 233 234 static int uniphier_nand_hw_init(struct uniphier_nand *nand) 235 { 236 int i; 237 238 for (i = 0; i < ARRAY_SIZE(nand->bbt); i++) 239 nand->bbt[i] = UNIPHIER_NAND_BBT_UNKNOWN; 240 241 nand->reg_base = nand->host_base + 0x100000; 242 243 nand->pages_per_block = 244 mmio_read_32(nand->reg_base + DENALI_PAGES_PER_BLOCK); 245 246 nand->page_size = 247 mmio_read_32(nand->reg_base + DENALI_DEVICE_MAIN_AREA_SIZE); 248 249 if (mmio_read_32(nand->reg_base + DENALI_TWO_ROW_ADDR_CYCLES) & BIT(0)) 250 nand->two_row_addr_cycles = 1; 251 252 uniphier_nand_host_write(nand, DENALI_MAP10, 253 DENALI_ACCESS_DEFAULT_AREA); 254 255 return 0; 256 } 257 258 static const uintptr_t uniphier_nand_base[] = { 259 [UNIPHIER_SOC_LD11] = 0x68000000, 260 [UNIPHIER_SOC_LD20] = 0x68000000, 261 [UNIPHIER_SOC_PXS3] = 0x68000000, 262 }; 263 264 int uniphier_nand_init(unsigned int soc, 265 struct io_block_dev_spec **block_dev_spec) 266 { 267 int ret; 268 269 assert(soc < ARRAY_SIZE(uniphier_nand_base)); 270 uniphier_nand.host_base = uniphier_nand_base[soc]; 271 if (!uniphier_nand.host_base) 272 return -ENOTSUP; 273 274 ret = uniphier_nand_hw_init(&uniphier_nand); 275 if (ret) 276 return ret; 277 278 uniphier_nand_dev_spec.block_size = uniphier_nand.page_size; 279 280 *block_dev_spec = &uniphier_nand_dev_spec; 281 282 return 0; 283 } 284