|
@@ -35,10 +35,133 @@
|
|
#include <linux/mtd/partitions.h>
|
|
#include <linux/mtd/partitions.h>
|
|
#include <linux/io.h>
|
|
#include <linux/io.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/slab.h>
|
|
-#include <linux/mtd/fsmc.h>
|
|
|
|
#include <linux/amba/bus.h>
|
|
#include <linux/amba/bus.h>
|
|
#include <mtd/mtd-abi.h>
|
|
#include <mtd/mtd-abi.h>
|
|
|
|
|
|
|
|
+#define FSMC_NAND_BW8 1
|
|
|
|
+#define FSMC_NAND_BW16 2
|
|
|
|
+
|
|
|
|
+#define FSMC_MAX_NOR_BANKS 4
|
|
|
|
+#define FSMC_MAX_NAND_BANKS 4
|
|
|
|
+
|
|
|
|
+#define FSMC_FLASH_WIDTH8 1
|
|
|
|
+#define FSMC_FLASH_WIDTH16 2
|
|
|
|
+
|
|
|
|
+/* 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)
|
|
|
|
+
|
|
|
|
+#define CTRL_TIM 0x4
|
|
|
|
+ /* ctrl_tim register definitions */
|
|
|
|
+
|
|
|
|
+#define FSMC_NOR_BANK_SZ 0x8
|
|
|
|
+#define FSMC_NOR_REG_SIZE 0x40
|
|
|
|
+
|
|
|
|
+#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)
|
|
|
|
+
|
|
|
|
+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
|
|
|
|
+ * @nand_timings: timing setup for the physical NAND interface
|
|
|
|
+ * @partitions: partition table for the platform, use a default fallback
|
|
|
|
+ * if this is NULL
|
|
|
|
+ * @nr_partitions: the number of partitions in the previous entry
|
|
|
|
+ * @options: different options for the driver
|
|
|
|
+ * @width: bus width
|
|
|
|
+ * @bank: default bank
|
|
|
|
+ * @select_bank: callback to select a certain bank, this is
|
|
|
|
+ * platform-specific. If the controller only supports one bank
|
|
|
|
+ * 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;
|
|
|
|
+
|
|
|
|
+ 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;
|
|
|
|
+};
|
|
|
|
+
|
|
static int fsmc_ecc1_ooblayout_ecc(struct mtd_info *mtd, int section,
|
|
static int fsmc_ecc1_ooblayout_ecc(struct mtd_info *mtd, int section,
|
|
struct mtd_oob_region *oobregion)
|
|
struct mtd_oob_region *oobregion)
|
|
{
|
|
{
|
|
@@ -714,7 +837,6 @@ static bool filter(struct dma_chan *chan, void *slave)
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
-#ifdef CONFIG_OF
|
|
|
|
static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
|
|
static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
|
|
struct device_node *np)
|
|
struct device_node *np)
|
|
{
|
|
{
|
|
@@ -757,13 +879,6 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
|
|
}
|
|
}
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
-#else
|
|
|
|
-static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
|
|
|
|
- struct device_node *np)
|
|
|
|
-{
|
|
|
|
- return -ENOSYS;
|
|
|
|
-}
|
|
|
|
-#endif
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
* fsmc_nand_probe - Probe function
|
|
* fsmc_nand_probe - Probe function
|
|
@@ -782,19 +897,15 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
|
|
u32 pid;
|
|
u32 pid;
|
|
int i;
|
|
int i;
|
|
|
|
|
|
- if (np) {
|
|
|
|
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
|
|
|
- pdev->dev.platform_data = pdata;
|
|
|
|
- ret = fsmc_nand_probe_config_dt(pdev, np);
|
|
|
|
- if (ret) {
|
|
|
|
- dev_err(&pdev->dev, "no platform data\n");
|
|
|
|
- return -ENODEV;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
|
|
|
+ if (!pdata)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
- if (!pdata) {
|
|
|
|
- dev_err(&pdev->dev, "platform data is NULL\n");
|
|
|
|
- return -EINVAL;
|
|
|
|
|
|
+ pdev->dev.platform_data = pdata;
|
|
|
|
+ ret = fsmc_nand_probe_config_dt(pdev, np);
|
|
|
|
+ if (ret) {
|
|
|
|
+ dev_err(&pdev->dev, "no platform data\n");
|
|
|
|
+ return -ENODEV;
|
|
}
|
|
}
|
|
|
|
|
|
/* Allocate memory for the device structure (and zero it) */
|
|
/* Allocate memory for the device structure (and zero it) */
|