/*
* Copyright © 2012 Mike Dunn <mikedunn@newsguy.com>
*
* mtd nand driver for M-Systems DiskOnChip G4
*
* 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.
*
* Tested on the Palm Treo 680. The G4 is also present on Toshiba Portege, Asus
* P526, some HTC smartphones (Wizard, Prophet, ...), O2 XDA Zinc, maybe others.
* Should work on these as well. Let me know!
*
* TODO:
*
* Mechanism for management of password-protected areas
*
* Hamming ecc when reading oob only
*
* According to the M-Sys documentation, this device is also available in a
* "dual-die" configuration having a 256MB capacity, but no mechanism for
* detecting this variant is documented. Currently this driver assumes 128MB
* capacity.
*
* Support for multiple cascaded devices ("floors"). Not sure which gadgets
* contain multiple G4s in a cascaded configuration, if any.
*
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/export.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/bitops.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/bch.h>
#include <linux/bitrev.h>
/*
* You'll want to ignore badblocks if you're reading a partition that contains
* data written by the TrueFFS library (i.e., by PalmOS, Windows, etc), since
* it does not use mtd nand's method for marking bad blocks (using oob area).
* This will also skip the check of the "page written" flag.
*/
static bool ignore_badblocks;
module_param(ignore_badblocks, bool, 0);
MODULE_PARM_DESC(ignore_badblocks, "no badblock checking performed");
struct docg4_priv {
struct mtd_info *mtd;
struct device *dev;
void __iomem *virtadr;
int status;
struct {
unsigned int command;
int column;
int page;
} last_command;
uint8_t oob_buf[16];
uint8_t ecc_buf[7];
int oob_page;
struct bch_control *bch;
};
/*
* Defines prefixed with DOCG4 are unique to the diskonchip G4. All others are
* shared with other diskonchip devices (P3, G3 at least).
*
* Functions with names prefixed with docg4_ are mtd / nand interface functions
* (though they may also be called internally). All others are internal.
*/
#define DOC_IOSPACE_DATA 0x0800
/* register offsets */
#define DOC_CHIPID 0x1000
#define DOC_DEVICESELECT 0x100a
#define DOC_ASICMODE 0x100c
#define DOC_DATAEND 0x101e
#define DOC_NOP 0x103e
#define DOC_FLASHSEQUENCE 0x1032
#define DOC_FLASHCOMMAND 0x1034
#define DOC_FLASHADDRESS 0x1036
#define DOC_FLASHCONTROL 0x1038
#define DOC_ECCCONF0 0x1040
#define DOC_ECCCONF1 0x1042
#define DOC_HAMMINGPARITY 0x1046
#define DOC_BCH_SYNDROM(idx) (0x1048 + idx)
#define DOC_ASICMODECONFIRM 0x1072
#define DOC_CHIPID_INV 0x1074
#define DOC_POWERMODE 0x107c
#define DOCG4_MYSTERY_REG 0x1050
/* apparently used only to write oob bytes 6 and 7 */
#define DOCG4_OOB_6_7 0x1052
/* DOC_FLASHSEQUENCE register commands */
#define DOC_SEQ_RESET 0x00
#define DOCG4_SEQ_PAGE_READ 0x03
#define DOCG4_SEQ_FLUSH 0x29
#define DOCG4_SEQ_PAGEWRITE 0x16
#define DOCG4_SEQ_PAGEPROG 0x1e
#define DOCG4_SEQ_BLOCKERASE 0x24
/* DOC_FLASHCOMMAND register commands */
#define DOCG4_CMD_PAGE_READ 0x00
#define DOC_CMD_ERASECYCLE2 0xd0
#define DOCG4_CMD_FLUSH 0x70
#define DOCG4_CMD_READ2 0x30
#define DOC_CMD_PROG_BLOCK_ADDR 0x60
#define DOCG4_CMD_PAGEWRITE 0x80
#define DOC_CMD_PROG_CYCLE2 0x10
#define DOC_CMD_RESET 0xff
/* DOC_POWERMODE register bits */
#define DOC_POWERDOWN_READY 0x80
/* DOC_FLASHCONTROL register bits */
#define DOC_CTRL_CE 0x10
#define DOC_CTRL_UNKNOWN 0x40