/*
* MTD map driver for AMD compatible flash chips (non-CFI)
*
* Author: Jonas Holmberg <jonas.holmberg@axis.com>
*
* $Id: amd_flash.c,v 1.28 2005/11/07 11:14:22 gleixner Exp $
*
* Copyright (c) 2001 Axis Communications AB
*
* This file is under GPL.
*
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/mtd/map.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/flashchip.h>
/* There's no limit. It exists only to avoid realloc. */
#define MAX_AMD_CHIPS 8
#define DEVICE_TYPE_X8 (8 / 8)
#define DEVICE_TYPE_X16 (16 / 8)
#define DEVICE_TYPE_X32 (32 / 8)
/* Addresses */
#define ADDR_MANUFACTURER 0x0000
#define ADDR_DEVICE_ID 0x0001
#define ADDR_SECTOR_LOCK 0x0002
#define ADDR_HANDSHAKE 0x0003
#define ADDR_UNLOCK_1 0x0555
#define ADDR_UNLOCK_2 0x02AA
/* Commands */
#define CMD_UNLOCK_DATA_1 0x00AA
#define CMD_UNLOCK_DATA_2 0x0055
#define CMD_MANUFACTURER_UNLOCK_DATA 0x0090
#define CMD_UNLOCK_BYPASS_MODE 0x0020
#define CMD_PROGRAM_UNLOCK_DATA 0x00A0
#define CMD_RESET_DATA 0x00F0
#define CMD_SECTOR_ERASE_UNLOCK_DATA 0x0080
#define CMD_SECTOR_ERASE_UNLOCK_DATA_2 0x0030
#define CMD_UNLOCK_SECTOR 0x0060
/* Manufacturers */
#define MANUFACTURER_AMD 0x0001
#define MANUFACTURER_ATMEL 0x001F
#define MANUFACTURER_FUJITSU 0x0004
#define MANUFACTURER_ST 0x0020
#define MANUFACTURER_SST 0x00BF
#define MANUFACTURER_TOSHIBA 0x0098
/* AMD */
#define AM29F800BB 0x2258
#define AM29F800BT 0x22D6
#define AM29LV800BB 0x225B
#define AM29LV800BT 0x22DA
#define AM29LV160DT 0x22C4
#define AM29LV160DB 0x2249
#define AM29BDS323D 0x22D1
/* Atmel */
#define AT49xV16x 0x00C0
#define AT49xV16xT 0x00C2
/* Fujitsu */
#define MBM29LV160TE 0x22C4
#define MBM29LV160BE 0x2249
#define MBM29LV800BB 0x225B
/* ST - www.st.com */
#define M29W800T 0x00D7
#define M29W160DT 0x22C4
#define M29W160DB 0x2249
/* SST */
#define SST39LF800 0x2781
#define SST39LF160 0x2782
/* Toshiba */
#define TC58FVT160 0x00C2
#define TC58FVB160 0x0043
#define D6_MASK 0x40
struct amd_flash_private {
int device_type;
int interleave;
int numchips;
unsigned long chipshift;
// const char *im_name;
struct flchip chips[0];
};
struct amd_flash_info {
const __u16 mfr_id;
const __u16 dev_id;
const char *name;
const u_long size;
const int numeraseregions;
const struct mtd_erase_region_info regions[4];
};
static int amd_flash_read(struct mtd_info *, loff_t, size_t, size_t *,
u_char *);
static int amd_flash_write(struct mtd_info *, loff_t, size_t, size_t *,
const u_char *);
static int amd_flash_erase(struct mtd_info *, struct erase_info *);
static void amd_flash_sync(struct mtd_info *);
static int amd_flash_suspend(struct mtd_info *);
static void amd_flash_resume(struct mtd_info *);
static void amd_flash_destroy(struct mtd_info *);
static struct mtd_info *amd_flash_probe(struct map_info *map);
static struct mtd_chip_driver amd_flash_chipdrv = {
.probe = amd_flash_probe,
.destroy = amd_flash_destroy,
.name = "amd_flash",
.module = THIS_MODULE
};
static const char im_name[] = "amd_flash";
static inline __u32 wide_read(struct map_info *map, __u32 addr)
{
if (map->buswidth == 1) {
return map_read8(map, addr);
} else if (map->buswidth == 2) {
return map_read16(map, addr);
} else if (map->buswidth == 4) {
return map_read32(map, addr);
}
return 0;
}
static inline void wide_write(struct map_info *map, __u32 val, __u32 addr)
{
if (map->buswidth == 1) {
map_write8(map, val, addr);
} else if (map->buswidth == 2) {
map_write16(map, val, addr);
} else if (map->buswidth == 4) {
map_write32(map, val, addr);
}
}
static inline __u32 make_cmd(struct map_info *map, __u32 cmd)
{
const struct amd_flash_private *private = map->fldrv_priv;
if ((private->interleave ==
|