xref: /rk3399_rockchip-uboot/board/socrates/nand.c (revision 1221ce459d04a428f8880f58581f671b736c3c27)
1fd51b0e0SSergei Poselenov /*
2fd51b0e0SSergei Poselenov  * (C) Copyright 2008
3fd51b0e0SSergei Poselenov  * Sergei Poselenov, Emcraft Systems, sposelenov@emcraft.com.
4fd51b0e0SSergei Poselenov  *
51a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
6fd51b0e0SSergei Poselenov  */
7fd51b0e0SSergei Poselenov 
8fd51b0e0SSergei Poselenov #include <common.h>
9fd51b0e0SSergei Poselenov 
106d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_SYS_NAND_BASE)
11fd51b0e0SSergei Poselenov #include <nand.h>
12*1221ce45SMasahiro Yamada #include <linux/errno.h>
13fd51b0e0SSergei Poselenov #include <asm/io.h>
14fd51b0e0SSergei Poselenov 
15fd51b0e0SSergei Poselenov static int state;
16169de905SMarek Vasut static void sc_nand_write_byte(struct mtd_info *mtd, u_char byte);
17169de905SMarek Vasut static void sc_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len);
18169de905SMarek Vasut static u_char sc_nand_read_byte(struct mtd_info *mtd);
19169de905SMarek Vasut static u16 sc_nand_read_word(struct mtd_info *mtd);
20169de905SMarek Vasut static void sc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len);
21169de905SMarek Vasut static int sc_nand_device_ready(struct mtd_info *mtdinfo);
22fd51b0e0SSergei Poselenov 
23fd51b0e0SSergei Poselenov #define FPGA_NAND_CMD_MASK		(0x7 << 28)
24fd51b0e0SSergei Poselenov #define FPGA_NAND_CMD_COMMAND		(0x0 << 28)
25fd51b0e0SSergei Poselenov #define FPGA_NAND_CMD_ADDR		(0x1 << 28)
26fd51b0e0SSergei Poselenov #define FPGA_NAND_CMD_READ		(0x2 << 28)
27fd51b0e0SSergei Poselenov #define FPGA_NAND_CMD_WRITE		(0x3 << 28)
28fd51b0e0SSergei Poselenov #define FPGA_NAND_BUSY			(0x1 << 15)
29fd51b0e0SSergei Poselenov #define FPGA_NAND_ENABLE		(0x1 << 31)
30fd51b0e0SSergei Poselenov #define FPGA_NAND_DATA_SHIFT		16
31fd51b0e0SSergei Poselenov 
32fd51b0e0SSergei Poselenov /**
33169de905SMarek Vasut  * sc_nand_write_byte -  write one byte to the chip
34fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
35fd51b0e0SSergei Poselenov  * @byte:	pointer to data byte to write
36fd51b0e0SSergei Poselenov  */
sc_nand_write_byte(struct mtd_info * mtd,u_char byte)37169de905SMarek Vasut static void sc_nand_write_byte(struct mtd_info *mtd, u_char byte)
38fd51b0e0SSergei Poselenov {
39169de905SMarek Vasut 	sc_nand_write_buf(mtd, (const uchar *)&byte, sizeof(byte));
40fd51b0e0SSergei Poselenov }
41fd51b0e0SSergei Poselenov 
42fd51b0e0SSergei Poselenov /**
43169de905SMarek Vasut  * sc_nand_write_buf -  write buffer to chip
44fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
45fd51b0e0SSergei Poselenov  * @buf:	data buffer
46fd51b0e0SSergei Poselenov  * @len:	number of bytes to write
47fd51b0e0SSergei Poselenov  */
sc_nand_write_buf(struct mtd_info * mtd,const u_char * buf,int len)48169de905SMarek Vasut static void sc_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
49fd51b0e0SSergei Poselenov {
50fd51b0e0SSergei Poselenov 	int i;
5117cb4b8fSScott Wood 	struct nand_chip *this = mtd_to_nand(mtd);
52fd51b0e0SSergei Poselenov 
53fd51b0e0SSergei Poselenov 	for (i = 0; i < len; i++) {
5468cf19aaSScott Wood 		out_be32(this->IO_ADDR_W,
5568cf19aaSScott Wood 			 state | (buf[i] << FPGA_NAND_DATA_SHIFT));
56fd51b0e0SSergei Poselenov 	}
57fd51b0e0SSergei Poselenov }
58fd51b0e0SSergei Poselenov 
59fd51b0e0SSergei Poselenov 
60fd51b0e0SSergei Poselenov /**
61169de905SMarek Vasut  * sc_nand_read_byte -  read one byte from the chip
62fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
63fd51b0e0SSergei Poselenov  */
sc_nand_read_byte(struct mtd_info * mtd)64169de905SMarek Vasut static u_char sc_nand_read_byte(struct mtd_info *mtd)
65fd51b0e0SSergei Poselenov {
66fd51b0e0SSergei Poselenov 	u8 byte;
67169de905SMarek Vasut 	sc_nand_read_buf(mtd, (uchar *)&byte, sizeof(byte));
68fd51b0e0SSergei Poselenov 	return byte;
69fd51b0e0SSergei Poselenov }
70fd51b0e0SSergei Poselenov 
71fd51b0e0SSergei Poselenov /**
72169de905SMarek Vasut  * sc_nand_read_word -  read one word from the chip
73fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
74fd51b0e0SSergei Poselenov  */
sc_nand_read_word(struct mtd_info * mtd)75169de905SMarek Vasut static u16 sc_nand_read_word(struct mtd_info *mtd)
76fd51b0e0SSergei Poselenov {
77fd51b0e0SSergei Poselenov 	u16 word;
78169de905SMarek Vasut 	sc_nand_read_buf(mtd, (uchar *)&word, sizeof(word));
79fd51b0e0SSergei Poselenov 	return word;
80fd51b0e0SSergei Poselenov }
81fd51b0e0SSergei Poselenov 
82fd51b0e0SSergei Poselenov /**
83169de905SMarek Vasut  * sc_nand_read_buf -  read chip data into buffer
84fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
85fd51b0e0SSergei Poselenov  * @buf:	buffer to store date
86fd51b0e0SSergei Poselenov  * @len:	number of bytes to read
87fd51b0e0SSergei Poselenov  */
sc_nand_read_buf(struct mtd_info * mtd,u_char * buf,int len)88169de905SMarek Vasut static void sc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
89fd51b0e0SSergei Poselenov {
90fd51b0e0SSergei Poselenov 	int i;
9117cb4b8fSScott Wood 	struct nand_chip *this = mtd_to_nand(mtd);
92fd51b0e0SSergei Poselenov 	int val;
93fd51b0e0SSergei Poselenov 
94fd51b0e0SSergei Poselenov 	val = (state & FPGA_NAND_ENABLE) | FPGA_NAND_CMD_READ;
95fd51b0e0SSergei Poselenov 
96fd51b0e0SSergei Poselenov 	out_be32(this->IO_ADDR_W, val);
97fd51b0e0SSergei Poselenov 	for (i = 0; i < len; i++) {
98fd51b0e0SSergei Poselenov 		buf[i] = (in_be32(this->IO_ADDR_R) >> FPGA_NAND_DATA_SHIFT) & 0xff;
99fd51b0e0SSergei Poselenov 	}
100fd51b0e0SSergei Poselenov }
101fd51b0e0SSergei Poselenov 
102fd51b0e0SSergei Poselenov /**
103169de905SMarek Vasut  * sc_nand_device_ready - Check the NAND device is ready for next command.
104fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
105fd51b0e0SSergei Poselenov  */
sc_nand_device_ready(struct mtd_info * mtdinfo)106169de905SMarek Vasut static int sc_nand_device_ready(struct mtd_info *mtdinfo)
107fd51b0e0SSergei Poselenov {
10817cb4b8fSScott Wood 	struct nand_chip *this = mtd_to_nand(mtdinfo);
109fd51b0e0SSergei Poselenov 
110fd51b0e0SSergei Poselenov 	if (in_be32(this->IO_ADDR_W) & FPGA_NAND_BUSY)
111fd51b0e0SSergei Poselenov 		return 0; /* busy */
112fd51b0e0SSergei Poselenov 	return 1;
113fd51b0e0SSergei Poselenov }
114fd51b0e0SSergei Poselenov 
115fd51b0e0SSergei Poselenov /**
116169de905SMarek Vasut  * sc_nand_hwcontrol - NAND control functions wrapper.
117fd51b0e0SSergei Poselenov  * @mtd:	MTD device structure
118fd51b0e0SSergei Poselenov  * @cmd:	Command
119fd51b0e0SSergei Poselenov  */
sc_nand_hwcontrol(struct mtd_info * mtdinfo,int cmd,unsigned int ctrl)120169de905SMarek Vasut static void sc_nand_hwcontrol(struct mtd_info *mtdinfo, int cmd, unsigned int ctrl)
121fd51b0e0SSergei Poselenov {
12268cf19aaSScott Wood 	if (ctrl & NAND_CTRL_CHANGE) {
12368cf19aaSScott Wood 		state &= ~(FPGA_NAND_CMD_MASK | FPGA_NAND_ENABLE);
124fd51b0e0SSergei Poselenov 
12568cf19aaSScott Wood 		switch (ctrl & (NAND_ALE | NAND_CLE)) {
12668cf19aaSScott Wood 		case 0:
12768cf19aaSScott Wood 			state |= FPGA_NAND_CMD_WRITE;
128fd51b0e0SSergei Poselenov 			break;
12968cf19aaSScott Wood 
13068cf19aaSScott Wood 		case NAND_ALE:
13168cf19aaSScott Wood 			state |= FPGA_NAND_CMD_ADDR;
132fd51b0e0SSergei Poselenov 			break;
13368cf19aaSScott Wood 
13468cf19aaSScott Wood 		case NAND_CLE:
13568cf19aaSScott Wood 			state |= FPGA_NAND_CMD_COMMAND;
136fd51b0e0SSergei Poselenov 			break;
13768cf19aaSScott Wood 
138fd51b0e0SSergei Poselenov 		default:
13968cf19aaSScott Wood 			printf("%s: unknown ctrl %#x\n", __FUNCTION__, ctrl);
140fd51b0e0SSergei Poselenov 		}
14168cf19aaSScott Wood 
14268cf19aaSScott Wood 		if (ctrl & NAND_NCE)
14368cf19aaSScott Wood 			state |= FPGA_NAND_ENABLE;
14468cf19aaSScott Wood 	}
14568cf19aaSScott Wood 
14668cf19aaSScott Wood 	if (cmd != NAND_CMD_NONE)
147169de905SMarek Vasut 		sc_nand_write_byte(mtdinfo, cmd);
148fd51b0e0SSergei Poselenov }
149fd51b0e0SSergei Poselenov 
board_nand_init(struct nand_chip * nand)150fd51b0e0SSergei Poselenov int board_nand_init(struct nand_chip *nand)
151fd51b0e0SSergei Poselenov {
152169de905SMarek Vasut 	nand->cmd_ctrl = sc_nand_hwcontrol;
15368cf19aaSScott Wood 	nand->ecc.mode = NAND_ECC_SOFT;
154169de905SMarek Vasut 	nand->dev_ready = sc_nand_device_ready;
155169de905SMarek Vasut 	nand->read_byte = sc_nand_read_byte;
156169de905SMarek Vasut 	nand->read_word = sc_nand_read_word;
157169de905SMarek Vasut 	nand->write_buf = sc_nand_write_buf;
158169de905SMarek Vasut 	nand->read_buf = sc_nand_read_buf;
159fd51b0e0SSergei Poselenov 
160fd51b0e0SSergei Poselenov 	return 0;
161fd51b0e0SSergei Poselenov }
162fd51b0e0SSergei Poselenov 
163fd51b0e0SSergei Poselenov #endif
164