1a13550d0SLionel Debieve /* 2*6e86b462SYann Gautier * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved 3a13550d0SLionel Debieve * 4a13550d0SLionel Debieve * SPDX-License-Identifier: BSD-3-Clause 5a13550d0SLionel Debieve */ 6a13550d0SLionel Debieve 7a13550d0SLionel Debieve #include <assert.h> 8a13550d0SLionel Debieve #include <errno.h> 9a13550d0SLionel Debieve #include <stddef.h> 10a13550d0SLionel Debieve 11a13550d0SLionel Debieve #include <common/debug.h> 12a13550d0SLionel Debieve #include <drivers/delay_timer.h> 13a13550d0SLionel Debieve #include <drivers/spi_nor.h> 14a13550d0SLionel Debieve #include <lib/utils.h> 15a13550d0SLionel Debieve 16a13550d0SLionel Debieve #define SR_WIP BIT(0) /* Write in progress */ 17a13550d0SLionel Debieve #define CR_QUAD_EN_SPAN BIT(1) /* Spansion Quad I/O */ 18a13550d0SLionel Debieve #define SR_QUAD_EN_MX BIT(6) /* Macronix Quad I/O */ 19a13550d0SLionel Debieve #define FSR_READY BIT(7) /* Device status, 0 = Busy, 1 = Ready */ 20a13550d0SLionel Debieve 21a13550d0SLionel Debieve /* Defined IDs for supported memories */ 22a13550d0SLionel Debieve #define SPANSION_ID 0x01U 23a13550d0SLionel Debieve #define MACRONIX_ID 0xC2U 24a13550d0SLionel Debieve #define MICRON_ID 0x2CU 25a13550d0SLionel Debieve 26a13550d0SLionel Debieve #define BANK_SIZE 0x1000000U 27a13550d0SLionel Debieve 28a13550d0SLionel Debieve #define SPI_READY_TIMEOUT_US 40000U 29a13550d0SLionel Debieve 30a13550d0SLionel Debieve static struct nor_device nor_dev; 31a13550d0SLionel Debieve 32a13550d0SLionel Debieve #pragma weak plat_get_nor_data 33a13550d0SLionel Debieve int plat_get_nor_data(struct nor_device *device) 34a13550d0SLionel Debieve { 35a13550d0SLionel Debieve return 0; 36a13550d0SLionel Debieve } 37a13550d0SLionel Debieve 38a13550d0SLionel Debieve static int spi_nor_reg(uint8_t reg, uint8_t *buf, size_t len, 39a13550d0SLionel Debieve enum spi_mem_data_dir dir) 40a13550d0SLionel Debieve { 41a13550d0SLionel Debieve struct spi_mem_op op; 42a13550d0SLionel Debieve 43a13550d0SLionel Debieve zeromem(&op, sizeof(struct spi_mem_op)); 44a13550d0SLionel Debieve op.cmd.opcode = reg; 45a13550d0SLionel Debieve op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE; 46a13550d0SLionel Debieve op.data.buswidth = SPI_MEM_BUSWIDTH_1_LINE; 47a13550d0SLionel Debieve op.data.dir = dir; 48a13550d0SLionel Debieve op.data.nbytes = len; 49a13550d0SLionel Debieve op.data.buf = buf; 50a13550d0SLionel Debieve 51a13550d0SLionel Debieve return spi_mem_exec_op(&op); 52a13550d0SLionel Debieve } 53a13550d0SLionel Debieve 54a13550d0SLionel Debieve static inline int spi_nor_read_id(uint8_t *id) 55a13550d0SLionel Debieve { 56a13550d0SLionel Debieve return spi_nor_reg(SPI_NOR_OP_READ_ID, id, 1U, SPI_MEM_DATA_IN); 57a13550d0SLionel Debieve } 58a13550d0SLionel Debieve 59a13550d0SLionel Debieve static inline int spi_nor_read_cr(uint8_t *cr) 60a13550d0SLionel Debieve { 61a13550d0SLionel Debieve return spi_nor_reg(SPI_NOR_OP_READ_CR, cr, 1U, SPI_MEM_DATA_IN); 62a13550d0SLionel Debieve } 63a13550d0SLionel Debieve 64a13550d0SLionel Debieve static inline int spi_nor_read_sr(uint8_t *sr) 65a13550d0SLionel Debieve { 66a13550d0SLionel Debieve return spi_nor_reg(SPI_NOR_OP_READ_SR, sr, 1U, SPI_MEM_DATA_IN); 67a13550d0SLionel Debieve } 68a13550d0SLionel Debieve 69a13550d0SLionel Debieve static inline int spi_nor_read_fsr(uint8_t *fsr) 70a13550d0SLionel Debieve { 71a13550d0SLionel Debieve return spi_nor_reg(SPI_NOR_OP_READ_FSR, fsr, 1U, SPI_MEM_DATA_IN); 72a13550d0SLionel Debieve } 73a13550d0SLionel Debieve 74a13550d0SLionel Debieve static inline int spi_nor_write_en(void) 75a13550d0SLionel Debieve { 76a13550d0SLionel Debieve return spi_nor_reg(SPI_NOR_OP_WREN, NULL, 0U, SPI_MEM_DATA_OUT); 77a13550d0SLionel Debieve } 78a13550d0SLionel Debieve 79a13550d0SLionel Debieve /* 80a13550d0SLionel Debieve * Check if device is ready. 81a13550d0SLionel Debieve * 82a13550d0SLionel Debieve * Return 0 if ready, 1 if busy or a negative error code otherwise 83a13550d0SLionel Debieve */ 84a13550d0SLionel Debieve static int spi_nor_ready(void) 85a13550d0SLionel Debieve { 86a13550d0SLionel Debieve uint8_t sr; 87a13550d0SLionel Debieve int ret; 88a13550d0SLionel Debieve 89a13550d0SLionel Debieve ret = spi_nor_read_sr(&sr); 90a13550d0SLionel Debieve if (ret != 0) { 91a13550d0SLionel Debieve return ret; 92a13550d0SLionel Debieve } 93a13550d0SLionel Debieve 94a13550d0SLionel Debieve if ((nor_dev.flags & SPI_NOR_USE_FSR) != 0U) { 95a13550d0SLionel Debieve uint8_t fsr; 96a13550d0SLionel Debieve 97a13550d0SLionel Debieve ret = spi_nor_read_fsr(&fsr); 98a13550d0SLionel Debieve if (ret != 0) { 99a13550d0SLionel Debieve return ret; 100a13550d0SLionel Debieve } 101a13550d0SLionel Debieve 102a13550d0SLionel Debieve return (((fsr & FSR_READY) != 0U) && ((sr & SR_WIP) == 0U)) ? 103a13550d0SLionel Debieve 0 : 1; 104a13550d0SLionel Debieve } 105a13550d0SLionel Debieve 1065130ad14SLionel Debieve return (((sr & SR_WIP) == 0U) ? 0 : 1); 107a13550d0SLionel Debieve } 108a13550d0SLionel Debieve 109a13550d0SLionel Debieve static int spi_nor_wait_ready(void) 110a13550d0SLionel Debieve { 111a13550d0SLionel Debieve int ret; 112a13550d0SLionel Debieve uint64_t timeout = timeout_init_us(SPI_READY_TIMEOUT_US); 113a13550d0SLionel Debieve 114a13550d0SLionel Debieve while (!timeout_elapsed(timeout)) { 115a13550d0SLionel Debieve ret = spi_nor_ready(); 116a13550d0SLionel Debieve if (ret <= 0) { 117a13550d0SLionel Debieve return ret; 118a13550d0SLionel Debieve } 119a13550d0SLionel Debieve } 120a13550d0SLionel Debieve 121a13550d0SLionel Debieve return -ETIMEDOUT; 122a13550d0SLionel Debieve } 123a13550d0SLionel Debieve 124a13550d0SLionel Debieve static int spi_nor_macronix_quad_enable(void) 125a13550d0SLionel Debieve { 126a13550d0SLionel Debieve uint8_t sr; 127a13550d0SLionel Debieve int ret; 128a13550d0SLionel Debieve 129a13550d0SLionel Debieve ret = spi_nor_read_sr(&sr); 130a13550d0SLionel Debieve if (ret != 0) { 131a13550d0SLionel Debieve return ret; 132a13550d0SLionel Debieve } 133a13550d0SLionel Debieve 134c3327408SLionel Debieve if ((sr & SR_QUAD_EN_MX) != 0U) { 135a13550d0SLionel Debieve return 0; 136a13550d0SLionel Debieve } 137a13550d0SLionel Debieve 138a13550d0SLionel Debieve ret = spi_nor_write_en(); 139a13550d0SLionel Debieve if (ret != 0) { 140a13550d0SLionel Debieve return ret; 141a13550d0SLionel Debieve } 142a13550d0SLionel Debieve 143a13550d0SLionel Debieve sr |= SR_QUAD_EN_MX; 1445130ad14SLionel Debieve ret = spi_nor_reg(SPI_NOR_OP_WRSR, &sr, 1U, SPI_MEM_DATA_OUT); 145a13550d0SLionel Debieve if (ret != 0) { 146a13550d0SLionel Debieve return ret; 147a13550d0SLionel Debieve } 148a13550d0SLionel Debieve 149a13550d0SLionel Debieve ret = spi_nor_wait_ready(); 150a13550d0SLionel Debieve if (ret != 0) { 151a13550d0SLionel Debieve return ret; 152a13550d0SLionel Debieve } 153a13550d0SLionel Debieve 154a13550d0SLionel Debieve ret = spi_nor_read_sr(&sr); 155a13550d0SLionel Debieve if ((ret != 0) || ((sr & SR_QUAD_EN_MX) == 0U)) { 156a13550d0SLionel Debieve return -EINVAL; 157a13550d0SLionel Debieve } 158a13550d0SLionel Debieve 159a13550d0SLionel Debieve return 0; 160a13550d0SLionel Debieve } 161a13550d0SLionel Debieve 162a13550d0SLionel Debieve static int spi_nor_write_sr_cr(uint8_t *sr_cr) 163a13550d0SLionel Debieve { 164a13550d0SLionel Debieve int ret; 165a13550d0SLionel Debieve 166a13550d0SLionel Debieve ret = spi_nor_write_en(); 167a13550d0SLionel Debieve if (ret != 0) { 168a13550d0SLionel Debieve return ret; 169a13550d0SLionel Debieve } 170a13550d0SLionel Debieve 1715130ad14SLionel Debieve ret = spi_nor_reg(SPI_NOR_OP_WRSR, sr_cr, 2U, SPI_MEM_DATA_OUT); 172a13550d0SLionel Debieve if (ret != 0) { 173a13550d0SLionel Debieve return -EINVAL; 174a13550d0SLionel Debieve } 175a13550d0SLionel Debieve 176a13550d0SLionel Debieve ret = spi_nor_wait_ready(); 177a13550d0SLionel Debieve if (ret != 0) { 178a13550d0SLionel Debieve return ret; 179a13550d0SLionel Debieve } 180a13550d0SLionel Debieve 181a13550d0SLionel Debieve return 0; 182a13550d0SLionel Debieve } 183a13550d0SLionel Debieve 184a13550d0SLionel Debieve static int spi_nor_quad_enable(void) 185a13550d0SLionel Debieve { 186a13550d0SLionel Debieve uint8_t sr_cr[2]; 187a13550d0SLionel Debieve int ret; 188a13550d0SLionel Debieve 189a13550d0SLionel Debieve ret = spi_nor_read_cr(&sr_cr[1]); 190a13550d0SLionel Debieve if (ret != 0) { 191a13550d0SLionel Debieve return ret; 192a13550d0SLionel Debieve } 193a13550d0SLionel Debieve 194a13550d0SLionel Debieve if ((sr_cr[1] & CR_QUAD_EN_SPAN) != 0U) { 195a13550d0SLionel Debieve return 0; 196a13550d0SLionel Debieve } 197a13550d0SLionel Debieve 198a13550d0SLionel Debieve sr_cr[1] |= CR_QUAD_EN_SPAN; 199a13550d0SLionel Debieve ret = spi_nor_read_sr(&sr_cr[0]); 200a13550d0SLionel Debieve if (ret != 0) { 201a13550d0SLionel Debieve return ret; 202a13550d0SLionel Debieve } 203a13550d0SLionel Debieve 204a13550d0SLionel Debieve ret = spi_nor_write_sr_cr(sr_cr); 205a13550d0SLionel Debieve if (ret != 0) { 206a13550d0SLionel Debieve return ret; 207a13550d0SLionel Debieve } 208a13550d0SLionel Debieve 209a13550d0SLionel Debieve ret = spi_nor_read_cr(&sr_cr[1]); 210a13550d0SLionel Debieve if ((ret != 0) || ((sr_cr[1] & CR_QUAD_EN_SPAN) == 0U)) { 211a13550d0SLionel Debieve return -EINVAL; 212a13550d0SLionel Debieve } 213a13550d0SLionel Debieve 214a13550d0SLionel Debieve return 0; 215a13550d0SLionel Debieve } 216a13550d0SLionel Debieve 217a13550d0SLionel Debieve static int spi_nor_clean_bar(void) 218a13550d0SLionel Debieve { 219a13550d0SLionel Debieve int ret; 220a13550d0SLionel Debieve 221a13550d0SLionel Debieve if (nor_dev.selected_bank == 0U) { 222a13550d0SLionel Debieve return 0; 223a13550d0SLionel Debieve } 224a13550d0SLionel Debieve 225a13550d0SLionel Debieve nor_dev.selected_bank = 0U; 226a13550d0SLionel Debieve 227a13550d0SLionel Debieve ret = spi_nor_write_en(); 228a13550d0SLionel Debieve if (ret != 0) { 229a13550d0SLionel Debieve return ret; 230a13550d0SLionel Debieve } 231a13550d0SLionel Debieve 232a13550d0SLionel Debieve return spi_nor_reg(nor_dev.bank_write_cmd, &nor_dev.selected_bank, 2335130ad14SLionel Debieve 1U, SPI_MEM_DATA_OUT); 234a13550d0SLionel Debieve } 235a13550d0SLionel Debieve 236a13550d0SLionel Debieve static int spi_nor_write_bar(uint32_t offset) 237a13550d0SLionel Debieve { 238a13550d0SLionel Debieve uint8_t selected_bank = offset / BANK_SIZE; 239a13550d0SLionel Debieve int ret; 240a13550d0SLionel Debieve 241a13550d0SLionel Debieve if (selected_bank == nor_dev.selected_bank) { 242a13550d0SLionel Debieve return 0; 243a13550d0SLionel Debieve } 244a13550d0SLionel Debieve 245a13550d0SLionel Debieve ret = spi_nor_write_en(); 246a13550d0SLionel Debieve if (ret != 0) { 247a13550d0SLionel Debieve return ret; 248a13550d0SLionel Debieve } 249a13550d0SLionel Debieve 250a13550d0SLionel Debieve ret = spi_nor_reg(nor_dev.bank_write_cmd, &selected_bank, 2515130ad14SLionel Debieve 1U, SPI_MEM_DATA_OUT); 252a13550d0SLionel Debieve if (ret != 0) { 253a13550d0SLionel Debieve return ret; 254a13550d0SLionel Debieve } 255a13550d0SLionel Debieve 256a13550d0SLionel Debieve nor_dev.selected_bank = selected_bank; 257a13550d0SLionel Debieve 258a13550d0SLionel Debieve return 0; 259a13550d0SLionel Debieve } 260a13550d0SLionel Debieve 261a13550d0SLionel Debieve static int spi_nor_read_bar(void) 262a13550d0SLionel Debieve { 2635130ad14SLionel Debieve uint8_t selected_bank = 0U; 264a13550d0SLionel Debieve int ret; 265a13550d0SLionel Debieve 266a13550d0SLionel Debieve ret = spi_nor_reg(nor_dev.bank_read_cmd, &selected_bank, 2675130ad14SLionel Debieve 1U, SPI_MEM_DATA_IN); 268a13550d0SLionel Debieve if (ret != 0) { 269a13550d0SLionel Debieve return ret; 270a13550d0SLionel Debieve } 271a13550d0SLionel Debieve 272a13550d0SLionel Debieve nor_dev.selected_bank = selected_bank; 273a13550d0SLionel Debieve 274a13550d0SLionel Debieve return 0; 275a13550d0SLionel Debieve } 276a13550d0SLionel Debieve 277a13550d0SLionel Debieve int spi_nor_read(unsigned int offset, uintptr_t buffer, size_t length, 278a13550d0SLionel Debieve size_t *length_read) 279a13550d0SLionel Debieve { 280a13550d0SLionel Debieve size_t remain_len; 281a13550d0SLionel Debieve int ret; 282a13550d0SLionel Debieve 2835130ad14SLionel Debieve *length_read = 0U; 284a13550d0SLionel Debieve nor_dev.read_op.addr.val = offset; 285a13550d0SLionel Debieve nor_dev.read_op.data.buf = (void *)buffer; 286a13550d0SLionel Debieve 287*6e86b462SYann Gautier VERBOSE("%s offset %u length %zu\n", __func__, offset, length); 288a13550d0SLionel Debieve 289a13550d0SLionel Debieve while (length != 0U) { 290a13550d0SLionel Debieve if ((nor_dev.flags & SPI_NOR_USE_BANK) != 0U) { 291a13550d0SLionel Debieve ret = spi_nor_write_bar(nor_dev.read_op.addr.val); 292a13550d0SLionel Debieve if (ret != 0) { 293a13550d0SLionel Debieve return ret; 294a13550d0SLionel Debieve } 295a13550d0SLionel Debieve 296a13550d0SLionel Debieve remain_len = (BANK_SIZE * (nor_dev.selected_bank + 1)) - 297a13550d0SLionel Debieve nor_dev.read_op.addr.val; 298a13550d0SLionel Debieve nor_dev.read_op.data.nbytes = MIN(length, remain_len); 299a13550d0SLionel Debieve } else { 300a13550d0SLionel Debieve nor_dev.read_op.data.nbytes = length; 301a13550d0SLionel Debieve } 302a13550d0SLionel Debieve 303a13550d0SLionel Debieve ret = spi_mem_exec_op(&nor_dev.read_op); 304a13550d0SLionel Debieve if (ret != 0) { 305a13550d0SLionel Debieve spi_nor_clean_bar(); 306a13550d0SLionel Debieve return ret; 307a13550d0SLionel Debieve } 308a13550d0SLionel Debieve 309a13550d0SLionel Debieve length -= nor_dev.read_op.data.nbytes; 310a13550d0SLionel Debieve nor_dev.read_op.addr.val += nor_dev.read_op.data.nbytes; 311a13550d0SLionel Debieve nor_dev.read_op.data.buf += nor_dev.read_op.data.nbytes; 312a13550d0SLionel Debieve *length_read += nor_dev.read_op.data.nbytes; 313a13550d0SLionel Debieve } 314a13550d0SLionel Debieve 315a13550d0SLionel Debieve if ((nor_dev.flags & SPI_NOR_USE_BANK) != 0U) { 316a13550d0SLionel Debieve ret = spi_nor_clean_bar(); 317a13550d0SLionel Debieve if (ret != 0) { 318a13550d0SLionel Debieve return ret; 319a13550d0SLionel Debieve } 320a13550d0SLionel Debieve } 321a13550d0SLionel Debieve 322a13550d0SLionel Debieve return 0; 323a13550d0SLionel Debieve } 324a13550d0SLionel Debieve 325a13550d0SLionel Debieve int spi_nor_init(unsigned long long *size, unsigned int *erase_size) 326a13550d0SLionel Debieve { 3275130ad14SLionel Debieve int ret; 328a13550d0SLionel Debieve uint8_t id; 329a13550d0SLionel Debieve 330a13550d0SLionel Debieve /* Default read command used */ 331a13550d0SLionel Debieve nor_dev.read_op.cmd.opcode = SPI_NOR_OP_READ; 332a13550d0SLionel Debieve nor_dev.read_op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE; 333a13550d0SLionel Debieve nor_dev.read_op.addr.nbytes = 3U; 334a13550d0SLionel Debieve nor_dev.read_op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE; 335a13550d0SLionel Debieve nor_dev.read_op.data.buswidth = SPI_MEM_BUSWIDTH_1_LINE; 336a13550d0SLionel Debieve nor_dev.read_op.data.dir = SPI_MEM_DATA_IN; 337a13550d0SLionel Debieve 338a13550d0SLionel Debieve if (plat_get_nor_data(&nor_dev) != 0) { 339a13550d0SLionel Debieve return -EINVAL; 340a13550d0SLionel Debieve } 341a13550d0SLionel Debieve 3425130ad14SLionel Debieve assert(nor_dev.size != 0U); 343a13550d0SLionel Debieve 344a13550d0SLionel Debieve if (nor_dev.size > BANK_SIZE) { 345a13550d0SLionel Debieve nor_dev.flags |= SPI_NOR_USE_BANK; 346a13550d0SLionel Debieve } 347a13550d0SLionel Debieve 348a13550d0SLionel Debieve *size = nor_dev.size; 349a13550d0SLionel Debieve 350a13550d0SLionel Debieve ret = spi_nor_read_id(&id); 351a13550d0SLionel Debieve if (ret != 0) { 352a13550d0SLionel Debieve return ret; 353a13550d0SLionel Debieve } 354a13550d0SLionel Debieve 355a13550d0SLionel Debieve if ((nor_dev.flags & SPI_NOR_USE_BANK) != 0U) { 356a13550d0SLionel Debieve switch (id) { 357a13550d0SLionel Debieve case SPANSION_ID: 358a13550d0SLionel Debieve nor_dev.bank_read_cmd = SPINOR_OP_BRRD; 359a13550d0SLionel Debieve nor_dev.bank_write_cmd = SPINOR_OP_BRWR; 360a13550d0SLionel Debieve break; 361a13550d0SLionel Debieve default: 362a13550d0SLionel Debieve nor_dev.bank_read_cmd = SPINOR_OP_RDEAR; 363a13550d0SLionel Debieve nor_dev.bank_write_cmd = SPINOR_OP_WREAR; 364a13550d0SLionel Debieve break; 365a13550d0SLionel Debieve } 366a13550d0SLionel Debieve } 367a13550d0SLionel Debieve 368a13550d0SLionel Debieve if (nor_dev.read_op.data.buswidth == 4U) { 369a13550d0SLionel Debieve switch (id) { 370a13550d0SLionel Debieve case MACRONIX_ID: 3716751b836SLionel Debieve INFO("Enable Macronix quad support\n"); 372a13550d0SLionel Debieve ret = spi_nor_macronix_quad_enable(); 373a13550d0SLionel Debieve break; 374a13550d0SLionel Debieve case MICRON_ID: 375a13550d0SLionel Debieve break; 376a13550d0SLionel Debieve default: 377a13550d0SLionel Debieve ret = spi_nor_quad_enable(); 378a13550d0SLionel Debieve break; 379a13550d0SLionel Debieve } 380a13550d0SLionel Debieve } 381a13550d0SLionel Debieve 382a13550d0SLionel Debieve if ((ret == 0) && ((nor_dev.flags & SPI_NOR_USE_BANK) != 0U)) { 383a13550d0SLionel Debieve ret = spi_nor_read_bar(); 384a13550d0SLionel Debieve } 385a13550d0SLionel Debieve 386a13550d0SLionel Debieve return ret; 387a13550d0SLionel Debieve } 388