blob: 7359ff7f2fcf795603dbdd9e979b276cd7c9325a [file] [log] [blame]
/*
* (C) Copyright 2012, Amlogic Inc.
* Author: Haixiang Bao<haixiang.bao@amlogic.com>
* Licensed under the GPL-2 or later.
*/
#include <common.h>
#include <malloc.h>
#include <spi_flash.h>
#include "spi_flash_amlogic.h"
struct gigadevice_spi_flash_params {
uint32_t id;
uint32_t sector_size;
uint32_t block_size;
uint32_t chip_size;
const char *name;
};
/* spi_flash needs to be first so upper layers can free() it */
struct gigadevice_spi_flash {
struct spi_flash flash;
const struct gigadevice_spi_flash_params *params;
};
static inline struct gigadevice_spi_flash *to_gigadevice_spi_flash(struct spi_flash *flash)
{
return container_of(flash, struct gigadevice_spi_flash, flash);
}
#define GIGADEVICE_ID_GD25Q16 0x4015
#define GIGADEVICE_ID_GD25Q32 0x4016
#define GIGADEVICE_ID_GD25Q40 0x4013
static const struct gigadevice_spi_flash_params gigadevice_spi_flash_table[] = {
{ .id = GIGADEVICE_ID_GD25Q16,
.sector_size = 4*1024,
.block_size = 16*4*1024 ,
.chip_size = 32*16*4*1024,
.name = "GD25Q16",
},
{ .id = GIGADEVICE_ID_GD25Q32,
.sector_size = 4*1024,
.block_size = 16*4*1024 ,
.chip_size = 64*16*4*1024,
.name = "GD25Q32",
},
{ .id = GIGADEVICE_ID_GD25Q40,
.sector_size = 4*1024,
.block_size = 16*4*1024 ,
.chip_size = 8*16*4*1024,
.name = "GD25Q40",
},
};
static int gigadevice_write(struct spi_flash *flash, u32 offset, size_t len, const void *buf)
{
int nReturn = 0;
spi_claim_bus(flash->spi);
nReturn = spi_flash_write_amlogic(flash, offset, len,buf);
spi_release_bus(flash->spi);
return nReturn;
}
static int gigadevice_read_fast(struct spi_flash *flash, u32 offset, size_t len, void *buf)
{
int nReturn =0;
spi_claim_bus(flash->spi);
nReturn = spi_flash_read_amlogic(flash, offset, len,buf);
spi_release_bus(flash->spi);
return nReturn;
}
static int gigadevice_erase(struct spi_flash *flash, u32 offset, size_t len)
{
struct gigadevice_spi_flash *stm = to_gigadevice_spi_flash(flash);
u32 sector_size;
int nReturn;
sector_size = stm->params->sector_size;
spi_claim_bus(flash->spi);
nReturn = spi_flash_erase_amlogic(flash, offset, len, sector_size);
spi_release_bus(flash->spi);
return nReturn;
}
struct spi_flash *spi_flash_probe_gigadevice(struct spi_slave *spi, u8 *idcode)
{
const struct gigadevice_spi_flash_params *params;
struct gigadevice_spi_flash *gigadevice;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(gigadevice_spi_flash_table); ++i) {
params = &gigadevice_spi_flash_table[i];
if (((idcode[1] << 8) | idcode[2]) == params->id)
break;
}
if (i == ARRAY_SIZE(gigadevice_spi_flash_table)) {
debug("SF: Unsupported GIGADEVICE ID %02x\n", idcode[1]);
return NULL;
}
gigadevice = malloc(sizeof(*gigadevice));
if (!gigadevice) {
debug("SF: Failed to allocate memory\n");
return NULL;
}
gigadevice->params = params;
gigadevice->flash.spi = spi;
gigadevice->flash.name = params->name;
gigadevice->flash.write = gigadevice_write;
gigadevice->flash.erase = gigadevice_erase;
gigadevice->flash.read = gigadevice_read_fast;
gigadevice->flash.size = params->chip_size;
debug("SF: Detected %s with page size %u, total %u bytes\n",
params->name, params->page_size, gigadevice->flash.size);
return &gigadevice->flash;
}