Files
banban/ql-bootloader/updater/quectel/inc/spinand.h
T

514 lines
16 KiB
C

/******************************************************************************
*
* (C)Copyright 2005 - 2008 Marvell. All Rights Reserved.
*
* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MARVELL.
* The copyright notice above does not evidence any actual or intended
* publication of such source code.
* This Module contains Proprietary Information of Marvell and should be
* treated as Confidential.
* The information in this file is provided for the exclusive use of the
* licensees of Marvell.
* Such users have the right to use, modify, and incorporate this code into
* products for purposes authorized by the license agreement provided they
* include this notice and the associated copyright notice with any such
* product.
* The information in this file is provided "AS IS" without warranty.
*
******************************************************************************/
/***********************************************************
* SPIFlash.h
* This is the header file for the SPIFlash driver.
*
* Revision History:
* 5/2/07 - initial draft
************************************************************/
#ifndef __SPI_NAND_H__
#define __SPI_NAND_H__
#include "common.h"
#include "qspi_dma.h"
#include "xllp_dmac.h"
#include "SPI.h"
#define DMA_DEFAULT_TIMEOUT 3000U
#define DEFAULT_WAIT_TIME 1000U
#define MANU_RESERVE_BLOCK 4U
#define WRITE_SIZE (256)
#define SIZE_4KB (0x1000)
/*
* SPI Command Set
*/
#define SPINAND_WRITE_ENABLE 0x06
#define SPINAND_WRITE_DISABLE 0x04
#define SPINAND_GET_FEATURES 0x0F
#define SPINAND_SET_FEATURES 0x1F
#define SPINAND_CACHE_LOAD 0x13
#define SPINAND_CACHE_READ 0x03
#define SPINAND_READ_ID 0x9F
#define SPINAND_PROGRAM_LOAD 0x02
#define SPINAND_PROGRAM_EXECUTE 0x10
#define SPINAND_BLOCK_ERASE 0xD8
#define SPINAND_RESET 0xFF
/*
* SPI NAND Feature Types
*/
typedef enum
{
SPINAND_PROTECTION = 0xA0,
SPINAND_FEATURE = 0xB0,
SPINAND_STATUS = 0xC0
} SPINAND_Feature_E;
//
// GigaDevice GD5F1GQ4RAYIG: protection register 0xa0
//
// 7 6 5 4 3 2 1 0
// +------+------+------+------+------+------+------+------+
// | BRWD | Rerd | BP2 | BP1 | BP0 | INV | CMP |Rerd |
// +------+------+------+------+------+------+------+------+
#define GIGA_SPINAND_PROTECTION_Rerd1 BIT_0 // Rserved
#define GIGA_SPINAND_PROTECTION_CMP BIT_1 // level of protected blcok
#define GIGA_SPINAND_PROTECTION_INV BIT_2 // level of protected blcok
#define GIGA_SPINAND_PROTECTION_BP0 BIT_3 // level of protected blcok
#define GIGA_SPINAND_PROTECTION_BP1 BIT_4 // level of protected blcok
#define GIGA_SPINAND_PROTECTION_BP2 BIT_5 // level of protected blcok
#define GIGA_SPINAND_PROTECTION_BP3 BIT_6 // level of protected blcok
#define GIGA_SPINAND_PROTECTION_BRWD BIT_7 // block protection lock
//
// GigaDevice GD5F1GQ4RAYIG: feature register 0xb0
//
// 7 6 5 4 3 2 1 0
// +-------+------+------+------+------+------+------+------+
// |OTP_PRT|OTP_EN| Rerd |ECC_EN| Rerd | Rerd | Rerd | QE |
// +-------+------+------+------+------+------+------+------+
#define GIGA_SPINAND_FEATURE_QE BIT_0 // quad enable
#define GIGA_SPINAND_FEATURE_Rerd3 BIT_1 // reserved
#define GIGA_SPINAND_FEATURE_Rerd2 BIT_2 // reserved
#define GIGA_SPINAND_FEATURE_Rerd1 BIT_3 // reserved
#define GIGA_SPINAND_FEATURE_ECC_EN BIT_4 // ecc enable
#define GIGA_SPINAND_FEATURE_Rerd BIT_5 // reserved
#define GIGA_SPINAND_FEATURE_OTP_EN BIT_6 // one-time program
#define GIGA_SPINAND_FEATURE_OTP_PRT BIT_7 // one-time program
//
// GigaDevice GD5F1GQ4RAYIG: status register 0xc0
//
// 7 6 5 4 3 2 1 0
// +-----+------+------+------+------+------+------+------+
// | Rerd| Rerd |ECCS1 |ECCS0 |P_FAIL|E_FAIL| WEL | OIP |
// +-----+------+------+------+------+------+------+------+
#define GIGA_SPINAND_STATUS_OIP BIT_0 // operation in progress
#define GIGA_SPINAND_STATUS_WEL BIT_1 // write enable latch
#define GIGA_SPINAND_STATUS_E_FAIL BIT_2 // erase fail
#define GIGA_SPINAND_STATUS_P_FAIL BIT_3 // program fail
#define GIGA_SPINAND_STATUS_ECCS0 BIT_4 // ecc status
#define GIGA_SPINAND_STATUS_ECCS1 BIT_5 // ecc status
#define GIGA_SPINAND_STATUS_Rerd BIT_6 // reserved
#define GIGA_SPINAND_STATUS_Rerd1 BIT_7 // reserved
/*
* SPI NAND Timeouts (all in MICRO seconds!!)
* NOTE: I roughly doubled all the values listed in the specification, as the
* core will be running slowly in BootROM and I wanted to avoid any situation
* where the operation finished at the edge of the timeout value, but the
* slow running core captures the timer value just after timeout
*/
#define SN_READ_TIMEOUT 0x100 //maximum time to load a page into the cache field
#define SN_ERASE_TIMEOUT 0x800 //maximum time for the erase operation
#define SN_PROGRAM_TIMEOUT 0x5000 //maximum time for the program operation
#define SSP_READ_TIME_OUT 0x80000 //timeout for reading data from cache to internal memory
//this is dependent on CPU and DMA clock speeds, NOT the SPI device!
// /*
// * SPI NAND: other values
// */
// typedef enum
// {
// SSP_CLOCK_13M = 0x0,
// SSP_CLOCK_26M = 0x1,
// SSP_CLOCK_52M = 0x2,
// } SSP_Clock;
#define SPINAND_PAGE_SIZE 0x800
#define SPINAND_BLOCK_SIZE 0x20000
#define SPINAND_PAGE_WORDS_SIZE 0x200
#define SPINAND_PAGE_WITH_SPARE_WORDS_SIZE 0x210
#define SPINAND_PAGE_WITH_SPARE_BYTES_SIZE (SPINAND_PAGE_WITH_SPARE_WORDS_SIZE<<2)
#define SPI_NAND_MAX_TEST_SIZE (65536+4)
/*
* Nezha: SSP Register locations.
*/
#define SSPORT_BASE_FOR_SPI get_ssp_base()
/* SSP Control Register 0: (Offset: 0x00) */
#define SSPORT_CR0 ((volatile unsigned int *) (SSPORT_BASE_FOR_SPI+SSP_SSCR0))
/* SSP Control Register 1: (Offset: 0x04) */
#define SSPORT_CR1 ((volatile unsigned int *) (SSPORT_BASE_FOR_SPI+SSP_SSCR1))
/* SSP Status Register: (Offset: 0x08) */
#define SSPORT_SR ((volatile unsigned int *) (SSPORT_BASE_FOR_SPI+SSP_SSSR))
/* SSP Data Write/Read Register: (Offset: 0x10) */
#define SSPORT_DR ((volatile unsigned int *) (SSPORT_BASE_FOR_SPI+SSP_SSDR))
/* SSP SSP Programmable Serial Protocol Register: (Offset: 0x2C) */
#define SSPORT_SP ((volatile unsigned int *) (SSPORT_BASE_FOR_SPI+SSP_SSPSP))
/* SSP Top Control Register: (Offset: 0x00)*/
#define SSPORT_TCR ((volatile int *) (SSPORT_BASE_FOR_SPI+SSP_TOP_CTRL))
/* SSP FIFO Control Register: (Offset: 0x04)*/
#define SSPORT_FCR ((volatile int *) (SSPORT_BASE_FOR_SPI+SSP_FIFO_CTRL))
/* SSP Interrupt Enable Register: (Offset: 0x08)*/
#define SSPORT_IER ((volatile int *) (SSPORT_BASE_FOR_SPI+SSP_INT_EN))
/* SSP Time Out Register: (Offset: 0x0C)*/
#define SSPORT_TOR ((volatile int *) (SSPORT_BASE_FOR_SPI+SSP_TIMEOUT))
/* SSP Status Register: (Offset: 0x14)*/
#define SSPORT_STS ((volatile int *) (SSPORT_BASE_FOR_SPI+SSP_STATUS))
#define SPINAND_MAX_ID_LEN 4
struct spinand_device;
/**
* struct nand_ecc_req - NAND ECC reqirement.
* @strength: ECC strength
* @step_size: ECC step/block size.
*/
struct nand_ecc_req {
unsigned int strength;
unsigned int step_size;
unsigned int hw_ecc;
};
#define NAND_ECCREQ(str, stp, ecc) \
{ \
.strength=(str), \
.step_size=(stp), \
.hw_ecc=(ecc), \
}
/**
* struct nand_memory_organization structures.
* @bit_per_celi: number of bits per NAND celi.
* @pagesize: page size
* @oobsize: OOB area size
* @pages_per_eraseblock: number of pages per eraseblock.
* @eraseblocks_per_lun: number of eraseblocks per LUN(Logical Unit Number).
* @max_bad_eraseblocks_per_lun: maxium number of eraseblocks per LUN.
* @plans_per_lun:numbers of plans per LUN.
* @luns_per_target: number of LUN
* @ntarget: total number of target exposed bu the NAND device.
*/
struct nand_memory_organization {
unsigned int bit_per_celi;
unsigned int pagesize;
unsigned int oobsize;
unsigned int pages_per_eraseblock;
unsigned int eraseblocks_per_lun;
unsigned int max_bad_eraseblocks_per_lun;
unsigned int planes_per_lun;
unsigned int luns_per_target;
unsigned int ntargets;
};
#define NAND_MEMORG(bpc, ps, os, ppe, epl, mbb, ppl, lpt, nt) \
{ \
.bit_per_celi = (bpc), \
.pagesize = (ps), \
.oobsize = (os), \
.pages_per_eraseblock = (ppe), \
.eraseblocks_per_lun = (epl), \
.max_bad_eraseblocks_per_lun = (mbb),\
.planes_per_lun = (ppl), \
.luns_per_target = (lpt), \
.ntargets = (nt), \
}
/**
* struct nand_device - NAND device.
* @mtd: MTD instance attached to the NAND device.
* @memorg: memory layout.
* @eccreq: ECC Reqirement.
*/
struct nand_device {
struct nand_memory_organization memorg;
struct nand_ecc_req eccreq;
};
/**
* struct spinand_id - SPI NAND id structurs.
* @data: buffer containing the id bytes. Currently 4 bytes large.
* @len: ID Length.
*/
struct spinand_id {
unsigned char data[SPINAND_MAX_ID_LEN];
unsigned int len;
};
enum spinand_readid_method {
SPINAND_READID_METHOD_OPCODE,
SPINAND_READID_METHOD_OPCODE_ADDR,
SPINAND_READID_METHOD_OPCODE_DUMMY,
};
/** * struct spinand_devid - SPI NAND device id structure
* @id: device id of current chip
* @len: number of bytes in device id
* @method: method to read chip id
* There are 3 possible variants:
* SPINAND_READID_METHOD_OPCODE: chip id is returned immediately
* after read_id opcode.
* SPINAND_READID_METHOD_OPCODE_ADDR: chip id is returned after
* read_id opcode + 1-byte address.
* SPINAND_READID_METHOD_OPCODE_DUMMY: chip id is returned after
* read_id opcode + 1 dummy byte.
*/
struct spinand_devid{
const unsigned char *id;
const unsigned char len;
const enum spinand_readid_method method;
};
#define SPINAND_ID(__method, ...) \
{ \
.id = (const unsigned char[]){ __VA_ARGS__ }, \
.len = sizeof((unsigned char[]){ __VA_ARGS__ }), \
.method = __method, \
}
/**
* struct spinand_info - structture used to describe SPI NAND chips.
* @model: model name
* @devid: device id
* @eccreq: ECC Reqirement.
* @selcet_target: function used to select a target/die, Required only for
multi_dies.
* Each SPI NAND manufaturer driver should have a spinand_info table
* decribing all the chips supported by the driver.
*/
struct spinand_info {
const char *model;
struct spinand_devid devid;
struct nand_memory_organization memorg;
struct nand_ecc_req eccreq;
int (*select_target)(struct spinand_device *spinand, unsigned int target);
};
#define SPINAND_SELECT_TARGET(__func) \
.select_target = __func,
#define SPINAND_INFO(__model, __id, __memorg, __eccreq, ...) \
{ \
.model = __model, \
.devid = __id, \
.memorg = __memorg, \
.eccreq = __eccreq, \
__VA_ARGS__ \
}
/**
* struct spinand_device - SPI NAND device instance
* @base: NAND device instance.
* @lock: lock used to serialize accessed to the NAND.
* @id: NAND ID as returned by READ_ID.
* @select_target:select a specific target/die. Usually called before sending
a command addressing a page or an eraseblock embedded in this die.
* @menufacturer: SPI NAND manufacturer informaition.
*/
struct spinand_device {
struct nand_device base;
struct spinand_id id;
int (*select_target) (struct spinand_device *spinand, unsigned int cur_target);
unsigned int cur_target;
const struct spinand_manufacturer *manufacturer;
};
/**
* struct manufacotuerer_ops - OPS NAND manufacturer specific operations
* @init: initlization a SPI NAND device
* @cleanup: cleanup a SPI NAND devices
* Each SPI NAND manufactuer driver should implement the interface so that
* NAND chips coming form this vendor can be initilization properly.
*/
struct spinand_manufacturer_ops {
int (*init)(struct spinand_device *spinand);
int (*cleanup) (struct spinand_device *spinand);
int (*check_ecc) (unsigned char val);
};
/**
* struct spinand_manufacturer - SPI NAND manfacturer instance.
* @id: manufacturer ID.
* @name: manufacturer name.
* @spinand_info: spinand info.
* @nchips:
* manufacturer_ops:
*/
struct spinand_manufacturer {
unsigned char id;
unsigned char *name;
const struct spinand_info *chips;
const unsigned int nchips;
const struct spinand_manufacturer_ops *ops;
};
/**
* spinand_to_nand() - Get the SPI NAND device embedded in a SPI NAND object.
* @spinand: SPI NAND device.
* Returns: the NAND device.
*/
static inline struct nand_device * spinand_to_nand(struct spinand_device *spinand)
{
return &spinand->base;
}
/**
* nanddev_page_size() - Get NAND Page Size.
* @spinand: SPI NAND device.
* Returns: the page size.
*/
static inline unsigned int nanddev_page_size(const struct nand_device *nand)
{
return nand->memorg.pagesize;
}
/**
* nanddev_oobsize() - Get NAND Page Size.
* @spinand: SPI NAND device.
* Returns: the page size.
*/
static inline unsigned int nanddev_per_page_oobsize(const struct nand_device *nand)
{
return nand->memorg.oobsize;
}
/**
* nanddev_eraseblock_size() - Get NAND erase block Size.
* @spinand: SPI NAND device.
* Returns: the erase block size.
*/
static inline unsigned int nanddev_eraseblock_size(const struct nand_device *nand)
{
return nand->memorg.pages_per_eraseblock * nand->memorg.pagesize ;
}
/**
* nanddev_eraseblock_size() - Get NAND erase block Size.
* @spinand: SPI NAND device.
* Returns: the number of target/die used by us.
*/
static inline unsigned int nanddev_eraseblocks_per_target(const struct nand_device *nand)
{
return (nand->memorg.luns_per_target *nand->memorg.eraseblocks_per_lun);
}
/**
* nanddev_page_size() - Get total size provided by a single target/die.
* @spinand: SPI NAND device.
* Returns: the total size per target/die.
*/
static inline unsigned long long nanddev_target_size(const struct nand_device *nand)
{
return (unsigned long long )nand->memorg.luns_per_target *
nand->memorg.eraseblocks_per_lun *
nand->memorg.pages_per_eraseblock *
nand->memorg.pagesize;
}
/**
* nanddev_size() - Get the total targets.
* @spinand: SPI NAND device.
* Returns: the total number.
*/
static inline unsigned int nanddev_ntargets(const struct nand_device *nand)
{
return nand->memorg.ntargets;
}
/**
* nanddev_size() - Get NAND Size.
* @spinand: SPI NAND device.
* Returns: the page size.
*/
static inline unsigned int nanddev_size(const struct nand_device *nand)
{
return nanddev_target_size(nand) * nanddev_ntargets(nand);
}
struct SPINAND_ADDRESS_FIELDS
{
unsigned int CA :11;
unsigned int RA :16;
unsigned int reserved :5;
};
typedef union
{
unsigned int value;
struct SPINAND_ADDRESS_FIELDS fields;
} SPINAND_ADDRESS_FIELD_T;
enum{
QUEC_SPI_NAND_DEV0 = 0,
QUEC_SPI_NAND_DEV2 = 2
};
enum{
QUEC_SPI_NAND_PIN_16_19 ,
QUEC_SPI_NAND_PIN_33_36 ,
QUEC_SPI_NAND_PIN_12_15 ,
};
enum{
QUEC_SPI_NAND_CLOCK_13M = 0x0,
QUEC_SPI_NAND_CLOCK_26M = 0x1,
QUEC_SPI_NAND_CLOCK_52M = 0x2,
};
unsigned int SPINANDDevice_Init(unsigned char flashnu, FlashBootType_T flashbootType, unsigned char *P_DefaultPartitonNum);
unsigned int SPINAND_Read(unsigned int FlashOffset, unsigned int Buffer,
unsigned int Size, FlashBootType_T fbt);
unsigned int SPINAND_Write(unsigned int FlashOffset, unsigned int Buffer,
unsigned int Size, FlashBootType_T fbt);
unsigned int SPINAND_Erase(unsigned int FlashOffset, unsigned int Size,
FlashBootType_T fbt);
unsigned int SPINAND_Read_Page_SpareData(unsigned int FlashOffset,
unsigned int Buffer, unsigned int size);
unsigned int SPINAND_Write_Page_SpareData(unsigned int FlashOffset,
unsigned int Buffer, unsigned int size);
int quec_nand_spi_init(int spi_port,int spi_pin,int spi_clk);
#endif