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_mx25.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 
mx25_read_status_reg(fwk_id_t id,const struct qspi_api * qspi_api,uint8_t * buf)45 static int mx25_read_status_reg(
46     fwk_id_t id,
47     const struct qspi_api *qspi_api,
48     uint8_t *buf)
49 {
50     int status;
51 
52     status = set_read_command(id, qspi_api, COMMAND_READ_STATUS_REG);
53     if (status != FWK_SUCCESS) {
54         return status;
55     }
56 
57     return qspi_api->read(id, 0, buf, sizeof(buf[0]));
58 }
59 
mx25_write_status_reg(fwk_id_t id,const struct qspi_api * qspi_api,uint8_t buf)60 static int mx25_write_status_reg(
61     fwk_id_t id,
62     const struct qspi_api *qspi_api,
63     uint8_t buf)
64 {
65     int status;
66 
67     status = set_write_command(id, qspi_api, COMMAND_WRITE_STATUS_REG);
68     if (status != FWK_SUCCESS) {
69         return status;
70     }
71 
72     return qspi_api->write(id, 0, &buf, sizeof(buf));
73 }
74 
mx25_read_security_reg(fwk_id_t id,const struct qspi_api * qspi_api,uint8_t * buf)75 static int mx25_read_security_reg(
76     fwk_id_t id,
77     const struct qspi_api *qspi_api,
78     uint8_t *buf)
79 {
80     int status;
81 
82     status = set_read_command(id, qspi_api, MX25_COMMAND_READ_SECURITY_REG);
83     if (status != FWK_SUCCESS) {
84         return status;
85     }
86 
87     return qspi_api->read(id, 0, buf, sizeof(buf[0]));
88 }
89 
90 /*
91  * User APIs
92  */
mx25_nor_set_io_protocol(fwk_id_t id,const struct qspi_api * qspi_api,void * arg)93 int mx25_nor_set_io_protocol(
94     fwk_id_t id,
95     const struct qspi_api *qspi_api,
96     void *arg)
97 {
98     uint8_t io_num = *(uint8_t *)arg;
99     uint8_t buf;
100     bool req_quad;
101     int status;
102 
103     if (io_num != 1 && io_num != 2 && io_num != 4) {
104         return FWK_E_PARAM;
105     }
106 
107     req_quad = (io_num == 4);
108 
109     status = mx25_read_status_reg(id, qspi_api, &buf);
110     if (status != FWK_SUCCESS) {
111         return status;
112     }
113 
114     if (!req_quad || MX25_IS_QUAD_ENABLE(buf)) {
115         return FWK_SUCCESS;
116     }
117 
118     if (!MX25_IS_WEL_ENABLE(buf)) {
119         return FWK_E_ACCESS;
120     }
121 
122     /* At here, quad transfer is requested but not yet enabled. */
123     MX25_QUAD_ENABLE(buf);
124 
125     status = mx25_write_status_reg(id, qspi_api, buf);
126     if (status != FWK_SUCCESS) {
127         return status;
128     }
129 
130     return FWK_SUCCESS;
131 }
132 
mx25_nor_set_4byte_addr_mode(fwk_id_t id,const struct qspi_api * qspi_api,void * arg)133 int mx25_nor_set_4byte_addr_mode(
134     fwk_id_t id,
135     const struct qspi_api *qspi_api,
136     void *arg)
137 {
138     bool enable = *(bool *)arg;
139     struct qspi_command command;
140 
141     if (enable) {
142         command = MX25_COMMAND_ENTER_4BYTE;
143     } else {
144         command = MX25_COMMAND_EXIT_4BYTE;
145     }
146 
147     return set_write_command(id, qspi_api, command);
148 }
149 
mx25_nor_get_program_result(fwk_id_t id,const struct qspi_api * qspi_api,void * arg)150 int mx25_nor_get_program_result(
151     fwk_id_t id,
152     const struct qspi_api *qspi_api,
153     void *arg)
154 {
155     uint8_t buf;
156     bool *is_fail = (bool *)arg;
157     int status;
158 
159     status = mx25_read_security_reg(id, qspi_api, &buf);
160     if (status != FWK_SUCCESS) {
161         return status;
162     }
163 
164     if (MX25_IS_PROGRAM_FAIL(buf)) {
165         *is_fail = true;
166     } else {
167         *is_fail = false;
168     }
169 
170     return FWK_SUCCESS;
171 }
172 
mx25_nor_get_erase_result(fwk_id_t id,const struct qspi_api * qspi_api,void * arg)173 int mx25_nor_get_erase_result(
174     fwk_id_t id,
175     const struct qspi_api *qspi_api,
176     void *arg)
177 {
178     uint8_t buf;
179     bool *is_fail = (bool *)arg;
180     int status;
181 
182     status = mx25_read_security_reg(id, qspi_api, &buf);
183     if (status != FWK_SUCCESS) {
184         return status;
185     }
186 
187     if (MX25_IS_ERASE_FAIL(buf)) {
188         *is_fail = true;
189     } else {
190         *is_fail = false;
191     }
192 
193     return FWK_SUCCESS;
194 }
195