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 }