aboutsummaryrefslogtreecommitdiff
path: root/drivers/mtd/devices/hs_sfc/hisfc350.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/devices/hs_sfc/hisfc350.c')
-rw-r--r--drivers/mtd/devices/hs_sfc/hisfc350.c249
1 files changed, 104 insertions, 145 deletions
diff --git a/drivers/mtd/devices/hs_sfc/hisfc350.c b/drivers/mtd/devices/hs_sfc/hisfc350.c
index 97292e0546b7..252ddb596818 100644
--- a/drivers/mtd/devices/hs_sfc/hisfc350.c
+++ b/drivers/mtd/devices/hs_sfc/hisfc350.c
@@ -1,12 +1,19 @@
-/*****************************************************************************
- * Copyright (c) 2009-2011 by Hisi
- * All rights reserved.
- * ***
- * Create by CCC 2010-09-01
+/*
+ * SFC (Serial Flash Controller) device driver for Serial NOR Flash on
+ * Hisilicon platform
+ * The serial nor interface is based on drivers/mtd/m25p80.c and
+ * drivers/mtd/devices/spear_smi.c
*
- *****************************************************************************/
+ * Copyright © 2012-2013 Linaro Ltd.
+ * zhang.mingjun@linaro.org
+ * The initial developer of the original code is Zhiyong Cai
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
-/*****************************************************************************/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
@@ -27,30 +34,9 @@
#include "hisfc350.h"
-/*****************************************************************************/
-/* Don't change the follow config */
-#define HISFC350_SUPPORT_READ (SPI_IF_READ_STD \
- | SPI_IF_READ_FAST \
- | SPI_IF_READ_DUAL \
- | SPI_IF_READ_DUAL_ADDR \
- | SPI_IF_READ_QUAD \
- | SPI_IF_READ_QUAD_ADDR)
-
-#define HISFC350_SUPPORT_WRITE (SPI_IF_WRITE_STD \
- | SPI_IF_WRITE_DUAL \
- | SPI_IF_WRITE_DUAL_ADDR \
- | SPI_IF_WRITE_QUAD \
- | SPI_IF_WRITE_QUAD_ADDR)
-
-#define HISFC350_SUPPORT_MAX_DUMMY (7)
-
-/* this function only for debug, reg read is slower then dma read */
-#undef HISFCV350_SUPPORT_REG_READ
-
#define DRIVER_NAME "hi_sfc"
-
/*****************************************************************************/
-static char *ultohstr(unsigned long long size, char *buffer)
+static char *ultohstr(u32 size, char *buffer)
{
char *fmt[] = {"%u", "%uK", "%uM", "%uG", "%uT", "%uT"};
int ix;
@@ -61,11 +47,53 @@ static char *ultohstr(unsigned long long size, char *buffer)
sprintf(buffer, fmt[ix], size);
return buffer;
}
-static int hisfc350_wait_ready(struct hisfc_host *host,
+
+/*
+ * wait sfc controller to finish sending the cmd to flash-chip
+ */
+static inline int hisfc350_wait_cmd_timeout(struct hisfc_host *host)
+{
+ int timeout = 0x10000000;
+
+ while (((hisfc_read(HISFC350_CMD_CONFIG)
+ & HISFC350_CMD_CONFIG_START)) && timeout) {
+ --timeout;
+ }
+
+ if (!timeout) {
+ dev_err(host->dev, "cmd wait cpu finished timeout\n");
+ return -EIO;
+ } else
+ return 0;
+}
+
+/*
+ * wait sfc controller to finish the dma ops
+ * TODO: this func need to be rewrite, using irq and wait_event_timeout
+ */
+static inline int hisfc350_wait_dma_cmd_timeout(struct hisfc_host *host)
+{
+ int timeout = 0x10000000;
+
+ while (((hisfc_read(HISFC350_BUS_DMA_CTRL)
+ & HISFC350_BUS_DMA_CTRL_START)) && timeout) {
+ --timeout;
+ cond_resched();
+ }
+
+ if (!timeout) {
+ dev_err(host->dev, "dma wait cpu finish timeout\n");
+ return -EIO;
+ } else
+ return 0;
+}
+
+/* send a read status cmd to flash-chip to see if it was in write ops */
+static int hisfc350_wait_flash_ready_timeout(struct hisfc_host *host,
struct hisfc_flash_device *flash)
{
- unsigned long val;
unsigned long deadline = jiffies + HISFC350_MAX_READY_WAIT_JIFFIES;
+ u32 val;
do {
hisfc_write(HISFC350_CMD_INS, SPI_CMD_RDSR);
@@ -76,7 +104,7 @@ static int hisfc350_wait_ready(struct hisfc_host *host,
| HISFC350_CMD_CONFIG_RW_READ
| HISFC350_CMD_CONFIG_START);
- HISFC350_CMD_WAIT_CPU_FINISH(host);
+ hisfc350_wait_cmd_timeout(host);
val = hisfc_read(HISFC350_CMD_DATABUF0);
if (!(val & SPI_CMD_SR_WIP))
@@ -86,10 +114,11 @@ static int hisfc350_wait_ready(struct hisfc_host *host,
} while (!time_after_eq(jiffies, deadline));
- pr_info(KERN_ERR "Wait flash-dev ready timeout.\n");
+ dev_err(host->dev, "Wait flash-dev ready timeout.\n");
return -EBUSY;
}
+
/*****************************************************************************/
static void hisfc350_flash_set_4byte(struct hisfc_flash_device *flash,
int enable)
@@ -108,14 +137,14 @@ static void hisfc350_flash_set_4byte(struct hisfc_flash_device *flash,
HISFC350_CMD_CONFIG_SEL_CS(flash->cs)
| HISFC350_CMD_CONFIG_START);
- HISFC350_CMD_WAIT_CPU_FINISH(host);
+ hisfc350_wait_cmd_timeout(host);
}
/* config host to co-operate with the flash chip */
static inline void hisfc350_host_select_flash(struct hisfc_host *host,
struct hisfc_flash_device *flash)
{
- unsigned int val;
+ u32 val;
if (host->addr_mode != flash->addr_mode) {
val = hisfc_read(HISFC350_GLOBAL_CONFIG);
@@ -134,7 +163,7 @@ static inline void hisfc350_host_select_flash(struct hisfc_host *host,
static void hisfc350_dma_bus_config(struct hisfc_host *host,
struct hisfc_flash_device *flash)
{
- unsigned int val = 0;
+ u32 val = 0;
val |= HISFC350_BUS_CONFIG1_WRITE_INS(flash->info.write.cmd);
val |= HISFC350_BUS_CONFIG1_WRITE_DUMMY_CNT(flash->info.write.dummy);
@@ -174,14 +203,12 @@ static void hisfc350_map_iftype(struct hisfc_flash_device *flash)
info->write.iftype = iftype_hw_map[info->write.iftype];
}
/*****************************************************************************/
-static void hisfc350_dma_transfer(struct hisfc_host *host,
- unsigned int spi_start_addr, dma_addr_t dma_buffer,
- unsigned char is_read, unsigned int size, unsigned char cs)
+static void hisfc350_dma_transfer(struct hisfc_host *host, u32 start_addr,
+ dma_addr_t dma_buffer, u8 is_read, u32 size, u8 cs)
{
hisfc_write(HISFC350_BUS_DMA_MEM_SADDR, dma_buffer);
- hisfc_write(HISFC350_BUS_DMA_FLASH_SADDR,
- spi_start_addr);
+ hisfc_write(HISFC350_BUS_DMA_FLASH_SADDR, start_addr);
hisfc_write(HISFC350_BUS_DMA_LEN,
HISFC350_BUS_DMA_LEN_DATA_CNT(size));
@@ -196,85 +223,24 @@ static void hisfc350_dma_transfer(struct hisfc_host *host,
| HISFC350_BUS_DMA_CTRL_CS(cs)
| HISFC350_BUS_DMA_CTRL_START);
- HISFC350_DMA_WAIT_CPU_FINISH(host);
+ hisfc350_wait_dma_cmd_timeout(host);
}
/*****************************************************************************/
-#ifdef HISFCV350_SUPPORT_REG_READ
-static char *hisfc350_reg_read_buf(struct hisfc_host *host,
- struct hisfc_flash_device *flash, unsigned int spi_start_addr,
- unsigned int size, unsigned char *buffer)
-{
- int numread;
- int index = 0;
-
- hisfc_write(HISFC350_CMD_INS, flash->info.read.cmd);
- hisfc_write(HISFC350_CMD_ADDR,
- (spi_start_addr & HISFC350_CMD_ADDR_MASK));
- hisfc_write(HISFC350_CMD_CONFIG,
- HISFC350_CMD_CONFIG_MEM_IF_TYPE(flash->info.read.iftype)
- | HISFC350_CMD_CONFIG_DATA_CNT(size)
- | HISFC350_CMD_CONFIG_RW_READ
- | HISFC350_CMD_CONFIG_DATA_EN
- | HISFC350_CMD_CONFIG_DUMMY_CNT(flash->info.read.dummy)
- | HISFC350_CMD_CONFIG_ADDR_EN
- | HISFC350_CMD_CONFIG_SEL_CS(flash->cs)
- | HISFC350_CMD_CONFIG_START);
-
- HISFC350_CMD_WAIT_CPU_FINISH(host);
-
- memcpy(buffer, host->io_base + HISFC350_CMD_DATABUF0, size);
-
- return buffer;
-}
-/*****************************************************************************/
-static int hisfc350_reg_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
-{
- int num;
- int result = -EIO;
- unsigned char *ptr = buf;
- struct hisfc_host *host = MTD_TO_HOST(mtd);
- struct hisfc_flash_device *flash = host->flash;
-
- mutex_lock(&host->lock);
-
- if (hisfc350_wait_ready(host, flash))
- goto fail;
- /* clk_round_rate(host->clk, flash->info.read.clock); */
-
- while (len > 0) {
- num = len > HISFC350_REG_BUF_SIZE ?
- HISFC350_REG_BUF_SIZE : len;
-
- hisfc350_reg_read_buf(host, flash, from, num, ptr);
- from += num;
- ptr += num;
- len -= num;
- }
- result = 0;
- *retlen = (size_t)(ptr - buf);
-fail:
- mutex_unlock(&host->lock);
- return result;
-}
-#endif /* HISFCV350_SUPPORT_REG_READ */
-/*****************************************************************************/
-
static int hisfc350_dma_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
- int num;
- int result = -EIO;
- unsigned char *ptr = buf;
struct hisfc_flash_device *flash = mtd->priv;
struct hisfc_host *host = flash->priv;
+ u_char *ptr = buf;
+ int result = -EIO;
+ int num;
mutex_lock(&host->lock);
hisfc350_host_select_flash(host, flash);
- if (hisfc350_wait_ready(host, flash))
+ if (hisfc350_wait_flash_ready_timeout(host, flash))
goto fail;
hisfc350_dma_bus_config(host, flash);
@@ -290,8 +256,8 @@ static int hisfc350_dma_read(struct mtd_info *mtd, loff_t from, size_t len,
if (num > len)
num = len;
- hisfc350_dma_transfer(host, from, host->dma_buffer, READ,
- num, flash->cs);
+ hisfc350_dma_transfer(host, from, host->dma_buffer,
+ SFC_DMA_READ, num, flash->cs);
memcpy(ptr, host->buffer, num);
from += num;
ptr += num;
@@ -300,8 +266,8 @@ static int hisfc350_dma_read(struct mtd_info *mtd, loff_t from, size_t len,
while (len) {/* 2) the reset */
num = len > HISFC350_DMA_MAX_SIZE ? HISFC350_DMA_MAX_SIZE : len;
- hisfc350_dma_transfer(host, from, host->dma_buffer, READ,
- num, flash->cs);
+ hisfc350_dma_transfer(host, from, host->dma_buffer,
+ SFC_DMA_READ, num, flash->cs);
memcpy(ptr, host->buffer, num);
ptr += num;
from += num;
@@ -315,7 +281,7 @@ fail:
return result;
}
/*****************************************************************************/
-static int hisfc350_read_id(struct hisfc_host *host, int cs, u8 *id, int len)
+static int hisfc350_read_id(struct hisfc_host *host, u8 cs, u8 *id, int len)
{
hisfc_write(HISFC350_CMD_INS, SPI_CMD_RDID);
hisfc_write(HISFC350_CMD_CONFIG,
@@ -325,7 +291,7 @@ static int hisfc350_read_id(struct hisfc_host *host, int cs, u8 *id, int len)
| HISFC350_CMD_CONFIG_DATA_CNT(len)
| HISFC350_CMD_CONFIG_START);
- HISFC350_CMD_WAIT_CPU_FINISH(host);
+ hisfc350_wait_cmd_timeout(host);
memcpy(id, host->io_base + HISFC350_CMD_DATABUF0, len);
@@ -335,7 +301,7 @@ static int hisfc350_read_id(struct hisfc_host *host, int cs, u8 *id, int len)
static int hisfc350_write_enable(struct hisfc_host *host,
struct hisfc_flash_device *flash)
{
- unsigned int val = 0;
+ u32 val = 0;
hisfc_write(HISFC350_CMD_INS, SPI_CMD_WREN);
@@ -343,7 +309,7 @@ static int hisfc350_write_enable(struct hisfc_host *host,
| HISFC350_CMD_CONFIG_START;
hisfc_write(HISFC350_CMD_CONFIG, val);
- HISFC350_CMD_WAIT_CPU_FINISH(host);
+ hisfc350_wait_cmd_timeout(host);
return 0;
}
@@ -351,7 +317,7 @@ static int hisfc350_write_enable(struct hisfc_host *host,
static int hisfc350_sector_erase(struct hisfc_host *host,
struct hisfc_flash_device *flash, u32 offset)
{
- if (hisfc350_wait_ready(host, flash))
+ if (hisfc350_wait_flash_ready_timeout(host, flash))
return -EBUSY;
hisfc350_write_enable(host, flash);
@@ -368,7 +334,7 @@ static int hisfc350_sector_erase(struct hisfc_host *host,
| HISFC350_CMD_CONFIG_ADDR_EN
| HISFC350_CMD_CONFIG_START);
- HISFC350_CMD_WAIT_CPU_FINISH(host);
+ hisfc350_wait_cmd_timeout(host);
return 0;
}
@@ -386,7 +352,7 @@ static int hisfc350_dma_write(struct mtd_info *mtd, loff_t to, size_t len,
mutex_lock(&host->lock);
hisfc350_host_select_flash(host, flash);
- if (hisfc350_wait_ready(host, flash))
+ if (hisfc350_wait_flash_ready_timeout(host, flash))
goto fail;
hisfc350_write_enable(host, flash);
hisfc350_dma_bus_config(host, flash);
@@ -400,7 +366,7 @@ static int hisfc350_dma_write(struct mtd_info *mtd, loff_t to, size_t len,
num = len;
memcpy(host->buffer, ptr, num);
- hisfc350_dma_transfer(host, to, host->dma_buffer, WRITE,
+ hisfc350_dma_transfer(host, to, host->dma_buffer, SFC_DMA_WRITE,
num, flash->cs);
to += num;
ptr += num;
@@ -412,7 +378,7 @@ static int hisfc350_dma_write(struct mtd_info *mtd, loff_t to, size_t len,
? HISFC350_DMA_MAX_SIZE : len;
memcpy(host->buffer, ptr, num);
- hisfc350_dma_transfer(host, to, host->dma_buffer, WRITE,
+ hisfc350_dma_transfer(host, to, host->dma_buffer, SFC_DMA_WRITE,
num, flash->cs);
to += num;
@@ -430,15 +396,15 @@ static int hisfc350_reg_erase(struct mtd_info *mtd, struct erase_info *instr)
{
struct hisfc_flash_device *flash = mtd->priv;
struct hisfc_host *host = flash->priv;
- uint64_t addr = instr->addr;
- uint64_t len = instr->len;
+ u32 addr = instr->addr;
+ u32 len = instr->len;
int ret;
mutex_lock(&host->lock);
hisfc350_host_select_flash(host, flash);
while (len) {
- ret = hisfc350_sector_erase(host, flash, (u32)addr);
+ ret = hisfc350_sector_erase(host, flash, addr);
if (ret) {
instr->state = MTD_ERASE_FAILED;
mutex_unlock(&host->lock);
@@ -455,8 +421,8 @@ static int hisfc350_reg_erase(struct mtd_info *mtd, struct erase_info *instr)
return 0;
}
/*****************************************************************************/
-static const struct flash_info *__devinit hisfc_flash_probe(
- struct hisfc_host *host, int cs)
+static const struct flash_info *hisfc_flash_probe(struct hisfc_host *host,
+ int cs)
{
int tmp;
u8 id[5];
@@ -495,7 +461,7 @@ static const struct flash_info *__devinit hisfc_flash_probe(
return ERR_PTR(-ENODEV);
}
-static inline void dump_flash_info(struct hisfc_flash_device *flash)
+static void dump_flash_info(struct hisfc_flash_device *flash)
{
struct flash_info *info = &flash->info;
char buf1[20];
@@ -504,8 +470,8 @@ static inline void dump_flash_info(struct hisfc_flash_device *flash)
pr_info("SFC(cs%d): Name:\"%s\" Block:%sB Chip:%sB\n",
flash->cs,
info->name,
- ultohstr(info->erase_size, buf1),
- ultohstr(info->chip_size, buf2));
+ ultohstr(info->sector_size, buf1),
+ ultohstr(info->sector_size * info->nr_sectors, buf2));
pr_info("addr_width:%sB read:%s,0x%02x,%dM\n",
info->addr_width == 3 ? "3" : "4",
@@ -550,9 +516,9 @@ static int hisfc350_setup_flash_device(struct hisfc_host *host, int cs)
*/
flash->mtd.name = DRIVER_NAME;
flash->mtd.type = MTD_NORFLASH;
- flash->mtd.size = info->chip_size;
+ flash->mtd.size = info->sector_size * info->nr_sectors;
flash->mtd.writesize = 1;
- flash->mtd.erasesize = info->erase_size;
+ flash->mtd.erasesize = info->sector_size;
flash->mtd.flags = MTD_CAP_NORFLASH;
flash->mtd.owner = THIS_MODULE;
flash->mtd._erase = hisfc350_reg_erase;
@@ -633,24 +599,18 @@ static int hisfc350_driver_resume(struct platform_device *pdev)
#endif /* CONFIG_PM */
/*****************************************************************************/
#ifdef CONFIG_OF
-static int __devinit hisfc_probe_config_dt(struct platform_device *pdev,
+static int hisfc_probe_config_dt(struct platform_device *pdev,
struct device_node *np)
{
- struct hisfc_host *host = platform_get_drvdata(pdev);
- unsigned int version;
-
if (!np)
return -ENODEV;
/* TODO: get clk here */
- if (!of_property_read_u32(np, "version_reg_offset", &version))
- host->version = version;
-
return 0;
}
#else
-static int __devinit hisfc_probe_config_dt(struct platform_device *pdev,
+static int hisfc_probe_config_dt(struct platform_device *pdev,
struct device_node *np)
{
return -ENOSYS;
@@ -660,12 +620,12 @@ static int __devinit hisfc_probe_config_dt(struct platform_device *pdev,
/*****************************************************************************/
static inline void hisfc_check_version(struct hisfc_host *host)
{
- int version = hisfc_read(host->version);
+ int version = hisfc_read(HISFC350_VERSION);
pr_info("hs-sfc controller version 0x%x\n", version);
}
-static int __devinit hisfc350_driver_probe(struct platform_device *pdev)
+static int hisfc350_driver_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
@@ -713,7 +673,7 @@ static int __devinit hisfc350_driver_probe(struct platform_device *pdev)
host->buffer = dma_alloc_coherent(host->dev, HISFC350_DMA_MAX_SIZE,
&host->dma_buffer, GFP_KERNEL);
if (!host->buffer) {
- pr_err("sfc alloc dma buffer failed.\n");
+ dev_err(host->dev, "sfc alloc dma buffer failed.\n");
goto err_res;
}
hisfc_check_version(host);
@@ -768,7 +728,7 @@ err:
return ret;
}
-static int __devexit hisfc350_driver_remove(struct platform_device *pdev)
+static int hisfc350_driver_remove(struct platform_device *pdev)
{
struct hisfc_host *host = platform_get_drvdata(pdev);
struct hisfc_flash_device *flash;
@@ -819,7 +779,7 @@ static void hisfc350_driver_shutdown(struct platform_device *pdev)
#ifdef CONFIG_OF
static const struct of_device_id sfc_id_table[] = {
- { .compatible = "hs,sfc350" },
+ { .compatible = "hisilicon,sfc350" },
{}
};
MODULE_DEVICE_TABLE(of, sfc_id_table);
@@ -855,6 +815,5 @@ static void __exit hisfc350_module_exit(void)
}
module_exit(hisfc350_module_exit);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("HiC");
+MODULE_LICENSE("GPLv2");
MODULE_DESCRIPTION("Hisilicon Spi Flash Controller V350 Device Driver, Version 1.00");