/*******************************************************************/
-#define HACK_WRITE_NO_DELAY
+#undef HACK_WRITE_NO_DELAY
/*
* Name of this driver
#define xqspipss_write(addr, val) __raw_writel((val), (addr))
#else
static inline
-u32 xqspipss_read(u32 addr)
+u32 xqspipss_read(void *addr)
{
u32 val;
- val = XIo_In32(addr);
+ val = XIo_In32((unsigned)addr);
#ifdef DEBUG_REG
printf("xqspipss_read: addr: 0x%08x = 0x%08x\n",
addr, val);
return val;
}
static inline
-void xqspipss_write(u32 addr, u32 val)
+void xqspipss_write(void *addr, u32 val)
{
#ifdef DEBUG_REG
printf("xqspipss_write: addr: 0x%08x = 0x%08x\n",
addr, val);
#endif
- XIo_Out32(addr, val);
+ XIo_Out32((unsigned)addr, val);
}
#endif
config_reg &= 0xFBFFFFFF; /* Set little endian mode of TX FIFO */
config_reg |= 0x8000FCC1;
xqspipss_write(regs_base + XQSPIPSS_CONFIG_OFFSET, config_reg);
+
+#ifdef CONFIG_XILINX_PSS_QSPI_USE_DUAL_FLASH
+ xqspipss_write(regs_base + XQSPIPSS_LINEAR_CFG_OFFSET, 0x6400016B);
+#endif
+
xqspipss_write(regs_base + XQSPIPSS_ENABLE_OFFSET,
XQSPIPSS_ENABLE_ENABLE_MASK);
}
xqspi->curr_inst = &flash_inst[index];
xqspi->inst_response = 1;
+#ifdef CONFIG_XILINX_PSS_QSPI_USE_DUAL_FLASH
+ /* In case of dual memories, convert 25 bit address to 24 bit
+ * address before transmitting to the 2 memories
+ */
+ if ((instruction == XQSPIPSS_FLASH_OPCODE_PP) ||
+ (instruction == XQSPIPSS_FLASH_OPCODE_SE) ||
+ (instruction == XQSPIPSS_FLASH_OPCODE_BE_32K) ||
+ (instruction == XQSPIPSS_FLASH_OPCODE_BE_4K) ||
+ (instruction == XQSPIPSS_FLASH_OPCODE_BE) ||
+ (instruction == XQSPIPSS_FLASH_OPCODE_NORM_READ) ||
+ (instruction == XQSPIPSS_FLASH_OPCODE_FAST_READ) ||
+ (instruction == XQSPIPSS_FLASH_OPCODE_DUAL_READ) ||
+ (instruction == XQSPIPSS_FLASH_OPCODE_QUAD_READ)) {
+
+ u8 *ptr = (u8*) (xqspi->txbuf);
+ data = ((u32) ptr[1] << 24) | ((u32) ptr[2] << 16) |
+ ((u32) ptr[3] << 8) | ((u32) ptr[4]);
+ data = data/2;
+ ptr[1] = (u8) (data >> 16);
+ ptr[2] = (u8) (data >> 8);
+ ptr[3] = (u8) (data);
+ xqspi->bytes_to_transfer -= 1;
+ xqspi->bytes_to_receive -= 1;
+ }
+#endif
+
/* Get the instruction */
data = 0;
xqspipss_copy_write_data(xqspi, &data,
struct stmicro_spi_flash {
struct spi_flash flash;
const struct stmicro_spi_flash_params *params;
+
+ unsigned addr_width;
};
static inline struct stmicro_spi_flash *to_stmicro_spi_flash(struct spi_flash
.idcode = STM_ID_N25Q128,
.page_size = 256,
.pages_per_sector = 256,
+#ifdef CONFIG_XILINX_PSS_QSPI_USE_DUAL_FLASH
+ .nr_sectors = 512,
+ .name = "N25Q128x2",
+#else
.nr_sectors = 256,
.name = "N25Q128",
+#endif
},
{
.idcode1 = STM_ID_M25P128,
},
};
+static inline void stmicro_addr2cmd(struct stmicro_spi_flash *stm,
+ unsigned page_addr, unsigned byte_addr, u8 *cmd)
+{
+ /* opcode is in cmd[0] */
+ if (stm->addr_width == 4) {
+ cmd[1] = page_addr >> 16;
+ cmd[2] = page_addr >> 8;
+ cmd[3] = page_addr;
+ cmd[4] = byte_addr;
+ } else {
+ cmd[1] = page_addr >> 8;
+ cmd[2] = page_addr;
+ cmd[3] = byte_addr;
+ }
+}
+
+static inline int stmicro_cmdsz(struct stmicro_spi_flash *flash)
+{
+ return 1 + flash->addr_width;
+}
+
static int stmicro_wait_ready(struct spi_flash *flash, unsigned long timeout)
{
struct spi_slave *spi = flash->spi;
struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash);
unsigned long page_addr;
unsigned long page_size;
- u8 cmd[5];
+ u8 cmd[6];
page_size = stm->params->page_size;
page_addr = offset / page_size;
cmd[0] = CMD_READ_ARRAY_FAST;
- cmd[1] = page_addr >> 8;
- cmd[2] = page_addr;
- cmd[3] = offset % page_size;
- cmd[4] = 0x00;
+ stmicro_addr2cmd(stm, page_addr, offset % page_size, cmd);
+ cmd[stmicro_cmdsz(stm)] = 0x00;
- return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len);
+ return spi_flash_read_common(flash, cmd, stmicro_cmdsz(stm)+1 , buf, len);
}
static int stmicro_write(struct spi_flash *flash,
size_t chunk_len;
size_t actual;
int ret;
- u8 cmd[4];
+ u8 cmd[5];
page_size = stm->params->page_size;
page_addr = offset / page_size;
chunk_len = min(len - actual, page_size - byte_addr);
cmd[0] = CMD_M25PXX_PP;
- cmd[1] = page_addr >> 8;
- cmd[2] = page_addr;
- cmd[3] = byte_addr;
+ stmicro_addr2cmd(stm, page_addr, byte_addr, cmd);
debug
("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %d\n",
break;
}
- ret = spi_flash_cmd_write(flash->spi, cmd, 4,
+ ret = spi_flash_cmd_write(flash->spi, cmd, stmicro_cmdsz(stm),
buf + actual, chunk_len);
if (ret < 0) {
debug("SF: STMicro Page Program failed\n");
unsigned long sector_size;
size_t actual;
int ret;
- u8 cmd[4];
+ u8 cmd[5];
/*
* This function currently uses sector erase only.
len /= sector_size;
cmd[0] = CMD_M25PXX_SE;
- cmd[2] = 0x00;
- cmd[3] = 0x00;
ret = spi_claim_bus(flash->spi);
if (ret) {
ret = 0;
for (actual = 0; actual < len; actual++) {
- cmd[1] = offset >> 16;
+ unsigned page_addr;
+
+ page_addr = offset / stm->params->page_size;
+ stmicro_addr2cmd(stm, page_addr, 0, cmd);
+
offset += sector_size;
ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0);
break;
}
- ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0);
+ ret = spi_flash_cmd_write(flash->spi, cmd, stmicro_cmdsz(stm), NULL, 0);
if (ret < 0) {
debug("SF: STMicro page erase failed\n");
break;
stm->flash.size = params->page_size * params->pages_per_sector
* params->nr_sectors;
+ if (stm->flash.size > 0x1000000) {
+ stm->addr_width = 4;
+ } else {
+ stm->addr_width = 3;
+ }
+
printf("SF: Detected %s with page size %u, total ",
params->name, params->page_size);
print_size(stm->flash.size, "\n");