blob: 11354c26d4f12061f9573a1263b3b866c917aba2 [file] [log] [blame]
/*
* Amlogic SPI flash interface
*
* Copyright (C) 2011 Amlogic Corporation
*
* Licensed under the GPL-2 or later.
*
*
* Dedicated for Amlogic SPI controller use
*/
#include <common.h>
#include <malloc.h>
#include <asm/cache.h>
#include "spi_flash_amlogic.h"
#include <asm/arch/secure_apb.h>
#include <asm/cpu_id.h>
#ifdef CONFIG_SPI_NOR_SECURE_STORAGE
#include "spi_secure_storage.h"
#endif
/*note: To use Amlogic SPI flash controller for SPI flash access
two macro CONFIG_CMD_SF & CONFIG_AML_MESON_1/2/3
must be set to 1
header file locate at: \board\amlogic\configs\
backup PIN_MAX_1 value before claim bus for SPI controller
restore the original value after usage
note: following two functions for one SPI operation
void spi_release_bus(struct spi_slave *slave)
int spi_claim_bus(struct spi_slave *slave)
static u32 g_u32_PERIPHS_PIN_MUX_1_backup = 0;
*/
int spi_flash_cmd(struct spi_slave *spi, u32 cmd, void *response, size_t len)
{
unsigned long flags = SPI_XFER_BEGIN;
int ret;
u32 var=cmd;
if (len == 0)
flags |= SPI_XFER_END;
flags|=SPI_XFER_CMD;
ret = spi_xfer(spi, 4*8, (u8*)&var, NULL, flags);
if (ret) {
debug("SF: Failed to send command %02x: %d\n", cmd, ret);
return ret;
}
if (len) {
if ((1<<SPI_FLASH_RDID) == cmd) {
flags=SPI_XFER_ID;
}
else{
if ((1<<SPI_FLASH_RDSR) == cmd) {
flags=SPI_XFER_STATUS;
}
}
ret = spi_xfer(spi, len * 8, NULL, response, flags|SPI_XFER_END);
if (ret) {
debug("SF: Failed to read response (%zu bytes): %d\n",
len, ret);
}
}
return ret;
}
///////////////////////////////////////////////////////////////////////////////////////
//
// implementation of header file <project>\include\spi.h
//
//
struct aml_spi_slave {
struct spi_slave slave;
void * adr_base;
u32 mode;
u32 ctl;
};
#ifdef CONFIG_AML_SPICC
extern void spicc_cs_activate(struct spi_slave *slave);
extern void spicc_cs_deactivate(struct spi_slave *slave);
extern struct spi_slave *spicc_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode);
extern void spicc_free_slave(struct spi_slave *slave);
extern int spicc_claim_bus(struct spi_slave *slave);
extern void spicc_release_bus(struct spi_slave *slave);
extern int spicc_xfer(struct spi_slave *slave, unsigned int bitlen,
const void *dout, void *din, unsigned long flags);
#endif
static inline struct aml_spi_slave *to_aml_spi(struct spi_slave *slave){
return container_of(slave, struct aml_spi_slave, slave);
}
__attribute__((weak)) void spi_init(void){}
__attribute__((weak)) int spi_cs_is_valid(unsigned int bus, unsigned int cs){return 0;}
__attribute__((weak)) void spi_cs_activate(struct spi_slave *slave)
{
#ifdef CONFIG_AML_SPICC
if (slave->bus == BUS_SPICC) {
spicc_cs_activate(slave);
return;
}
#endif
}
__attribute__((weak)) void spi_cs_deactivate(struct spi_slave *slave)
{
#ifdef CONFIG_AML_SPICC
if (slave->bus == BUS_SPICC) {
spicc_cs_deactivate(slave);
return;
}
#endif
}
static void spi_initialize(void){
writel(0xea949,P_SPI_FLASH_CTRL); //SPI clock-> system clock / 10
}
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
{
#ifdef CONFIG_AML_SPICC
if (bus == BUS_SPICC) {
return spicc_setup_slave(bus, cs, max_hz, mode);
}
#endif
struct aml_spi_slave * amls;
amls = ( struct aml_spi_slave *)malloc(sizeof(struct aml_spi_slave));
if (!amls)
return NULL;
spi_initialize();
amls->slave.bus = bus;
amls->slave.cs = cs;
amls->adr_base =(void*)0xCC000000;
amls->mode=mode;
return &amls->slave;
}
void spi_free_slave(struct spi_slave *slave)
{
#ifdef CONFIG_AML_SPICC
if (slave->bus == BUS_SPICC) {
spicc_free_slave(slave);
return;
}
#endif
struct aml_spi_slave *amls = to_aml_spi(slave);
free(amls);
}
int spi_check_write_protect(void)
{
writel(1<<SPI_FLASH_RDSR, P_SPI_FLASH_CMD);
while (readl(P_SPI_FLASH_CMD) != 0) ;
return (readl(P_SPI_FLASH_STATUS)&(0xf<<2)) == (0xf<<2)?1:0;
}
void spi_enable_write_protect(void)
{
unsigned char statusValue;
int ret;
statusValue = 0xf<<2;//all protect;
/*write enable*/
writel(1<<SPI_FLASH_WREN, P_SPI_FLASH_CMD);
while (readl(P_SPI_FLASH_CMD) != 0) {
do {
writel(1<<SPI_FLASH_RDSR, P_SPI_FLASH_CMD);
while (readl(P_SPI_FLASH_CMD) != 0) ;
ret = readl(P_SPI_FLASH_STATUS);
}while (ret&1);
}
/*write status register*/
writel(statusValue,P_SPI_FLASH_STATUS);
writel(1<<SPI_FLASH_WRSR, P_SPI_FLASH_CMD);
while (readl(P_SPI_FLASH_CMD) != 0) {
do {
writel(1<<SPI_FLASH_RDSR, P_SPI_FLASH_CMD);
while (readl(P_SPI_FLASH_CMD) != 0) ;
ret = readl(P_SPI_FLASH_STATUS);
}while (ret&1);
}
}
void spi_disable_write_protect(void)
{
unsigned char statusValue;
int ret, var;
statusValue = 0;
/*write enable*/
var = 1 << SPI_FLASH_WREN;
writel(var, P_SPI_FLASH_CMD);
while (readl(P_SPI_FLASH_CMD) != 0) ;
ret=1;
while ((ret&1) == 1) {
var=1<<SPI_FLASH_RDSR;
writel(var, P_SPI_FLASH_CMD);
while (readl(P_SPI_FLASH_CMD) != 0) ;
ret = readl(P_SPI_FLASH_STATUS)&0xff;
}
/*write status register*/
writel(statusValue,P_SPI_FLASH_STATUS);
var = 1<<SPI_FLASH_WRSR;
writel(var, P_SPI_FLASH_CMD);
while (readl(P_SPI_FLASH_CMD) != 0) ;
ret=1;
while ( (ret&1) == 1 ) {
var=1<<SPI_FLASH_RDSR;
writel(var, P_SPI_FLASH_CMD);
while (readl(P_SPI_FLASH_CMD) != 0) ;
ret = readl(P_SPI_FLASH_STATUS)&0xff;
}
}
int spi_claim_bus(struct spi_slave *slave)
{
#ifdef CONFIG_AML_SPICC
if (slave->bus == BUS_SPICC) {
return spicc_claim_bus(slave);
}
#endif
debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
setbits_le32(P_PERIPHS_PIN_MUX_5,(0xf<<16));
return 0;
}
void spi_release_bus(struct spi_slave *slave)
{
#ifdef CONFIG_AML_SPICC
if (slave->bus == BUS_SPICC) {
spicc_release_bus(slave);
return;
}
#endif
debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
clrbits_le32(P_PERIPHS_PIN_MUX_5,(0xf<<16));
}
//Only for Amlogic SPI controller
//note flag for cmd adr status data trans
//bitlen is byte*8
int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
{
#ifdef CONFIG_AML_SPICC
if (slave->bus == BUS_SPICC) {
return spicc_xfer(slave, bitlen, dout, din, flags);
}
#endif
struct aml_spi_slave *as = to_aml_spi(slave);
u32 len;
u32 temp_len;
u8 temp_data[4];
u8 *buf = temp_data;
const u8 *txp = (u8 *)dout;
u8 *rxp = (u8 *)din;
u32 value;
int i,j;
volatile unsigned int * c0;
if (bitlen == 0)/* Finish any previously submitted transfers */
goto out;
if (bitlen % 8) {/* Errors always terminate an ongoing transfer*/
flags |= SPI_XFER_END;
goto out;
}
len = bitlen / 8; //convert to BYTE counter
if (flags & SPI_XFER_BEGIN)
spi_cs_activate(slave);
//Set Address register of SPI controller
if (flags&SPI_XFER_ADR) {
writel(*((u32*)txp), P_SPI_FLASH_ADDR);
goto out;
}
//Send command to device through SPI FLASH command register
if (flags&SPI_XFER_CMD) {
if (*((u32*)dout) == (1<<SPI_FLASH_RDID)) {
/*only for RDID, clear the cache for a fresh load*/
writel(0, P_SPI_FLASH_C0);
}
writel(*((u32*)txp), P_SPI_FLASH_CMD);
while (readl(P_SPI_FLASH_CMD) != 0) ;
goto out;
}
//Write data to SPI data cache for transfer
//Then SPI controller will transfer them to SPI device with WREN(Writer enable) & PP(Page program)
if ((txp) && (flags&SPI_XFER_WRITECACHE)) {
c0 = P_SPI_FLASH_C0;
for ( j=0;j<len;j+=4) {
value = *(u32*)(txp+j);
writel(value, c0++);
//printf("buf%d:0x%x\n", j, value);
}
goto out;
}
//for input to host
//following code will use rxp
if (!rxp)
goto out;
//Read status register
if (flags&SPI_XFER_STATUS) { /*FIXME WRSTAUS */
value=readl(P_SPI_FLASH_STATUS)&0xffff;
*rxp=value&0xff;
*(rxp+1)=(value>>8)&0xff;
goto out;
}
//Read vender & chip ID
if (flags&SPI_XFER_ID) { /*FIXME EON*/
value=readl(P_SPI_FLASH_C0)&0xffffff;
*rxp=value&0xff;
*(rxp+1)=(value>>8)&0xff;
*(rxp+2)=(value>>16)&0xff;
goto out;
}
//Load data from cache, SPI controller will auto send read read flash command and store data to address as->adr_base
if (flags&SPI_XFER_COPY) {
setbits_le32(P_SPI_FLASH_CTRL, 1<<SPI_ENABLE_AHB); /*for AHB data bus request*/
memcpy((unsigned char *)(rxp),(unsigned char *)((as->adr_base)+(*(u32*)txp)),bitlen/8);
clrbits_le32(P_SPI_FLASH_CTRL, 1<<SPI_ENABLE_AHB); /*release AHB bus*/
//printf("Hisun: XFER_COPY -> 0x%08X Bytes from 0x%08X to 0x%08X\n",bitlen/8,((as->adr_base)+(*(u32*)txp)),(rxp));
goto out;
}
//Load from SPI controller data cache
if (flags&SPI_XFER_READCACHE) {
temp_len = len/4;
c0 = P_SPI_FLASH_C0;
for ( i=0;i<temp_len*4;i+=4) {
value = readl(c0++);
*(u32 *)(rxp+i) = value;
//printf("val[%d]=0x%8x\n", i, value);
}
if (len%4) {
temp_len = len%4;
*(u32 *)buf = readl(c0++);
for (j=0;j<temp_len;j++) {
*(u8 *)(rxp+i+j)=*(buf+j);
}
}
goto out;
}
//note: from here to label "out:" any code without rxp usage
// but rxp is not NULL will be pass
//.....
out:
if (flags & SPI_XFER_END) {
spi_cs_deactivate(slave);
}
setbits_le32(P_SPI_FLASH_CTRL, 1<<SPI_ENABLE_AHB); /*for AHB data bus request*/
return 0;
}
//from trunk\spi_flash_aml.c
static int spi_flash_addr_write(struct spi_slave *spi, u32 addr){
unsigned flags = SPI_XFER_END;
u32 nAddress = addr;
int ret;
flags |= SPI_XFER_ADR;
ret = spi_xfer(spi,4*8,&nAddress,NULL,flags);
if (ret) {
debug("SF: Faild to send addr(4 bytes): %d\n",ret);
}
return ret;
}
int spi_flash_erase_amlogic(struct spi_flash *flash,u32 offset, size_t len, u32 sector_size)
{
struct spi_slave * slave=flash->spi;
size_t actual;
unsigned var;
int nReturn = -1;
if (offset % sector_size || len % sector_size) {
printf("SF: Erase offset/length not multiple of sector size!\n");
return nReturn;
}
//close AHB bus before any APB bus operation
clrbits_le32(P_SPI_FLASH_CTRL, 1<<SPI_ENABLE_AHB);
#ifdef SPI_WRITE_PROTECT
spi_disable_write_protect();
#endif
for (actual = 0; actual < len; actual+=sector_size) {
debug("Erase:%zu\n",actual);
var=(offset+actual) & 0xffffff;
#ifdef CONFIG_SPI_NOR_SECURE_STORAGE
if (flash->secure_protect) {
if ((var >=flash->securestorage_info->start_pos) && (var < flash->securestorage_info->end_pos)) {
//printf("addr: 0x%x \n",var);
continue;
}
}
#endif
spi_flash_addr_write(slave,var);
//Trigger write enable command
var=1<<SPI_FLASH_WREN;
spi_flash_cmd(slave,var,NULL,0);
//Trigger sector erase command
var=1<<SPI_FLASH_SE;
spi_flash_cmd(slave,var,NULL,0);
//debug for hangup
//printf("PIN_MAX_REG0 = 0x%08X\n",READ_CBUS_REG(PERIPHS_PIN_MUX_1));
nReturn=1;
while ( (nReturn&1) == 1 ) {
var=1<<SPI_FLASH_RDSR;
spi_flash_cmd(slave,var,&nReturn,2); //2 byte status
}
}
//reopen AHB bus after any APB bus operation
setbits_le32(P_SPI_FLASH_CTRL, 1<<SPI_ENABLE_AHB);
#ifdef CONFIG_SPI_NOR_SECURE_STORAGE
void secure_storage_spi_disable(void);
secure_storage_spi_disable();
#endif
return nReturn;
}
//for CONFIG_SPI_FLASH_SPANSION no SE(0x20) command
//use Block erase 0xD8 command
int spi_flash_erase_be_amlogic(struct spi_flash *flash,u32 offset, size_t len, u32 sector_size)
{
struct spi_slave * slave=flash->spi;
size_t actual;
unsigned var;
int nReturn = -1;
if (offset % sector_size || len % sector_size) {
printf("SF: Erase offset/length not multiple of sector size!\n");
return nReturn;
}
//close AHB bus before any APB bus operation
clrbits_le32(P_SPI_FLASH_CTRL, 1<<SPI_ENABLE_AHB);
#ifdef SPI_WRITE_PROTECT
spi_disable_write_protect();
#endif
for (actual = 0; actual < len; actual+=sector_size) {
debug("Erase:%zu\n",actual);
var=(offset+actual) & 0xffffff;
#ifdef CONFIG_SPI_NOR_SECURE_STORAGE
if (flash->secure_protect) {
if ((var >=flash->securestorage_info->start_pos) && (var < flash->securestorage_info->end_pos)) {
//printf("addr: 0x%x \n",var);
continue;
}
}
#endif
spi_flash_addr_write(slave,var);
//Trigger write enable command
var=1<<SPI_FLASH_WREN;
spi_flash_cmd(slave,var,NULL,0);
//Trigger sector erase command
//for CONFIG_SPI_FLASH_SPANSION no SE(0x20) command
//use BE(0xD8) command
var=1<<SPI_FLASH_BE;
spi_flash_cmd(slave,var,NULL,0);
//debug for hangup
//printf("PIN_MAX_REG0 = 0x%08X\n",READ_CBUS_REG(PERIPHS_PIN_MUX_1));
nReturn=1;
while ( (nReturn&1) == 1 ) {
var=1<<SPI_FLASH_RDSR;
spi_flash_cmd(slave,var,&nReturn,2); //2 byte status
}
}
//reopen AHB bus after any APB bus operation
setbits_le32(P_SPI_FLASH_CTRL, 1<<SPI_ENABLE_AHB);
#ifdef CONFIG_SPI_NOR_SECURE_STORAGE
void secure_storage_spi_disable(void);
secure_storage_spi_disable();
#endif
return nReturn;
}
int spi_flash_write_amlogic(struct spi_flash *flash,u32 offset, size_t len, const void *buf){
struct spi_slave *spi = flash->spi;
u32 temp_addr = offset;
int temp_length = len;
unsigned flags;
int nReturn = 0;
if (!len)
return nReturn;
nReturn = 1;
#ifdef SPI_WRITE_PROTECT
spi_disable_write_protect();
#endif
//clean data cache
//dcache_clean_range((u32)buf, len);
flush_dcache_all();
//close AHB bus before any APB bus operation
clrbits_le32(P_SPI_FLASH_CTRL, 1<<SPI_ENABLE_AHB);
while (temp_length>0) {
flags=(temp_addr & 0xffffff)|( (temp_length>=32?32:temp_length) << SPI_FLASH_BYTES_LEN);
#ifdef CONFIG_SPI_NOR_SECURE_STORAGE
if (flash->secure_protect) {
if ((temp_addr >= flash->securestorage_info->start_pos) &&(temp_addr<flash->securestorage_info->end_pos)) {
temp_addr += (temp_length>=32?32:temp_length);
buf += (temp_length>=32?32:temp_length);
temp_length -= (temp_length>=32?32:temp_length);
//printf("prohibit write,%s:%d\n",__func__,__LINE__);
continue;
}
}
#endif
spi_flash_addr_write(spi, flags);
flags=SPI_XFER_WRITECACHE;
spi_xfer(spi,(temp_length>=32?32:temp_length)*8,buf,NULL,flags);
flags=(1<<SPI_FLASH_WREN);
spi_flash_cmd(spi,flags,NULL,0);
flags=(1<<SPI_FLASH_PP);
spi_flash_cmd(spi,flags,NULL,0);
nReturn=1;
while ( (nReturn&1) == 1 ) {
flags=1<<SPI_FLASH_RDSR;
spi_flash_cmd(spi,flags,&nReturn,2); //2 byte status
}
temp_addr += (temp_length>=32?32:temp_length);
buf += (temp_length>=32?32:temp_length);
temp_length -= (temp_length>=32?32:temp_length);
}
//reopen AHB bus after any APB bus operation
setbits_le32(P_SPI_FLASH_CTRL, 1<<SPI_ENABLE_AHB);
#ifdef SPI_WRITE_PROTECT
spi_enable_write_protect();
#endif
//cache refresh
flush_dcache_all();
return nReturn;
}
int spi_flash_read_amlogic(struct spi_flash *flash,u32 offset, size_t len, void *buf){
struct spi_slave *spi = flash->spi;
u32 temp_addr = offset;
int temp_length = len;
unsigned flags;
if (!len)
return 0;
#ifdef CONFIG_SPI_NOR_SECURE_STORAGE
if (flash->secure_protect) {
if (((offset+len)>flash->securestorage_info->start_pos) &&((offset+len) <= flash->securestorage_info->end_pos)) {
//printf("prohibit read,%s:%d\n",__func__,__LINE__);
return -1;
}
else if(((offset+len)>flash->securestorage_info->end_pos)
&&(offset>=flash->securestorage_info->start_pos)
&&(offset<flash->securestorage_info->end_pos)){
//printf("prohibit read,%s:%d\n",__func__,__LINE__);
return -1;
}
else if(((offset+len)>flash->securestorage_info->end_pos)
&&(offset < flash->securestorage_info->start_pos)
&&(len>(flash->securestorage_info->start_pos-offset))){
//printf("prohibit read,%s:%d\n",__func__,__LINE__);
return -1;
}
}
#endif
//invalid data cache
//dcache_invalid_range((u32)buf,len);
flush_dcache_all();
/* 0x400000 ~ 0x7fffff */
if (temp_addr + len > 0x400000 && temp_addr < 0x400000) {
//Read data from SPI controller from temp_addr to 0x3fffff
//From 0x400000 to (temp_addr+len) need to set address and
//load from cache with 32Bytes per package
flags = SPI_XFER_END|SPI_XFER_COPY;
spi_xfer(spi,(0x400000-temp_addr)*8,&temp_addr,buf,flags);
buf += (0x400000-temp_addr);
temp_length = len - (0x400000-temp_addr);
temp_addr = 0x400000;
}
/* 0x000000 ~ 0x3fffff */
else if(temp_addr < 0x400000){
flags=SPI_XFER_END|SPI_XFER_COPY;
spi_xfer(spi,temp_length*8,&temp_addr,buf,flags);
return 0;
}
while (temp_length>0) {
//(byte counter << 24| 24bit device address) for SPI address register
flags=(temp_addr & 0xffffff)|( (temp_length>=32?32:temp_length) << SPI_FLASH_BYTES_LEN);
spi_flash_addr_write(spi, flags);
//trigger SPI flash read command
flags=(1<<SPI_FLASH_READ);
spi_flash_cmd(spi,flags,NULL,0);
//load data from SPI controller 32bytes data cache
flags=SPI_XFER_READCACHE;
spi_xfer(spi,(temp_length>=32?32:temp_length)*8,NULL,buf,flags);
//adjust address, buffer & length
temp_addr += (temp_length>=32?32:temp_length);
buf += (temp_length>=32?32:temp_length);
temp_length -= (temp_length>=32?32:temp_length);
}
//cache refresh
flush_dcache_all();
return 0;
}
void spi_flash_free(struct spi_flash *flash)
{
#ifdef CONFIG_SPI_NOR_SECURE_STORAGE
extern void spi_securestorage_free(void);
spi_securestorage_free();
#endif
spi_free_slave(flash->spi);
free(flash);
}
/*
* The following table holds all device probe functions
*
* shift: number of continuation bytes before the ID
* idcode: the expected IDCODE or 0xff for non JEDEC devices
* probe: the function to call
*
* Non JEDEC devices should be ordered in the table such that
* the probe functions with best detection algorithms come first.
*
* Several matching entries are permitted, they will be tried
* in sequence until a probe function returns non NULL.
*
* IDCODE_CONT_LEN may be redefined if a device needs to declare a
* larger "shift" value. IDCODE_PART_LEN generally shouldn't be
* changed. This is the max number of bytes probe functions may
* examine when looking up part-specific identification info.
*
* Probe functions will be given the idcode buffer starting at their
* manu id byte (the "idcode" in the table below). In other words,
* all of the continuation bytes will be skipped (the "shift" below).
*/
#define IDCODE_CONT_LEN 0
#define IDCODE_PART_LEN 5
static const struct {
const u8 shift;
const u8 idcode;
struct spi_flash *(*probe) (struct spi_slave *spi, u8 *idcode);
} g_flashes[] = {
/* Keep it sorted by define name */
//#ifdef CONFIG_SPI_FLASH_ATMEL
// { 0, 0x1f, spi_flash_probe_atmel, },
//#endif
#ifdef CONFIG_SPI_FLASH_EON
{ 0, 0x1c, spi_flash_probe_eon, },
#endif
#ifdef CONFIG_SPI_FLASH_MACRONIX
{ 0, 0xc2, spi_flash_probe_macronix, },
#endif
#ifdef CONFIG_SPI_FLASH_SPANSION
{ 0, 0x01, spi_flash_probe_spansion, },
#endif
#ifdef CONFIG_SPI_FLASH_SST
{ 0, 0xbf, spi_flash_probe_sst, },
#endif
#ifdef CONFIG_SPI_FLASH_STMICRO
{ 0, 0x20, spi_flash_probe_stmicro, },
#endif
#ifdef CONFIG_SPI_FLASH_WINBOND
{ 0, 0xef, spi_flash_probe_winbond, },
#endif
#ifdef CONFIG_SPI_FLASH_GIGADEVICE
{ 0, 0xc8, spi_flash_probe_gigadevice, },
#endif
#ifdef CONFIG_SPI_FLASH_PMDEVICE
{ 0, 0x7f, spi_flash_probe_pmdevice, },
#endif
#ifdef CONFIG_SPI_FLASH_ESMT
{ 0, 0x8c, spi_flash_probe_esmt, },
#endif
//#ifdef CONFIG_SPI_FRAM_RAMTRON
// { 6, 0xc2, spi_fram_probe_ramtron, },
//# undef IDCODE_CONT_LEN
//# define IDCODE_CONT_LEN 6
//#endif
/* Keep it sorted by best detection */
#ifdef CONFIG_SPI_FLASH_STMICRO
{ 0, 0xff, spi_flash_probe_stmicro, },
#endif
//#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC
// { 0, 0xff, spi_fram_probe_ramtron, },
//#endif
};
#define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN)
struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int spi_mode)
{
struct spi_slave *spi;
struct spi_flash *flash = NULL;
int ret, i, shift;
u8 idcode[IDCODE_LEN], *idp;
if (get_cpu_id().family_id >= MESON_CPU_MAJOR_ID_GXL) {
*P_PAD_PULL_UP_EN_REG2 = 0xffff87ff;
*P_PAD_PULL_UP_REG2 = 0xffff8700;
// deselect nand/emmc, select spi.
if (get_cpu_id().family_id <= MESON_CPU_MAJOR_ID_GXM) {
*P_PERIPHS_PIN_MUX_7 &= ~((1<<28) | (7<<2) | 1);
}
else {
*P_PERIPHS_PIN_MUX_7 &= ~((1<<31) | (1<<28) | (7<<20));
}
*P_PERIPHS_PIN_MUX_7 |= 0xf<<10;
(*((volatile unsigned *)((volatile uint32_t *)0xc1108c88)))=(0x2aaf7f);
}
spi = spi_setup_slave(bus, cs, max_hz, spi_mode);
if (!spi) {
printf("SF: Failed to set up slave\n");
return NULL;
}
ret = spi_claim_bus(spi);
if (ret) {
debug("SF: Failed to claim SPI bus: %d\n", ret);
goto err_claim_bus;
}
/* Read the ID codes */
memset(idcode,0,sizeof(idcode));
ret = spi_flash_cmd(spi, 1<<SPI_FLASH_RDID, idcode, sizeof(idcode));
if (ret)
goto err_read_id;
/* count the number of continuation bytes */
for (shift = 0, idp = idcode;
shift < IDCODE_CONT_LEN && *idp == 0x7f;
++shift, ++idp)
continue;
/* search the table for matches in shift and id */
for (i = 0; i < ARRAY_SIZE(g_flashes); ++i)
if (g_flashes[i].shift == shift && g_flashes[i].idcode == *idp) {
/* we have a match, call probe */
flash = g_flashes[i].probe(spi, idp);
if (flash)
break;
}
if (!flash) {
printf("SF: Unsupported manufacturer %02x\n", *idp);
goto err_manufacturer_probe;
}
#ifdef CONFIG_SPI_NOR_SECURE_STORAGE
extern int spi_securestorage_probe(void *keypara);
if (spi_securestorage_probe(flash)) {
printf("spi secure storage probe fail\n");
}
#endif
#ifdef SPI_WRITE_PROTECT
if (spi_check_write_protect())
printf("\nSPI NOR Flash have write protect!!!\n");
else{
printf("\nSPI NOR Flash NO write protect!!!, So I will enable it...\n");
spi_enable_write_protect();
}
#endif
spi_release_bus(spi);
return flash;
err_manufacturer_probe:
err_read_id:
spi_release_bus(spi);
err_claim_bus:
spi_free_slave(spi);
return NULL;
}