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