1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2019-2020, Broadcom 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <stdbool.h> 8*91f16700Schasinglulu #include <stddef.h> 9*91f16700Schasinglulu #include <stdint.h> 10*91f16700Schasinglulu 11*91f16700Schasinglulu #include <common/debug.h> 12*91f16700Schasinglulu #include <drivers/delay_timer.h> 13*91f16700Schasinglulu #include <errno.h> 14*91f16700Schasinglulu 15*91f16700Schasinglulu #include <sf.h> 16*91f16700Schasinglulu #include <spi.h> 17*91f16700Schasinglulu 18*91f16700Schasinglulu #define SPI_FLASH_CMD_LEN 4 19*91f16700Schasinglulu #define QSPI_WAIT_TIMEOUT_US 200000U /* usec */ 20*91f16700Schasinglulu 21*91f16700Schasinglulu #define FINFO(jedec_id, ext_id, _sector_size, _n_sectors, _page_size, _flags) \ 22*91f16700Schasinglulu .id = { \ 23*91f16700Schasinglulu ((jedec_id) >> 16) & 0xff, \ 24*91f16700Schasinglulu ((jedec_id) >> 8) & 0xff, \ 25*91f16700Schasinglulu (jedec_id) & 0xff, \ 26*91f16700Schasinglulu ((ext_id) >> 8) & 0xff, \ 27*91f16700Schasinglulu (ext_id) & 0xff, \ 28*91f16700Schasinglulu }, \ 29*91f16700Schasinglulu .id_len = (!(jedec_id) ? 0 : (3 + ((ext_id) ? 2 : 0))), \ 30*91f16700Schasinglulu .sector_size = (_sector_size), \ 31*91f16700Schasinglulu .n_sectors = (_n_sectors), \ 32*91f16700Schasinglulu .page_size = _page_size, \ 33*91f16700Schasinglulu .flags = (_flags), 34*91f16700Schasinglulu 35*91f16700Schasinglulu /* SPI/QSPI flash device params structure */ 36*91f16700Schasinglulu const struct spi_flash_info spi_flash_ids[] = { 37*91f16700Schasinglulu {"W25Q64CV", FINFO(0xef4017, 0x0, 64 * 1024, 128, 256, WR_QPP | SECT_4K)}, 38*91f16700Schasinglulu {"W25Q64DW", FINFO(0xef6017, 0x0, 64 * 1024, 128, 256, WR_QPP | SECT_4K)}, 39*91f16700Schasinglulu {"W25Q32", FINFO(0xef4016, 0x0, 64 * 1024, 64, 256, SECT_4K)}, 40*91f16700Schasinglulu {"MX25l3205D", FINFO(0xc22016, 0x0, 64 * 1024, 64, 256, SECT_4K)}, 41*91f16700Schasinglulu }; 42*91f16700Schasinglulu 43*91f16700Schasinglulu static void spi_flash_addr(uint32_t addr, uint8_t *cmd) 44*91f16700Schasinglulu { 45*91f16700Schasinglulu /* 46*91f16700Schasinglulu * cmd[0] holds a SPI Flash command, stored earlier 47*91f16700Schasinglulu * cmd[1/2/3] holds 24bit flash address 48*91f16700Schasinglulu */ 49*91f16700Schasinglulu cmd[1] = addr >> 16; 50*91f16700Schasinglulu cmd[2] = addr >> 8; 51*91f16700Schasinglulu cmd[3] = addr >> 0; 52*91f16700Schasinglulu } 53*91f16700Schasinglulu 54*91f16700Schasinglulu static const struct spi_flash_info *spi_flash_read_id(void) 55*91f16700Schasinglulu { 56*91f16700Schasinglulu const struct spi_flash_info *info; 57*91f16700Schasinglulu uint8_t id[SPI_FLASH_MAX_ID_LEN]; 58*91f16700Schasinglulu int ret; 59*91f16700Schasinglulu 60*91f16700Schasinglulu ret = spi_flash_cmd(CMD_READ_ID, id, SPI_FLASH_MAX_ID_LEN); 61*91f16700Schasinglulu if (ret < 0) { 62*91f16700Schasinglulu ERROR("SF: Error %d reading JEDEC ID\n", ret); 63*91f16700Schasinglulu return NULL; 64*91f16700Schasinglulu } 65*91f16700Schasinglulu 66*91f16700Schasinglulu for (info = spi_flash_ids; info->name != NULL; info++) { 67*91f16700Schasinglulu if (info->id_len) { 68*91f16700Schasinglulu if (!memcmp(info->id, id, info->id_len)) 69*91f16700Schasinglulu return info; 70*91f16700Schasinglulu } 71*91f16700Schasinglulu } 72*91f16700Schasinglulu 73*91f16700Schasinglulu printf("SF: unrecognized JEDEC id bytes: %02x, %02x, %02x\n", 74*91f16700Schasinglulu id[0], id[1], id[2]); 75*91f16700Schasinglulu return NULL; 76*91f16700Schasinglulu } 77*91f16700Schasinglulu 78*91f16700Schasinglulu /* Enable writing on the SPI flash */ 79*91f16700Schasinglulu static inline int spi_flash_cmd_write_enable(struct spi_flash *flash) 80*91f16700Schasinglulu { 81*91f16700Schasinglulu return spi_flash_cmd(CMD_WRITE_ENABLE, NULL, 0); 82*91f16700Schasinglulu } 83*91f16700Schasinglulu 84*91f16700Schasinglulu static int spi_flash_cmd_wait(struct spi_flash *flash) 85*91f16700Schasinglulu { 86*91f16700Schasinglulu uint8_t cmd; 87*91f16700Schasinglulu uint32_t i; 88*91f16700Schasinglulu uint8_t status; 89*91f16700Schasinglulu int ret; 90*91f16700Schasinglulu 91*91f16700Schasinglulu i = 0; 92*91f16700Schasinglulu while (1) { 93*91f16700Schasinglulu cmd = CMD_RDSR; 94*91f16700Schasinglulu ret = spi_flash_cmd_read(&cmd, 1, &status, 1); 95*91f16700Schasinglulu if (ret < 0) { 96*91f16700Schasinglulu ERROR("SF: cmd wait failed\n"); 97*91f16700Schasinglulu break; 98*91f16700Schasinglulu } 99*91f16700Schasinglulu if (!(status & STATUS_WIP)) 100*91f16700Schasinglulu break; 101*91f16700Schasinglulu 102*91f16700Schasinglulu i++; 103*91f16700Schasinglulu if (i >= QSPI_WAIT_TIMEOUT_US) { 104*91f16700Schasinglulu ERROR("SF: cmd wait timeout\n"); 105*91f16700Schasinglulu ret = -1; 106*91f16700Schasinglulu break; 107*91f16700Schasinglulu } 108*91f16700Schasinglulu udelay(1); 109*91f16700Schasinglulu } 110*91f16700Schasinglulu 111*91f16700Schasinglulu return ret; 112*91f16700Schasinglulu } 113*91f16700Schasinglulu 114*91f16700Schasinglulu static int spi_flash_write_common(struct spi_flash *flash, const uint8_t *cmd, 115*91f16700Schasinglulu size_t cmd_len, const void *buf, 116*91f16700Schasinglulu size_t buf_len) 117*91f16700Schasinglulu { 118*91f16700Schasinglulu int ret; 119*91f16700Schasinglulu 120*91f16700Schasinglulu ret = spi_flash_cmd_write_enable(flash); 121*91f16700Schasinglulu if (ret < 0) { 122*91f16700Schasinglulu ERROR("SF: enabling write failed\n"); 123*91f16700Schasinglulu return ret; 124*91f16700Schasinglulu } 125*91f16700Schasinglulu 126*91f16700Schasinglulu ret = spi_flash_cmd_write(cmd, cmd_len, buf, buf_len); 127*91f16700Schasinglulu if (ret < 0) { 128*91f16700Schasinglulu ERROR("SF: write cmd failed\n"); 129*91f16700Schasinglulu return ret; 130*91f16700Schasinglulu } 131*91f16700Schasinglulu 132*91f16700Schasinglulu ret = spi_flash_cmd_wait(flash); 133*91f16700Schasinglulu if (ret < 0) { 134*91f16700Schasinglulu ERROR("SF: write timed out\n"); 135*91f16700Schasinglulu return ret; 136*91f16700Schasinglulu } 137*91f16700Schasinglulu 138*91f16700Schasinglulu return ret; 139*91f16700Schasinglulu } 140*91f16700Schasinglulu 141*91f16700Schasinglulu static int spi_flash_read_common(const uint8_t *cmd, size_t cmd_len, 142*91f16700Schasinglulu void *data, size_t data_len) 143*91f16700Schasinglulu { 144*91f16700Schasinglulu int ret; 145*91f16700Schasinglulu 146*91f16700Schasinglulu ret = spi_flash_cmd_read(cmd, cmd_len, data, data_len); 147*91f16700Schasinglulu if (ret < 0) { 148*91f16700Schasinglulu ERROR("SF: read cmd failed\n"); 149*91f16700Schasinglulu return ret; 150*91f16700Schasinglulu } 151*91f16700Schasinglulu 152*91f16700Schasinglulu return ret; 153*91f16700Schasinglulu } 154*91f16700Schasinglulu 155*91f16700Schasinglulu int spi_flash_read(struct spi_flash *flash, uint32_t offset, 156*91f16700Schasinglulu uint32_t len, void *data) 157*91f16700Schasinglulu { 158*91f16700Schasinglulu uint32_t read_len = 0, read_addr; 159*91f16700Schasinglulu uint8_t cmd[SPI_FLASH_CMD_LEN]; 160*91f16700Schasinglulu int ret; 161*91f16700Schasinglulu 162*91f16700Schasinglulu ret = spi_claim_bus(); 163*91f16700Schasinglulu if (ret) { 164*91f16700Schasinglulu ERROR("SF: unable to claim SPI bus\n"); 165*91f16700Schasinglulu return ret; 166*91f16700Schasinglulu } 167*91f16700Schasinglulu 168*91f16700Schasinglulu cmd[0] = CMD_READ_NORMAL; 169*91f16700Schasinglulu while (len) { 170*91f16700Schasinglulu read_addr = offset; 171*91f16700Schasinglulu read_len = MIN(flash->page_size, (len - read_len)); 172*91f16700Schasinglulu spi_flash_addr(read_addr, cmd); 173*91f16700Schasinglulu 174*91f16700Schasinglulu ret = spi_flash_read_common(cmd, sizeof(cmd), data, read_len); 175*91f16700Schasinglulu if (ret < 0) { 176*91f16700Schasinglulu ERROR("SF: read failed\n"); 177*91f16700Schasinglulu break; 178*91f16700Schasinglulu } 179*91f16700Schasinglulu 180*91f16700Schasinglulu offset += read_len; 181*91f16700Schasinglulu len -= read_len; 182*91f16700Schasinglulu data += read_len; 183*91f16700Schasinglulu } 184*91f16700Schasinglulu SPI_DEBUG("SF read done\n"); 185*91f16700Schasinglulu 186*91f16700Schasinglulu spi_release_bus(); 187*91f16700Schasinglulu return ret; 188*91f16700Schasinglulu } 189*91f16700Schasinglulu 190*91f16700Schasinglulu int spi_flash_write(struct spi_flash *flash, uint32_t offset, 191*91f16700Schasinglulu uint32_t len, void *buf) 192*91f16700Schasinglulu { 193*91f16700Schasinglulu unsigned long byte_addr, page_size; 194*91f16700Schasinglulu uint8_t cmd[SPI_FLASH_CMD_LEN]; 195*91f16700Schasinglulu uint32_t chunk_len, actual; 196*91f16700Schasinglulu uint32_t write_addr; 197*91f16700Schasinglulu int ret; 198*91f16700Schasinglulu 199*91f16700Schasinglulu ret = spi_claim_bus(); 200*91f16700Schasinglulu if (ret) { 201*91f16700Schasinglulu ERROR("SF: unable to claim SPI bus\n"); 202*91f16700Schasinglulu return ret; 203*91f16700Schasinglulu } 204*91f16700Schasinglulu 205*91f16700Schasinglulu page_size = flash->page_size; 206*91f16700Schasinglulu 207*91f16700Schasinglulu cmd[0] = flash->write_cmd; 208*91f16700Schasinglulu for (actual = 0; actual < len; actual += chunk_len) { 209*91f16700Schasinglulu write_addr = offset; 210*91f16700Schasinglulu byte_addr = offset % page_size; 211*91f16700Schasinglulu chunk_len = MIN(len - actual, 212*91f16700Schasinglulu (uint32_t)(page_size - byte_addr)); 213*91f16700Schasinglulu spi_flash_addr(write_addr, cmd); 214*91f16700Schasinglulu 215*91f16700Schasinglulu SPI_DEBUG("SF:0x%p=>cmd:{0x%02x 0x%02x%02x%02x} chunk_len:%d\n", 216*91f16700Schasinglulu buf + actual, cmd[0], cmd[1], 217*91f16700Schasinglulu cmd[2], cmd[3], chunk_len); 218*91f16700Schasinglulu 219*91f16700Schasinglulu ret = spi_flash_write_common(flash, cmd, sizeof(cmd), 220*91f16700Schasinglulu buf + actual, chunk_len); 221*91f16700Schasinglulu if (ret < 0) { 222*91f16700Schasinglulu ERROR("SF: write cmd failed\n"); 223*91f16700Schasinglulu break; 224*91f16700Schasinglulu } 225*91f16700Schasinglulu 226*91f16700Schasinglulu offset += chunk_len; 227*91f16700Schasinglulu } 228*91f16700Schasinglulu SPI_DEBUG("SF write done\n"); 229*91f16700Schasinglulu 230*91f16700Schasinglulu spi_release_bus(); 231*91f16700Schasinglulu return ret; 232*91f16700Schasinglulu } 233*91f16700Schasinglulu 234*91f16700Schasinglulu int spi_flash_erase(struct spi_flash *flash, uint32_t offset, uint32_t len) 235*91f16700Schasinglulu { 236*91f16700Schasinglulu uint8_t cmd[SPI_FLASH_CMD_LEN]; 237*91f16700Schasinglulu uint32_t erase_size, erase_addr; 238*91f16700Schasinglulu int ret; 239*91f16700Schasinglulu 240*91f16700Schasinglulu erase_size = flash->erase_size; 241*91f16700Schasinglulu 242*91f16700Schasinglulu if (offset % erase_size || len % erase_size) { 243*91f16700Schasinglulu ERROR("SF: Erase offset/length not multiple of erase size\n"); 244*91f16700Schasinglulu return -1; 245*91f16700Schasinglulu } 246*91f16700Schasinglulu 247*91f16700Schasinglulu ret = spi_claim_bus(); 248*91f16700Schasinglulu if (ret) { 249*91f16700Schasinglulu ERROR("SF: unable to claim SPI bus\n"); 250*91f16700Schasinglulu return ret; 251*91f16700Schasinglulu } 252*91f16700Schasinglulu 253*91f16700Schasinglulu cmd[0] = flash->erase_cmd; 254*91f16700Schasinglulu while (len) { 255*91f16700Schasinglulu erase_addr = offset; 256*91f16700Schasinglulu spi_flash_addr(erase_addr, cmd); 257*91f16700Schasinglulu 258*91f16700Schasinglulu SPI_DEBUG("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], 259*91f16700Schasinglulu cmd[2], cmd[3], erase_addr); 260*91f16700Schasinglulu 261*91f16700Schasinglulu ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0); 262*91f16700Schasinglulu if (ret < 0) { 263*91f16700Schasinglulu ERROR("SF: erase failed\n"); 264*91f16700Schasinglulu break; 265*91f16700Schasinglulu } 266*91f16700Schasinglulu 267*91f16700Schasinglulu offset += erase_size; 268*91f16700Schasinglulu len -= erase_size; 269*91f16700Schasinglulu } 270*91f16700Schasinglulu SPI_DEBUG("sf erase done\n"); 271*91f16700Schasinglulu 272*91f16700Schasinglulu spi_release_bus(); 273*91f16700Schasinglulu return ret; 274*91f16700Schasinglulu } 275*91f16700Schasinglulu 276*91f16700Schasinglulu int spi_flash_probe(struct spi_flash *flash) 277*91f16700Schasinglulu { 278*91f16700Schasinglulu const struct spi_flash_info *info = NULL; 279*91f16700Schasinglulu int ret; 280*91f16700Schasinglulu 281*91f16700Schasinglulu ret = spi_claim_bus(); 282*91f16700Schasinglulu if (ret) { 283*91f16700Schasinglulu ERROR("SF: Unable to claim SPI bus\n"); 284*91f16700Schasinglulu ERROR("SF: probe failed\n"); 285*91f16700Schasinglulu return ret; 286*91f16700Schasinglulu } 287*91f16700Schasinglulu 288*91f16700Schasinglulu info = spi_flash_read_id(); 289*91f16700Schasinglulu if (!info) 290*91f16700Schasinglulu goto probe_fail; 291*91f16700Schasinglulu 292*91f16700Schasinglulu INFO("Flash Name: %s sectors %x, sec size %x\n", 293*91f16700Schasinglulu info->name, info->n_sectors, 294*91f16700Schasinglulu info->sector_size); 295*91f16700Schasinglulu flash->size = info->n_sectors * info->sector_size; 296*91f16700Schasinglulu flash->sector_size = info->sector_size; 297*91f16700Schasinglulu flash->page_size = info->page_size; 298*91f16700Schasinglulu flash->flags = info->flags; 299*91f16700Schasinglulu 300*91f16700Schasinglulu flash->read_cmd = CMD_READ_NORMAL; 301*91f16700Schasinglulu flash->write_cmd = CMD_PAGE_PROGRAM; 302*91f16700Schasinglulu flash->erase_cmd = CMD_ERASE_64K; 303*91f16700Schasinglulu flash->erase_size = ERASE_SIZE_64K; 304*91f16700Schasinglulu 305*91f16700Schasinglulu probe_fail: 306*91f16700Schasinglulu spi_release_bus(); 307*91f16700Schasinglulu return ret; 308*91f16700Schasinglulu } 309