1898e76c9SJagannadha Sutradharudu Teki /* 2898e76c9SJagannadha Sutradharudu Teki * SPI flash probing 3898e76c9SJagannadha Sutradharudu Teki * 4898e76c9SJagannadha Sutradharudu Teki * Copyright (C) 2008 Atmel Corporation 5898e76c9SJagannadha Sutradharudu Teki * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik 6898e76c9SJagannadha Sutradharudu Teki * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. 7898e76c9SJagannadha Sutradharudu Teki * 80c88a84aSJagannadha Sutradharudu Teki * SPDX-License-Identifier: GPL-2.0+ 9898e76c9SJagannadha Sutradharudu Teki */ 10898e76c9SJagannadha Sutradharudu Teki 11898e76c9SJagannadha Sutradharudu Teki #include <common.h> 12fbb09918SSimon Glass #include <dm.h> 13ae242cbfSSimon Glass #include <errno.h> 14898e76c9SJagannadha Sutradharudu Teki #include <fdtdec.h> 15898e76c9SJagannadha Sutradharudu Teki #include <malloc.h> 160eb25b61SJoe Hershberger #include <mapmem.h> 17898e76c9SJagannadha Sutradharudu Teki #include <spi.h> 18898e76c9SJagannadha Sutradharudu Teki #include <spi_flash.h> 19ffdb20beSMike Frysinger #include <asm/io.h> 20898e76c9SJagannadha Sutradharudu Teki 21898e76c9SJagannadha Sutradharudu Teki #include "sf_internal.h" 22898e76c9SJagannadha Sutradharudu Teki 23898e76c9SJagannadha Sutradharudu Teki DECLARE_GLOBAL_DATA_PTR; 24898e76c9SJagannadha Sutradharudu Teki 254e09cc1eSJagannadha Sutradharudu Teki /* Read commands array */ 264e09cc1eSJagannadha Sutradharudu Teki static u8 spi_read_cmds_array[] = { 274e09cc1eSJagannadha Sutradharudu Teki CMD_READ_ARRAY_SLOW, 286dd6e90eSJagannadha Sutradharudu Teki CMD_READ_ARRAY_FAST, 294e09cc1eSJagannadha Sutradharudu Teki CMD_READ_DUAL_OUTPUT_FAST, 304e09cc1eSJagannadha Sutradharudu Teki CMD_READ_DUAL_IO_FAST, 313163aaa6SJagannadha Sutradharudu Teki CMD_READ_QUAD_OUTPUT_FAST, 32c4ba0d82SJagannadha Sutradharudu Teki CMD_READ_QUAD_IO_FAST, 334e09cc1eSJagannadha Sutradharudu Teki }; 344e09cc1eSJagannadha Sutradharudu Teki 359f4322fdSJagannadha Sutradharudu Teki #ifdef CONFIG_SPI_FLASH_MACRONIX 369f4322fdSJagannadha Sutradharudu Teki static int spi_flash_set_qeb_mxic(struct spi_flash *flash) 379f4322fdSJagannadha Sutradharudu Teki { 389f4322fdSJagannadha Sutradharudu Teki u8 qeb_status; 399f4322fdSJagannadha Sutradharudu Teki int ret; 409f4322fdSJagannadha Sutradharudu Teki 419f4322fdSJagannadha Sutradharudu Teki ret = spi_flash_cmd_read_status(flash, &qeb_status); 429f4322fdSJagannadha Sutradharudu Teki if (ret < 0) 439f4322fdSJagannadha Sutradharudu Teki return ret; 449f4322fdSJagannadha Sutradharudu Teki 459f4322fdSJagannadha Sutradharudu Teki if (qeb_status & STATUS_QEB_MXIC) { 469f4322fdSJagannadha Sutradharudu Teki debug("SF: mxic: QEB is already set\n"); 479f4322fdSJagannadha Sutradharudu Teki } else { 489f4322fdSJagannadha Sutradharudu Teki ret = spi_flash_cmd_write_status(flash, STATUS_QEB_MXIC); 499f4322fdSJagannadha Sutradharudu Teki if (ret < 0) 509f4322fdSJagannadha Sutradharudu Teki return ret; 519f4322fdSJagannadha Sutradharudu Teki } 529f4322fdSJagannadha Sutradharudu Teki 539f4322fdSJagannadha Sutradharudu Teki return ret; 549f4322fdSJagannadha Sutradharudu Teki } 559f4322fdSJagannadha Sutradharudu Teki #endif 569f4322fdSJagannadha Sutradharudu Teki 579f4322fdSJagannadha Sutradharudu Teki #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) 589f4322fdSJagannadha Sutradharudu Teki static int spi_flash_set_qeb_winspan(struct spi_flash *flash) 599f4322fdSJagannadha Sutradharudu Teki { 609f4322fdSJagannadha Sutradharudu Teki u8 qeb_status; 619f4322fdSJagannadha Sutradharudu Teki int ret; 629f4322fdSJagannadha Sutradharudu Teki 639f4322fdSJagannadha Sutradharudu Teki ret = spi_flash_cmd_read_config(flash, &qeb_status); 649f4322fdSJagannadha Sutradharudu Teki if (ret < 0) 659f4322fdSJagannadha Sutradharudu Teki return ret; 669f4322fdSJagannadha Sutradharudu Teki 679f4322fdSJagannadha Sutradharudu Teki if (qeb_status & STATUS_QEB_WINSPAN) { 689f4322fdSJagannadha Sutradharudu Teki debug("SF: winspan: QEB is already set\n"); 699f4322fdSJagannadha Sutradharudu Teki } else { 709f4322fdSJagannadha Sutradharudu Teki ret = spi_flash_cmd_write_config(flash, STATUS_QEB_WINSPAN); 719f4322fdSJagannadha Sutradharudu Teki if (ret < 0) 729f4322fdSJagannadha Sutradharudu Teki return ret; 739f4322fdSJagannadha Sutradharudu Teki } 749f4322fdSJagannadha Sutradharudu Teki 759f4322fdSJagannadha Sutradharudu Teki return ret; 769f4322fdSJagannadha Sutradharudu Teki } 779f4322fdSJagannadha Sutradharudu Teki #endif 789f4322fdSJagannadha Sutradharudu Teki 79d08a1bafSJagannadha Sutradharudu Teki static int spi_flash_set_qeb(struct spi_flash *flash, u8 idcode0) 80d08a1bafSJagannadha Sutradharudu Teki { 81d08a1bafSJagannadha Sutradharudu Teki switch (idcode0) { 8206795122SJagannadha Sutradharudu Teki #ifdef CONFIG_SPI_FLASH_MACRONIX 8306795122SJagannadha Sutradharudu Teki case SPI_FLASH_CFI_MFR_MACRONIX: 8406795122SJagannadha Sutradharudu Teki return spi_flash_set_qeb_mxic(flash); 8506795122SJagannadha Sutradharudu Teki #endif 86d08a1bafSJagannadha Sutradharudu Teki #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) 87d08a1bafSJagannadha Sutradharudu Teki case SPI_FLASH_CFI_MFR_SPANSION: 88d08a1bafSJagannadha Sutradharudu Teki case SPI_FLASH_CFI_MFR_WINBOND: 89d08a1bafSJagannadha Sutradharudu Teki return spi_flash_set_qeb_winspan(flash); 90d08a1bafSJagannadha Sutradharudu Teki #endif 91d08a1bafSJagannadha Sutradharudu Teki #ifdef CONFIG_SPI_FLASH_STMICRO 92d08a1bafSJagannadha Sutradharudu Teki case SPI_FLASH_CFI_MFR_STMICRO: 93d08a1bafSJagannadha Sutradharudu Teki debug("SF: QEB is volatile for %02x flash\n", idcode0); 94d08a1bafSJagannadha Sutradharudu Teki return 0; 95d08a1bafSJagannadha Sutradharudu Teki #endif 96d08a1bafSJagannadha Sutradharudu Teki default: 97d08a1bafSJagannadha Sutradharudu Teki printf("SF: Need set QEB func for %02x flash\n", idcode0); 98d08a1bafSJagannadha Sutradharudu Teki return -1; 99d08a1bafSJagannadha Sutradharudu Teki } 100d08a1bafSJagannadha Sutradharudu Teki } 101d08a1bafSJagannadha Sutradharudu Teki 102234a9e1cSJagan Teki #ifdef CONFIG_SPI_FLASH_BAR 103234a9e1cSJagan Teki static int spi_flash_read_bank(struct spi_flash *flash, u8 idcode0) 104234a9e1cSJagan Teki { 105234a9e1cSJagan Teki u8 curr_bank = 0; 106234a9e1cSJagan Teki int ret; 107234a9e1cSJagan Teki 108234a9e1cSJagan Teki if (flash->size <= SPI_FLASH_16MB_BOUN) 109234a9e1cSJagan Teki goto bank_end; 110234a9e1cSJagan Teki 111234a9e1cSJagan Teki switch (idcode0) { 112234a9e1cSJagan Teki case SPI_FLASH_CFI_MFR_SPANSION: 113234a9e1cSJagan Teki flash->bank_read_cmd = CMD_BANKADDR_BRRD; 114234a9e1cSJagan Teki flash->bank_write_cmd = CMD_BANKADDR_BRWR; 115234a9e1cSJagan Teki default: 116234a9e1cSJagan Teki flash->bank_read_cmd = CMD_EXTNADDR_RDEAR; 117234a9e1cSJagan Teki flash->bank_write_cmd = CMD_EXTNADDR_WREAR; 118234a9e1cSJagan Teki } 119234a9e1cSJagan Teki 120234a9e1cSJagan Teki ret = spi_flash_read_common(flash, &flash->bank_read_cmd, 1, 121234a9e1cSJagan Teki &curr_bank, 1); 122234a9e1cSJagan Teki if (ret) { 123234a9e1cSJagan Teki debug("SF: fail to read bank addr register\n"); 124234a9e1cSJagan Teki return ret; 125234a9e1cSJagan Teki } 126234a9e1cSJagan Teki 127234a9e1cSJagan Teki bank_end: 128234a9e1cSJagan Teki flash->bank_curr = curr_bank; 129234a9e1cSJagan Teki return 0; 130234a9e1cSJagan Teki } 131234a9e1cSJagan Teki #endif 132234a9e1cSJagan Teki 133ae242cbfSSimon Glass static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode, 134ae242cbfSSimon Glass struct spi_flash *flash) 135898e76c9SJagannadha Sutradharudu Teki { 136898e76c9SJagannadha Sutradharudu Teki const struct spi_flash_params *params; 1374e09cc1eSJagannadha Sutradharudu Teki u8 cmd; 138898e76c9SJagannadha Sutradharudu Teki u16 jedec = idcode[1] << 8 | idcode[2]; 139898e76c9SJagannadha Sutradharudu Teki u16 ext_jedec = idcode[3] << 8 | idcode[4]; 140898e76c9SJagannadha Sutradharudu Teki 141ae242cbfSSimon Glass /* Validate params from spi_flash_params table */ 14233adfb5fSJagannadha Sutradharudu Teki params = spi_flash_params_table; 14333adfb5fSJagannadha Sutradharudu Teki for (; params->name != NULL; params++) { 144898e76c9SJagannadha Sutradharudu Teki if ((params->jedec >> 16) == idcode[0]) { 145898e76c9SJagannadha Sutradharudu Teki if ((params->jedec & 0xFFFF) == jedec) { 146898e76c9SJagannadha Sutradharudu Teki if (params->ext_jedec == 0) 147898e76c9SJagannadha Sutradharudu Teki break; 148898e76c9SJagannadha Sutradharudu Teki else if (params->ext_jedec == ext_jedec) 149898e76c9SJagannadha Sutradharudu Teki break; 150898e76c9SJagannadha Sutradharudu Teki } 151898e76c9SJagannadha Sutradharudu Teki } 152898e76c9SJagannadha Sutradharudu Teki } 153898e76c9SJagannadha Sutradharudu Teki 15433adfb5fSJagannadha Sutradharudu Teki if (!params->name) { 155898e76c9SJagannadha Sutradharudu Teki printf("SF: Unsupported flash IDs: "); 156898e76c9SJagannadha Sutradharudu Teki printf("manuf %02x, jedec %04x, ext_jedec %04x\n", 157898e76c9SJagannadha Sutradharudu Teki idcode[0], jedec, ext_jedec); 158ae242cbfSSimon Glass return -EPROTONOSUPPORT; 159898e76c9SJagannadha Sutradharudu Teki } 160898e76c9SJagannadha Sutradharudu Teki 161469146c0SJagannadha Sutradharudu Teki /* Assign spi data */ 162898e76c9SJagannadha Sutradharudu Teki flash->spi = spi; 163898e76c9SJagannadha Sutradharudu Teki flash->name = params->name; 164ce22b922SJagannadha Sutradharudu Teki flash->memory_map = spi->memory_map; 165f77f4691SJagannadha Sutradharudu Teki flash->dual_flash = flash->spi->option; 166898e76c9SJagannadha Sutradharudu Teki 167898e76c9SJagannadha Sutradharudu Teki /* Assign spi_flash ops */ 168fbb09918SSimon Glass #ifndef CONFIG_DM_SPI_FLASH 169898e76c9SJagannadha Sutradharudu Teki flash->write = spi_flash_cmd_write_ops; 170fbb09918SSimon Glass #if defined(CONFIG_SPI_FLASH_SST) 171*1fabefddSJagan Teki if (params->flags & SST_WR) 172*1fabefddSJagan Teki flash->flags |= SNOR_F_SST_WR; 173*1fabefddSJagan Teki 174*1fabefddSJagan Teki if (params->flags & SNOR_F_SST_WR) { 17554ba653aSJagannadha Sutradharudu Teki if (flash->spi->op_mode_tx & SPI_OPM_TX_BP) 17654ba653aSJagannadha Sutradharudu Teki flash->write = sst_write_bp; 17754ba653aSJagannadha Sutradharudu Teki else 178898e76c9SJagannadha Sutradharudu Teki flash->write = sst_write_wp; 17954ba653aSJagannadha Sutradharudu Teki } 180898e76c9SJagannadha Sutradharudu Teki #endif 181898e76c9SJagannadha Sutradharudu Teki flash->erase = spi_flash_cmd_erase_ops; 182898e76c9SJagannadha Sutradharudu Teki flash->read = spi_flash_cmd_read_ops; 183fbb09918SSimon Glass #endif 184898e76c9SJagannadha Sutradharudu Teki 185898e76c9SJagannadha Sutradharudu Teki /* Compute the flash size */ 186056fbc73SJagannadha Sutradharudu Teki flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0; 187bf64035aSMarek Vasut /* 188bf64035aSMarek Vasut * The Spansion S25FL032P and S25FL064P have 256b pages, yet use the 189bf64035aSMarek Vasut * 0x4d00 Extended JEDEC code. The rest of the Spansion flashes with 190bf64035aSMarek Vasut * the 0x4d00 Extended JEDEC code have 512b pages. All of the others 191bf64035aSMarek Vasut * have 256b pages. 192bf64035aSMarek Vasut */ 193bf64035aSMarek Vasut if (ext_jedec == 0x4d00) { 194bf64035aSMarek Vasut if ((jedec == 0x0215) || (jedec == 0x216)) 195bf64035aSMarek Vasut flash->page_size = 256; 196bf64035aSMarek Vasut else 197bf64035aSMarek Vasut flash->page_size = 512; 198bf64035aSMarek Vasut } else { 199bf64035aSMarek Vasut flash->page_size = 256; 200bf64035aSMarek Vasut } 201bf64035aSMarek Vasut flash->page_size <<= flash->shift; 202056fbc73SJagannadha Sutradharudu Teki flash->sector_size = params->sector_size << flash->shift; 203056fbc73SJagannadha Sutradharudu Teki flash->size = flash->sector_size * params->nr_sectors << flash->shift; 204b902e07cSJagannadha Sutradharudu Teki #ifdef CONFIG_SF_DUAL_FLASH 205f77f4691SJagannadha Sutradharudu Teki if (flash->dual_flash & SF_DUAL_STACKED_FLASH) 206f77f4691SJagannadha Sutradharudu Teki flash->size <<= 1; 207b902e07cSJagannadha Sutradharudu Teki #endif 208898e76c9SJagannadha Sutradharudu Teki 209898e76c9SJagannadha Sutradharudu Teki /* Compute erase sector and command */ 210898e76c9SJagannadha Sutradharudu Teki if (params->flags & SECT_4K) { 211898e76c9SJagannadha Sutradharudu Teki flash->erase_cmd = CMD_ERASE_4K; 212056fbc73SJagannadha Sutradharudu Teki flash->erase_size = 4096 << flash->shift; 213898e76c9SJagannadha Sutradharudu Teki } else if (params->flags & SECT_32K) { 214898e76c9SJagannadha Sutradharudu Teki flash->erase_cmd = CMD_ERASE_32K; 215056fbc73SJagannadha Sutradharudu Teki flash->erase_size = 32768 << flash->shift; 216898e76c9SJagannadha Sutradharudu Teki } else { 217898e76c9SJagannadha Sutradharudu Teki flash->erase_cmd = CMD_ERASE_64K; 218898e76c9SJagannadha Sutradharudu Teki flash->erase_size = flash->sector_size; 219898e76c9SJagannadha Sutradharudu Teki } 220898e76c9SJagannadha Sutradharudu Teki 221c650ca7bSJagannadha Sutradharudu Teki /* Now erase size becomes valid sector size */ 222c650ca7bSJagannadha Sutradharudu Teki flash->sector_size = flash->erase_size; 223c650ca7bSJagannadha Sutradharudu Teki 2244e09cc1eSJagannadha Sutradharudu Teki /* Look for the fastest read cmd */ 2254e09cc1eSJagannadha Sutradharudu Teki cmd = fls(params->e_rd_cmd & flash->spi->op_mode_rx); 2264e09cc1eSJagannadha Sutradharudu Teki if (cmd) { 2274e09cc1eSJagannadha Sutradharudu Teki cmd = spi_read_cmds_array[cmd - 1]; 2284e09cc1eSJagannadha Sutradharudu Teki flash->read_cmd = cmd; 2294e09cc1eSJagannadha Sutradharudu Teki } else { 2302ba863faSJagannadha Sutradharudu Teki /* Go for default supported read cmd */ 2314e09cc1eSJagannadha Sutradharudu Teki flash->read_cmd = CMD_READ_ARRAY_FAST; 2324e09cc1eSJagannadha Sutradharudu Teki } 2334e09cc1eSJagannadha Sutradharudu Teki 2343163aaa6SJagannadha Sutradharudu Teki /* Not require to look for fastest only two write cmds yet */ 2353163aaa6SJagannadha Sutradharudu Teki if (params->flags & WR_QPP && flash->spi->op_mode_tx & SPI_OPM_TX_QPP) 2363163aaa6SJagannadha Sutradharudu Teki flash->write_cmd = CMD_QUAD_PAGE_PROGRAM; 2373163aaa6SJagannadha Sutradharudu Teki else 2383163aaa6SJagannadha Sutradharudu Teki /* Go for default supported write cmd */ 2393163aaa6SJagannadha Sutradharudu Teki flash->write_cmd = CMD_PAGE_PROGRAM; 2403163aaa6SJagannadha Sutradharudu Teki 241ff063ed4SJagannadha Sutradharudu Teki /* Read dummy_byte: dummy byte is determined based on the 242ff063ed4SJagannadha Sutradharudu Teki * dummy cycles of a particular command. 243ff063ed4SJagannadha Sutradharudu Teki * Fast commands - dummy_byte = dummy_cycles/8 244ff063ed4SJagannadha Sutradharudu Teki * I/O commands- dummy_byte = (dummy_cycles * no.of lines)/8 245ff063ed4SJagannadha Sutradharudu Teki * For I/O commands except cmd[0] everything goes on no.of lines 246ff063ed4SJagannadha Sutradharudu Teki * based on particular command but incase of fast commands except 247ff063ed4SJagannadha Sutradharudu Teki * data all go on single line irrespective of command. 248ff063ed4SJagannadha Sutradharudu Teki */ 249ff063ed4SJagannadha Sutradharudu Teki switch (flash->read_cmd) { 250ff063ed4SJagannadha Sutradharudu Teki case CMD_READ_QUAD_IO_FAST: 251ff063ed4SJagannadha Sutradharudu Teki flash->dummy_byte = 2; 252ff063ed4SJagannadha Sutradharudu Teki break; 253ff063ed4SJagannadha Sutradharudu Teki case CMD_READ_ARRAY_SLOW: 254ff063ed4SJagannadha Sutradharudu Teki flash->dummy_byte = 0; 255ff063ed4SJagannadha Sutradharudu Teki break; 256ff063ed4SJagannadha Sutradharudu Teki default: 257ff063ed4SJagannadha Sutradharudu Teki flash->dummy_byte = 1; 258ff063ed4SJagannadha Sutradharudu Teki } 259ff063ed4SJagannadha Sutradharudu Teki 2602ba863faSJagannadha Sutradharudu Teki /* Poll cmd selection */ 261898e76c9SJagannadha Sutradharudu Teki flash->poll_cmd = CMD_READ_STATUS; 262898e76c9SJagannadha Sutradharudu Teki #ifdef CONFIG_SPI_FLASH_STMICRO 263898e76c9SJagannadha Sutradharudu Teki if (params->flags & E_FSR) 264898e76c9SJagannadha Sutradharudu Teki flash->poll_cmd = CMD_FLAG_STATUS; 265898e76c9SJagannadha Sutradharudu Teki #endif 266898e76c9SJagannadha Sutradharudu Teki 267898e76c9SJagannadha Sutradharudu Teki /* Configure the BAR - discover bank cmds and read current bank */ 268ce22b922SJagannadha Sutradharudu Teki #ifdef CONFIG_SPI_FLASH_BAR 269234a9e1cSJagan Teki int ret = spi_flash_read_bank(flash, idcode[0]); 270234a9e1cSJagan Teki if (ret < 0) 271ae242cbfSSimon Glass return ret; 272898e76c9SJagannadha Sutradharudu Teki #endif 273898e76c9SJagannadha Sutradharudu Teki 274898e76c9SJagannadha Sutradharudu Teki /* Flash powers up read-only, so clear BP# bits */ 275898e76c9SJagannadha Sutradharudu Teki #if defined(CONFIG_SPI_FLASH_ATMEL) || \ 276898e76c9SJagannadha Sutradharudu Teki defined(CONFIG_SPI_FLASH_MACRONIX) || \ 277898e76c9SJagannadha Sutradharudu Teki defined(CONFIG_SPI_FLASH_SST) 278898e76c9SJagannadha Sutradharudu Teki spi_flash_cmd_write_status(flash, 0); 279898e76c9SJagannadha Sutradharudu Teki #endif 280898e76c9SJagannadha Sutradharudu Teki 281ae242cbfSSimon Glass return 0; 282898e76c9SJagannadha Sutradharudu Teki } 283898e76c9SJagannadha Sutradharudu Teki 2840f925822SMasahiro Yamada #if CONFIG_IS_ENABLED(OF_CONTROL) 285898e76c9SJagannadha Sutradharudu Teki int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) 286898e76c9SJagannadha Sutradharudu Teki { 287898e76c9SJagannadha Sutradharudu Teki fdt_addr_t addr; 288898e76c9SJagannadha Sutradharudu Teki fdt_size_t size; 289898e76c9SJagannadha Sutradharudu Teki int node; 290898e76c9SJagannadha Sutradharudu Teki 291898e76c9SJagannadha Sutradharudu Teki /* If there is no node, do nothing */ 292898e76c9SJagannadha Sutradharudu Teki node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); 293898e76c9SJagannadha Sutradharudu Teki if (node < 0) 294898e76c9SJagannadha Sutradharudu Teki return 0; 295898e76c9SJagannadha Sutradharudu Teki 296898e76c9SJagannadha Sutradharudu Teki addr = fdtdec_get_addr_size(blob, node, "memory-map", &size); 297898e76c9SJagannadha Sutradharudu Teki if (addr == FDT_ADDR_T_NONE) { 298898e76c9SJagannadha Sutradharudu Teki debug("%s: Cannot decode address\n", __func__); 299898e76c9SJagannadha Sutradharudu Teki return 0; 300898e76c9SJagannadha Sutradharudu Teki } 301898e76c9SJagannadha Sutradharudu Teki 302898e76c9SJagannadha Sutradharudu Teki if (flash->size != size) { 303898e76c9SJagannadha Sutradharudu Teki debug("%s: Memory map must cover entire device\n", __func__); 304898e76c9SJagannadha Sutradharudu Teki return -1; 305898e76c9SJagannadha Sutradharudu Teki } 306ffdb20beSMike Frysinger flash->memory_map = map_sysmem(addr, size); 307898e76c9SJagannadha Sutradharudu Teki 308898e76c9SJagannadha Sutradharudu Teki return 0; 309898e76c9SJagannadha Sutradharudu Teki } 3100f925822SMasahiro Yamada #endif /* CONFIG_IS_ENABLED(OF_CONTROL) */ 311898e76c9SJagannadha Sutradharudu Teki 312ae242cbfSSimon Glass /** 313ae242cbfSSimon Glass * spi_flash_probe_slave() - Probe for a SPI flash device on a bus 314ae242cbfSSimon Glass * 315ae242cbfSSimon Glass * @spi: Bus to probe 316ae242cbfSSimon Glass * @flashp: Pointer to place to put flash info, which may be NULL if the 317ae242cbfSSimon Glass * space should be allocated 318ae242cbfSSimon Glass */ 319ae242cbfSSimon Glass int spi_flash_probe_slave(struct spi_slave *spi, struct spi_flash *flash) 320898e76c9SJagannadha Sutradharudu Teki { 321898e76c9SJagannadha Sutradharudu Teki u8 idcode[5]; 322898e76c9SJagannadha Sutradharudu Teki int ret; 323898e76c9SJagannadha Sutradharudu Teki 324898e76c9SJagannadha Sutradharudu Teki /* Setup spi_slave */ 325898e76c9SJagannadha Sutradharudu Teki if (!spi) { 326898e76c9SJagannadha Sutradharudu Teki printf("SF: Failed to set up slave\n"); 327ae242cbfSSimon Glass return -ENODEV; 328898e76c9SJagannadha Sutradharudu Teki } 329898e76c9SJagannadha Sutradharudu Teki 330898e76c9SJagannadha Sutradharudu Teki /* Claim spi bus */ 331898e76c9SJagannadha Sutradharudu Teki ret = spi_claim_bus(spi); 332898e76c9SJagannadha Sutradharudu Teki if (ret) { 333898e76c9SJagannadha Sutradharudu Teki debug("SF: Failed to claim SPI bus: %d\n", ret); 334ae242cbfSSimon Glass return ret; 335898e76c9SJagannadha Sutradharudu Teki } 336898e76c9SJagannadha Sutradharudu Teki 337898e76c9SJagannadha Sutradharudu Teki /* Read the ID codes */ 338898e76c9SJagannadha Sutradharudu Teki ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); 339898e76c9SJagannadha Sutradharudu Teki if (ret) { 340898e76c9SJagannadha Sutradharudu Teki printf("SF: Failed to get idcodes\n"); 341898e76c9SJagannadha Sutradharudu Teki goto err_read_id; 342898e76c9SJagannadha Sutradharudu Teki } 343898e76c9SJagannadha Sutradharudu Teki 344898e76c9SJagannadha Sutradharudu Teki #ifdef DEBUG 345898e76c9SJagannadha Sutradharudu Teki printf("SF: Got idcodes\n"); 346898e76c9SJagannadha Sutradharudu Teki print_buffer(0, idcode, 1, sizeof(idcode), 0); 347898e76c9SJagannadha Sutradharudu Teki #endif 348898e76c9SJagannadha Sutradharudu Teki 349ae242cbfSSimon Glass if (spi_flash_validate_params(spi, idcode, flash)) { 350ae242cbfSSimon Glass ret = -EINVAL; 351898e76c9SJagannadha Sutradharudu Teki goto err_read_id; 352ae242cbfSSimon Glass } 353898e76c9SJagannadha Sutradharudu Teki 3541f436a6dSPoddar, Sourav /* Set the quad enable bit - only for quad commands */ 3551f436a6dSPoddar, Sourav if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) || 3561f436a6dSPoddar, Sourav (flash->read_cmd == CMD_READ_QUAD_IO_FAST) || 3571f436a6dSPoddar, Sourav (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) { 3581f436a6dSPoddar, Sourav if (spi_flash_set_qeb(flash, idcode[0])) { 3591f436a6dSPoddar, Sourav debug("SF: Fail to set QEB for %02x\n", idcode[0]); 360ae242cbfSSimon Glass ret = -EINVAL; 361ae242cbfSSimon Glass goto err_read_id; 3621f436a6dSPoddar, Sourav } 3631f436a6dSPoddar, Sourav } 3641f436a6dSPoddar, Sourav 3650f925822SMasahiro Yamada #if CONFIG_IS_ENABLED(OF_CONTROL) 366898e76c9SJagannadha Sutradharudu Teki if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { 367898e76c9SJagannadha Sutradharudu Teki debug("SF: FDT decode error\n"); 368ae242cbfSSimon Glass ret = -EINVAL; 369898e76c9SJagannadha Sutradharudu Teki goto err_read_id; 370898e76c9SJagannadha Sutradharudu Teki } 371898e76c9SJagannadha Sutradharudu Teki #endif 372898e76c9SJagannadha Sutradharudu Teki #ifndef CONFIG_SPL_BUILD 373898e76c9SJagannadha Sutradharudu Teki printf("SF: Detected %s with page size ", flash->name); 374898e76c9SJagannadha Sutradharudu Teki print_size(flash->page_size, ", erase size "); 375898e76c9SJagannadha Sutradharudu Teki print_size(flash->erase_size, ", total "); 376898e76c9SJagannadha Sutradharudu Teki print_size(flash->size, ""); 377898e76c9SJagannadha Sutradharudu Teki if (flash->memory_map) 378898e76c9SJagannadha Sutradharudu Teki printf(", mapped at %p", flash->memory_map); 379898e76c9SJagannadha Sutradharudu Teki puts("\n"); 380898e76c9SJagannadha Sutradharudu Teki #endif 381898e76c9SJagannadha Sutradharudu Teki #ifndef CONFIG_SPI_FLASH_BAR 382f77f4691SJagannadha Sutradharudu Teki if (((flash->dual_flash == SF_SINGLE_FLASH) && 383f77f4691SJagannadha Sutradharudu Teki (flash->size > SPI_FLASH_16MB_BOUN)) || 384f77f4691SJagannadha Sutradharudu Teki ((flash->dual_flash > SF_SINGLE_FLASH) && 385f77f4691SJagannadha Sutradharudu Teki (flash->size > SPI_FLASH_16MB_BOUN << 1))) { 386898e76c9SJagannadha Sutradharudu Teki puts("SF: Warning - Only lower 16MiB accessible,"); 387898e76c9SJagannadha Sutradharudu Teki puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); 388898e76c9SJagannadha Sutradharudu Teki } 389898e76c9SJagannadha Sutradharudu Teki #endif 3909fe6d871SDaniel Schwierzeck #ifdef CONFIG_SPI_FLASH_MTD 3919fe6d871SDaniel Schwierzeck ret = spi_flash_mtd_register(flash); 3929fe6d871SDaniel Schwierzeck #endif 393898e76c9SJagannadha Sutradharudu Teki 394898e76c9SJagannadha Sutradharudu Teki err_read_id: 395898e76c9SJagannadha Sutradharudu Teki spi_release_bus(spi); 396ae242cbfSSimon Glass return ret; 397ae242cbfSSimon Glass } 398ae242cbfSSimon Glass 399fbb09918SSimon Glass #ifndef CONFIG_DM_SPI_FLASH 400fbb09918SSimon Glass struct spi_flash *spi_flash_probe_tail(struct spi_slave *bus) 401ae242cbfSSimon Glass { 402ae242cbfSSimon Glass struct spi_flash *flash; 403ae242cbfSSimon Glass 404ae242cbfSSimon Glass /* Allocate space if needed (not used by sf-uclass */ 405ae242cbfSSimon Glass flash = calloc(1, sizeof(*flash)); 406ae242cbfSSimon Glass if (!flash) { 407ae242cbfSSimon Glass debug("SF: Failed to allocate spi_flash\n"); 408898e76c9SJagannadha Sutradharudu Teki return NULL; 409898e76c9SJagannadha Sutradharudu Teki } 410898e76c9SJagannadha Sutradharudu Teki 411ae242cbfSSimon Glass if (spi_flash_probe_slave(bus, flash)) { 412ae242cbfSSimon Glass spi_free_slave(bus); 413ae242cbfSSimon Glass free(flash); 414ae242cbfSSimon Glass return NULL; 415ae242cbfSSimon Glass } 416ae242cbfSSimon Glass 417ae242cbfSSimon Glass return flash; 418ae242cbfSSimon Glass } 419ae242cbfSSimon Glass 420ae242cbfSSimon Glass struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs, 4210efc0249SSimon Glass unsigned int max_hz, unsigned int spi_mode) 4220efc0249SSimon Glass { 423ae242cbfSSimon Glass struct spi_slave *bus; 4240efc0249SSimon Glass 425ae242cbfSSimon Glass bus = spi_setup_slave(busnum, cs, max_hz, spi_mode); 4264fbad92eSPeng Fan if (!bus) 4274fbad92eSPeng Fan return NULL; 428ae242cbfSSimon Glass return spi_flash_probe_tail(bus); 4290efc0249SSimon Glass } 4300efc0249SSimon Glass 4310efc0249SSimon Glass #ifdef CONFIG_OF_SPI_FLASH 4320efc0249SSimon Glass struct spi_flash *spi_flash_probe_fdt(const void *blob, int slave_node, 4330efc0249SSimon Glass int spi_node) 4340efc0249SSimon Glass { 435ae242cbfSSimon Glass struct spi_slave *bus; 4360efc0249SSimon Glass 437ae242cbfSSimon Glass bus = spi_setup_slave_fdt(blob, slave_node, spi_node); 4384fbad92eSPeng Fan if (!bus) 4394fbad92eSPeng Fan return NULL; 440ae242cbfSSimon Glass return spi_flash_probe_tail(bus); 4410efc0249SSimon Glass } 4420efc0249SSimon Glass #endif 4430efc0249SSimon Glass 444898e76c9SJagannadha Sutradharudu Teki void spi_flash_free(struct spi_flash *flash) 445898e76c9SJagannadha Sutradharudu Teki { 4469fe6d871SDaniel Schwierzeck #ifdef CONFIG_SPI_FLASH_MTD 4479fe6d871SDaniel Schwierzeck spi_flash_mtd_unregister(); 4489fe6d871SDaniel Schwierzeck #endif 449898e76c9SJagannadha Sutradharudu Teki spi_free_slave(flash->spi); 450898e76c9SJagannadha Sutradharudu Teki free(flash); 451898e76c9SJagannadha Sutradharudu Teki } 452fbb09918SSimon Glass 453fbb09918SSimon Glass #else /* defined CONFIG_DM_SPI_FLASH */ 454fbb09918SSimon Glass 455fbb09918SSimon Glass static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len, 456fbb09918SSimon Glass void *buf) 457fbb09918SSimon Glass { 458e564f054SSimon Glass struct spi_flash *flash = dev_get_uclass_priv(dev); 459fbb09918SSimon Glass 460fbb09918SSimon Glass return spi_flash_cmd_read_ops(flash, offset, len, buf); 461fbb09918SSimon Glass } 462fbb09918SSimon Glass 463fbb09918SSimon Glass int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len, 464fbb09918SSimon Glass const void *buf) 465fbb09918SSimon Glass { 466e564f054SSimon Glass struct spi_flash *flash = dev_get_uclass_priv(dev); 467fbb09918SSimon Glass 468074eed51SBin Meng #if defined(CONFIG_SPI_FLASH_SST) 469*1fabefddSJagan Teki if (flash->flags & SNOR_F_SST_WR) { 470074eed51SBin Meng if (flash->spi->op_mode_tx & SPI_OPM_TX_BP) 471074eed51SBin Meng return sst_write_bp(flash, offset, len, buf); 472074eed51SBin Meng else 473074eed51SBin Meng return sst_write_wp(flash, offset, len, buf); 474074eed51SBin Meng } 475074eed51SBin Meng #endif 476074eed51SBin Meng 477fbb09918SSimon Glass return spi_flash_cmd_write_ops(flash, offset, len, buf); 478fbb09918SSimon Glass } 479fbb09918SSimon Glass 480fbb09918SSimon Glass int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len) 481fbb09918SSimon Glass { 482e564f054SSimon Glass struct spi_flash *flash = dev_get_uclass_priv(dev); 483fbb09918SSimon Glass 484fbb09918SSimon Glass return spi_flash_cmd_erase_ops(flash, offset, len); 485fbb09918SSimon Glass } 486fbb09918SSimon Glass 487fbb09918SSimon Glass int spi_flash_std_probe(struct udevice *dev) 488fbb09918SSimon Glass { 489fbb09918SSimon Glass struct spi_slave *slave = dev_get_parentdata(dev); 490d0cff03eSSimon Glass struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev); 491fbb09918SSimon Glass struct spi_flash *flash; 492fbb09918SSimon Glass 493e564f054SSimon Glass flash = dev_get_uclass_priv(dev); 494fbb09918SSimon Glass flash->dev = dev; 495d0cff03eSSimon Glass debug("%s: slave=%p, cs=%d\n", __func__, slave, plat->cs); 496fbb09918SSimon Glass return spi_flash_probe_slave(slave, flash); 497fbb09918SSimon Glass } 498fbb09918SSimon Glass 499fbb09918SSimon Glass static const struct dm_spi_flash_ops spi_flash_std_ops = { 500fbb09918SSimon Glass .read = spi_flash_std_read, 501fbb09918SSimon Glass .write = spi_flash_std_write, 502fbb09918SSimon Glass .erase = spi_flash_std_erase, 503fbb09918SSimon Glass }; 504fbb09918SSimon Glass 505fbb09918SSimon Glass static const struct udevice_id spi_flash_std_ids[] = { 506fbb09918SSimon Glass { .compatible = "spi-flash" }, 507fbb09918SSimon Glass { } 508fbb09918SSimon Glass }; 509fbb09918SSimon Glass 510fbb09918SSimon Glass U_BOOT_DRIVER(spi_flash_std) = { 511fbb09918SSimon Glass .name = "spi_flash_std", 512fbb09918SSimon Glass .id = UCLASS_SPI_FLASH, 513fbb09918SSimon Glass .of_match = spi_flash_std_ids, 514fbb09918SSimon Glass .probe = spi_flash_std_probe, 515fbb09918SSimon Glass .priv_auto_alloc_size = sizeof(struct spi_flash), 516fbb09918SSimon Glass .ops = &spi_flash_std_ops, 517fbb09918SSimon Glass }; 518fbb09918SSimon Glass 519fbb09918SSimon Glass #endif /* CONFIG_DM_SPI_FLASH */ 520