1 /* spi_dw.h - Designware SPI driver private definitions */
2
3 /*
4 * Copyright (c) 2015 Intel Corporation.
5 * Copyright (c) 2023 Synopsys, Inc. All rights reserved.
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 */
9
10 #ifndef ZEPHYR_DRIVERS_SPI_SPI_DW_H_
11 #define ZEPHYR_DRIVERS_SPI_SPI_DW_H_
12
13 #include <string.h>
14 #include <zephyr/drivers/spi.h>
15
16 #include "spi_context.h"
17
18 #ifdef __cplusplus
19 extern "C" {
20 #endif
21
22 typedef void (*spi_dw_config_t)(void);
23 typedef uint32_t (*spi_dw_read_t)(uint8_t size, uint32_t addr, uint32_t off);
24 typedef void (*spi_dw_write_t)(uint8_t size, uint32_t data, uint32_t addr, uint32_t off);
25 typedef void (*spi_dw_set_bit_t)(uint8_t bit, uint32_t addr, uint32_t off);
26 typedef void (*spi_dw_clear_bit_t)(uint8_t bit, uint32_t addr, uint32_t off);
27 typedef int (*spi_dw_test_bit_t)(uint8_t bit, uint32_t addr, uint32_t off);
28
29 /* Private structures */
30 struct spi_dw_config {
31 uint32_t regs;
32 uint32_t clock_frequency;
33 spi_dw_config_t config_func;
34 uint8_t op_modes;
35 uint8_t fifo_depth;
36 #ifdef CONFIG_PINCTRL
37 const struct pinctrl_dev_config *pcfg;
38 #endif
39 spi_dw_read_t read_func;
40 spi_dw_write_t write_func;
41 spi_dw_set_bit_t set_bit_func;
42 spi_dw_clear_bit_t clear_bit_func;
43 spi_dw_test_bit_t test_bit_func;
44 };
45
46 struct spi_dw_data {
47 struct spi_context ctx;
48 uint8_t dfs; /* dfs in bytes: 1,2 or 4 */
49 uint8_t fifo_diff; /* cannot be bigger than FIFO depth */
50 uint16_t _unused;
51 };
52
53 /* Register operation functions */
54 #define DT_INST_NODE_PROP_NOT_OR(inst, prop) \
55 !DT_INST_PROP(inst, prop) ||
56 #define DT_ANY_INST_NOT_PROP_STATUS_OKAY(prop) \
57 (DT_INST_FOREACH_STATUS_OKAY_VARGS(DT_INST_NODE_PROP_NOT_OR, prop) 0)
58
59 #define DT_INST_NODE_PROP_AND_OR(inst, prop) \
60 DT_INST_PROP(inst, prop) ||
61 #define DT_ANY_INST_PROP_STATUS_OKAY(prop) \
62 (DT_INST_FOREACH_STATUS_OKAY_VARGS(DT_INST_NODE_PROP_AND_OR, prop) 0)
63
64 #if DT_ANY_INST_PROP_STATUS_OKAY(aux_reg)
aux_reg_read(uint8_t size,uint32_t addr,uint32_t off)65 static uint32_t aux_reg_read(uint8_t size, uint32_t addr, uint32_t off)
66 {
67 ARG_UNUSED(size);
68 return sys_in32(addr + off/4);
69 }
70
aux_reg_write(uint8_t size,uint32_t data,uint32_t addr,uint32_t off)71 static void aux_reg_write(uint8_t size, uint32_t data, uint32_t addr, uint32_t off)
72 {
73 ARG_UNUSED(size);
74 sys_out32(data, addr + off/4);
75 }
76
aux_reg_set_bit(uint8_t bit,uint32_t addr,uint32_t off)77 static void aux_reg_set_bit(uint8_t bit, uint32_t addr, uint32_t off)
78 {
79 sys_io_set_bit(addr + off/4, bit);
80 }
81
aux_reg_clear_bit(uint8_t bit,uint32_t addr,uint32_t off)82 static void aux_reg_clear_bit(uint8_t bit, uint32_t addr, uint32_t off)
83 {
84 sys_io_clear_bit(addr + off/4, bit);
85 }
86
aux_reg_test_bit(uint8_t bit,uint32_t addr,uint32_t off)87 static int aux_reg_test_bit(uint8_t bit, uint32_t addr, uint32_t off)
88 {
89 return sys_io_test_bit(addr + off/4, bit);
90 }
91 #endif
92
93 #if DT_ANY_INST_NOT_PROP_STATUS_OKAY(aux_reg)
reg_read(uint8_t size,uint32_t addr,uint32_t off)94 static uint32_t reg_read(uint8_t size, uint32_t addr, uint32_t off)
95 {
96 switch (size) {
97 case 8:
98 return sys_read8(addr + off);
99 case 16:
100 return sys_read16(addr + off);
101 case 32:
102 return sys_read32(addr + off);
103 default:
104 return -EINVAL;
105 }
106 }
107
reg_write(uint8_t size,uint32_t data,uint32_t addr,uint32_t off)108 static void reg_write(uint8_t size, uint32_t data, uint32_t addr, uint32_t off)
109 {
110 switch (size) {
111 case 8:
112 sys_write8(data, addr + off); break;
113 case 16:
114 sys_write16(data, addr + off); break;
115 case 32:
116 sys_write32(data, addr + off); break;
117 default:
118 break;
119 }
120 }
121
reg_set_bit(uint8_t bit,uint32_t addr,uint32_t off)122 static void reg_set_bit(uint8_t bit, uint32_t addr, uint32_t off)
123 {
124 sys_set_bit(addr + off, bit);
125 }
126
reg_clear_bit(uint8_t bit,uint32_t addr,uint32_t off)127 static void reg_clear_bit(uint8_t bit, uint32_t addr, uint32_t off)
128 {
129 sys_clear_bit(addr + off, bit);
130 }
131
reg_test_bit(uint8_t bit,uint32_t addr,uint32_t off)132 static int reg_test_bit(uint8_t bit, uint32_t addr, uint32_t off)
133 {
134 return sys_test_bit(addr + off, bit);
135 }
136 #endif
137
138 /* Helper macros */
139
140 #define SPI_DW_CLK_DIVIDER(clock_freq, ssi_clk_hz) \
141 ((clock_freq / ssi_clk_hz) & 0xFFFF)
142
143 #define DEFINE_MM_REG_READ(__reg, __off, __sz) \
144 static inline uint32_t read_##__reg(const struct spi_dw_config *info) \
145 { \
146 return info->read_func(__sz, info->regs, __off); \
147 }
148 #define DEFINE_MM_REG_WRITE(__reg, __off, __sz) \
149 static inline void write_##__reg(const struct spi_dw_config *info, uint32_t data)\
150 { \
151 info->write_func(__sz, data, info->regs, __off); \
152 }
153
154 #define DEFINE_SET_BIT_OP(__reg_bit, __reg_off, __bit) \
155 static inline void set_bit_##__reg_bit(const struct spi_dw_config *info) \
156 { \
157 info->set_bit_func(__bit, info->regs, __reg_off); \
158 }
159
160 #define DEFINE_CLEAR_BIT_OP(__reg_bit, __reg_off, __bit) \
161 static inline void clear_bit_##__reg_bit(const struct spi_dw_config *info)\
162 { \
163 info->clear_bit_func(__bit, info->regs, __reg_off); \
164 }
165
166 #define DEFINE_TEST_BIT_OP(__reg_bit, __reg_off, __bit) \
167 static inline int test_bit_##__reg_bit(const struct spi_dw_config *info)\
168 { \
169 return info->test_bit_func(__bit, info->regs, __reg_off); \
170 }
171
172 /* Common registers settings, bits etc... */
173
174 /* CTRLR0 settings */
175 #define DW_SPI_CTRLR0_SCPH_BIT (6)
176 #define DW_SPI_CTRLR0_SCPOL_BIT (7)
177 #define DW_SPI_CTRLR0_SRL_BIT (11)
178
179 #define DW_SPI_CTRLR0_SCPH BIT(DW_SPI_CTRLR0_SCPH_BIT)
180 #define DW_SPI_CTRLR0_SCPOL BIT(DW_SPI_CTRLR0_SCPOL_BIT)
181 #define DW_SPI_CTRLR0_SRL BIT(DW_SPI_CTRLR0_SRL_BIT)
182
183 #define DW_SPI_CTRLR0_SLV_OE_BIT (10)
184 #define DW_SPI_CTRLR0_SLV_OE BIT(DW_SPI_CTRLR0_SLV_OE_BIT)
185
186 #define DW_SPI_CTRLR0_TMOD_SHIFT (8)
187
188 #define DW_SPI_CTRLR0_TMOD_TX_RX (0)
189 #define DW_SPI_CTRLR0_TMOD_TX (1 << DW_SPI_CTRLR0_TMOD_SHIFT)
190 #define DW_SPI_CTRLR0_TMOD_RX (2 << DW_SPI_CTRLR0_TMOD_SHIFT)
191 #define DW_SPI_CTRLR0_TMOD_EEPROM (3 << DW_SPI_CTRLR0_TMOD_SHIFT)
192 #define DW_SPI_CTRLR0_TMOD_RESET (3 << DW_SPI_CTRLR0_TMOD_SHIFT)
193
194 #define DW_SPI_CTRLR0_DFS_16(__bpw) ((__bpw) - 1)
195 #define DW_SPI_CTRLR0_DFS_32(__bpw) (((__bpw) - 1) << 16)
196
197 #if defined(CONFIG_ARC)
198 #define DW_SPI_CTRLR0_DFS DW_SPI_CTRLR0_DFS_16
199 #else
200 #define DW_SPI_CTRLR0_DFS DW_SPI_CTRLR0_DFS_32
201 #endif
202
203 /* 0x38 represents the bits 8, 16 and 32. Knowing that 24 is bits 8 and 16
204 * These are the bits were when you divide by 8, you keep the result as it is.
205 * For all the other ones, 4 to 7, 9 to 15, etc... you need a +1,
206 * since on such division it takes only the result above 0
207 */
208 #define SPI_WS_TO_DFS(__bpw) (((__bpw) & ~0x38) ? \
209 (((__bpw) / 8) + 1) : \
210 ((__bpw) / 8))
211
212 /* SSIENR bits */
213 #define DW_SPI_SSIENR_SSIEN_BIT (0)
214
215 /* CLK_ENA bits */
216 #define DW_SPI_CLK_ENA_BIT (0)
217
218 /* SR bits and values */
219 #define DW_SPI_SR_BUSY_BIT (0)
220 #define DW_SPI_SR_TFNF_BIT (1)
221 #define DW_SPI_SR_RFNE_BIT (3)
222
223 /* IMR bits (ISR valid as well) */
224 #define DW_SPI_IMR_TXEIM_BIT (0)
225 #define DW_SPI_IMR_TXOIM_BIT (1)
226 #define DW_SPI_IMR_RXUIM_BIT (2)
227 #define DW_SPI_IMR_RXOIM_BIT (3)
228 #define DW_SPI_IMR_RXFIM_BIT (4)
229 #define DW_SPI_IMR_MSTIM_BIT (5)
230
231 /* IMR values */
232 #define DW_SPI_IMR_TXEIM BIT(DW_SPI_IMR_TXEIM_BIT)
233 #define DW_SPI_IMR_TXOIM BIT(DW_SPI_IMR_TXOIM_BIT)
234 #define DW_SPI_IMR_RXUIM BIT(DW_SPI_IMR_RXUIM_BIT)
235 #define DW_SPI_IMR_RXOIM BIT(DW_SPI_IMR_RXOIM_BIT)
236 #define DW_SPI_IMR_RXFIM BIT(DW_SPI_IMR_RXFIM_BIT)
237 #define DW_SPI_IMR_MSTIM BIT(DW_SPI_IMR_MSTIM_BIT)
238
239 /* ISR values (same as IMR) */
240 #define DW_SPI_ISR_TXEIS DW_SPI_IMR_TXEIM
241 #define DW_SPI_ISR_TXOIS DW_SPI_IMR_TXOIM
242 #define DW_SPI_ISR_RXUIS DW_SPI_IMR_RXUIM
243 #define DW_SPI_ISR_RXOIS DW_SPI_IMR_RXOIM
244 #define DW_SPI_ISR_RXFIS DW_SPI_IMR_RXFIM
245 #define DW_SPI_ISR_MSTIS DW_SPI_IMR_MSTIM
246
247 /* Error interrupt */
248 #define DW_SPI_ISR_ERRORS_MASK (DW_SPI_ISR_TXOIS | \
249 DW_SPI_ISR_RXUIS | \
250 DW_SPI_ISR_RXOIS | \
251 DW_SPI_ISR_MSTIS)
252 /* ICR Bit */
253 #define DW_SPI_SR_ICR_BIT (0)
254
255 /* Interrupt mask (IMR) */
256 #define DW_SPI_IMR_MASK (0x0)
257 #define DW_SPI_IMR_UNMASK (DW_SPI_IMR_TXEIM | \
258 DW_SPI_IMR_TXOIM | \
259 DW_SPI_IMR_RXUIM | \
260 DW_SPI_IMR_RXOIM | \
261 DW_SPI_IMR_RXFIM)
262 #define DW_SPI_IMR_MASK_TX (~(DW_SPI_IMR_TXEIM | \
263 DW_SPI_IMR_TXOIM))
264 #define DW_SPI_IMR_MASK_RX (~(DW_SPI_IMR_RXUIM | \
265 DW_SPI_IMR_RXOIM | \
266 DW_SPI_IMR_RXFIM))
267
268 /*
269 * Including the right register definition file
270 * SoC SPECIFIC!
271 *
272 * The file included next uses the DEFINE_MM_REG macros above to
273 * declare functions. In this situation we'll leave the containing
274 * extern "C" active in C++ compilations.
275 */
276 #include "spi_dw_regs.h"
277
278 #define z_extra_clock_on(...)
279 #define z_extra_clock_off(...)
280
281 /* Based on those macros above, here are common helpers for some registers */
282
283 DEFINE_MM_REG_READ(txflr, DW_SPI_REG_TXFLR, 32)
284 DEFINE_MM_REG_READ(rxflr, DW_SPI_REG_RXFLR, 32)
285
286 #ifdef CONFIG_SPI_DW_ACCESS_WORD_ONLY
287 DEFINE_MM_REG_WRITE(baudr, DW_SPI_REG_BAUDR, 32)
288 DEFINE_MM_REG_WRITE(imr, DW_SPI_REG_IMR, 32)
289 DEFINE_MM_REG_READ(imr, DW_SPI_REG_IMR, 32)
290 DEFINE_MM_REG_READ(isr, DW_SPI_REG_ISR, 32)
291 #else
292 DEFINE_MM_REG_WRITE(baudr, DW_SPI_REG_BAUDR, 16)
293 DEFINE_MM_REG_WRITE(imr, DW_SPI_REG_IMR, 8)
294 DEFINE_MM_REG_READ(imr, DW_SPI_REG_IMR, 8)
295 DEFINE_MM_REG_READ(isr, DW_SPI_REG_ISR, 8)
296 #endif
297
298 DEFINE_SET_BIT_OP(ssienr, DW_SPI_REG_SSIENR, DW_SPI_SSIENR_SSIEN_BIT)
299 DEFINE_CLEAR_BIT_OP(ssienr, DW_SPI_REG_SSIENR, DW_SPI_SSIENR_SSIEN_BIT)
300 DEFINE_TEST_BIT_OP(ssienr, DW_SPI_REG_SSIENR, DW_SPI_SSIENR_SSIEN_BIT)
301 DEFINE_TEST_BIT_OP(sr_busy, DW_SPI_REG_SR, DW_SPI_SR_BUSY_BIT)
302
303 #ifdef __cplusplus
304 }
305 #endif
306
307 #endif /* ZEPHYR_DRIVERS_SPI_SPI_DW_H_ */
308