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:
Linus Torvalds
2012-03-30 17:31:56 -07:00
152 changed files with 6063 additions and 2493 deletions
+28
View File
@@ -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__ */
+5
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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 */
+5 -2
View File
@@ -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
-78
View File
@@ -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__ */
+40
View File
@@ -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)
+65
View File
@@ -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 */