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; 135be7be78eSBin Meng #ifdef CONFIG_DM_SPI_FLASH 136be7be78eSBin Meng flash->flags = params->flags; 137be7be78eSBin 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 190*c650ca7bSJagannadha Sutradharudu Teki /* Now erase size becomes valid sector size */ 191*c650ca7bSJagannadha Sutradharudu Teki flash->sector_size = flash->erase_size; 192*c650ca7bSJagannadha Sutradharudu Teki 1934e09cc1eSJagannadha Sutradharudu Teki /* Look for the fastest read cmd */ 1944e09cc1eSJagannadha Sutradharudu Teki cmd = fls(params->e_rd_cmd & flash->spi->op_mode_rx); 1954e09cc1eSJagannadha Sutradharudu Teki if (cmd) { 1964e09cc1eSJagannadha Sutradharudu Teki cmd = spi_read_cmds_array[cmd - 1]; 1974e09cc1eSJagannadha Sutradharudu Teki flash->read_cmd = cmd; 1984e09cc1eSJagannadha Sutradharudu Teki } else { 1992ba863faSJagannadha Sutradharudu Teki /* Go for default supported read cmd */ 2004e09cc1eSJagannadha Sutradharudu Teki flash->read_cmd = CMD_READ_ARRAY_FAST; 2014e09cc1eSJagannadha Sutradharudu Teki } 2024e09cc1eSJagannadha Sutradharudu Teki 2033163aaa6SJagannadha Sutradharudu Teki /* Not require to look for fastest only two write cmds yet */ 2043163aaa6SJagannadha Sutradharudu Teki if (params->flags & WR_QPP && flash->spi->op_mode_tx & SPI_OPM_TX_QPP) 2053163aaa6SJagannadha Sutradharudu Teki flash->write_cmd = CMD_QUAD_PAGE_PROGRAM; 2063163aaa6SJagannadha Sutradharudu Teki else 2073163aaa6SJagannadha Sutradharudu Teki /* Go for default supported write cmd */ 2083163aaa6SJagannadha Sutradharudu Teki flash->write_cmd = CMD_PAGE_PROGRAM; 2093163aaa6SJagannadha Sutradharudu Teki 210ff063ed4SJagannadha Sutradharudu Teki /* Read dummy_byte: dummy byte is determined based on the 211ff063ed4SJagannadha Sutradharudu Teki * dummy cycles of a particular command. 212ff063ed4SJagannadha Sutradharudu Teki * Fast commands - dummy_byte = dummy_cycles/8 213ff063ed4SJagannadha Sutradharudu Teki * I/O commands- dummy_byte = (dummy_cycles * no.of lines)/8 214ff063ed4SJagannadha Sutradharudu Teki * For I/O commands except cmd[0] everything goes on no.of lines 215ff063ed4SJagannadha Sutradharudu Teki * based on particular command but incase of fast commands except 216ff063ed4SJagannadha Sutradharudu Teki * data all go on single line irrespective of command. 217ff063ed4SJagannadha Sutradharudu Teki */ 218ff063ed4SJagannadha Sutradharudu Teki switch (flash->read_cmd) { 219ff063ed4SJagannadha Sutradharudu Teki case CMD_READ_QUAD_IO_FAST: 220ff063ed4SJagannadha Sutradharudu Teki flash->dummy_byte = 2; 221ff063ed4SJagannadha Sutradharudu Teki break; 222ff063ed4SJagannadha Sutradharudu Teki case CMD_READ_ARRAY_SLOW: 223ff063ed4SJagannadha Sutradharudu Teki flash->dummy_byte = 0; 224ff063ed4SJagannadha Sutradharudu Teki break; 225ff063ed4SJagannadha Sutradharudu Teki default: 226ff063ed4SJagannadha Sutradharudu Teki flash->dummy_byte = 1; 227ff063ed4SJagannadha Sutradharudu Teki } 228ff063ed4SJagannadha Sutradharudu Teki 2292ba863faSJagannadha Sutradharudu Teki /* Poll cmd selection */ 230898e76c9SJagannadha Sutradharudu Teki flash->poll_cmd = CMD_READ_STATUS; 231898e76c9SJagannadha Sutradharudu Teki #ifdef CONFIG_SPI_FLASH_STMICRO 232898e76c9SJagannadha Sutradharudu Teki if (params->flags & E_FSR) 233898e76c9SJagannadha Sutradharudu Teki flash->poll_cmd = CMD_FLAG_STATUS; 234898e76c9SJagannadha Sutradharudu Teki #endif 235898e76c9SJagannadha Sutradharudu Teki 236898e76c9SJagannadha Sutradharudu Teki /* Configure the BAR - discover bank cmds and read current bank */ 237ce22b922SJagannadha Sutradharudu Teki #ifdef CONFIG_SPI_FLASH_BAR 238898e76c9SJagannadha Sutradharudu Teki u8 curr_bank = 0; 239898e76c9SJagannadha Sutradharudu Teki if (flash->size > SPI_FLASH_16MB_BOUN) { 240ae242cbfSSimon Glass int ret; 241ae242cbfSSimon Glass 242898e76c9SJagannadha Sutradharudu Teki flash->bank_read_cmd = (idcode[0] == 0x01) ? 243898e76c9SJagannadha Sutradharudu Teki CMD_BANKADDR_BRRD : CMD_EXTNADDR_RDEAR; 244898e76c9SJagannadha Sutradharudu Teki flash->bank_write_cmd = (idcode[0] == 0x01) ? 245898e76c9SJagannadha Sutradharudu Teki CMD_BANKADDR_BRWR : CMD_EXTNADDR_WREAR; 246898e76c9SJagannadha Sutradharudu Teki 247ae242cbfSSimon Glass ret = spi_flash_read_common(flash, &flash->bank_read_cmd, 1, 248ae242cbfSSimon Glass &curr_bank, 1); 249ae242cbfSSimon Glass if (ret) { 250898e76c9SJagannadha Sutradharudu Teki debug("SF: fail to read bank addr register\n"); 251ae242cbfSSimon Glass return ret; 252898e76c9SJagannadha Sutradharudu Teki } 253898e76c9SJagannadha Sutradharudu Teki flash->bank_curr = curr_bank; 254898e76c9SJagannadha Sutradharudu Teki } else { 255898e76c9SJagannadha Sutradharudu Teki flash->bank_curr = curr_bank; 256898e76c9SJagannadha Sutradharudu Teki } 257898e76c9SJagannadha Sutradharudu Teki #endif 258898e76c9SJagannadha Sutradharudu Teki 259898e76c9SJagannadha Sutradharudu Teki /* Flash powers up read-only, so clear BP# bits */ 260898e76c9SJagannadha Sutradharudu Teki #if defined(CONFIG_SPI_FLASH_ATMEL) || \ 261898e76c9SJagannadha Sutradharudu Teki defined(CONFIG_SPI_FLASH_MACRONIX) || \ 262898e76c9SJagannadha Sutradharudu Teki defined(CONFIG_SPI_FLASH_SST) 263898e76c9SJagannadha Sutradharudu Teki spi_flash_cmd_write_status(flash, 0); 264898e76c9SJagannadha Sutradharudu Teki #endif 265898e76c9SJagannadha Sutradharudu Teki 266ae242cbfSSimon Glass return 0; 267898e76c9SJagannadha Sutradharudu Teki } 268898e76c9SJagannadha Sutradharudu Teki 269898e76c9SJagannadha Sutradharudu Teki #ifdef CONFIG_OF_CONTROL 270898e76c9SJagannadha Sutradharudu Teki int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) 271898e76c9SJagannadha Sutradharudu Teki { 272898e76c9SJagannadha Sutradharudu Teki fdt_addr_t addr; 273898e76c9SJagannadha Sutradharudu Teki fdt_size_t size; 274898e76c9SJagannadha Sutradharudu Teki int node; 275898e76c9SJagannadha Sutradharudu Teki 276898e76c9SJagannadha Sutradharudu Teki /* If there is no node, do nothing */ 277898e76c9SJagannadha Sutradharudu Teki node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); 278898e76c9SJagannadha Sutradharudu Teki if (node < 0) 279898e76c9SJagannadha Sutradharudu Teki return 0; 280898e76c9SJagannadha Sutradharudu Teki 281898e76c9SJagannadha Sutradharudu Teki addr = fdtdec_get_addr_size(blob, node, "memory-map", &size); 282898e76c9SJagannadha Sutradharudu Teki if (addr == FDT_ADDR_T_NONE) { 283898e76c9SJagannadha Sutradharudu Teki debug("%s: Cannot decode address\n", __func__); 284898e76c9SJagannadha Sutradharudu Teki return 0; 285898e76c9SJagannadha Sutradharudu Teki } 286898e76c9SJagannadha Sutradharudu Teki 287898e76c9SJagannadha Sutradharudu Teki if (flash->size != size) { 288898e76c9SJagannadha Sutradharudu Teki debug("%s: Memory map must cover entire device\n", __func__); 289898e76c9SJagannadha Sutradharudu Teki return -1; 290898e76c9SJagannadha Sutradharudu Teki } 291ffdb20beSMike Frysinger flash->memory_map = map_sysmem(addr, size); 292898e76c9SJagannadha Sutradharudu Teki 293898e76c9SJagannadha Sutradharudu Teki return 0; 294898e76c9SJagannadha Sutradharudu Teki } 295898e76c9SJagannadha Sutradharudu Teki #endif /* CONFIG_OF_CONTROL */ 296898e76c9SJagannadha Sutradharudu Teki 297ae242cbfSSimon Glass /** 298ae242cbfSSimon Glass * spi_flash_probe_slave() - Probe for a SPI flash device on a bus 299ae242cbfSSimon Glass * 300ae242cbfSSimon Glass * @spi: Bus to probe 301ae242cbfSSimon Glass * @flashp: Pointer to place to put flash info, which may be NULL if the 302ae242cbfSSimon Glass * space should be allocated 303ae242cbfSSimon Glass */ 304ae242cbfSSimon Glass int spi_flash_probe_slave(struct spi_slave *spi, struct spi_flash *flash) 305898e76c9SJagannadha Sutradharudu Teki { 306898e76c9SJagannadha Sutradharudu Teki u8 idcode[5]; 307898e76c9SJagannadha Sutradharudu Teki int ret; 308898e76c9SJagannadha Sutradharudu Teki 309898e76c9SJagannadha Sutradharudu Teki /* Setup spi_slave */ 310898e76c9SJagannadha Sutradharudu Teki if (!spi) { 311898e76c9SJagannadha Sutradharudu Teki printf("SF: Failed to set up slave\n"); 312ae242cbfSSimon Glass return -ENODEV; 313898e76c9SJagannadha Sutradharudu Teki } 314898e76c9SJagannadha Sutradharudu Teki 315898e76c9SJagannadha Sutradharudu Teki /* Claim spi bus */ 316898e76c9SJagannadha Sutradharudu Teki ret = spi_claim_bus(spi); 317898e76c9SJagannadha Sutradharudu Teki if (ret) { 318898e76c9SJagannadha Sutradharudu Teki debug("SF: Failed to claim SPI bus: %d\n", ret); 319ae242cbfSSimon Glass return ret; 320898e76c9SJagannadha Sutradharudu Teki } 321898e76c9SJagannadha Sutradharudu Teki 322898e76c9SJagannadha Sutradharudu Teki /* Read the ID codes */ 323898e76c9SJagannadha Sutradharudu Teki ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); 324898e76c9SJagannadha Sutradharudu Teki if (ret) { 325898e76c9SJagannadha Sutradharudu Teki printf("SF: Failed to get idcodes\n"); 326898e76c9SJagannadha Sutradharudu Teki goto err_read_id; 327898e76c9SJagannadha Sutradharudu Teki } 328898e76c9SJagannadha Sutradharudu Teki 329898e76c9SJagannadha Sutradharudu Teki #ifdef DEBUG 330898e76c9SJagannadha Sutradharudu Teki printf("SF: Got idcodes\n"); 331898e76c9SJagannadha Sutradharudu Teki print_buffer(0, idcode, 1, sizeof(idcode), 0); 332898e76c9SJagannadha Sutradharudu Teki #endif 333898e76c9SJagannadha Sutradharudu Teki 334ae242cbfSSimon Glass if (spi_flash_validate_params(spi, idcode, flash)) { 335ae242cbfSSimon Glass ret = -EINVAL; 336898e76c9SJagannadha Sutradharudu Teki goto err_read_id; 337ae242cbfSSimon Glass } 338898e76c9SJagannadha Sutradharudu Teki 3391f436a6dSPoddar, Sourav /* Set the quad enable bit - only for quad commands */ 3401f436a6dSPoddar, Sourav if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) || 3411f436a6dSPoddar, Sourav (flash->read_cmd == CMD_READ_QUAD_IO_FAST) || 3421f436a6dSPoddar, Sourav (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) { 3431f436a6dSPoddar, Sourav if (spi_flash_set_qeb(flash, idcode[0])) { 3441f436a6dSPoddar, Sourav debug("SF: Fail to set QEB for %02x\n", idcode[0]); 345ae242cbfSSimon Glass ret = -EINVAL; 346ae242cbfSSimon Glass goto err_read_id; 3471f436a6dSPoddar, Sourav } 3481f436a6dSPoddar, Sourav } 3491f436a6dSPoddar, Sourav 350898e76c9SJagannadha Sutradharudu Teki #ifdef CONFIG_OF_CONTROL 351898e76c9SJagannadha Sutradharudu Teki if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { 352898e76c9SJagannadha Sutradharudu Teki debug("SF: FDT decode error\n"); 353ae242cbfSSimon Glass ret = -EINVAL; 354898e76c9SJagannadha Sutradharudu Teki goto err_read_id; 355898e76c9SJagannadha Sutradharudu Teki } 356898e76c9SJagannadha Sutradharudu Teki #endif 357898e76c9SJagannadha Sutradharudu Teki #ifndef CONFIG_SPL_BUILD 358898e76c9SJagannadha Sutradharudu Teki printf("SF: Detected %s with page size ", flash->name); 359898e76c9SJagannadha Sutradharudu Teki print_size(flash->page_size, ", erase size "); 360898e76c9SJagannadha Sutradharudu Teki print_size(flash->erase_size, ", total "); 361898e76c9SJagannadha Sutradharudu Teki print_size(flash->size, ""); 362898e76c9SJagannadha Sutradharudu Teki if (flash->memory_map) 363898e76c9SJagannadha Sutradharudu Teki printf(", mapped at %p", flash->memory_map); 364898e76c9SJagannadha Sutradharudu Teki puts("\n"); 365898e76c9SJagannadha Sutradharudu Teki #endif 366898e76c9SJagannadha Sutradharudu Teki #ifndef CONFIG_SPI_FLASH_BAR 367f77f4691SJagannadha Sutradharudu Teki if (((flash->dual_flash == SF_SINGLE_FLASH) && 368f77f4691SJagannadha Sutradharudu Teki (flash->size > SPI_FLASH_16MB_BOUN)) || 369f77f4691SJagannadha Sutradharudu Teki ((flash->dual_flash > SF_SINGLE_FLASH) && 370f77f4691SJagannadha Sutradharudu Teki (flash->size > SPI_FLASH_16MB_BOUN << 1))) { 371898e76c9SJagannadha Sutradharudu Teki puts("SF: Warning - Only lower 16MiB accessible,"); 372898e76c9SJagannadha Sutradharudu Teki puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); 373898e76c9SJagannadha Sutradharudu Teki } 374898e76c9SJagannadha Sutradharudu Teki #endif 375898e76c9SJagannadha Sutradharudu Teki 376898e76c9SJagannadha Sutradharudu Teki /* Release spi bus */ 377898e76c9SJagannadha Sutradharudu Teki spi_release_bus(spi); 378898e76c9SJagannadha Sutradharudu Teki 379ae242cbfSSimon Glass return 0; 380898e76c9SJagannadha Sutradharudu Teki 381898e76c9SJagannadha Sutradharudu Teki err_read_id: 382898e76c9SJagannadha Sutradharudu Teki spi_release_bus(spi); 383ae242cbfSSimon Glass return ret; 384ae242cbfSSimon Glass } 385ae242cbfSSimon Glass 386fbb09918SSimon Glass #ifndef CONFIG_DM_SPI_FLASH 387fbb09918SSimon Glass struct spi_flash *spi_flash_probe_tail(struct spi_slave *bus) 388ae242cbfSSimon Glass { 389ae242cbfSSimon Glass struct spi_flash *flash; 390ae242cbfSSimon Glass 391ae242cbfSSimon Glass /* Allocate space if needed (not used by sf-uclass */ 392ae242cbfSSimon Glass flash = calloc(1, sizeof(*flash)); 393ae242cbfSSimon Glass if (!flash) { 394ae242cbfSSimon Glass debug("SF: Failed to allocate spi_flash\n"); 395898e76c9SJagannadha Sutradharudu Teki return NULL; 396898e76c9SJagannadha Sutradharudu Teki } 397898e76c9SJagannadha Sutradharudu Teki 398ae242cbfSSimon Glass if (spi_flash_probe_slave(bus, flash)) { 399ae242cbfSSimon Glass spi_free_slave(bus); 400ae242cbfSSimon Glass free(flash); 401ae242cbfSSimon Glass return NULL; 402ae242cbfSSimon Glass } 403ae242cbfSSimon Glass 404ae242cbfSSimon Glass return flash; 405ae242cbfSSimon Glass } 406ae242cbfSSimon Glass 407ae242cbfSSimon Glass struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs, 4080efc0249SSimon Glass unsigned int max_hz, unsigned int spi_mode) 4090efc0249SSimon Glass { 410ae242cbfSSimon Glass struct spi_slave *bus; 4110efc0249SSimon Glass 412ae242cbfSSimon Glass bus = spi_setup_slave(busnum, cs, max_hz, spi_mode); 4134fbad92eSPeng Fan if (!bus) 4144fbad92eSPeng Fan return NULL; 415ae242cbfSSimon Glass return spi_flash_probe_tail(bus); 4160efc0249SSimon Glass } 4170efc0249SSimon Glass 4180efc0249SSimon Glass #ifdef CONFIG_OF_SPI_FLASH 4190efc0249SSimon Glass struct spi_flash *spi_flash_probe_fdt(const void *blob, int slave_node, 4200efc0249SSimon Glass int spi_node) 4210efc0249SSimon Glass { 422ae242cbfSSimon Glass struct spi_slave *bus; 4230efc0249SSimon Glass 424ae242cbfSSimon Glass bus = spi_setup_slave_fdt(blob, slave_node, spi_node); 4254fbad92eSPeng Fan if (!bus) 4264fbad92eSPeng Fan return NULL; 427ae242cbfSSimon Glass return spi_flash_probe_tail(bus); 4280efc0249SSimon Glass } 4290efc0249SSimon Glass #endif 4300efc0249SSimon Glass 431898e76c9SJagannadha Sutradharudu Teki void spi_flash_free(struct spi_flash *flash) 432898e76c9SJagannadha Sutradharudu Teki { 433898e76c9SJagannadha Sutradharudu Teki spi_free_slave(flash->spi); 434898e76c9SJagannadha Sutradharudu Teki free(flash); 435898e76c9SJagannadha Sutradharudu Teki } 436fbb09918SSimon Glass 437fbb09918SSimon Glass #else /* defined CONFIG_DM_SPI_FLASH */ 438fbb09918SSimon Glass 439fbb09918SSimon Glass static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len, 440fbb09918SSimon Glass void *buf) 441fbb09918SSimon Glass { 442e564f054SSimon Glass struct spi_flash *flash = dev_get_uclass_priv(dev); 443fbb09918SSimon Glass 444fbb09918SSimon Glass return spi_flash_cmd_read_ops(flash, offset, len, buf); 445fbb09918SSimon Glass } 446fbb09918SSimon Glass 447fbb09918SSimon Glass int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len, 448fbb09918SSimon Glass const void *buf) 449fbb09918SSimon Glass { 450e564f054SSimon Glass struct spi_flash *flash = dev_get_uclass_priv(dev); 451fbb09918SSimon Glass 452074eed51SBin Meng #if defined(CONFIG_SPI_FLASH_SST) 453074eed51SBin Meng if (flash->flags & SST_WR) { 454074eed51SBin Meng if (flash->spi->op_mode_tx & SPI_OPM_TX_BP) 455074eed51SBin Meng return sst_write_bp(flash, offset, len, buf); 456074eed51SBin Meng else 457074eed51SBin Meng return sst_write_wp(flash, offset, len, buf); 458074eed51SBin Meng } 459074eed51SBin Meng #endif 460074eed51SBin Meng 461fbb09918SSimon Glass return spi_flash_cmd_write_ops(flash, offset, len, buf); 462fbb09918SSimon Glass } 463fbb09918SSimon Glass 464fbb09918SSimon Glass int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len) 465fbb09918SSimon Glass { 466e564f054SSimon Glass struct spi_flash *flash = dev_get_uclass_priv(dev); 467fbb09918SSimon Glass 468fbb09918SSimon Glass return spi_flash_cmd_erase_ops(flash, offset, len); 469fbb09918SSimon Glass } 470fbb09918SSimon Glass 471fbb09918SSimon Glass int spi_flash_std_probe(struct udevice *dev) 472fbb09918SSimon Glass { 473fbb09918SSimon Glass struct spi_slave *slave = dev_get_parentdata(dev); 474d0cff03eSSimon Glass struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev); 475fbb09918SSimon Glass struct spi_flash *flash; 476fbb09918SSimon Glass 477e564f054SSimon Glass flash = dev_get_uclass_priv(dev); 478fbb09918SSimon Glass flash->dev = dev; 479d0cff03eSSimon Glass debug("%s: slave=%p, cs=%d\n", __func__, slave, plat->cs); 480fbb09918SSimon Glass return spi_flash_probe_slave(slave, flash); 481fbb09918SSimon Glass } 482fbb09918SSimon Glass 483fbb09918SSimon Glass static const struct dm_spi_flash_ops spi_flash_std_ops = { 484fbb09918SSimon Glass .read = spi_flash_std_read, 485fbb09918SSimon Glass .write = spi_flash_std_write, 486fbb09918SSimon Glass .erase = spi_flash_std_erase, 487fbb09918SSimon Glass }; 488fbb09918SSimon Glass 489fbb09918SSimon Glass static const struct udevice_id spi_flash_std_ids[] = { 490fbb09918SSimon Glass { .compatible = "spi-flash" }, 491fbb09918SSimon Glass { } 492fbb09918SSimon Glass }; 493fbb09918SSimon Glass 494fbb09918SSimon Glass U_BOOT_DRIVER(spi_flash_std) = { 495fbb09918SSimon Glass .name = "spi_flash_std", 496fbb09918SSimon Glass .id = UCLASS_SPI_FLASH, 497fbb09918SSimon Glass .of_match = spi_flash_std_ids, 498fbb09918SSimon Glass .probe = spi_flash_std_probe, 499fbb09918SSimon Glass .priv_auto_alloc_size = sizeof(struct spi_flash), 500fbb09918SSimon Glass .ops = &spi_flash_std_ops, 501fbb09918SSimon Glass }; 502fbb09918SSimon Glass 503fbb09918SSimon Glass #endif /* CONFIG_DM_SPI_FLASH */ 504