| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Copyright (C) 2005, Intec Automation Inc. |
| * Copyright (C) 2014, Freescale Semiconductor, Inc. |
| */ |
| |
| #include <linux/mtd/spi-nor.h> |
| |
| #include "core.h" |
| |
| #define XILINX_OP_SE 0x50 /* Sector erase */ |
| #define XILINX_OP_PP 0x82 /* Page program */ |
| #define XILINX_OP_RDSR 0xd7 /* Read status register */ |
| |
| #define XSR_PAGESIZE BIT(0) /* Page size in Po2 or Linear */ |
| #define XSR_RDY BIT(7) /* Ready */ |
| |
| #define S3AN_INFO(_jedec_id, _n_sectors, _page_size) \ |
| .id = { \ |
| ((_jedec_id) >> 16) & 0xff, \ |
| ((_jedec_id) >> 8) & 0xff, \ |
| (_jedec_id) & 0xff \ |
| }, \ |
| .id_len = 3, \ |
| .sector_size = (8 * (_page_size)), \ |
| .n_sectors = (_n_sectors), \ |
| .page_size = (_page_size), \ |
| .addr_width = 3, \ |
| .flags = SPI_NOR_NO_FR |
| |
| /* Xilinx S3AN share MFR with Atmel SPI NOR */ |
| static const struct flash_info xilinx_nor_parts[] = { |
| /* Xilinx S3AN Internal Flash */ |
| { "3S50AN", S3AN_INFO(0x1f2200, 64, 264) }, |
| { "3S200AN", S3AN_INFO(0x1f2400, 256, 264) }, |
| { "3S400AN", S3AN_INFO(0x1f2400, 256, 264) }, |
| { "3S700AN", S3AN_INFO(0x1f2500, 512, 264) }, |
| { "3S1400AN", S3AN_INFO(0x1f2600, 512, 528) }, |
| }; |
| |
| /* |
| * This code converts an address to the Default Address Mode, that has non |
| * power of two page sizes. We must support this mode because it is the default |
| * mode supported by Xilinx tools, it can access the whole flash area and |
| * changing over to the Power-of-two mode is irreversible and corrupts the |
| * original data. |
| * Addr can safely be unsigned int, the biggest S3AN device is smaller than |
| * 4 MiB. |
| */ |
| static u32 s3an_nor_convert_addr(struct spi_nor *nor, u32 addr) |
| { |
| u32 page_size = nor->params->page_size; |
| u32 offset, page; |
| |
| offset = addr % page_size; |
| page = addr / page_size; |
| page <<= (page_size > 512) ? 10 : 9; |
| |
| return page | offset; |
| } |
| |
| /** |
| * xilinx_nor_read_sr() - Read the Status Register on S3AN flashes. |
| * @nor: pointer to 'struct spi_nor'. |
| * @sr: pointer to a DMA-able buffer where the value of the |
| * Status Register will be written. |
| * |
| * Return: 0 on success, -errno otherwise. |
| */ |
| static int xilinx_nor_read_sr(struct spi_nor *nor, u8 *sr) |
| { |
| int ret; |
| |
| if (nor->spimem) { |
| struct spi_mem_op op = |
| SPI_MEM_OP(SPI_MEM_OP_CMD(XILINX_OP_RDSR, 0), |
| SPI_MEM_OP_NO_ADDR, |
| SPI_MEM_OP_NO_DUMMY, |
| SPI_MEM_OP_DATA_IN(1, sr, 0)); |
| |
| spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); |
| |
| ret = spi_mem_exec_op(nor->spimem, &op); |
| } else { |
| ret = spi_nor_controller_ops_read_reg(nor, XILINX_OP_RDSR, sr, |
| 1); |
| } |
| |
| if (ret) |
| dev_dbg(nor->dev, "error %d reading SR\n", ret); |
| |
| return ret; |
| } |
| |
| /** |
| * xilinx_nor_sr_ready() - Query the Status Register of the S3AN flash to see |
| * if the flash is ready for new commands. |
| * @nor: pointer to 'struct spi_nor'. |
| * |
| * Return: 1 if ready, 0 if not ready, -errno on errors. |
| */ |
| static int xilinx_nor_sr_ready(struct spi_nor *nor) |
| { |
| int ret; |
| |
| ret = xilinx_nor_read_sr(nor, nor->bouncebuf); |
| if (ret) |
| return ret; |
| |
| return !!(nor->bouncebuf[0] & XSR_RDY); |
| } |
| |
| static int xilinx_nor_setup(struct spi_nor *nor, |
| const struct spi_nor_hwcaps *hwcaps) |
| { |
| u32 page_size; |
| int ret; |
| |
| ret = xilinx_nor_read_sr(nor, nor->bouncebuf); |
| if (ret) |
| return ret; |
| |
| nor->erase_opcode = XILINX_OP_SE; |
| nor->program_opcode = XILINX_OP_PP; |
| nor->read_opcode = SPINOR_OP_READ; |
| nor->flags |= SNOR_F_NO_OP_CHIP_ERASE; |
| |
| /* |
| * This flashes have a page size of 264 or 528 bytes (known as |
| * Default addressing mode). It can be changed to a more standard |
| * Power of two mode where the page size is 256/512. This comes |
| * with a price: there is 3% less of space, the data is corrupted |
| * and the page size cannot be changed back to default addressing |
| * mode. |
| * |
| * The current addressing mode can be read from the XRDSR register |
| * and should not be changed, because is a destructive operation. |
| */ |
| if (nor->bouncebuf[0] & XSR_PAGESIZE) { |
| /* Flash in Power of 2 mode */ |
| page_size = (nor->params->page_size == 264) ? 256 : 512; |
| nor->params->page_size = page_size; |
| nor->mtd.writebufsize = page_size; |
| nor->params->size = 8 * page_size * nor->info->n_sectors; |
| nor->mtd.erasesize = 8 * page_size; |
| } else { |
| /* Flash in Default addressing mode */ |
| nor->params->convert_addr = s3an_nor_convert_addr; |
| nor->mtd.erasesize = nor->info->sector_size; |
| } |
| |
| return 0; |
| } |
| |
| static void xilinx_nor_late_init(struct spi_nor *nor) |
| { |
| nor->params->setup = xilinx_nor_setup; |
| nor->params->ready = xilinx_nor_sr_ready; |
| } |
| |
| static const struct spi_nor_fixups xilinx_nor_fixups = { |
| .late_init = xilinx_nor_late_init, |
| }; |
| |
| const struct spi_nor_manufacturer spi_nor_xilinx = { |
| .name = "xilinx", |
| .parts = xilinx_nor_parts, |
| .nparts = ARRAY_SIZE(xilinx_nor_parts), |
| .fixups = &xilinx_nor_fixups, |
| }; |