Merge tag 'for-linus-3.4' of git://git.infradead.org/mtd-2.6
Pull MTD changes from David Woodhouse: - Artem's cleanup of the MTD API continues apace. - Fixes and improvements for ST FSMC and SuperH FLCTL NAND, amongst others. - More work on DiskOnChip G3, new driver for DiskOnChip G4. - Clean up debug/warning printks in JFFS2 to use pr_<level>. Fix up various trivial conflicts, largely due to changes in calling conventions for things like dmaengine_prep_slave_sg() (new inline wrapper to hide new parameter, clashing with rewrite of previously last parameter that used to be an 'append' flag, and is now a bitmap of 'unsigned long flags'). (Also some header file fallout - like so many merges this merge window - and silly conflicts with sparse fixes) * tag 'for-linus-3.4' of git://git.infradead.org/mtd-2.6: (120 commits) mtd: docg3 add protection against concurrency mtd: docg3 refactor cascade floors structure mtd: docg3 increase write/erase timeout mtd: docg3 fix inbound calculations mtd: nand: gpmi: fix function annotations mtd: phram: fix section mismatch for phram_setup mtd: unify initialization of erase_info->fail_addr mtd: support ONFI multi lun NAND mtd: sm_ftl: fix typo in major number. mtd: add device-tree support to spear_smi mtd: spear_smi: Remove default partition information from driver mtd: Add device-tree support to fsmc_nand mtd: fix section mismatch for doc_probe_device mtd: nand/fsmc: Remove sparse warnings and errors mtd: nand/fsmc: Add DMA support mtd: nand/fsmc: Access the NAND device word by word whenever possible mtd: nand/fsmc: Use dev_err to report error scenario mtd: nand/fsmc: Use devm routines mtd: nand/fsmc: Modify fsmc driver to accept nand timing parameters via platform mtd: fsmc_nand: add pm callbacks to support hibernation ...
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __MACH_MXS_DMA_H__
|
||||
#define __MACH_MXS_DMA_H__
|
||||
|
||||
#include <linux/dmaengine.h>
|
||||
|
||||
struct mxs_dma_data {
|
||||
int chan_irq;
|
||||
};
|
||||
|
||||
static inline int mxs_dma_is_apbh(struct dma_chan *chan)
|
||||
{
|
||||
return !strcmp(dev_name(chan->device->dev), "mxs-dma-apbh");
|
||||
}
|
||||
|
||||
static inline int mxs_dma_is_apbx(struct dma_chan *chan)
|
||||
{
|
||||
return !strcmp(dev_name(chan->device->dev), "mxs-dma-apbx");
|
||||
}
|
||||
|
||||
#endif /* __MACH_MXS_DMA_H__ */
|
||||
@@ -112,6 +112,11 @@ struct nand_bbt_descr {
|
||||
#define NAND_BBT_USE_FLASH 0x00020000
|
||||
/* Do not store flash based bad block table in OOB area; store it in-band */
|
||||
#define NAND_BBT_NO_OOB 0x00040000
|
||||
/*
|
||||
* Do not write new bad block markers to OOB; useful, e.g., when ECC covers
|
||||
* entire spare area. Must be used with NAND_BBT_USE_FLASH.
|
||||
*/
|
||||
#define NAND_BBT_NO_OOB_BBM 0x00080000
|
||||
|
||||
/*
|
||||
* Flag set by nand_create_default_bbt_descr(), marking that the nand_bbt_descr
|
||||
|
||||
@@ -47,6 +47,7 @@ struct mtd_blktrans_dev {
|
||||
struct request_queue *rq;
|
||||
spinlock_t queue_lock;
|
||||
void *priv;
|
||||
fmode_t file_mode;
|
||||
};
|
||||
|
||||
struct mtd_blktrans_ops {
|
||||
|
||||
+89
-76
@@ -26,95 +26,83 @@
|
||||
#define FSMC_NAND_BW8 1
|
||||
#define FSMC_NAND_BW16 2
|
||||
|
||||
/*
|
||||
* The placement of the Command Latch Enable (CLE) and
|
||||
* Address Latch Enable (ALE) is twisted around in the
|
||||
* SPEAR310 implementation.
|
||||
*/
|
||||
#if defined(CONFIG_MACH_SPEAR310)
|
||||
#define PLAT_NAND_CLE (1 << 17)
|
||||
#define PLAT_NAND_ALE (1 << 16)
|
||||
#else
|
||||
#define PLAT_NAND_CLE (1 << 16)
|
||||
#define PLAT_NAND_ALE (1 << 17)
|
||||
#endif
|
||||
|
||||
#define FSMC_MAX_NOR_BANKS 4
|
||||
#define FSMC_MAX_NAND_BANKS 4
|
||||
|
||||
#define FSMC_FLASH_WIDTH8 1
|
||||
#define FSMC_FLASH_WIDTH16 2
|
||||
|
||||
struct fsmc_nor_bank_regs {
|
||||
uint32_t ctrl;
|
||||
uint32_t ctrl_tim;
|
||||
};
|
||||
/* fsmc controller registers for NOR flash */
|
||||
#define CTRL 0x0
|
||||
/* ctrl register definitions */
|
||||
#define BANK_ENABLE (1 << 0)
|
||||
#define MUXED (1 << 1)
|
||||
#define NOR_DEV (2 << 2)
|
||||
#define WIDTH_8 (0 << 4)
|
||||
#define WIDTH_16 (1 << 4)
|
||||
#define RSTPWRDWN (1 << 6)
|
||||
#define WPROT (1 << 7)
|
||||
#define WRT_ENABLE (1 << 12)
|
||||
#define WAIT_ENB (1 << 13)
|
||||
|
||||
/* ctrl register definitions */
|
||||
#define BANK_ENABLE (1 << 0)
|
||||
#define MUXED (1 << 1)
|
||||
#define NOR_DEV (2 << 2)
|
||||
#define WIDTH_8 (0 << 4)
|
||||
#define WIDTH_16 (1 << 4)
|
||||
#define RSTPWRDWN (1 << 6)
|
||||
#define WPROT (1 << 7)
|
||||
#define WRT_ENABLE (1 << 12)
|
||||
#define WAIT_ENB (1 << 13)
|
||||
|
||||
/* ctrl_tim register definitions */
|
||||
|
||||
struct fsmc_nand_bank_regs {
|
||||
uint32_t pc;
|
||||
uint32_t sts;
|
||||
uint32_t comm;
|
||||
uint32_t attrib;
|
||||
uint32_t ioata;
|
||||
uint32_t ecc1;
|
||||
uint32_t ecc2;
|
||||
uint32_t ecc3;
|
||||
};
|
||||
#define CTRL_TIM 0x4
|
||||
/* ctrl_tim register definitions */
|
||||
|
||||
#define FSMC_NOR_BANK_SZ 0x8
|
||||
#define FSMC_NOR_REG_SIZE 0x40
|
||||
|
||||
struct fsmc_regs {
|
||||
struct fsmc_nor_bank_regs nor_bank_regs[FSMC_MAX_NOR_BANKS];
|
||||
uint8_t reserved_1[0x40 - 0x20];
|
||||
struct fsmc_nand_bank_regs bank_regs[FSMC_MAX_NAND_BANKS];
|
||||
uint8_t reserved_2[0xfe0 - 0xc0];
|
||||
uint32_t peripid0; /* 0xfe0 */
|
||||
uint32_t peripid1; /* 0xfe4 */
|
||||
uint32_t peripid2; /* 0xfe8 */
|
||||
uint32_t peripid3; /* 0xfec */
|
||||
uint32_t pcellid0; /* 0xff0 */
|
||||
uint32_t pcellid1; /* 0xff4 */
|
||||
uint32_t pcellid2; /* 0xff8 */
|
||||
uint32_t pcellid3; /* 0xffc */
|
||||
};
|
||||
#define FSMC_NOR_REG(base, bank, reg) (base + \
|
||||
FSMC_NOR_BANK_SZ * (bank) + \
|
||||
reg)
|
||||
|
||||
/* fsmc controller registers for NAND flash */
|
||||
#define PC 0x00
|
||||
/* pc register definitions */
|
||||
#define FSMC_RESET (1 << 0)
|
||||
#define FSMC_WAITON (1 << 1)
|
||||
#define FSMC_ENABLE (1 << 2)
|
||||
#define FSMC_DEVTYPE_NAND (1 << 3)
|
||||
#define FSMC_DEVWID_8 (0 << 4)
|
||||
#define FSMC_DEVWID_16 (1 << 4)
|
||||
#define FSMC_ECCEN (1 << 6)
|
||||
#define FSMC_ECCPLEN_512 (0 << 7)
|
||||
#define FSMC_ECCPLEN_256 (1 << 7)
|
||||
#define FSMC_TCLR_1 (1)
|
||||
#define FSMC_TCLR_SHIFT (9)
|
||||
#define FSMC_TCLR_MASK (0xF)
|
||||
#define FSMC_TAR_1 (1)
|
||||
#define FSMC_TAR_SHIFT (13)
|
||||
#define FSMC_TAR_MASK (0xF)
|
||||
#define STS 0x04
|
||||
/* sts register definitions */
|
||||
#define FSMC_CODE_RDY (1 << 15)
|
||||
#define COMM 0x08
|
||||
/* comm register definitions */
|
||||
#define FSMC_TSET_0 0
|
||||
#define FSMC_TSET_SHIFT 0
|
||||
#define FSMC_TSET_MASK 0xFF
|
||||
#define FSMC_TWAIT_6 6
|
||||
#define FSMC_TWAIT_SHIFT 8
|
||||
#define FSMC_TWAIT_MASK 0xFF
|
||||
#define FSMC_THOLD_4 4
|
||||
#define FSMC_THOLD_SHIFT 16
|
||||
#define FSMC_THOLD_MASK 0xFF
|
||||
#define FSMC_THIZ_1 1
|
||||
#define FSMC_THIZ_SHIFT 24
|
||||
#define FSMC_THIZ_MASK 0xFF
|
||||
#define ATTRIB 0x0C
|
||||
#define IOATA 0x10
|
||||
#define ECC1 0x14
|
||||
#define ECC2 0x18
|
||||
#define ECC3 0x1C
|
||||
#define FSMC_NAND_BANK_SZ 0x20
|
||||
|
||||
#define FSMC_NAND_REG(base, bank, reg) (base + FSMC_NOR_REG_SIZE + \
|
||||
(FSMC_NAND_BANK_SZ * (bank)) + \
|
||||
reg)
|
||||
|
||||
#define FSMC_BUSY_WAIT_TIMEOUT (1 * HZ)
|
||||
|
||||
/* pc register definitions */
|
||||
#define FSMC_RESET (1 << 0)
|
||||
#define FSMC_WAITON (1 << 1)
|
||||
#define FSMC_ENABLE (1 << 2)
|
||||
#define FSMC_DEVTYPE_NAND (1 << 3)
|
||||
#define FSMC_DEVWID_8 (0 << 4)
|
||||
#define FSMC_DEVWID_16 (1 << 4)
|
||||
#define FSMC_ECCEN (1 << 6)
|
||||
#define FSMC_ECCPLEN_512 (0 << 7)
|
||||
#define FSMC_ECCPLEN_256 (1 << 7)
|
||||
#define FSMC_TCLR_1 (1 << 9)
|
||||
#define FSMC_TAR_1 (1 << 13)
|
||||
|
||||
/* sts register definitions */
|
||||
#define FSMC_CODE_RDY (1 << 15)
|
||||
|
||||
/* comm register definitions */
|
||||
#define FSMC_TSET_0 (0 << 0)
|
||||
#define FSMC_TWAIT_6 (6 << 8)
|
||||
#define FSMC_THOLD_4 (4 << 16)
|
||||
#define FSMC_THIZ_1 (1 << 24)
|
||||
|
||||
/*
|
||||
* There are 13 bytes of ecc for every 512 byte block in FSMC version 8
|
||||
* and it has to be read consecutively and immediately after the 512
|
||||
@@ -133,6 +121,20 @@ struct fsmc_eccplace {
|
||||
struct fsmc_nand_eccplace eccplace[MAX_ECCPLACE_ENTRIES];
|
||||
};
|
||||
|
||||
struct fsmc_nand_timings {
|
||||
uint8_t tclr;
|
||||
uint8_t tar;
|
||||
uint8_t thiz;
|
||||
uint8_t thold;
|
||||
uint8_t twait;
|
||||
uint8_t tset;
|
||||
};
|
||||
|
||||
enum access_mode {
|
||||
USE_DMA_ACCESS = 1,
|
||||
USE_WORD_ACCESS,
|
||||
};
|
||||
|
||||
/**
|
||||
* fsmc_nand_platform_data - platform specific NAND controller config
|
||||
* @partitions: partition table for the platform, use a default fallback
|
||||
@@ -146,12 +148,23 @@ struct fsmc_eccplace {
|
||||
* this may be set to NULL
|
||||
*/
|
||||
struct fsmc_nand_platform_data {
|
||||
struct fsmc_nand_timings *nand_timings;
|
||||
struct mtd_partition *partitions;
|
||||
unsigned int nr_partitions;
|
||||
unsigned int options;
|
||||
unsigned int width;
|
||||
unsigned int bank;
|
||||
|
||||
/* CLE, ALE offsets */
|
||||
unsigned int cle_off;
|
||||
unsigned int ale_off;
|
||||
enum access_mode mode;
|
||||
|
||||
void (*select_bank)(uint32_t bank, uint32_t busw);
|
||||
|
||||
/* priv structures for dma accesses */
|
||||
void *read_dma_priv;
|
||||
void *write_dma_priv;
|
||||
};
|
||||
|
||||
extern int __init fsmc_nor_init(struct platform_device *pdev,
|
||||
|
||||
+84
-220
@@ -164,6 +164,9 @@ struct mtd_info {
|
||||
/* ECC layout structure pointer - read only! */
|
||||
struct nand_ecclayout *ecclayout;
|
||||
|
||||
/* max number of correctible bit errors per writesize */
|
||||
unsigned int ecc_strength;
|
||||
|
||||
/* Data for variable erase regions. If numeraseregions is zero,
|
||||
* it means that the whole device has erasesize as given above.
|
||||
*/
|
||||
@@ -174,52 +177,52 @@ struct mtd_info {
|
||||
* Do not call via these pointers, use corresponding mtd_*()
|
||||
* wrappers instead.
|
||||
*/
|
||||
int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
|
||||
int (*point) (struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, void **virt, resource_size_t *phys);
|
||||
void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
|
||||
unsigned long (*get_unmapped_area) (struct mtd_info *mtd,
|
||||
unsigned long len,
|
||||
unsigned long offset,
|
||||
unsigned long flags);
|
||||
int (*read) (struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf);
|
||||
int (*write) (struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, const u_char *buf);
|
||||
int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, const u_char *buf);
|
||||
int (*read_oob) (struct mtd_info *mtd, loff_t from,
|
||||
struct mtd_oob_ops *ops);
|
||||
int (*write_oob) (struct mtd_info *mtd, loff_t to,
|
||||
int (*_erase) (struct mtd_info *mtd, struct erase_info *instr);
|
||||
int (*_point) (struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, void **virt, resource_size_t *phys);
|
||||
int (*_unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
|
||||
unsigned long (*_get_unmapped_area) (struct mtd_info *mtd,
|
||||
unsigned long len,
|
||||
unsigned long offset,
|
||||
unsigned long flags);
|
||||
int (*_read) (struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf);
|
||||
int (*_write) (struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, const u_char *buf);
|
||||
int (*_panic_write) (struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, const u_char *buf);
|
||||
int (*_read_oob) (struct mtd_info *mtd, loff_t from,
|
||||
struct mtd_oob_ops *ops);
|
||||
int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf,
|
||||
size_t len);
|
||||
int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from,
|
||||
size_t len, size_t *retlen, u_char *buf);
|
||||
int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf,
|
||||
size_t len);
|
||||
int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from,
|
||||
size_t len, size_t *retlen, u_char *buf);
|
||||
int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, u_char *buf);
|
||||
int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from,
|
||||
size_t len);
|
||||
int (*writev) (struct mtd_info *mtd, const struct kvec *vecs,
|
||||
int (*_write_oob) (struct mtd_info *mtd, loff_t to,
|
||||
struct mtd_oob_ops *ops);
|
||||
int (*_get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf,
|
||||
size_t len);
|
||||
int (*_read_fact_prot_reg) (struct mtd_info *mtd, loff_t from,
|
||||
size_t len, size_t *retlen, u_char *buf);
|
||||
int (*_get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf,
|
||||
size_t len);
|
||||
int (*_read_user_prot_reg) (struct mtd_info *mtd, loff_t from,
|
||||
size_t len, size_t *retlen, u_char *buf);
|
||||
int (*_write_user_prot_reg) (struct mtd_info *mtd, loff_t to,
|
||||
size_t len, size_t *retlen, u_char *buf);
|
||||
int (*_lock_user_prot_reg) (struct mtd_info *mtd, loff_t from,
|
||||
size_t len);
|
||||
int (*_writev) (struct mtd_info *mtd, const struct kvec *vecs,
|
||||
unsigned long count, loff_t to, size_t *retlen);
|
||||
void (*sync) (struct mtd_info *mtd);
|
||||
int (*lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
int (*unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
int (*is_locked) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
|
||||
int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);
|
||||
int (*suspend) (struct mtd_info *mtd);
|
||||
void (*resume) (struct mtd_info *mtd);
|
||||
void (*_sync) (struct mtd_info *mtd);
|
||||
int (*_lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
int (*_unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
int (*_is_locked) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs);
|
||||
int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);
|
||||
int (*_suspend) (struct mtd_info *mtd);
|
||||
void (*_resume) (struct mtd_info *mtd);
|
||||
/*
|
||||
* If the driver is something smart, like UBI, it may need to maintain
|
||||
* its own reference counting. The below functions are only for driver.
|
||||
*/
|
||||
int (*get_device) (struct mtd_info *mtd);
|
||||
void (*put_device) (struct mtd_info *mtd);
|
||||
int (*_get_device) (struct mtd_info *mtd);
|
||||
void (*_put_device) (struct mtd_info *mtd);
|
||||
|
||||
/* Backing device capabilities for this device
|
||||
* - provides mmap capabilities
|
||||
@@ -240,214 +243,75 @@ struct mtd_info {
|
||||
int usecount;
|
||||
};
|
||||
|
||||
/*
|
||||
* Erase is an asynchronous operation. Device drivers are supposed
|
||||
* to call instr->callback() whenever the operation completes, even
|
||||
* if it completes with a failure.
|
||||
* Callers are supposed to pass a callback function and wait for it
|
||||
* to be called before writing to the block.
|
||||
*/
|
||||
static inline int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
{
|
||||
return mtd->erase(mtd, instr);
|
||||
}
|
||||
|
||||
/*
|
||||
* This stuff for eXecute-In-Place. phys is optional and may be set to NULL.
|
||||
*/
|
||||
static inline int mtd_point(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, void **virt, resource_size_t *phys)
|
||||
{
|
||||
*retlen = 0;
|
||||
if (!mtd->point)
|
||||
return -EOPNOTSUPP;
|
||||
return mtd->point(mtd, from, len, retlen, virt, phys);
|
||||
}
|
||||
|
||||
/* We probably shouldn't allow XIP if the unpoint isn't a NULL */
|
||||
static inline void mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
|
||||
{
|
||||
return mtd->unpoint(mtd, from, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow NOMMU mmap() to directly map the device (if not NULL)
|
||||
* - return the address to which the offset maps
|
||||
* - return -ENOSYS to indicate refusal to do the mapping
|
||||
*/
|
||||
static inline unsigned long mtd_get_unmapped_area(struct mtd_info *mtd,
|
||||
unsigned long len,
|
||||
unsigned long offset,
|
||||
unsigned long flags)
|
||||
{
|
||||
if (!mtd->get_unmapped_area)
|
||||
return -EOPNOTSUPP;
|
||||
return mtd->get_unmapped_area(mtd, len, offset, flags);
|
||||
}
|
||||
|
||||
static inline int mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf)
|
||||
{
|
||||
return mtd->read(mtd, from, len, retlen, buf);
|
||||
}
|
||||
|
||||
static inline int mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, const u_char *buf)
|
||||
{
|
||||
*retlen = 0;
|
||||
if (!mtd->write)
|
||||
return -EROFS;
|
||||
return mtd->write(mtd, to, len, retlen, buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* In blackbox flight recorder like scenarios we want to make successful writes
|
||||
* in interrupt context. panic_write() is only intended to be called when its
|
||||
* known the kernel is about to panic and we need the write to succeed. Since
|
||||
* the kernel is not going to be running for much longer, this function can
|
||||
* break locks and delay to ensure the write succeeds (but not sleep).
|
||||
*/
|
||||
static inline int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, const u_char *buf)
|
||||
{
|
||||
*retlen = 0;
|
||||
if (!mtd->panic_write)
|
||||
return -EOPNOTSUPP;
|
||||
return mtd->panic_write(mtd, to, len, retlen, buf);
|
||||
}
|
||||
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
|
||||
int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
|
||||
void **virt, resource_size_t *phys);
|
||||
int mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len);
|
||||
unsigned long mtd_get_unmapped_area(struct mtd_info *mtd, unsigned long len,
|
||||
unsigned long offset, unsigned long flags);
|
||||
int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
|
||||
u_char *buf);
|
||||
int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
|
||||
const u_char *buf);
|
||||
int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
|
||||
const u_char *buf);
|
||||
|
||||
static inline int mtd_read_oob(struct mtd_info *mtd, loff_t from,
|
||||
struct mtd_oob_ops *ops)
|
||||
{
|
||||
ops->retlen = ops->oobretlen = 0;
|
||||
if (!mtd->read_oob)
|
||||
if (!mtd->_read_oob)
|
||||
return -EOPNOTSUPP;
|
||||
return mtd->read_oob(mtd, from, ops);
|
||||
return mtd->_read_oob(mtd, from, ops);
|
||||
}
|
||||
|
||||
static inline int mtd_write_oob(struct mtd_info *mtd, loff_t to,
|
||||
struct mtd_oob_ops *ops)
|
||||
{
|
||||
ops->retlen = ops->oobretlen = 0;
|
||||
if (!mtd->write_oob)
|
||||
if (!mtd->_write_oob)
|
||||
return -EOPNOTSUPP;
|
||||
return mtd->write_oob(mtd, to, ops);
|
||||
if (!(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
return mtd->_write_oob(mtd, to, ops);
|
||||
}
|
||||
|
||||
/*
|
||||
* Method to access the protection register area, present in some flash
|
||||
* devices. The user data is one time programmable but the factory data is read
|
||||
* only.
|
||||
*/
|
||||
static inline int mtd_get_fact_prot_info(struct mtd_info *mtd,
|
||||
struct otp_info *buf, size_t len)
|
||||
{
|
||||
if (!mtd->get_fact_prot_info)
|
||||
return -EOPNOTSUPP;
|
||||
return mtd->get_fact_prot_info(mtd, buf, len);
|
||||
}
|
||||
|
||||
static inline int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
|
||||
size_t len, size_t *retlen,
|
||||
u_char *buf)
|
||||
{
|
||||
*retlen = 0;
|
||||
if (!mtd->read_fact_prot_reg)
|
||||
return -EOPNOTSUPP;
|
||||
return mtd->read_fact_prot_reg(mtd, from, len, retlen, buf);
|
||||
}
|
||||
|
||||
static inline int mtd_get_user_prot_info(struct mtd_info *mtd,
|
||||
struct otp_info *buf,
|
||||
size_t len)
|
||||
{
|
||||
if (!mtd->get_user_prot_info)
|
||||
return -EOPNOTSUPP;
|
||||
return mtd->get_user_prot_info(mtd, buf, len);
|
||||
}
|
||||
|
||||
static inline int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
|
||||
size_t len, size_t *retlen,
|
||||
u_char *buf)
|
||||
{
|
||||
*retlen = 0;
|
||||
if (!mtd->read_user_prot_reg)
|
||||
return -EOPNOTSUPP;
|
||||
return mtd->read_user_prot_reg(mtd, from, len, retlen, buf);
|
||||
}
|
||||
|
||||
static inline int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to,
|
||||
size_t len, size_t *retlen,
|
||||
u_char *buf)
|
||||
{
|
||||
*retlen = 0;
|
||||
if (!mtd->write_user_prot_reg)
|
||||
return -EOPNOTSUPP;
|
||||
return mtd->write_user_prot_reg(mtd, to, len, retlen, buf);
|
||||
}
|
||||
|
||||
static inline int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
|
||||
size_t len)
|
||||
{
|
||||
if (!mtd->lock_user_prot_reg)
|
||||
return -EOPNOTSUPP;
|
||||
return mtd->lock_user_prot_reg(mtd, from, len);
|
||||
}
|
||||
int mtd_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
|
||||
size_t len);
|
||||
int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf);
|
||||
int mtd_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf,
|
||||
size_t len);
|
||||
int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf);
|
||||
int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, u_char *buf);
|
||||
int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len);
|
||||
|
||||
int mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
|
||||
unsigned long count, loff_t to, size_t *retlen);
|
||||
|
||||
static inline void mtd_sync(struct mtd_info *mtd)
|
||||
{
|
||||
if (mtd->sync)
|
||||
mtd->sync(mtd);
|
||||
if (mtd->_sync)
|
||||
mtd->_sync(mtd);
|
||||
}
|
||||
|
||||
/* Chip-supported device locking */
|
||||
static inline int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
{
|
||||
if (!mtd->lock)
|
||||
return -EOPNOTSUPP;
|
||||
return mtd->lock(mtd, ofs, len);
|
||||
}
|
||||
|
||||
static inline int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
{
|
||||
if (!mtd->unlock)
|
||||
return -EOPNOTSUPP;
|
||||
return mtd->unlock(mtd, ofs, len);
|
||||
}
|
||||
|
||||
static inline int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
{
|
||||
if (!mtd->is_locked)
|
||||
return -EOPNOTSUPP;
|
||||
return mtd->is_locked(mtd, ofs, len);
|
||||
}
|
||||
int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||
int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs);
|
||||
int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs);
|
||||
|
||||
static inline int mtd_suspend(struct mtd_info *mtd)
|
||||
{
|
||||
return mtd->suspend ? mtd->suspend(mtd) : 0;
|
||||
return mtd->_suspend ? mtd->_suspend(mtd) : 0;
|
||||
}
|
||||
|
||||
static inline void mtd_resume(struct mtd_info *mtd)
|
||||
{
|
||||
if (mtd->resume)
|
||||
mtd->resume(mtd);
|
||||
}
|
||||
|
||||
static inline int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
if (!mtd->block_isbad)
|
||||
return 0;
|
||||
return mtd->block_isbad(mtd, ofs);
|
||||
}
|
||||
|
||||
static inline int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
if (!mtd->block_markbad)
|
||||
return -EOPNOTSUPP;
|
||||
return mtd->block_markbad(mtd, ofs);
|
||||
if (mtd->_resume)
|
||||
mtd->_resume(mtd);
|
||||
}
|
||||
|
||||
static inline uint32_t mtd_div_by_eb(uint64_t sz, struct mtd_info *mtd)
|
||||
@@ -482,12 +346,12 @@ static inline uint32_t mtd_mod_by_ws(uint64_t sz, struct mtd_info *mtd)
|
||||
|
||||
static inline int mtd_has_oob(const struct mtd_info *mtd)
|
||||
{
|
||||
return mtd->read_oob && mtd->write_oob;
|
||||
return mtd->_read_oob && mtd->_write_oob;
|
||||
}
|
||||
|
||||
static inline int mtd_can_have_bb(const struct mtd_info *mtd)
|
||||
{
|
||||
return !!mtd->block_isbad;
|
||||
return !!mtd->_block_isbad;
|
||||
}
|
||||
|
||||
/* Kernel-side ioctl definitions */
|
||||
|
||||
@@ -324,6 +324,7 @@ struct nand_hw_control {
|
||||
* @steps: number of ECC steps per page
|
||||
* @size: data bytes per ECC step
|
||||
* @bytes: ECC bytes per step
|
||||
* @strength: max number of correctible bits per ECC step
|
||||
* @total: total number of ECC bytes per page
|
||||
* @prepad: padding information for syndrome based ECC generators
|
||||
* @postpad: padding information for syndrome based ECC generators
|
||||
@@ -351,6 +352,7 @@ struct nand_ecc_ctrl {
|
||||
int size;
|
||||
int bytes;
|
||||
int total;
|
||||
int strength;
|
||||
int prepad;
|
||||
int postpad;
|
||||
struct nand_ecclayout *layout;
|
||||
@@ -448,8 +450,9 @@ struct nand_buffers {
|
||||
* will be copied to the appropriate nand_bbt_descr's.
|
||||
* @badblockpos: [INTERN] position of the bad block marker in the oob
|
||||
* area.
|
||||
* @badblockbits: [INTERN] number of bits to left-shift the bad block
|
||||
* number
|
||||
* @badblockbits: [INTERN] minimum number of set bits in a good block's
|
||||
* bad block marker position; i.e., BBM == 11110111b is
|
||||
* not bad when badblockbits == 7
|
||||
* @cellinfo: [INTERN] MLC/multichip data from chip ident
|
||||
* @numchips: [INTERN] number of physical chips
|
||||
* @chipsize: [INTERN] the size of one chip for multichip arrays
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* PMC551 PCI Mezzanine Ram Device
|
||||
*
|
||||
* Author:
|
||||
* Mark Ferrell
|
||||
* Copyright 1999,2000 Nortel Networks
|
||||
*
|
||||
* License:
|
||||
* As part of this driver was derrived from the slram.c driver it falls
|
||||
* under the same license, which is GNU General Public License v2
|
||||
*/
|
||||
|
||||
#ifndef __MTD_PMC551_H__
|
||||
#define __MTD_PMC551_H__
|
||||
|
||||
#include <linux/mtd/mtd.h>
|
||||
|
||||
#define PMC551_VERSION \
|
||||
"Ramix PMC551 PCI Mezzanine Ram Driver. (C) 1999,2000 Nortel Networks.\n"
|
||||
|
||||
/*
|
||||
* Our personal and private information
|
||||
*/
|
||||
struct mypriv {
|
||||
struct pci_dev *dev;
|
||||
u_char *start;
|
||||
u32 base_map0;
|
||||
u32 curr_map0;
|
||||
u32 asize;
|
||||
struct mtd_info *nextpmc551;
|
||||
};
|
||||
|
||||
/*
|
||||
* Function Prototypes
|
||||
*/
|
||||
static int pmc551_erase(struct mtd_info *, struct erase_info *);
|
||||
static void pmc551_unpoint(struct mtd_info *, loff_t, size_t);
|
||||
static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, void **virt, resource_size_t *phys);
|
||||
static int pmc551_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
|
||||
static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
|
||||
|
||||
|
||||
/*
|
||||
* Define the PCI ID's if the kernel doesn't define them for us
|
||||
*/
|
||||
#ifndef PCI_VENDOR_ID_V3_SEMI
|
||||
#define PCI_VENDOR_ID_V3_SEMI 0x11b0
|
||||
#endif
|
||||
|
||||
#ifndef PCI_DEVICE_ID_V3_SEMI_V370PDC
|
||||
#define PCI_DEVICE_ID_V3_SEMI_V370PDC 0x0200
|
||||
#endif
|
||||
|
||||
|
||||
#define PMC551_PCI_MEM_MAP0 0x50
|
||||
#define PMC551_PCI_MEM_MAP1 0x54
|
||||
#define PMC551_PCI_MEM_MAP_MAP_ADDR_MASK 0x3ff00000
|
||||
#define PMC551_PCI_MEM_MAP_APERTURE_MASK 0x000000f0
|
||||
#define PMC551_PCI_MEM_MAP_REG_EN 0x00000002
|
||||
#define PMC551_PCI_MEM_MAP_ENABLE 0x00000001
|
||||
|
||||
#define PMC551_SDRAM_MA 0x60
|
||||
#define PMC551_SDRAM_CMD 0x62
|
||||
#define PMC551_DRAM_CFG 0x64
|
||||
#define PMC551_SYS_CTRL_REG 0x78
|
||||
|
||||
#define PMC551_DRAM_BLK0 0x68
|
||||
#define PMC551_DRAM_BLK1 0x6c
|
||||
#define PMC551_DRAM_BLK2 0x70
|
||||
#define PMC551_DRAM_BLK3 0x74
|
||||
#define PMC551_DRAM_BLK_GET_SIZE(x) (524288<<((x>>4)&0x0f))
|
||||
#define PMC551_DRAM_BLK_SET_COL_MUX(x,v) (((x) & ~0x00007000) | (((v) & 0x7) << 12))
|
||||
#define PMC551_DRAM_BLK_SET_ROW_MUX(x,v) (((x) & ~0x00000f00) | (((v) & 0xf) << 8))
|
||||
|
||||
|
||||
#endif /* __MTD_PMC551_H__ */
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/pm_qos.h>
|
||||
|
||||
/* FLCTL registers */
|
||||
#define FLCMNCR(f) (f->reg + 0x0)
|
||||
@@ -38,6 +39,7 @@
|
||||
#define FLDTFIFO(f) (f->reg + 0x24)
|
||||
#define FLECFIFO(f) (f->reg + 0x28)
|
||||
#define FLTRCR(f) (f->reg + 0x2C)
|
||||
#define FLHOLDCR(f) (f->reg + 0x38)
|
||||
#define FL4ECCRESULT0(f) (f->reg + 0x80)
|
||||
#define FL4ECCRESULT1(f) (f->reg + 0x84)
|
||||
#define FL4ECCRESULT2(f) (f->reg + 0x88)
|
||||
@@ -67,6 +69,30 @@
|
||||
#define CE0_ENABLE (0x1 << 3) /* Chip Enable 0 */
|
||||
#define TYPESEL_SET (0x1 << 0)
|
||||
|
||||
/*
|
||||
* Clock settings using the PULSEx registers from FLCMNCR
|
||||
*
|
||||
* Some hardware uses bits called PULSEx instead of FCKSEL_E and QTSEL_E
|
||||
* to control the clock divider used between the High-Speed Peripheral Clock
|
||||
* and the FLCTL internal clock. If so, use CLK_8_BIT_xxx for connecting 8 bit
|
||||
* and CLK_16_BIT_xxx for connecting 16 bit bus bandwith NAND chips. For the 16
|
||||
* bit version the divider is seperate for the pulse width of high and low
|
||||
* signals.
|
||||
*/
|
||||
#define PULSE3 (0x1 << 27)
|
||||
#define PULSE2 (0x1 << 17)
|
||||
#define PULSE1 (0x1 << 15)
|
||||
#define PULSE0 (0x1 << 9)
|
||||
#define CLK_8B_0_5 PULSE1
|
||||
#define CLK_8B_1 0x0
|
||||
#define CLK_8B_1_5 (PULSE1 | PULSE2)
|
||||
#define CLK_8B_2 PULSE0
|
||||
#define CLK_8B_3 (PULSE0 | PULSE1 | PULSE2)
|
||||
#define CLK_8B_4 (PULSE0 | PULSE2)
|
||||
#define CLK_16B_6L_2H PULSE0
|
||||
#define CLK_16B_9L_3H (PULSE0 | PULSE1 | PULSE2)
|
||||
#define CLK_16B_12L_4H (PULSE0 | PULSE2)
|
||||
|
||||
/* FLCMDCR control bits */
|
||||
#define ADRCNT2_E (0x1 << 31) /* 5byte address enable */
|
||||
#define ADRMD_E (0x1 << 26) /* Sector address access */
|
||||
@@ -85,6 +111,15 @@
|
||||
#define TRSTRT (0x1 << 0) /* translation start */
|
||||
#define TREND (0x1 << 1) /* translation end */
|
||||
|
||||
/*
|
||||
* FLHOLDCR control bits
|
||||
*
|
||||
* HOLDEN: Bus Occupancy Enable (inverted)
|
||||
* Enable this bit when the external bus might be used in between transfers.
|
||||
* If not set and the bus gets used by other modules, a deadlock occurs.
|
||||
*/
|
||||
#define HOLDEN (0x1 << 0)
|
||||
|
||||
/* FL4ECCCR control bits */
|
||||
#define _4ECCFA (0x1 << 2) /* 4 symbols correct fault */
|
||||
#define _4ECCEND (0x1 << 1) /* 4 symbols end */
|
||||
@@ -97,6 +132,7 @@ struct sh_flctl {
|
||||
struct mtd_info mtd;
|
||||
struct nand_chip chip;
|
||||
struct platform_device *pdev;
|
||||
struct dev_pm_qos_request pm_qos;
|
||||
void __iomem *reg;
|
||||
|
||||
uint8_t done_buff[2048 + 64]; /* max size 2048 + 64 */
|
||||
@@ -108,11 +144,14 @@ struct sh_flctl {
|
||||
int erase1_page_addr; /* page_addr in ERASE1 cmd */
|
||||
uint32_t erase_ADRCNT; /* bits of FLCMDCR in ERASE1 cmd */
|
||||
uint32_t rw_ADRCNT; /* bits of FLCMDCR in READ WRITE cmd */
|
||||
uint32_t flcmncr_base; /* base value of FLCMNCR */
|
||||
|
||||
int hwecc_cant_correct[4];
|
||||
|
||||
unsigned page_size:1; /* NAND page size (0 = 512, 1 = 2048) */
|
||||
unsigned hwecc:1; /* Hardware ECC (0 = disabled, 1 = enabled) */
|
||||
unsigned holden:1; /* Hardware has FLHOLDCR and HOLDEN is set */
|
||||
unsigned qos_request:1; /* QoS request to prevent deep power shutdown */
|
||||
};
|
||||
|
||||
struct sh_flctl_platform_data {
|
||||
@@ -121,6 +160,7 @@ struct sh_flctl_platform_data {
|
||||
unsigned long flcmncr_val;
|
||||
|
||||
unsigned has_hwecc:1;
|
||||
unsigned use_holden:1;
|
||||
};
|
||||
|
||||
static inline struct sh_flctl *mtd_to_flctl(struct mtd_info *mtdinfo)
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright © 2010 ST Microelectronics
|
||||
* Shiraz Hashim <shiraz.hashim@st.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __MTD_SPEAR_SMI_H
|
||||
#define __MTD_SPEAR_SMI_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
/* max possible slots for serial-nor flash chip in the SMI controller */
|
||||
#define MAX_NUM_FLASH_CHIP 4
|
||||
|
||||
/* macro to define partitions for flash devices */
|
||||
#define DEFINE_PARTS(n, of, s) \
|
||||
{ \
|
||||
.name = n, \
|
||||
.offset = of, \
|
||||
.size = s, \
|
||||
}
|
||||
|
||||
/**
|
||||
* struct spear_smi_flash_info - platform structure for passing flash
|
||||
* information
|
||||
*
|
||||
* name: name of the serial nor flash for identification
|
||||
* mem_base: the memory base on which the flash is mapped
|
||||
* size: size of the flash in bytes
|
||||
* partitions: parition details
|
||||
* nr_partitions: number of partitions
|
||||
* fast_mode: whether flash supports fast mode
|
||||
*/
|
||||
|
||||
struct spear_smi_flash_info {
|
||||
char *name;
|
||||
unsigned long mem_base;
|
||||
unsigned long size;
|
||||
struct mtd_partition *partitions;
|
||||
int nr_partitions;
|
||||
u8 fast_mode;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct spear_smi_plat_data - platform structure for configuring smi
|
||||
*
|
||||
* clk_rate: clk rate at which SMI must operate
|
||||
* num_flashes: number of flashes present on board
|
||||
* board_flash_info: specific details of each flash present on board
|
||||
*/
|
||||
struct spear_smi_plat_data {
|
||||
unsigned long clk_rate;
|
||||
int num_flashes;
|
||||
struct spear_smi_flash_info *board_flash_info;
|
||||
struct device_node *np[MAX_NUM_FLASH_CHIP];
|
||||
};
|
||||
|
||||
#endif /* __MTD_SPEAR_SMI_H */
|
||||
Reference in New Issue
Block a user