GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -0,0 +1,29 @@
config FMC_SPI_NOR
bool "lotus SPI Nor Flash Interface support"
depends on FMC
help
Enable the lotus SPI Nor flash support.
If unsure, say N
config SPI_BLOCK_PROTECT
bool "Spi Nor Device BP(Block Protect) Support"
depends on FMC_SPI_NOR
help
SFC supports BP(Block Protect) feature to preestablish a series
area to avoid writing and erasing, except to reading. With this macro
definition we can get the BP info which was setted before. The
BOTTOM/TOP bit is setted to BOTTOM, it means the lock area starts
from 0 address.
If unsure, say N
config DTR_MODE_SUPPORT
bool "Spi Nor Device DTR mode Support"
depends on FMC_SPI_NOR
default n
help
To support DTR mode
If unsure, say N
@@ -0,0 +1,4 @@
obj-y = spi_nor.o
obj-$(CONFIG_FMC_SPI_NOR) += fmc100/
@@ -0,0 +1,4 @@
ccflags-y += -I$(srctree)/lotus/drivers/mtd
obj-y += fmc100.o fmc100_os.o fmc_spi_nor_ids.o
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,169 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifndef __FMC100_H__
#define __FMC100_H__
#include <spi_flash.h>
#include <linux/lotus/fmc_common.h>
#include "fmc_spi_ids.h"
#include <cpu_func.h>
/* These macroes are for debug only, reg read is slower then dma read,
so we don't define it */
#undef FMC100_SPI_NOR_SUPPORT_REG_READ
#undef FMC100_SPI_NOR_SUPPORT_REG_WRITE
#define FMC100_DMA_WR_MAX_SIZE 4096
#define FMC100_DMA_WR_MASK (FMC100_DMA_WR_MAX_SIZE - 1)
#define FMC100_DMA_RD_MAX_SIZE (_2M)
#define FMC100_DMA_RD_MASK (FMC100_DMA_RD_MAX_SIZE - 1)
#define FMC100_REG_RD_MAX_SIZE (_16K)
#define FMC100_REG_RD_MASK (FMC100_REG_RD_MAX_SIZE - 1)
#define SPI_NOR_CR_SHIFT 8 /* Config Register shift(bit) */
#define SPI_NOR_CR_4BYTE_SHIFT 5
#define SPI_NOR_CR_4BYTE_MASK (1 << SPI_NOR_CR_4BYTE_SHIFT)
#define spi_nor_get_4byte_by_cr(cr) (((cr) & SPI_NOR_CR_4BYTE_MASK) \
>> SPI_NOR_CR_4BYTE_SHIFT)
#define SPI_NOR_CR_QE_SHIFT 1
#define SPI_NOR_CR_QE_MASK (1 << SPI_NOR_CR_QE_SHIFT)
#define spi_nor_get_qe_by_cr(cr) (((cr) & SPI_NOR_CR_QE_MASK) \
>> SPI_NOR_CR_QE_SHIFT)
#define SPI_NOR_CR_RST_HOLD_SHIFT 7
#define SPI_NOR_CR_RST_HOLD_MASK (1 << SPI_NOR_CR_RST_HOLD_SHIFT)
#define SPI_NOR_CR_HOLD_MASK (~(1 << SPI_NOR_CR_RST_HOLD_SHIFT))
#define spi_nor_get_rst_hold_by_cr(cr) (((cr) & SPI_NOR_CR_RST_HOLD_MASK) \
>> SPI_NOR_CR_RST_HOLD_SHIFT)
#define spi_nor_set_rst_by_cr(cr) ((cr) | SPI_NOR_CR_RST_HOLD_MASK)
#define spi_nor_set_hold_by_cr(cr) ((cr) & SPI_NOR_CR_HOLD_MASK)
#ifdef CONFIG_SPI_BLOCK_PROTECT
#define DEBUG_SPI_NOR_BP 0
#define SPI_NOR_SR_SRWD_SHIFT 7
#define SPI_NOR_SR_SRWD_MASK (1 << SPI_NOR_SR_SRWD_SHIFT)
#define SPI_NOR_SR_BP0_SHIFT 2
#define SPI_NOR_SR_BP_WIDTH_4 0xf
#define SPI_NOR_SR_BP_MASK_4 (SPI_NOR_SR_BP_WIDTH_4 << SPI_NOR_SR_BP0_SHIFT)
#define SPI_NOR_SR_BP_WIDTH_3 0x7
#define SPI_NOR_SR_BP_MASK_3 (SPI_NOR_SR_BP_WIDTH_3 << SPI_NOR_SR_BP0_SHIFT)
#define SPI_NOR_SR_TB_SHIFT 3
#define SPI_NOR_SR_TB_MASK (1 << SPI_NOR_SR_TB_SHIFT)
#define SPI_NOR_SR_TB_SHIFT_S 5
#define SPI_NOR_SR_TB_MASK_S (1 << SPI_NOR_SR_TB_SHIFT_S)
#define spi_bp_bottom_rdcr_set_s(config) ((config) | \
(0x01 << SPI_NOR_SR_TB_SHIFT_S))
#define spi_bp_bottom_rdcr_set(config) ((config) | \
(0x01 << SPI_NOR_SR_TB_SHIFT))
#define spi_bp_bottom_rdsr_set_1(bp_num) (0x1 << (2 + bp_num))
#define spi_bp_bottom_rdsr_set_0(bp_num) (~(0x1 << (2 + bp_num)))
#define lock_level_max(bp_num) (((0x01) << bp_num) - 1)
#endif /* CONFIG_SPI_BLOCK_PROTECT */
#ifdef CONFIG_DTR_MODE_SUPPORT
#define DTR_DUMMY_CYCLES_4 4
#define DTR_DUMMY_CYCLES_6 6
#define DTR_DUMMY_CYCLES_8 8
#define DTR_DUMMY_CYCLES_10 10
#define dtr_rdcr_dc_mask(_val) (_val)
#define DTR_RDSR_DC_SHIFT 14
#define DTR_RDCR_DC_SHIFT 6
#define dtr_rdcr_dc_bit_clr(_reg) ((_reg) & (~(3 << DTR_RDSR_DC_SHIFT)))
#define dtr_gd_dc_bit_clr(_reg) ((_reg) & (0xfe))
#define dtr_py_dc_bit_clr(_reg) ((_reg) & (0xf7))
#define dtr_xmc_dc_bit_clr(_reg) ((_reg) & (~(3)))
#define DTR_MODE_REQUEST_SHIFT 2
#define DTR_TRAINING_POINT_NUM 12
#define DTR_TRAINING_POINT_MASK 12
#define dtr_training_point_clr(_reg) ((_reg) & (~(0xf << 12)))
#define DTR_TRAINING_CMP_ADDR_SHIFT (CONFIG_BOOT_HEAD_SIZE)
#define DTR_TRAINING_CMP_ADDR_S (CONFIG_SYS_TEXT_BASE_ORI + \
DTR_TRAINING_CMP_ADDR_SHIFT)
#define DTR_TRAINING_CMP_LEN 0x100
#define SFDP_BUF_LEN 0x33
#define SFDP_DTR_BIT_SHIFT 3
#define SFDP_DTR_BYTE_SHIFT 0x32
#define SFDP_DTR_BIT_MASK 0x1
#define DEVICE_ID_SUPPORT_DTR_WINBOND 0x70
#endif /* CONFIG_DTR_MODE_SUPPORT */
/* MXIC Config Register's dummy cycle bits */
#define CR_DUMMY_CYCLE (0x03 << 6)
#define SPI_CMD_RDCR_MX 0x15 /* MXIC Read Config Register */
#define DTR_MODE_REQUEST_SHIFT 2
#define SPI_NOR_SR_WIP_MASK (1 << 0)
struct fmc_host {
struct spi_flash spi_nor_flash[1];
struct mtd_info_ex *spi_nor_info;
struct fmc_spi spi[CONFIG_SPI_NOR_MAX_CHIP_NUM];
void *regbase;
void *iobase;
void (*set_system_clock)(struct spi_op *op, int clk_en);
void (*set_host_addr_mode)(struct fmc_host *host, int enable);
#ifdef CONFIG_SPI_BLOCK_PROTECT
unsigned int start_addr;
unsigned int end_addr;
unsigned char cmp;
unsigned int bp_num;
/* the BT bit location, decide the data num count */
unsigned int bt_loc;
unsigned char level;
#endif
#ifdef CONFIG_DTR_MODE_SUPPORT
unsigned int dtr_mode_en;
unsigned int dtr_training_flag;
#endif
};
#ifdef CONFIG_SPI_BLOCK_PROTECT
unsigned short fmc100_set_spi_lock_info(struct fmc_host *host);
void fmc100_get_bp_lock_level(struct fmc_host *host);
void fmc100_spi_lock(struct fmc_host *host, unsigned char level);
void fmc100_spi_flash_lock(unsigned char cmp, unsigned char level,
unsigned char op);
unsigned short fmc100_handle_bp_rdcr_info(struct fmc_host *host,
u_char cmd);
unsigned char fmc100_bp_to_level(struct fmc_host *host);
unsigned short fmc100_handle_bp_rdsr_info(struct fmc_host *host,
u_char cmd);
#endif
unsigned char spi_general_get_flash_register(struct fmc_spi *spi,
u_char cmd);
#define spiflash_to_host(_spiflash) ((struct fmc_host *)(_spiflash))
#ifdef CONFIG_DTR_MODE_SUPPORT
void fmc_dtr_mode_ctrl(struct fmc_spi *spi, int dtr_en);
unsigned int spi_dtr_training(struct fmc_host *host);
void spi_dtr_to_sdr_switch(struct fmc_spi *spi);
int spi_dtr_dummy_training_set(struct fmc_host *host, int dtr_en);
void fmc_check_spi_dtr_support(struct fmc_spi *spi, u_char *ids, int len);
unsigned int spi_mxic_check_spi_dtr_support(struct fmc_spi *spi);
#endif
void fmc100_read_ids(const struct fmc_spi *, u_char, u_char* const);
void fmc100_op_reg(struct fmc_spi *spi, unsigned char opcode,
unsigned int len, unsigned char optype);
int fmc_spi_nor_probe(struct mtd_info_ex *mtd, struct fmc_spi *spi);
int fmc100_spi_nor_init(struct fmc_host *);
struct spi_flash *fmc100_spi_nor_scan(struct fmc_host *host);
#endif /* End of __FMC100_H__ */
@@ -0,0 +1,183 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#include "fmc100_os.h"
#include <common.h>
#include <linux/mtd/mtd.h>
#include <asm/io.h>
static struct fmc_host fmc100_host;
static struct mtd_info_ex fmc100_spi_nor_info = {.type = 0, };
static void fmc100_driver_shutdown(void)
{
unsigned int start_up_addr_mode = get_fmc_boot_mode();
if (start_up_addr_mode == SPI_NOR_ADDR_MODE_3_BYTES) {
int ix;
struct fmc_host *host = &fmc100_host;
struct fmc_spi *spi = host->spi;
struct mtd_info_ex *spi_nor_info = &fmc100_spi_nor_info;
fmc_dev_type_switch(FLASH_TYPE_SPI_NOR);
for (ix = 0; ix < spi_nor_info->numchips; ix++, spi++) {
/* 4 byte addr mode */
if (spi->addrcycle == 4) {
spi->driver->wait_ready(spi);
spi->driver->entry_4addr(spi, DISABLE);
}
}
}
}
static int fmc100_driver_probe(void)
{
int ret;
struct fmc_host *host = &fmc100_host;
fmc_pr(BT_DBG, "\t|*-Start SPI nor flash driver probe\n");
/* FMC ip version check */
ret = fmc_ip_ver_check();
if (ret) {
fmc_pr(BT_DBG, "\t|*-IP version unknown, result: %d\n", ret);
return ret;
}
fmc_pr(BT_DBG, "\t||-SPI nor host init\n");
memset((char *)host, 0, sizeof(struct fmc_host));
ret = fmc100_spi_nor_init(host);
if (ret) {
fmc_pr(BT_DBG, "Error: SPI Nor init failed, ret: %d\n", ret);
goto end;
}
end:
fmc_pr(BT_DBG, "\t|*-End SPI nor flash driver probe\n");
return ret;
}
struct mtd_info_ex *fmc100_get_spi_nor_info(struct spi_flash *spi_nor_flash)
{
if (fmc100_spi_nor_info.type == 0) {
if (fmc100_spi_nor_probe(NULL) == NULL)
return NULL;
}
return &fmc100_spi_nor_info;
}
static void fmc100_probe_spi_size(struct spi_flash* const spi_nor_flash)
{
struct fmc_host *host = &fmc100_host;
struct fmc_spi *spi = host->spi;
unsigned int ix;
unsigned int total = 0;
struct mtd_info_ex *spi_nor_info = host->spi_nor_info;
fmc_pr(BT_DBG, "\t|*-Start probe SPI nor flash total size\n");
for (ix = 0; ix < spi_nor_info->numchips; ix++, spi++) {
fmc_pr(BT_DBG, "\t||-SPI nor flash[%d]: %dMB\n", ix,
(u_int)byte_to_mb(spi->chipsize));
total += spi->chipsize;
}
spi_nor_flash->size = total;
fmc_pr(BT_DBG, "\t|*-Probe SPI nor total size: %dMB, chip num: %d\n",
byte_to_mb(spi_nor_flash->size), spi_nor_info->numchips);
}
struct spi_flash *fmc100_spi_nor_probe(struct mtd_info_ex **spi_nor_info)
{
static struct spi_flash *spi_nor_flash = NULL;
fmc_pr(BT_DBG, "\t*-Start SPI Nor flash probe\n");
if (spi_nor_flash) {
fmc_pr(BT_DBG, "\t*-SPI Nor flash is initialized.\n");
return spi_nor_flash;
}
/* Check current SPI device type whether SPI nor */
fmc_dev_type_switch(FLASH_TYPE_SPI_NOR);
fmc_pr(BT_DBG, "\t|-SPI Nor flash driver probe\n");
if (!fmc100_driver_probe()) {
struct fmc_host *host = &fmc100_host;
fmc_pr(BT_DBG, "\t|-SPI nor flash scanning\n");
host->spi_nor_info = &fmc100_spi_nor_info;
spi_nor_flash = fmc100_spi_nor_scan(host);
if (spi_nor_flash) {
*spi_nor_info =
fmc100_get_spi_nor_info(spi_nor_flash);
if (*spi_nor_info == NULL)
return NULL;
fmc100_probe_spi_size(spi_nor_flash);
printf("SPI Nor total size: %uMB\n",
byte_to_mb(spi_nor_flash->size));
fmc_pr(BT_DBG, "\t|-Add func hook for Reset cmd\n");
add_shutdown(fmc100_driver_shutdown);
goto end;
}
}
spi_nor_flash = NULL;
fmc100_spi_nor_info.type = 0;
end:
/* Change SPI device type to default */
fmc_dev_type_switch(FLASH_TYPE_DEFAULT);
fmc_pr(BT_DBG, "\t*-End SPI Nor flash probe\n");
return spi_nor_flash;
}
#ifdef CONFIG_SPI_BLOCK_PROTECT
void fmc100_spi_flash_lock(unsigned char cmp, unsigned char level,
unsigned char op)
{
struct fmc_host *host = &fmc100_host;
struct spi_flash *nor = host->spi_nor_flash;
host->cmp = cmp;
if (op == BP_OP_GET) {
puts("Get spi lock information\n");
if (host->level) {
if (host->level == nor->bp_level_max)
puts("all blocks are locked.\n");
else
printf("level: %d\n", host->level);
printf("Spi is locked. lock address[0 => %#x]\n",
host->end_addr);
} else {
puts("all blocks are unlocked.\n");
}
return;
}
if (op == BP_OP_SET) {
if (level) {
if (level == nor->bp_level_max)
puts("lock all blocks.\n");
else
printf("lock level: %d\n", level);
} else {
puts("unlock all block.\n");
}
fmc100_spi_lock(host, level);
return;
}
printf("%s ERROR: Invalid optin argument!", __func__);
}
#endif /* CONFIG_SPI_BLOCK_PROTECT */
@@ -0,0 +1,14 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifndef __FMC100_OS_H__
#define __FMC100_OS_H__
#include <linux/lotus/fmc.h>
#include "fmc100.h"
/*****************************************************************************/
#endif /* End of __FMC100_OS_H__ */
@@ -0,0 +1,280 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#define GD_SPI_CMD_RDSR1 0x35 /* Read Status Register-1 */
/*
* enable QE bit if QUAD read write is supported by GD "25qxxx" SPI
*/
#ifndef CONFIG_DTR_MODE_SUPPORT
static void clear_dtr_mode_gd(struct fmc_spi *spi)
{
unsigned int regval;
struct fmc_host *host = (struct fmc_host *)spi->host;
unsigned char config;
unsigned short reg;
config = spi_general_get_flash_register(spi, SPI_CMD_RDSR3);
fmc_pr(DTR_DB, "Get Status Register-3[%#x]\n", config);
regval = fmc_read(host, FMC_GLOBAL_CFG);
if ((regval >> DTR_MODE_REQUEST_SHIFT) & 0x1) {
regval &= (~(1 << DTR_MODE_REQUEST_SHIFT));
regval = fmc_write(host, FMC_GLOBAL_CFG, regval);
}
if (config & 0x1) {
config &= (0xfe);
reg = ((unsigned short)config);
writew(reg, host->iobase);
spi->driver->write_enable(spi);
fmc100_op_reg(spi, SPI_CMD_WRSR3, sizeof(unsigned char),
fmc_op_write_data_en(ENABLE));
}
}
#endif
static void set_cmd(struct fmc_spi* const spi, u8 cmd, u8 len)
{
struct fmc_host *host = (struct fmc_host *)spi->host;
unsigned int regval;
regval = fmc_cmd_cmd1(cmd);
fmc_write(host, FMC_CMD, regval);
fmc_pr(QE_DBG, "\t|-Set CMD[%#x]%#x\n", FMC_CMD, regval);
regval = op_cfg_fm_cs(spi->chipselect) | OP_CFG_OEN_EN;
fmc_write(host, FMC_OP_CFG, regval);
fmc_pr(QE_DBG, "\t|-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, regval);
regval = fmc_data_num_cnt(len);
fmc_write(host, FMC_DATA_NUM, regval);
fmc_pr(QE_DBG, "\t|-Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, regval);
regval = fmc_op_cmd1_en(ENABLE) |
fmc_op_write_data_en(ENABLE) |
FMC_OP_REG_OP_START;
fmc_write(host, FMC_OP, regval);
fmc_pr(QE_DBG, "\t|-Set OP[%#x]%#x\n", FMC_OP, regval);
fmc_cmd_wait_cpu_finish(host);
spi->driver->wait_ready(spi);
}
static int spi_gd25q256_entry_4addr(struct fmc_spi *spi, int enable)
{
return 0;
}
static int gd_16pin_qe_enable(struct fmc_spi * const spi, int op)
{
struct fmc_host *host = (struct fmc_host *)spi->host;
unsigned char config;
unsigned char status;
const char *str[] = {"Disable", "Enable"};
#ifndef CONFIG_DTR_MODE_SUPPORT
clear_dtr_mode_gd(spi);
#endif
config = spi_general_get_flash_register(spi, GD_SPI_CMD_RDSR1);
fmc_pr(QE_DBG, "\t|-Read GD SR-1[%#x], val: %#x\n", GD_SPI_CMD_RDSR1,
config);
if (op && (op == spi_nor_get_qe_by_cr(config))) {
fmc_pr(QE_DBG, "\t* Quad was %sd, status:%#x\n", str[op],
config);
return op;
}
/* First, we enable/disable QE for 16Pin GD flash, use WRSR[01h] cmd */
fmc_pr(QE_DBG, "\t|-First, 16Pin GD flash %s Quad.\n", str[op]);
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR);
fmc_pr(QE_DBG, "\t|-Read Status Register[%#x]%#x\n", SPI_CMD_RDSR,
status);
spi->driver->write_enable(spi);
if (op)
config |= SPI_NOR_CR_QE_MASK;
else
config &= ~SPI_NOR_CR_QE_MASK;
writeb(status, host->iobase);
writeb(config, host->iobase + SPI_NOR_SR_LEN);
fmc_pr(QE_DBG, "\t|-Write IO[%p]%#x\n", host->iobase,
*(unsigned short *)host->iobase);
set_cmd(spi, SPI_CMD_WRSR, SPI_NOR_SR_LEN + SPI_NOR_CR_LEN);
config = spi_general_get_flash_register(spi, GD_SPI_CMD_RDSR1);
fmc_pr(QE_DBG, "\t|-Read GD SR-1[%#x], val: %#x\n", GD_SPI_CMD_RDSR1,
config);
if (op == spi_nor_get_qe_by_cr(config)) {
fmc_pr(QE_DBG, "\t|-16P %s Quad success reg: %#x\n", str[op],
config);
return op;
} else {
fmc_pr(QE_DBG, "\t|-16P %s Quad failed, reg: %#x\n", str[op],
config);
}
return 0;
}
static void gd_8pin_qe_enable(struct fmc_spi * const spi, int op)
{
unsigned char config;
unsigned char status;
const char *str[] = {"Disable", "Enable"};
struct fmc_host *host = (struct fmc_host *)spi->host;
fmc_pr(QE_DBG, "\t|-Second, 8Pin GD flash %s Quad.\n", str[op]);
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR);
fmc_pr(QE_DBG, "\t|-Read Status Register[%#x]:%#x\n", SPI_CMD_RDSR,
status);
if (!(status & STATUS_WEL_MASK))
spi->driver->write_enable(spi);
config = spi_general_get_flash_register(spi, SPI_CMD_RDSR2);
fmc_pr(QE_DBG, "\t|-Read SR-2[%#x], val: %#x\n", SPI_CMD_RDSR2,
config);
if (op && (op == spi_nor_get_qe_by_cr(config))) {
fmc_pr(QE_DBG, "\t* Quad was %sd, status:%#x\n", str[op],
config);
return;
}
if (op)
config |= SPI_NOR_CR_QE_MASK;
else
config &= ~SPI_NOR_CR_QE_MASK;
writeb(config, host->iobase);
fmc_pr(QE_DBG, "\t|-Write IO[%p]%#x\n", host->iobase,
*(unsigned char *)host->iobase);
set_cmd(spi, SPI_CMD_WRSR2, SPI_NOR_CR_LEN);
config = spi_general_get_flash_register(spi, SPI_CMD_RDSR2);
fmc_pr(QE_DBG, "\t|-Read GD SR-2[%#x], val: %#x\n", SPI_CMD_RDSR2,
config);
if (op == spi_nor_get_qe_by_cr(config))
fmc_pr(QE_DBG, "\t|-8P %s Quad success, reg: %#x.\n", str[op],
config);
else
db_msg("Error: %s Quad failed, reg: %#x\n", str[op], config);
return;
}
static int spi_gd25qxxx_qe_enable(struct fmc_spi *spi)
{
unsigned char op;
const char *str[] = {"Disable", "Enable"};
if (!spi || !spi->host)
return -1;
op = spi_is_quad(spi);
fmc_pr(QE_DBG, "\t*-Start GD SPI nor %s Quad.\n", str[op]);
/* First, we enable/disable QE for 16Pin GD flash, use WRSR[01h] cmd */
if (gd_16pin_qe_enable(spi, op))
goto qe_end;
/* Second, we enable/disable QE for 8Pin GD flash, use WRSR2[31h] cmd */
gd_8pin_qe_enable(spi, op);
qe_end:
/* Enable the reset pin when working on dual mode for 8PIN */
if (!op)
spi_nor_reset_pin_enable(spi, ENABLE);
fmc_pr(QE_DBG, "\t*-End GD SPI nor %s Quad end.\n", str[op]);
return op;
}
#ifdef CONFIG_DTR_MODE_SUPPORT
void spi_gd_set_reg(struct fmc_spi *spi)
{
unsigned int regval;
struct fmc_host *host = (struct fmc_host *)spi->host;
regval = fmc_cmd_cmd1(SPI_CMD_WRSR3);
fmc_write(host, FMC_CMD, regval);
fmc_pr(DTR_DB, " Set CMD[%#x]%#x\n", FMC_CMD, regval);
regval = op_cfg_fm_cs(spi->chipselect) | OP_CFG_OEN_EN;
fmc_write(host, FMC_OP_CFG, regval);
fmc_pr(DTR_DB, " Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, regval);
regval = fmc_data_num_cnt(SPI_NOR_SR_LEN);
fmc_write(host, FMC_DATA_NUM, regval);
fmc_pr(DTR_DB, " Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, regval);
regval = fmc_op_cmd1_en(ENABLE) |
fmc_op_write_data_en(ENABLE) |
FMC_OP_REG_OP_START;
fmc_write(host, FMC_OP, regval);
fmc_pr(DTR_DB, " Set OP[%#x]%#x\n", FMC_OP, regval);
}
int spi_gd_output_driver_strength_set(struct fmc_spi *spi, int dtr_en)
{
unsigned char config;
unsigned char reg;
unsigned char val;
unsigned int ix;
struct fmc_host *host = NULL;
/* DC | Numbers of Dummy clock cycles| Quad IO DTR Read */
/* 0(default)| 8 | 66 */
/* 1 | 10 | 80 */
unsigned int str_dummy[] = {
DTR_DUMMY_CYCLES_8, dtr_rdcr_dc_mask(0),
DTR_DUMMY_CYCLES_10, dtr_rdcr_dc_mask(1),
0, 0,
};
val = 0;
if (!spi || !spi->driver)
return -1;
host = (struct fmc_host *)spi->host;
if (!host)
return -1;
/* get the RDCR and RDSR */
spi->driver->wait_ready(spi);
/* setting the DC value to match high system clock */
config = spi_general_get_flash_register(spi, SPI_CMD_RDSR3);
fmc_pr(DTR_DB, "Get Status Register-3[%#x]\n", config);
if (dtr_en == ENABLE) {
/* setting DC value */
fmc_pr(DTR_DB, "Get the dummy value[%#x]\n", spi->read->dummy);
/* Only the element with an even number of arrays is required, so increase is 2 */
for (ix = 0; str_dummy[ix]; ix += _2B) {
if (spi->read->dummy < str_dummy[ix])
break;
val = (unsigned char)str_dummy[ix + 1];
}
} else {
val = dtr_rdcr_dc_mask(0);
}
reg = dtr_gd_dc_bit_clr(config) | val;
fmc_pr(DTR_DB, "Get the reg value[%#x]\n", reg);
spi->driver->write_enable(spi);
writew(reg, host->iobase);
fmc_pr(DTR_DB, "Write IO[%p]%#x\n", host->iobase,
*(unsigned short *)host->iobase);
spi_gd_set_reg(spi);
fmc_cmd_wait_cpu_finish(host);
config = spi_general_get_flash_register(spi, SPI_CMD_RDSR3);
fmc_pr(DTR_DB, "Get Status Register-3[%#x]\n", config);
if ((config & 0x1) != (unsigned char)val) {
printf("* Set DC dummy fail.\n");
return -1;
}
return 0;
}
#endif /* CONFIG_DTR_MODE_SUPPORT */
@@ -0,0 +1,401 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
/*
Get status/config register value from SPI Nor flash
*/
unsigned char spi_general_get_flash_register(struct fmc_spi * const spi, u_char cmd)
{
unsigned char status;
unsigned int reg;
struct fmc_host *host = (struct fmc_host *)spi->host;
host->set_system_clock(NULL, ENABLE);
fmc_pr(SR_DBG, "\t * Start get flash Register[%#x]\n", cmd);
reg = op_cfg_fm_cs(spi->chipselect) | OP_CFG_OEN_EN;
fmc_write(host, FMC_OP_CFG, reg);
if (cmd == SPI_CMD_RDSR) {
reg = fmc_op_read_status_en(ENABLE) | FMC_OP_REG_OP_START;
goto cmd_config_done;
}
fmc_write(host, FMC_CMD, cmd);
fmc_pr(SR_DBG, "\t Set CMD[%#x]%#x\n", FMC_CMD, cmd);
reg = fmc_data_num_cnt(SPI_NOR_CR_LEN);
fmc_write(host, FMC_DATA_NUM, reg);
fmc_pr(SR_DBG, "\t Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, reg);
reg = fmc_op_cmd1_en(ENABLE) | fmc_op_read_data_en(ENABLE) |
FMC_OP_REG_OP_START;
cmd_config_done:
fmc_write(host, FMC_OP, reg);
fmc_pr(SR_DBG, "\t Set OP[%#x]%#x\n", FMC_OP, reg);
fmc_cmd_wait_cpu_finish(host);
if (cmd == SPI_CMD_RDSR)
status = fmc_read(host, FMC_STATUS);
else
status = readb(host->iobase);
fmc_pr(SR_DBG, "\t * End get flash Register[%#x], val: %#x\n", cmd,
status);
return status;
}
/*
Read status[C0H]:[0]bit OIP, judge whether the device is busy or not
*/
static int spi_general_wait_ready(struct fmc_spi * const spi)
{
unsigned char status;
/* need a big number,so move left 20 bit */
unsigned int deadline = 1 << 20;
if (!spi || !spi->host)
return -1;
do {
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR);
if (!(status & SPI_NOR_SR_WIP_MASK))
return 0;
udelay(1); /* delay 1 us */
} while (deadline--);
db_msg("Error: SPI nor wait ready timeout, status[%#x]\n", status);
return 1;
}
/*
Send write enable cmd to SPI Nor, status[C0H]:[2]bit WEL must be set 1
*/
static int spi_general_write_enable(struct fmc_spi *spi)
{
unsigned char status;
unsigned int reg;
if (!spi || !spi->driver || !spi->host) {
printf("%s:spi data is NULL, please check input parameter\n", __func__);
return -1;
}
struct fmc_host *host = (struct fmc_host *)spi->host;
if (WE_DBG)
printf("\n");
fmc_pr(WE_DBG, "\t * Start Write Enable\n");
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR);
fmc_pr(WE_DBG, "\t Read Status Register[%#x]:%#x\n", SPI_CMD_RDSR,
status);
if (status & STATUS_WEL_MASK) {
fmc_pr(WE_DBG, "\t Write Enable was opened! reg: %#x\n",
status);
return 0;
}
reg = fmc_read(host, FMC_GLOBAL_CFG);
if (reg & FMC_GLOBAL_CFG_WP_ENABLE) {
reg &= ~FMC_GLOBAL_CFG_WP_ENABLE;
fmc_write(host, FMC_GLOBAL_CFG, reg);
fmc_pr(WE_DBG, "\t Set GLOBAL_CFG[%#x]%#x\n",
FMC_GLOBAL_CFG, reg);
}
reg = fmc_cmd_cmd1(SPI_CMD_WREN);
fmc_write(host, FMC_CMD, reg);
fmc_pr(WE_DBG, "\t Set CMD[%#x]%#x\n", FMC_CMD, reg);
reg = op_cfg_fm_cs(spi->chipselect) | OP_CFG_OEN_EN;
fmc_write(host, FMC_OP_CFG, reg);
fmc_pr(WE_DBG, "\t Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
reg = fmc_op_cmd1_en(ENABLE) | FMC_OP_REG_OP_START;
fmc_write(host, FMC_OP, reg);
fmc_pr(WE_DBG, "\t Set OP[%#x]%#x\n", FMC_OP, reg);
fmc_cmd_wait_cpu_finish(host);
spi->driver->wait_ready(spi);
reg = spi_general_get_flash_register(spi, SPI_CMD_RDSR);
if (reg & STATUS_WEL_MASK) {
fmc_pr(WE_DBG, "\t Write Enable success.reg: %#x\n", reg);
} else {
db_msg("Error: Write Enable failed! status: %#x\n", reg);
return status;
}
fmc_pr(WE_DBG, "\t * End Write Enable\n");
return 0;
}
/*
enable 4byte address for SPI which memory more than 16M
*/
static int spi_general_entry_4addr(struct fmc_spi *spi, int enable)
{
unsigned char status;
unsigned int reg;
const char *str[] = {"Disable", "Enable"};
struct fmc_host *host = NULL;
if (!spi || !spi->driver)
return -1;
host = (struct fmc_host*)spi->host;
if (!host)
return -1;
fmc_pr(AC_DBG, "\t* Start SPI Nor flash %s 4-byte mode.\n",
str[enable]);
if (spi->addrcycle != SPI_NOR_4BYTE_ADDR_LEN) {
fmc_pr(AC_DBG, "\t* Flash isn't support entry 4-byte mode.\n");
return 0;
}
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR3);
fmc_pr(AC_DBG, "\t Read Status Register-3[%#x]:%#x\n", SPI_CMD_RDSR3,
status);
if (spi_nor_get_4byte_by_cr(status) == enable) {
fmc_pr(AC_DBG, "\t* 4-byte was %sd, reg:%#x\n", str[enable],
status);
return 0;
}
if (enable)
reg = SPI_CMD_EN4B;
else
reg = SPI_CMD_EX4B;
fmc_write(host, FMC_CMD, fmc_cmd_cmd1(reg));
fmc_pr(AC_DBG, "\t Set CMD[%#x]%#x\n", FMC_CMD, reg);
reg = op_cfg_fm_cs(spi->chipselect) | OP_CFG_OEN_EN;
fmc_write(host, FMC_OP_CFG, reg);
fmc_pr(AC_DBG, "\t Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
reg = fmc_op_cmd1_en(ENABLE) | FMC_OP_REG_OP_START;
fmc_write(host, FMC_OP, reg);
fmc_pr(AC_DBG, "\t Set OP[%#x]%#x\n", FMC_OP, reg);
fmc_cmd_wait_cpu_finish(host);
spi->driver->wait_ready(spi);
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR3);
fmc_pr(AC_DBG, "\t Read SR-3[%#x]:%#x\n", SPI_CMD_RDSR3,
status);
if (spi_nor_get_4byte_by_cr(status) != enable) {
db_msg("Error: %s 4-byte failed! SR3:%#x\n",
str[enable], status);
return status;
}
fmc_pr(AC_DBG, "\t %s 4-byte success, SR3:%#x\n", str[enable], status);
fmc_pr(AC_DBG, "\t* End SPI Nor flash %s 4-byte mode.\n", str[enable]);
return 0;
}
/*
judge whether SPI Nor support QUAD read write or not
*/
unsigned char spi_is_quad(const struct fmc_spi * const spi)
{
char *const if_str[] = {"STD", "DUAL", "DIO", "QUAD", "QIO", "DTR"};
if (!spi) {
printf("%s:spi is NULL, please check input parameter\n", __func__);
return 0;
}
fmc_pr(QE_DBG, "\t\t|*-SPI read iftype: %s write iftype: %s\n",
if_str[spi->read->iftype], if_str[spi->write->iftype]);
if ((spi->read->iftype == IF_TYPE_QUAD) ||
(spi->read->iftype == IF_TYPE_QIO) ||
(spi->write->iftype == IF_TYPE_QUAD) ||
#ifdef CONFIG_DTR_MODE_SUPPORT
(spi->read->iftype == IF_TYPE_DTR) ||
#endif
(spi->write->iftype == IF_TYPE_QIO)
)
return 1;
return 0;
}
static void spi_general_set_cmd(struct fmc_spi * const spi)
{
unsigned int reg;
struct fmc_host *host = (struct fmc_host *)spi->host;
reg = fmc_cmd_cmd1(SPI_CMD_WRSR);
fmc_write(host, FMC_CMD, reg);
fmc_pr(QE_DBG, "\t|-Set CMD[%#x]%#x\n", FMC_CMD, reg);
reg = op_cfg_fm_cs(spi->chipselect) | OP_CFG_OEN_EN;
fmc_write(host, FMC_OP_CFG, reg);
fmc_pr(QE_DBG, "\t|-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
reg = fmc_data_num_cnt(SPI_NOR_SR_LEN + SPI_NOR_CR_LEN);
fmc_write(host, FMC_DATA_NUM, reg);
fmc_pr(QE_DBG, "\t|-Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, reg);
reg = fmc_op_cmd1_en(ENABLE) |
fmc_op_write_data_en(ENABLE) |
FMC_OP_REG_OP_START;
fmc_write(host, FMC_OP, reg);
fmc_pr(QE_DBG, "\t|-Set OP[%#x]%#x\n", FMC_OP, reg);
fmc_cmd_wait_cpu_finish(host);
}
/*
* enable QE bit if QUAD read write is supported by SPI
*/
static int spi_general_qe_enable(struct fmc_spi *spi)
{
unsigned char status;
unsigned char config;
unsigned char op;
const char *str[] = {"Disable", "Enable"};
struct fmc_host *host = NULL;
if (!spi || !spi->driver)
return -1;
host = (struct fmc_host *)spi->host;
if (!host || !host->iobase)
return -1;
op = spi_is_quad(spi);
fmc_pr(QE_DBG, "\t*-Start SPI Nor %s Quad.\n", str[op]);
config = spi_general_get_flash_register(spi, SPI_CMD_RDCR);
fmc_pr(QE_DBG, "\t|-Read Config Register[%#x]%#x\n", SPI_CMD_RDCR,
config);
if (op == spi_nor_get_qe_by_cr(config)) {
fmc_pr(QE_DBG, "\t* Quad was %sd, config:%#x\n", str[op],
config);
return op;
}
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR);
fmc_pr(QE_DBG, "\t|-Read Status Register[%#x]%#x\n", SPI_CMD_RDSR,
status);
spi->driver->write_enable(spi);
if (op)
config |= SPI_NOR_CR_QE_MASK;
else
config &= ~SPI_NOR_CR_QE_MASK;
writeb(status, host->iobase);
writeb(config, host->iobase + SPI_NOR_SR_LEN);
fmc_pr(QE_DBG, "\t|-Write IO[%p]%#x\n", host->iobase,
*(unsigned short *)host->iobase);
spi_general_set_cmd(spi);
spi->driver->wait_ready(spi);
config = spi_general_get_flash_register(spi, SPI_CMD_RDCR);
if (op == spi_nor_get_qe_by_cr(config)) {
fmc_pr(QE_DBG, "\t|-%s Quad success, config: %#x\n", str[op],
config);
} else {
db_msg("Error: %s Quad failed! reg: %#x\n", str[op], config);
}
fmc_pr(QE_DBG, "\t* End SPI Nor %s Quad.\n", str[op]);
return op;
}
/*
some chip don't QUAD enable
*/
static int spi_do_not_qe_enable(struct fmc_spi *spi)
{
return 0;
}
static void reset_pin_enable_fmc_op(struct fmc_host* const host,
struct fmc_spi* const spi)
{
unsigned int regval;
regval = fmc_cmd_cmd1(SPI_CMD_WRSR3);
fmc_write(host, FMC_CMD, regval);
fmc_pr(RST_DB, "\t|-Set CMD[%#x]%#x\n", FMC_CMD, regval);
regval = op_cfg_fm_cs(spi->chipselect) | OP_CFG_OEN_EN;
fmc_write(host, FMC_OP_CFG, regval);
fmc_pr(RST_DB, "\t|-Set OP_CFG[%#x]%#x\n",
FMC_OP_CFG, regval);
regval = fmc_data_num_cnt(SPI_NOR_CR_LEN);
fmc_write(host, FMC_DATA_NUM, regval);
fmc_pr(RST_DB, "\t|-Set DATA_NUM[%#x]%#x\n",
FMC_DATA_NUM, regval);
regval = fmc_op_cmd1_en(ENABLE) |
fmc_op_write_data_en(ENABLE) |
FMC_OP_REG_OP_START;
fmc_write(host, FMC_OP, regval);
fmc_pr(RST_DB, "\t|-Set OP[%#x]%#x\n", FMC_OP, regval);
fmc_cmd_wait_cpu_finish(host);
}
/*
* some chip set the mux HOLD#/RESET#/IO3 pin to RESET#, as it is HOLD# default.
*/
static void spi_nor_reset_pin_enable(struct fmc_spi *spi, int enable)
{
unsigned char config;
const char *str[] = {"HOLD#", "RESET#"};
struct fmc_host *host = NULL;
if (!spi || !spi->driver)
return;
host = (struct fmc_host *)spi->host;
if (!host || !host->iobase)
return;
config = spi_general_get_flash_register(spi, SPI_CMD_RDSR3);
fmc_pr(RST_DB, "\t|-Read SR-3[%#x], val: %#x\n",
SPI_CMD_RDSR3, config);
if (enable == spi_nor_get_rst_hold_by_cr(config)) {
fmc_pr(RST_DB, " Device has worked on %s.\n", str[enable]);
return;
}
fmc_pr(RST_DB, " Start to enable %s function.\n", str[enable]);
spi->driver->write_enable(spi);
if (enable)
config = spi_nor_set_rst_by_cr(config);
else
config = spi_nor_set_hold_by_cr(config);
writeb(config, host->iobase);
fmc_pr(RST_DB, "\t|-Write IO[%p]%#x\n", host->iobase,
*(unsigned char *)host->iobase);
reset_pin_enable_fmc_op(host, spi);
spi->driver->wait_ready(spi);
config = spi_general_get_flash_register(spi, SPI_CMD_RDSR3);
fmc_pr(RST_DB, "\t|-Read SR-3[%#x], val: %#x\n",
SPI_CMD_RDSR3, config);
if (enable == spi_nor_get_rst_hold_by_cr(config))
fmc_pr(RST_DB, "\t|- Set the MUX pin to RESET# success!\n");
else
fmc_pr(RST_DB, "\t|- The MUX pin works on HOLD# or DNU!\n");
}
@@ -0,0 +1,91 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#define SPI_NOR_ISSI_QE_SHIFT 6
#define SPI_NOR_ISSI_SRWD_MASK (1 << 7)
#define SPI_NOR_ISSI_QE_MASK (1 << SPI_NOR_ISSI_QE_SHIFT)
#define spi_nor_issi_get_qe(sr) (((sr) & SPI_NOR_ISSI_QE_MASK) \
>> SPI_NOR_ISSI_QE_SHIFT)
static void spi_issi_set_cmd(struct fmc_spi * const spi)
{
unsigned int reg;
struct fmc_host *host = (struct fmc_host *)spi->host;
reg = fmc_cmd_cmd1(SPI_CMD_WRSR);
fmc_write(host, FMC_CMD, reg);
fmc_pr(QE_DBG, "\t|-Set CMD[%#x]%#x\n", FMC_CMD, reg);
reg = op_cfg_fm_cs(spi->chipselect) | OP_CFG_OEN_EN;
fmc_write(host, FMC_OP_CFG, reg);
fmc_pr(QE_DBG, "\t|-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
reg = fmc_data_num_cnt(SPI_NOR_SR_LEN);
fmc_write(host, FMC_DATA_NUM, reg);
fmc_pr(QE_DBG, "\t|-Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, reg);
reg = fmc_op_cmd1_en(ENABLE) |
fmc_op_write_data_en(ENABLE) |
FMC_OP_REG_OP_START;
fmc_write(host, FMC_OP, reg);
fmc_pr(QE_DBG, "\t|-Set OP[%#x]%#x\n", FMC_OP, reg);
fmc_cmd_wait_cpu_finish(host);
}
static int spi_issi_qe_enable(struct fmc_spi *spi)
{
unsigned char config;
unsigned char op;
const char *str[] = {"Disable", "Enable"};
struct fmc_host *host = NULL;
if (!spi || !spi->driver)
return -1;
host = (struct fmc_host *)spi->host;
if (!host || !host->iobase)
return -1;
op = spi_is_quad(spi);
fmc_pr(QE_DBG, "\t*-Start SPI Nor %s Quad.\n", str[op]);
config = spi_general_get_flash_register(spi, SPI_CMD_RDSR);
fmc_pr(QE_DBG, "\t|-Read Config Register[%#x]%#x\n", SPI_CMD_RDSR,
config);
if (op == spi_nor_issi_get_qe(config)) {
fmc_pr(QE_DBG, "\t* Quad was %sd, config:%#x\n", str[op],
config);
return op;
}
spi->driver->write_enable(spi);
config = spi_general_get_flash_register(spi, SPI_CMD_RDSR);
config &= ~SPI_NOR_ISSI_SRWD_MASK;
if (op)
config |= SPI_NOR_ISSI_QE_MASK;
else
config &= ~SPI_NOR_ISSI_QE_MASK;
writeb(config, host->iobase);
fmc_pr(QE_DBG, "\t|-Write IO[%p]%#x\n", host->iobase,
*(unsigned short *)host->iobase);
spi_issi_set_cmd(spi);
spi->driver->wait_ready(spi);
config = spi_general_get_flash_register(spi, SPI_CMD_RDSR);
if (op == spi_nor_issi_get_qe(config)) {
fmc_pr(QE_DBG, "\t|-%s Quad success, config: %#x\n", str[op],
config);
} else {
db_msg("Error: %s Quad failed! reg: %#x\n", str[op], config);
}
fmc_pr(QE_DBG, "\t* End SPI Nor %s Quad.\n", str[op]);
return op;
}
@@ -0,0 +1,91 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#define SPI_CMD_FIRST_RESET_4ADDR 0x66
#define SPI_CMD_SECOND_RESET_4ADDR 0x99
#define SPI_CMD_FLAG_SR_MICRON 0x70 /* READ FLAG STATUS REGISTER */
#define SPI_CMD_RD_RDCR_MICRON 0xB5 /* READ NONVOLATILE CONFIGURATION
REGISTER */
#define SPI_CMD_WR_RDCR_MICRON 0xB1 /* WRITE NONVOLATILE CONFIGURATION
REGISTER */
#define SPI_NOR_ADS_MASK 0x1
#define spi_nor_get_4byte_by_flag_sr(sr) ((sr) & SPI_NOR_ADS_MASK)
#define spi_nor_ads_set_4byte(cr) ((cr) & (~SPI_NOR_ADS_MASK))
#define spi_nor_ads_get_4byte(cr) ((cr) & SPI_NOR_ADS_MASK)
static void entry_4addr_fmc_op(struct fmc_host* const host,
struct fmc_spi* const spi,
int enable)
{
unsigned int reg;
if (enable)
reg = SPI_CMD_EN4B;
else
reg = SPI_CMD_EX4B;
fmc_write(host, FMC_CMD, fmc_cmd_cmd1(reg));
fmc_pr(AC_DBG, "\t Set CMD[%#x]%#x\n", FMC_CMD, reg);
reg = op_cfg_fm_cs(spi->chipselect) | OP_CFG_OEN_EN;
fmc_write(host, FMC_OP_CFG, reg);
fmc_pr(AC_DBG, "\t Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
reg = fmc_op_cmd1_en(ENABLE) | FMC_OP_REG_OP_START;
fmc_write(host, FMC_OP, reg);
fmc_pr(AC_DBG, "\t Set OP[%#x]%#x\n", FMC_OP, reg);
fmc_cmd_wait_cpu_finish(host);
}
static int spi_micron_entry_4addr(struct fmc_spi *spi, int enable)
{
unsigned char status;
const char *str[] = {"Disable", "Enable"};
struct fmc_host *host = NULL;
if (!spi || !spi->driver)
return -1;
host = (struct fmc_host *)spi->host;
if (!host)
return -1;
fmc_pr(AC_DBG, "\t* Start SPI Nor %s 4-byte mode.\n",
str[enable]);
if (spi->addrcycle != SPI_NOR_4BYTE_ADDR_LEN) {
fmc_pr(AC_DBG, "\t* Not support 4B mode.\n");
return 0;
}
status = spi_general_get_flash_register(spi, SPI_CMD_FLAG_SR_MICRON);
fmc_pr(AC_DBG, "\t Read flag status register[%#x]:%#x\n",
SPI_CMD_FLAG_SR_MICRON, status);
if (spi_nor_get_4byte_by_flag_sr(status) == enable) {
fmc_pr(AC_DBG, "\t* 4-byte was %sd, reg:%#x\n", str[enable],
status);
return 0;
}
spi->driver->write_enable(spi);
entry_4addr_fmc_op(host, spi, enable);
spi->driver->wait_ready(spi);
status = spi_general_get_flash_register(spi,
SPI_CMD_FLAG_SR_MICRON);
fmc_pr(AC_DBG, "\t Read flag status register[%#x]:%#x\n",
SPI_CMD_FLAG_SR_MICRON, status);
if (spi_nor_get_4byte_by_flag_sr(status) != enable) {
db_msg("Error: %s 4-byte failed! SR3:%#x\n",
str[enable], status);
return status;
}
fmc_pr(AC_DBG, "\t %s 4-byte success, SR3:%#x\n", str[enable], status);
fmc_pr(AC_DBG, "\t* End SPI Nor flash %s 4-byte mode.\n", str[enable]);
return 0;
}
@@ -0,0 +1,259 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
/* MXIC QE(bit) include in Status Register */
#define MX_SPI_NOR_SR_QE_SHIFT 6
#define MX_SPI_NOR_SR_QE_MASK (1 << MX_SPI_NOR_SR_QE_SHIFT)
#define mx_spi_nor_get_qe_by_sr(sr) (((sr) & MX_SPI_NOR_SR_QE_MASK) >> MX_SPI_NOR_SR_QE_SHIFT)
/*
* enable QE bit if 4X R/W is supported by MXIC "25L(256/257)35(E/F)" SPI
*/
#ifndef CONFIG_DTR_MODE_SUPPORT
static void clear_dtr_mode(struct fmc_spi *spi, unsigned char status)
{
unsigned int regval;
struct fmc_host *host = (struct fmc_host *)spi->host;
unsigned char config;
unsigned short reg;
config = spi_general_get_flash_register(spi, SPI_CMD_RDCR_MX);
regval = fmc_read(host, FMC_GLOBAL_CFG);
if ((regval >> DTR_MODE_REQUEST_SHIFT) & 0x1) {
regval &= (~(1 << DTR_MODE_REQUEST_SHIFT));
regval = fmc_write(host, FMC_GLOBAL_CFG, regval);
}
if (config & CR_DUMMY_CYCLE) {
config &= (~CR_DUMMY_CYCLE);
reg = ((unsigned short)config << SPI_NOR_CR_SHIFT) | status;
writew(reg, host->iobase);
spi->driver->write_enable(spi);
fmc100_op_reg(spi, SPI_CMD_WRSR, sizeof(unsigned short), fmc_op_write_data_en(ENABLE));
}
}
#endif
static void spi_mx25l25635e_set_cmd(struct fmc_spi * const spi)
{
unsigned int regval;
struct fmc_host *host = (struct fmc_host *)spi->host;
regval = fmc_cmd_cmd1(SPI_CMD_WRSR);
fmc_write(host, FMC_CMD, regval);
fmc_pr(QE_DBG, "\t||-Set CMD[%#x]%#x\n", FMC_CMD, regval);
regval = op_cfg_fm_cs(spi->chipselect) | OP_CFG_OEN_EN;
fmc_write(host, FMC_OP_CFG, regval);
fmc_pr(QE_DBG, "\t||-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, regval);
regval = fmc_data_num_cnt(SPI_NOR_SR_LEN);
fmc_write(host, FMC_DATA_NUM, regval);
fmc_pr(QE_DBG, "\t||-Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, regval);
regval = fmc_op_cmd1_en(ENABLE) | fmc_op_write_data_en(ENABLE) |
FMC_OP_REG_OP_START;
fmc_write(host, FMC_OP, regval);
fmc_pr(QE_DBG, "\t||-Set OP[%#x]%#x\n", FMC_OP, regval);
fmc_cmd_wait_cpu_finish(host);
}
static int spi_mx25l25635e_qe_enable(struct fmc_spi *spi)
{
unsigned char status;
unsigned char op;
const char *str[] = {"Disable", "Enable"};
struct fmc_host *host = NULL;
if (!spi || !spi->driver)
return -1;
host = (struct fmc_host *)spi->host;
if (!host || !host->iobase)
return -1;
op = spi_is_quad(spi);
fmc_pr(QE_DBG, "\t|*-Start MXIC SPI Nor %s Quad.\n", str[op]);
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR);
fmc_pr(QE_DBG, "\t||-Read Status Register[%#x]%#x\n", SPI_CMD_RDSR,
status);
#ifndef CONFIG_DTR_MODE_SUPPORT
clear_dtr_mode(spi, status);
#endif
if (mx_spi_nor_get_qe_by_sr(status) == op) {
fmc_pr(QE_DBG, "\t|*-Quad was %sd, status:%#x\n", str[op],
status);
return op;
}
spi->driver->write_enable(spi);
if (op)
status |= MX_SPI_NOR_SR_QE_MASK;
else
status &= ~MX_SPI_NOR_SR_QE_MASK;
writeb(status, host->iobase);
fmc_pr(QE_DBG, "\t||-Write IO[%p]%#x\n", host->iobase,
*(unsigned char *)host->iobase);
spi_mx25l25635e_set_cmd(spi);
spi->driver->wait_ready(spi);
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR);
if (mx_spi_nor_get_qe_by_sr(status) == op)
fmc_pr(QE_DBG, "\t||-%s Quad success, status:%#x.\n", str[op],
status);
else
db_msg("Error: %s Quad failed! reg: %#x\n", str[op], status);
fmc_pr(QE_DBG, "\t|*-End MXIC SPI Nor %s Quad.\n", str[op]);
return op;
}
#ifdef CONFIG_DTR_MODE_SUPPORT
void spi_mxic_set_reg(struct fmc_spi *spi)
{
unsigned int regval;
struct fmc_host *host = (struct fmc_host *)spi->host;
regval = fmc_cmd_cmd1(SPI_CMD_WRSR);
fmc_write(host, FMC_CMD, regval);
fmc_pr(DTR_DB, " Set CMD[%#x]%#x\n", FMC_CMD, regval);
regval = op_cfg_fm_cs(spi->chipselect) | OP_CFG_OEN_EN;
fmc_write(host, FMC_OP_CFG, regval);
fmc_pr(DTR_DB, " Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, regval);
regval = fmc_data_num_cnt(SPI_NOR_SR_LEN + SPI_NOR_CR_LEN);
fmc_write(host, FMC_DATA_NUM, regval);
fmc_pr(DTR_DB, " Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, regval);
regval = fmc_op_cmd1_en(ENABLE) |
fmc_op_write_data_en(ENABLE) |
FMC_OP_REG_OP_START;
fmc_write(host, FMC_OP, regval);
fmc_pr(DTR_DB, " Set OP[%#x]%#x\n", FMC_OP, regval);
}
int spi_mxic_output_driver_strength_set(struct fmc_spi *spi, int dtr_en)
{
unsigned char status;
unsigned char config;
unsigned short reg;
unsigned short val;
unsigned int ix;
struct fmc_host *host = NULL;
/* DC[1:0] | Numbers of Dummy clock cycles| Quad IO DTR Read */
/* 00(default)| 6 | 54 */
/* 01 | 6 | 54 */
/* 10 | 8 | 70/80R */
/* 11 | 10 | 84/100R */
unsigned int str_dummy[] = {
DTR_DUMMY_CYCLES_6, dtr_rdcr_dc_mask(0),
DTR_DUMMY_CYCLES_6, dtr_rdcr_dc_mask(1),
DTR_DUMMY_CYCLES_8, dtr_rdcr_dc_mask(2),
DTR_DUMMY_CYCLES_10, dtr_rdcr_dc_mask(3),
0, 0,
};
val = 0;
if (!spi || !spi->driver)
return -1;
host = (struct fmc_host *)spi->host;
if (!host)
return -1;
/* get the RDCR and RDSR */
spi->driver->wait_ready(spi);
/* setting the DC value to match high system clock */
config = spi_general_get_flash_register(spi, SPI_CMD_RDCR_MX);
fmc_pr(DTR_DB, "Get Config Register[%#x]\n", config);
/* check the QE value */
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR);
fmc_pr(DTR_DB, "Get Status Register[%#x]\n", status);
reg = ((unsigned short)config << SPI_NOR_CR_SHIFT) | status;
if (dtr_en == ENABLE) {
/* setting DC value */
fmc_pr(DTR_DB, "Get the dummy value[%#x]\n", spi->read->dummy);
/* Only the element with an even number of arrays is required, so increase is 2 */
for (ix = 0; str_dummy[ix]; ix += _2B) {
if (spi->read->dummy < str_dummy[ix])
break;
val = (unsigned short)str_dummy[ix + 1];
}
} else {
val = dtr_rdcr_dc_mask(0);
}
reg = dtr_rdcr_dc_bit_clr(reg) | (val << DTR_RDSR_DC_SHIFT);
spi->driver->write_enable(spi);
writew(reg, host->iobase);
fmc_pr(DTR_DB, "Write IO[%p]%#x\n", host->iobase,
*(unsigned short *)host->iobase);
spi_mxic_set_reg(spi);
fmc_cmd_wait_cpu_finish(host);
config = spi_general_get_flash_register(spi, SPI_CMD_RDCR_MX);
if ((config >> DTR_RDCR_DC_SHIFT) != (unsigned char)val) {
printf("* Set DC dummy fail.\n");
return -1;
}
return 0;
}
unsigned int spi_mxic_check_spi_dtr_support(struct fmc_spi *spi)
{
unsigned int regval;
unsigned int rd_sfdp_dummy = 1;
unsigned int sfdp_addrcycle = 3;
struct fmc_host *host = (struct fmc_host *)spi->host;
/* get the RDCR and RDSR */
spi->driver->wait_ready(spi);
/* Read the Serial Flash Discoverable Parameter (SFDP) */
fmc_write(host, FMC_CMD, SPI_CMD_RD_SFDP);
fmc_pr(DTR_DB, "\t Set CMD[%#x]%#x\n", FMC_CMD, SPI_CMD_RD_SFDP);
regval = op_cfg_fm_cs(spi->chipselect) |
OP_CFG_OEN_EN |
op_cfg_addr_num(sfdp_addrcycle) |
op_cfg_dummy_num(rd_sfdp_dummy);
fmc_write(host, FMC_OP_CFG, regval);
fmc_pr(DTR_DB, "\t\t Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, regval);
regval = fmc_data_num_cnt(SFDP_BUF_LEN);
fmc_write(host, FMC_DATA_NUM, regval);
fmc_pr(DTR_DB, "\t Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, regval);
regval = fmc_op_dummy_en(ENABLE) |
fmc_op_cmd1_en(ENABLE) |
fmc_op_addr_en(ENABLE) |
fmc_op_read_data_en(ENABLE) |
FMC_OP_REG_OP_START;
fmc_write(host, FMC_OP, regval);
fmc_pr(DTR_DB, "\t Set OP[%#x]%#x\n", FMC_OP, regval);
fmc_cmd_wait_cpu_finish(host);
regval = readb((char *)host->iobase + SFDP_DTR_BYTE_SHIFT);
fmc_pr(DTR_DB, "\t the dtr_mode_support is: %#x\n", regval);
/* get the DTR mode support bit */
spi->dtr_mode_support = (regval >> SFDP_DTR_BIT_SHIFT)
& SFDP_DTR_BIT_MASK;
return spi->dtr_mode_support;
}
#endif /* CONFIG_DTR_MODE_SUPPORT */
@@ -0,0 +1,102 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#define SPI_NOR_NM_QE_SHIFT 2
#define SPI_NOR_NM_QE_MASK (1 << SPI_NOR_NM_QE_SHIFT)
#define spi_nor_get_qe_by_nm(cr) (((cr) & SPI_NOR_NM_QE_MASK) \
>> SPI_NOR_NM_QE_SHIFT)
static int spi_nm25q128_entry_4addr(struct fmc_spi *spi, int enable)
{
return 0;
}
static void spi_nm25q128_set_op(const struct fmc_spi *spi)
{
unsigned int regval;
struct fmc_host *host = (struct fmc_host *)spi->host;
regval = fmc_cmd_cmd1(SPI_CMD_WRSR2);
fmc_write(host, FMC_CMD, regval);
fmc_pr(QE_DBG, "\t Set CMD[%#x]%#x\n", FMC_CMD, regval);
regval = op_cfg_fm_cs(spi->chipselect) | OP_CFG_OEN_EN;
fmc_write(host, FMC_OP_CFG, regval);
fmc_pr(QE_DBG, "\t Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, regval);
regval = fmc_data_num_cnt(SPI_NOR_SR_LEN);
fmc_write(host, FMC_DATA_NUM, regval);
fmc_pr(QE_DBG, "\t Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, regval);
regval = fmc_op_cmd1_en(ENABLE) |
fmc_op_write_data_en(ENABLE) |
FMC_OP_REG_OP_START;
fmc_write(host, FMC_OP, regval);
fmc_pr(QE_DBG, "\t Set OP[%#x]%#x\n", FMC_OP, regval);
fmc_cmd_wait_cpu_finish(host);
}
/*
enable QE bit if QUAD read write is supported by NM25Q128EVBSIG
*/
static int spi_nm25q128_qe_enable(struct fmc_spi *spi)
{
unsigned char status, op;
const char *str[] = {"Disable", "Enable"};
struct fmc_host *host = NULL;
if (!spi || !spi->driver)
return -1;
host = (struct fmc_host *)spi->host;
if (!host || !host->iobase)
return -1;
op = spi_is_quad(spi);
fmc_pr(QE_DBG, "\t* Start SPI Nor NM25Q(128/64)EVBSIG %s Quad.\n", str[op]);
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR2);
fmc_pr(QE_DBG, "\t Read Status Register-2[%#x]%#x\n", SPI_CMD_RDSR2,
status);
if (op == spi_nor_get_qe_by_nm(status)) {
fmc_pr(QE_DBG, "\t* Quad was %s status:%#x\n", str[op], status);
goto QE_END;
}
spi->driver->write_enable(spi);
if (op)
status |= SPI_NOR_NM_QE_MASK;
else
status &= ~SPI_NOR_NM_QE_MASK;
writeb(status, host->iobase);
fmc_pr(QE_DBG, "\t Write IO[%p]%#x\n", host->iobase,
*(unsigned char *)host->iobase);
/* There is new cmd for Write Status Register 2 by NM25Q(128/64)EVBSIG */
spi_nm25q128_set_op(spi);
/* wait the flash have switched quad mode success */
spi->driver->wait_ready(spi);
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR2);
fmc_pr(QE_DBG, "\t Read Status Register-2[%#x]:%#x\n",
SPI_CMD_RDSR2, status);
if (op == spi_nor_get_qe_by_nm(status)) {
fmc_pr(QE_DBG, "\t %s Quad success. status:%#x\n",
str[op], status);
} else {
db_msg("Error: %s Quad failed! reg:%#x\n", str[op],
status);
}
QE_END:
/* Enable the reset pin when working on dual mode for 8PIN */
if (!op)
spi_nor_reset_pin_enable(spi, ENABLE);
fmc_pr(QE_DBG, "\t* End SPI Nor NM25Q(128/64)EVBSIG %s Quad.\n", str[op]);
return op;
}
@@ -0,0 +1,202 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
static void puya_qe_enable_fmc_op(struct fmc_host * const host, struct fmc_spi * const spi)
{
unsigned int regval;
regval = fmc_cmd_cmd1(SPI_CMD_WRSR2);
fmc_write(host, FMC_CMD, regval);
fmc_pr(QE_DBG, "\t Set CMD[%#x]%#x\n", FMC_CMD, regval);
regval = op_cfg_fm_cs(spi->chipselect);
fmc_write(host, FMC_OP_CFG, regval);
fmc_pr(QE_DBG, "\t Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, regval);
regval = fmc_data_num_cnt(SPI_NOR_SR_LEN);
fmc_write(host, FMC_DATA_NUM, regval);
fmc_pr(QE_DBG, "\t Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, regval);
regval = fmc_op_cmd1_en(ENABLE) |
fmc_op_write_data_en(ENABLE) | FMC_OP_REG_OP_START;
fmc_write(host, FMC_OP, regval);
fmc_pr(QE_DBG, "\t Set OP[%#x]%#x\n", FMC_OP, regval);
fmc_cmd_wait_cpu_finish(host);
}
/*
* enable QE bit if QUAD read write is supported by puya'a P25Q128H,it is as same as W25Q(128/256)FV
* opcode type name
* 0x35 RD SR(S15-S8)
* 0x31 WR SR(S15-S8)
*/
static int spi_puya_qe_enable(struct fmc_spi *spi)
{
unsigned char status;
unsigned char op;
const char *str[] = {"Disable", "Enable"};
struct fmc_host *host = NULL;
if (!spi || !spi->driver)
return -1;
host = (struct fmc_host *)spi->host;
if (!host || !host->iobase)
return -1;
op = spi_is_quad(spi);
fmc_pr(QE_DBG, "\t* Start SPI Nor %s Quad.\n", str[op]);
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR2);
fmc_pr(QE_DBG, "\t Read Status Register-2[%#x]%#x\n", SPI_CMD_RDSR2,
status);
if (spi_nor_get_qe_by_cr(status) == op) {
fmc_pr(QE_DBG, "\t* Quad was %s status:%#x\n", str[op], status);
goto QE_END;
}
spi->driver->write_enable(spi);
if (op)
status |= SPI_NOR_CR_QE_MASK;
else
status &= ~SPI_NOR_CR_QE_MASK;
writeb(status, host->iobase);
fmc_pr(QE_DBG, "\t Write IO[%#lx]%#x\n", (uintptr_t)host->iobase,
*(unsigned char *)host->iobase);
/* There is new cmd for Write Status Register 2 by W25Q(128/256)FV */
puya_qe_enable_fmc_op(host, spi);
/* wait the flash have switched quad mode success */
spi->driver->wait_ready(spi);
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR2);
fmc_pr(QE_DBG, "\t Read Status Register-2[%#x]:%#x\n",
SPI_CMD_RDSR2, status);
if (spi_nor_get_qe_by_cr(status) == op)
fmc_pr(QE_DBG, "\t %s Quad success. status:%#x\n",
str[op], status);
else
db_msg("Error: %s Quad failed! reg:%#x\n", str[op], status);
QE_END:
return op;
}
static int spi_puya_entry_4addr(struct fmc_spi *spi, int enable)
{
const char *str[] = {"Disable", "Enable"};
struct fmc_host *host = NULL;
if (!spi || !spi->driver)
return -1;
host = (struct fmc_host*)spi->host;
if (!host)
return -1;
fmc_pr(AC_DBG, "\t* Start SPI Nor flash %s 4-byte mode.\n",
str[enable]);
if (spi->addrcycle != SPI_NOR_4BYTE_ADDR_LEN) {
fmc_pr(AC_DBG, "\t* Flash isn't support entry 4-byte mode.\n");
return 0;
}
if (!enable)
{
/* reset cmd same sa w25q256fv */
spi_w25q256fv_set_cmd(spi, SPI_CMD_FIRST_RESET_4ADDR);
spi_w25q256fv_set_cmd(spi, SPI_CMD_SECOND_RESET_4ADDR);
fmc_pr(AC_DBG, "\tnow PY25Q256HB start software reset\n");
udelay(30); /* delay 30 us */
}
fmc_pr(AC_DBG, "\t* End SPI Nor flash %s 4-byte mode.\n", str[enable]);
return 0;
}
#ifdef CONFIG_DTR_MODE_SUPPORT
void spi_py_set_reg(struct fmc_spi *spi)
{
unsigned int regval;
struct fmc_host *host = (struct fmc_host *)spi->host;
regval = fmc_cmd_cmd1(SPI_CMD_WRSR3);
fmc_write(host, FMC_CMD, regval);
fmc_pr(DTR_DB, " Set CMD[%#x]%#x\n", FMC_CMD, regval);
regval = op_cfg_fm_cs(spi->chipselect) | OP_CFG_OEN_EN;
fmc_write(host, FMC_OP_CFG, regval);
fmc_pr(DTR_DB, " Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, regval);
regval = fmc_data_num_cnt(SPI_NOR_SR_LEN);
fmc_write(host, FMC_DATA_NUM, regval);
fmc_pr(DTR_DB, " Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, regval);
regval = fmc_op_cmd1_en(ENABLE) |
fmc_op_write_data_en(ENABLE) |
FMC_OP_REG_OP_START;
fmc_write(host, FMC_OP, regval);
fmc_pr(DTR_DB, " Set OP[%#x]%#x\n", FMC_OP, regval);
}
int spi_py_output_driver_strength_set(struct fmc_spi *spi, int dtr_en)
{
unsigned char config;
unsigned char reg;
unsigned char val;
unsigned int ix;
struct fmc_host *host = NULL;
/* DC | Numbers of Dummy clock cycles| Quad IO DTR Read */
/* 0(default)| 8 | 80 */
/* 1 | 10 | 100 */
unsigned int str_dummy[] = {
DTR_DUMMY_CYCLES_8, dtr_rdcr_dc_mask(0),
DTR_DUMMY_CYCLES_10, dtr_rdcr_dc_mask(1),
0, 0,
};
val = 0;
if (!spi || !spi->driver)
return -1;
host = (struct fmc_host *)spi->host;
if (!host)
return -1;
/* get the RDCR and RDSR */
spi->driver->wait_ready(spi);
/* setting the DC value to match high system clock */
config = spi_general_get_flash_register(spi, SPI_CMD_RDSR3);
fmc_pr(DTR_DB, "Get Status Register-3[%#x]\n", config);
if (dtr_en == ENABLE) {
/* setting DC value */
fmc_pr(DTR_DB, "Get the dummy value[%#x]\n", spi->read->dummy);
/* Only the element with an even number of arrays is required, so increase is 2 */
for (ix = 0; str_dummy[ix]; ix += _2B) {
if (spi->read->dummy < str_dummy[ix])
break;
val = (unsigned char)str_dummy[ix + 1];
}
} else {
val = dtr_rdcr_dc_mask(0);
}
reg = dtr_py_dc_bit_clr(config) | (val << 3);
fmc_pr(DTR_DB, "Get the reg value[%#x]\n", reg);
spi->driver->write_enable(spi);
writew(reg, host->iobase);
fmc_pr(DTR_DB, "Write IO[%p]%#x\n", host->iobase,
*(unsigned short *)host->iobase);
spi_py_set_reg(spi);
fmc_cmd_wait_cpu_finish(host);
config = spi_general_get_flash_register(spi, SPI_CMD_RDSR3);
fmc_pr(DTR_DB, "Get Status Register-3[%#x]\n", config);
if (((config & 0x8) >> 3) != (unsigned char)val) {
printf("* Set DC dummy fail.\n");
return -1;
}
return 0;
}
#endif /* CONFIG_DTR_MODE_SUPPORT */
@@ -0,0 +1,100 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
/* SpanSion SPI Nor Flash "S25FL256S" Bank Address Register command */
#define SS_SPI_CMD_BRRD 0x16 /* Read Bank Register */
#define SS_SPI_CMD_BRWR 0x17 /* Write Bank Register */
/* Bank Address Register length(byte) */
#define SS_SPI_NOR_BR_LEN 1
/* Extended Address Enable bit[7] include in Bank Address Register */
#define SS_SPI_NOR_BR_EAE_SHIFT 7
#define SS_SPI_NOR_BR_EAE_MASK (1 << SS_SPI_NOR_BR_EAE_SHIFT)
#define ss_spi_nor_get_eae_by_br(br) (((br) & SS_SPI_NOR_BR_EAE_MASK) >> SS_SPI_NOR_BR_EAE_SHIFT)
static void spi_s25fl256s_set_cmd(const struct fmc_spi *spi)
{
unsigned int regval;
struct fmc_host *host = (struct fmc_host *)spi->host;
regval = fmc_cmd_cmd1(SS_SPI_CMD_BRWR);
fmc_write(host, FMC_CMD, regval);
fmc_pr(AC_DBG, "\t Set CMD[%#x]%#x\n", FMC_CMD, regval);
regval = op_cfg_fm_cs(spi->chipselect);
fmc_write(host, FMC_OP_CFG, regval);
fmc_pr(AC_DBG, "\t Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, regval);
regval = fmc_data_num_cnt(SS_SPI_NOR_BR_LEN);
fmc_write(host, FMC_DATA_NUM, regval);
fmc_pr(AC_DBG, "\t Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, regval);
regval = fmc_op_cmd1_en(ENABLE) |
fmc_op_write_data_en(ENABLE) |
FMC_OP_REG_OP_START;
fmc_write(host, FMC_OP, regval);
fmc_pr(AC_DBG, "\t Set OP[%#x]%#x\n", FMC_OP, regval);
fmc_cmd_wait_cpu_finish(host);
}
/*
enable 4byte address mode for SpanSion "s25fl256" SPI Nor
*/
static int spi_s25fl256s_entry_4addr(struct fmc_spi *spi, int enable)
{
unsigned char bank;
const char *str[] = {"Disable", "Enable"};
struct fmc_host *host = NULL;
if (!spi || !spi->driver)
return -1;
host = (struct fmc_host *)spi->host;
if (!host || !host->iobase)
return -1;
fmc_pr(AC_DBG, "\t* Start SpanSion SPI Nor %s 4-byte mode.\n",
str[enable]);
if (spi->addrcycle != SPI_NOR_4BYTE_ADDR_LEN) {
fmc_pr(AC_DBG, "\t* Flash isn't support 4-byte mode.\n");
return 0;
}
/* Read old Bank Register value */
bank = spi_general_get_flash_register(spi, SS_SPI_CMD_BRRD);
fmc_pr(AC_DBG, "\t Read Bank Register[%#x]%#x\n", SS_SPI_CMD_BRRD,
bank);
if (ss_spi_nor_get_eae_by_br(bank) == enable) {
fmc_pr(AC_DBG, "\t* 4-byte was %sd, bank:%#x\n", str[enable], bank);
return 0;
}
/* Write new Bank Register value */
if (enable)
bank |= SS_SPI_NOR_BR_EAE_MASK;
else
bank &= ~SS_SPI_NOR_BR_EAE_MASK;
writeb(bank, host->iobase);
fmc_pr(AC_DBG, "\t Write IO[%p]%#x\n", host->iobase,
*(unsigned char *)host->iobase);
spi_s25fl256s_set_cmd(spi);
spi->driver->wait_ready(spi);
/* Check out Bank Register value */
bank = spi_general_get_flash_register(spi, SS_SPI_CMD_BRRD);
fmc_pr(AC_DBG, "\t Read Bank Register[%#x]%#x\n", SS_SPI_CMD_BRRD,
bank);
if (ss_spi_nor_get_eae_by_br(bank) != enable) {
db_msg("Error: %s 4bytes failed! bank: %#x\n", str[enable], bank);
return bank;
}
fmc_pr(AC_DBG, "\t %s 4byte success, bank:%#x.\n", str[enable], bank);
fmc_pr(AC_DBG, "\t* End SpanSion SPI Nor %s 4-byte mode.\n",
str[enable]);
return 0;
}
@@ -0,0 +1,181 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#define W25Q256FV_CR_4BYTE_MASK 0x1
#define WB_SPI_NOR_SR_ADS_MASK 1
#define wb_spi_nor_get_4byte_by_sr(sr) ((sr) & WB_SPI_NOR_SR_ADS_MASK)
#define SPI_CMD_FIRST_RESET_4ADDR 0x66
#define SPI_CMD_SECOND_RESET_4ADDR 0x99
static void spi_w25q256fv_set_cmd(const struct fmc_spi *spi, u8 cmd)
{
unsigned int regval;
struct fmc_host *host = (struct fmc_host *)spi->host;
regval = fmc_cmd_cmd1(cmd);
fmc_write(host, FMC_CMD, regval);
fmc_pr(AC_DBG, "\t Set CMD[%#x]%#x\n", FMC_CMD, regval);
regval = op_cfg_fm_cs(spi->chipselect) | OP_CFG_OEN_EN;
fmc_write(host, FMC_OP_CFG, regval);
fmc_pr(AC_DBG, "\t Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, regval);
regval = fmc_op_cmd1_en(ENABLE) | FMC_OP_REG_OP_START;
fmc_write(host, FMC_OP, regval);
fmc_pr(AC_DBG, "\t Set OP[%#x]%#x\n", FMC_OP, regval);
fmc_cmd_wait_cpu_finish(host);
}
static int spi_w25q256jv_entry_4addr(struct fmc_spi *spi, int enable)
{
return 0;
}
static int spi_w25q256fv_entry_4addr(struct fmc_spi *spi, int enable)
{
unsigned char status;
const char *str[] = {"Disable", "Enable"};
if (!spi || !spi->host)
return -1;
fmc_pr(AC_DBG, "\t* Start W25Q256FV SPI Nor %s 4-byte mode.\n",
str[enable]);
if (spi->addrcycle != SPI_NOR_4BYTE_ADDR_LEN) {
fmc_pr(AC_DBG, "\t* W25Q(128/256)FV not support 4B mode.\n");
return 0;
}
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR3);
fmc_pr(AC_DBG, "\t Read Status Register-3[%#x]:%#x\n", SPI_CMD_RDSR3,
status);
if (wb_spi_nor_get_4byte_by_sr(status) == enable) {
fmc_pr(AC_DBG, "\t* 4-byte was %sd, reg:%#x\n", str[enable],
status);
return 0;
}
if (enable) {
spi_w25q256fv_set_cmd(spi, SPI_CMD_EN4B);
if (!spi->driver)
return -1;
spi->driver->wait_ready(spi);
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR3);
fmc_pr(AC_DBG, "\t Get Status Register 3[%#x]:%#x\n",
SPI_CMD_RDSR3, status);
if (status & W25Q256FV_CR_4BYTE_MASK) {
fmc_pr(AC_DBG, "\t Enter 4-byte success, reg[%#x]\n",
status);
} else {
db_msg("Error: Enter 4-byte failed! [%#x]\n", status);
}
} else {
/* reset cmd */
spi_w25q256fv_set_cmd(spi, SPI_CMD_FIRST_RESET_4ADDR);
spi_w25q256fv_set_cmd(spi, SPI_CMD_SECOND_RESET_4ADDR);
fmc_pr(AC_DBG, "\tnow W25Q256FV start software reset\n");
udelay(30); /* delay 30 us */
}
fmc_pr(AC_DBG, "\t* End W25Q256FV enter 4-byte mode.\n");
return 0;
}
static void spi_w25q256fv_set_op(const struct fmc_spi *spi)
{
unsigned int regval;
struct fmc_host *host = (struct fmc_host *)spi->host;
regval = fmc_cmd_cmd1(SPI_CMD_WRSR2);
fmc_write(host, FMC_CMD, regval);
fmc_pr(QE_DBG, "\t Set CMD[%#x]%#x\n", FMC_CMD, regval);
regval = op_cfg_fm_cs(spi->chipselect) | OP_CFG_OEN_EN;
fmc_write(host, FMC_OP_CFG, regval);
fmc_pr(QE_DBG, "\t Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, regval);
regval = fmc_data_num_cnt(SPI_NOR_SR_LEN);
fmc_write(host, FMC_DATA_NUM, regval);
fmc_pr(QE_DBG, "\t Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, regval);
regval = fmc_op_cmd1_en(ENABLE) |
fmc_op_write_data_en(ENABLE) |
FMC_OP_REG_OP_START;
fmc_write(host, FMC_OP, regval);
fmc_pr(QE_DBG, "\t Set OP[%#x]%#x\n", FMC_OP, regval);
fmc_cmd_wait_cpu_finish(host);
}
/*
enable QE bit if QUAD read write is supported by W25Q(128/256)FV
*/
static int spi_w25q256fv_qe_enable(struct fmc_spi *spi)
{
unsigned char status, op;
const char *str[] = {"Disable", "Enable"};
struct fmc_host *host = NULL;
if (!spi || !spi->driver)
return -1;
host = (struct fmc_host *)spi->host;
if (!host || !host->iobase)
return -1;
op = spi_is_quad(spi);
fmc_pr(QE_DBG, "\t* Start SPI Nor W25Q(128/256)FV %s Quad.\n", str[op]);
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR2);
fmc_pr(QE_DBG, "\t Read Status Register-2[%#x]%#x\n", SPI_CMD_RDSR2,
status);
if (op == spi_nor_get_qe_by_cr(status)) {
fmc_pr(QE_DBG, "\t* Quad was %s status:%#x\n", str[op], status);
goto QE_END;
}
spi->driver->write_enable(spi);
if (op)
status |= SPI_NOR_CR_QE_MASK;
else
status &= ~SPI_NOR_CR_QE_MASK;
writeb(status, host->iobase);
fmc_pr(QE_DBG, "\t Write IO[%p]%#x\n", host->iobase,
*(unsigned char *)host->iobase);
/* There is new cmd for Write Status Register 2 by W25Q(128/256)FV */
spi_w25q256fv_set_op(spi);
/* wait the flash have switched quad mode success */
spi->driver->wait_ready(spi);
status = spi_general_get_flash_register(spi, SPI_CMD_RDSR2);
fmc_pr(QE_DBG, "\t Read Status Register-2[%#x]:%#x\n",
SPI_CMD_RDSR2, status);
if (op == spi_nor_get_qe_by_cr(status)) {
fmc_pr(QE_DBG, "\t %s Quad success. status:%#x\n",
str[op], status);
} else {
db_msg("Error: %s Quad failed! reg:%#x\n", str[op],
status);
}
QE_END:
/* Enable the reset pin when working on dual mode for 8PIN */
if (!op)
spi_nor_reset_pin_enable(spi, ENABLE);
fmc_pr(QE_DBG, "\t* End SPI Nor W25Q(128/256)FV %s Quad.\n", str[op]);
return op;
}
@@ -0,0 +1,90 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifdef CONFIG_DTR_MODE_SUPPORT
void spi_xmc_set_reg(struct fmc_spi *spi)
{
unsigned int regval;
struct fmc_host *host = (struct fmc_host *)spi->host;
regval = fmc_cmd_cmd1(SPI_CMD_WRSR3);
fmc_write(host, FMC_CMD, regval);
fmc_pr(DTR_DB, " Set CMD[%#x]%#x\n", FMC_CMD, regval);
regval = op_cfg_fm_cs(spi->chipselect) | OP_CFG_OEN_EN;
fmc_write(host, FMC_OP_CFG, regval);
fmc_pr(DTR_DB, " Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, regval);
regval = fmc_data_num_cnt(SPI_NOR_SR_LEN);
fmc_write(host, FMC_DATA_NUM, regval);
fmc_pr(DTR_DB, " Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, regval);
regval = fmc_op_cmd1_en(ENABLE) |
fmc_op_write_data_en(ENABLE) |
FMC_OP_REG_OP_START;
fmc_write(host, FMC_OP, regval);
fmc_pr(DTR_DB, " Set OP[%#x]%#x\n", FMC_OP, regval);
}
int spi_xmc_output_driver_strength_set(struct fmc_spi *spi, int dtr_en)
{
unsigned char config;
unsigned short val;
unsigned int ix;
struct fmc_host *host = NULL;
/* DC[1:0] | Numbers of Dummy clock cycles| Quad IO DTR Read */
/* 00(default)| 8 | 90 */
/* 01 | 4 | 66 */
/* 10 | 6 | 66 */
/* 11 | 10 | 108 */
unsigned int str_dummy[] = {
DTR_DUMMY_CYCLES_4, dtr_rdcr_dc_mask(1),
DTR_DUMMY_CYCLES_6, dtr_rdcr_dc_mask(2),
DTR_DUMMY_CYCLES_8, dtr_rdcr_dc_mask(0),
DTR_DUMMY_CYCLES_10, dtr_rdcr_dc_mask(3),
0, 0,
};
val = 0;
if (!spi || !spi->driver)
return -1;
host = (struct fmc_host *)spi->host;
if (!host)
return -1;
/* get the RDCR and RDSR */
spi->driver->wait_ready(spi);
/* setting the DC value to match high system clock */
config = spi_general_get_flash_register(spi, SPI_CMD_RDCR_MX);
fmc_pr(DTR_DB, "Get Config Register[%#x]\n", config);
if (dtr_en == ENABLE) {
/* setting DC value */
fmc_pr(DTR_DB, "Get the dummy value[%#x]\n", spi->read->dummy);
/* Only the element with an even number of arrays is required, so increase is 2 */
for (ix = 0; str_dummy[ix]; ix += _2B) {
if (spi->read->dummy < str_dummy[ix])
break;
val = (unsigned short)str_dummy[ix + 1];
}
} else {
val = dtr_rdcr_dc_mask(0);
}
config = dtr_xmc_dc_bit_clr(config) | val;
spi->driver->write_enable(spi);
writeb(config, host->iobase);
fmc_pr(DTR_DB, "Write IO[%p]%#x\n", host->iobase,
*(unsigned short *)host->iobase);
spi_xmc_set_reg(spi);
fmc_cmd_wait_cpu_finish(host);
config = spi_general_get_flash_register(spi, SPI_CMD_RDCR_MX);
if ((config & 3) != (unsigned char)val) {
printf("* Set DC dummy fail.\n");
return -1;
}
return 0;
}
#endif /* CONFIG_DTR_MODE_SUPPORT */
@@ -0,0 +1,92 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#define XTX_READ_SR_H 0x35
#define XTX_READ_SR_L 0x05
static void spi_xtx_set_op(const struct fmc_spi *spi)
{
unsigned int regval;
struct fmc_host *host = (struct fmc_host *)spi->host;
regval = fmc_cmd_cmd1(SPI_CMD_WRSR);
fmc_write(host, FMC_CMD, regval);
fmc_pr(QE_DBG, "\t Set CMD[%#x]%#x\n", FMC_CMD, regval);
regval = op_cfg_fm_cs(spi->chipselect) | OP_CFG_OEN_EN;
fmc_write(host, FMC_OP_CFG, regval);
fmc_pr(QE_DBG, "\t Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, regval);
regval = fmc_data_num_cnt(sizeof(unsigned short));
fmc_write(host, FMC_DATA_NUM, regval);
fmc_pr(QE_DBG, "\t Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, regval);
regval = fmc_op_cmd1_en(ENABLE) | fmc_op_write_data_en(ENABLE) |
FMC_OP_REG_OP_START;
fmc_write(host, FMC_OP, regval);
fmc_pr(QE_DBG, "\t Set OP[%#x]%#x\n", FMC_OP, regval);
fmc_cmd_wait_cpu_finish(host);
}
/*
enable QE bit if QUAD read write is supported by xtx's flash
*/
static int spi_xtx_qe_enable(struct fmc_spi *spi)
{
unsigned char status_h;
unsigned char status_l;
unsigned char op;
unsigned short reg;
const char *str[] = {"Disable", "Enable"};
struct fmc_host *host = NULL;
if (!spi || !spi->driver)
return -1;
host = (struct fmc_host *)spi->host;
if (!host || !host->iobase)
return -1;
op = spi_is_quad(spi);
fmc_pr(QE_DBG, "\t* Start SPI Nor xtx %s Quad.\n", str[op]);
status_h = spi_general_get_flash_register(spi, XTX_READ_SR_H);
fmc_pr(QE_DBG, "\t Read Status Register-h[%#x]%#x\n", XTX_READ_SR_H,
status_h);
if (op == spi_nor_get_qe_by_cr(status_h)) {
fmc_pr(QE_DBG, "\t* Quad was %s status:%#x\n", str[op], status_h);
goto QE_END;
}
spi->driver->write_enable(spi);
status_l = spi_general_get_flash_register(spi, XTX_READ_SR_L);
if (op)
status_h |= SPI_NOR_CR_QE_MASK;
else
status_h &= ~SPI_NOR_CR_QE_MASK;
/* Move left to 8 bit to assign a value to the upper bits */
reg = ((unsigned short)status_h << 8) | status_l;
writew(reg, host->iobase);
fmc_pr(QE_DBG, "\t Write IO[%p]%#x\n", host->iobase,
*(unsigned short *)host->iobase);
spi_xtx_set_op(spi);
/* wait the flash have switched quad mode success */
spi->driver->wait_ready(spi);
status_h = spi_general_get_flash_register(spi, XTX_READ_SR_H);
fmc_pr(QE_DBG, "\t Read Status Register-h[%#x]:%#x\n",
XTX_READ_SR_H, status_h);
if (op == spi_nor_get_qe_by_cr(status_h)) {
fmc_pr(QE_DBG, "\t %s Quad success. status_h:%#x\n",
str[op], status_h);
} else {
db_msg("Error: %s Quad failed! reg:%#x\n", str[op],
status_h);
}
QE_END:
return status_h;
}
@@ -0,0 +1,68 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#include <common.h>
#include <malloc.h>
#include <asm/io.h>
#include <spi_flash.h>
#include <errno.h>
#include <linux/mtd/mtd.h>
#include <linux/lotus/fmc.h>
/*****************************************************************************/
static struct spi_flash *spiflash;
static struct mtd_info_ex *spiinfo_ex;
/*****************************************************************************/
struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int spi_mode)
{
if (get_boot_media() != BOOT_MEDIA_SPIFLASH) {
return NULL;
}
if (spiflash)
return spiflash;
#ifdef CONFIG_FMC_SPI_NOR
spiflash = fmc100_spi_nor_probe(&spiinfo_ex);
spiflash->erase_size = spiinfo_ex->erasesize;
#endif
return spiflash;
}
/*****************************************************************************/
struct mtd_info_ex *get_spiflash_info(void)
{
if (spiinfo_ex)
return spiinfo_ex;
#ifdef CONFIG_FMC_SPI_NOR
spiinfo_ex = fmc100_get_spi_nor_info(spiflash);
#endif
return spiinfo_ex;
}
/*****************************************************************************/
void spi_flash_free(struct spi_flash *flash)
{
}
/*****************************************************************************/
#ifdef CONFIG_SPI_BLOCK_PROTECT
void spi_flash_lock(unsigned char cmp, unsigned char level, unsigned char op)
{
cmp = BP_CMP_BOTTOM;
if (spiflash->lock)
spiflash->lock(cmp, level, op);
return;
}
/*****************************************************************************/
#endif /* CONFIG_SPI_BLOCK_PROTECT */