1 /*
2 * Copyright (c) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "hifmc100_spi_nand.h"
17
18 #include "hdf_base.h"
19 #include "hdf_log.h"
20
21 #define HIFMC_WAIT_DEV_READY_TIMEOUT 0x10000
HifmcCntlrSpinandWaitReadyDefault(struct SpiFlash * spi)22 static int32_t HifmcCntlrSpinandWaitReadyDefault(struct SpiFlash *spi)
23 {
24 struct HifmcCntlr *cntlr = NULL;
25 unsigned char status;
26 int32_t timeout = HIFMC_WAIT_DEV_READY_TIMEOUT;
27 int32_t ret;
28
29 if (spi == NULL || spi->mtd.cntlr == NULL) {
30 return HDF_ERR_INVALID_OBJECT;
31 }
32 cntlr = spi->mtd.cntlr;
33
34 while (timeout >= 0) {
35 ret = HifmcCntlrDevFeatureOp(cntlr, spi, true, MTD_SPI_NAND_STATUS_ADDR, &status);
36 if (ret != HDF_SUCCESS) {
37 return ret;
38 }
39 if (!(status & MTD_SPI_SR_WIP_MASK)) {
40 return HDF_SUCCESS;
41 }
42 timeout--;
43 }
44
45 return HDF_ERR_TIMEOUT;
46 }
47
HifmcCntlrSpinandWriteEnableDefault(struct SpiFlash * spi)48 static int32_t HifmcCntlrSpinandWriteEnableDefault(struct SpiFlash *spi)
49 {
50 struct HifmcCntlr *cntlr = NULL;
51 unsigned int reg;
52 uint8_t status;
53 int32_t ret;
54
55 if (spi == NULL || spi->mtd.cntlr == NULL) {
56 return HDF_ERR_INVALID_OBJECT;
57 }
58 cntlr = spi->mtd.cntlr;
59
60 ret = HifmcCntlrDevFeatureOp(cntlr, spi, true, MTD_SPI_NAND_STATUS_ADDR, &status);
61 if (ret != HDF_SUCCESS) {
62 return ret;
63 }
64 #ifdef MTD_DEBUG
65 HDF_LOGD("%s: read status before we addr[%#x]:0x%x", __func__, MTD_SPI_NAND_STATUS_ADDR, status);
66 #endif
67 if ((status & MTD_SPI_SR_WEL_MASK) != 0) {
68 HDF_LOGD("%s: write enable already set", __func__);
69 return HDF_SUCCESS;
70 }
71
72 reg = HIFMC_REG_READ(cntlr, HIFMC_GLOBAL_CFG_REG_OFF);
73 if ((reg & HIFMC_GLOBAL_CFG_WP_ENABLE) != 0) {
74 reg &= ~HIFMC_GLOBAL_CFG_WP_ENABLE;
75 HIFMC_REG_WRITE(cntlr, reg, HIFMC_GLOBAL_CFG_REG_OFF);
76 }
77
78 reg = HIFMC_CMD_CMD1(MTD_SPI_CMD_WREN);
79 HIFMC_REG_WRITE(cntlr, reg, HIFMC_CMD_REG_OFF);
80
81 reg = HIFMC_OP_CFG_FM_CS(spi->cs);
82 HIFMC_REG_WRITE(cntlr, reg, HIFMC_OP_CFG_REG_OFF);
83
84 reg = HIFMC_OP_CMD1_EN(1) | HIFMC_OP_REG_OP_START;
85 HIFMC_REG_WRITE(cntlr, reg, HIFMC_OP_REG_OFF);
86
87 HIFMC_CMD_WAIT_CPU_FINISH(cntlr);
88
89 ret = HifmcCntlrDevFeatureOp(cntlr, spi, true, MTD_SPI_NAND_STATUS_ADDR, &status);
90 if (ret != HDF_SUCCESS) {
91 return ret;
92 }
93 #ifdef MTD_DEBUG
94 HDF_LOGD("%s: read status after we addr[%#x]:0x%x", __func__, MTD_SPI_NAND_STATUS_ADDR, status);
95 #endif
96
97 #ifdef MTD_DEBUG
98 HDF_LOGD("%s: write enabled", __func__);
99 #endif
100 return HDF_SUCCESS;
101 }
102
HifmcCntlrSpinandQeEnableDefault(struct SpiFlash * spi)103 static int32_t HifmcCntlrSpinandQeEnableDefault(struct SpiFlash *spi)
104 {
105 struct HifmcCntlr *cntlr = NULL;
106 uint8_t feature;
107 int32_t ret;
108 int enable;
109
110 if (spi == NULL || spi->mtd.cntlr == NULL) {
111 return HDF_ERR_INVALID_OBJECT;
112 }
113 cntlr = spi->mtd.cntlr;
114
115 enable = ((spi->writeCfg.ifType >= MTD_SPI_IF_QUAD) ||
116 (spi->readCfg.ifType >= MTD_SPI_IF_QUAD)) ? 1 : 0;
117 ret = HifmcCntlrDevFeatureOp(cntlr, spi, true, MTD_SPI_NAND_FEATURE_ADDR, &feature);
118 if (ret != HDF_SUCCESS) {
119 return ret;
120 }
121 if (!!(feature & MTD_SPI_FEATURE_QE_ENABLE) == enable) {
122 HDF_LOGI("%s: qe feature:%d, qe enable:%d", __func__, feature, enable);
123 return HDF_SUCCESS;
124 }
125
126 if (enable == 1) {
127 feature |= MTD_SPI_FEATURE_QE_ENABLE;
128 } else {
129 feature &= ~MTD_SPI_FEATURE_QE_ENABLE;
130 }
131 #ifdef MTD_DEBUG
132 HDF_LOGD("%s: spi nand %s quad", __func__, enable == 1 ? "enable" : "disable");
133 #endif
134 ret = HifmcCntlrDevFeatureOp(cntlr, spi, false, MTD_SPI_NAND_FEATURE_ADDR, &feature);
135 if (ret != HDF_SUCCESS) {
136 return ret;
137 }
138
139 SpiFlashWaitReady(spi);
140 ret = HifmcCntlrDevFeatureOp(cntlr, spi, true, MTD_SPI_NAND_FEATURE_ADDR, &feature);
141 if (ret != HDF_SUCCESS) {
142 return ret;
143 }
144 if (!!(feature & MTD_SPI_FEATURE_QE_ENABLE) == enable) {
145 HDF_LOGD("%s: spi nand %s quad success", __func__, enable == 1 ? "enable" : "disable");
146 return HDF_SUCCESS;
147 } else {
148 HDF_LOGE("%s: spi nand %s quad failed", __func__, enable == 1 ? "enable" : "disable");
149 return HDF_ERR_IO;
150 }
151 }
152
HifmcCntlrSpinandQeNotEnable(struct SpiFlash * spi)153 static int32_t HifmcCntlrSpinandQeNotEnable(struct SpiFlash *spi)
154 {
155 (void)spi;
156 return HDF_SUCCESS;
157 }
158
159 static struct MtdSpiOps g_spiOpsDefault = {
160 .waitReady = HifmcCntlrSpinandWaitReadyDefault,
161 .writeEnable = HifmcCntlrSpinandWriteEnableDefault,
162 .qeEnable = HifmcCntlrSpinandQeEnableDefault,
163 };
164
165 static struct SpiOpsInfo g_spiInfoTable[] = {
166 {
167 .id = {0x2c, 0x14}, // MT29f2G01ABA
168 .idLen = 2,
169 .spiOps = {
170 .qeEnable = HifmcCntlrSpinandQeNotEnable,
171 },
172 },
173 {
174 .id = {0x2c, 0x25}, // MT29f2G01ABB
175 .idLen = 2,
176 .spiOps = {
177 .qeEnable = HifmcCntlrSpinandQeNotEnable,
178 },
179 },
180 };
181
SpinandGetSpiOps(struct SpiFlash * spi)182 int32_t SpinandGetSpiOps(struct SpiFlash *spi)
183 {
184 size_t i;
185
186 if (spi == NULL) {
187 return HDF_ERR_INVALID_OBJECT;
188 }
189 spi->spiOps = g_spiOpsDefault;
190
191 for (i = 0; i < (sizeof(g_spiInfoTable) / sizeof(g_spiInfoTable[0])); i++) {
192 if (memcmp(spi->mtd.id, g_spiInfoTable[i].id, g_spiInfoTable[i].idLen) != 0) {
193 continue;
194 }
195 if (g_spiInfoTable[i].spiOps.waitReady != NULL) {
196 spi->spiOps.waitReady = g_spiInfoTable[i].spiOps.waitReady;
197 }
198 if (g_spiInfoTable[i].spiOps.writeEnable != NULL) {
199 spi->spiOps.writeEnable = g_spiInfoTable[i].spiOps.writeEnable;
200 }
201 if (g_spiInfoTable[i].spiOps.qeEnable != NULL) {
202 spi->spiOps.qeEnable = g_spiInfoTable[i].spiOps.qeEnable;
203 }
204 break;
205 }
206 return HDF_SUCCESS;
207 }
208