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