1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include <da1469x_qspic.h>
21 #include <assert.h>
22
23 /*
24 * JEDEC commands that should be supported by all NOR and PSRAM
25 * vendors in single bus mode.
26 */
27 #define MEMORY_JEDEC_RESET_ENABLE 0x66
28 #define MEMORY_JEDEC_RESET_CMD 0x99
29 #define MEMORY_JEDEC_READ_ID_CMD 0x9F
30
31 #define QSPIC_BURSTCMDB_REG_SET_FIELD(_field, _var, _val) \
32 ((_var)) = \
33 ((_var) & ~(QSPIC_QSPIC_BURSTCMDB_REG_ ## _field ## _Msk)) | \
34 (((_val) << QSPIC_QSPIC_BURSTCMDB_REG_ ## _field ## _Pos) & \
35 QSPIC_QSPIC_BURSTCMDB_REG_ ## _field ## _Msk)
36
37 #define QSPIC_CTRLMODE_REG_SET_FIELD(_field, _var, _val) \
38 ((_var)) = \
39 ((_var) & ~(QSPIC_QSPIC_CTRLMODE_REG_ ## _field ## _Msk)) | \
40 (((_val) << QSPIC_QSPIC_CTRLMODE_REG_ ## _field ## _Pos) & \
41 QSPIC_QSPIC_CTRLMODE_REG_ ## _field ## _Msk)
42
43 #define QSPIC_ERASECMDB_REG_SET_FIELD(_field, _var, _val) \
44 ((_var)) = \
45 ((_var) & ~(QSPIC_QSPIC_ERASECMDB_REG_ ## _field ## _Msk)) | \
46 (((_val) << QSPIC_QSPIC_ERASECMDB_REG_ ## _field ## _Pos) & \
47 QSPIC_QSPIC_ERASECMDB_REG_ ## _field ## _Msk)
48
49 #define QSPIC_MEMBLEN_REG_SET_FIELD(_field, _var, _val) \
50 ((_var)) = \
51 ((_var) & ~(QSPIC2_QSPIC2_MEMBLEN_REG_ ## _field ## _Msk)) | \
52 (((_val) << QSPIC2_QSPIC2_MEMBLEN_REG_ ## _field ## _Pos) & \
53 QSPIC2_QSPIC2_MEMBLEN_REG_ ## _field ## _Msk)
54
55 static inline void
qspi_set_cs_state(QSPIC_TYPE qspi_id,bool state)56 qspi_set_cs_state(QSPIC_TYPE qspi_id, bool state)
57 {
58 if (state) {
59 qspi_id->QSPIC_CTRLBUS_REG = QSPIC_QSPIC_CTRLBUS_REG_QSPIC_EN_CS_Msk;
60 } else {
61 qspi_id->QSPIC_CTRLBUS_REG = QSPIC_QSPIC_CTRLBUS_REG_QSPIC_DIS_CS_Msk;
62 }
63 }
64
65 static inline void
qspi_write8_data(QSPIC_TYPE qspi_id,int8_t data)66 qspi_write8_data(QSPIC_TYPE qspi_id, int8_t data)
67 {
68 volatile uint8_t *reg8 = (uint8_t *)&qspi_id->QSPIC_WRITEDATA_REG;
69
70 *reg8 = data;
71 }
72
73 static inline uint8_t
qspi_read8_data(QSPIC_TYPE qspi_id)74 qspi_read8_data(QSPIC_TYPE qspi_id)
75 {
76 volatile uint8_t *reg8 = (uint8_t *)&qspi_id->QSPIC_READDATA_REG;
77
78 return *reg8;
79 }
80
81 static void
qspi_write(QSPIC_TYPE qspi_id,const uint8_t * wbuf,size_t wlen)82 qspi_write(QSPIC_TYPE qspi_id, const uint8_t *wbuf, size_t wlen)
83 {
84 assert((qspi_id->QSPIC_CTRLMODE_REG & QSPIC_QSPIC_CTRLMODE_REG_QSPIC_AUTO_MD_Msk) == 0);
85
86 qspi_set_cs_state(qspi_id, true);
87
88 for (int i = 0; i < wlen; i++) {
89 qspi_write8_data(qspi_id, wbuf[i]);
90 }
91
92 qspi_set_cs_state(qspi_id, false);
93 }
94
95 static void
qspi_transact(QSPIC_TYPE qspi_id,const uint8_t * wbuf,size_t wlen,uint8_t * rbuf,size_t rlen)96 qspi_transact(QSPIC_TYPE qspi_id, const uint8_t *wbuf, size_t wlen, uint8_t *rbuf, size_t rlen)
97 {
98 assert((qspi_id->QSPIC_CTRLMODE_REG & QSPIC_QSPIC_CTRLMODE_REG_QSPIC_AUTO_MD_Msk) == 0);
99
100 qspi_set_cs_state(qspi_id, true);
101
102 for (int i = 0; i < wlen; i++) {
103 qspi_write8_data(qspi_id, wbuf[i]);
104 }
105
106 for (int i = 0; i < rlen; i++) {
107 rbuf[i] = qspi_read8_data(qspi_id);
108 }
109
110 qspi_set_cs_state(qspi_id, false);
111 }
112
113 void
da1469x_qspi_set_bus_mode(QSPIC_TYPE qspi_id,qspi_bus_mode_t mode)114 da1469x_qspi_set_bus_mode(QSPIC_TYPE qspi_id, qspi_bus_mode_t mode)
115 {
116 assert((qspi_id->QSPIC_CTRLMODE_REG & QSPIC_QSPIC_CTRLMODE_REG_QSPIC_AUTO_MD_Msk) == 0);
117
118 qspi_id->QSPIC_CTRLBUS_REG = mode;
119
120 switch (mode) {
121 case QSPI_BUS_MODE_SINGLE:
122 case QSPI_BUS_MODE_DUAL:
123 qspi_id->QSPIC_CTRLMODE_REG |= (QSPIC_QSPIC_CTRLMODE_REG_QSPIC_IO2_OEN_Msk |
124 QSPIC_QSPIC_CTRLMODE_REG_QSPIC_IO3_OEN_Msk |
125 QSPIC_QSPIC_CTRLMODE_REG_QSPIC_IO2_DAT_Msk |
126 QSPIC_QSPIC_CTRLMODE_REG_QSPIC_IO3_DAT_Msk);
127 break;
128 case QSPI_BUS_MODE_QUAD:
129 qspi_id->QSPIC_CTRLMODE_REG &= ~(QSPIC_QSPIC_CTRLMODE_REG_QSPIC_IO2_OEN_Msk |
130 QSPIC_QSPIC_CTRLMODE_REG_QSPIC_IO3_OEN_Msk);
131 break;
132 }
133 }
134
135 void
da1469x_qspi_memory_jedec_reset(QSPIC_TYPE qspi_id)136 da1469x_qspi_memory_jedec_reset(QSPIC_TYPE qspi_id)
137 {
138 assert((qspi_id->QSPIC_CTRLMODE_REG & QSPIC_QSPIC_CTRLMODE_REG_QSPIC_AUTO_MD_Msk) == 0);
139
140 uint8_t cmd;
141 da1469x_qspi_set_bus_mode(qspi_id, QSPI_BUS_MODE_SINGLE);
142
143 /* Commands should be sent in separate CS assertion cycles. */
144 cmd = MEMORY_JEDEC_RESET_ENABLE;
145 qspi_write(qspi_id, (const uint8_t *)&cmd, 1);
146 cmd = MEMORY_JEDEC_RESET_CMD;
147 qspi_write(qspi_id, (const uint8_t *)&cmd, 1);
148
149 /*
150 * It might happen that PSRAM/NOR device is already in QPI mode and so
151 * the previous commands should be sent in quad bus mode.
152 */
153 da1469x_qspi_set_bus_mode(qspi_id, QSPI_BUS_MODE_QUAD);
154 cmd = MEMORY_JEDEC_RESET_ENABLE;
155 qspi_write(qspi_id, (const uint8_t *)&cmd, 1);
156 cmd = MEMORY_JEDEC_RESET_CMD;
157 qspi_write(qspi_id, (const uint8_t *)&cmd, 1);
158 }
159
160 void
da1469x_qspi_memory_jedec_read_id(QSPIC_TYPE qspi_id,qspi_memory_id_t * id)161 da1469x_qspi_memory_jedec_read_id(QSPIC_TYPE qspi_id, qspi_memory_id_t *id)
162 {
163 assert((qspi_id->QSPIC_CTRLMODE_REG & QSPIC_QSPIC_CTRLMODE_REG_QSPIC_AUTO_MD_Msk) == 0);
164
165 uint8_t cmd[4] = { 0 };
166 uint8_t *response = (uint8_t *)id;
167
168 da1469x_qspi_set_bus_mode(qspi_id, QSPI_BUS_MODE_SINGLE);
169
170 cmd[0] = MEMORY_JEDEC_READ_ID_CMD;
171 qspi_transact(qspi_id, (const uint8_t *)cmd, sizeof(cmd), response, sizeof(*id));
172 }
173
174 void
da1469x_qspi_enter_exit_qpi_mode(QSPIC_TYPE qspi_id,bool enter,uint8_t cmd)175 da1469x_qspi_enter_exit_qpi_mode(QSPIC_TYPE qspi_id, bool enter, uint8_t cmd)
176 {
177 assert((qspi_id->QSPIC_CTRLMODE_REG & QSPIC_QSPIC_CTRLMODE_REG_QSPIC_AUTO_MD_Msk) == 0);
178
179 da1469x_qspi_set_bus_mode(qspi_id, enter ? QSPI_BUS_MODE_SINGLE : QSPI_BUS_MODE_QUAD);
180 qspi_write(qspi_id, (const uint8_t *)&cmd, 1);
181 }
182
183 void
da1469x_qspi_set_read_pipe_delay(QSPIC_TYPE qspi_id,uint8_t delay)184 da1469x_qspi_set_read_pipe_delay(QSPIC_TYPE qspi_id, uint8_t delay)
185 {
186 uint32_t qspic_ctrlmode_reg = qspi_id->QSPIC_CTRLMODE_REG;
187 QSPIC_CTRLMODE_REG_SET_FIELD(QSPIC_RPIPE_EN, qspic_ctrlmode_reg, 1);
188 QSPIC_CTRLMODE_REG_SET_FIELD(QSPIC_PCLK_MD, qspic_ctrlmode_reg, delay);
189 qspi_id->QSPIC_CTRLMODE_REG = qspic_ctrlmode_reg;
190 }
191
192 void
da1469x_qspi_set_cs_delay(QSPIC_TYPE qspi_id,uint32_t sys_clock_freq,uint32_t read_delay_ns,uint32_t erase_delay_ns)193 da1469x_qspi_set_cs_delay(QSPIC_TYPE qspi_id, uint32_t sys_clock_freq,
194 uint32_t read_delay_ns, uint32_t erase_delay_ns)
195 {
196 sys_clock_freq /= 100000;
197 uint32_t read_delay_cyc =
198 ((read_delay_ns * sys_clock_freq) + 9999) / 10000;
199 uint32_t erase_delay_cyc =
200 ((erase_delay_ns * sys_clock_freq) + 9999) / 10000;
201
202 uint32_t reg = qspi_id->QSPIC_BURSTCMDB_REG;
203 QSPIC_BURSTCMDB_REG_SET_FIELD(QSPIC_CS_HIGH_MIN, reg, read_delay_cyc);
204 qspi_id->QSPIC_BURSTCMDB_REG = reg;
205
206 reg = qspi_id->QSPIC_ERASECMDB_REG;
207 QSPIC_ERASECMDB_REG_SET_FIELD(QSPIC_ERS_CS_HI, reg, erase_delay_cyc);
208 qspi_id->QSPIC_ERASECMDB_REG = reg;
209 }
210
211 void
da1469x_qspi_set_tcem(uint32_t sys_clock_freq,uint32_t tcem_us)212 da1469x_qspi_set_tcem(uint32_t sys_clock_freq, uint32_t tcem_us)
213 {
214 uint32_t cs_active_max_cyc =
215 tcem_us * (sys_clock_freq / 1000000);
216
217 uint32_t qspic_mmemblen_reg = QSPIC2->QSPIC2_MEMBLEN_REG;
218 QSPIC_MEMBLEN_REG_SET_FIELD(QSPIC_T_CEM_EN, qspic_mmemblen_reg, 1);
219 QSPIC_MEMBLEN_REG_SET_FIELD(QSPIC_T_CEM_CC, qspic_mmemblen_reg, cs_active_max_cyc);
220 QSPIC2->QSPIC2_MEMBLEN_REG = qspic_mmemblen_reg;
221 }
222