1/* 2 * This program is free software; you can redistribute it and/or modify it 3 * under the terms of the GNU General Public License version 2 as published 4 * by the Free Software Foundation. 5 * 6 * Copyright © 2012 John Crispin <blogic@openwrt.org> 7 */ 8 9#include <linux/mtd/nand.h> 10#include <linux/of_gpio.h> 11#include <linux/of_platform.h> 12 13#include <lantiq_soc.h> 14 15/* nand registers */ 16#define EBU_ADDSEL1 0x24 17#define EBU_NAND_CON 0xB0 18#define EBU_NAND_WAIT 0xB4 19#define EBU_NAND_ECC0 0xB8 20#define EBU_NAND_ECC_AC 0xBC 21 22/* nand commands */ 23#define NAND_CMD_ALE (1 << 2) 24#define NAND_CMD_CLE (1 << 3) 25#define NAND_CMD_CS (1 << 4) 26#define NAND_WRITE_CMD_RESET 0xff 27#define NAND_WRITE_CMD (NAND_CMD_CS | NAND_CMD_CLE) 28#define NAND_WRITE_ADDR (NAND_CMD_CS | NAND_CMD_ALE) 29#define NAND_WRITE_DATA (NAND_CMD_CS) 30#define NAND_READ_DATA (NAND_CMD_CS) 31#define NAND_WAIT_WR_C (1 << 3) 32#define NAND_WAIT_RD (0x1) 33 34/* we need to tel the ebu which addr we mapped the nand to */ 35#define ADDSEL1_MASK(x) (x << 4) 36#define ADDSEL1_REGEN 1 37 38/* we need to tell the EBU that we have nand attached and set it up properly */ 39#define BUSCON1_SETUP (1 << 22) 40#define BUSCON1_BCGEN_RES (0x3 << 12) 41#define BUSCON1_WAITWRC2 (2 << 8) 42#define BUSCON1_WAITRDC2 (2 << 6) 43#define BUSCON1_HOLDC1 (1 << 4) 44#define BUSCON1_RECOVC1 (1 << 2) 45#define BUSCON1_CMULT4 1 46 47#define NAND_CON_CE (1 << 20) 48#define NAND_CON_OUT_CS1 (1 << 10) 49#define NAND_CON_IN_CS1 (1 << 8) 50#define NAND_CON_PRE_P (1 << 7) 51#define NAND_CON_WP_P (1 << 6) 52#define NAND_CON_SE_P (1 << 5) 53#define NAND_CON_CS_P (1 << 4) 54#define NAND_CON_CSMUX (1 << 1) 55#define NAND_CON_NANDM 1 56 57static void xway_reset_chip(struct nand_chip *chip) 58{ 59 unsigned long nandaddr = (unsigned long) chip->IO_ADDR_W; 60 unsigned long flags; 61 62 nandaddr &= ~NAND_WRITE_ADDR; 63 nandaddr |= NAND_WRITE_CMD; 64 65 /* finish with a reset */ 66 spin_lock_irqsave(&ebu_lock, flags); 67 writeb(NAND_WRITE_CMD_RESET, (void __iomem *) nandaddr); 68 while ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0) 69 ; 70 spin_unlock_irqrestore(&ebu_lock, flags); 71} 72 73static void xway_select_chip(struct mtd_info *mtd, int chip) 74{ 75 76 switch (chip) { 77 case -1: 78 ltq_ebu_w32_mask(NAND_CON_CE, 0, EBU_NAND_CON); 79 ltq_ebu_w32_mask(NAND_CON_NANDM, 0, EBU_NAND_CON); 80 break; 81 case 0: 82 ltq_ebu_w32_mask(0, NAND_CON_NANDM, EBU_NAND_CON); 83 ltq_ebu_w32_mask(0, NAND_CON_CE, EBU_NAND_CON); 84 break; 85 default: 86 BUG(); 87 } 88} 89 90static void xway_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) 91{ 92 struct nand_chip *this = mtd->priv; 93 unsigned long nandaddr = (unsigned long) this->IO_ADDR_W; 94 unsigned long flags; 95 96 if (ctrl & NAND_CTRL_CHANGE) { 97 nandaddr &= ~(NAND_WRITE_CMD | NAND_WRITE_ADDR); 98 if (ctrl & NAND_CLE) 99 nandaddr |= NAND_WRITE_CMD; 100 else 101 nandaddr |= NAND_WRITE_ADDR; 102 this->IO_ADDR_W = (void __iomem *) nandaddr; 103 } 104 105 if (cmd != NAND_CMD_NONE) { 106 spin_lock_irqsave(&ebu_lock, flags); 107 writeb(cmd, this->IO_ADDR_W); 108 while ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0) 109 ; 110 spin_unlock_irqrestore(&ebu_lock, flags); 111 } 112} 113 114static int xway_dev_ready(struct mtd_info *mtd) 115{ 116 return ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_RD; 117} 118 119static unsigned char xway_read_byte(struct mtd_info *mtd) 120{ 121 struct nand_chip *this = mtd->priv; 122 unsigned long nandaddr = (unsigned long) this->IO_ADDR_R; 123 unsigned long flags; 124 int ret; 125 126 spin_lock_irqsave(&ebu_lock, flags); 127 ret = ltq_r8((void __iomem *)(nandaddr + NAND_READ_DATA)); 128 spin_unlock_irqrestore(&ebu_lock, flags); 129 130 return ret; 131} 132 133static int xway_nand_probe(struct platform_device *pdev) 134{ 135 struct nand_chip *this = platform_get_drvdata(pdev); 136 unsigned long nandaddr = (unsigned long) this->IO_ADDR_W; 137 const __be32 *cs = of_get_property(pdev->dev.of_node, 138 "lantiq,cs", NULL); 139 u32 cs_flag = 0; 140 141 /* load our CS from the DT. Either we find a valid 1 or default to 0 */ 142 if (cs && (*cs == 1)) 143 cs_flag = NAND_CON_IN_CS1 | NAND_CON_OUT_CS1; 144 145 /* setup the EBU to run in NAND mode on our base addr */ 146 ltq_ebu_w32(CPHYSADDR(nandaddr) 147 | ADDSEL1_MASK(3) | ADDSEL1_REGEN, EBU_ADDSEL1); 148 149 ltq_ebu_w32(BUSCON1_SETUP | BUSCON1_BCGEN_RES | BUSCON1_WAITWRC2 150 | BUSCON1_WAITRDC2 | BUSCON1_HOLDC1 | BUSCON1_RECOVC1 151 | BUSCON1_CMULT4, LTQ_EBU_BUSCON1); 152 153 ltq_ebu_w32(NAND_CON_NANDM | NAND_CON_CSMUX | NAND_CON_CS_P 154 | NAND_CON_SE_P | NAND_CON_WP_P | NAND_CON_PRE_P 155 | cs_flag, EBU_NAND_CON); 156 157 /* finish with a reset */ 158 xway_reset_chip(this); 159 160 return 0; 161} 162 163/* allow users to override the partition in DT using the cmdline */ 164static const char *part_probes[] = { "cmdlinepart", "ofpart", NULL }; 165 166static struct platform_nand_data xway_nand_data = { 167 .chip = { 168 .nr_chips = 1, 169 .chip_delay = 30, 170 .part_probe_types = part_probes, 171 }, 172 .ctrl = { 173 .probe = xway_nand_probe, 174 .cmd_ctrl = xway_cmd_ctrl, 175 .dev_ready = xway_dev_ready, 176 .select_chip = xway_select_chip, 177 .read_byte = xway_read_byte, 178 } 179}; 180 181/* 182 * Try to find the node inside the DT. If it is available attach out 183 * platform_nand_data 184 */ 185static int __init xway_register_nand(void) 186{ 187 struct device_node *node; 188 struct platform_device *pdev; 189 190 node = of_find_compatible_node(NULL, NULL, "lantiq,nand-xway"); 191 if (!node) 192 return -ENOENT; 193 pdev = of_find_device_by_node(node); 194 if (!pdev) 195 return -EINVAL; 196 pdev->dev.platform_data = &xway_nand_data; 197 of_node_put(node); 198 return 0; 199} 200 201subsys_initcall(xway_register_nand); 202