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 102ae242cbfSSimon Glass static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode, 103ae242cbfSSimon Glass struct spi_flash *flash) 104898e76c9SJagannadha Sutradharudu Teki { 105898e76c9SJagannadha Sutradharudu Teki const struct spi_flash_params *params; 1064e09cc1eSJagannadha Sutradharudu Teki u8 cmd; 107898e76c9SJagannadha Sutradharudu Teki u16 jedec = idcode[1] << 8 | idcode[2]; 108898e76c9SJagannadha Sutradharudu Teki u16 ext_jedec = idcode[3] << 8 | idcode[4]; 109898e76c9SJagannadha Sutradharudu Teki 110ae242cbfSSimon Glass /* Validate params from spi_flash_params table */ 11133adfb5fSJagannadha Sutradharudu Teki params = spi_flash_params_table; 11233adfb5fSJagannadha Sutradharudu Teki for (; params->name != NULL; params++) { 113898e76c9SJagannadha Sutradharudu Teki if ((params->jedec >> 16) == idcode[0]) { 114898e76c9SJagannadha Sutradharudu Teki if ((params->jedec & 0xFFFF) == jedec) { 115898e76c9SJagannadha Sutradharudu Teki if (params->ext_jedec == 0) 116898e76c9SJagannadha Sutradharudu Teki break; 117898e76c9SJagannadha Sutradharudu Teki else if (params->ext_jedec == ext_jedec) 118898e76c9SJagannadha Sutradharudu Teki break; 119898e76c9SJagannadha Sutradharudu Teki } 120898e76c9SJagannadha Sutradharudu Teki } 121898e76c9SJagannadha Sutradharudu Teki } 122898e76c9SJagannadha Sutradharudu Teki 12333adfb5fSJagannadha Sutradharudu Teki if (!params->name) { 124898e76c9SJagannadha Sutradharudu Teki printf("SF: Unsupported flash IDs: "); 125898e76c9SJagannadha Sutradharudu Teki printf("manuf %02x, jedec %04x, ext_jedec %04x\n", 126898e76c9SJagannadha Sutradharudu Teki idcode[0], jedec, ext_jedec); 127ae242cbfSSimon Glass return -EPROTONOSUPPORT; 128898e76c9SJagannadha Sutradharudu Teki } 129898e76c9SJagannadha Sutradharudu Teki 130469146c0SJagannadha Sutradharudu Teki /* Assign spi data */ 131898e76c9SJagannadha Sutradharudu Teki flash->spi = spi; 132898e76c9SJagannadha Sutradharudu Teki flash->name = params->name; 133ce22b922SJagannadha Sutradharudu Teki flash->memory_map = spi->memory_map; 134f77f4691SJagannadha Sutradharudu Teki flash->dual_flash = flash->spi->option; 135*be7be78eSBin Meng #ifdef CONFIG_DM_SPI_FLASH 136*be7be78eSBin Meng flash->flags = params->flags; 137*be7be78eSBin Meng #endif 138898e76c9SJagannadha Sutradharudu Teki 139898e76c9SJagannadha Sutradharudu Teki /* Assign spi_flash ops */ 140fbb09918SSimon Glass #ifndef CONFIG_DM_SPI_FLASH 141898e76c9SJagannadha Sutradharudu Teki flash->write = spi_flash_cmd_write_ops; 142fbb09918SSimon Glass #if defined(CONFIG_SPI_FLASH_SST) 14354ba653aSJagannadha Sutradharudu Teki if (params->flags & SST_WR) { 14454ba653aSJagannadha Sutradharudu Teki if (flash->spi->op_mode_tx & SPI_OPM_TX_BP) 14554ba653aSJagannadha Sutradharudu Teki flash->write = sst_write_bp; 14654ba653aSJagannadha Sutradharudu Teki else 147898e76c9SJagannadha Sutradharudu Teki flash->write = sst_write_wp; 14854ba653aSJagannadha Sutradharudu Teki } 149898e76c9SJagannadha Sutradharudu Teki #endif 150898e76c9SJagannadha Sutradharudu Teki flash->erase = spi_flash_cmd_erase_ops; 151898e76c9SJagannadha Sutradharudu Teki flash->read = spi_flash_cmd_read_ops; 152fbb09918SSimon Glass #endif 153898e76c9SJagannadha Sutradharudu Teki 154898e76c9SJagannadha Sutradharudu Teki /* Compute the flash size */ 155056fbc73SJagannadha Sutradharudu Teki flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0; 156bf64035aSMarek Vasut /* 157bf64035aSMarek Vasut * The Spansion S25FL032P and S25FL064P have 256b pages, yet use the 158bf64035aSMarek Vasut * 0x4d00 Extended JEDEC code. The rest of the Spansion flashes with 159bf64035aSMarek Vasut * the 0x4d00 Extended JEDEC code have 512b pages. All of the others 160bf64035aSMarek Vasut * have 256b pages. 161bf64035aSMarek Vasut */ 162bf64035aSMarek Vasut if (ext_jedec == 0x4d00) { 163bf64035aSMarek Vasut if ((jedec == 0x0215) || (jedec == 0x216)) 164bf64035aSMarek Vasut flash->page_size = 256; 165bf64035aSMarek Vasut else 166bf64035aSMarek Vasut flash->page_size = 512; 167bf64035aSMarek Vasut } else { 168bf64035aSMarek Vasut flash->page_size = 256; 169bf64035aSMarek Vasut } 170bf64035aSMarek Vasut flash->page_size <<= flash->shift; 171056fbc73SJagannadha Sutradharudu Teki flash->sector_size = params->sector_size << flash->shift; 172056fbc73SJagannadha Sutradharudu Teki flash->size = flash->sector_size * params->nr_sectors << flash->shift; 173b902e07cSJagannadha Sutradharudu Teki #ifdef CONFIG_SF_DUAL_FLASH 174f77f4691SJagannadha Sutradharudu Teki if (flash->dual_flash & SF_DUAL_STACKED_FLASH) 175f77f4691SJagannadha Sutradharudu Teki flash->size <<= 1; 176b902e07cSJagannadha Sutradharudu Teki #endif 177898e76c9SJagannadha Sutradharudu Teki 178898e76c9SJagannadha Sutradharudu Teki /* Compute erase sector and command */ 179898e76c9SJagannadha Sutradharudu Teki if (params->flags & SECT_4K) { 180898e76c9SJagannadha Sutradharudu Teki flash->erase_cmd = CMD_ERASE_4K; 181056fbc73SJagannadha Sutradharudu Teki flash->erase_size = 4096 << flash->shift; 182898e76c9SJagannadha Sutradharudu Teki } else if (params->flags & SECT_32K) { 183898e76c9SJagannadha Sutradharudu Teki flash->erase_cmd = CMD_ERASE_32K; 184056fbc73SJagannadha Sutradharudu Teki flash->erase_size = 32768 << flash->shift; 185898e76c9SJagannadha Sutradharudu Teki } else { 186898e76c9SJagannadha Sutradharudu Teki flash->erase_cmd = CMD_ERASE_64K; 187898e76c9SJagannadha Sutradharudu Teki flash->erase_size = flash->sector_size; 188898e76c9SJagannadha Sutradharudu Teki } 189898e76c9SJagannadha Sutradharudu Teki 1904e09cc1eSJagannadha Sutradharudu Teki /* Look for the fastest read cmd */ 1914e09cc1eSJagannadha Sutradharudu Teki cmd = fls(params->e_rd_cmd & flash->spi->op_mode_rx); 1924e09cc1eSJagannadha Sutradharudu Teki if (cmd) { 1934e09cc1eSJagannadha Sutradharudu Teki cmd = spi_read_cmds_array[cmd - 1]; 1944e09cc1eSJagannadha Sutradharudu Teki flash->read_cmd = cmd; 1954e09cc1eSJagannadha Sutradharudu Teki } else { 1962ba863faSJagannadha Sutradharudu Teki /* Go for default supported read cmd */ 1974e09cc1eSJagannadha Sutradharudu Teki flash->read_cmd = CMD_READ_ARRAY_FAST; 1984e09cc1eSJagannadha Sutradharudu Teki } 1994e09cc1eSJagannadha Sutradharudu Teki 2003163aaa6SJagannadha Sutradharudu Teki /* Not require to look for fastest only two write cmds yet */ 2013163aaa6SJagannadha Sutradharudu Teki if (params->flags & WR_QPP && flash->spi->op_mode_tx & SPI_OPM_TX_QPP) 2023163aaa6SJagannadha Sutradharudu Teki flash->write_cmd = CMD_QUAD_PAGE_PROGRAM; 2033163aaa6SJagannadha Sutradharudu Teki else 2043163aaa6SJagannadha Sutradharudu Teki /* Go for default supported write cmd */ 2053163aaa6SJagannadha Sutradharudu Teki flash->write_cmd = CMD_PAGE_PROGRAM; 2063163aaa6SJagannadha Sutradharudu Teki 207ff063ed4SJagannadha Sutradharudu Teki /* Read dummy_byte: dummy byte is determined based on the 208ff063ed4SJagannadha Sutradharudu Teki * dummy cycles of a particular command. 209ff063ed4SJagannadha Sutradharudu Teki * Fast commands - dummy_byte = dummy_cycles/8 210ff063ed4SJagannadha Sutradharudu Teki * I/O commands- dummy_byte = (dummy_cycles * no.of lines)/8 211ff063ed4SJagannadha Sutradharudu Teki * For I/O commands except cmd[0] everything goes on no.of lines 212ff063ed4SJagannadha Sutradharudu Teki * based on particular command but incase of fast commands except 213ff063ed4SJagannadha Sutradharudu Teki * data all go on single line irrespective of command. 214ff063ed4SJagannadha Sutradharudu Teki */ 215ff063ed4SJagannadha Sutradharudu Teki switch (flash->read_cmd) { 216ff063ed4SJagannadha Sutradharudu Teki case CMD_READ_QUAD_IO_FAST: 217ff063ed4SJagannadha Sutradharudu Teki flash->dummy_byte = 2; 218ff063ed4SJagannadha Sutradharudu Teki break; 219ff063ed4SJagannadha Sutradharudu Teki case CMD_READ_ARRAY_SLOW: 220ff063ed4SJagannadha Sutradharudu Teki flash->dummy_byte = 0; 221ff063ed4SJagannadha Sutradharudu Teki break; 222ff063ed4SJagannadha Sutradharudu Teki default: 223ff063ed4SJagannadha Sutradharudu Teki flash->dummy_byte = 1; 224ff063ed4SJagannadha Sutradharudu Teki } 225ff063ed4SJagannadha Sutradharudu Teki 2262ba863faSJagannadha Sutradharudu Teki /* Poll cmd selection */ 227898e76c9SJagannadha Sutradharudu Teki flash->poll_cmd = CMD_READ_STATUS; 228898e76c9SJagannadha Sutradharudu Teki #ifdef CONFIG_SPI_FLASH_STMICRO 229898e76c9SJagannadha Sutradharudu Teki if (params->flags & E_FSR) 230898e76c9SJagannadha Sutradharudu Teki flash->poll_cmd = CMD_FLAG_STATUS; 231898e76c9SJagannadha Sutradharudu Teki #endif 232898e76c9SJagannadha Sutradharudu Teki 233898e76c9SJagannadha Sutradharudu Teki /* Configure the BAR - discover bank cmds and read current bank */ 234ce22b922SJagannadha Sutradharudu Teki #ifdef CONFIG_SPI_FLASH_BAR 235898e76c9SJagannadha Sutradharudu Teki u8 curr_bank = 0; 236898e76c9SJagannadha Sutradharudu Teki if (flash->size > SPI_FLASH_16MB_BOUN) { 237ae242cbfSSimon Glass int ret; 238ae242cbfSSimon Glass 239898e76c9SJagannadha Sutradharudu Teki flash->bank_read_cmd = (idcode[0] == 0x01) ? 240898e76c9SJagannadha Sutradharudu Teki CMD_BANKADDR_BRRD : CMD_EXTNADDR_RDEAR; 241898e76c9SJagannadha Sutradharudu Teki flash->bank_write_cmd = (idcode[0] == 0x01) ? 242898e76c9SJagannadha Sutradharudu Teki CMD_BANKADDR_BRWR : CMD_EXTNADDR_WREAR; 243898e76c9SJagannadha Sutradharudu Teki 244ae242cbfSSimon Glass ret = spi_flash_read_common(flash, &flash->bank_read_cmd, 1, 245ae242cbfSSimon Glass &curr_bank, 1); 246ae242cbfSSimon Glass if (ret) { 247898e76c9SJagannadha Sutradharudu Teki debug("SF: fail to read bank addr register\n"); 248ae242cbfSSimon Glass return ret; 249898e76c9SJagannadha Sutradharudu Teki } 250898e76c9SJagannadha Sutradharudu Teki flash->bank_curr = curr_bank; 251898e76c9SJagannadha Sutradharudu Teki } else { 252898e76c9SJagannadha Sutradharudu Teki flash->bank_curr = curr_bank; 253898e76c9SJagannadha Sutradharudu Teki } 254898e76c9SJagannadha Sutradharudu Teki #endif 255898e76c9SJagannadha Sutradharudu Teki 256898e76c9SJagannadha Sutradharudu Teki /* Flash powers up read-only, so clear BP# bits */ 257898e76c9SJagannadha Sutradharudu Teki #if defined(CONFIG_SPI_FLASH_ATMEL) || \ 258898e76c9SJagannadha Sutradharudu Teki defined(CONFIG_SPI_FLASH_MACRONIX) || \ 259898e76c9SJagannadha Sutradharudu Teki defined(CONFIG_SPI_FLASH_SST) 260898e76c9SJagannadha Sutradharudu Teki spi_flash_cmd_write_status(flash, 0); 261898e76c9SJagannadha Sutradharudu Teki #endif 262898e76c9SJagannadha Sutradharudu Teki 263ae242cbfSSimon Glass return 0; 264898e76c9SJagannadha Sutradharudu Teki } 265898e76c9SJagannadha Sutradharudu Teki 266898e76c9SJagannadha Sutradharudu Teki #ifdef CONFIG_OF_CONTROL 267898e76c9SJagannadha Sutradharudu Teki int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) 268898e76c9SJagannadha Sutradharudu Teki { 269898e76c9SJagannadha Sutradharudu Teki fdt_addr_t addr; 270898e76c9SJagannadha Sutradharudu Teki fdt_size_t size; 271898e76c9SJagannadha Sutradharudu Teki int node; 272898e76c9SJagannadha Sutradharudu Teki 273898e76c9SJagannadha Sutradharudu Teki /* If there is no node, do nothing */ 274898e76c9SJagannadha Sutradharudu Teki node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); 275898e76c9SJagannadha Sutradharudu Teki if (node < 0) 276898e76c9SJagannadha Sutradharudu Teki return 0; 277898e76c9SJagannadha Sutradharudu Teki 278898e76c9SJagannadha Sutradharudu Teki addr = fdtdec_get_addr_size(blob, node, "memory-map", &size); 279898e76c9SJagannadha Sutradharudu Teki if (addr == FDT_ADDR_T_NONE) { 280898e76c9SJagannadha Sutradharudu Teki debug("%s: Cannot decode address\n", __func__); 281898e76c9SJagannadha Sutradharudu Teki return 0; 282898e76c9SJagannadha Sutradharudu Teki } 283898e76c9SJagannadha Sutradharudu Teki 284898e76c9SJagannadha Sutradharudu Teki if (flash->size != size) { 285898e76c9SJagannadha Sutradharudu Teki debug("%s: Memory map must cover entire device\n", __func__); 286898e76c9SJagannadha Sutradharudu Teki return -1; 287898e76c9SJagannadha Sutradharudu Teki } 288ffdb20beSMike Frysinger flash->memory_map = map_sysmem(addr, size); 289898e76c9SJagannadha Sutradharudu Teki 290898e76c9SJagannadha Sutradharudu Teki return 0; 291898e76c9SJagannadha Sutradharudu Teki } 292898e76c9SJagannadha Sutradharudu Teki #endif /* CONFIG_OF_CONTROL */ 293898e76c9SJagannadha Sutradharudu Teki 294ae242cbfSSimon Glass /** 295ae242cbfSSimon Glass * spi_flash_probe_slave() - Probe for a SPI flash device on a bus 296ae242cbfSSimon Glass * 297ae242cbfSSimon Glass * @spi: Bus to probe 298ae242cbfSSimon Glass * @flashp: Pointer to place to put flash info, which may be NULL if the 299ae242cbfSSimon Glass * space should be allocated 300ae242cbfSSimon Glass */ 301ae242cbfSSimon Glass int spi_flash_probe_slave(struct spi_slave *spi, struct spi_flash *flash) 302898e76c9SJagannadha Sutradharudu Teki { 303898e76c9SJagannadha Sutradharudu Teki u8 idcode[5]; 304898e76c9SJagannadha Sutradharudu Teki int ret; 305898e76c9SJagannadha Sutradharudu Teki 306898e76c9SJagannadha Sutradharudu Teki /* Setup spi_slave */ 307898e76c9SJagannadha Sutradharudu Teki if (!spi) { 308898e76c9SJagannadha Sutradharudu Teki printf("SF: Failed to set up slave\n"); 309ae242cbfSSimon Glass return -ENODEV; 310898e76c9SJagannadha Sutradharudu Teki } 311898e76c9SJagannadha Sutradharudu Teki 312898e76c9SJagannadha Sutradharudu Teki /* Claim spi bus */ 313898e76c9SJagannadha Sutradharudu Teki ret = spi_claim_bus(spi); 314898e76c9SJagannadha Sutradharudu Teki if (ret) { 315898e76c9SJagannadha Sutradharudu Teki debug("SF: Failed to claim SPI bus: %d\n", ret); 316ae242cbfSSimon Glass return ret; 317898e76c9SJagannadha Sutradharudu Teki } 318898e76c9SJagannadha Sutradharudu Teki 319898e76c9SJagannadha Sutradharudu Teki /* Read the ID codes */ 320898e76c9SJagannadha Sutradharudu Teki ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); 321898e76c9SJagannadha Sutradharudu Teki if (ret) { 322898e76c9SJagannadha Sutradharudu Teki printf("SF: Failed to get idcodes\n"); 323898e76c9SJagannadha Sutradharudu Teki goto err_read_id; 324898e76c9SJagannadha Sutradharudu Teki } 325898e76c9SJagannadha Sutradharudu Teki 326898e76c9SJagannadha Sutradharudu Teki #ifdef DEBUG 327898e76c9SJagannadha Sutradharudu Teki printf("SF: Got idcodes\n"); 328898e76c9SJagannadha Sutradharudu Teki print_buffer(0, idcode, 1, sizeof(idcode), 0); 329898e76c9SJagannadha Sutradharudu Teki #endif 330898e76c9SJagannadha Sutradharudu Teki 331ae242cbfSSimon Glass if (spi_flash_validate_params(spi, idcode, flash)) { 332ae242cbfSSimon Glass ret = -EINVAL; 333898e76c9SJagannadha Sutradharudu Teki goto err_read_id; 334ae242cbfSSimon Glass } 335898e76c9SJagannadha Sutradharudu Teki 3361f436a6dSPoddar, Sourav /* Set the quad enable bit - only for quad commands */ 3371f436a6dSPoddar, Sourav if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) || 3381f436a6dSPoddar, Sourav (flash->read_cmd == CMD_READ_QUAD_IO_FAST) || 3391f436a6dSPoddar, Sourav (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) { 3401f436a6dSPoddar, Sourav if (spi_flash_set_qeb(flash, idcode[0])) { 3411f436a6dSPoddar, Sourav debug("SF: Fail to set QEB for %02x\n", idcode[0]); 342ae242cbfSSimon Glass ret = -EINVAL; 343ae242cbfSSimon Glass goto err_read_id; 3441f436a6dSPoddar, Sourav } 3451f436a6dSPoddar, Sourav } 3461f436a6dSPoddar, Sourav 347898e76c9SJagannadha Sutradharudu Teki #ifdef CONFIG_OF_CONTROL 348898e76c9SJagannadha Sutradharudu Teki if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { 349898e76c9SJagannadha Sutradharudu Teki debug("SF: FDT decode error\n"); 350ae242cbfSSimon Glass ret = -EINVAL; 351898e76c9SJagannadha Sutradharudu Teki goto err_read_id; 352898e76c9SJagannadha Sutradharudu Teki } 353898e76c9SJagannadha Sutradharudu Teki #endif 354898e76c9SJagannadha Sutradharudu Teki #ifndef CONFIG_SPL_BUILD 355898e76c9SJagannadha Sutradharudu Teki printf("SF: Detected %s with page size ", flash->name); 356898e76c9SJagannadha Sutradharudu Teki print_size(flash->page_size, ", erase size "); 357898e76c9SJagannadha Sutradharudu Teki print_size(flash->erase_size, ", total "); 358898e76c9SJagannadha Sutradharudu Teki print_size(flash->size, ""); 359898e76c9SJagannadha Sutradharudu Teki if (flash->memory_map) 360898e76c9SJagannadha Sutradharudu Teki printf(", mapped at %p", flash->memory_map); 361898e76c9SJagannadha Sutradharudu Teki puts("\n"); 362898e76c9SJagannadha Sutradharudu Teki #endif 363898e76c9SJagannadha Sutradharudu Teki #ifndef CONFIG_SPI_FLASH_BAR 364f77f4691SJagannadha Sutradharudu Teki if (((flash->dual_flash == SF_SINGLE_FLASH) && 365f77f4691SJagannadha Sutradharudu Teki (flash->size > SPI_FLASH_16MB_BOUN)) || 366f77f4691SJagannadha Sutradharudu Teki ((flash->dual_flash > SF_SINGLE_FLASH) && 367f77f4691SJagannadha Sutradharudu Teki (flash->size > SPI_FLASH_16MB_BOUN << 1))) { 368898e76c9SJagannadha Sutradharudu Teki puts("SF: Warning - Only lower 16MiB accessible,"); 369898e76c9SJagannadha Sutradharudu Teki puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); 370898e76c9SJagannadha Sutradharudu Teki } 371898e76c9SJagannadha Sutradharudu Teki #endif 372898e76c9SJagannadha Sutradharudu Teki 373898e76c9SJagannadha Sutradharudu Teki /* Release spi bus */ 374898e76c9SJagannadha Sutradharudu Teki spi_release_bus(spi); 375898e76c9SJagannadha Sutradharudu Teki 376ae242cbfSSimon Glass return 0; 377898e76c9SJagannadha Sutradharudu Teki 378898e76c9SJagannadha Sutradharudu Teki err_read_id: 379898e76c9SJagannadha Sutradharudu Teki spi_release_bus(spi); 380ae242cbfSSimon Glass return ret; 381ae242cbfSSimon Glass } 382ae242cbfSSimon Glass 383fbb09918SSimon Glass #ifndef CONFIG_DM_SPI_FLASH 384fbb09918SSimon Glass struct spi_flash *spi_flash_probe_tail(struct spi_slave *bus) 385ae242cbfSSimon Glass { 386ae242cbfSSimon Glass struct spi_flash *flash; 387ae242cbfSSimon Glass 388ae242cbfSSimon Glass /* Allocate space if needed (not used by sf-uclass */ 389ae242cbfSSimon Glass flash = calloc(1, sizeof(*flash)); 390ae242cbfSSimon Glass if (!flash) { 391ae242cbfSSimon Glass debug("SF: Failed to allocate spi_flash\n"); 392898e76c9SJagannadha Sutradharudu Teki return NULL; 393898e76c9SJagannadha Sutradharudu Teki } 394898e76c9SJagannadha Sutradharudu Teki 395ae242cbfSSimon Glass if (spi_flash_probe_slave(bus, flash)) { 396ae242cbfSSimon Glass spi_free_slave(bus); 397ae242cbfSSimon Glass free(flash); 398ae242cbfSSimon Glass return NULL; 399ae242cbfSSimon Glass } 400ae242cbfSSimon Glass 401ae242cbfSSimon Glass return flash; 402ae242cbfSSimon Glass } 403ae242cbfSSimon Glass 404ae242cbfSSimon Glass struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs, 4050efc0249SSimon Glass unsigned int max_hz, unsigned int spi_mode) 4060efc0249SSimon Glass { 407ae242cbfSSimon Glass struct spi_slave *bus; 4080efc0249SSimon Glass 409ae242cbfSSimon Glass bus = spi_setup_slave(busnum, cs, max_hz, spi_mode); 4104fbad92eSPeng Fan if (!bus) 4114fbad92eSPeng Fan return NULL; 412ae242cbfSSimon Glass return spi_flash_probe_tail(bus); 4130efc0249SSimon Glass } 4140efc0249SSimon Glass 4150efc0249SSimon Glass #ifdef CONFIG_OF_SPI_FLASH 4160efc0249SSimon Glass struct spi_flash *spi_flash_probe_fdt(const void *blob, int slave_node, 4170efc0249SSimon Glass int spi_node) 4180efc0249SSimon Glass { 419ae242cbfSSimon Glass struct spi_slave *bus; 4200efc0249SSimon Glass 421ae242cbfSSimon Glass bus = spi_setup_slave_fdt(blob, slave_node, spi_node); 4224fbad92eSPeng Fan if (!bus) 4234fbad92eSPeng Fan return NULL; 424ae242cbfSSimon Glass return spi_flash_probe_tail(bus); 4250efc0249SSimon Glass } 4260efc0249SSimon Glass #endif 4270efc0249SSimon Glass 428898e76c9SJagannadha Sutradharudu Teki void spi_flash_free(struct spi_flash *flash) 429898e76c9SJagannadha Sutradharudu Teki { 430898e76c9SJagannadha Sutradharudu Teki spi_free_slave(flash->spi); 431898e76c9SJagannadha Sutradharudu Teki free(flash); 432898e76c9SJagannadha Sutradharudu Teki } 433fbb09918SSimon Glass 434fbb09918SSimon Glass #else /* defined CONFIG_DM_SPI_FLASH */ 435fbb09918SSimon Glass 436fbb09918SSimon Glass static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len, 437fbb09918SSimon Glass void *buf) 438fbb09918SSimon Glass { 439e564f054SSimon Glass struct spi_flash *flash = dev_get_uclass_priv(dev); 440fbb09918SSimon Glass 441fbb09918SSimon Glass return spi_flash_cmd_read_ops(flash, offset, len, buf); 442fbb09918SSimon Glass } 443fbb09918SSimon Glass 444fbb09918SSimon Glass int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len, 445fbb09918SSimon Glass const void *buf) 446fbb09918SSimon Glass { 447e564f054SSimon Glass struct spi_flash *flash = dev_get_uclass_priv(dev); 448fbb09918SSimon Glass 449fbb09918SSimon Glass return spi_flash_cmd_write_ops(flash, offset, len, buf); 450fbb09918SSimon Glass } 451fbb09918SSimon Glass 452fbb09918SSimon Glass int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len) 453fbb09918SSimon Glass { 454e564f054SSimon Glass struct spi_flash *flash = dev_get_uclass_priv(dev); 455fbb09918SSimon Glass 456fbb09918SSimon Glass return spi_flash_cmd_erase_ops(flash, offset, len); 457fbb09918SSimon Glass } 458fbb09918SSimon Glass 459fbb09918SSimon Glass int spi_flash_std_probe(struct udevice *dev) 460fbb09918SSimon Glass { 461fbb09918SSimon Glass struct spi_slave *slave = dev_get_parentdata(dev); 462d0cff03eSSimon Glass struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev); 463fbb09918SSimon Glass struct spi_flash *flash; 464fbb09918SSimon Glass 465e564f054SSimon Glass flash = dev_get_uclass_priv(dev); 466fbb09918SSimon Glass flash->dev = dev; 467d0cff03eSSimon Glass debug("%s: slave=%p, cs=%d\n", __func__, slave, plat->cs); 468fbb09918SSimon Glass return spi_flash_probe_slave(slave, flash); 469fbb09918SSimon Glass } 470fbb09918SSimon Glass 471fbb09918SSimon Glass static const struct dm_spi_flash_ops spi_flash_std_ops = { 472fbb09918SSimon Glass .read = spi_flash_std_read, 473fbb09918SSimon Glass .write = spi_flash_std_write, 474fbb09918SSimon Glass .erase = spi_flash_std_erase, 475fbb09918SSimon Glass }; 476fbb09918SSimon Glass 477fbb09918SSimon Glass static const struct udevice_id spi_flash_std_ids[] = { 478fbb09918SSimon Glass { .compatible = "spi-flash" }, 479fbb09918SSimon Glass { } 480fbb09918SSimon Glass }; 481fbb09918SSimon Glass 482fbb09918SSimon Glass U_BOOT_DRIVER(spi_flash_std) = { 483fbb09918SSimon Glass .name = "spi_flash_std", 484fbb09918SSimon Glass .id = UCLASS_SPI_FLASH, 485fbb09918SSimon Glass .of_match = spi_flash_std_ids, 486fbb09918SSimon Glass .probe = spi_flash_std_probe, 487fbb09918SSimon Glass .priv_auto_alloc_size = sizeof(struct spi_flash), 488fbb09918SSimon Glass .ops = &spi_flash_std_ops, 489fbb09918SSimon Glass }; 490fbb09918SSimon Glass 491fbb09918SSimon Glass #endif /* CONFIG_DM_SPI_FLASH */ 492