xref: /openbmc/u-boot/board/socrates/nand.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2fd51b0e0SSergei Poselenov /*
3fd51b0e0SSergei Poselenov  * (C) Copyright 2008
4fd51b0e0SSergei Poselenov  * Sergei Poselenov, Emcraft Systems, sposelenov@emcraft.com.
5fd51b0e0SSergei Poselenov  */
6fd51b0e0SSergei Poselenov 
7fd51b0e0SSergei Poselenov #include <common.h>
8fd51b0e0SSergei Poselenov 
96d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_SYS_NAND_BASE)
10fd51b0e0SSergei Poselenov #include <nand.h>
111221ce45SMasahiro Yamada #include <linux/errno.h>
12fd51b0e0SSergei Poselenov #include <asm/io.h>
13fd51b0e0SSergei Poselenov 
14fd51b0e0SSergei Poselenov static int state;
15169de905SMarek Vasut static void sc_nand_write_byte(struct mtd_info *mtd, u_char byte);
16169de905SMarek Vasut static void sc_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len);
17169de905SMarek Vasut static u_char sc_nand_read_byte(struct mtd_info *mtd);
18169de905SMarek Vasut static u16 sc_nand_read_word(struct mtd_info *mtd);
19169de905SMarek Vasut static void sc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len);
20169de905SMarek Vasut static int sc_nand_device_ready(struct mtd_info *mtdinfo);
21fd51b0e0SSergei Poselenov 
22fd51b0e0SSergei Poselenov #define FPGA_NAND_CMD_MASK		(0x7 << 28)
23fd51b0e0SSergei Poselenov #define FPGA_NAND_CMD_COMMAND		(0x0 << 28)
24fd51b0e0SSergei Poselenov #define FPGA_NAND_CMD_ADDR		(0x1 << 28)
25fd51b0e0SSergei Poselenov #define FPGA_NAND_CMD_READ		(0x2 << 28)
26fd51b0e0SSergei Poselenov #define FPGA_NAND_CMD_WRITE		(0x3 << 28)
27fd51b0e0SSergei Poselenov #define FPGA_NAND_BUSY			(0x1 << 15)
28fd51b0e0SSergei Poselenov #define FPGA_NAND_ENABLE		(0x1 << 31)
29fd51b0e0SSergei Poselenov #define FPGA_NAND_DATA_SHIFT		16
30fd51b0e0SSergei Poselenov 
31fd51b0e0SSergei Poselenov /**
32169de905SMarek Vasut  * sc_nand_write_byte -  write one byte to the chip
33fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
34fd51b0e0SSergei Poselenov  * @byte:	pointer to data byte to write
35fd51b0e0SSergei Poselenov  */
sc_nand_write_byte(struct mtd_info * mtd,u_char byte)36169de905SMarek Vasut static void sc_nand_write_byte(struct mtd_info *mtd, u_char byte)
37fd51b0e0SSergei Poselenov {
38169de905SMarek Vasut 	sc_nand_write_buf(mtd, (const uchar *)&byte, sizeof(byte));
39fd51b0e0SSergei Poselenov }
40fd51b0e0SSergei Poselenov 
41fd51b0e0SSergei Poselenov /**
42169de905SMarek Vasut  * sc_nand_write_buf -  write buffer to chip
43fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
44fd51b0e0SSergei Poselenov  * @buf:	data buffer
45fd51b0e0SSergei Poselenov  * @len:	number of bytes to write
46fd51b0e0SSergei Poselenov  */
sc_nand_write_buf(struct mtd_info * mtd,const u_char * buf,int len)47169de905SMarek Vasut static void sc_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
48fd51b0e0SSergei Poselenov {
49fd51b0e0SSergei Poselenov 	int i;
5017cb4b8fSScott Wood 	struct nand_chip *this = mtd_to_nand(mtd);
51fd51b0e0SSergei Poselenov 
52fd51b0e0SSergei Poselenov 	for (i = 0; i < len; i++) {
5368cf19aaSScott Wood 		out_be32(this->IO_ADDR_W,
5468cf19aaSScott Wood 			 state | (buf[i] << FPGA_NAND_DATA_SHIFT));
55fd51b0e0SSergei Poselenov 	}
56fd51b0e0SSergei Poselenov }
57fd51b0e0SSergei Poselenov 
58fd51b0e0SSergei Poselenov 
59fd51b0e0SSergei Poselenov /**
60169de905SMarek Vasut  * sc_nand_read_byte -  read one byte from the chip
61fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
62fd51b0e0SSergei Poselenov  */
sc_nand_read_byte(struct mtd_info * mtd)63169de905SMarek Vasut static u_char sc_nand_read_byte(struct mtd_info *mtd)
64fd51b0e0SSergei Poselenov {
65fd51b0e0SSergei Poselenov 	u8 byte;
66169de905SMarek Vasut 	sc_nand_read_buf(mtd, (uchar *)&byte, sizeof(byte));
67fd51b0e0SSergei Poselenov 	return byte;
68fd51b0e0SSergei Poselenov }
69fd51b0e0SSergei Poselenov 
70fd51b0e0SSergei Poselenov /**
71169de905SMarek Vasut  * sc_nand_read_word -  read one word from the chip
72fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
73fd51b0e0SSergei Poselenov  */
sc_nand_read_word(struct mtd_info * mtd)74169de905SMarek Vasut static u16 sc_nand_read_word(struct mtd_info *mtd)
75fd51b0e0SSergei Poselenov {
76fd51b0e0SSergei Poselenov 	u16 word;
77169de905SMarek Vasut 	sc_nand_read_buf(mtd, (uchar *)&word, sizeof(word));
78fd51b0e0SSergei Poselenov 	return word;
79fd51b0e0SSergei Poselenov }
80fd51b0e0SSergei Poselenov 
81fd51b0e0SSergei Poselenov /**
82169de905SMarek Vasut  * sc_nand_read_buf -  read chip data into buffer
83fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
84fd51b0e0SSergei Poselenov  * @buf:	buffer to store date
85fd51b0e0SSergei Poselenov  * @len:	number of bytes to read
86fd51b0e0SSergei Poselenov  */
sc_nand_read_buf(struct mtd_info * mtd,u_char * buf,int len)87169de905SMarek Vasut static void sc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
88fd51b0e0SSergei Poselenov {
89fd51b0e0SSergei Poselenov 	int i;
9017cb4b8fSScott Wood 	struct nand_chip *this = mtd_to_nand(mtd);
91fd51b0e0SSergei Poselenov 	int val;
92fd51b0e0SSergei Poselenov 
93fd51b0e0SSergei Poselenov 	val = (state & FPGA_NAND_ENABLE) | FPGA_NAND_CMD_READ;
94fd51b0e0SSergei Poselenov 
95fd51b0e0SSergei Poselenov 	out_be32(this->IO_ADDR_W, val);
96fd51b0e0SSergei Poselenov 	for (i = 0; i < len; i++) {
97fd51b0e0SSergei Poselenov 		buf[i] = (in_be32(this->IO_ADDR_R) >> FPGA_NAND_DATA_SHIFT) & 0xff;
98fd51b0e0SSergei Poselenov 	}
99fd51b0e0SSergei Poselenov }
100fd51b0e0SSergei Poselenov 
101fd51b0e0SSergei Poselenov /**
102169de905SMarek Vasut  * sc_nand_device_ready - Check the NAND device is ready for next command.
103fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
104fd51b0e0SSergei Poselenov  */
sc_nand_device_ready(struct mtd_info * mtdinfo)105169de905SMarek Vasut static int sc_nand_device_ready(struct mtd_info *mtdinfo)
106fd51b0e0SSergei Poselenov {
10717cb4b8fSScott Wood 	struct nand_chip *this = mtd_to_nand(mtdinfo);
108fd51b0e0SSergei Poselenov 
109fd51b0e0SSergei Poselenov 	if (in_be32(this->IO_ADDR_W) & FPGA_NAND_BUSY)
110fd51b0e0SSergei Poselenov 		return 0; /* busy */
111fd51b0e0SSergei Poselenov 	return 1;
112fd51b0e0SSergei Poselenov }
113fd51b0e0SSergei Poselenov 
114fd51b0e0SSergei Poselenov /**
115169de905SMarek Vasut  * sc_nand_hwcontrol - NAND control functions wrapper.
116fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
117fd51b0e0SSergei Poselenov  * @cmd:	Command
118fd51b0e0SSergei Poselenov  */
sc_nand_hwcontrol(struct mtd_info * mtdinfo,int cmd,unsigned int ctrl)119169de905SMarek Vasut static void sc_nand_hwcontrol(struct mtd_info *mtdinfo, int cmd, unsigned int ctrl)
120fd51b0e0SSergei Poselenov {
12168cf19aaSScott Wood 	if (ctrl & NAND_CTRL_CHANGE) {
12268cf19aaSScott Wood 		state &= ~(FPGA_NAND_CMD_MASK | FPGA_NAND_ENABLE);
123fd51b0e0SSergei Poselenov 
12468cf19aaSScott Wood 		switch (ctrl & (NAND_ALE | NAND_CLE)) {
12568cf19aaSScott Wood 		case 0:
12668cf19aaSScott Wood 			state |= FPGA_NAND_CMD_WRITE;
127fd51b0e0SSergei Poselenov 			break;
12868cf19aaSScott Wood 
12968cf19aaSScott Wood 		case NAND_ALE:
13068cf19aaSScott Wood 			state |= FPGA_NAND_CMD_ADDR;
131fd51b0e0SSergei Poselenov 			break;
13268cf19aaSScott Wood 
13368cf19aaSScott Wood 		case NAND_CLE:
13468cf19aaSScott Wood 			state |= FPGA_NAND_CMD_COMMAND;
135fd51b0e0SSergei Poselenov 			break;
13668cf19aaSScott Wood 
137fd51b0e0SSergei Poselenov 		default:
13868cf19aaSScott Wood 			printf("%s: unknown ctrl %#x\n", __FUNCTION__, ctrl);
139fd51b0e0SSergei Poselenov 		}
14068cf19aaSScott Wood 
14168cf19aaSScott Wood 		if (ctrl & NAND_NCE)
14268cf19aaSScott Wood 			state |= FPGA_NAND_ENABLE;
14368cf19aaSScott Wood 	}
14468cf19aaSScott Wood 
14568cf19aaSScott Wood 	if (cmd != NAND_CMD_NONE)
146169de905SMarek Vasut 		sc_nand_write_byte(mtdinfo, cmd);
147fd51b0e0SSergei Poselenov }
148fd51b0e0SSergei Poselenov 
board_nand_init(struct nand_chip * nand)149fd51b0e0SSergei Poselenov int board_nand_init(struct nand_chip *nand)
150fd51b0e0SSergei Poselenov {
151169de905SMarek Vasut 	nand->cmd_ctrl = sc_nand_hwcontrol;
15268cf19aaSScott Wood 	nand->ecc.mode = NAND_ECC_SOFT;
153169de905SMarek Vasut 	nand->dev_ready = sc_nand_device_ready;
154169de905SMarek Vasut 	nand->read_byte = sc_nand_read_byte;
155169de905SMarek Vasut 	nand->read_word = sc_nand_read_word;
156169de905SMarek Vasut 	nand->write_buf = sc_nand_write_buf;
157169de905SMarek Vasut 	nand->read_buf = sc_nand_read_buf;
158fd51b0e0SSergei Poselenov 
159fd51b0e0SSergei Poselenov 	return 0;
160fd51b0e0SSergei Poselenov }
161fd51b0e0SSergei Poselenov 
162fd51b0e0SSergei Poselenov #endif
163