1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include "nor/device_nor_s25.h"
9 #include "qspi_api.h"
10
11 #include <fwk_id.h>
12 #include <fwk_module.h>
13 #include <fwk_status.h>
14
15 #include <stdbool.h>
16 #include <stdint.h>
17
18 /*
19 * local functions
20 */
set_read_command(fwk_id_t id,const struct qspi_api * qspi_api,struct qspi_command command)21 static int set_read_command(
22 fwk_id_t id,
23 const struct qspi_api *qspi_api,
24 struct qspi_command command)
25 {
26 if (IS_QSPI_COMMAND_EMPTY(command)) {
27 return FWK_E_SUPPORT;
28 }
29
30 return qspi_api->set_read_command(id, &command);
31 }
32
set_write_command(fwk_id_t id,const struct qspi_api * qspi_api,struct qspi_command command)33 static int set_write_command(
34 fwk_id_t id,
35 const struct qspi_api *qspi_api,
36 struct qspi_command command)
37 {
38 if (IS_QSPI_COMMAND_EMPTY(command)) {
39 return FWK_E_SUPPORT;
40 }
41
42 return qspi_api->set_write_command(id, &command);
43 }
44
s25_is_write_enable(fwk_id_t id,const struct qspi_api * qspi_api)45 static bool s25_is_write_enable(fwk_id_t id, const struct qspi_api *qspi_api)
46 {
47 int status;
48 uint8_t buf;
49
50 status = set_read_command(id, qspi_api, COMMAND_READ_STATUS_REG);
51 if (status != FWK_SUCCESS) {
52 return false;
53 }
54
55 status = qspi_api->read(id, 0, &buf, sizeof(buf));
56 if (status != FWK_SUCCESS) {
57 return false;
58 }
59
60 return S25_IS_WEL_ENABLE(buf);
61 }
62
s25_read_status_reg(fwk_id_t id,const struct qspi_api * qspi_api,uint8_t * buf)63 static int s25_read_status_reg(
64 fwk_id_t id,
65 const struct qspi_api *qspi_api,
66 uint8_t *buf)
67 {
68 int status;
69
70 status = set_read_command(id, qspi_api, COMMAND_READ_STATUS_REG);
71 if (status != FWK_SUCCESS) {
72 return status;
73 }
74
75 return qspi_api->read(id, 0, buf, sizeof(buf[0]));
76 }
77
s25_read_config_reg(fwk_id_t id,const struct qspi_api * qspi_api,uint8_t * buf)78 static int s25_read_config_reg(
79 fwk_id_t id,
80 const struct qspi_api *qspi_api,
81 uint8_t *buf)
82 {
83 int status;
84
85 status = set_read_command(id, qspi_api, S25_COMMAND_READ_CONFIG_REG);
86 if (status != FWK_SUCCESS) {
87 return status;
88 }
89
90 return qspi_api->read(id, 0, buf, sizeof(buf[0]));
91 }
92
s25_write_config_reg(fwk_id_t id,const struct qspi_api * qspi_api,uint8_t buf)93 static int s25_write_config_reg(
94 fwk_id_t id,
95 const struct qspi_api *qspi_api,
96 uint8_t buf)
97 {
98 int status;
99 uint8_t write_buf[2];
100
101 status = s25_read_status_reg(id, qspi_api, &write_buf[0]);
102 if (status != FWK_SUCCESS) {
103 return status;
104 }
105
106 write_buf[1] = buf;
107
108 status = set_write_command(id, qspi_api, S25_COMMAND_WRITE_CONFIG_REG);
109 if (status != FWK_SUCCESS) {
110 return status;
111 }
112
113 return qspi_api->write(id, 0, &write_buf, sizeof(write_buf));
114 }
115
s25_read_bank_reg(fwk_id_t id,const struct qspi_api * qspi_api,uint8_t * buf)116 static int s25_read_bank_reg(
117 fwk_id_t id,
118 const struct qspi_api *qspi_api,
119 uint8_t *buf)
120 {
121 int status;
122
123 status = set_read_command(id, qspi_api, S25_COMMAND_READ_BANK_REG);
124 if (status != FWK_SUCCESS) {
125 return status;
126 }
127
128 return qspi_api->read(id, 0, buf, sizeof(buf[0]));
129 }
130
s25_write_bank_reg(fwk_id_t id,const struct qspi_api * qspi_api,uint8_t buf)131 static int s25_write_bank_reg(
132 fwk_id_t id,
133 const struct qspi_api *qspi_api,
134 uint8_t buf)
135 {
136 int status;
137
138 status = set_write_command(id, qspi_api, S25_COMMAND_WRITE_BANK_REG);
139 if (status != FWK_SUCCESS) {
140 return status;
141 }
142
143 return qspi_api->write(id, 0, &buf, sizeof(buf));
144 }
145
146 /*
147 * User APIs
148 */
s25_nor_set_io_protocol(fwk_id_t id,const struct qspi_api * qspi_api,void * arg)149 int s25_nor_set_io_protocol(
150 fwk_id_t id,
151 const struct qspi_api *qspi_api,
152 void *arg)
153 {
154 uint8_t io_num = *(uint8_t *)arg;
155 uint8_t buf;
156 bool req_quad;
157 int status;
158
159 if (io_num != 1 && io_num != 2 && io_num != 4) {
160 return FWK_E_PARAM;
161 }
162
163 req_quad = (io_num == 4);
164
165 status = s25_read_config_reg(id, qspi_api, &buf);
166 if (status != FWK_SUCCESS) {
167 return status;
168 }
169
170 if (!req_quad || S25_IS_QUAD_ENABLE(buf)) {
171 return FWK_SUCCESS;
172 }
173
174 if (!s25_is_write_enable(id, qspi_api)) {
175 return FWK_E_ACCESS;
176 }
177
178 /* At here, quad transfer is requested but not yet enabled. */
179 S25_QUAD_ENABLE(buf);
180
181 status = s25_write_config_reg(id, qspi_api, buf);
182 if (status != FWK_SUCCESS) {
183 return status;
184 }
185
186 return FWK_SUCCESS;
187 }
188
s25_nor_set_4byte_addr_mode(fwk_id_t id,const struct qspi_api * qspi_api,void * arg)189 int s25_nor_set_4byte_addr_mode(
190 fwk_id_t id,
191 const struct qspi_api *qspi_api,
192 void *arg)
193 {
194 bool enable = *(bool *)arg;
195 uint8_t buf;
196 int status;
197
198 status = s25_read_bank_reg(id, qspi_api, &buf);
199 if (status != FWK_SUCCESS) {
200 return status;
201 }
202
203 if (enable == S25_IS_4BYTE_ENABLE(buf)) {
204 return FWK_SUCCESS;
205 }
206
207 if (enable) {
208 S25_4BYTE_ENABLE(buf);
209 } else {
210 S25_4BYTE_DISABLE(buf);
211 }
212
213 // not require the WREN before this command
214
215 status = s25_write_bank_reg(id, qspi_api, buf);
216 if (status != FWK_SUCCESS) {
217 return status;
218 }
219
220 return FWK_SUCCESS;
221 }
222
s25_nor_get_program_result(fwk_id_t id,const struct qspi_api * qspi_api,void * arg)223 int s25_nor_get_program_result(
224 fwk_id_t id,
225 const struct qspi_api *qspi_api,
226 void *arg)
227 {
228 uint8_t buf;
229 bool *is_fail = (bool *)arg;
230 int status;
231
232 status = s25_read_status_reg(id, qspi_api, &buf);
233 if (status != FWK_SUCCESS) {
234 return status;
235 }
236
237 if (S25_IS_PROGRAM_FAIL(buf)) {
238 *is_fail = true;
239 } else {
240 *is_fail = false;
241 }
242
243 return FWK_SUCCESS;
244 }
245
s25_nor_get_erase_result(fwk_id_t id,const struct qspi_api * qspi_api,void * arg)246 int s25_nor_get_erase_result(
247 fwk_id_t id,
248 const struct qspi_api *qspi_api,
249 void *arg)
250 {
251 uint8_t buf;
252 bool *is_fail = (bool *)arg;
253 int status;
254
255 status = s25_read_status_reg(id, qspi_api, &buf);
256 if (status != FWK_SUCCESS) {
257 return status;
258 }
259
260 if (S25_IS_ERASE_FAIL(buf)) {
261 *is_fail = true;
262 } else {
263 *is_fail = false;
264 }
265
266 return FWK_SUCCESS;
267 }
268