nand: Port MTD from U-boot to depthcharge

This is the first stage in a patchset giving NAND support to depthcharge.
This patch copies MTD from U-boot and cleans up the code, adding
the appropriate makefiles, etc.

Basing depthcharge's NAND support on mtd is intended to reduce
the work required to port SoC-specific NAND drivers from the
Linux kernel or U-Boot to depthcharge. An attempt has been made
to minimize the amount of code which was brought in, but there may
still be room for improvement in importing less code or cleanups.

The interfaces and source code locations are probably as they need
to be, so this can provide an adequate basis for vendors to
begin working on low-level drivers or higher-level code to be
written on top.

From the user's perspective, the two main functions are
- mtd_block_isbad, to determine if a block is bad
- mtd_read, to read from NAND memory
Devices are lazily instantiated from an MtdDevCtrlr to an MtdDev.

A backend implementation for a particular SoC implements methods
in the MtdDev struct which describe the behavior of the device.

BUG=chromium:403432
TEST=ported the IPQ8064 NAND driver and ran a hacked up kernel
loader, observing it to initialize NAND, read from it, and fail
verification.
BRANCH=none

Signed-off-by: Dan Ehrenberg <dehrenberg@chromium.org>

Change-Id: Id4c6b827cc4a0808a646448fd9ff25a97d332d7b
Reviewed-on: https://chromium-review.googlesource.com/222310
Reviewed-by: Julius Werner <jwerner@chromium.org>
Commit-Queue: Daniel Ehrenberg <dehrenberg@chromium.org>
Tested-by: Daniel Ehrenberg <dehrenberg@chromium.org>
diff --git a/src/drivers/storage/Makefile.inc b/src/drivers/storage/Makefile.inc
index de4a5d7..ca68b92 100644
--- a/src/drivers/storage/Makefile.inc
+++ b/src/drivers/storage/Makefile.inc
@@ -26,3 +26,5 @@
 depthcharge-y += usb.c
 depthcharge-$(CONFIG_DRIVER_SDHCI) += sdhci.c mem_sdhci.c
 depthcharge-$(CONFIG_DRIVER_STORAGE_SDHCI_PCI) += pci_sdhci.c
+depthcharge-$(CONFIG_DRIVER_STORAGE_SPI_GPT) += spi_gpt.c
+subdirs-y += mtd
diff --git a/src/drivers/storage/mtd/Kconfig b/src/drivers/storage/mtd/Kconfig
new file mode 100644
index 0000000..66d669b
--- /dev/null
+++ b/src/drivers/storage/mtd/Kconfig
@@ -0,0 +1 @@
+source src/drivers/storage/mtd/nand/Kconfig
diff --git a/src/drivers/storage/mtd/Makefile.inc b/src/drivers/storage/mtd/Makefile.inc
new file mode 100644
index 0000000..bb888a6
--- /dev/null
+++ b/src/drivers/storage/mtd/Makefile.inc
@@ -0,0 +1,18 @@
+##
+## Copyright 2012 Google Inc.
+##
+## 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; version 2 of the License.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+subdirs-y += nand
diff --git a/src/drivers/storage/mtd/mtd.h b/src/drivers/storage/mtd/mtd.h
new file mode 100644
index 0000000..7ed447e
--- /dev/null
+++ b/src/drivers/storage/mtd/mtd.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al.
+ *
+ * Released under GPL
+ */
+
+#ifndef __DRIVERS_STORAGE_MTD_MTD_H__
+#define __DRIVERS_STORAGE_MTD_MTD_H__
+
+#include <assert.h>
+#include <libpayload.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/**
+ * struct mtd_ecc_stats - error correction stats
+ *
+ * @corrected:	number of corrected bits
+ * @failed:	number of uncorrectable errors
+ * @badblocks:	number of bad blocks in this partition
+ * @bbtblocks:	number of blocks reserved for bad block tables
+ */
+struct mtd_ecc_stats {
+	uint32_t corrected;
+	uint32_t failed;
+	uint32_t badblocks;
+	uint32_t bbtblocks;
+};
+
+#define MTD_ERASE_PENDING	0x01
+#define MTD_ERASING		0x02
+#define MTD_ERASE_SUSPEND	0x04
+#define MTD_ERASE_DONE          0x08
+#define MTD_ERASE_FAILED        0x10
+
+#define MTD_FAIL_ADDR_UNKNOWN	-1LL
+
+/*
+ * Certain error codes from the Linux kernel
+ * These aren't shared with the kernel, so they don't have to be
+ * kept in sync, but they are made with equal values for ease of
+ * interpretation.
+ */
+#define	ENODEV		19	/* No such device */
+#define	EBUSY		16	/* Device or resource busy */
+#define	EBADMSG		74	/* Not a data message */
+#define	EUCLEAN		117	/* Structure needs cleaning */
+#define	EINVAL		22	/* Invalid argument */
+#define	EROFS		30	/* Read-only file system */
+#define	ENOMEM		12	/* Out of memory */
+#define	EFAULT		14	/* Bad address */
+#define	EIO		 5	/* I/O error */
+#define	EPERM		 1	/* Operation not permitted */
+#define	ETIMEDOUT	110	/* Connection timed out */
+#define	ENOENT		 2	/* No such file or directory */
+#define	ENOSYS		38	/* Function not implemented */
+
+
+/* If the erase fails, fail_addr might indicate exactly which block failed.  If
+ * fail_addr = MTD_FAIL_ADDR_UNKNOWN, the failure was not at the device level
+ * or was not specific to any particular block. */
+struct erase_info {
+	uint64_t addr;
+	uint64_t len;
+	uint64_t fail_addr;
+	int scrub;
+};
+
+/*
+ * oob operation modes
+ *
+ * MTD_OOB_PLACE:	oob data are placed at the given offset
+ * MTD_OOB_AUTO:	oob data are automatically placed at the free areas
+ *			which are defined by the ecclayout
+ * MTD_OOB_RAW:		mode to read raw data+oob in one chunk. The oob data
+ *			is inserted into the data. Thats a raw image of the
+ *			flash contents.
+ */
+typedef enum {
+	MTD_OOB_PLACE,
+	MTD_OOB_AUTO,
+	MTD_OOB_RAW,
+} mtd_oob_mode_t;
+
+/**
+ * struct mtd_oob_ops - oob operation operands
+ * @mode:	operation mode
+ *
+ * @len:	number of data bytes to write/read
+ *
+ * @retlen:	number of data bytes written/read
+ *
+ * @ooblen:	number of oob bytes to write/read
+ * @oobretlen:	number of oob bytes written/read
+ * @ooboffs:	offset of oob data in the oob area (only relevant when
+ *		mode = MTD_OOB_PLACE)
+ * @datbuf:	data buffer - if NULL only oob data are read/written
+ * @oobbuf:	oob data buffer
+ *
+ * Note, it is allowed to read more then one OOB area at one go, but not write.
+ * The interface assumes that the OOB write requests program only one page's
+ * OOB area.
+ */
+struct mtd_oob_ops {
+	mtd_oob_mode_t	mode;
+	size_t		len;
+	size_t		retlen;
+	size_t		ooblen;
+	size_t		oobretlen;
+	uint32_t	ooboffs;
+	uint8_t		*datbuf;
+	uint8_t		*oobbuf;
+};
+
+typedef struct MtdDev {
+	unsigned char type;
+	uint32_t flags;
+	uint64_t size;	 /* Total size of the MTD */
+
+	/* "Major" erase size for the device. Naïve users may take this
+	 * to be the only erase size available, or may use the more detailed
+	 * information below if they desire
+	 */
+	uint32_t erasesize;
+	/* Minimal writable flash unit size. In case of NOR flash it is 1 (even
+	 * though individual bits can be cleared), in case of NAND flash it is
+	 * one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR
+	 * it is of ECC block size, etc. It is illegal to have writesize = 0.
+	 * Any driver registering a MtdDev must ensure a writesize of
+	 * 1 or larger.
+	 */
+	uint32_t writesize;
+
+	uint32_t oobsize;   /* Amount of OOB data per block (e.g. 16) */
+	uint32_t oobavail;  /* Available OOB bytes per block */
+
+	/*
+	 * 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.
+	 */
+	int (*erase) (struct MtdDev *mtd, struct erase_info *instr);
+
+
+	int (*read) (struct MtdDev *mtd, uint64_t from, size_t len,
+		     size_t *retlen, unsigned char *buf);
+	int (*write) (struct MtdDev *mtd, uint64_t to, size_t len,
+		      size_t *retlen, const unsigned char *buf);
+
+	int (*read_oob) (struct MtdDev *mtd, uint64_t from,
+			 struct mtd_oob_ops *ops);
+	int (*write_oob) (struct MtdDev *mtd, uint64_t to,
+			 struct mtd_oob_ops *ops);
+
+	/* Bad block management functions */
+	int (*block_isbad) (struct MtdDev *mtd, uint64_t ofs);
+	int (*block_markbad) (struct MtdDev *mtd, uint64_t ofs);
+
+	/* ECC status information */
+	struct mtd_ecc_stats ecc_stats;
+
+	void *priv;
+} MtdDev;
+
+typedef struct MtdDevCtrlr {
+	MtdDev *dev;
+	int (*update)(struct MtdDevCtrlr *me);
+} MtdDevCtrlr;
+
+#endif /* __DRIVERS_STORAGE_MTD_MTD_H__ */
diff --git a/src/drivers/storage/mtd/nand/Kconfig b/src/drivers/storage/mtd/nand/Kconfig
new file mode 100644
index 0000000..422932d
--- /dev/null
+++ b/src/drivers/storage/mtd/nand/Kconfig
@@ -0,0 +1,6 @@
+config DRIVER_STORAGE_MTD_NAND
+	bool "NAND Device Support"
+	help
+	  This enables support for accessing all type of NAND flash
+	  devices. For further information see
+	  <http://www.linux-mtd.infradead.org/doc/nand.html>.
diff --git a/src/drivers/storage/mtd/nand/Makefile.inc b/src/drivers/storage/mtd/nand/Makefile.inc
new file mode 100644
index 0000000..f48615b
--- /dev/null
+++ b/src/drivers/storage/mtd/nand/Makefile.inc
@@ -0,0 +1,18 @@
+##
+## Copyright 2012 Google Inc.
+##
+## 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; version 2 of the License.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+depthcharge-$(CONFIG_DRIVER_STORAGE_MTD_NAND) += nand_ids.c
diff --git a/src/drivers/storage/mtd/nand/nand.h b/src/drivers/storage/mtd/nand/nand.h
new file mode 100644
index 0000000..765f1b9
--- /dev/null
+++ b/src/drivers/storage/mtd/nand/nand.h
@@ -0,0 +1,139 @@
+/*
+ *  linux/include/linux/mtd/nand.h
+ *
+ *  Copyright © 2000-2010 David Woodhouse <dwmw2@infradead.org>
+ *                        Steven J. Hill <sjhill@realitydiluted.com>
+ *		          Thomas Gleixner <tglx@linutronix.de>
+ *
+ * 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.
+ *
+ * Info:
+ *	Contains standard defines and IDs for NAND flash devices
+ *
+ * Changelog:
+ *	See git changelog.
+ */
+#ifndef __DRIVERS_STORAGE_MTD_NAND_NAND_H__
+#define __DRIVERS_STORAGE_MTD_NAND_NAND_H__
+
+#include "drivers/storage/mtd/mtd.h"
+
+/*
+ * Standard NAND flash commands
+ */
+#define NAND_CMD_READ0		0
+#define NAND_CMD_READ1		1
+#define NAND_CMD_RNDOUT		5
+#define NAND_CMD_PAGEPROG	0x10
+#define NAND_CMD_READOOB	0x50
+#define NAND_CMD_ERASE1		0x60
+#define NAND_CMD_STATUS		0x70
+#define NAND_CMD_STATUS_MULTI	0x71
+#define NAND_CMD_SEQIN		0x80
+#define NAND_CMD_RNDIN		0x85
+#define NAND_CMD_READID		0x90
+#define NAND_CMD_ERASE2		0xd0
+#define NAND_CMD_PARAM		0xec
+#define NAND_CMD_RESET		0xff
+
+#define NAND_CMD_LOCK		0x2a
+#define NAND_CMD_LOCK_TIGHT	0x2c
+#define NAND_CMD_UNLOCK1	0x23
+#define NAND_CMD_UNLOCK2	0x24
+#define NAND_CMD_LOCK_STATUS	0x7a
+
+/* Extended commands for large page devices */
+#define NAND_CMD_READSTART	0x30
+#define NAND_CMD_RNDOUTSTART	0xE0
+#define NAND_CMD_CACHEDPROG	0x15
+
+#define NAND_CMD_NONE		-1
+
+/* Status bits */
+#define NAND_STATUS_FAIL	0x01
+#define NAND_STATUS_FAIL_N1	0x02
+#define NAND_STATUS_TRUE_READY	0x20
+#define NAND_STATUS_READY	0x40
+#define NAND_STATUS_WP		0x80
+
+struct nand_onfi_params {
+	/* rev info and features block */
+	/* 'O' 'N' 'F' 'I'  */
+	u8 sig[4];
+	u16 revision;
+	u16 features;
+	u16 opt_cmd;
+	u8 reserved[22];
+
+	/* manufacturer information block */
+	char manufacturer[12];
+	char model[20];
+	u8 jedec_id;
+	u16 date_code;
+	u8 reserved2[13];
+
+	/* memory organization block */
+	u32 byte_per_page;
+	u16 spare_bytes_per_page;
+	u32 data_bytes_per_ppage;
+	u16 spare_bytes_per_ppage;
+	u32 pages_per_block;
+	u32 blocks_per_lun;
+	u8 lun_count;
+	u8 addr_cycles;
+	u8 bits_per_cell;
+	u16 bb_per_lun;
+	u16 block_endurance;
+	u8 guaranteed_good_blocks;
+	u16 guaranteed_block_endurance;
+	u8 programs_per_page;
+	u8 ppage_attr;
+	u8 ecc_bits;
+	u8 interleaved_bits;
+	u8 interleaved_ops;
+	u8 reserved3[13];
+
+	/* electrical parameter block */
+	u8 io_pin_capacitance_max;
+	u16 async_timing_mode;
+	u16 program_cache_timing_mode;
+	u16 t_prog;
+	u16 t_bers;
+	u16 t_r;
+	u16 t_ccs;
+	u16 src_sync_timing_mode;
+	u16 src_ssync_features;
+	u16 clk_pin_capacitance_typ;
+	u16 io_pin_capacitance_typ;
+	u16 input_pin_capacitance_typ;
+	u8 input_pin_capacitance_max;
+	u8 driver_strenght_support;
+	u16 t_int_r;
+	u16 t_ald;
+	u8 reserved4[7];
+
+	/* vendor */
+	u8 reserved5[90];
+
+	u16 crc;
+} __attribute__((packed));
+
+#define ONFI_CRC_BASE	0x4F4E
+
+/**
+ * struct nand_flash_dev - NAND Flash Device ID Structure
+ * Only newer NAND with the pagesize and erasesize implicit
+ * in the ID are allowed.
+ * @id:		least significant nibble of device ID code
+ * @chipsize:	Total chipsize in Mega Bytes
+ */
+struct nand_flash_dev {
+	int id;
+	int chipsize;
+};
+
+extern const struct nand_flash_dev nand_flash_ids[];
+
+#endif /* __DRIVERS_STORAGE_MTD_NAND_NAND_H__ */
diff --git a/src/drivers/storage/mtd/nand/nand_ids.c b/src/drivers/storage/mtd/nand/nand_ids.c
new file mode 100644
index 0000000..d5b9436
--- /dev/null
+++ b/src/drivers/storage/mtd/nand/nand_ids.c
@@ -0,0 +1,93 @@
+/*
+ *  drivers/mtd/nandids.c
+ *
+ *  Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
+ *
+ * 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.
+ *
+ */
+
+#include "drivers/storage/mtd/nand/nand.h"
+/*
+*	Chip ID list
+*
+*	Name. ID code, chipsize in MegaByte
+*
+*/
+const struct nand_flash_dev nand_flash_ids[] = {
+	/*512 Megabit */
+	{0xA2, 64},
+	{0xA0, 64},
+	{0xF2, 64},
+	{0xD0, 64},
+	{0xB2, 64},
+	{0xB0, 64},
+	{0xC2, 64},
+	{0xC0, 64},
+
+	/* 1 Gigabit */
+	{0xA1, 128},
+	{0xF1, 128},
+	{0xD1, 128},
+	{0xB1, 128},
+	{0xC1, 128},
+	{0xAD, 128},
+
+	/* 2 Gigabit */
+	{0xAA, 256},
+	{0xDA, 256},
+	{0xBA, 256},
+	{0xCA, 256},
+
+	/* 4 Gigabit */
+	{0xAC, 512},
+	{0xDC, 512},
+	{0xBC, 512},
+	{0xCC, 512},
+
+	/* 8 Gigabit */
+	{0xA3, 1024},
+	{0xD3, 1024},
+	{0xB3, 1024},
+	{0xC3, 1024},
+
+	/* 16 Gigabit */
+	{0xA5, 2048},
+	{0xD5, 2048},
+	{0xB5, 2048},
+	{0xC5, 2048},
+
+	/* 32 Gigabit */
+	{0xA7, 4096},
+	{0xD7, 4096},
+	{0xB7, 4096},
+	{0xC7, 4096},
+
+	/* 64 Gigabit */
+	{0xAE, 8192},
+	{0xDE, 8192},
+	{0xBE, 8192},
+	{0xCE, 8192},
+
+	/* 128 Gigabit */
+	{0x1A, 16384},
+	{0x3A, 16384},
+	{0x2A, 16384},
+	{0x4A, 16384},
+
+	/* 256 Gigabit */
+	{0x1C, 32768},
+	{0x3C, 32768},
+	{0x2C, 32768},
+	{0x4C, 32768},
+
+	/* 512 Gigabit */
+	{0x1E, 65536},
+	{0x3E, 65536},
+	{0x2E, 65536},
+	{0x4E, 65536},
+
+	{0, 0}
+};