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> 16898e76c9SJagannadha Sutradharudu Teki #include <spi.h> 17898e76c9SJagannadha Sutradharudu Teki #include <spi_flash.h> 18ffdb20beSMike Frysinger #include <asm/io.h> 19898e76c9SJagannadha Sutradharudu Teki 20898e76c9SJagannadha Sutradharudu Teki #include "sf_internal.h" 21898e76c9SJagannadha Sutradharudu Teki 22898e76c9SJagannadha Sutradharudu Teki DECLARE_GLOBAL_DATA_PTR; 23898e76c9SJagannadha Sutradharudu Teki 244e09cc1eSJagannadha Sutradharudu Teki /* Read commands array */ 254e09cc1eSJagannadha Sutradharudu Teki static u8 spi_read_cmds_array[] = { 264e09cc1eSJagannadha Sutradharudu Teki CMD_READ_ARRAY_SLOW, 276dd6e90eSJagannadha Sutradharudu Teki CMD_READ_ARRAY_FAST, 284e09cc1eSJagannadha Sutradharudu Teki CMD_READ_DUAL_OUTPUT_FAST, 294e09cc1eSJagannadha Sutradharudu Teki CMD_READ_DUAL_IO_FAST, 303163aaa6SJagannadha Sutradharudu Teki CMD_READ_QUAD_OUTPUT_FAST, 31c4ba0d82SJagannadha Sutradharudu Teki CMD_READ_QUAD_IO_FAST, 324e09cc1eSJagannadha Sutradharudu Teki }; 334e09cc1eSJagannadha Sutradharudu Teki 349f4322fdSJagannadha Sutradharudu Teki #ifdef CONFIG_SPI_FLASH_MACRONIX 359f4322fdSJagannadha Sutradharudu Teki static int spi_flash_set_qeb_mxic(struct spi_flash *flash) 369f4322fdSJagannadha Sutradharudu Teki { 379f4322fdSJagannadha Sutradharudu Teki u8 qeb_status; 389f4322fdSJagannadha Sutradharudu Teki int ret; 399f4322fdSJagannadha Sutradharudu Teki 409f4322fdSJagannadha Sutradharudu Teki ret = spi_flash_cmd_read_status(flash, &qeb_status); 419f4322fdSJagannadha Sutradharudu Teki if (ret < 0) 429f4322fdSJagannadha Sutradharudu Teki return ret; 439f4322fdSJagannadha Sutradharudu Teki 449f4322fdSJagannadha Sutradharudu Teki if (qeb_status & STATUS_QEB_MXIC) { 459f4322fdSJagannadha Sutradharudu Teki debug("SF: mxic: QEB is already set\n"); 469f4322fdSJagannadha Sutradharudu Teki } else { 479f4322fdSJagannadha Sutradharudu Teki ret = spi_flash_cmd_write_status(flash, STATUS_QEB_MXIC); 489f4322fdSJagannadha Sutradharudu Teki if (ret < 0) 499f4322fdSJagannadha Sutradharudu Teki return ret; 509f4322fdSJagannadha Sutradharudu Teki } 519f4322fdSJagannadha Sutradharudu Teki 529f4322fdSJagannadha Sutradharudu Teki return ret; 539f4322fdSJagannadha Sutradharudu Teki } 549f4322fdSJagannadha Sutradharudu Teki #endif 559f4322fdSJagannadha Sutradharudu Teki 569f4322fdSJagannadha Sutradharudu Teki #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) 579f4322fdSJagannadha Sutradharudu Teki static int spi_flash_set_qeb_winspan(struct spi_flash *flash) 589f4322fdSJagannadha Sutradharudu Teki { 599f4322fdSJagannadha Sutradharudu Teki u8 qeb_status; 609f4322fdSJagannadha Sutradharudu Teki int ret; 619f4322fdSJagannadha Sutradharudu Teki 629f4322fdSJagannadha Sutradharudu Teki ret = spi_flash_cmd_read_config(flash, &qeb_status); 639f4322fdSJagannadha Sutradharudu Teki if (ret < 0) 649f4322fdSJagannadha Sutradharudu Teki return ret; 659f4322fdSJagannadha Sutradharudu Teki 669f4322fdSJagannadha Sutradharudu Teki if (qeb_status & STATUS_QEB_WINSPAN) { 679f4322fdSJagannadha Sutradharudu Teki debug("SF: winspan: QEB is already set\n"); 689f4322fdSJagannadha Sutradharudu Teki } else { 699f4322fdSJagannadha Sutradharudu Teki ret = spi_flash_cmd_write_config(flash, STATUS_QEB_WINSPAN); 709f4322fdSJagannadha Sutradharudu Teki if (ret < 0) 719f4322fdSJagannadha Sutradharudu Teki return ret; 729f4322fdSJagannadha Sutradharudu Teki } 739f4322fdSJagannadha Sutradharudu Teki 749f4322fdSJagannadha Sutradharudu Teki return ret; 759f4322fdSJagannadha Sutradharudu Teki } 769f4322fdSJagannadha Sutradharudu Teki #endif 779f4322fdSJagannadha Sutradharudu Teki 78d08a1bafSJagannadha Sutradharudu Teki static int spi_flash_set_qeb(struct spi_flash *flash, u8 idcode0) 79d08a1bafSJagannadha Sutradharudu Teki { 80d08a1bafSJagannadha Sutradharudu Teki switch (idcode0) { 8106795122SJagannadha Sutradharudu Teki #ifdef CONFIG_SPI_FLASH_MACRONIX 8206795122SJagannadha Sutradharudu Teki case SPI_FLASH_CFI_MFR_MACRONIX: 8306795122SJagannadha Sutradharudu Teki return spi_flash_set_qeb_mxic(flash); 8406795122SJagannadha Sutradharudu Teki #endif 85d08a1bafSJagannadha Sutradharudu Teki #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) 86d08a1bafSJagannadha Sutradharudu Teki case SPI_FLASH_CFI_MFR_SPANSION: 87d08a1bafSJagannadha Sutradharudu Teki case SPI_FLASH_CFI_MFR_WINBOND: 88d08a1bafSJagannadha Sutradharudu Teki return spi_flash_set_qeb_winspan(flash); 89d08a1bafSJagannadha Sutradharudu Teki #endif 90d08a1bafSJagannadha Sutradharudu Teki #ifdef CONFIG_SPI_FLASH_STMICRO 91d08a1bafSJagannadha Sutradharudu Teki case SPI_FLASH_CFI_MFR_STMICRO: 92d08a1bafSJagannadha Sutradharudu Teki debug("SF: QEB is volatile for %02x flash\n", idcode0); 93d08a1bafSJagannadha Sutradharudu Teki return 0; 94d08a1bafSJagannadha Sutradharudu Teki #endif 95d08a1bafSJagannadha Sutradharudu Teki default: 96d08a1bafSJagannadha Sutradharudu Teki printf("SF: Need set QEB func for %02x flash\n", idcode0); 97d08a1bafSJagannadha Sutradharudu Teki return -1; 98d08a1bafSJagannadha Sutradharudu Teki } 99d08a1bafSJagannadha Sutradharudu Teki } 100d08a1bafSJagannadha Sutradharudu Teki 101ae242cbfSSimon Glass static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode, 102ae242cbfSSimon Glass struct spi_flash *flash) 103898e76c9SJagannadha Sutradharudu Teki { 104898e76c9SJagannadha Sutradharudu Teki const struct spi_flash_params *params; 1054e09cc1eSJagannadha Sutradharudu Teki u8 cmd; 106898e76c9SJagannadha Sutradharudu Teki u16 jedec = idcode[1] << 8 | idcode[2]; 107898e76c9SJagannadha Sutradharudu Teki u16 ext_jedec = idcode[3] << 8 | idcode[4]; 108898e76c9SJagannadha Sutradharudu Teki 109ae242cbfSSimon Glass /* Validate params from spi_flash_params table */ 11033adfb5fSJagannadha Sutradharudu Teki params = spi_flash_params_table; 11133adfb5fSJagannadha Sutradharudu Teki for (; params->name != NULL; params++) { 112898e76c9SJagannadha Sutradharudu Teki if ((params->jedec >> 16) == idcode[0]) { 113898e76c9SJagannadha Sutradharudu Teki if ((params->jedec & 0xFFFF) == jedec) { 114898e76c9SJagannadha Sutradharudu Teki if (params->ext_jedec == 0) 115898e76c9SJagannadha Sutradharudu Teki break; 116898e76c9SJagannadha Sutradharudu Teki else if (params->ext_jedec == ext_jedec) 117898e76c9SJagannadha Sutradharudu Teki break; 118898e76c9SJagannadha Sutradharudu Teki } 119898e76c9SJagannadha Sutradharudu Teki } 120898e76c9SJagannadha Sutradharudu Teki } 121898e76c9SJagannadha Sutradharudu Teki 12233adfb5fSJagannadha Sutradharudu Teki if (!params->name) { 123898e76c9SJagannadha Sutradharudu Teki printf("SF: Unsupported flash IDs: "); 124898e76c9SJagannadha Sutradharudu Teki printf("manuf %02x, jedec %04x, ext_jedec %04x\n", 125898e76c9SJagannadha Sutradharudu Teki idcode[0], jedec, ext_jedec); 126ae242cbfSSimon Glass return -EPROTONOSUPPORT; 127898e76c9SJagannadha Sutradharudu Teki } 128898e76c9SJagannadha Sutradharudu Teki 129469146c0SJagannadha Sutradharudu Teki /* Assign spi data */ 130898e76c9SJagannadha Sutradharudu Teki flash->spi = spi; 131898e76c9SJagannadha Sutradharudu Teki flash->name = params->name; 132ce22b922SJagannadha Sutradharudu Teki flash->memory_map = spi->memory_map; 133f77f4691SJagannadha Sutradharudu Teki flash->dual_flash = flash->spi->option; 134898e76c9SJagannadha Sutradharudu Teki 135898e76c9SJagannadha Sutradharudu Teki /* Assign spi_flash ops */ 136fbb09918SSimon Glass #ifndef CONFIG_DM_SPI_FLASH 137898e76c9SJagannadha Sutradharudu Teki flash->write = spi_flash_cmd_write_ops; 138fbb09918SSimon Glass #if defined(CONFIG_SPI_FLASH_SST) 13954ba653aSJagannadha Sutradharudu Teki if (params->flags & SST_WR) { 14054ba653aSJagannadha Sutradharudu Teki if (flash->spi->op_mode_tx & SPI_OPM_TX_BP) 14154ba653aSJagannadha Sutradharudu Teki flash->write = sst_write_bp; 14254ba653aSJagannadha Sutradharudu Teki else 143898e76c9SJagannadha Sutradharudu Teki flash->write = sst_write_wp; 14454ba653aSJagannadha Sutradharudu Teki } 145898e76c9SJagannadha Sutradharudu Teki #endif 146898e76c9SJagannadha Sutradharudu Teki flash->erase = spi_flash_cmd_erase_ops; 147898e76c9SJagannadha Sutradharudu Teki flash->read = spi_flash_cmd_read_ops; 148fbb09918SSimon Glass #endif 149898e76c9SJagannadha Sutradharudu Teki 150898e76c9SJagannadha Sutradharudu Teki /* Compute the flash size */ 151056fbc73SJagannadha Sutradharudu Teki flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0; 152bf64035aSMarek Vasut /* 153bf64035aSMarek Vasut * The Spansion S25FL032P and S25FL064P have 256b pages, yet use the 154bf64035aSMarek Vasut * 0x4d00 Extended JEDEC code. The rest of the Spansion flashes with 155bf64035aSMarek Vasut * the 0x4d00 Extended JEDEC code have 512b pages. All of the others 156bf64035aSMarek Vasut * have 256b pages. 157bf64035aSMarek Vasut */ 158bf64035aSMarek Vasut if (ext_jedec == 0x4d00) { 159bf64035aSMarek Vasut if ((jedec == 0x0215) || (jedec == 0x216)) 160bf64035aSMarek Vasut flash->page_size = 256; 161bf64035aSMarek Vasut else 162bf64035aSMarek Vasut flash->page_size = 512; 163bf64035aSMarek Vasut } else { 164bf64035aSMarek Vasut flash->page_size = 256; 165bf64035aSMarek Vasut } 166bf64035aSMarek Vasut flash->page_size <<= flash->shift; 167056fbc73SJagannadha Sutradharudu Teki flash->sector_size = params->sector_size << flash->shift; 168056fbc73SJagannadha Sutradharudu Teki flash->size = flash->sector_size * params->nr_sectors << flash->shift; 169b902e07cSJagannadha Sutradharudu Teki #ifdef CONFIG_SF_DUAL_FLASH 170f77f4691SJagannadha Sutradharudu Teki if (flash->dual_flash & SF_DUAL_STACKED_FLASH) 171f77f4691SJagannadha Sutradharudu Teki flash->size <<= 1; 172b902e07cSJagannadha Sutradharudu Teki #endif 173898e76c9SJagannadha Sutradharudu Teki 174898e76c9SJagannadha Sutradharudu Teki /* Compute erase sector and command */ 175898e76c9SJagannadha Sutradharudu Teki if (params->flags & SECT_4K) { 176898e76c9SJagannadha Sutradharudu Teki flash->erase_cmd = CMD_ERASE_4K; 177056fbc73SJagannadha Sutradharudu Teki flash->erase_size = 4096 << flash->shift; 178898e76c9SJagannadha Sutradharudu Teki } else if (params->flags & SECT_32K) { 179898e76c9SJagannadha Sutradharudu Teki flash->erase_cmd = CMD_ERASE_32K; 180056fbc73SJagannadha Sutradharudu Teki flash->erase_size = 32768 << flash->shift; 181898e76c9SJagannadha Sutradharudu Teki } else { 182898e76c9SJagannadha Sutradharudu Teki flash->erase_cmd = CMD_ERASE_64K; 183898e76c9SJagannadha Sutradharudu Teki flash->erase_size = flash->sector_size; 184898e76c9SJagannadha Sutradharudu Teki } 185898e76c9SJagannadha Sutradharudu Teki 1864e09cc1eSJagannadha Sutradharudu Teki /* Look for the fastest read cmd */ 1874e09cc1eSJagannadha Sutradharudu Teki cmd = fls(params->e_rd_cmd & flash->spi->op_mode_rx); 1884e09cc1eSJagannadha Sutradharudu Teki if (cmd) { 1894e09cc1eSJagannadha Sutradharudu Teki cmd = spi_read_cmds_array[cmd - 1]; 1904e09cc1eSJagannadha Sutradharudu Teki flash->read_cmd = cmd; 1914e09cc1eSJagannadha Sutradharudu Teki } else { 1922ba863faSJagannadha Sutradharudu Teki /* Go for default supported read cmd */ 1934e09cc1eSJagannadha Sutradharudu Teki flash->read_cmd = CMD_READ_ARRAY_FAST; 1944e09cc1eSJagannadha Sutradharudu Teki } 1954e09cc1eSJagannadha Sutradharudu Teki 1963163aaa6SJagannadha Sutradharudu Teki /* Not require to look for fastest only two write cmds yet */ 1973163aaa6SJagannadha Sutradharudu Teki if (params->flags & WR_QPP && flash->spi->op_mode_tx & SPI_OPM_TX_QPP) 1983163aaa6SJagannadha Sutradharudu Teki flash->write_cmd = CMD_QUAD_PAGE_PROGRAM; 1993163aaa6SJagannadha Sutradharudu Teki else 2003163aaa6SJagannadha Sutradharudu Teki /* Go for default supported write cmd */ 2013163aaa6SJagannadha Sutradharudu Teki flash->write_cmd = CMD_PAGE_PROGRAM; 2023163aaa6SJagannadha Sutradharudu Teki 203ff063ed4SJagannadha Sutradharudu Teki /* Read dummy_byte: dummy byte is determined based on the 204ff063ed4SJagannadha Sutradharudu Teki * dummy cycles of a particular command. 205ff063ed4SJagannadha Sutradharudu Teki * Fast commands - dummy_byte = dummy_cycles/8 206ff063ed4SJagannadha Sutradharudu Teki * I/O commands- dummy_byte = (dummy_cycles * no.of lines)/8 207ff063ed4SJagannadha Sutradharudu Teki * For I/O commands except cmd[0] everything goes on no.of lines 208ff063ed4SJagannadha Sutradharudu Teki * based on particular command but incase of fast commands except 209ff063ed4SJagannadha Sutradharudu Teki * data all go on single line irrespective of command. 210ff063ed4SJagannadha Sutradharudu Teki */ 211ff063ed4SJagannadha Sutradharudu Teki switch (flash->read_cmd) { 212ff063ed4SJagannadha Sutradharudu Teki case CMD_READ_QUAD_IO_FAST: 213ff063ed4SJagannadha Sutradharudu Teki flash->dummy_byte = 2; 214ff063ed4SJagannadha Sutradharudu Teki break; 215ff063ed4SJagannadha Sutradharudu Teki case CMD_READ_ARRAY_SLOW: 216ff063ed4SJagannadha Sutradharudu Teki flash->dummy_byte = 0; 217ff063ed4SJagannadha Sutradharudu Teki break; 218ff063ed4SJagannadha Sutradharudu Teki default: 219ff063ed4SJagannadha Sutradharudu Teki flash->dummy_byte = 1; 220ff063ed4SJagannadha Sutradharudu Teki } 221ff063ed4SJagannadha Sutradharudu Teki 2222ba863faSJagannadha Sutradharudu Teki /* Poll cmd selection */ 223898e76c9SJagannadha Sutradharudu Teki flash->poll_cmd = CMD_READ_STATUS; 224898e76c9SJagannadha Sutradharudu Teki #ifdef CONFIG_SPI_FLASH_STMICRO 225898e76c9SJagannadha Sutradharudu Teki if (params->flags & E_FSR) 226898e76c9SJagannadha Sutradharudu Teki flash->poll_cmd = CMD_FLAG_STATUS; 227898e76c9SJagannadha Sutradharudu Teki #endif 228898e76c9SJagannadha Sutradharudu Teki 229898e76c9SJagannadha Sutradharudu Teki /* Configure the BAR - discover bank cmds and read current bank */ 230ce22b922SJagannadha Sutradharudu Teki #ifdef CONFIG_SPI_FLASH_BAR 231898e76c9SJagannadha Sutradharudu Teki u8 curr_bank = 0; 232898e76c9SJagannadha Sutradharudu Teki if (flash->size > SPI_FLASH_16MB_BOUN) { 233ae242cbfSSimon Glass int ret; 234ae242cbfSSimon Glass 235898e76c9SJagannadha Sutradharudu Teki flash->bank_read_cmd = (idcode[0] == 0x01) ? 236898e76c9SJagannadha Sutradharudu Teki CMD_BANKADDR_BRRD : CMD_EXTNADDR_RDEAR; 237898e76c9SJagannadha Sutradharudu Teki flash->bank_write_cmd = (idcode[0] == 0x01) ? 238898e76c9SJagannadha Sutradharudu Teki CMD_BANKADDR_BRWR : CMD_EXTNADDR_WREAR; 239898e76c9SJagannadha Sutradharudu Teki 240ae242cbfSSimon Glass ret = spi_flash_read_common(flash, &flash->bank_read_cmd, 1, 241ae242cbfSSimon Glass &curr_bank, 1); 242ae242cbfSSimon Glass if (ret) { 243898e76c9SJagannadha Sutradharudu Teki debug("SF: fail to read bank addr register\n"); 244ae242cbfSSimon Glass return ret; 245898e76c9SJagannadha Sutradharudu Teki } 246898e76c9SJagannadha Sutradharudu Teki flash->bank_curr = curr_bank; 247898e76c9SJagannadha Sutradharudu Teki } else { 248898e76c9SJagannadha Sutradharudu Teki flash->bank_curr = curr_bank; 249898e76c9SJagannadha Sutradharudu Teki } 250898e76c9SJagannadha Sutradharudu Teki #endif 251898e76c9SJagannadha Sutradharudu Teki 252898e76c9SJagannadha Sutradharudu Teki /* Flash powers up read-only, so clear BP# bits */ 253898e76c9SJagannadha Sutradharudu Teki #if defined(CONFIG_SPI_FLASH_ATMEL) || \ 254898e76c9SJagannadha Sutradharudu Teki defined(CONFIG_SPI_FLASH_MACRONIX) || \ 255898e76c9SJagannadha Sutradharudu Teki defined(CONFIG_SPI_FLASH_SST) 256898e76c9SJagannadha Sutradharudu Teki spi_flash_cmd_write_status(flash, 0); 257898e76c9SJagannadha Sutradharudu Teki #endif 258898e76c9SJagannadha Sutradharudu Teki 259ae242cbfSSimon Glass return 0; 260898e76c9SJagannadha Sutradharudu Teki } 261898e76c9SJagannadha Sutradharudu Teki 262898e76c9SJagannadha Sutradharudu Teki #ifdef CONFIG_OF_CONTROL 263898e76c9SJagannadha Sutradharudu Teki int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) 264898e76c9SJagannadha Sutradharudu Teki { 265898e76c9SJagannadha Sutradharudu Teki fdt_addr_t addr; 266898e76c9SJagannadha Sutradharudu Teki fdt_size_t size; 267898e76c9SJagannadha Sutradharudu Teki int node; 268898e76c9SJagannadha Sutradharudu Teki 269898e76c9SJagannadha Sutradharudu Teki /* If there is no node, do nothing */ 270898e76c9SJagannadha Sutradharudu Teki node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); 271898e76c9SJagannadha Sutradharudu Teki if (node < 0) 272898e76c9SJagannadha Sutradharudu Teki return 0; 273898e76c9SJagannadha Sutradharudu Teki 274898e76c9SJagannadha Sutradharudu Teki addr = fdtdec_get_addr_size(blob, node, "memory-map", &size); 275898e76c9SJagannadha Sutradharudu Teki if (addr == FDT_ADDR_T_NONE) { 276898e76c9SJagannadha Sutradharudu Teki debug("%s: Cannot decode address\n", __func__); 277898e76c9SJagannadha Sutradharudu Teki return 0; 278898e76c9SJagannadha Sutradharudu Teki } 279898e76c9SJagannadha Sutradharudu Teki 280898e76c9SJagannadha Sutradharudu Teki if (flash->size != size) { 281898e76c9SJagannadha Sutradharudu Teki debug("%s: Memory map must cover entire device\n", __func__); 282898e76c9SJagannadha Sutradharudu Teki return -1; 283898e76c9SJagannadha Sutradharudu Teki } 284ffdb20beSMike Frysinger flash->memory_map = map_sysmem(addr, size); 285898e76c9SJagannadha Sutradharudu Teki 286898e76c9SJagannadha Sutradharudu Teki return 0; 287898e76c9SJagannadha Sutradharudu Teki } 288898e76c9SJagannadha Sutradharudu Teki #endif /* CONFIG_OF_CONTROL */ 289898e76c9SJagannadha Sutradharudu Teki 290562f8df1SHeiko Schocher #ifdef CONFIG_SYS_SPI_ST_ENABLE_WP_PIN 291562f8df1SHeiko Schocher /* enable the W#/Vpp signal to disable writing to the status register */ 292562f8df1SHeiko Schocher static int spi_enable_wp_pin(struct spi_flash *flash) 293562f8df1SHeiko Schocher { 294562f8df1SHeiko Schocher u8 status; 295562f8df1SHeiko Schocher int ret; 296562f8df1SHeiko Schocher 297562f8df1SHeiko Schocher ret = spi_flash_cmd_read_status(flash, &status); 298562f8df1SHeiko Schocher if (ret < 0) 299562f8df1SHeiko Schocher return ret; 300562f8df1SHeiko Schocher 301562f8df1SHeiko Schocher ret = spi_flash_cmd_write_status(flash, STATUS_SRWD); 302562f8df1SHeiko Schocher if (ret < 0) 303562f8df1SHeiko Schocher return ret; 304562f8df1SHeiko Schocher 305562f8df1SHeiko Schocher ret = spi_flash_cmd_write_disable(flash); 306562f8df1SHeiko Schocher if (ret < 0) 307562f8df1SHeiko Schocher return ret; 308562f8df1SHeiko Schocher 309562f8df1SHeiko Schocher return 0; 310562f8df1SHeiko Schocher } 311562f8df1SHeiko Schocher #else 312562f8df1SHeiko Schocher static int spi_enable_wp_pin(struct spi_flash *flash) 313562f8df1SHeiko Schocher { 314562f8df1SHeiko Schocher return 0; 315562f8df1SHeiko Schocher } 316562f8df1SHeiko Schocher #endif 317562f8df1SHeiko Schocher 318ae242cbfSSimon Glass /** 319ae242cbfSSimon Glass * spi_flash_probe_slave() - Probe for a SPI flash device on a bus 320ae242cbfSSimon Glass * 321ae242cbfSSimon Glass * @spi: Bus to probe 322ae242cbfSSimon Glass * @flashp: Pointer to place to put flash info, which may be NULL if the 323ae242cbfSSimon Glass * space should be allocated 324ae242cbfSSimon Glass */ 325ae242cbfSSimon Glass int spi_flash_probe_slave(struct spi_slave *spi, struct spi_flash *flash) 326898e76c9SJagannadha Sutradharudu Teki { 327898e76c9SJagannadha Sutradharudu Teki u8 idcode[5]; 328898e76c9SJagannadha Sutradharudu Teki int ret; 329898e76c9SJagannadha Sutradharudu Teki 330898e76c9SJagannadha Sutradharudu Teki /* Setup spi_slave */ 331898e76c9SJagannadha Sutradharudu Teki if (!spi) { 332898e76c9SJagannadha Sutradharudu Teki printf("SF: Failed to set up slave\n"); 333ae242cbfSSimon Glass return -ENODEV; 334898e76c9SJagannadha Sutradharudu Teki } 335898e76c9SJagannadha Sutradharudu Teki 336898e76c9SJagannadha Sutradharudu Teki /* Claim spi bus */ 337898e76c9SJagannadha Sutradharudu Teki ret = spi_claim_bus(spi); 338898e76c9SJagannadha Sutradharudu Teki if (ret) { 339898e76c9SJagannadha Sutradharudu Teki debug("SF: Failed to claim SPI bus: %d\n", ret); 340ae242cbfSSimon Glass return ret; 341898e76c9SJagannadha Sutradharudu Teki } 342898e76c9SJagannadha Sutradharudu Teki 343898e76c9SJagannadha Sutradharudu Teki /* Read the ID codes */ 344898e76c9SJagannadha Sutradharudu Teki ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); 345898e76c9SJagannadha Sutradharudu Teki if (ret) { 346898e76c9SJagannadha Sutradharudu Teki printf("SF: Failed to get idcodes\n"); 347898e76c9SJagannadha Sutradharudu Teki goto err_read_id; 348898e76c9SJagannadha Sutradharudu Teki } 349898e76c9SJagannadha Sutradharudu Teki 350898e76c9SJagannadha Sutradharudu Teki #ifdef DEBUG 351898e76c9SJagannadha Sutradharudu Teki printf("SF: Got idcodes\n"); 352898e76c9SJagannadha Sutradharudu Teki print_buffer(0, idcode, 1, sizeof(idcode), 0); 353898e76c9SJagannadha Sutradharudu Teki #endif 354898e76c9SJagannadha Sutradharudu Teki 355ae242cbfSSimon Glass if (spi_flash_validate_params(spi, idcode, flash)) { 356ae242cbfSSimon Glass ret = -EINVAL; 357898e76c9SJagannadha Sutradharudu Teki goto err_read_id; 358ae242cbfSSimon Glass } 359898e76c9SJagannadha Sutradharudu Teki 3601f436a6dSPoddar, Sourav /* Set the quad enable bit - only for quad commands */ 3611f436a6dSPoddar, Sourav if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) || 3621f436a6dSPoddar, Sourav (flash->read_cmd == CMD_READ_QUAD_IO_FAST) || 3631f436a6dSPoddar, Sourav (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) { 3641f436a6dSPoddar, Sourav if (spi_flash_set_qeb(flash, idcode[0])) { 3651f436a6dSPoddar, Sourav debug("SF: Fail to set QEB for %02x\n", idcode[0]); 366ae242cbfSSimon Glass ret = -EINVAL; 367ae242cbfSSimon Glass goto err_read_id; 3681f436a6dSPoddar, Sourav } 3691f436a6dSPoddar, Sourav } 3701f436a6dSPoddar, Sourav 371898e76c9SJagannadha Sutradharudu Teki #ifdef CONFIG_OF_CONTROL 372898e76c9SJagannadha Sutradharudu Teki if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { 373898e76c9SJagannadha Sutradharudu Teki debug("SF: FDT decode error\n"); 374ae242cbfSSimon Glass ret = -EINVAL; 375898e76c9SJagannadha Sutradharudu Teki goto err_read_id; 376898e76c9SJagannadha Sutradharudu Teki } 377898e76c9SJagannadha Sutradharudu Teki #endif 378898e76c9SJagannadha Sutradharudu Teki #ifndef CONFIG_SPL_BUILD 379898e76c9SJagannadha Sutradharudu Teki printf("SF: Detected %s with page size ", flash->name); 380898e76c9SJagannadha Sutradharudu Teki print_size(flash->page_size, ", erase size "); 381898e76c9SJagannadha Sutradharudu Teki print_size(flash->erase_size, ", total "); 382898e76c9SJagannadha Sutradharudu Teki print_size(flash->size, ""); 383898e76c9SJagannadha Sutradharudu Teki if (flash->memory_map) 384898e76c9SJagannadha Sutradharudu Teki printf(", mapped at %p", flash->memory_map); 385898e76c9SJagannadha Sutradharudu Teki puts("\n"); 386898e76c9SJagannadha Sutradharudu Teki #endif 387898e76c9SJagannadha Sutradharudu Teki #ifndef CONFIG_SPI_FLASH_BAR 388f77f4691SJagannadha Sutradharudu Teki if (((flash->dual_flash == SF_SINGLE_FLASH) && 389f77f4691SJagannadha Sutradharudu Teki (flash->size > SPI_FLASH_16MB_BOUN)) || 390f77f4691SJagannadha Sutradharudu Teki ((flash->dual_flash > SF_SINGLE_FLASH) && 391f77f4691SJagannadha Sutradharudu Teki (flash->size > SPI_FLASH_16MB_BOUN << 1))) { 392898e76c9SJagannadha Sutradharudu Teki puts("SF: Warning - Only lower 16MiB accessible,"); 393898e76c9SJagannadha Sutradharudu Teki puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); 394898e76c9SJagannadha Sutradharudu Teki } 395898e76c9SJagannadha Sutradharudu Teki #endif 396562f8df1SHeiko Schocher if (spi_enable_wp_pin(flash)) 397562f8df1SHeiko Schocher puts("Enable WP pin failed\n"); 398898e76c9SJagannadha Sutradharudu Teki 399898e76c9SJagannadha Sutradharudu Teki /* Release spi bus */ 400898e76c9SJagannadha Sutradharudu Teki spi_release_bus(spi); 401898e76c9SJagannadha Sutradharudu Teki 402ae242cbfSSimon Glass return 0; 403898e76c9SJagannadha Sutradharudu Teki 404898e76c9SJagannadha Sutradharudu Teki err_read_id: 405898e76c9SJagannadha Sutradharudu Teki spi_release_bus(spi); 406ae242cbfSSimon Glass return ret; 407ae242cbfSSimon Glass } 408ae242cbfSSimon Glass 409fbb09918SSimon Glass #ifndef CONFIG_DM_SPI_FLASH 410fbb09918SSimon Glass struct spi_flash *spi_flash_probe_tail(struct spi_slave *bus) 411ae242cbfSSimon Glass { 412ae242cbfSSimon Glass struct spi_flash *flash; 413ae242cbfSSimon Glass 414ae242cbfSSimon Glass /* Allocate space if needed (not used by sf-uclass */ 415ae242cbfSSimon Glass flash = calloc(1, sizeof(*flash)); 416ae242cbfSSimon Glass if (!flash) { 417ae242cbfSSimon Glass debug("SF: Failed to allocate spi_flash\n"); 418898e76c9SJagannadha Sutradharudu Teki return NULL; 419898e76c9SJagannadha Sutradharudu Teki } 420898e76c9SJagannadha Sutradharudu Teki 421ae242cbfSSimon Glass if (spi_flash_probe_slave(bus, flash)) { 422ae242cbfSSimon Glass spi_free_slave(bus); 423ae242cbfSSimon Glass free(flash); 424ae242cbfSSimon Glass return NULL; 425ae242cbfSSimon Glass } 426ae242cbfSSimon Glass 427ae242cbfSSimon Glass return flash; 428ae242cbfSSimon Glass } 429ae242cbfSSimon Glass 430ae242cbfSSimon Glass struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs, 4310efc0249SSimon Glass unsigned int max_hz, unsigned int spi_mode) 4320efc0249SSimon Glass { 433ae242cbfSSimon Glass struct spi_slave *bus; 4340efc0249SSimon Glass 435ae242cbfSSimon Glass bus = spi_setup_slave(busnum, cs, max_hz, spi_mode); 436ae242cbfSSimon Glass return spi_flash_probe_tail(bus); 4370efc0249SSimon Glass } 4380efc0249SSimon Glass 4390efc0249SSimon Glass #ifdef CONFIG_OF_SPI_FLASH 4400efc0249SSimon Glass struct spi_flash *spi_flash_probe_fdt(const void *blob, int slave_node, 4410efc0249SSimon Glass int spi_node) 4420efc0249SSimon Glass { 443ae242cbfSSimon Glass struct spi_slave *bus; 4440efc0249SSimon Glass 445ae242cbfSSimon Glass bus = spi_setup_slave_fdt(blob, slave_node, spi_node); 446ae242cbfSSimon Glass return spi_flash_probe_tail(bus); 4470efc0249SSimon Glass } 4480efc0249SSimon Glass #endif 4490efc0249SSimon Glass 450898e76c9SJagannadha Sutradharudu Teki void spi_flash_free(struct spi_flash *flash) 451898e76c9SJagannadha Sutradharudu Teki { 452898e76c9SJagannadha Sutradharudu Teki spi_free_slave(flash->spi); 453898e76c9SJagannadha Sutradharudu Teki free(flash); 454898e76c9SJagannadha Sutradharudu Teki } 455fbb09918SSimon Glass 456fbb09918SSimon Glass #else /* defined CONFIG_DM_SPI_FLASH */ 457fbb09918SSimon Glass 458fbb09918SSimon Glass static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len, 459fbb09918SSimon Glass void *buf) 460fbb09918SSimon Glass { 461fbb09918SSimon Glass struct spi_flash *flash = dev->uclass_priv; 462fbb09918SSimon Glass 463fbb09918SSimon Glass return spi_flash_cmd_read_ops(flash, offset, len, buf); 464fbb09918SSimon Glass } 465fbb09918SSimon Glass 466fbb09918SSimon Glass int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len, 467fbb09918SSimon Glass const void *buf) 468fbb09918SSimon Glass { 469fbb09918SSimon Glass struct spi_flash *flash = dev->uclass_priv; 470fbb09918SSimon Glass 471fbb09918SSimon Glass return spi_flash_cmd_write_ops(flash, offset, len, buf); 472fbb09918SSimon Glass } 473fbb09918SSimon Glass 474fbb09918SSimon Glass int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len) 475fbb09918SSimon Glass { 476fbb09918SSimon Glass struct spi_flash *flash = dev->uclass_priv; 477fbb09918SSimon Glass 478fbb09918SSimon Glass return spi_flash_cmd_erase_ops(flash, offset, len); 479fbb09918SSimon Glass } 480fbb09918SSimon Glass 481fbb09918SSimon Glass int spi_flash_std_probe(struct udevice *dev) 482fbb09918SSimon Glass { 483fbb09918SSimon Glass struct spi_slave *slave = dev_get_parentdata(dev); 484*d0cff03eSSimon Glass struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev); 485fbb09918SSimon Glass struct spi_flash *flash; 486fbb09918SSimon Glass 487fbb09918SSimon Glass flash = dev->uclass_priv; 488fbb09918SSimon Glass flash->dev = dev; 489*d0cff03eSSimon Glass debug("%s: slave=%p, cs=%d\n", __func__, slave, plat->cs); 490fbb09918SSimon Glass return spi_flash_probe_slave(slave, flash); 491fbb09918SSimon Glass } 492fbb09918SSimon Glass 493fbb09918SSimon Glass static const struct dm_spi_flash_ops spi_flash_std_ops = { 494fbb09918SSimon Glass .read = spi_flash_std_read, 495fbb09918SSimon Glass .write = spi_flash_std_write, 496fbb09918SSimon Glass .erase = spi_flash_std_erase, 497fbb09918SSimon Glass }; 498fbb09918SSimon Glass 499fbb09918SSimon Glass static const struct udevice_id spi_flash_std_ids[] = { 500fbb09918SSimon Glass { .compatible = "spi-flash" }, 501fbb09918SSimon Glass { } 502fbb09918SSimon Glass }; 503fbb09918SSimon Glass 504fbb09918SSimon Glass U_BOOT_DRIVER(spi_flash_std) = { 505fbb09918SSimon Glass .name = "spi_flash_std", 506fbb09918SSimon Glass .id = UCLASS_SPI_FLASH, 507fbb09918SSimon Glass .of_match = spi_flash_std_ids, 508fbb09918SSimon Glass .probe = spi_flash_std_probe, 509fbb09918SSimon Glass .priv_auto_alloc_size = sizeof(struct spi_flash), 510fbb09918SSimon Glass .ops = &spi_flash_std_ops, 511fbb09918SSimon Glass }; 512fbb09918SSimon Glass 513fbb09918SSimon Glass #endif /* CONFIG_DM_SPI_FLASH */ 514