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