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