/* * SMI (Serial Memory Controller) device driver for Serial NOR Flash on * SPEAr platform * The serial nor interface is largely based on m25p80.c, however the SPI * interface has been replaced by SMI. * * Copyright © 2010 STMicroelectronics. * Ashish Priyadarshi * Shiraz Hashim <[email protected]> * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ #include <linux/clk.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/err.h> #include <linux/errno.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/ioport.h> #include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/param.h> #include <linux/platform_device.h> #include <linux/pm.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/mtd/spear_smi.h> #include <linux/mutex.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/wait.h> #include <linux/of.h> #include <linux/of_address.h> /* SMI clock rate */ #define SMI_MAX_CLOCK_FREQ … /* MAX time out to safely come out of a erase or write busy conditions */ #define SMI_PROBE_TIMEOUT … #define SMI_MAX_TIME_OUT … /* timeout for command completion */ #define SMI_CMD_TIMEOUT … /* registers of smi */ #define SMI_CR1 … #define SMI_CR2 … #define SMI_SR … #define SMI_TR … #define SMI_RR … /* defines for control_reg 1 */ #define BANK_EN … #define DSEL_TIME … #define SW_MODE … #define WB_MODE … #define FAST_MODE … #define HOLD1 … /* defines for control_reg 2 */ #define SEND … #define TFIE … #define WCIE … #define RD_STATUS_REG … #define WE … #define TX_LEN_SHIFT … #define RX_LEN_SHIFT … #define BANK_SHIFT … /* defines for status register */ #define SR_WIP … #define SR_WEL … #define SR_BP0 … #define SR_BP1 … #define SR_BP2 … #define SR_SRWD … #define TFF … #define WCF … #define ERF1 … #define ERF2 … #define WM_SHIFT … /* flash opcodes */ #define OPCODE_RDID … /* Flash Device Ids maintenance section */ /* data structure to maintain flash ids from different vendors */ struct flash_device { … }; #define FLASH_ID(n, es, id, psize, ssize, size) … static struct flash_device flash_devices[] = …; /* Define spear specific structures */ struct spear_snor_flash; /** * struct spear_smi - Structure for SMI Device * * @clk: functional clock * @status: current status register of SMI. * @clk_rate: functional clock rate of SMI (default: SMI_MAX_CLOCK_FREQ) * @lock: lock to prevent parallel access of SMI. * @io_base: base address for registers of SMI. * @pdev: platform device * @cmd_complete: queue to wait for command completion of NOR-flash. * @num_flashes: number of flashes actually present on board. * @flash: separate structure for each Serial NOR-flash attached to SMI. */ struct spear_smi { … }; /** * struct spear_snor_flash - Structure for Serial NOR Flash * * @bank: Bank number(0, 1, 2, 3) for each NOR-flash. * @dev_id: Device ID of NOR-flash. * @lock: lock to manage flash read, write and erase operations * @mtd: MTD info for each NOR-flash. * @num_parts: Total number of partition in each bank of NOR-flash. * @parts: Partition info for each bank of NOR-flash. * @page_size: Page size of NOR-flash. * @base_addr: Base address of NOR-flash. * @erase_cmd: erase command may vary on different flash types * @fast_mode: flash supports read in fast mode */ struct spear_snor_flash { … }; static inline struct spear_snor_flash *get_flash_data(struct mtd_info *mtd) { … } /** * spear_smi_read_sr - Read status register of flash through SMI * @dev: structure of SMI information. * @bank: bank to which flash is connected * * This routine will return the status register of the flash chip present at the * given bank. */ static int spear_smi_read_sr(struct spear_smi *dev, u32 bank) { … } /** * spear_smi_wait_till_ready - wait till flash is ready * @dev: structure of SMI information. * @bank: flash corresponding to this bank * @timeout: timeout for busy wait condition * * This routine checks for WIP (write in progress) bit in Status register * If successful the routine returns 0 else -EBUSY */ static int spear_smi_wait_till_ready(struct spear_smi *dev, u32 bank, unsigned long timeout) { … } /** * spear_smi_int_handler - SMI Interrupt Handler. * @irq: irq number * @dev_id: structure of SMI device, embedded in dev_id. * * The handler clears all interrupt conditions and records the status in * dev->status which is used by the driver later. */ static irqreturn_t spear_smi_int_handler(int irq, void *dev_id) { … } /** * spear_smi_hw_init - initializes the smi controller. * @dev: structure of smi device * * this routine initializes the smi controller wit the default values */ static void spear_smi_hw_init(struct spear_smi *dev) { … } /** * get_flash_index - match chip id from a flash list. * @flash_id: a valid nor flash chip id obtained from board. * * try to validate the chip id by matching from a list, if not found then simply * returns negative. In case of success returns index in to the flash devices * array. */ static int get_flash_index(u32 flash_id) { … } /** * spear_smi_write_enable - Enable the flash to do write operation * @dev: structure of SMI device * @bank: enable write for flash connected to this bank * * Set write enable latch with Write Enable command. * Returns 0 on success. */ static int spear_smi_write_enable(struct spear_smi *dev, u32 bank) { … } static inline u32 get_sector_erase_cmd(struct spear_snor_flash *flash, u32 offset) { … } /** * spear_smi_erase_sector - erase one sector of flash * @dev: structure of SMI information * @command: erase command to be send * @bank: bank to which this command needs to be send * @bytes: size of command * * Erase one sector of flash memory at offset ``offset'' which is any * address within the sector which should be erased. * Returns 0 if successful, non-zero otherwise. */ static int spear_smi_erase_sector(struct spear_smi *dev, u32 bank, u32 command, u32 bytes) { … } /** * spear_mtd_erase - perform flash erase operation as requested by user * @mtd: Provides the memory characteristics * @e_info: Provides the erase information * * Erase an address range on the flash chip. The address range may extend * one or more erase sectors. Return an error is there is a problem erasing. */ static int spear_mtd_erase(struct mtd_info *mtd, struct erase_info *e_info) { … } /** * spear_mtd_read - performs flash read operation as requested by the user * @mtd: MTD information of the memory bank * @from: Address from which to start read * @len: Number of bytes to be read * @retlen: Fills the Number of bytes actually read * @buf: Fills this after reading * * Read an address range from the flash chip. The address range * may be any size provided it is within the physical boundaries. * Returns 0 on success, non zero otherwise */ static int spear_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u8 *buf) { … } /* * The purpose of this function is to ensure a memcpy_toio() with byte writes * only. Its structure is inspired from the ARM implementation of _memcpy_toio() * which also does single byte writes but cannot be used here as this is just an * implementation detail and not part of the API. Not mentioning the comment * stating that _memcpy_toio() should be optimized. */ static void spear_smi_memcpy_toio_b(volatile void __iomem *dest, const void *src, size_t len) { … } static inline int spear_smi_cpy_toio(struct spear_smi *dev, u32 bank, void __iomem *dest, const void *src, size_t len) { … } /** * spear_mtd_write - performs write operation as requested by the user. * @mtd: MTD information of the memory bank. * @to: Address to write. * @len: Number of bytes to be written. * @retlen: Number of bytes actually wrote. * @buf: Buffer from which the data to be taken. * * Write an address range to the flash chip. Data must be written in * flash_page_size chunks. The address range may be any size provided * it is within the physical boundaries. * Returns 0 on success, non zero otherwise */ static int spear_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u8 *buf) { … } /** * spear_smi_probe_flash - Detects the NOR Flash chip. * @dev: structure of SMI information. * @bank: bank on which flash must be probed * * This routine will check whether there exists a flash chip on a given memory * bank ID. * Return index of the probed flash in flash devices structure */ static int spear_smi_probe_flash(struct spear_smi *dev, u32 bank) { … } #ifdef CONFIG_OF static int spear_smi_probe_config_dt(struct platform_device *pdev, struct device_node *np) { … } #else static int spear_smi_probe_config_dt(struct platform_device *pdev, struct device_node *np) { return -ENOSYS; } #endif static int spear_smi_setup_banks(struct platform_device *pdev, u32 bank, struct device_node *np) { … } /** * spear_smi_probe - Entry routine * @pdev: platform device structure * * This is the first routine which gets invoked during booting and does all * initialization/allocation work. The routine looks for available memory banks, * and do proper init for any found one. * Returns 0 on success, non zero otherwise */ static int spear_smi_probe(struct platform_device *pdev) { … } /** * spear_smi_remove - Exit routine * @pdev: platform device structure * * free all allocations and delete the partitions. */ static void spear_smi_remove(struct platform_device *pdev) { … } #ifdef CONFIG_PM_SLEEP static int spear_smi_suspend(struct device *dev) { … } static int spear_smi_resume(struct device *dev) { … } #endif static SIMPLE_DEV_PM_OPS(spear_smi_pm_ops, spear_smi_suspend, spear_smi_resume); #ifdef CONFIG_OF static const struct of_device_id spear_smi_id_table[] = …; MODULE_DEVICE_TABLE(of, spear_smi_id_table); #endif static struct platform_driver spear_smi_driver = …; module_platform_driver(…) …; MODULE_LICENSE(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …;