• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * hifmc100_spi_general.c
3  *
4  * The Flash Memory Controller v100 Device Driver for hisilicon
5  *
6  * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
7  *
8  * This program is free software; you can redistribute  it and/or modify it
9  * under  the terms of  the GNU General  Public License as published by the
10  * Free Software Foundation;  either version 2 of the  License, or (at your
11  * option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 /*
24  * Send set/get features command to SPI Nand flash
25  */
26 /*****************************************************************************/
spi_nand_set_cmd(struct hifmc_host * host,u_char op,u_char addr,u_char val)27 void spi_nand_set_cmd(struct hifmc_host *host, u_char op, u_char addr,
28 				u_char val)
29 {
30 	unsigned int reg;
31 
32 	reg = fmc_cmd_cmd1(op ? SPI_CMD_SET_FEATURE : SPI_CMD_GET_FEATURES);
33 	hifmc_write(host, FMC_CMD, reg);
34 	fmc_pr(FT_DBG, "\t||||-Set CMD[%#x]%#x\n", FMC_CMD, reg);
35 
36 	hifmc_write(host, FMC_ADDRL, addr);
37 	fmc_pr(FT_DBG, "\t||||-Set ADDRL[%#x]%#x\n", FMC_ADDRL, addr);
38 
39 	reg = op_cfg_fm_cs(host->cmd_op.cs) | OP_CFG_OEN_EN |
40 		op_cfg_addr_num(FEATURES_OP_ADDR_NUM);
41 	hifmc_write(host, FMC_OP_CFG, reg);
42 	fmc_pr(FT_DBG, "\t||||-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
43 
44 	reg = fmc_data_num_cnt(FEATURES_DATA_LEN);
45 	hifmc_write(host, FMC_DATA_NUM, reg);
46 	fmc_pr(FT_DBG, "\t||||-Set DATA_NUM[%#x]%#x\n", FMC_DATA_NUM, reg);
47 
48 	reg = fmc_op_cmd1_en(ENABLE) | fmc_op_addr_en(ENABLE) |
49 		FMC_OP_REG_OP_START;
50 
51 	if (op == SET_OP) {
52 		reg |= fmc_op_write_data_en(ENABLE);
53 		writeb(val, host->iobase);
54 		fmc_pr(FT_DBG, "\t||||-Write IO[%p]%#x\n", host->iobase,
55 		       *(u_char *)host->iobase);
56 	} else {
57 		reg |= fmc_op_read_data_en(ENABLE);
58 	}
59 
60 	hifmc_write(host, FMC_OP, reg);
61 	fmc_pr(FT_DBG, "\t||||-Set OP[%#x]%#x\n", FMC_OP, reg);
62 
63 	fmc_cmd_wait_cpu_finish(host);
64 }
65 /*****************************************************************************/
spi_nand_feature_op(struct hifmc_spi * spi,unsigned char op,unsigned char addr,unsigned char val)66 unsigned char spi_nand_feature_op(struct hifmc_spi *spi, unsigned char op,
67 					unsigned char addr, unsigned char val)
68 {
69 	unsigned int reg = 0;
70 	const char *str[] = {"Get", "Set"};
71 	struct hifmc_host *host = (struct hifmc_host *)spi->host;
72 
73 	if ((op == GET_OP) && (addr == STATUS_ADDR)) {
74 		fmc_pr(SR_DBG, "\n\t\t|*-Start Get Status\n");
75 
76 		reg = op_cfg_fm_cs(host->cmd_op.cs) | OP_CFG_OEN_EN;
77 		hifmc_write(host, FMC_OP_CFG, reg);
78 		fmc_pr(SR_DBG, "\t\t||-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
79 
80 		reg = fmc_op_read_status_en(ENABLE) | FMC_OP_REG_OP_START;
81 		hifmc_write(host, FMC_OP, reg);
82 		fmc_pr(SR_DBG, "\t\t||-Set OP[%#x]%#x\n", FMC_OP, reg);
83 
84 		fmc_cmd_wait_cpu_finish(host);
85 
86 		val = hifmc_read(host, FMC_STATUS);
87 		fmc_pr(SR_DBG, "\t\t|*-End Get Status, result: %#x\n", val);
88 
89 		return val;
90 	}
91 
92 	fmc_pr(FT_DBG, "\t|||*-Start %s feature, addr[%#x]\n", str[op], addr);
93 
94 	hifmc100_ecc0_switch(host, ENABLE);
95 
96 	spi_nand_set_cmd(host, op, addr, val);
97 
98 	if (op == GET_OP) {
99 		val = readb(host->iobase);
100 		fmc_pr(FT_DBG, "\t||||-Read IO[%p]%#x\n", host->iobase,
101 		       *(u_char *)host->iobase);
102 	}
103 
104 	hifmc100_ecc0_switch(host, DISABLE);
105 
106 	fmc_pr(FT_DBG, "\t|||*-End %s Feature[%#x]:%#x\n", str[op], addr, val);
107 
108 	return val;
109 }
110 
111 /*****************************************************************************/
112 /*
113  * Read status[C0H]:[0]bit OIP, judge whether the device is busy or not
114  */
spi_general_wait_ready(struct hifmc_spi * spi)115 static int spi_general_wait_ready(struct hifmc_spi *spi)
116 {
117 	unsigned char status;
118 	/* just get a big number, so move left 12 bits */
119 	unsigned int deadline = 1 << 12;
120 	struct hifmc_host *host = (struct hifmc_host *)spi->host;
121 
122 	do {
123 		status = spi_nand_feature_op(spi, GET_OP, STATUS_ADDR, 0);
124 		if (!(status & STATUS_OIP_MASK)) {
125 			if ((host->cmd_op.l_cmd == NAND_CMD_ERASE2) &&
126 				(status & STATUS_E_FAIL_MASK)) {
127 				return status;
128 			}
129 			if ((host->cmd_op.l_cmd == NAND_CMD_PAGEPROG) &&
130 				(status & STATUS_P_FAIL_MASK)) {
131 				return status;
132 			}
133 			return 0;
134 		}
135 
136 		udelay(1); /* delay 1 us */
137 	} while (deadline--);
138 
139 	db_msg("Error: SPI Nand wait ready timeout, status: %#x\n", status);
140 
141 	return 1;
142 }
143 
144 /*****************************************************************************/
145 /*
146  * Send write enable cmd to SPI Nand, status[C0H]:[2]bit WEL must be set 1
147  */
spi_general_write_enable(struct hifmc_spi * spi)148 static int spi_general_write_enable(struct hifmc_spi *spi)
149 {
150 	unsigned int reg;
151 	struct hifmc_host *host = (struct hifmc_host *)spi->host;
152 
153 	if (WE_DBG)
154 		printf("\n");
155 	fmc_pr(WE_DBG, "\t|*-Start Write Enable\n");
156 
157 	reg = spi_nand_feature_op(spi, GET_OP, STATUS_ADDR, 0);
158 	if (reg & STATUS_WEL_MASK) {
159 		fmc_pr(WE_DBG, "\t||-Write Enable was opened! reg: %#x\n",
160 		       reg);
161 		return 0;
162 	}
163 
164 	reg = hifmc_read(host, FMC_GLOBAL_CFG);
165 	fmc_pr(WE_DBG, "\t||-Get GLOBAL_CFG[%#x]%#x\n", FMC_GLOBAL_CFG, reg);
166 	if (reg & FMC_GLOBAL_CFG_WP_ENABLE) {
167 		reg &= ~FMC_GLOBAL_CFG_WP_ENABLE;
168 		hifmc_write(host, FMC_GLOBAL_CFG, reg);
169 		fmc_pr(WE_DBG, "\t||-Set GLOBAL_CFG[%#x]%#x\n",
170 		       FMC_GLOBAL_CFG, reg);
171 	}
172 
173 	reg = fmc_cmd_cmd1(SPI_CMD_WREN);
174 	hifmc_write(host, FMC_CMD, reg);
175 	fmc_pr(WE_DBG, "\t||-Set CMD[%#x]%#x\n", FMC_CMD, reg);
176 
177 	reg = op_cfg_fm_cs(host->cmd_op.cs) | OP_CFG_OEN_EN;
178 	hifmc_write(host, FMC_OP_CFG, reg);
179 	fmc_pr(WE_DBG, "\t||-Set OP_CFG[%#x]%#x\n", FMC_OP_CFG, reg);
180 
181 	reg = fmc_op_cmd1_en(ENABLE) | FMC_OP_REG_OP_START;
182 	hifmc_write(host, FMC_OP, reg);
183 	fmc_pr(WE_DBG, "\t||-Set OP[%#x]%#x\n", FMC_OP, reg);
184 
185 	fmc_cmd_wait_cpu_finish(host);
186 
187 #if WE_DBG
188 	spi->driver->wait_ready(spi);
189 
190 	reg = spi_nand_feature_op(spi, GET_OP, STATUS_ADDR, 0);
191 	if (reg & STATUS_WEL_MASK) {
192 		fmc_pr(WE_DBG, "\t||-Write Enable success. reg: %#x\n", reg);
193 	} else {
194 		db_msg("Error: Write Enable failed! reg: %#x\n", reg);
195 		return reg;
196 	}
197 #endif
198 
199 	fmc_pr(WE_DBG, "\t|*-End Write Enable\n");
200 	return 0;
201 }
202 
203 /*****************************************************************************/
204 /*
205  * judge whether SPI Nand support QUAD read/write or not
206  */
spi_is_quad(struct hifmc_spi * spi)207 static int spi_is_quad(struct hifmc_spi *spi)
208 {
209 	const char *if_str[] = {"STD", "DUAL", "DIO", "QUAD", "QIO"};
210 
211 	fmc_pr(QE_DBG, "\t\t|||*-SPI read iftype: %s write iftype: %s\n",
212 			if_str[spi->read->iftype], if_str[spi->write->iftype]);
213 
214 	if ((spi->read->iftype == IF_TYPE_QUAD) 		||
215 			(spi->read->iftype == IF_TYPE_QIO) 	||
216 			(spi->write->iftype == IF_TYPE_QUAD) 	||
217 			(spi->write->iftype == IF_TYPE_QIO))
218 		return 1;
219 
220 	return 0;
221 }
222 
223 /*****************************************************************************/
224 /*
225  * Send set features cmd to SPI Nand, feature[B0H]:[0]bit QE would be set
226  */
spi_general_qe_enable(struct hifmc_spi * spi)227 static int spi_general_qe_enable(struct hifmc_spi *spi)
228 {
229 	unsigned int reg;
230 	unsigned int op;
231 
232 	const char *str[] = {"Disable", "Enable"};
233 
234 	fmc_pr(QE_DBG, "\t||*-Start SPI Nand flash QE\n");
235 
236 	op = spi_is_quad(spi);
237 
238 	fmc_pr(QE_DBG, "\t|||*-End Quad check, SPI Nand %s Quad.\n", str[op]);
239 
240 	reg = spi_nand_feature_op(spi, GET_OP, FEATURE_ADDR, 0);
241 	fmc_pr(QE_DBG, "\t|||-Get [%#x]feature: %#x\n", FEATURE_ADDR, reg);
242 	if ((reg & FEATURE_QE_ENABLE) == op) {
243 		fmc_pr(QE_DBG, "\t||*-SPI Nand quad was %sd!\n", str[op]);
244 		return op;
245 	}
246 
247 	if (op == ENABLE)
248 		reg |= FEATURE_QE_ENABLE;
249 	else
250 		reg &= ~FEATURE_QE_ENABLE;
251 
252 	spi_nand_feature_op(spi, SET_OP, FEATURE_ADDR, reg);
253 	fmc_pr(QE_DBG, "\t|||-SPI Nand %s Quad\n", str[op]);
254 
255 	spi->driver->wait_ready(spi);
256 
257 	reg = spi_nand_feature_op(spi, GET_OP, FEATURE_ADDR, 0);
258 	if ((reg & FEATURE_QE_ENABLE) == op)
259 		fmc_pr(QE_DBG, "\t|||-SPI Nand %s Quad succeed!\n", str[op]);
260 	else
261 		db_msg("Error: %s Quad failed! reg: %#x\n", str[op], reg);
262 
263 	fmc_pr(QE_DBG, "\t||*-End SPI Nand %s Quad.\n", str[op]);
264 
265 	return op;
266 }
267 
268 /****************************************************************************/
269 /* some spi nand flash don't QUAD enable */
spi_do_not_qe_enable(struct hifmc_spi * spi)270 static int spi_do_not_qe_enable(struct hifmc_spi *spi)
271 {
272 	return 0;
273 }