• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
xway_reset_chip(struct nand_chip * chip)57 static 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 
xway_select_chip(struct mtd_info * mtd,int chip)73 static 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 
xway_cmd_ctrl(struct mtd_info * mtd,int cmd,unsigned int ctrl)90 static 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 
xway_dev_ready(struct mtd_info * mtd)114 static int xway_dev_ready(struct mtd_info *mtd)
115 {
116 	return ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_RD;
117 }
118 
xway_read_byte(struct mtd_info * mtd)119 static 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 
xway_nand_probe(struct platform_device * pdev)133 static 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 */
164 static const char *part_probes[] = { "cmdlinepart", "ofpart", NULL };
165 
166 static 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  */
xway_register_nand(void)185 static 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 
201 subsys_initcall(xway_register_nand);
202