diff options
Diffstat (limited to 'drivers/mtd/devices/hs_sfc/hisfc350.c')
-rw-r--r-- | drivers/mtd/devices/hs_sfc/hisfc350.c | 249 |
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"); |