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_w25.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 
w25_is_write_enable(fwk_id_t id,const struct qspi_api * qspi_api)45 static bool w25_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 W25_IS_WEL_ENABLE(buf);
61 }
62 
w25_read_status_reg_2(fwk_id_t id,const struct qspi_api * qspi_api,uint8_t * buf)63 static int w25_read_status_reg_2(
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 
w25_write_status_reg_2(fwk_id_t id,const struct qspi_api * qspi_api,uint8_t buf)78 static int w25_write_status_reg_2(
79     fwk_id_t id,
80     const struct qspi_api *qspi_api,
81     uint8_t buf)
82 {
83     int status;
84 
85     status = set_write_command(id, qspi_api, COMMAND_WRITE_STATUS_REG);
86     if (status != FWK_SUCCESS) {
87         return status;
88     }
89 
90     return qspi_api->write(id, 0, &buf, sizeof(buf));
91 }
92 
93 /*
94  * User APIs
95  */
w25_nor_set_io_protocol(fwk_id_t id,const struct qspi_api * qspi_api,void * arg)96 int w25_nor_set_io_protocol(
97     fwk_id_t id,
98     const struct qspi_api *qspi_api,
99     void *arg)
100 {
101     uint8_t io_num = *(uint8_t *)arg;
102     uint8_t buf;
103     bool req_quad;
104     int status;
105 
106     if (io_num != 1 && io_num != 2 && io_num != 4) {
107         return FWK_E_PARAM;
108     }
109 
110     req_quad = (io_num == 4);
111 
112     status = w25_read_status_reg_2(id, qspi_api, &buf);
113     if (status != FWK_SUCCESS) {
114         return status;
115     }
116 
117     if (!req_quad || W25_IS_QUAD_ENABLE(buf)) {
118         return FWK_SUCCESS;
119     }
120 
121     if (!w25_is_write_enable(id, qspi_api)) {
122         return FWK_E_ACCESS;
123     }
124 
125     /* At here, quad transfer is requested but not yet enabled. */
126     W25_QUAD_ENABLE(buf);
127 
128     status = w25_write_status_reg_2(id, qspi_api, buf);
129     if (status != FWK_SUCCESS) {
130         return status;
131     }
132 
133     return FWK_SUCCESS;
134 }
135 
w25_nor_set_4byte_addr_mode(fwk_id_t id,const struct qspi_api * qspi_api,void * arg)136 int w25_nor_set_4byte_addr_mode(
137     fwk_id_t id,
138     const struct qspi_api *qspi_api,
139     void *arg)
140 {
141     bool enable = *(bool *)arg;
142     struct qspi_command command;
143 
144     if (enable) {
145         command = W25_COMMAND_ENTER_4BYTE;
146     } else {
147         command = W25_COMMAND_EXIT_4BYTE;
148     }
149 
150     return set_write_command(id, qspi_api, command);
151 }
152