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